15 Commits
20 changed files with 313 additions and 151 deletions
+19 -7
View File
@@ -8,7 +8,7 @@ BPM Utils provides a number of different helper commands for creating and mainta
## Provided utilities
- bpm-setup (Sets up directories for BPM source package creation)
- 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
#### Using a package manager
@@ -33,7 +33,7 @@ Creating a package for BPM with these utilities is simple
bpm-setup -D my_package
```
2) This will create a directory named `my_package` containing all files required for bpm package creation
3) You may wish to edit the pkg.info 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
name: my_package
description: My package's description
@@ -42,11 +42,23 @@ revision: 2 (Optional)
url: https://www.my-website.com/ (Optional)
license: MyLicense (Optional)
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
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
@@ -55,4 +67,4 @@ type: source
```
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
+32
View File
@@ -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
View File
@@ -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 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
# 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() {
wget "$DOWNLOAD"
tar -xvf "$FILENAME" --strip-components=1 -C "$BPM_SOURCE"
echo "You may remove this function if you do not intend to use it"
}
# The build function is executed in the source directory
# This function is used to compile the source code
build() {
mkdir build
cd build
cmake -DCMAKE_INSTALL_PREFIX=/usr ..
make
cmake -B build -DCMAKE_INSTALL_PREFIX=/usr
cmake --build build
}
# 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() {
cd build
make test
ctest --test-dir build
}
# The package function is executed in the source directory
# This function is used to move the compiled files into the output directory
package() {
cd build
make DESTDIR="$BPM_OUTPUT" install
DESTDIR="$BPM_OUTPUT" cmake --install build
# Install package license
install -Dm644 "$BPM_SOURCE"/LICENSE "$BPM_OUTPUT"/usr/share/licenses/$NAME/LICENSE
+2 -6
View File
@@ -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 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
# 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() {
wget "$DOWNLOAD"
tar -xvf "$FILENAME" --strip-components=1 -C "$BPM_SOURCE"
echo "You may remove this function if you do not intend to use it"
}
# The build function is executed in the source directory
+2 -6
View File
@@ -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 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
# 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() {
wget "$DOWNLOAD"
tar -xvf "$FILENAME" --strip-components=1 -C "$BPM_SOURCE"
echo "You may remove this function if you do not intend to use it"
}
# The build function is executed in the source directory
+6 -17
View File
@@ -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 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
# 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() {
wget "$DOWNLOAD"
tar -xvf "$FILENAME" --strip-components=1 -C "$BPM_SOURCE"
echo "You may remove this function if you do not intend to use it"
}
# The build function is executed in the source directory
# This function is used to compile the source code
build() {
mkdir build
cd build
meson setup --prefix=/usr ..
meson compile
meson setup build --prefix=/usr
meson compile -C build
}
# 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() {
cd build
meson test
meson test -C build --print-errorlogs
}
# The package function is executed in the source directory
# This function is used to move the compiled files into the output directory
package() {
cd build
meson install --destdir="$BPM_OUTPUT"
meson install -C build --destdir="$BPM_OUTPUT"
# Install package license
install -Dm644 "$BPM_SOURCE"/LICENSE "$BPM_OUTPUT"/usr/share/licenses/$NAME/LICENSE
+2 -6
View File
@@ -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 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
# 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() {
wget "$DOWNLOAD"
tar -xvf "$FILENAME" --strip-components=1 -C "$BPM_SOURCE"
echo "You may remove this function if you do not intend to use it"
}
# The build function is executed in the source directory
+2
View File
@@ -8,4 +8,6 @@ require (
gopkg.in/yaml.v3 v3.0.1
)
require github.com/drone/envsubst v1.0.3 // indirect
replace bpm-utils-shared => ../bpm-utils-shared
+4
View File
@@ -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/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
+43 -16
View File
@@ -2,6 +2,7 @@ package main
import (
bpmutilsshared "bpm-utils-shared"
"bytes"
"fmt"
"io"
"log"
@@ -22,6 +23,7 @@ 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 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 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")
func main() {
@@ -69,27 +71,52 @@ func createArchive() string {
// 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"} {
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)
}
}
// Read pkg.info file into basic struct
pkgInfo := struct {
Name string `yaml:"name"`
Version string `yaml:"version"`
Revision int `yaml:"revision"`
Arch string `yaml:"architecture"`
}{
Revision: 1,
}
data, err := os.ReadFile("pkg.info")
// Read pkg.info file
pkgInfo, err := bpmutilsshared.ReadPacakgeInfoFromFile("pkg.info")
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 {
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
@@ -142,7 +169,7 @@ func compilePackage(archive string) {
if *yesAll {
args = append(args, "-y")
}
args = append(args, "--fd=3")
args = append(args, "--output-fd=3")
args = append(args, archive)
cmd := exec.Command("bpm", args...)
cmd.Stdin = os.Stdin
@@ -181,7 +208,7 @@ func compilePackage(archive string) {
outputPkgs := make(map[string]string)
for _, line := range strings.Split(strings.TrimSpace(string(cmdOutput)), "\n") {
// Read generated package info
pkgInfo, err := bpmutilsshared.ReadPacakgeInfo(line)
pkgInfo, err := bpmutilsshared.ReadPacakgeInfoFromTarball(line)
if repo := bpmutilsshared.GetRepository(); repo != "" && *moveToBinaryDir {
// Remove old package from binary dir
+2
View File
@@ -8,4 +8,6 @@ require (
gopkg.in/yaml.v3 v3.0.1
)
require github.com/drone/envsubst v1.0.3 // indirect
replace bpm-utils-shared => ../bpm-utils-shared
+4
View File
@@ -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/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
+9 -2
View File
@@ -3,6 +3,7 @@ package main
import (
bpmutilsshared "bpm-utils-shared"
"bufio"
"context"
"fmt"
"io/fs"
"log"
@@ -176,6 +177,10 @@ func checkVersionsFunc(repo string) {
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 {
@@ -188,7 +193,9 @@ func checkVersionsFunc(repo string) {
}
// Execute check-version.sh script
cmd := exec.Command("bash", "-e", path.Join(dir, "check-version.sh"))
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 {
@@ -261,6 +268,7 @@ func checkVersionsFunc(repo string) {
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))
@@ -268,7 +276,6 @@ func checkVersionsFunc(repo string) {
for _, pkg := range keys {
log.Printf("Error: check-version.sh script for package (%s) failed: %s", pkg, pkgsWithError[pkg])
}
}
// Print summary
fmt.Println("----- Summary -----")
+7 -1
View File
@@ -2,6 +2,12 @@ module git.enumerated.dev/bubble-package-manager/bpm-utils/src/bpm-setup
go 1.23
require github.com/spf13/pflag v1.0.10
require (
bpm-utils-shared v1.0.0
github.com/spf13/pflag v1.0.10
gopkg.in/yaml.v3 v3.0.1
)
require github.com/drone/envsubst v1.0.3 // indirect
replace bpm-utils-shared => ../bpm-utils-shared
+8
View File
@@ -1,2 +1,10 @@
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/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/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+27 -13
View File
@@ -1,7 +1,9 @@
package main
import (
bpmutilsshared "bpm-utils-shared"
"bufio"
"bytes"
"fmt"
"io"
"log"
@@ -12,6 +14,7 @@ import (
"strings"
flag "github.com/spf13/pflag"
yaml "gopkg.in/yaml.v3"
)
var directory = flag.StringP("directory", "D", "", "Path to package directory")
@@ -115,21 +118,32 @@ func createDirectory() {
log.Fatalf("Error: could not create directory: %s", err)
}
// Create pkg.info contents string
pkgInfo := "name: " + *name + "\n"
pkgInfo += "description: " + *description + "\n"
pkgInfo += "version: " + *version + "\n"
if url != nil && *url != "" {
pkgInfo += "url: " + *url + "\n"
// Create package info struct
pkgInfo := bpmutilsshared.PackageInfo{
Name: *name,
Description: *description,
Version: *version,
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
err = os.WriteFile(path.Join(*directory, "pkg.info"), []byte(pkgInfo), 0644)
var buffer bytes.Buffer
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 {
log.Fatalf("Could not write to pkg.info: %s", err)
}
+1 -1
View File
@@ -78,7 +78,7 @@ func GenerateDatabase(path string) error {
}
// Get package info
entry.PackageInfo, err = ReadPacakgeInfo(packagePath)
entry.PackageInfo, err = ReadPacakgeInfoFromTarball(packagePath)
if err != nil {
return err
}
+2
View File
@@ -3,3 +3,5 @@ module bpm-utils-shared
go 1.23
require gopkg.in/yaml.v3 v3.0.1
require github.com/drone/envsubst v1.0.3
+4
View File
@@ -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=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+110 -38
View File
@@ -1,48 +1,56 @@
package bpm_utils_shared
import (
"fmt"
"os"
"os/exec"
"strings"
"github.com/drone/envsubst"
"gopkg.in/yaml.v3"
)
type PackageInfo struct {
Name string `yaml:"name,omitempty"`
Name string `yaml:"name"`
Description string `yaml:"description,omitempty"`
Version string `yaml:"version,omitempty"`
Revision int `yaml:"revision,omitempty"`
Url string `yaml:"url,omitempty"`
License string `yaml:"license,omitempty"`
Arch string `yaml:"architecture,omitempty"`
OutputArch string `yaml:"output_architecture,omitempty"`
Type string `yaml:"type,omitempty"`
Keep []string `yaml:"keep,omitempty"`
Depends []string `yaml:"depends,omitempty"`
MakeDepends []string `yaml:"make_depends,omitempty"`
OptionalDepends []string `yaml:"optional_depends,omitempty"`
MakeDepends []string `yaml:"make_depends,omitempty"`
Conflicts []string `yaml:"conflicts,omitempty"`
Replaces []string `yaml:"replaces,omitempty"`
Provides []string `yaml:"provides,omitempty"`
Downloads []PackageDownload `yaml:"downloads,omitempty"`
SplitPackages []*PackageInfo `yaml:"split_packages,omitempty"`
}
func ReadPacakgeInfo(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
type PackageDownload struct {
Url string `yaml:"url"`
Type string `yaml:"type,omitempty"`
Filepath string `yaml:"filepath,omitempty,omitempty"`
// 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{
Name: "",
Description: "",
Version: "",
Revision: 1,
Url: "",
License: "",
Arch: "",
Type: "",
Keep: make([]string, 0),
Depends: make([]string, 0),
MakeDepends: make([]string, 0),
@@ -50,11 +58,28 @@ func ReadPacakgeInfo(path string) (*PackageInfo, error) {
Conflicts: make([]string, 0),
Replaces: make([]string, 0),
Provides: make([]string, 0),
Downloads: make([]PackageDownload, 0),
SplitPackages: make([]*PackageInfo, 0),
}
// Unmarshal yaml
err = yaml.Unmarshal(output, pkgInfo)
err := yaml.Unmarshal(data, pkgInfo)
if err != nil {
return nil, err
}
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
}
@@ -63,36 +88,83 @@ func ReadPacakgeInfo(path string) (*PackageInfo, error) {
}
func ReadPacakgeInfoFromFile(path string) (*PackageInfo, error) {
// Extract package info using tar
// Read data from file
output, err := os.ReadFile(path)
if err != nil {
return nil, err
}
pkgInfo := &PackageInfo{
Name: "",
Description: "",
Version: "",
Revision: 1,
Url: "",
License: "",
Arch: "",
Type: "",
Keep: make([]string, 0),
Depends: make([]string, 0),
MakeDepends: make([]string, 0),
OptionalDepends: make([]string, 0),
Conflicts: make([]string, 0),
Replaces: make([]string, 0),
Provides: make([]string, 0),
SplitPackages: make([]*PackageInfo, 0),
}
// Unmarshal yaml
err = yaml.Unmarshal(output, pkgInfo)
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)
}
}