9 Commits
22 changed files with 508 additions and 208 deletions
+4 -4
View File
@@ -33,7 +33,7 @@ Creating a package for BPM with these utilities is simple
bpm-setup -D my_package
```
2) This will create a directory named `my_package` containing all files required for bpm package creation
3) You may wish to edit the pkg.info metedata file inside the newly created directory to include dependencies or add/change other information. Here's an example of what a metedata file could look like
3) You may wish to edit the info.yml metedata file inside the newly created directory to include dependencies or add/change other information. Here's an example of what a metedata file could look like
```yaml
name: my_package
description: My package's description
@@ -61,9 +61,9 @@ downloads:
checksum: 9d19c8884cb22a594ba06a4caa6a3088e15ddfd4f3ede8c3b9e8f5cbb5a4a7a8
```
4) If you would like to bundle patches or other files with your package place them in the 'source-files' directory. They will be extracted to the same location as the source.sh file during compilation
5) You now need to edit your source.sh file which contains the compilation instructions for your package, the default source template comments should explain the basic process of compiling your program and how to edit it
6) When you are done editing your source.sh script run the following command to create a BPM source package archive. You may run the `bpm-package` command with no arguments to get an explanation of what each flag does
4) If you would like to bundle patches or other files with your package place them in the 'source-files' directory. They will be extracted to the same location as the recipe.sh file during compilation
5) You now need to edit your recipe.sh file which contains the compilation instructions for your package, the default source template comments should explain the basic process of compiling your program and how to edit it
6) When you are done editing your recipe.sh script run the following command to create a BPM source package archive. You may run the `bpm-package` command with no arguments to get an explanation of what each flag does
```
bpm-package
```
+1 -1
View File
@@ -1,4 +1,4 @@
# This is the source.sh script. It is executed by BPM in a temporary directory when compiling a source package
# This is the recipe.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
+1 -1
View File
@@ -1,4 +1,4 @@
# This is the source.sh script. It is executed by BPM in a temporary directory when compiling a source package
# This is the recipe.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
+1 -1
View File
@@ -1,4 +1,4 @@
# This is the source.sh script. It is executed by BPM in a temporary directory when compiling a source package
# This is the recipe.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
+1 -1
View File
@@ -1,4 +1,4 @@
# This is the source.sh script. It is executed by BPM in a temporary directory when compiling a source package
# This is the recipe.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
+1 -1
View File
@@ -1,4 +1,4 @@
# This is the source.sh script. It is executed by BPM in a temporary directory when compiling a source package
# This is the recipe.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
+1 -1
View File
@@ -1,4 +1,4 @@
# This is the source.sh script. It is executed by BPM in a temporary directory when compiling a source package
# This is the recipe.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
+2 -2
View File
@@ -1,4 +1,4 @@
# This is the source.sh script. It is executed by BPM in a temporary directory when compiling a source package
# This is the recipe.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
@@ -6,7 +6,7 @@
# 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')"
cargo fetch --locked --target "$(rustc --print host-tuple)"
}
# The build function is executed in the source directory
+4 -1
View File
@@ -8,6 +8,9 @@ require (
gopkg.in/yaml.v3 v3.0.1
)
require github.com/drone/envsubst v1.0.3 // indirect
require (
github.com/drone/envsubst v1.0.3 // indirect
github.com/knqyf263/go-rpm-version v0.0.0-20240918084003-2afd7dc6a38f // indirect
)
replace bpm-utils-shared => ../bpm-utils-shared
+2
View File
@@ -2,6 +2,8 @@ github.com/drone/envsubst v1.0.3 h1:PCIBwNDYjs50AsLZPYdfhSATKaRg/FJmDc2D6+C2x8g=
github.com/drone/envsubst v1.0.3/go.mod h1:N2jZmlMufstn1KEqvbHjw40h1KyTmnVzHcSc9bFiJ2g=
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/knqyf263/go-rpm-version v0.0.0-20240918084003-2afd7dc6a38f h1:xt29M2T6STgldg+WEP51gGePQCsQvklmP2eIhPIBK3g=
github.com/knqyf263/go-rpm-version v0.0.0-20240918084003-2afd7dc6a38f/go.mod h1:i4sF0l1fFnY1aiw08QQSwVAFxHEm311Me3WsU/X7nL0=
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
+148 -84
View File
@@ -5,6 +5,7 @@ import (
"bytes"
"fmt"
"io"
"io/fs"
"log"
"maps"
"os"
@@ -21,13 +22,13 @@ import (
var compile = flag.BoolP("compile", "c", false, "Compile BPM source package")
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 skipChecks = 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 force = flag.BoolP("force", "f", false, "Bypass warnings during package compilation")
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 updateInfo = flag.BoolP("update-info", "u", false, "Update the pkg.info file")
var updateInfo = flag.BoolP("update-info", "u", false, "Update the info.yml file")
var signPackage = flag.BoolP("sign", "s", false, "Sign package using GPG")
var yesAll = flag.BoolP("yes", "y", false, "Accept all confirmation prompts")
@@ -44,17 +45,21 @@ func main() {
if *compile {
compilePackage(outputFile)
}
if repo := bpmutilsshared.GetRepository(); repo != "" {
bpmutilsshared.UpdateDatabases(repo)
}
}
func runChecks() {
// Check if pkg.info file exists
if stat, err := os.Stat("pkg.info"); err != nil || !stat.Mode().IsRegular() {
log.Fatalf("Error: pkg.info does not exist or is not a regular file")
// Check if info.yml file exists
if stat, err := os.Stat("info.yml"); err != nil || !stat.Mode().IsRegular() {
log.Fatalf("Error: info.yml does not exist or is not a regular file")
}
// Check if source.sh file exists
if stat, err := os.Stat("source.sh"); err != nil || !stat.Mode().IsRegular() {
log.Fatalf("Error: pkg.info does not exist or is not a regular file")
// Check if recipe.sh file exists
if stat, err := os.Stat("recipe.sh"); err != nil || !stat.Mode().IsRegular() {
log.Fatalf("Error: info.yml does not exist or is not a regular file")
}
}
@@ -68,7 +73,7 @@ func createArchive() string {
filesToInclude := make([]string, 0)
// Include base files
filesToInclude = append(filesToInclude, "pkg.info", "source.sh")
filesToInclude = append(filesToInclude, "info.yml", "recipe.sh")
// Check if non-empty source-files directory exists and include it
if stat, err := os.Stat("source-files"); err == nil && stat.IsDir() {
@@ -87,13 +92,13 @@ func createArchive() string {
}
}
// Read pkg.info file
pkgInfo, err := bpmutilsshared.ReadPacakgeInfoFromFile("pkg.info")
// Read info.yml file
pkgInfo, err := bpmutilsshared.ReadPacakgeInfoFromFile("info.yml")
if err != nil {
log.Fatalf("Error: could not read package info: %s", err)
}
// Update pkg.info file
// Update info.yml file
if *updateInfo {
// Update download checksums
for i, download := range pkgInfo.Downloads {
@@ -125,51 +130,46 @@ func createArchive() string {
log.Fatalf("Could not marshal package info: %s", err)
}
// Stat pkg.info
stat, err := os.Stat("pkg.info")
// Stat info.yml
stat, err := os.Stat("info.yml")
if err != nil {
log.Fatalf("Could not stat pkg.info: %s", err)
log.Fatalf("Could not stat info.yml: %s", err)
}
// Write package info back to file
err = os.WriteFile("pkg.info", data.Bytes(), stat.Mode().Perm())
err = os.WriteFile("info.yml", data.Bytes(), stat.Mode().Perm())
if err != nil {
log.Fatalf("Could not write package info to pkg.info: %s", err)
log.Fatalf("Could not write package info to info.yml: %s", err)
}
}
// Remove old BPM archives in current directory
oldArchives, err := filepath.Glob("*.bpm")
if err != nil {
log.Printf("Warning: could not search for old BPM archives: %s", err)
// Remove old package from source dir
if repo := bpmutilsshared.GetRepository(); repo != "" {
removedFiles, err := RemoveSourcePackage(repo, pkgInfo.Name)
for _, file := range removedFiles {
fmt.Println("Removed " + file)
}
for _, bpmArchive := range oldArchives {
err = os.Remove(bpmArchive)
if err != nil {
log.Printf("Warning: could not remove old BPM archive (%s): %s", bpmArchive, err)
}
}
// 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)
log.Printf("Warning: could not remove old source packages: %s", err)
}
}
// Create filename
filename := fmt.Sprintf("%s-%s-%d-%s-src.bpm", pkgInfo.Name, pkgInfo.Version, pkgInfo.Revision, pkgInfo.Arch)
if repo := bpmutilsshared.GetRepository(); repo != "" {
// Create source directory
os.MkdirAll(path.Join(repo, "source", pkgInfo.Arch), 0755)
filename = path.Join(repo, "source", pkgInfo.Arch, filename)
}
// Create archive using tar
args := make([]string, 0)
args = append(args, "-c", "--owner=0", "--group=0", "--no-same-owner", "-f", filename)
args = append(args, filesToInclude...)
cmd := exec.Command("tar", args...)
cmd := exec.Command("tar", "cf", filename,
"--sort=name",
"--pax-option=exthdr.name=%d/PaxHeaders/%f,delete=atime,delete=ctime",
"--mtime=UTC 1970-01-01",
"--owner=0", "--group=0", "--numeric-owner")
cmd.Args = append(cmd.Args, filesToInclude...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err = cmd.Run()
@@ -179,7 +179,7 @@ func createArchive() string {
// Sign package
if *signPackage {
cmd := exec.Command("gpg", "--detach-sign", filename)
cmd := exec.Command("gpg", "--yes", "--detach-sign", filename)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Stdin = os.Stdin
@@ -204,24 +204,18 @@ func compilePackage(archive string) {
// Setup compile command
args := make([]string, 0)
args = append(args, "compile")
if *verbose {
args = append(args, "-v")
addArg := func(condition bool, arg string) {
if condition {
args = append(args, arg)
}
if *skipCheck {
args = append(args, "-s")
}
if *keepCompilationFiles {
args = append(args, "-k")
}
if *installDepends {
args = append(args, "-d")
}
if *compilationJobs > 0 {
args = append(args, "-j"+strconv.Itoa(*compilationJobs))
}
if *yesAll {
args = append(args, "-y")
}
addArg(*verbose, "-v")
addArg(*skipChecks, "--skip-checks")
addArg(*keepCompilationFiles, "-k")
addArg(*installDepends, "-d")
addArg(*compilationJobs > 0, "-j"+strconv.Itoa(*compilationJobs))
addArg(*yesAll, "-y")
addArg(*force, "-f")
args = append(args, "--output-fd=3")
args = append(args, archive)
cmd := exec.Command("bpm", args...)
@@ -262,31 +256,22 @@ func compilePackage(archive string) {
for _, line := range strings.Split(strings.TrimSpace(string(cmdOutput)), "\n") {
// Read generated package info
pkgInfo, err := bpmutilsshared.ReadPacakgeInfoFromTarball(line)
if repo := bpmutilsshared.GetRepository(); repo != "" && *moveToBinaryDir {
// Remove old package from binary dir
if database, err := bpmutilsshared.ReadDatabase(path.Join(repo, "binary/database.bpmdb")); err == nil {
if entry, ok := database.Entries[pkgInfo.Name]; ok {
pkgFilepath := path.Join(repo, "binary", entry.Filepath)
err := os.Remove(pkgFilepath)
if err != nil {
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)
}
}
}
}
// Move package to binary dir
if err != nil {
log.Fatalf("Error: could not read package info: %s", err)
}
if repo := bpmutilsshared.GetRepository(); repo != "" {
// Remove old package from binary dir
removedFiles, err := RemoveBinaryPackage(repo, pkgInfo.Name)
for _, file := range removedFiles {
fmt.Println("Removed " + file)
}
if err != nil {
log.Printf("Warning: could not remove old binary packages: %s", err)
}
// Move package to binary dir
newPath := path.Join(repo, "binary", pkgInfo.Arch, path.Base(line))
os.MkdirAll(path.Dir(newPath), 0755)
os.Rename(line, newPath)
@@ -296,14 +281,11 @@ func compilePackage(archive string) {
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 := exec.Command("gpg", "--yes", "--detach-sign", v)
cmd.Dir = path.Dir(v)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
@@ -359,3 +341,85 @@ func setupFlagsAndHelp(usage, desc string) {
}
flag.Parse()
}
func RemoveSourcePackage(repo, pkgName string) (removedFiles []string, err error) {
if _, err := os.Stat(path.Join(repo, "source")); err != nil {
return removedFiles, nil
}
err = filepath.Walk(path.Join(repo, "source"), func(packagePath string, info fs.FileInfo, err error) error {
if !strings.HasSuffix(packagePath, ".bpm") {
return nil
}
// Get package info
pkgInfo, err := bpmutilsshared.ReadPacakgeInfoFromTarball(packagePath)
if err != nil {
return err
}
if pkgInfo.Name != pkgName {
return nil
}
// Remove package and its signature
err = os.Remove(packagePath)
if err != nil {
return err
}
if relPath, err := filepath.Rel(repo, packagePath); err != nil {
removedFiles = append(removedFiles, packagePath)
} else {
removedFiles = append(removedFiles, relPath)
}
err = os.Remove(packagePath + ".sig")
if err != nil && !os.IsNotExist(err) {
return err
}
return nil
})
return removedFiles, err
}
func RemoveBinaryPackage(repo, pkgName string) (removedFiles []string, err error) {
if _, err := os.Stat(path.Join(repo, "binary")); err != nil {
return removedFiles, nil
}
err = filepath.Walk(path.Join(repo, "binary"), func(packagePath string, info fs.FileInfo, err error) error {
if !strings.HasSuffix(packagePath, ".bpm") {
return nil
}
// Get package info
pkgInfo, err := bpmutilsshared.ReadPacakgeInfoFromTarball(packagePath)
if err != nil {
return err
}
if pkgInfo.Name != pkgName {
return nil
}
// Remove package and its signature
err = os.Remove(packagePath)
if err != nil {
return err
}
if relPath, err := filepath.Rel(repo, packagePath); err != nil {
removedFiles = append(removedFiles, packagePath)
} else {
removedFiles = append(removedFiles, relPath)
}
err = os.Remove(packagePath + ".sig")
if err != nil && !os.IsNotExist(err) {
return err
}
return nil
})
return removedFiles, err
}
+4 -1
View File
@@ -8,6 +8,9 @@ require (
gopkg.in/yaml.v3 v3.0.1
)
require github.com/drone/envsubst v1.0.3 // indirect
require (
github.com/drone/envsubst v1.0.3 // indirect
github.com/knqyf263/go-rpm-version v0.0.0-20240918084003-2afd7dc6a38f // indirect
)
replace bpm-utils-shared => ../bpm-utils-shared
+2
View File
@@ -2,6 +2,8 @@ github.com/drone/envsubst v1.0.3 h1:PCIBwNDYjs50AsLZPYdfhSATKaRg/FJmDc2D6+C2x8g=
github.com/drone/envsubst v1.0.3/go.mod h1:N2jZmlMufstn1KEqvbHjw40h1KyTmnVzHcSc9bFiJ2g=
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/knqyf263/go-rpm-version v0.0.0-20240918084003-2afd7dc6a38f h1:xt29M2T6STgldg+WEP51gGePQCsQvklmP2eIhPIBK3g=
github.com/knqyf263/go-rpm-version v0.0.0-20240918084003-2afd7dc6a38f/go.mod h1:i4sF0l1fFnY1aiw08QQSwVAFxHEm311Me3WsU/X7nL0=
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
+163 -72
View File
@@ -147,7 +147,7 @@ func createRepository(name, description string) {
log.Fatalf("Error: could not write to file: %s", err)
}
err = os.Mkdir(path.Join(name, "source"), 0755)
err = os.Mkdir(path.Join(name, "recipes"), 0755)
if err != nil {
log.Fatalf("Error: could not create directory: %s", err)
}
@@ -185,15 +185,15 @@ func checkVersionsFunc(repo string) {
directories := make([]string, 0)
if currentFlagSet.NArg() > 0 {
for _, dir := range currentFlagSet.Args() {
if _, err := os.Stat(path.Join(repo, "source", dir, "pkg.info")); err != nil {
log.Fatalf("Error: could not find pkg.info file in directory (%s): %s", dir, err)
if _, err := os.Stat(path.Join(repo, "recipes", dir, "info.yml")); err != nil {
log.Fatalf("Error: could not find info.yml file in directory (%s): %s", dir, err)
}
directories = append(directories, path.Join(repo, "source", dir))
directories = append(directories, path.Join(repo, "recipes", dir))
}
} else {
// Loop through each directory with a 'pkg.info' file
err := filepath.Walk(path.Join(repo, "source"), func(path string, info fs.FileInfo, err error) error {
if filepath.Base(path) == "pkg.info" {
// Loop through each directory with a 'info.yml' file
err := filepath.Walk(path.Join(repo, "recipes"), func(path string, info fs.FileInfo, err error) error {
if filepath.Base(path) == "info.yml" {
directories = append(directories, filepath.Dir(path))
}
return nil
@@ -212,7 +212,7 @@ func checkVersionsFunc(repo string) {
}, 0)
pkgsUpToDate := 0
for _, dir := range directories {
pkgInfo, err := bpmutilsshared.ReadPacakgeInfoFromFile(path.Join(dir, "pkg.info"))
pkgInfo, err := bpmutilsshared.ReadPacakgeInfoFromFile(path.Join(dir, "info.yml"))
if err != nil {
log.Fatalf("Could not read package info: %s", err)
}
@@ -294,7 +294,7 @@ func checkVersionsFunc(repo string) {
encoder.Encode(pkgInfo)
// Write package information
err := os.WriteFile(path.Join(dir, "pkg.info"), data.Bytes(), 0644)
err := os.WriteFile(path.Join(dir, "info.yml"), data.Bytes(), 0644)
if err != nil {
log.Printf("Warning: could not write new version for package (%s) to file: %s", pkgInfo.Name, err)
}
@@ -327,7 +327,11 @@ func checkVersionsFunc(repo string) {
keys := slices.Collect(maps.Keys(pkgsWithUpdates))
sort.Strings(keys)
for _, pkg := range keys {
if bpmutilsshared.CompareVersions(pkgsWithUpdates[pkg].NewVersion, pkgsWithUpdates[pkg].OldVersion) >= 0 {
fmt.Printf("Update available for package (%s): %s -> %s", pkg, pkgsWithUpdates[pkg].OldVersion, pkgsWithUpdates[pkg].NewVersion)
} else {
fmt.Printf("Downgrade(?) available for package (%s): %s -> %s", pkg, pkgsWithUpdates[pkg].OldVersion, pkgsWithUpdates[pkg].NewVersion)
}
if cachedVersions[pkg].OnHold {
fmt.Print(" (On hold)")
}
@@ -375,8 +379,8 @@ func holdPackage(repo string) {
}
// 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)
if _, err := os.Stat(path.Join(repo, "recipes", pkgName, "info.yml")); err != nil {
log.Fatalf("Error: could not find info.yml file in directory (%s): %s", pkgName, err)
}
// Read version cache
@@ -435,44 +439,40 @@ func holdPackage(repo string) {
}
func listPackagesFunc(repo string) {
// Read package recipes
pkgs := bpmutilsshared.ReadRepositoryRecipes(repo)
// Read databases
sourceDatabase, err := bpmutilsshared.ReadDatabase(path.Join(repo, "source/database.bpmdb"))
if err != nil {
return
}
sourceDatabase, _ := bpmutilsshared.ReadDatabase(path.Join(repo, "source/database.bpmdb"))
binaryDatabase, _ := bpmutilsshared.ReadDatabase(path.Join(repo, "binary/database.bpmdb"))
binaryDatabase, err := bpmutilsshared.ReadDatabase(path.Join(repo, "binary/database.bpmdb"))
if err != nil {
binaryDatabase = &bpmutilsshared.BPMDatabase{}
}
for _, pkg := range pkgs {
fmt.Printf("%s (%s):\n", pkg.Name, pkg.Version)
// Sort database entries
entriesSorted := slices.Collect(maps.Values(sourceDatabase.Entries))
sort.Slice(entriesSorted, func(i, j int) bool {
return entriesSorted[i].PackageInfo.Name < entriesSorted[j].PackageInfo.Name
})
// Loop through each entry
for _, entry := range entriesSorted {
if len(entry.PackageInfo.SplitPackages) > 0 {
for _, splitPkg := range entry.PackageInfo.SplitPackages {
// Handle split packages
additionalText := ""
if binaryEntry, ok := binaryDatabase.Entries[splitPkg.Name]; !ok {
additionalText += "(Binary package missing) "
} else if fmt.Sprintf("%s-%d", binaryEntry.PackageInfo.Version, binaryEntry.PackageInfo.Revision) != fmt.Sprintf("%s-%d", entry.PackageInfo.Version, entry.PackageInfo.Revision) {
additionalText += "(Binary package version mismatch) "
}
fmt.Printf("%s %s-%d %s\n", splitPkg.Name, entry.PackageInfo.Version, entry.PackageInfo.Revision, additionalText)
// Show source package version
if sourceDatabase != nil {
if entry, ok := sourceDatabase.Entries[pkg.Name]; ok {
if entry.PackageInfo.Version == pkg.Version {
fmt.Printf(" Source package: %s\n", entry.PackageInfo.Version)
} else {
fmt.Printf(" Source package: %s ≠ %s (Version mismatch)\n", entry.PackageInfo.Version, pkg.Version)
}
} else {
additionalText := ""
if binaryEntry, ok := binaryDatabase.Entries[entry.PackageInfo.Name]; !ok {
additionalText += "(Binary package missing) "
} else if fmt.Sprintf("%s-%d", binaryEntry.PackageInfo.Version, binaryEntry.PackageInfo.Revision) != fmt.Sprintf("%s-%d", entry.PackageInfo.Version, entry.PackageInfo.Revision) {
additionalText += "(Binary package version mismatch) "
fmt.Println(" Source package not found!")
}
}
// Show binary package version
if binaryDatabase != nil {
if entry, ok := binaryDatabase.Entries[pkg.Name]; ok {
if entry.PackageInfo.Version == pkg.Version {
fmt.Printf(" Binary package: %s\n", entry.PackageInfo.Version)
} else {
fmt.Printf(" Binary package: %s ≠ %s (Version mismatch)\n", entry.PackageInfo.Version, pkg.Version)
}
} else {
fmt.Println(" Binary package not found!")
}
fmt.Printf("%s %s-%d %s\n", entry.PackageInfo.Name, entry.PackageInfo.Version, entry.PackageInfo.Revision, additionalText)
}
}
}
@@ -489,31 +489,33 @@ func compileAllPackagesFunc(repo string) {
log.Fatalf("Error: failed to read config: %s", err)
}
// Ensure database is updated
bpmutilsshared.UpdateDatabases(repo)
// Read package recipes
pkgs := bpmutilsshared.ReadRepositoryRecipes(repo)
pkgsMap := make(map[string]bpmutilsshared.PackageInfo)
for _, pkg := range pkgs {
pkgsMap[pkg.Name] = pkg
// Add split packages
for _, splitPkg := range pkg.SplitPackages {
if _, ok := pkgsMap[splitPkg.Name]; !ok {
pkgsMap[splitPkg.Name] = pkg
}
}
}
// 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 {
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!")
return fmt.Errorf("circular dependency found")
}
marked[pkgInfo.Name] = 1
@@ -523,47 +525,134 @@ func compileAllPackagesFunc(repo string) {
depends = append(depends, pkgInfo.MakeDepends...)
for _, depend := range depends {
dependName, _, _ := bpmutilsshared.SplitPkgNameAndVersion(depend)
// Find package in repository
dependEntry, ok := sourceDatabase.Entries[depend]
dependInfo, ok := pkgsMap[dependName]
if !ok {
// Search for virtual package
for _, entry := range sourceDatabase.Entries {
if slices.Contains(entry.PackageInfo.Provides, depend) {
dependEntry = entry
for _, pkg := range pkgsMap {
if slices.Contains(pkg.Provides, dependName) {
dependInfo = pkg
ok = true
break
}
}
if !ok {
// Try to see if package exists in BPM's other repositories
err := exec.Command("bpm", "query", "-d", depend).Run()
if err != nil {
return fmt.Errorf("could not find package (%s) in any database", depend)
}
continue
}
}
err := visit(dependEntry.PackageInfo)
if err != nil && verbose {
fmt.Printf("Circular dependency found! (%s -> %s)\n", pkgInfo.Name, dependEntry.PackageInfo.Name)
err := visit(dependInfo)
if err != nil {
if strings.Contains(err.Error(), "circular") {
if verbose {
fmt.Printf("Circular dependency found! (%s -> %s)\n", pkgInfo.Name, dependInfo.Name)
}
} else {
log.Fatalf("Error: could not resolve dependencies: %s", err)
}
}
}
marked[pkgInfo.Name] = 2
sorted = append(sorted, *pkgInfo)
sorted = append(sorted, pkgInfo)
return nil
}
for _, entry := range packages {
if mark, _ := marked[entry.PackageInfo.Name]; mark != 2 {
visit(entry.PackageInfo)
for _, pkg := range pkgs {
if mark, _ := marked[pkg.Name]; mark != 2 {
visit(pkg)
}
}
// 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() {
skip := false
if modifiedOnly {
skip = true
// Check if required version is valid
for _, depend := range pkgInfo.Depends {
if !strings.ContainsRune(depend, '=') {
continue
}
dependName, _, _ := bpmutilsshared.SplitPkgNameAndVersion(depend)
if !bpmutilsshared.EvaluateDependency(depend, pkgsMap[dependName].Version) {
skip = false
break
}
}
for _, depend := range pkgInfo.MakeDepends {
if !strings.ContainsRune(depend, '=') {
continue
}
dependName, _, _ := bpmutilsshared.SplitPkgNameAndVersion(depend)
if !bpmutilsshared.EvaluateDependency(depend, pkgsMap[dependName].Version) {
skip = false
break
}
}
// Check if source database entry is not synced
if sourceDatabase != nil {
if len(pkgInfo.SplitPackages) != 0 {
sourcePkgInfo, ok := sourceDatabase.Entries[pkgInfo.Name]
if ok {
hasSplitPkg := func(name string) bool {
return slices.ContainsFunc(sourcePkgInfo.PackageInfo.SplitPackages, func(splitPkg *bpmutilsshared.PackageInfo) bool {
return name == splitPkg.Name
})
}
for _, splitPkg := range pkgInfo.SplitPackages {
if !hasSplitPkg(splitPkg.Name) || sourcePkgInfo.PackageInfo.GetFullVersion() != pkgInfo.GetFullVersion() {
skip = false
break
}
}
} else {
skip = false
}
} else {
if sourcePkgInfo, ok := sourceDatabase.Entries[pkgInfo.Name]; !ok || sourcePkgInfo.PackageInfo.GetFullVersion() != pkgInfo.GetFullVersion() {
skip = false
}
}
}
// Check if binary database entry is not synced
if binaryDatabase != nil {
if len(pkgInfo.SplitPackages) != 0 {
for _, splitPkg := range pkgInfo.SplitPackages {
if binaryPkgInfo, ok := binaryDatabase.Entries[splitPkg.Name]; !ok || binaryPkgInfo.PackageInfo.GetFullVersion() != pkgInfo.GetFullVersion() {
skip = false
break
}
}
} else {
if binaryPkgInfo, ok := binaryDatabase.Entries[pkgInfo.Name]; !ok || binaryPkgInfo.PackageInfo.GetFullVersion() != pkgInfo.GetFullVersion() {
skip = false
}
}
}
}
if skip {
continue
}
if showOrder {
@@ -581,17 +670,18 @@ func compileAllPackagesFunc(repo string) {
}
// Compile source package
cmd = exec.Command("bpm-package", "-cdvusmy")
cmd = exec.Command("bpm-package", "-cdusy")
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Dir = path.Join(repo, "source", pkgInfo.Name)
cmd.Dir = path.Join(repo, "recipes", 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
if !showOrder {
cmd := exec.Command(config.PrivilegeEscalatorCmd, "sh", "-c", "bpm u -y")
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
@@ -599,6 +689,7 @@ func compileAllPackagesFunc(repo string) {
if err := cmd.Run(); err != nil {
log.Fatalf("Error: could not update packages): %s", err)
}
}
}
func readEnvFile(repo string) error {
+4 -1
View File
@@ -8,6 +8,9 @@ require (
gopkg.in/yaml.v3 v3.0.1
)
require github.com/drone/envsubst v1.0.3 // indirect
require (
github.com/drone/envsubst v1.0.3 // indirect
github.com/knqyf263/go-rpm-version v0.0.0-20240918084003-2afd7dc6a38f // indirect
)
replace bpm-utils-shared => ../bpm-utils-shared
+2
View File
@@ -2,6 +2,8 @@ github.com/drone/envsubst v1.0.3 h1:PCIBwNDYjs50AsLZPYdfhSATKaRg/FJmDc2D6+C2x8g=
github.com/drone/envsubst v1.0.3/go.mod h1:N2jZmlMufstn1KEqvbHjw40h1KyTmnVzHcSc9bFiJ2g=
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/knqyf263/go-rpm-version v0.0.0-20240918084003-2afd7dc6a38f h1:xt29M2T6STgldg+WEP51gGePQCsQvklmP2eIhPIBK3g=
github.com/knqyf263/go-rpm-version v0.0.0-20240918084003-2afd7dc6a38f/go.mod h1:i4sF0l1fFnY1aiw08QQSwVAFxHEm311Me3WsU/X7nL0=
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
+41 -28
View File
@@ -10,14 +10,12 @@ import (
"os"
"os/exec"
"path"
"path/filepath"
"strings"
flag "github.com/spf13/pflag"
yaml "gopkg.in/yaml.v3"
)
var directory = flag.StringP("directory", "D", "", "Path to package directory")
var name = flag.StringP("name", "n", "", "Set the package name")
var description = flag.StringP("description", "d", "Default Package Description", "Set the description")
var version = flag.StringP("version", "v", "1.0", "Set the package version")
@@ -26,20 +24,35 @@ var license = flag.StringP("license", "l", "", "Set the package licenses")
var template = flag.StringP("template", "t", "gnu-configure", "Set the package template")
var git = flag.BoolP("git", "g", true, "Create git repository")
var directory = ""
func main() {
// Setup flags and help
setupFlagsAndHelp("bpm-setup <options>", "Sets up files and directories for BPM source package creation")
// Trim package name
*name = strings.TrimSpace(*name)
// Show command help if no directory name is given
if *directory == "" {
log.Println("Error: directory flag is required")
if *name == "" {
log.Println("Error: name flag is required")
flag.Usage()
os.Exit(1)
}
// Set package name to directory name if empty
if *name == "" {
*name = filepath.Base(*directory)
// Get current repository
repo := bpmutilsshared.GetRepository()
// Set directory
if repo != "" {
directory = path.Join(repo, "recipes", *name)
} else {
workDir, err := os.Getwd()
if err != nil {
log.Fatalf("Error: could not get working directory")
}
directory = path.Join(workDir, *name)
}
// run checks
@@ -62,25 +75,29 @@ func main() {
}
func runChecks() {
if strings.TrimSpace(*directory) == "" {
log.Fatalf("No directory was specified!")
// Check if package name is valid
if *name == "" {
log.Fatalf("Error: no package name was specified!")
}
if strings.TrimSpace(*name) == "" {
log.Fatalf("No package name was specified!")
// Check if parent directory is valid
if _, err := os.Stat(path.Dir(directory)); err != nil {
log.Fatalf("Error: %s is not a valid directory: %s", path.Dir(directory), err)
}
// Check if package directory exists
if _, err := os.Stat(directory); err == nil {
log.Fatalf("Error: %s already exists", directory)
}
// Check if template file is valid
if stat, err := os.Stat(path.Join("/etc/bpm-utils/templates/", *template)); err != nil || stat.IsDir() {
log.Fatalf("%s is not a valid template file!", *template)
log.Fatalf("Error: '%s' is not a valid template file!", *template)
}
}
func showSummary() {
absPath, err := filepath.Abs(strings.TrimSpace(*directory))
if err != nil {
log.Fatalf("Failed to determine absolute path: %s", err)
}
fmt.Printf("Setting up package directory at %s with the following information:\n", absPath)
fmt.Printf("Setting up package directory at %s with the following information:\n", directory)
fmt.Printf("Package name: %s\n", strings.TrimSpace(*name))
fmt.Printf("Package description: %s\n", *description)
fmt.Printf("Package version: %s\n", *version)
@@ -114,12 +131,8 @@ func createDirectory() {
log.Fatalf("Error: failed to read config: %s", err)
}
// Trim spaces
*directory = strings.TrimSpace(*directory)
*name = strings.TrimSpace(*name)
// Create directory
err = os.Mkdir(*directory, 0755)
err = os.Mkdir(directory, 0755)
if err != nil {
log.Fatalf("Error: could not create directory: %s", err)
}
@@ -153,13 +166,13 @@ func createDirectory() {
encoder.Encode(&pkgInfo)
// Write package info to file
err = os.WriteFile(path.Join(*directory, "pkg.info"), buffer.Bytes(), 0644)
err = os.WriteFile(path.Join(directory, "info.yml"), buffer.Bytes(), 0644)
if err != nil {
log.Fatalf("Could not write to pkg.info: %s", err)
log.Fatalf("Could not write to info.yml: %s", err)
}
// Create source-files directory
err = os.Mkdir(path.Join(*directory, "source-files"), 0755)
err = os.Mkdir(path.Join(directory, "source-files"), 0755)
if err != nil {
log.Fatalf("Error: could not create directory: %s", err)
}
@@ -174,7 +187,7 @@ func createDirectory() {
// Replace variables in template file
input = []byte(replaceVariables(string(input)))
err = os.WriteFile(path.Join(*directory, "source.sh"), input, 0644)
err = os.WriteFile(path.Join(directory, "recipe.sh"), input, 0644)
if err != nil {
log.Fatalf("Error: could not write to source file: %s", err)
return
@@ -182,7 +195,7 @@ func createDirectory() {
// Create git repository
if git != nil && *git {
err = exec.Command("git", "init", *directory).Run()
err = exec.Command("git", "init", directory).Run()
if err != nil {
log.Fatalf("Error: could not initialize git repository: %s", err)
}
@@ -193,7 +206,7 @@ func createDirectory() {
return
}
defer defaultGitignoreFile.Close()
newGitignoreFile, err := os.OpenFile(path.Join(*directory, ".gitignore"), os.O_CREATE|os.O_WRONLY, 0644)
newGitignoreFile, err := os.OpenFile(path.Join(directory, ".gitignore"), os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
log.Fatalf("Error: could not create .gitignore file: %s", err)
}
+2 -2
View File
@@ -72,7 +72,7 @@ func GenerateDatabase(path string) error {
// Get package installed size
if entry.PackageInfo.Type == "binary" {
cmd := exec.Command("tar", "xf", packagePath, "pkg.files", "-O")
cmd := exec.Command("tar", "xf", packagePath, "files.txt", "-O")
output, err := cmd.Output()
if err != nil {
return err
@@ -85,7 +85,7 @@ func GenerateDatabase(path string) error {
}
stringEntry := strings.Split(line, " ")
if len(stringEntry) < 5 {
return fmt.Errorf("pkg.files is not formatted correctly")
return fmt.Errorf("files.txt is not formatted correctly")
}
size, err := strconv.ParseInt(stringEntry[len(stringEntry)-1], 10, 64)
if err != nil {
+2
View File
@@ -5,3 +5,5 @@ go 1.23
require gopkg.in/yaml.v3 v3.0.1
require github.com/drone/envsubst v1.0.3
require github.com/knqyf263/go-rpm-version v0.0.0-20240918084003-2afd7dc6a38f // indirect
+2
View File
@@ -2,6 +2,8 @@ github.com/drone/envsubst v1.0.3 h1:PCIBwNDYjs50AsLZPYdfhSATKaRg/FJmDc2D6+C2x8g=
github.com/drone/envsubst v1.0.3/go.mod h1:N2jZmlMufstn1KEqvbHjw40h1KyTmnVzHcSc9bFiJ2g=
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/knqyf263/go-rpm-version v0.0.0-20240918084003-2afd7dc6a38f h1:xt29M2T6STgldg+WEP51gGePQCsQvklmP2eIhPIBK3g=
github.com/knqyf263/go-rpm-version v0.0.0-20240918084003-2afd7dc6a38f/go.mod h1:i4sF0l1fFnY1aiw08QQSwVAFxHEm311Me3WsU/X7nL0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+85 -1
View File
@@ -8,6 +8,7 @@ import (
"strings"
"github.com/drone/envsubst"
version "github.com/knqyf263/go-rpm-version"
"gopkg.in/yaml.v3"
)
@@ -32,10 +33,27 @@ type PackageInfo struct {
Replaces []string `yaml:"replaces,omitempty"`
Provides []string `yaml:"provides,omitempty"`
Options []string `yaml:"options,omitempty"`
Flags []PackageFlag `yaml:"flags,omitempty"`
Downloads []PackageDownload `yaml:"downloads,omitempty"`
SplitPackages []*PackageInfo `yaml:"split_packages,omitempty"`
}
type PackageFlag struct {
Name string `yaml:"name"`
DefaultValue string `yaml:"default_value"`
BuiltValue string `yaml:"built_value"`
AcceptedValues []PackageAcceptedValue `yaml:"accepted_values,omitempty"`
}
type PackageAcceptedValue struct {
Value string `yaml:"value"`
Depends []string `yaml:"depends,omitempty"`
RuntimeDepends []string `yaml:"runtime_depends,omitempty"`
OptionalDepends []string `yaml:"optional_depends,omitempty"`
MakeDepends []string `yaml:"make_depends,omitempty"`
CheckDepends []string `yaml:"check_depends,omitempty"`
}
type PackageDownload struct {
Url string `yaml:"url"`
Type string `yaml:"type,omitempty"`
@@ -84,7 +102,7 @@ func (pkgInfo *PackageInfo) GetFullVersion() string {
func ReadPacakgeInfoFromTarball(path string) (*PackageInfo, error) {
// Extract package info using tar
cmd := exec.Command("tar", "-x", "-f", path, "pkg.info", "-O")
cmd := exec.Command("tar", "-x", "-f", path, "info.yml", "-O")
output, err := cmd.Output()
if err != nil {
return nil, err
@@ -179,3 +197,69 @@ func (pkgDownload *PackageDownload) CalculateChecksum(pkgInfo *PackageInfo) (str
return "", fmt.Errorf("unknown download type (%s)", pkgDownload.Type)
}
}
func CompareVersions(version1, version2 string) int {
v1 := version.NewVersion(version1)
v2 := version.NewVersion(version2)
return v1.Compare(v2)
}
func SplitPkgNameAndVersion(pkg string) (string, string, string) {
if strings.Contains(pkg, ">=") {
pkgSplit := strings.SplitN(pkg, ">=", 2)
pkgName := pkgSplit[0]
pkgVersion := pkgSplit[1]
return pkgName, ">=", pkgVersion
} else if strings.Contains(pkg, ">") {
pkgSplit := strings.SplitN(pkg, ">", 2)
pkgName := pkgSplit[0]
pkgVersion := pkgSplit[1]
return pkgName, ">", pkgVersion
} else if strings.Contains(pkg, "<=") {
pkgSplit := strings.SplitN(pkg, "<=", 2)
pkgName := pkgSplit[0]
pkgVersion := pkgSplit[1]
return pkgName, "<=", pkgVersion
} else if strings.Contains(pkg, "<") {
pkgSplit := strings.SplitN(pkg, "<", 2)
pkgName := pkgSplit[0]
pkgVersion := pkgSplit[1]
return pkgName, "<", pkgVersion
} else if strings.Contains(pkg, "=") {
pkgSplit := strings.SplitN(pkg, "=", 2)
pkgName := pkgSplit[0]
pkgVersion := pkgSplit[1]
return pkgName, "=", pkgVersion
}
return pkg, "", ""
}
func EvaluateDependency(pkg, matchVersion string) bool {
_, comparisonSymbol, pkgVersion := SplitPkgNameAndVersion(pkg)
switch comparisonSymbol {
case ">=":
return CompareVersions(matchVersion, pkgVersion) >= 0
case ">":
return CompareVersions(matchVersion, pkgVersion) > 0
case "<=":
return CompareVersions(matchVersion, pkgVersion) <= 0
case "<":
return CompareVersions(matchVersion, pkgVersion) < 0
case "=":
if cutPkgVersion, ok := strings.CutSuffix(pkgVersion, "*"); ok {
return strings.HasPrefix(matchVersion, cutPkgVersion)
} else {
return CompareVersions(matchVersion, pkgVersion) == 0
}
default:
return true
}
}
+29
View File
@@ -3,6 +3,7 @@ package bpm_utils_shared
import (
"os"
"path"
"sort"
)
func GetRepository() string {
@@ -23,3 +24,31 @@ func GetRepository() string {
}
return dir
}
func ReadRepositoryRecipes(repository string) []PackageInfo {
// Read package recipes
recipeDirs, err := os.ReadDir(path.Join(repository, "recipes"))
if err != nil {
return nil
}
pkgs := make([]PackageInfo, 0)
for _, dir := range recipeDirs {
pkgInfoPath := path.Join(repository, "recipes", dir.Name(), "info.yml")
if _, err := os.Stat(pkgInfoPath); err != nil {
continue
}
pkgInfo, err := ReadPacakgeInfoFromFile(pkgInfoPath)
if err == nil {
pkgs = append(pkgs, *pkgInfo)
}
}
// Sort package recipes
sort.Slice(pkgs, func(i, j int) bool {
return pkgs[i].Name < pkgs[j].Name
})
return pkgs
}