mirror of
https://github.com/EnumeratedDev/bpm-utils.git
synced 2026-09-16 02:56:11 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
66e1aacc5f
|
||
|
|
8034c7d7ea
|
||
|
|
d781c30146
|
||
|
|
8eb771111c
|
||
|
|
3f84dd4bc3
|
||
|
|
e1daa498e8
|
||
|
|
68ffb7972f
|
||
|
|
9114bb4148
|
||
|
|
5dbdfdd4c1
|
||
|
|
eb13b2653d
|
||
|
|
581c864f1d
|
||
|
|
7e7b8487ea
|
||
|
|
a7f751c094
|
||
|
|
54e192f220
|
||
|
|
c508ce6a01
|
||
|
|
2b81dad6cf
|
||
|
|
82777ebac1
|
||
|
|
b20766bddb
|
||
|
|
0ff9eb9cf2
|
||
|
|
4371b7f0e3
|
||
|
|
65849fdf86
|
||
|
|
a64ad39ca7
|
||
|
|
bf9874af6b
|
||
|
|
07a9e8c9d2
|
||
|
|
598e6710f4
|
||
|
|
902fcbf296
|
||
|
|
03bf97b8d8
|
||
|
|
5240ae4a8c
|
||
|
|
9d03b5b423
|
||
|
|
f17bc777d9
|
||
|
|
154f546b7f
|
||
|
|
c4a0e9f860
|
||
|
|
b9d7dfd9d0
|
@@ -33,7 +33,7 @@ Creating a package for BPM with these utilities is simple
|
|||||||
bpm-setup -D my_package
|
bpm-setup -D my_package
|
||||||
```
|
```
|
||||||
2) This will create a directory named `my_package` containing all files required for bpm package creation
|
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
|
```yaml
|
||||||
name: my_package
|
name: my_package
|
||||||
description: My package's description
|
description: My package's description
|
||||||
@@ -61,9 +61,9 @@ downloads:
|
|||||||
checksum: 9d19c8884cb22a594ba06a4caa6a3088e15ddfd4f3ede8c3b9e8f5cbb5a4a7a8
|
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
|
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 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
|
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 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
|
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
|
bpm-package
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
# Exclude bpm archives
|
# Ignore BPM archives and signatures
|
||||||
*.bpm
|
*.bpm
|
||||||
|
*.bpm.sig
|
||||||
|
|||||||
@@ -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 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
|
# BPM Expects the output files to be present in the automatically created 'output' directory which can be accessed using $BPM_OUTPUT
|
||||||
|
|
||||||
|
|||||||
@@ -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 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
|
# BPM Expects the output files to be present in the automatically created 'output' directory which can be accessed using $BPM_OUTPUT
|
||||||
|
|
||||||
|
|||||||
@@ -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 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
|
# BPM Expects the output files to be present in the automatically created 'output' directory which can be accessed using $BPM_OUTPUT
|
||||||
|
|
||||||
|
|||||||
@@ -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 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
|
# BPM Expects the output files to be present in the automatically created 'output' directory which can be accessed using $BPM_OUTPUT
|
||||||
|
|
||||||
|
|||||||
@@ -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 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
|
# BPM Expects the output files to be present in the automatically created 'output' directory which can be accessed using $BPM_OUTPUT
|
||||||
|
|
||||||
|
|||||||
@@ -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 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
|
# BPM Expects the output files to be present in the automatically created 'output' directory which can be accessed using $BPM_OUTPUT
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
# 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
|
||||||
|
|
||||||
|
# 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 --print host-tuple)"
|
||||||
|
}
|
||||||
|
|
||||||
|
# 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
|
||||||
|
}
|
||||||
@@ -8,6 +8,9 @@ require (
|
|||||||
gopkg.in/yaml.v3 v3.0.1
|
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
|
replace bpm-utils-shared => ../bpm-utils-shared
|
||||||
|
|||||||
@@ -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/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 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
|
||||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
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 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
|
||||||
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
|
|||||||
+195
-52
@@ -5,6 +5,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"io/fs"
|
||||||
"log"
|
"log"
|
||||||
"maps"
|
"maps"
|
||||||
"os"
|
"os"
|
||||||
@@ -12,6 +13,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 +21,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 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 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 installPackage = flag.BoolP("install", "i", false, "Install compiled BPM package after compilation finishes")
|
||||||
var moveToBinaryDir = flag.BoolP("move", "m", false, "Move output packages to the current repository's binary directory")
|
var compilationJobs = flag.IntP("jobs", "j", 0, "Set the amount of concurrent processes to use for source package compilation")
|
||||||
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 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")
|
var yesAll = flag.BoolP("yes", "y", false, "Accept all confirmation prompts")
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@@ -39,25 +45,35 @@ func main() {
|
|||||||
if *compile {
|
if *compile {
|
||||||
compilePackage(outputFile)
|
compilePackage(outputFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if repo := bpmutilsshared.GetRepository(); repo != "" {
|
||||||
|
bpmutilsshared.UpdateDatabases(repo)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func runChecks() {
|
func runChecks() {
|
||||||
// Check if pkg.info file exists
|
// Check if info.yml file exists
|
||||||
if stat, err := os.Stat("pkg.info"); err != nil || !stat.Mode().IsRegular() {
|
if stat, err := os.Stat("info.yml"); err != nil || !stat.Mode().IsRegular() {
|
||||||
log.Fatalf("Error: pkg.info does not exist or is not a regular file")
|
log.Fatalf("Error: info.yml does not exist or is not a regular file")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if source.sh file exists
|
// Check if recipe.sh file exists
|
||||||
if stat, err := os.Stat("source.sh"); err != nil || !stat.Mode().IsRegular() {
|
if stat, err := os.Stat("recipe.sh"); err != nil || !stat.Mode().IsRegular() {
|
||||||
log.Fatalf("Error: pkg.info does not exist or is not a regular file")
|
log.Fatalf("Error: info.yml does not exist or is not a regular file")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
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
|
// Check if non-empty source-files directory exists and include it
|
||||||
if stat, err := os.Stat("source-files"); err == nil && stat.IsDir() {
|
if stat, err := os.Stat("source-files"); err == nil && stat.IsDir() {
|
||||||
@@ -76,14 +92,15 @@ func createArchive() string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read pkg.info file
|
// Read info.yml file
|
||||||
pkgInfo, err := bpmutilsshared.ReadPacakgeInfoFromFile("pkg.info")
|
pkgInfo, err := bpmutilsshared.ReadPacakgeInfoFromFile("info.yml")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Error: could not read package info: %s", err)
|
log.Fatalf("Error: could not read package info: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update checksums
|
// Update info.yml 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 +114,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)
|
||||||
@@ -106,39 +130,46 @@ func createArchive() string {
|
|||||||
log.Fatalf("Could not marshal package info: %s", err)
|
log.Fatalf("Could not marshal package info: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stat pkg.info
|
// Stat info.yml
|
||||||
stat, err := os.Stat("pkg.info")
|
stat, err := os.Stat("info.yml")
|
||||||
if err != nil {
|
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
|
// 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 {
|
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
|
// Remove old package from source dir
|
||||||
oldArchives, err := filepath.Glob("*.bpm")
|
if repo := bpmutilsshared.GetRepository(); repo != "" {
|
||||||
if err != nil {
|
removedFiles, err := RemoveSourcePackage(repo, pkgInfo.Name)
|
||||||
log.Printf("Warning: could not search for old BPM archives: %s", err)
|
for _, file := range removedFiles {
|
||||||
|
fmt.Println("Removed " + file)
|
||||||
}
|
}
|
||||||
for _, bpmArchive := range oldArchives {
|
|
||||||
err = os.Remove(bpmArchive)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Warning: could not remove old BPM archive (%s): %s", bpmArchive, err)
|
log.Printf("Warning: could not remove old source packages: %s", 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)
|
||||||
|
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
|
// Create archive using tar
|
||||||
args := make([]string, 0)
|
cmd := exec.Command("tar", "cf", filename,
|
||||||
args = append(args, "-c", "--owner=0", "--group=0", "--no-same-owner", "-f", filename)
|
"--sort=name",
|
||||||
args = append(args, filesToInclude...)
|
"--pax-option=exthdr.name=%d/PaxHeaders/%f,delete=atime,delete=ctime",
|
||||||
cmd := exec.Command("tar", args...)
|
"--mtime=UTC 1970-01-01",
|
||||||
|
"--owner=0", "--group=0", "--numeric-owner")
|
||||||
|
cmd.Args = append(cmd.Args, filesToInclude...)
|
||||||
cmd.Stdout = os.Stdout
|
cmd.Stdout = os.Stdout
|
||||||
cmd.Stderr = os.Stderr
|
cmd.Stderr = os.Stderr
|
||||||
err = cmd.Run()
|
err = cmd.Run()
|
||||||
@@ -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", "--yes", "--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,15 +204,18 @@ 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 *skipCheck {
|
addArg := func(condition bool, arg string) {
|
||||||
args = append(args, "-s")
|
if condition {
|
||||||
|
args = append(args, arg)
|
||||||
}
|
}
|
||||||
if *installDepends {
|
|
||||||
args = append(args, "-d")
|
|
||||||
}
|
|
||||||
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, "--output-fd=3")
|
||||||
args = append(args, archive)
|
args = append(args, archive)
|
||||||
cmd := exec.Command("bpm", args...)
|
cmd := exec.Command("bpm", args...)
|
||||||
@@ -209,34 +256,48 @@ func compilePackage(archive string) {
|
|||||||
for _, line := range strings.Split(strings.TrimSpace(string(cmdOutput)), "\n") {
|
for _, line := range strings.Split(strings.TrimSpace(string(cmdOutput)), "\n") {
|
||||||
// Read generated package info
|
// Read generated package info
|
||||||
pkgInfo, err := bpmutilsshared.ReadPacakgeInfoFromTarball(line)
|
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Move package to binary dir
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Error: could not read package info: %s", err)
|
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))
|
newPath := path.Join(repo, "binary", pkgInfo.Arch, path.Base(line))
|
||||||
os.MkdirAll(path.Dir(newPath), 0755)
|
os.MkdirAll(path.Dir(newPath), 0755)
|
||||||
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sign package
|
||||||
|
if *signPackage {
|
||||||
|
for k, v := range outputPkgs {
|
||||||
|
cmd := exec.Command("gpg", "--yes", "--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 {
|
||||||
fmt.Printf("Package (%s) was successfully compiled! Binary package generated at: %s\n", k, v)
|
fmt.Printf("Package (%s) was successfully compiled! Binary package generated at: %s\n", k, v)
|
||||||
@@ -280,3 +341,85 @@ func setupFlagsAndHelp(usage, desc string) {
|
|||||||
}
|
}
|
||||||
flag.Parse()
|
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
@@ -8,6 +8,9 @@ require (
|
|||||||
gopkg.in/yaml.v3 v3.0.1
|
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
|
replace bpm-utils-shared => ../bpm-utils-shared
|
||||||
|
|||||||
@@ -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/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 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
|
||||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
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 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
|
||||||
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
|
|||||||
+401
-35
@@ -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, "recipes"), 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"))
|
||||||
@@ -145,15 +185,15 @@ func checkVersionsFunc(repo string) {
|
|||||||
directories := make([]string, 0)
|
directories := make([]string, 0)
|
||||||
if currentFlagSet.NArg() > 0 {
|
if currentFlagSet.NArg() > 0 {
|
||||||
for _, dir := range currentFlagSet.Args() {
|
for _, dir := range currentFlagSet.Args() {
|
||||||
if _, err := os.Stat(path.Join(repo, "source", dir, "pkg.info")); err != nil {
|
if _, err := os.Stat(path.Join(repo, "recipes", dir, "info.yml")); err != nil {
|
||||||
log.Fatalf("Error: could not find pkg.info file in directory (%s): %s", dir, err)
|
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 {
|
} else {
|
||||||
// Loop through each directory with a 'pkg.info' file
|
// Loop through each directory with a 'info.yml' file
|
||||||
err := filepath.Walk(path.Join(repo, "source"), func(path string, info fs.FileInfo, err error) error {
|
err := filepath.Walk(path.Join(repo, "recipes"), func(path string, info fs.FileInfo, err error) error {
|
||||||
if filepath.Base(path) == "pkg.info" {
|
if filepath.Base(path) == "info.yml" {
|
||||||
directories = append(directories, filepath.Dir(path))
|
directories = append(directories, filepath.Dir(path))
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@@ -172,7 +212,7 @@ func checkVersionsFunc(repo string) {
|
|||||||
}, 0)
|
}, 0)
|
||||||
pkgsUpToDate := 0
|
pkgsUpToDate := 0
|
||||||
for _, dir := range directories {
|
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 {
|
if err != nil {
|
||||||
log.Fatalf("Could not read package info: %s", err)
|
log.Fatalf("Could not read package info: %s", err)
|
||||||
}
|
}
|
||||||
@@ -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, "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)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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,15 @@ 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)
|
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)")
|
||||||
|
}
|
||||||
|
fmt.Println()
|
||||||
}
|
}
|
||||||
|
|
||||||
if verbose {
|
if verbose {
|
||||||
@@ -286,45 +366,328 @@ func checkVersionsFunc(repo string) {
|
|||||||
fmt.Println("Errors:", len(pkgsWithError))
|
fmt.Println("Errors:", len(pkgsWithError))
|
||||||
}
|
}
|
||||||
|
|
||||||
func listPackagesFunc(repo string) {
|
func holdPackage(repo string) {
|
||||||
// Read databases
|
// Get flags
|
||||||
sourceDatabase, err := bpmutilsshared.ReadDatabase(path.Join(repo, "source/database.bpmdb"))
|
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, "recipes", pkgName, "info.yml")); err != nil {
|
||||||
|
log.Fatalf("Error: could not find info.yml 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 {
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
binaryDatabase, err := bpmutilsshared.ReadDatabase(path.Join(repo, "binary/database.bpmdb"))
|
// 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 {
|
if err != nil {
|
||||||
binaryDatabase = &bpmutilsshared.BPMDatabase{}
|
log.Fatalf("Error: value (%s) is not a boolean", currentFlagSet.Arg(1))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort database entries
|
// Set on_hold value
|
||||||
entriesSorted := slices.Collect(maps.Values(sourceDatabase.Entries))
|
cachedVersions[pkgName].OnHold = value
|
||||||
sort.Slice(entriesSorted, func(i, j int) bool {
|
|
||||||
return entriesSorted[i].PackageInfo.Name < entriesSorted[j].PackageInfo.Name
|
|
||||||
})
|
|
||||||
|
|
||||||
// Loop through each entry
|
// Save cached versions to file
|
||||||
for _, entry := range entriesSorted {
|
data, err = yaml.Marshal(cachedVersions)
|
||||||
if len(entry.PackageInfo.SplitPackages) > 0 {
|
if err == nil {
|
||||||
for _, splitPkg := range entry.PackageInfo.SplitPackages {
|
err := os.WriteFile(path.Join(repo, ".version-cache"), data, 0644)
|
||||||
// Handle split packages
|
if err != nil {
|
||||||
additionalText := ""
|
log.Printf("Warning: could not write cached versions to file: %s", err)
|
||||||
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)
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
// Read package recipes
|
||||||
|
pkgs := bpmutilsshared.ReadRepositoryRecipes(repo)
|
||||||
|
|
||||||
|
// Read databases
|
||||||
|
sourceDatabase, _ := bpmutilsshared.ReadDatabase(path.Join(repo, "source/database.bpmdb"))
|
||||||
|
binaryDatabase, _ := bpmutilsshared.ReadDatabase(path.Join(repo, "binary/database.bpmdb"))
|
||||||
|
|
||||||
|
for _, pkg := range pkgs {
|
||||||
|
fmt.Printf("%s (%s):\n", pkg.Name, pkg.Version)
|
||||||
|
|
||||||
|
// 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 {
|
} else {
|
||||||
additionalText := ""
|
fmt.Println(" Source package not found!")
|
||||||
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.Printf("%s %s-%d %s\n", entry.PackageInfo.Name, entry.PackageInfo.Version, entry.PackageInfo.Revision, additionalText)
|
}
|
||||||
|
|
||||||
|
// 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!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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"))
|
||||||
|
binaryDatabase, _ := bpmutilsshared.ReadDatabase(path.Join(repo, "binary/database.bpmdb"))
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
dependName, _, _ := bpmutilsshared.SplitPkgNameAndVersion(depend)
|
||||||
|
|
||||||
|
// Find package in repository
|
||||||
|
dependInfo, ok := pkgsMap[dependName]
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
// Search for virtual package
|
||||||
|
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(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)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, pkg := range pkgs {
|
||||||
|
if mark, _ := marked[pkg.Name]; mark != 2 {
|
||||||
|
visit(pkg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compile all packages in order
|
||||||
|
for _, pkgInfo := range sorted {
|
||||||
|
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 {
|
||||||
|
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", "-cdusy")
|
||||||
|
cmd.Stdin = os.Stdin
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
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
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
log.Fatalf("Error: could not update packages): %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -361,7 +724,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) {
|
||||||
|
|||||||
@@ -8,6 +8,9 @@ require (
|
|||||||
gopkg.in/yaml.v3 v3.0.1
|
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
|
replace bpm-utils-shared => ../bpm-utils-shared
|
||||||
|
|||||||
@@ -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/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 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
|
||||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
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 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
|
||||||
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
|
|||||||
+50
-27
@@ -10,14 +10,12 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
flag "github.com/spf13/pflag"
|
flag "github.com/spf13/pflag"
|
||||||
yaml "gopkg.in/yaml.v3"
|
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 name = flag.StringP("name", "n", "", "Set the package name")
|
||||||
var description = flag.StringP("description", "d", "Default Package Description", "Set the description")
|
var description = flag.StringP("description", "d", "Default Package Description", "Set the description")
|
||||||
var version = flag.StringP("version", "v", "1.0", "Set the package version")
|
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 template = flag.StringP("template", "t", "gnu-configure", "Set the package template")
|
||||||
var git = flag.BoolP("git", "g", true, "Create git repository")
|
var git = flag.BoolP("git", "g", true, "Create git repository")
|
||||||
|
|
||||||
|
var directory = ""
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// Setup flags and help
|
// Setup flags and help
|
||||||
setupFlagsAndHelp("bpm-setup <options>", "Sets up files and directories for BPM source package creation")
|
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
|
// Show command help if no directory name is given
|
||||||
if *directory == "" {
|
if *name == "" {
|
||||||
log.Println("Error: directory flag is required")
|
log.Println("Error: name flag is required")
|
||||||
flag.Usage()
|
flag.Usage()
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set package name to directory name if empty
|
// Get current repository
|
||||||
if *name == "" {
|
repo := bpmutilsshared.GetRepository()
|
||||||
*name = filepath.Base(*directory)
|
|
||||||
|
// 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
|
// run checks
|
||||||
@@ -62,25 +75,29 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func runChecks() {
|
func runChecks() {
|
||||||
if strings.TrimSpace(*directory) == "" {
|
// Check if package name is valid
|
||||||
log.Fatalf("No directory was specified!")
|
if *name == "" {
|
||||||
|
log.Fatalf("Error: no package name was specified!")
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.TrimSpace(*name) == "" {
|
// Check if parent directory is valid
|
||||||
log.Fatalf("No package name was specified!")
|
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() {
|
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() {
|
func showSummary() {
|
||||||
absPath, err := filepath.Abs(strings.TrimSpace(*directory))
|
fmt.Printf("Setting up package directory at %s with the following information:\n", 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("Package name: %s\n", strings.TrimSpace(*name))
|
fmt.Printf("Package name: %s\n", strings.TrimSpace(*name))
|
||||||
fmt.Printf("Package description: %s\n", *description)
|
fmt.Printf("Package description: %s\n", *description)
|
||||||
fmt.Printf("Package version: %s\n", *version)
|
fmt.Printf("Package version: %s\n", *version)
|
||||||
@@ -108,12 +125,14 @@ func replaceVariables(templateContents string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func createDirectory() {
|
func createDirectory() {
|
||||||
// Trim spaces
|
// Read BPM utils config
|
||||||
*directory = strings.TrimSpace(*directory)
|
config, err := bpmutilsshared.ReadBPMUtilsConfig()
|
||||||
*name = strings.TrimSpace(*name)
|
if err != nil {
|
||||||
|
log.Fatalf("Error: failed to read config: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
// 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 +142,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 +156,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)
|
||||||
@@ -143,13 +166,13 @@ func createDirectory() {
|
|||||||
encoder.Encode(&pkgInfo)
|
encoder.Encode(&pkgInfo)
|
||||||
|
|
||||||
// Write package info to file
|
// 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 {
|
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
|
// 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 {
|
if err != nil {
|
||||||
log.Fatalf("Error: could not create directory: %s", err)
|
log.Fatalf("Error: could not create directory: %s", err)
|
||||||
}
|
}
|
||||||
@@ -164,7 +187,7 @@ func createDirectory() {
|
|||||||
// Replace variables in template file
|
// Replace variables in template file
|
||||||
input = []byte(replaceVariables(string(input)))
|
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 {
|
if err != nil {
|
||||||
log.Fatalf("Error: could not write to source file: %s", err)
|
log.Fatalf("Error: could not write to source file: %s", err)
|
||||||
return
|
return
|
||||||
@@ -172,7 +195,7 @@ func createDirectory() {
|
|||||||
|
|
||||||
// Create git repository
|
// Create git repository
|
||||||
if git != nil && *git {
|
if git != nil && *git {
|
||||||
err = exec.Command("git", "init", *directory).Run()
|
err = exec.Command("git", "init", directory).Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Error: could not initialize git repository: %s", err)
|
log.Fatalf("Error: could not initialize git repository: %s", err)
|
||||||
}
|
}
|
||||||
@@ -183,7 +206,7 @@ func createDirectory() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer defaultGitignoreFile.Close()
|
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 {
|
if err != nil {
|
||||||
log.Fatalf("Error: could not create .gitignore file: %s", err)
|
log.Fatalf("Error: could not create .gitignore file: %s", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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, "files.txt", "-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("files.txt 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)
|
||||||
|
|||||||
@@ -5,3 +5,5 @@ go 1.23
|
|||||||
require gopkg.in/yaml.v3 v3.0.1
|
require gopkg.in/yaml.v3 v3.0.1
|
||||||
|
|
||||||
require github.com/drone/envsubst v1.0.3
|
require github.com/drone/envsubst v1.0.3
|
||||||
|
|
||||||
|
require github.com/knqyf263/go-rpm-version v0.0.0-20240918084003-2afd7dc6a38f // indirect
|
||||||
|
|||||||
@@ -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/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 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
|
||||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
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 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
|||||||
@@ -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,9 +4,11 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/drone/envsubst"
|
"github.com/drone/envsubst"
|
||||||
|
version "github.com/knqyf263/go-rpm-version"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -17,20 +19,41 @@ 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"`
|
||||||
|
Flags []PackageFlag `yaml:"flags,omitempty"`
|
||||||
Downloads []PackageDownload `yaml:"downloads,omitempty"`
|
Downloads []PackageDownload `yaml:"downloads,omitempty"`
|
||||||
SplitPackages []*PackageInfo `yaml:"split_packages,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 {
|
type PackageDownload struct {
|
||||||
Url string `yaml:"url"`
|
Url string `yaml:"url"`
|
||||||
Type string `yaml:"type,omitempty"`
|
Type string `yaml:"type,omitempty"`
|
||||||
@@ -54,10 +77,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,9 +96,13 @@ 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, "info.yml", "-O")
|
||||||
output, err := cmd.Output()
|
output, err := cmd.Output()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -168,3 +197,69 @@ func (pkgDownload *PackageDownload) CalculateChecksum(pkgInfo *PackageInfo) (str
|
|||||||
return "", fmt.Errorf("unknown download type (%s)", pkgDownload.Type)
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package bpm_utils_shared
|
|||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
"sort"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetRepository() string {
|
func GetRepository() string {
|
||||||
@@ -23,3 +24,31 @@ func GetRepository() string {
|
|||||||
}
|
}
|
||||||
return dir
|
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
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user