mirror of
https://github.com/EnumeratedDev/bpm-utils.git
synced 2026-09-26 15:36:13 +00:00
Compare commits
19
Commits
1b6585424f
...
7.0.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4217626dde
|
||
|
|
d7da13034c | ||
|
|
cdb044d751
|
||
|
|
60b0f4489e
|
||
|
|
65c32d628f
|
||
|
|
4ff4a74fa3
|
||
|
|
f6ef60aa40
|
||
|
|
9625b5d7af
|
||
|
|
d881ac31c3
|
||
|
|
96a39a6b40
|
||
|
|
7a63ad6388
|
||
|
|
10f918034a
|
||
|
|
59c72d1a40
|
||
|
|
61c01ae88f | ||
|
|
0fdef74c73 | ||
|
|
d5abad3371 | ||
|
|
334eb15c94 | ||
|
|
7aff954df4 | ||
|
|
2197f78bc0 |
@@ -8,7 +8,7 @@ BPM Utils provides a number of different helper commands for creating and mainta
|
|||||||
## Provided utilities
|
## Provided utilities
|
||||||
- bpm-setup (Sets up directories for BPM source package creation)
|
- bpm-setup (Sets up directories for BPM source package creation)
|
||||||
- bpm-repo (Allows for easy management of multiple-package repositories)
|
- bpm-repo (Allows for easy management of multiple-package repositories)
|
||||||
- bpm-package (Turns a BPM package directory into a .bpm archive)
|
- bpm-package (Turns a BPM source package directory into a .bpm archive)
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
#### Using a package manager
|
#### Using a package manager
|
||||||
@@ -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 descriptor file inside the newly created directory to include dependencies or add/change other information. Here's an example of what a descriptor file could look like
|
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
|
||||||
```yaml
|
```yaml
|
||||||
name: my_package
|
name: my_package
|
||||||
description: My package's description
|
description: My package's description
|
||||||
@@ -42,11 +42,23 @@ revision: 2 (Optional)
|
|||||||
url: https://www.my-website.com/ (Optional)
|
url: https://www.my-website.com/ (Optional)
|
||||||
license: MyLicense (Optional)
|
license: MyLicense (Optional)
|
||||||
architecture: x86_64
|
architecture: x86_64
|
||||||
depends: ["dependency1","dependency2"] (Optional)
|
|
||||||
optional_depends: ["optional_depend1","optional_depend2"] (Optional)
|
|
||||||
make_depends: ["make_depend1","make_depend2"] (Optional)
|
|
||||||
keep: ["etc/my_config.conf"] (Optional)
|
|
||||||
type: source
|
type: source
|
||||||
|
depends:
|
||||||
|
- dependency1
|
||||||
|
- dependency2
|
||||||
|
optional_depends:
|
||||||
|
- optional_depend1
|
||||||
|
- optional_depend2
|
||||||
|
make_depends:
|
||||||
|
- make_depend1
|
||||||
|
- make_depend2
|
||||||
|
keep:
|
||||||
|
- etc/my_config.conf
|
||||||
|
downloads:
|
||||||
|
- url: https://wwww.my-url.com/file.tar.gz
|
||||||
|
extract_strip_components: 1
|
||||||
|
extract_to_bpm_source: true
|
||||||
|
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 source.sh file during compilation
|
||||||
@@ -55,4 +67,4 @@ type: source
|
|||||||
```
|
```
|
||||||
bpm-package
|
bpm-package
|
||||||
```
|
```
|
||||||
7) The `bpm-package` command will output a binary bpm archive which can be installed by BPM using `bpm install <file.bpm>`. If you are operating inside a BPM repository created using `bpm-repo` the file will automatically be moved to the binary subdirectory of your package repository
|
7) The `bpm-package` command will output a source bpm archive (and binary if passed the '-c' flag) which can be installed by BPM using `bpm install <file.bpm>`. If you are operating inside a BPM repository created using `bpm-repo` the file will automatically be moved to the binary subdirectory of your package repository
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
# This is the source.sh script. It is executed by BPM in a temporary directory when compiling a source package
|
||||||
|
# BPM Expects the source code to be extracted into the automatically created 'source' directory which can be accessed using $BPM_SOURCE
|
||||||
|
# BPM Expects the output files to be present in the automatically created 'output' directory which can be accessed using $BPM_OUTPUT
|
||||||
|
|
||||||
|
# The prepare function is executed in the root of the temp directory
|
||||||
|
# This function is used for putting downloaded files to the correct location or applying patches
|
||||||
|
prepare() {
|
||||||
|
cd "$BPM_SOURCE"
|
||||||
|
# Fetch cargo dependencies
|
||||||
|
cargo fetch --locked --target "$(rustc -vV | sed -n 's/host: //p')"
|
||||||
|
}
|
||||||
|
|
||||||
|
# The build function is executed in the source directory
|
||||||
|
# This function is used to compile the source code
|
||||||
|
build() {
|
||||||
|
cargo build --release --frozen --workspace
|
||||||
|
}
|
||||||
|
|
||||||
|
# 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 --frozen
|
||||||
|
}
|
||||||
|
|
||||||
|
# The package function is executed in the source directory
|
||||||
|
# This function is used to move the compiled files into the output directory
|
||||||
|
package() {
|
||||||
|
find target/release -maxdepth 1 -type f -executable -exec install -Dm755 -t "$BPM_OUTPUT"/usr/bin {} +
|
||||||
|
|
||||||
|
# Install package license
|
||||||
|
install -Dm644 "$BPM_SOURCE"/LICENSE "$BPM_OUTPUT"/usr/share/licenses/$NAME/LICENSE
|
||||||
|
}
|
||||||
+6
-17
@@ -2,40 +2,29 @@
|
|||||||
# 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
|
||||||
|
|
||||||
DOWNLOAD="https://wwww.my-url.com/file.tar.gz"
|
|
||||||
FILENAME="${DOWNLOAD##*/}"
|
|
||||||
|
|
||||||
# The prepare function is executed in the root of the temp directory
|
# The prepare function is executed in the root of the temp directory
|
||||||
# This function is used for downloading files and putting them into the correct location
|
# This function is used for putting downloaded files to the correct location or applying patches
|
||||||
prepare() {
|
prepare() {
|
||||||
wget "$DOWNLOAD"
|
echo "You may remove this function if you do not intend to use it"
|
||||||
tar -xvf "$FILENAME" --strip-components=1 -C "$BPM_SOURCE"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# The build function is executed in the source directory
|
# The build function is executed in the source directory
|
||||||
# This function is used to compile the source code
|
# This function is used to compile the source code
|
||||||
build() {
|
build() {
|
||||||
mkdir build
|
cmake -B build -DCMAKE_INSTALL_PREFIX=/usr
|
||||||
cd build
|
cmake --build build
|
||||||
|
|
||||||
cmake -DCMAKE_INSTALL_PREFIX=/usr ..
|
|
||||||
make
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# The check function is executed in the source directory
|
# The check function is executed in the source directory
|
||||||
# This function is used to run tests to verify the package has been compiled correctly
|
# This function is used to run tests to verify the package has been compiled correctly
|
||||||
check() {
|
check() {
|
||||||
cd build
|
ctest --test-dir build
|
||||||
|
|
||||||
make test
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# The package function is executed in the source directory
|
# The package function is executed in the source directory
|
||||||
# This function is used to move the compiled files into the output directory
|
# This function is used to move the compiled files into the output directory
|
||||||
package() {
|
package() {
|
||||||
cd build
|
DESTDIR="$BPM_OUTPUT" cmake --install build
|
||||||
|
|
||||||
make DESTDIR="$BPM_OUTPUT" install
|
|
||||||
|
|
||||||
# Install package license
|
# Install package license
|
||||||
install -Dm644 "$BPM_SOURCE"/LICENSE "$BPM_OUTPUT"/usr/share/licenses/$NAME/LICENSE
|
install -Dm644 "$BPM_SOURCE"/LICENSE "$BPM_OUTPUT"/usr/share/licenses/$NAME/LICENSE
|
||||||
|
|||||||
@@ -2,14 +2,10 @@
|
|||||||
# 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
|
||||||
|
|
||||||
DOWNLOAD="https://wwww.my-url.com/file.tar.gz"
|
|
||||||
FILENAME="${DOWNLOAD##*/}"
|
|
||||||
|
|
||||||
# The prepare function is executed in the root of the temp directory
|
# The prepare function is executed in the root of the temp directory
|
||||||
# This function is used for downloading files and putting them into the correct location
|
# This function is used for putting downloaded files to the correct location or applying patches
|
||||||
prepare() {
|
prepare() {
|
||||||
wget "$DOWNLOAD"
|
echo "You may remove this function if you do not intend to use it"
|
||||||
tar -xvf "$FILENAME" --strip-components=1 -C "$BPM_SOURCE"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# The build function is executed in the source directory
|
# The build function is executed in the source directory
|
||||||
|
|||||||
@@ -2,14 +2,10 @@
|
|||||||
# 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
|
||||||
|
|
||||||
DOWNLOAD="https://wwww.my-url.com/file.tar.gz"
|
|
||||||
FILENAME="${DOWNLOAD##*/}"
|
|
||||||
|
|
||||||
# The prepare function is executed in the root of the temp directory
|
# The prepare function is executed in the root of the temp directory
|
||||||
# This function is used for downloading files and putting them into the correct location
|
# This function is used for putting downloaded files to the correct location or applying patches
|
||||||
prepare() {
|
prepare() {
|
||||||
wget "$DOWNLOAD"
|
echo "You may remove this function if you do not intend to use it"
|
||||||
tar -xvf "$FILENAME" --strip-components=1 -C "$BPM_SOURCE"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# The build function is executed in the source directory
|
# The build function is executed in the source directory
|
||||||
|
|||||||
+6
-17
@@ -2,40 +2,29 @@
|
|||||||
# 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
|
||||||
|
|
||||||
DOWNLOAD="https://wwww.my-url.com/file.tar.gz"
|
|
||||||
FILENAME="${DOWNLOAD##*/}"
|
|
||||||
|
|
||||||
# The prepare function is executed in the root of the temp directory
|
# The prepare function is executed in the root of the temp directory
|
||||||
# This function is used for downloading files and putting them into the correct location
|
# This function is used for putting downloaded files to the correct location or applying patches
|
||||||
prepare() {
|
prepare() {
|
||||||
wget "$DOWNLOAD"
|
echo "You may remove this function if you do not intend to use it"
|
||||||
tar -xvf "$FILENAME" --strip-components=1 -C "$BPM_SOURCE"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# The build function is executed in the source directory
|
# The build function is executed in the source directory
|
||||||
# This function is used to compile the source code
|
# This function is used to compile the source code
|
||||||
build() {
|
build() {
|
||||||
mkdir build
|
meson setup build --prefix=/usr
|
||||||
cd build
|
meson compile -C build
|
||||||
|
|
||||||
meson setup --prefix=/usr ..
|
|
||||||
meson compile
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# The check function is executed in the source directory
|
# The check function is executed in the source directory
|
||||||
# This function is used to run tests to verify the package has been compiled correctly
|
# This function is used to run tests to verify the package has been compiled correctly
|
||||||
check() {
|
check() {
|
||||||
cd build
|
meson test -C build --print-errorlogs
|
||||||
|
|
||||||
meson test
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# The package function is executed in the source directory
|
# The package function is executed in the source directory
|
||||||
# This function is used to move the compiled files into the output directory
|
# This function is used to move the compiled files into the output directory
|
||||||
package() {
|
package() {
|
||||||
cd build
|
meson install -C build --destdir="$BPM_OUTPUT"
|
||||||
|
|
||||||
meson install --destdir="$BPM_OUTPUT"
|
|
||||||
|
|
||||||
# Install package license
|
# Install package license
|
||||||
install -Dm644 "$BPM_SOURCE"/LICENSE "$BPM_OUTPUT"/usr/share/licenses/$NAME/LICENSE
|
install -Dm644 "$BPM_SOURCE"/LICENSE "$BPM_OUTPUT"/usr/share/licenses/$NAME/LICENSE
|
||||||
|
|||||||
@@ -2,14 +2,10 @@
|
|||||||
# 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
|
||||||
|
|
||||||
DOWNLOAD="https://wwww.my-url.com/file.tar.gz"
|
|
||||||
FILENAME="${DOWNLOAD##*/}"
|
|
||||||
|
|
||||||
# The prepare function is executed in the root of the temp directory
|
# The prepare function is executed in the root of the temp directory
|
||||||
# This function is used for downloading files and putting them into the correct location
|
# This function is used for putting downloaded files to the correct location or applying patches
|
||||||
prepare() {
|
prepare() {
|
||||||
wget "$DOWNLOAD"
|
echo "You may remove this function if you do not intend to use it"
|
||||||
tar -xvf "$FILENAME" --strip-components=1 -C "$BPM_SOURCE"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# The build function is executed in the source directory
|
# The build function is executed in the source directory
|
||||||
|
|||||||
@@ -8,4 +8,6 @@ require (
|
|||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
)
|
)
|
||||||
|
|
||||||
|
require github.com/drone/envsubst v1.0.3 // indirect
|
||||||
|
|
||||||
replace bpm-utils-shared => ../bpm-utils-shared
|
replace bpm-utils-shared => ../bpm-utils-shared
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
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/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=
|
||||||
|
|||||||
+65
-28
@@ -2,6 +2,7 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
bpmutilsshared "bpm-utils-shared"
|
bpmutilsshared "bpm-utils-shared"
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
@@ -22,12 +23,12 @@ var skipCheck = flag.BoolP("skip-checks", "s", false, "Skip 'check' function whi
|
|||||||
var installDepends = flag.BoolP("depends", "d", false, "Install package dependencies for compilation")
|
var installDepends = flag.BoolP("depends", "d", false, "Install package dependencies for compilation")
|
||||||
var installPackage = flag.BoolP("install", "i", false, "Install compiled BPM package after compilation finishes")
|
var installPackage = flag.BoolP("install", "i", false, "Install compiled BPM package after compilation finishes")
|
||||||
var moveToBinaryDir = flag.BoolP("move", "m", false, "Move output packages to the current repository's binary directory")
|
var moveToBinaryDir = flag.BoolP("move", "m", false, "Move output packages to the current repository's binary directory")
|
||||||
|
var updateChecksums = flag.BoolP("update-checksums", "u", false, "Update the checksums for all download entries")
|
||||||
var 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() {
|
||||||
// Setup flags and help
|
// Setup flags and help
|
||||||
bpmutilsshared.SetupHelp("bpm-package <options>", "Generates source BPM package from current directory")
|
setupFlagsAndHelp("bpm-package <options>", "Generates source BPM package from current directory")
|
||||||
bpmutilsshared.SetupFlags()
|
|
||||||
|
|
||||||
// Run checks
|
// Run checks
|
||||||
runChecks()
|
runChecks()
|
||||||
@@ -70,27 +71,52 @@ func createArchive() string {
|
|||||||
// Check for package scripts and include them
|
// Check for package scripts and include them
|
||||||
for _, script := range []string{"pre_install.sh", "post_install.sh", "pre_update.sh", "post_update.sh", "pre_remove.sh", "post_remove.sh"} {
|
for _, script := range []string{"pre_install.sh", "post_install.sh", "pre_update.sh", "post_update.sh", "pre_remove.sh", "post_remove.sh"} {
|
||||||
if stat, err := os.Stat(script); err == nil && stat.Mode().IsRegular() {
|
if stat, err := os.Stat(script); err == nil && stat.Mode().IsRegular() {
|
||||||
fmt.Printf("Package script '%s' found", script)
|
fmt.Printf("Package script '%s' found\n", script)
|
||||||
filesToInclude = append(filesToInclude, script)
|
filesToInclude = append(filesToInclude, script)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read pkg.info file into basic struct
|
// Read pkg.info file
|
||||||
pkgInfo := struct {
|
pkgInfo, err := bpmutilsshared.ReadPacakgeInfoFromFile("pkg.info")
|
||||||
Name string `yaml:"name"`
|
|
||||||
Version string `yaml:"version"`
|
|
||||||
Revision int `yaml:"revision"`
|
|
||||||
Arch string `yaml:"architecture"`
|
|
||||||
}{
|
|
||||||
Revision: 1,
|
|
||||||
}
|
|
||||||
data, err := os.ReadFile("pkg.info")
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Error: could not read pkg.info file")
|
log.Fatalf("Error: could not read package info: %s", err)
|
||||||
}
|
}
|
||||||
err = yaml.Unmarshal(data, &pkgInfo)
|
|
||||||
|
// Update checksums
|
||||||
|
if *updateChecksums {
|
||||||
|
for i, download := range pkgInfo.Downloads {
|
||||||
|
if download.Checksum == "skip" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
download.Checksum, err = download.CalculateChecksum(pkgInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Error: could not unmarshal pkg.info file")
|
log.Fatalf("Could not calculate checksum for download entry %d: %s", i+1, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
pkgInfo.Downloads[i] = download
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save yaml back to file
|
||||||
|
var data bytes.Buffer
|
||||||
|
encoder := yaml.NewEncoder(&data)
|
||||||
|
encoder.SetIndent(2)
|
||||||
|
encoder.Encode(pkgInfo)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Could not marshal package info: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stat pkg.info
|
||||||
|
stat, err := os.Stat("pkg.info")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Could not stat pkg.info: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write package info back to file
|
||||||
|
err = os.WriteFile("pkg.info", data.Bytes(), stat.Mode().Perm())
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Could not write package info to pkg.info: %s", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove old BPM archives in current directory
|
// Remove old BPM archives in current directory
|
||||||
@@ -143,7 +169,7 @@ func compilePackage(archive string) {
|
|||||||
if *yesAll {
|
if *yesAll {
|
||||||
args = append(args, "-y")
|
args = append(args, "-y")
|
||||||
}
|
}
|
||||||
args = append(args, "--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...)
|
||||||
cmd.Stdin = os.Stdin
|
cmd.Stdin = os.Stdin
|
||||||
@@ -182,18 +208,9 @@ func compilePackage(archive string) {
|
|||||||
outputPkgs := make(map[string]string)
|
outputPkgs := make(map[string]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.ReadPacakgeInfo(line)
|
pkgInfo, err := bpmutilsshared.ReadPacakgeInfoFromTarball(line)
|
||||||
|
|
||||||
if repo := bpmutilsshared.GetRepository(); repo != "" && *moveToBinaryDir {
|
if repo := bpmutilsshared.GetRepository(); repo != "" && *moveToBinaryDir {
|
||||||
// Move package to binary dir
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Error: could not read package info: %s", err)
|
|
||||||
}
|
|
||||||
newPath := path.Join(repo, "binary", pkgInfo.Arch, path.Base(line))
|
|
||||||
os.MkdirAll(path.Dir(newPath), 0755)
|
|
||||||
os.Rename(line, newPath)
|
|
||||||
outputPkgs[pkgInfo.Name] = newPath
|
|
||||||
|
|
||||||
// Remove old package from binary dir
|
// Remove old package from binary dir
|
||||||
if database, err := bpmutilsshared.ReadDatabase(path.Join(repo, "binary/database.bpmdb")); err == nil {
|
if database, err := bpmutilsshared.ReadDatabase(path.Join(repo, "binary/database.bpmdb")); err == nil {
|
||||||
if entry, ok := database.Entries[pkgInfo.Name]; ok {
|
if entry, ok := database.Entries[pkgInfo.Name]; ok {
|
||||||
@@ -203,8 +220,18 @@ func compilePackage(archive string) {
|
|||||||
log.Printf("Warning: could not remove old binary package (%s): %s", pkgFilepath, err)
|
log.Printf("Warning: could not remove old binary package (%s): %s", pkgFilepath, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bpmutilsshared.UpdateDatabases(repo)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Move package to binary dir
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Error: could not read package info: %s", err)
|
||||||
|
}
|
||||||
|
newPath := path.Join(repo, "binary", pkgInfo.Arch, path.Base(line))
|
||||||
|
os.MkdirAll(path.Dir(newPath), 0755)
|
||||||
|
os.Rename(line, newPath)
|
||||||
|
outputPkgs[pkgInfo.Name] = newPath
|
||||||
|
|
||||||
|
bpmutilsshared.UpdateDatabases(repo)
|
||||||
} else {
|
} else {
|
||||||
outputPkgs[pkgInfo.Name] = line
|
outputPkgs[pkgInfo.Name] = line
|
||||||
}
|
}
|
||||||
@@ -243,3 +270,13 @@ func compilePackage(archive string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func setupFlagsAndHelp(usage, desc string) {
|
||||||
|
flag.Usage = func() {
|
||||||
|
fmt.Println("Usage: " + usage)
|
||||||
|
fmt.Println("Description: " + desc)
|
||||||
|
fmt.Println("Options:")
|
||||||
|
flag.PrintDefaults()
|
||||||
|
}
|
||||||
|
flag.Parse()
|
||||||
|
}
|
||||||
|
|||||||
+2
-3
@@ -5,10 +5,9 @@ go 1.23
|
|||||||
require (
|
require (
|
||||||
bpm-utils-shared v1.0.0
|
bpm-utils-shared v1.0.0
|
||||||
github.com/spf13/pflag v1.0.10
|
github.com/spf13/pflag v1.0.10
|
||||||
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require github.com/drone/envsubst v1.0.3 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
|
||||||
)
|
|
||||||
|
|
||||||
replace bpm-utils-shared => ../bpm-utils-shared
|
replace bpm-utils-shared => ../bpm-utils-shared
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
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/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=
|
||||||
|
|||||||
+263
-12
@@ -3,28 +3,41 @@ package main
|
|||||||
import (
|
import (
|
||||||
bpmutilsshared "bpm-utils-shared"
|
bpmutilsshared "bpm-utils-shared"
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/fs"
|
||||||
"log"
|
"log"
|
||||||
"maps"
|
"maps"
|
||||||
"os"
|
"os"
|
||||||
|
"os/exec"
|
||||||
"path"
|
"path"
|
||||||
|
"path/filepath"
|
||||||
"slices"
|
"slices"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
flag "github.com/spf13/pflag"
|
flag "github.com/spf13/pflag"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
var createRepo = flag.BoolP("create", "c", false, "Create a new BPM repository")
|
var currentFlagSet *flag.FlagSet
|
||||||
var updateDatabases = flag.BoolP("update-databases", "u", false, "Update update source and binary databases in current repository")
|
|
||||||
var listPackages = flag.BoolP("list", "l", false, "List packages")
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
if len(os.Args) < 2 {
|
||||||
|
log.Println("Error: no subcommand")
|
||||||
|
listSubcommands()
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
subcommand := os.Args[1]
|
||||||
|
|
||||||
|
switch subcommand {
|
||||||
|
case "create-repo", "c":
|
||||||
// Setup flags and help
|
// Setup flags and help
|
||||||
bpmutilsshared.SetupHelp("bpm-repo <options>", "Manage BPM repositories and databases")
|
flagset := flag.NewFlagSet("create-repo", flag.ExitOnError)
|
||||||
bpmutilsshared.SetupFlags()
|
setupFlagsAndHelp(flagset, fmt.Sprintf("bpm-repo %s <options>", subcommand), "Create a new BPM repository", os.Args[:1])
|
||||||
|
|
||||||
if *createRepo {
|
|
||||||
// Get current database
|
// Get current database
|
||||||
repo := bpmutilsshared.GetRepository()
|
repo := bpmutilsshared.GetRepository()
|
||||||
if repo != "" {
|
if repo != "" {
|
||||||
@@ -44,7 +57,11 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
createRepository(strings.TrimSpace(name), strings.TrimSpace(desc))
|
createRepository(strings.TrimSpace(name), strings.TrimSpace(desc))
|
||||||
} else if *updateDatabases {
|
case "update-db", "u":
|
||||||
|
// Setup flags and help
|
||||||
|
flagset := flag.NewFlagSet("update-db", flag.ExitOnError)
|
||||||
|
setupFlagsAndHelp(flagset, fmt.Sprintf("bpm-repo %s <options>", subcommand), "Update update source and binary databases in current repository", os.Args[:1])
|
||||||
|
|
||||||
// Get current database
|
// Get current database
|
||||||
repo := bpmutilsshared.GetRepository()
|
repo := bpmutilsshared.GetRepository()
|
||||||
if repo == "" {
|
if repo == "" {
|
||||||
@@ -52,16 +69,36 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bpmutilsshared.UpdateDatabases(repo)
|
bpmutilsshared.UpdateDatabases(repo)
|
||||||
} else if *listPackages {
|
case "list", "l":
|
||||||
|
flagset := flag.NewFlagSet("list", flag.ExitOnError)
|
||||||
|
setupFlagsAndHelp(flagset, fmt.Sprintf("bpm-repo %s <options>", subcommand), "List packages", os.Args[:1])
|
||||||
|
|
||||||
// Get current database
|
// Get current database
|
||||||
repo := bpmutilsshared.GetRepository()
|
repo := bpmutilsshared.GetRepository()
|
||||||
if repo == "" {
|
if repo == "" {
|
||||||
log.Fatal("Error: this command may only be run inside a BPM repository")
|
log.Fatal("Error: this command may only be run inside a BPM repository")
|
||||||
}
|
}
|
||||||
|
|
||||||
listPacakges(repo)
|
listPackagesFunc(repo)
|
||||||
} else {
|
case "check-versions", "v":
|
||||||
bpmutilsshared.ShowHelp()
|
// 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("force", "f", false, "Force current operation to bypass certain conditions")
|
||||||
|
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")
|
||||||
|
}
|
||||||
|
|
||||||
|
checkVersionsFunc(repo)
|
||||||
|
default:
|
||||||
|
log.Println("Error: unknown subcommand")
|
||||||
|
listSubcommands()
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,7 +117,176 @@ func createRepository(name, description string) {
|
|||||||
fmt.Println("Repository created successfully!")
|
fmt.Println("Repository created successfully!")
|
||||||
}
|
}
|
||||||
|
|
||||||
func listPacakges(repo string) {
|
func checkVersionsFunc(repo string) {
|
||||||
|
// Get flags
|
||||||
|
verbose, _ := currentFlagSet.GetBool("verbose")
|
||||||
|
force, _ := currentFlagSet.GetBool("force")
|
||||||
|
|
||||||
|
// Read environment files
|
||||||
|
err := readEnvFile(repo)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Error: could not read environment file: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read version cache
|
||||||
|
type CachedVersionEntry struct {
|
||||||
|
LatestVersion string `yaml:"latest_version"`
|
||||||
|
Timestamp int64 `yaml:"timestamp"`
|
||||||
|
}
|
||||||
|
cachedVersions := make(map[string]CachedVersionEntry)
|
||||||
|
data, err := os.ReadFile(path.Join(repo, ".version-cache"))
|
||||||
|
if err == nil {
|
||||||
|
err := yaml.Unmarshal(data, &cachedVersions)
|
||||||
|
if err != nil {
|
||||||
|
cachedVersions = make(map[string]CachedVersionEntry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
directories = append(directories, path.Join(repo, "source", 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" {
|
||||||
|
directories = append(directories, filepath.Dir(path))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Error: could not loop through all packages: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pkgsWithoutScript := make([]string, 0)
|
||||||
|
pkgsIgnored := make([]string, 0)
|
||||||
|
pkgsWithError := make(map[string]error)
|
||||||
|
pkgsWithUpdates := make(map[string]struct {
|
||||||
|
OldVersion string
|
||||||
|
NewVersion string
|
||||||
|
}, 0)
|
||||||
|
pkgsUpToDate := 0
|
||||||
|
for _, dir := range directories {
|
||||||
|
pkgInfo, err := bpmutilsshared.ReadPacakgeInfoFromFile(path.Join(dir, "pkg.info"))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Could not read package info: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if verbose {
|
||||||
|
fmt.Printf("Checking version for package (%s)...\n", pkgInfo.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check cached latest version
|
||||||
|
latestVersion := ""
|
||||||
|
if cachedVersion, ok := cachedVersions[pkgInfo.Name]; ok && !force && time.Since(time.UnixMilli(cachedVersion.Timestamp)).Milliseconds() < 604800000 {
|
||||||
|
latestVersion = cachedVersion.LatestVersion
|
||||||
|
} else {
|
||||||
|
// Check whether check-version.sh script exists
|
||||||
|
if _, err := os.Stat(path.Join(dir, "check-version.sh")); err != nil {
|
||||||
|
pkgsWithoutScript = append(pkgsWithoutScript, pkgInfo.Name)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute check-version.sh script
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
cmd := exec.CommandContext(ctx, "bash", "-e", path.Join(dir, "check-version.sh"))
|
||||||
|
cmd.Environ()
|
||||||
|
output, err := cmd.Output()
|
||||||
|
if err != nil {
|
||||||
|
pkgsWithError[pkgInfo.Name] = err
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
latestVersion = strings.TrimSpace(string(output))
|
||||||
|
|
||||||
|
// Check if package should be ignored
|
||||||
|
if latestVersion == "ignore" {
|
||||||
|
pkgsIgnored = append(pkgsIgnored, pkgInfo.Name)
|
||||||
|
|
||||||
|
// Remove cached status
|
||||||
|
delete(cachedVersions, pkgInfo.Name)
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure latest version is valid
|
||||||
|
if latestVersion == "" || latestVersion == "null" {
|
||||||
|
pkgsWithError[pkgInfo.Name] = fmt.Errorf("invalid version number \"%s\"", latestVersion)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cache latest version
|
||||||
|
cachedVersions[pkgInfo.Name] = CachedVersionEntry{
|
||||||
|
LatestVersion: latestVersion,
|
||||||
|
Timestamp: time.Now().UnixMilli(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare versions
|
||||||
|
if pkgInfo.Version != latestVersion {
|
||||||
|
pkgsWithUpdates[pkgInfo.Name] = struct {
|
||||||
|
OldVersion string
|
||||||
|
NewVersion string
|
||||||
|
}{
|
||||||
|
OldVersion: pkgInfo.Version,
|
||||||
|
NewVersion: latestVersion,
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
pkgsUpToDate++
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save cached versions to file
|
||||||
|
data, err = yaml.Marshal(cachedVersions)
|
||||||
|
if err == nil {
|
||||||
|
err := os.WriteFile(path.Join(repo, ".version-cache"), data, 0644)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Warning: could not write cached versions to file: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print updates
|
||||||
|
keys := slices.Collect(maps.Keys(pkgsWithUpdates))
|
||||||
|
sort.Strings(keys)
|
||||||
|
for _, pkg := range keys {
|
||||||
|
fmt.Printf("Update available for package (%s): %s -> %s\n", pkg, pkgsWithUpdates[pkg].OldVersion, pkgsWithUpdates[pkg].NewVersion)
|
||||||
|
}
|
||||||
|
|
||||||
|
if verbose {
|
||||||
|
// Print ignored packages
|
||||||
|
for _, pkg := range pkgsIgnored {
|
||||||
|
log.Printf("Warning: package (%s) was ignored\n", pkg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print packages without check-version.sh script
|
||||||
|
for _, pkg := range pkgsWithoutScript {
|
||||||
|
log.Printf("Warning: package (%s) has no check-version.sh script\n", pkg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print errors
|
||||||
|
keys = slices.Collect(maps.Keys(pkgsWithError))
|
||||||
|
sort.Strings(keys)
|
||||||
|
for _, pkg := range keys {
|
||||||
|
log.Printf("Error: check-version.sh script for package (%s) failed: %s", pkg, pkgsWithError[pkg])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print summary
|
||||||
|
fmt.Println("----- Summary -----")
|
||||||
|
fmt.Println("Available updates:", len(pkgsWithUpdates))
|
||||||
|
fmt.Println("Up to date:", pkgsUpToDate)
|
||||||
|
fmt.Println("Missing script:", len(pkgsWithoutScript))
|
||||||
|
fmt.Println("Ignored: ", len(pkgsIgnored))
|
||||||
|
fmt.Println("Errors:", len(pkgsWithError))
|
||||||
|
}
|
||||||
|
|
||||||
|
func listPackagesFunc(repo string) {
|
||||||
// Read databases
|
// Read databases
|
||||||
sourceDatabase, err := bpmutilsshared.ReadDatabase(path.Join(repo, "source/database.bpmdb"))
|
sourceDatabase, err := bpmutilsshared.ReadDatabase(path.Join(repo, "source/database.bpmdb"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -122,3 +328,48 @@ func listPacakges(repo string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func readEnvFile(repo string) error {
|
||||||
|
data, err := os.ReadFile(path.Join(repo, ".env"))
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
return nil
|
||||||
|
} else if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, line := range strings.Split(string(data), "\n") {
|
||||||
|
line = strings.TrimSpace(line)
|
||||||
|
if line == "" || line[0] == '#' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
splitLine := strings.Split(line, "=")
|
||||||
|
if len(splitLine) != 2 {
|
||||||
|
return fmt.Errorf("invalid format")
|
||||||
|
}
|
||||||
|
|
||||||
|
os.Setenv(splitLine[0], splitLine[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func listSubcommands() {
|
||||||
|
fmt.Println("Usage: bpm-repo <subcommand> <options>")
|
||||||
|
fmt.Println("Description: Manage BPM repositories and databases")
|
||||||
|
fmt.Println("Subcommands:")
|
||||||
|
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(" v, check-versions Manage BPM repositories and databases")
|
||||||
|
fmt.Println(" l, list List packages")
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupFlagsAndHelp(flagset *flag.FlagSet, usage, desc string, args []string) {
|
||||||
|
flagset.Usage = func() {
|
||||||
|
fmt.Println("Usage: " + usage)
|
||||||
|
fmt.Println("Description: " + desc)
|
||||||
|
fmt.Println("Options:")
|
||||||
|
flagset.PrintDefaults()
|
||||||
|
}
|
||||||
|
flagset.Parse(args)
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,8 +5,9 @@ go 1.23
|
|||||||
require (
|
require (
|
||||||
bpm-utils-shared v1.0.0
|
bpm-utils-shared v1.0.0
|
||||||
github.com/spf13/pflag v1.0.10
|
github.com/spf13/pflag v1.0.10
|
||||||
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
)
|
)
|
||||||
|
|
||||||
require gopkg.in/yaml.v3 v3.0.1 // indirect
|
require github.com/drone/envsubst v1.0.3 // indirect
|
||||||
|
|
||||||
replace bpm-utils-shared => ../bpm-utils-shared
|
replace bpm-utils-shared => ../bpm-utils-shared
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
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/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=
|
||||||
|
|||||||
+39
-17
@@ -3,6 +3,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
bpmutilsshared "bpm-utils-shared"
|
bpmutilsshared "bpm-utils-shared"
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
@@ -13,6 +14,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
flag "github.com/spf13/pflag"
|
flag "github.com/spf13/pflag"
|
||||||
|
yaml "gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
var directory = flag.StringP("directory", "D", "", "Path to package directory")
|
var directory = flag.StringP("directory", "D", "", "Path to package directory")
|
||||||
@@ -26,13 +28,12 @@ var git = flag.BoolP("git", "g", true, "Create git repository")
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// Setup flags and help
|
// Setup flags and help
|
||||||
bpmutilsshared.SetupHelp("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")
|
||||||
bpmutilsshared.SetupFlags()
|
|
||||||
|
|
||||||
// Show command help if no directory name is given
|
// Show command help if no directory name is given
|
||||||
if *directory == "" {
|
if *directory == "" {
|
||||||
log.Println("Directory flag is required")
|
log.Println("Error: directory flag is required")
|
||||||
bpmutilsshared.ShowHelp()
|
flag.Usage()
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,21 +118,32 @@ func createDirectory() {
|
|||||||
log.Fatalf("Error: could not create directory: %s", err)
|
log.Fatalf("Error: could not create directory: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create pkg.info contents string
|
// Create package info struct
|
||||||
pkgInfo := "name: " + *name + "\n"
|
pkgInfo := bpmutilsshared.PackageInfo{
|
||||||
pkgInfo += "description: " + *description + "\n"
|
Name: *name,
|
||||||
pkgInfo += "version: " + *version + "\n"
|
Description: *description,
|
||||||
if url != nil && *url != "" {
|
Version: *version,
|
||||||
pkgInfo += "url: " + *url + "\n"
|
Url: *url,
|
||||||
|
License: *license,
|
||||||
|
Arch: "any",
|
||||||
|
Type: "source",
|
||||||
|
Downloads: []bpmutilsshared.PackageDownload{
|
||||||
|
{
|
||||||
|
Url: "https://wwww.my-url.com/file.tar.gz",
|
||||||
|
ExtractTo: "${BPM_SOURCE}",
|
||||||
|
ExtractStripComponents: 1,
|
||||||
|
Checksum: "replaceme",
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
if license != nil && *license != "" {
|
|
||||||
pkgInfo += "license: " + *license + "\n"
|
|
||||||
}
|
|
||||||
pkgInfo += "architecture: any\n"
|
|
||||||
pkgInfo += "type: source\n"
|
|
||||||
|
|
||||||
// Write string to file
|
var buffer bytes.Buffer
|
||||||
err = os.WriteFile(path.Join(*directory, "pkg.info"), []byte(pkgInfo), 0644)
|
encoder := yaml.NewEncoder(&buffer)
|
||||||
|
encoder.SetIndent(2)
|
||||||
|
encoder.Encode(&pkgInfo)
|
||||||
|
|
||||||
|
// Write package info to file
|
||||||
|
err = os.WriteFile(path.Join(*directory, "pkg.info"), 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 pkg.info: %s", err)
|
||||||
}
|
}
|
||||||
@@ -182,3 +194,13 @@ func createDirectory() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func setupFlagsAndHelp(usage, desc string) {
|
||||||
|
flag.Usage = func() {
|
||||||
|
fmt.Println("Usage: " + usage)
|
||||||
|
fmt.Println("Description: " + desc)
|
||||||
|
fmt.Println("Options:")
|
||||||
|
flag.PrintDefaults()
|
||||||
|
}
|
||||||
|
flag.Parse()
|
||||||
|
}
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ func GenerateDatabase(path string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get package info
|
// Get package info
|
||||||
entry.PackageInfo, err = ReadPacakgeInfo(packagePath)
|
entry.PackageInfo, err = ReadPacakgeInfoFromTarball(packagePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ module bpm-utils-shared
|
|||||||
|
|
||||||
go 1.23
|
go 1.23
|
||||||
|
|
||||||
require (
|
require gopkg.in/yaml.v3 v3.0.1
|
||||||
github.com/spf13/pflag v1.0.10
|
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
require github.com/drone/envsubst v1.0.3
|
||||||
)
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
|
github.com/drone/envsubst v1.0.3 h1:PCIBwNDYjs50AsLZPYdfhSATKaRg/FJmDc2D6+C2x8g=
|
||||||
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
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=
|
||||||
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=
|
||||||
|
|||||||
@@ -1,16 +1,11 @@
|
|||||||
package bpm_utils_shared
|
package bpm_utils_shared
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
flag "github.com/spf13/pflag"
|
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
var usageMsg string
|
|
||||||
var description string
|
|
||||||
|
|
||||||
type BPMUtilsConfig struct {
|
type BPMUtilsConfig struct {
|
||||||
PrivilegeEscalatorCmd string `yaml:"privilege_escalator_cmd"`
|
PrivilegeEscalatorCmd string `yaml:"privilege_escalator_cmd"`
|
||||||
}
|
}
|
||||||
@@ -29,20 +24,3 @@ func ReadBPMUtilsConfig() (*BPMUtilsConfig, error) {
|
|||||||
|
|
||||||
return config, nil
|
return config, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func SetupFlags() {
|
|
||||||
flag.Usage = ShowHelp
|
|
||||||
flag.Parse()
|
|
||||||
}
|
|
||||||
|
|
||||||
func SetupHelp(usage, desc string) {
|
|
||||||
usageMsg = usage
|
|
||||||
description = desc
|
|
||||||
}
|
|
||||||
|
|
||||||
func ShowHelp() {
|
|
||||||
fmt.Println("Usage: " + usageMsg)
|
|
||||||
fmt.Println("Description: " + description)
|
|
||||||
fmt.Println("Options:")
|
|
||||||
flag.PrintDefaults()
|
|
||||||
}
|
|
||||||
|
|||||||
+125
-17
@@ -1,47 +1,56 @@
|
|||||||
package bpm_utils_shared
|
package bpm_utils_shared
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/drone/envsubst"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
type PackageInfo struct {
|
type PackageInfo struct {
|
||||||
Name string `yaml:"name,omitempty"`
|
Name string `yaml:"name"`
|
||||||
Description string `yaml:"description,omitempty"`
|
Description string `yaml:"description,omitempty"`
|
||||||
Version string `yaml:"version,omitempty"`
|
Version string `yaml:"version,omitempty"`
|
||||||
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"`
|
||||||
Arch string `yaml:"architecture,omitempty"`
|
Arch string `yaml:"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"`
|
||||||
MakeDepends []string `yaml:"make_depends,omitempty"`
|
|
||||||
OptionalDepends []string `yaml:"optional_depends,omitempty"`
|
OptionalDepends []string `yaml:"optional_depends,omitempty"`
|
||||||
|
MakeDepends []string `yaml:"make_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"`
|
||||||
|
Downloads []PackageDownload `yaml:"downloads,omitempty"`
|
||||||
SplitPackages []*PackageInfo `yaml:"split_packages,omitempty"`
|
SplitPackages []*PackageInfo `yaml:"split_packages,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func ReadPacakgeInfo(path string) (*PackageInfo, error) {
|
type PackageDownload struct {
|
||||||
// Extract package info using tar
|
Url string `yaml:"url"`
|
||||||
cmd := exec.Command("tar", "-x", "-f", path, "pkg.info", "-O")
|
Type string `yaml:"type,omitempty"`
|
||||||
output, err := cmd.Output()
|
Filepath string `yaml:"filepath,omitempty,omitempty"`
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Archive options
|
||||||
|
NoExtract bool `yaml:"no_extract,omitempty"`
|
||||||
|
ExtractTo string `yaml:"extract_to,omitempty"`
|
||||||
|
ExtractStripComponents int `yaml:"extract_strip_components,omitempty"`
|
||||||
|
|
||||||
|
// Git options
|
||||||
|
CloneTo string `yaml:"clone_to,omitempty"`
|
||||||
|
GitBranch string `yaml:"git_branch,omitempty"`
|
||||||
|
|
||||||
|
Checksum string `yaml:"checksum,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReadPackageInfo(data []byte) (*PackageInfo, error) {
|
||||||
pkgInfo := &PackageInfo{
|
pkgInfo := &PackageInfo{
|
||||||
Name: "",
|
|
||||||
Description: "",
|
|
||||||
Version: "",
|
|
||||||
Revision: 1,
|
Revision: 1,
|
||||||
Url: "",
|
|
||||||
License: "",
|
|
||||||
Arch: "",
|
|
||||||
Type: "",
|
|
||||||
Keep: make([]string, 0),
|
Keep: make([]string, 0),
|
||||||
Depends: make([]string, 0),
|
Depends: make([]string, 0),
|
||||||
MakeDepends: make([]string, 0),
|
MakeDepends: make([]string, 0),
|
||||||
@@ -49,14 +58,113 @@ func ReadPacakgeInfo(path string) (*PackageInfo, error) {
|
|||||||
Conflicts: make([]string, 0),
|
Conflicts: make([]string, 0),
|
||||||
Replaces: make([]string, 0),
|
Replaces: make([]string, 0),
|
||||||
Provides: make([]string, 0),
|
Provides: make([]string, 0),
|
||||||
|
Downloads: make([]PackageDownload, 0),
|
||||||
SplitPackages: make([]*PackageInfo, 0),
|
SplitPackages: make([]*PackageInfo, 0),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unmarshal yaml
|
// Unmarshal yaml
|
||||||
err = yaml.Unmarshal(output, pkgInfo)
|
err := yaml.Unmarshal(data, pkgInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return pkgInfo, nil
|
return pkgInfo, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ReadPacakgeInfoFromTarball(path string) (*PackageInfo, error) {
|
||||||
|
// Extract package info using tar
|
||||||
|
cmd := exec.Command("tar", "-x", "-f", path, "pkg.info", "-O")
|
||||||
|
output, err := cmd.Output()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
pkgInfo, err := ReadPackageInfo(output)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return pkgInfo, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReadPacakgeInfoFromFile(path string) (*PackageInfo, error) {
|
||||||
|
// Read data from file
|
||||||
|
output, err := os.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
pkgInfo, err := ReadPackageInfo(output)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return pkgInfo, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pkgDownload *PackageDownload) CalculateChecksum(pkgInfo *PackageInfo) (string, error) {
|
||||||
|
switch pkgDownload.Type {
|
||||||
|
case "", "file":
|
||||||
|
fmt.Println("Downloading and calculating checksum for file...")
|
||||||
|
|
||||||
|
// Replace variables in download url
|
||||||
|
downloadUrl := pkgDownload.Url
|
||||||
|
downloadUrl, err := envsubst.Eval(downloadUrl, func(s string) string {
|
||||||
|
switch s {
|
||||||
|
case "BPM_PKG_VERSION":
|
||||||
|
return pkgInfo.Version
|
||||||
|
case "BPM_PKG_NAME":
|
||||||
|
return pkgInfo.Name
|
||||||
|
default:
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := exec.Command("sh", "-c", fmt.Sprintf("curl -s -L %s | sha256sum | awk '{print $1}'", downloadUrl))
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
|
||||||
|
checksum, err := cmd.Output()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.TrimSpace(string(checksum)), err
|
||||||
|
case "git":
|
||||||
|
fmt.Println("Calculating checksum for git branch...")
|
||||||
|
|
||||||
|
// Replace variables in git branch
|
||||||
|
gitBranch := pkgDownload.GitBranch
|
||||||
|
gitBranch, err := envsubst.Eval(gitBranch, func(s string) string {
|
||||||
|
switch s {
|
||||||
|
case "BPM_PKG_VERSION":
|
||||||
|
return pkgInfo.Version
|
||||||
|
case "BPM_PKG_NAME":
|
||||||
|
return pkgInfo.Name
|
||||||
|
default:
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if pkgDownload.GitBranch == "" {
|
||||||
|
return "", fmt.Errorf("'git_branch' field cannot be empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := exec.Command("sh", "-c", fmt.Sprintf("git ls-remote -bt %s | grep -E 'refs/.*/%s(\\^\\{\\})?$' | tail -n1 | awk '{print $1}'", pkgDownload.Url, gitBranch))
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
|
||||||
|
checksum, err := cmd.Output()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.TrimSpace(string(checksum)), err
|
||||||
|
default:
|
||||||
|
return "", fmt.Errorf("unknown download type (%s)", pkgDownload.Type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user