mirror of
https://github.com/EnumeratedDev/bpm-utils.git
synced 2026-09-17 11:26:12 +00:00
Compare commits
24
Commits
7.0.0
..
eb13b2653d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eb13b2653d
|
||
|
|
581c864f1d
|
||
|
|
7e7b8487ea
|
||
|
|
a7f751c094
|
||
|
|
54e192f220
|
||
|
|
c508ce6a01
|
||
|
|
2b81dad6cf
|
||
|
|
82777ebac1
|
||
|
|
b20766bddb
|
||
|
|
0ff9eb9cf2
|
||
|
|
4371b7f0e3
|
||
|
|
65849fdf86
|
||
|
|
a64ad39ca7
|
||
|
|
bf9874af6b
|
||
|
|
07a9e8c9d2
|
||
|
|
598e6710f4
|
||
|
|
902fcbf296
|
||
|
|
03bf97b8d8
|
||
|
|
5240ae4a8c
|
||
|
|
9d03b5b423
|
||
|
|
f17bc777d9
|
||
|
|
154f546b7f
|
||
|
|
c4a0e9f860
|
||
|
|
b9d7dfd9d0
|
@@ -1,2 +1,3 @@
|
|||||||
# Exclude bpm archives
|
# Ignore BPM archives and signatures
|
||||||
*.bpm
|
*.bpm
|
||||||
|
*.bpm.sig
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
# This is the source.sh script. It is executed by BPM in a temporary directory when compiling a source package
|
||||||
|
# BPM Expects the source code to be extracted into the automatically created 'source' directory which can be accessed using $BPM_SOURCE
|
||||||
|
# BPM Expects the output files to be present in the automatically created 'output' directory which can be accessed using $BPM_OUTPUT
|
||||||
|
|
||||||
|
# The prepare function is executed in the root of the temp directory
|
||||||
|
# This function is used for putting downloaded files to the correct location or applying patches
|
||||||
|
prepare() {
|
||||||
|
cd "$BPM_SOURCE"
|
||||||
|
cargo fetch --locked --target "$(rustc -vV | sed -n 's/host: //p')"
|
||||||
|
}
|
||||||
|
|
||||||
|
# The build function is executed in the source directory
|
||||||
|
# This function is used to compile the source code
|
||||||
|
build() {
|
||||||
|
cargo build --release --locked --frozen
|
||||||
|
}
|
||||||
|
|
||||||
|
# The check function is executed in the source directory
|
||||||
|
# This function is used to run tests to verify the package has been compiled correctly
|
||||||
|
check() {
|
||||||
|
cargo test --release --frozen
|
||||||
|
}
|
||||||
|
|
||||||
|
# The package function is executed in the source directory
|
||||||
|
# This function is used to move the compiled files into the output directory
|
||||||
|
package() {
|
||||||
|
# Cargo built packages are not usually packaged manually and not with an 'install' subcommand
|
||||||
|
|
||||||
|
# Install package license
|
||||||
|
install -Dm644 "$BPM_SOURCE"/LICENSE "$BPM_OUTPUT"/usr/share/licenses/$NAME/LICENSE
|
||||||
|
}
|
||||||
+84
-5
@@ -12,6 +12,7 @@ import (
|
|||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"slices"
|
"slices"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
flag "github.com/spf13/pflag"
|
flag "github.com/spf13/pflag"
|
||||||
@@ -19,11 +20,15 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var compile = flag.BoolP("compile", "c", false, "Compile BPM source package")
|
var compile = flag.BoolP("compile", "c", false, "Compile BPM source package")
|
||||||
var skipCheck = flag.BoolP("skip-checks", "s", false, "Skip 'check' function while compiling")
|
var verbose = flag.BoolP("verbose", "v", false, "Show additional information about the compilation process")
|
||||||
|
var skipCheck = flag.Bool("skip-checks", false, "Skip 'check' function while compiling")
|
||||||
|
var keepCompilationFiles = flag.BoolP("keep", "k", false, "Keep compilation files after successful package compilation")
|
||||||
var installDepends = flag.BoolP("depends", "d", false, "Install package dependencies for compilation")
|
var installDepends = flag.BoolP("depends", "d", false, "Install package dependencies for compilation")
|
||||||
var installPackage = flag.BoolP("install", "i", false, "Install compiled BPM package after compilation finishes")
|
var installPackage = flag.BoolP("install", "i", false, "Install compiled BPM package after compilation finishes")
|
||||||
|
var compilationJobs = flag.IntP("jobs", "j", 0, "Set the amount of concurrent processes to use for source package compilation")
|
||||||
var moveToBinaryDir = flag.BoolP("move", "m", false, "Move output packages to the current repository's binary directory")
|
var moveToBinaryDir = flag.BoolP("move", "m", false, "Move output packages to the current repository's binary directory")
|
||||||
var updateChecksums = flag.BoolP("update-checksums", "u", false, "Update the checksums for all download entries")
|
var updateInfo = flag.BoolP("update-info", "u", false, "Update the pkg.info file")
|
||||||
|
var signPackage = flag.BoolP("sign", "s", false, "Sign package using GPG")
|
||||||
var yesAll = flag.BoolP("yes", "y", false, "Accept all confirmation prompts")
|
var yesAll = flag.BoolP("yes", "y", false, "Accept all confirmation prompts")
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@@ -54,6 +59,12 @@ func runChecks() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func createArchive() string {
|
func createArchive() string {
|
||||||
|
// Read BPM utils config
|
||||||
|
config, err := bpmutilsshared.ReadBPMUtilsConfig()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Error: failed to read config: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
filesToInclude := make([]string, 0)
|
filesToInclude := make([]string, 0)
|
||||||
|
|
||||||
// Include base files
|
// Include base files
|
||||||
@@ -82,8 +93,9 @@ func createArchive() string {
|
|||||||
log.Fatalf("Error: could not read package info: %s", err)
|
log.Fatalf("Error: could not read package info: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update checksums
|
// Update pkg.info file
|
||||||
if *updateChecksums {
|
if *updateInfo {
|
||||||
|
// Update download checksums
|
||||||
for i, download := range pkgInfo.Downloads {
|
for i, download := range pkgInfo.Downloads {
|
||||||
if download.Checksum == "skip" {
|
if download.Checksum == "skip" {
|
||||||
continue
|
continue
|
||||||
@@ -97,6 +109,13 @@ func createArchive() string {
|
|||||||
pkgInfo.Downloads[i] = download
|
pkgInfo.Downloads[i] = download
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add default maintainer
|
||||||
|
if config.AddDefaultMaintainer {
|
||||||
|
if !slices.Contains(pkgInfo.Maintainers, config.DefaultMaintainer) {
|
||||||
|
pkgInfo.Maintainers = append(pkgInfo.Maintainers, config.DefaultMaintainer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Save yaml back to file
|
// Save yaml back to file
|
||||||
var data bytes.Buffer
|
var data bytes.Buffer
|
||||||
encoder := yaml.NewEncoder(&data)
|
encoder := yaml.NewEncoder(&data)
|
||||||
@@ -131,6 +150,18 @@ func createArchive() string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove old BPM archive signatures in current directory
|
||||||
|
oldSignatures, err := filepath.Glob("*.sig")
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Warning: could not search for old BPM archive signatures: %s", err)
|
||||||
|
}
|
||||||
|
for _, signature := range oldSignatures {
|
||||||
|
err = os.Remove(signature)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Warning: could not remove old BPM archive signature (%s): %s", signature, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Create filename
|
// Create filename
|
||||||
filename := fmt.Sprintf("%s-%s-%d-%s-src.bpm", pkgInfo.Name, pkgInfo.Version, pkgInfo.Revision, pkgInfo.Arch)
|
filename := fmt.Sprintf("%s-%s-%d-%s-src.bpm", pkgInfo.Name, pkgInfo.Version, pkgInfo.Revision, pkgInfo.Arch)
|
||||||
|
|
||||||
@@ -146,6 +177,19 @@ func createArchive() string {
|
|||||||
log.Fatalf("Error: failed to create BPM source archive: %s", err)
|
log.Fatalf("Error: failed to create BPM source archive: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sign package
|
||||||
|
if *signPackage {
|
||||||
|
cmd := exec.Command("gpg", "--detach-sign", filename)
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
cmd.Stdin = os.Stdin
|
||||||
|
|
||||||
|
err := cmd.Run()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Error: could not sign package: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Get absolute path to filename
|
// Get absolute path to filename
|
||||||
absFilepath, err := filepath.Abs(filename)
|
absFilepath, err := filepath.Abs(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -160,12 +204,21 @@ func compilePackage(archive string) {
|
|||||||
// Setup compile command
|
// Setup compile command
|
||||||
args := make([]string, 0)
|
args := make([]string, 0)
|
||||||
args = append(args, "compile")
|
args = append(args, "compile")
|
||||||
|
if *verbose {
|
||||||
|
args = append(args, "-v")
|
||||||
|
}
|
||||||
if *skipCheck {
|
if *skipCheck {
|
||||||
args = append(args, "-s")
|
args = append(args, "-s")
|
||||||
}
|
}
|
||||||
|
if *keepCompilationFiles {
|
||||||
|
args = append(args, "-k")
|
||||||
|
}
|
||||||
if *installDepends {
|
if *installDepends {
|
||||||
args = append(args, "-d")
|
args = append(args, "-d")
|
||||||
}
|
}
|
||||||
|
if *compilationJobs > 0 {
|
||||||
|
args = append(args, "-j"+strconv.Itoa(*compilationJobs))
|
||||||
|
}
|
||||||
if *yesAll {
|
if *yesAll {
|
||||||
args = append(args, "-y")
|
args = append(args, "-y")
|
||||||
}
|
}
|
||||||
@@ -219,6 +272,14 @@ func compilePackage(archive string) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Warning: could not remove old binary package (%s): %s", pkgFilepath, err)
|
log.Printf("Warning: could not remove old binary package (%s): %s", pkgFilepath, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove package signature
|
||||||
|
if _, err := os.Stat(pkgFilepath + ".sig"); err == nil {
|
||||||
|
err := os.Remove(pkgFilepath + ".sig")
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Warning: could not remove old binary package signature (%s): %s", pkgFilepath+".str", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -231,11 +292,29 @@ func compilePackage(archive string) {
|
|||||||
os.Rename(line, newPath)
|
os.Rename(line, newPath)
|
||||||
outputPkgs[pkgInfo.Name] = newPath
|
outputPkgs[pkgInfo.Name] = newPath
|
||||||
|
|
||||||
bpmutilsshared.UpdateDatabases(repo)
|
|
||||||
} else {
|
} else {
|
||||||
outputPkgs[pkgInfo.Name] = line
|
outputPkgs[pkgInfo.Name] = line
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if repo := bpmutilsshared.GetRepository(); repo != "" && *moveToBinaryDir {
|
||||||
|
bpmutilsshared.UpdateDatabases(repo)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sign package
|
||||||
|
if *signPackage {
|
||||||
|
for k, v := range outputPkgs {
|
||||||
|
cmd := exec.Command("gpg", "--detach-sign", v)
|
||||||
|
cmd.Dir = path.Dir(v)
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
cmd.Stdin = os.Stdin
|
||||||
|
|
||||||
|
err := cmd.Run()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Error: could not sign package (%s) at: %s", k, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Print out generated packages
|
// Print out generated packages
|
||||||
for k, v := range outputPkgs {
|
for k, v := range outputPkgs {
|
||||||
|
|||||||
+276
-1
@@ -3,6 +3,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
bpmutilsshared "bpm-utils-shared"
|
bpmutilsshared "bpm-utils-shared"
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
@@ -14,6 +15,7 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"slices"
|
"slices"
|
||||||
"sort"
|
"sort"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -85,6 +87,7 @@ func main() {
|
|||||||
flagset := flag.NewFlagSet("check-versions", flag.ExitOnError)
|
flagset := flag.NewFlagSet("check-versions", flag.ExitOnError)
|
||||||
flagset.BoolP("verbose", "v", false, "Show additional information about the current operation")
|
flagset.BoolP("verbose", "v", false, "Show additional information about the current operation")
|
||||||
flagset.BoolP("force", "f", false, "Force current operation to bypass certain conditions")
|
flagset.BoolP("force", "f", false, "Force current operation to bypass certain conditions")
|
||||||
|
flagset.BoolP("apply", "a", false, "Apply new versions to packages")
|
||||||
setupFlagsAndHelp(flagset, fmt.Sprintf("bpm-repo %s <options>", subcommand), "Manage BPM repositories and databases", os.Args[2:])
|
setupFlagsAndHelp(flagset, fmt.Sprintf("bpm-repo %s <options>", subcommand), "Manage BPM repositories and databases", os.Args[2:])
|
||||||
currentFlagSet = flagset
|
currentFlagSet = flagset
|
||||||
|
|
||||||
@@ -95,6 +98,36 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
checkVersionsFunc(repo)
|
checkVersionsFunc(repo)
|
||||||
|
case "hold", "h":
|
||||||
|
// Setup flags and help
|
||||||
|
flagset := flag.NewFlagSet("hold", flag.ExitOnError)
|
||||||
|
flagset.Bool("get", false, "Show current value")
|
||||||
|
setupFlagsAndHelp(flagset, fmt.Sprintf("bpm-repo %s <options>", subcommand), "Manage BPM repositories and databases", os.Args[2:])
|
||||||
|
currentFlagSet = flagset
|
||||||
|
|
||||||
|
// Get current database
|
||||||
|
repo := bpmutilsshared.GetRepository()
|
||||||
|
if repo == "" {
|
||||||
|
log.Fatal("Error: this command may only be run inside a BPM repository")
|
||||||
|
}
|
||||||
|
|
||||||
|
holdPackage(repo)
|
||||||
|
case "compile-all", "a":
|
||||||
|
// Setup flags and help
|
||||||
|
flagset := flag.NewFlagSet("check-versions", flag.ExitOnError)
|
||||||
|
flagset.BoolP("verbose", "v", false, "Show additional information about the current operation")
|
||||||
|
flagset.BoolP("modified", "m", true, "Skip non-modified source packages")
|
||||||
|
flagset.BoolP("show-order", "o", false, "Show the order in which all packages will be compiled and exit")
|
||||||
|
setupFlagsAndHelp(flagset, fmt.Sprintf("bpm-repo %s <options>", subcommand), "Manage BPM repositories and databases", os.Args[2:])
|
||||||
|
currentFlagSet = flagset
|
||||||
|
|
||||||
|
// Get current database
|
||||||
|
repo := bpmutilsshared.GetRepository()
|
||||||
|
if repo == "" {
|
||||||
|
log.Fatal("Error: this command may only be run inside a BPM repository")
|
||||||
|
}
|
||||||
|
|
||||||
|
compileAllPackagesFunc(repo)
|
||||||
default:
|
default:
|
||||||
log.Println("Error: unknown subcommand")
|
log.Println("Error: unknown subcommand")
|
||||||
listSubcommands()
|
listSubcommands()
|
||||||
@@ -114,6 +147,11 @@ func createRepository(name, description string) {
|
|||||||
log.Fatalf("Error: could not write to file: %s", err)
|
log.Fatalf("Error: could not write to file: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = os.Mkdir(path.Join(name, "source"), 0755)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Error: could not create directory: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
fmt.Println("Repository created successfully!")
|
fmt.Println("Repository created successfully!")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,6 +159,7 @@ func checkVersionsFunc(repo string) {
|
|||||||
// Get flags
|
// Get flags
|
||||||
verbose, _ := currentFlagSet.GetBool("verbose")
|
verbose, _ := currentFlagSet.GetBool("verbose")
|
||||||
force, _ := currentFlagSet.GetBool("force")
|
force, _ := currentFlagSet.GetBool("force")
|
||||||
|
apply, _ := currentFlagSet.GetBool("apply")
|
||||||
|
|
||||||
// Read environment files
|
// Read environment files
|
||||||
err := readEnvFile(repo)
|
err := readEnvFile(repo)
|
||||||
@@ -132,6 +171,7 @@ func checkVersionsFunc(repo string) {
|
|||||||
type CachedVersionEntry struct {
|
type CachedVersionEntry struct {
|
||||||
LatestVersion string `yaml:"latest_version"`
|
LatestVersion string `yaml:"latest_version"`
|
||||||
Timestamp int64 `yaml:"timestamp"`
|
Timestamp int64 `yaml:"timestamp"`
|
||||||
|
OnHold bool `yaml:"on_hold,omitempty"`
|
||||||
}
|
}
|
||||||
cachedVersions := make(map[string]CachedVersionEntry)
|
cachedVersions := make(map[string]CachedVersionEntry)
|
||||||
data, err := os.ReadFile(path.Join(repo, ".version-cache"))
|
data, err := os.ReadFile(path.Join(repo, ".version-cache"))
|
||||||
@@ -220,10 +260,17 @@ func checkVersionsFunc(repo string) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get current on_hold value
|
||||||
|
onHold := false
|
||||||
|
if v, ok := cachedVersions[pkgInfo.Name]; ok {
|
||||||
|
onHold = v.OnHold
|
||||||
|
}
|
||||||
|
|
||||||
// Cache latest version
|
// Cache latest version
|
||||||
cachedVersions[pkgInfo.Name] = CachedVersionEntry{
|
cachedVersions[pkgInfo.Name] = CachedVersionEntry{
|
||||||
LatestVersion: latestVersion,
|
LatestVersion: latestVersion,
|
||||||
Timestamp: time.Now().UnixMilli(),
|
Timestamp: time.Now().UnixMilli(),
|
||||||
|
OnHold: onHold,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,6 +283,31 @@ func checkVersionsFunc(repo string) {
|
|||||||
OldVersion: pkgInfo.Version,
|
OldVersion: pkgInfo.Version,
|
||||||
NewVersion: latestVersion,
|
NewVersion: latestVersion,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Apply new version
|
||||||
|
pkgInfo.Version = latestVersion
|
||||||
|
pkgInfo.Revision = 1
|
||||||
|
if apply && !cachedVersions[pkgInfo.Name].OnHold {
|
||||||
|
var data bytes.Buffer
|
||||||
|
encoder := yaml.NewEncoder(&data)
|
||||||
|
encoder.SetIndent(2)
|
||||||
|
encoder.Encode(pkgInfo)
|
||||||
|
|
||||||
|
// Write package information
|
||||||
|
err := os.WriteFile(path.Join(dir, "pkg.info"), data.Bytes(), 0644)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Warning: could not write new version for package (%s) to file: %s", pkgInfo.Name, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate source package
|
||||||
|
cmd := exec.Command("bpm-package")
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
cmd.Dir = dir
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
log.Printf("Warning: could not generate source pacakge (%s): %s", pkgInfo.Name, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -255,7 +327,11 @@ func checkVersionsFunc(repo string) {
|
|||||||
keys := slices.Collect(maps.Keys(pkgsWithUpdates))
|
keys := slices.Collect(maps.Keys(pkgsWithUpdates))
|
||||||
sort.Strings(keys)
|
sort.Strings(keys)
|
||||||
for _, pkg := range keys {
|
for _, pkg := range keys {
|
||||||
fmt.Printf("Update available for package (%s): %s -> %s\n", pkg, pkgsWithUpdates[pkg].OldVersion, pkgsWithUpdates[pkg].NewVersion)
|
fmt.Printf("Update available for package (%s): %s -> %s", pkg, pkgsWithUpdates[pkg].OldVersion, pkgsWithUpdates[pkg].NewVersion)
|
||||||
|
if cachedVersions[pkg].OnHold {
|
||||||
|
fmt.Print(" (On hold)")
|
||||||
|
}
|
||||||
|
fmt.Println()
|
||||||
}
|
}
|
||||||
|
|
||||||
if verbose {
|
if verbose {
|
||||||
@@ -286,6 +362,78 @@ func checkVersionsFunc(repo string) {
|
|||||||
fmt.Println("Errors:", len(pkgsWithError))
|
fmt.Println("Errors:", len(pkgsWithError))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func holdPackage(repo string) {
|
||||||
|
// Get flags
|
||||||
|
get, _ := currentFlagSet.GetBool("get")
|
||||||
|
|
||||||
|
// Get package name
|
||||||
|
pkgName := ""
|
||||||
|
if len(currentFlagSet.Args()) < 1 {
|
||||||
|
log.Fatalf("Error: no package name set")
|
||||||
|
} else {
|
||||||
|
pkgName = currentFlagSet.Arg(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure package exists
|
||||||
|
if _, err := os.Stat(path.Join(repo, "source", pkgName, "pkg.info")); err != nil {
|
||||||
|
log.Fatalf("Error: could not find pkg.info file in directory (%s): %s", pkgName, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read version cache
|
||||||
|
type CachedVersionEntry struct {
|
||||||
|
LatestVersion string `yaml:"latest_version"`
|
||||||
|
Timestamp int64 `yaml:"timestamp"`
|
||||||
|
OnHold bool `yaml:"on_hold,omitempty"`
|
||||||
|
}
|
||||||
|
cachedVersions := make(map[string]*CachedVersionEntry)
|
||||||
|
data, err := os.ReadFile(path.Join(repo, ".version-cache"))
|
||||||
|
if err == nil {
|
||||||
|
err := yaml.Unmarshal(data, &cachedVersions)
|
||||||
|
if err != nil {
|
||||||
|
cachedVersions = make(map[string]*CachedVersionEntry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get current on_hold value
|
||||||
|
if get {
|
||||||
|
if cachedVersion, ok := cachedVersions[pkgName]; ok && cachedVersion.OnHold {
|
||||||
|
fmt.Printf("Package (%s) has been put on hold.\n", pkgName)
|
||||||
|
} else {
|
||||||
|
fmt.Printf("Package (%s) has not been put on hold.\n", pkgName)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get boolean value
|
||||||
|
var value bool
|
||||||
|
if len(currentFlagSet.Args()) < 2 {
|
||||||
|
log.Fatalf("Error: no boolean value set")
|
||||||
|
} else {
|
||||||
|
value, err = strconv.ParseBool(currentFlagSet.Arg(1))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Error: value (%s) is not a boolean", currentFlagSet.Arg(1))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set on_hold value
|
||||||
|
cachedVersions[pkgName].OnHold = value
|
||||||
|
|
||||||
|
// Save cached versions to file
|
||||||
|
data, err = yaml.Marshal(cachedVersions)
|
||||||
|
if err == nil {
|
||||||
|
err := os.WriteFile(path.Join(repo, ".version-cache"), data, 0644)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Warning: could not write cached versions to file: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if value {
|
||||||
|
fmt.Printf("Package (%s) was put on hold.\n", pkgName)
|
||||||
|
} else {
|
||||||
|
fmt.Printf("Package (%s) is no longer put on hold.\n", pkgName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func listPackagesFunc(repo string) {
|
func listPackagesFunc(repo string) {
|
||||||
// Read databases
|
// Read databases
|
||||||
sourceDatabase, err := bpmutilsshared.ReadDatabase(path.Join(repo, "source/database.bpmdb"))
|
sourceDatabase, err := bpmutilsshared.ReadDatabase(path.Join(repo, "source/database.bpmdb"))
|
||||||
@@ -329,6 +477,130 @@ func listPackagesFunc(repo string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func compileAllPackagesFunc(repo string) {
|
||||||
|
// Get flags
|
||||||
|
verbose, _ := currentFlagSet.GetBool("verbose")
|
||||||
|
modifiedOnly, _ := currentFlagSet.GetBool("modified")
|
||||||
|
showOrder, _ := currentFlagSet.GetBool("show-order")
|
||||||
|
|
||||||
|
// Read BPM utils config
|
||||||
|
config, err := bpmutilsshared.ReadBPMUtilsConfig()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Error: failed to read config: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure database is updated
|
||||||
|
bpmutilsshared.UpdateDatabases(repo)
|
||||||
|
|
||||||
|
// Read databases
|
||||||
|
sourceDatabase, err := bpmutilsshared.ReadDatabase(path.Join(repo, "source/database.bpmdb"))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Error: could not read source database: %s", err)
|
||||||
|
}
|
||||||
|
binaryDatabase, _ := bpmutilsshared.ReadDatabase(path.Join(repo, "binary/database.bpmdb"))
|
||||||
|
|
||||||
|
// Get all packages from database entries
|
||||||
|
packages := slices.Collect(maps.Values(sourceDatabase.Entries))
|
||||||
|
sort.Slice(packages, func(a, b int) bool {
|
||||||
|
return packages[a].PackageInfo.Name < packages[b].PackageInfo.Name
|
||||||
|
})
|
||||||
|
|
||||||
|
// Toposort packages using Depth-first search algorithm
|
||||||
|
sorted := make([]bpmutilsshared.PackageInfo, 0)
|
||||||
|
marked := make(map[string]int) // 0 = Unmarked, 1 = Temporary mark, 2 = Permanent mark
|
||||||
|
var visit func(pkgInfo *bpmutilsshared.PackageInfo) error
|
||||||
|
visit = func(pkgInfo *bpmutilsshared.PackageInfo) error {
|
||||||
|
if mark, _ := marked[pkgInfo.Name]; mark == 2 {
|
||||||
|
return nil
|
||||||
|
} else if mark == 1 {
|
||||||
|
return fmt.Errorf("Circular dependency found!")
|
||||||
|
}
|
||||||
|
|
||||||
|
marked[pkgInfo.Name] = 1
|
||||||
|
|
||||||
|
// Get all dependencies
|
||||||
|
depends := slices.Clone(pkgInfo.Depends)
|
||||||
|
depends = append(depends, pkgInfo.MakeDepends...)
|
||||||
|
|
||||||
|
for _, depend := range depends {
|
||||||
|
// Find package in repository
|
||||||
|
dependEntry, ok := sourceDatabase.Entries[depend]
|
||||||
|
if !ok {
|
||||||
|
// Search for virtual package
|
||||||
|
for _, entry := range sourceDatabase.Entries {
|
||||||
|
if slices.Contains(entry.PackageInfo.Provides, depend) {
|
||||||
|
dependEntry = entry
|
||||||
|
ok = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err := visit(dependEntry.PackageInfo)
|
||||||
|
if err != nil && verbose {
|
||||||
|
fmt.Printf("Circular dependency found! (%s -> %s)\n", pkgInfo.Name, dependEntry.PackageInfo.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
marked[pkgInfo.Name] = 2
|
||||||
|
sorted = append(sorted, *pkgInfo)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, entry := range packages {
|
||||||
|
if mark, _ := marked[entry.PackageInfo.Name]; mark != 2 {
|
||||||
|
visit(entry.PackageInfo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compile all packages in order
|
||||||
|
for _, pkgInfo := range sorted {
|
||||||
|
if modifiedOnly && binaryDatabase != nil {
|
||||||
|
if binaryPkgInfo, ok := binaryDatabase.Entries[pkgInfo.Name]; ok && binaryPkgInfo.PackageInfo.GetFullVersion() == pkgInfo.GetFullVersion() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if showOrder {
|
||||||
|
fmt.Println(pkgInfo.Name)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure installed packages are up-to-date
|
||||||
|
cmd := exec.Command(config.PrivilegeEscalatorCmd, "sh", "-c", "bpm u -y")
|
||||||
|
cmd.Stdin = os.Stdin
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
log.Fatalf("Error: could not update packages): %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compile source package
|
||||||
|
cmd = exec.Command("bpm-package", "-cdvusmy")
|
||||||
|
cmd.Stdin = os.Stdin
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
cmd.Dir = path.Join(repo, "source", pkgInfo.Name)
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
log.Fatalf("Error: could not compile package (%s): %s", pkgInfo.Name, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure installed packages are up-to-date
|
||||||
|
cmd := exec.Command(config.PrivilegeEscalatorCmd, "sh", "-c", "bpm u -y")
|
||||||
|
cmd.Stdin = os.Stdin
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
log.Fatalf("Error: could not update packages): %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func readEnvFile(repo string) error {
|
func readEnvFile(repo string) error {
|
||||||
data, err := os.ReadFile(path.Join(repo, ".env"))
|
data, err := os.ReadFile(path.Join(repo, ".env"))
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
@@ -361,7 +633,10 @@ func listSubcommands() {
|
|||||||
fmt.Println(" c, create-repo Create a new BPM repository")
|
fmt.Println(" c, create-repo Create a new BPM repository")
|
||||||
fmt.Println(" u, update-db Update update source and binary databases in current repositor")
|
fmt.Println(" u, update-db Update update source and binary databases in current repositor")
|
||||||
fmt.Println(" v, check-versions Manage BPM repositories and databases")
|
fmt.Println(" v, check-versions Manage BPM repositories and databases")
|
||||||
|
fmt.Println(" h, hold Prevent package from being automatically updated")
|
||||||
fmt.Println(" l, list List packages")
|
fmt.Println(" l, list List packages")
|
||||||
|
fmt.Println(" a, compile-all Compile all packages in the current repository")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupFlagsAndHelp(flagset *flag.FlagSet, usage, desc string, args []string) {
|
func setupFlagsAndHelp(flagset *flag.FlagSet, usage, desc string, args []string) {
|
||||||
|
|||||||
+11
-1
@@ -108,12 +108,18 @@ func replaceVariables(templateContents string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func createDirectory() {
|
func createDirectory() {
|
||||||
|
// Read BPM utils config
|
||||||
|
config, err := bpmutilsshared.ReadBPMUtilsConfig()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Error: failed to read config: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
// Trim spaces
|
// Trim spaces
|
||||||
*directory = strings.TrimSpace(*directory)
|
*directory = strings.TrimSpace(*directory)
|
||||||
*name = strings.TrimSpace(*name)
|
*name = strings.TrimSpace(*name)
|
||||||
|
|
||||||
// Create directory
|
// Create directory
|
||||||
err := os.Mkdir(*directory, 0755)
|
err = os.Mkdir(*directory, 0755)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Error: could not create directory: %s", err)
|
log.Fatalf("Error: could not create directory: %s", err)
|
||||||
}
|
}
|
||||||
@@ -123,6 +129,7 @@ func createDirectory() {
|
|||||||
Name: *name,
|
Name: *name,
|
||||||
Description: *description,
|
Description: *description,
|
||||||
Version: *version,
|
Version: *version,
|
||||||
|
Revision: 1,
|
||||||
Url: *url,
|
Url: *url,
|
||||||
License: *license,
|
License: *license,
|
||||||
Arch: "any",
|
Arch: "any",
|
||||||
@@ -136,6 +143,9 @@ func createDirectory() {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
if config.DefaultMaintainer != "" {
|
||||||
|
pkgInfo.Maintainers = append(pkgInfo.Maintainers, config.DefaultMaintainer)
|
||||||
|
}
|
||||||
|
|
||||||
var buffer bytes.Buffer
|
var buffer bytes.Buffer
|
||||||
encoder := yaml.NewEncoder(&buffer)
|
encoder := yaml.NewEncoder(&buffer)
|
||||||
|
|||||||
@@ -58,31 +58,44 @@ func GenerateDatabase(path string) error {
|
|||||||
// Initialize database entry
|
// Initialize database entry
|
||||||
entry := BPMDatabaseEntry{}
|
entry := BPMDatabaseEntry{}
|
||||||
entry.DownloadSize = info.Size()
|
entry.DownloadSize = info.Size()
|
||||||
|
entry.InstalledSize = 0
|
||||||
entry.Filepath, err = filepath.Rel(path, packagePath)
|
entry.Filepath, err = filepath.Rel(path, packagePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get package installed size
|
|
||||||
cmd := exec.Command("tar", "-t", "-v", "-f", packagePath, "files.tar.gz")
|
|
||||||
output, err := cmd.Output()
|
|
||||||
if err == nil {
|
|
||||||
entry.InstalledSize, err = strconv.ParseInt(strings.Fields(string(output))[2], 10, 64)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
} else if err.(*exec.ExitError).ExitCode() == 2 {
|
|
||||||
entry.InstalledSize = 0
|
|
||||||
} else {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get package info
|
// Get package info
|
||||||
entry.PackageInfo, err = ReadPacakgeInfoFromTarball(packagePath)
|
entry.PackageInfo, err = ReadPacakgeInfoFromTarball(packagePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get package installed size
|
||||||
|
if entry.PackageInfo.Type == "binary" {
|
||||||
|
cmd := exec.Command("tar", "xf", packagePath, "pkg.files", "-O")
|
||||||
|
output, err := cmd.Output()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, line := range strings.Split(string(output), "\n") {
|
||||||
|
line = strings.TrimSpace(line)
|
||||||
|
if line == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
stringEntry := strings.Split(line, " ")
|
||||||
|
if len(stringEntry) < 5 {
|
||||||
|
return fmt.Errorf("pkg.files is not formatted correctly")
|
||||||
|
}
|
||||||
|
size, err := strconv.ParseInt(stringEntry[len(stringEntry)-1], 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
entry.InstalledSize += size
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Add entry to database
|
// Add entry to database
|
||||||
if _, ok := database.Entries[entry.PackageInfo.Name]; ok {
|
if _, ok := database.Entries[entry.PackageInfo.Name]; ok {
|
||||||
return fmt.Errorf("package (%s) has already been added to the database", entry.PackageInfo.Name)
|
return fmt.Errorf("package (%s) has already been added to the database", entry.PackageInfo.Name)
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ import (
|
|||||||
|
|
||||||
type BPMUtilsConfig struct {
|
type BPMUtilsConfig struct {
|
||||||
PrivilegeEscalatorCmd string `yaml:"privilege_escalator_cmd"`
|
PrivilegeEscalatorCmd string `yaml:"privilege_escalator_cmd"`
|
||||||
|
DefaultMaintainer string `yaml:"default_maintainer,omitempty"`
|
||||||
|
AddDefaultMaintainer bool `yaml:"add_default_maintainer,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func ReadBPMUtilsConfig() (*BPMUtilsConfig, error) {
|
func ReadBPMUtilsConfig() (*BPMUtilsConfig, error) {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/drone/envsubst"
|
"github.com/drone/envsubst"
|
||||||
@@ -17,16 +18,20 @@ type PackageInfo struct {
|
|||||||
Revision int `yaml:"revision,omitempty"`
|
Revision int `yaml:"revision,omitempty"`
|
||||||
Url string `yaml:"url,omitempty"`
|
Url string `yaml:"url,omitempty"`
|
||||||
License string `yaml:"license,omitempty"`
|
License string `yaml:"license,omitempty"`
|
||||||
|
Maintainers []string `yaml:"maintainers,omitempty"`
|
||||||
Arch string `yaml:"architecture,omitempty"`
|
Arch string `yaml:"architecture,omitempty"`
|
||||||
OutputArch string `yaml:"output_architecture,omitempty"`
|
OutputArch string `yaml:"output_architecture,omitempty"`
|
||||||
Type string `yaml:"type,omitempty"`
|
Type string `yaml:"type,omitempty"`
|
||||||
Keep []string `yaml:"keep,omitempty"`
|
Keep []string `yaml:"keep,omitempty"`
|
||||||
Depends []string `yaml:"depends,omitempty"`
|
Depends []string `yaml:"depends,omitempty"`
|
||||||
|
RuntimeDepends []string `yaml:"runtime_depends,omitempty"`
|
||||||
OptionalDepends []string `yaml:"optional_depends,omitempty"`
|
OptionalDepends []string `yaml:"optional_depends,omitempty"`
|
||||||
MakeDepends []string `yaml:"make_depends,omitempty"`
|
MakeDepends []string `yaml:"make_depends,omitempty"`
|
||||||
|
CheckDepends []string `yaml:"check_depends,omitempty"`
|
||||||
Conflicts []string `yaml:"conflicts,omitempty"`
|
Conflicts []string `yaml:"conflicts,omitempty"`
|
||||||
Replaces []string `yaml:"replaces,omitempty"`
|
Replaces []string `yaml:"replaces,omitempty"`
|
||||||
Provides []string `yaml:"provides,omitempty"`
|
Provides []string `yaml:"provides,omitempty"`
|
||||||
|
Options []string `yaml:"options,omitempty"`
|
||||||
Downloads []PackageDownload `yaml:"downloads,omitempty"`
|
Downloads []PackageDownload `yaml:"downloads,omitempty"`
|
||||||
SplitPackages []*PackageInfo `yaml:"split_packages,omitempty"`
|
SplitPackages []*PackageInfo `yaml:"split_packages,omitempty"`
|
||||||
}
|
}
|
||||||
@@ -54,10 +59,12 @@ func ReadPackageInfo(data []byte) (*PackageInfo, error) {
|
|||||||
Keep: make([]string, 0),
|
Keep: make([]string, 0),
|
||||||
Depends: make([]string, 0),
|
Depends: make([]string, 0),
|
||||||
MakeDepends: make([]string, 0),
|
MakeDepends: make([]string, 0),
|
||||||
|
RuntimeDepends: make([]string, 0),
|
||||||
OptionalDepends: make([]string, 0),
|
OptionalDepends: make([]string, 0),
|
||||||
Conflicts: make([]string, 0),
|
Conflicts: make([]string, 0),
|
||||||
Replaces: make([]string, 0),
|
Replaces: make([]string, 0),
|
||||||
Provides: make([]string, 0),
|
Provides: make([]string, 0),
|
||||||
|
Options: make([]string, 0),
|
||||||
Downloads: make([]PackageDownload, 0),
|
Downloads: make([]PackageDownload, 0),
|
||||||
SplitPackages: make([]*PackageInfo, 0),
|
SplitPackages: make([]*PackageInfo, 0),
|
||||||
}
|
}
|
||||||
@@ -71,6 +78,10 @@ func ReadPackageInfo(data []byte) (*PackageInfo, error) {
|
|||||||
return pkgInfo, nil
|
return pkgInfo, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (pkgInfo *PackageInfo) GetFullVersion() string {
|
||||||
|
return pkgInfo.Version + "-" + strconv.Itoa(pkgInfo.Revision)
|
||||||
|
}
|
||||||
|
|
||||||
func ReadPacakgeInfoFromTarball(path string) (*PackageInfo, error) {
|
func ReadPacakgeInfoFromTarball(path string) (*PackageInfo, error) {
|
||||||
// Extract package info using tar
|
// Extract package info using tar
|
||||||
cmd := exec.Command("tar", "-x", "-f", path, "pkg.info", "-O")
|
cmd := exec.Command("tar", "-x", "-f", path, "pkg.info", "-O")
|
||||||
|
|||||||
Reference in New Issue
Block a user