Update to new package format

This commit is contained in:
2026-06-10 11:41:08 +03:00
parent e1daa498e8
commit 3f84dd4bc3
14 changed files with 109 additions and 58 deletions
+4 -4
View File
@@ -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 -1
View File
@@ -1,4 +1,4 @@
# This is the source.sh script. It is executed by BPM in a temporary directory when compiling a source package # This is the recipe.sh script. It is executed by BPM in a temporary directory when compiling a source package
# BPM Expects the source code to be extracted into the automatically created 'source' directory which can be accessed using $BPM_SOURCE # BPM Expects the 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 -1
View File
@@ -1,4 +1,4 @@
# This is the source.sh script. It is executed by BPM in a temporary directory when compiling a source package # This is the recipe.sh script. It is executed by BPM in a temporary directory when compiling a source package
# BPM Expects the source code to be extracted into the automatically created 'source' directory which can be accessed using $BPM_SOURCE # BPM Expects the 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 -1
View File
@@ -1,4 +1,4 @@
# This is the source.sh script. It is executed by BPM in a temporary directory when compiling a source package # This is the recipe.sh script. It is executed by BPM in a temporary directory when compiling a source package
# BPM Expects the source code to be extracted into the automatically created 'source' directory which can be accessed using $BPM_SOURCE # BPM Expects the 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 -1
View File
@@ -1,4 +1,4 @@
# This is the source.sh script. It is executed by BPM in a temporary directory when compiling a source package # This is the recipe.sh script. It is executed by BPM in a temporary directory when compiling a source package
# BPM Expects the source code to be extracted into the automatically created 'source' directory which can be accessed using $BPM_SOURCE # BPM Expects the 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 -1
View File
@@ -1,4 +1,4 @@
# This is the source.sh script. It is executed by BPM in a temporary directory when compiling a source package # This is the recipe.sh script. It is executed by BPM in a temporary directory when compiling a source package
# BPM Expects the source code to be extracted into the automatically created 'source' directory which can be accessed using $BPM_SOURCE # BPM Expects the 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 -1
View File
@@ -1,4 +1,4 @@
# This is the source.sh script. It is executed by BPM in a temporary directory when compiling a source package # This is the recipe.sh script. It is executed by BPM in a temporary directory when compiling a source package
# BPM Expects the source code to be extracted into the automatically created 'source' directory which can be accessed using $BPM_SOURCE # BPM Expects the 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
+2 -2
View File
@@ -1,4 +1,4 @@
# This is the source.sh script. It is executed by BPM in a temporary directory when compiling a source package # This is the recipe.sh script. It is executed by BPM in a temporary directory when compiling a source package
# BPM Expects the source code to be extracted into the automatically created 'source' directory which can be accessed using $BPM_SOURCE # BPM Expects the 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
@@ -6,7 +6,7 @@
# This function is used for putting downloaded files to the correct location or applying patches # This function is used for putting downloaded files to the correct location or applying patches
prepare() { prepare() {
cd "$BPM_SOURCE" cd "$BPM_SOURCE"
cargo fetch --locked --target "$(rustc -vV | sed -n 's/host: //p')" cargo fetch --locked --target "$(rustc --print host-tuple)"
} }
# The build function is executed in the source directory # The build function is executed in the source directory
+22 -20
View File
@@ -26,7 +26,7 @@ var keepCompilationFiles = flag.BoolP("keep", "k", false, "Keep compilation file
var installDepends = flag.BoolP("depends", "d", false, "Install package dependencies for compilation") var installDepends = flag.BoolP("depends", "d", false, "Install package dependencies for compilation")
var installPackage = flag.BoolP("install", "i", false, "Install compiled BPM package after compilation finishes") var installPackage = flag.BoolP("install", "i", false, "Install compiled BPM package after compilation finishes")
var compilationJobs = flag.IntP("jobs", "j", 0, "Set the amount of concurrent processes to use for source package compilation") var compilationJobs = flag.IntP("jobs", "j", 0, "Set the amount of concurrent processes to use for source package compilation")
var updateInfo = flag.BoolP("update-info", "u", false, "Update the pkg.info file") var updateInfo = flag.BoolP("update-info", "u", false, "Update the info.yml file")
var signPackage = flag.BoolP("sign", "s", false, "Sign package using GPG") var 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")
@@ -50,14 +50,14 @@ func main() {
} }
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")
} }
} }
@@ -71,7 +71,7 @@ func createArchive() string {
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() {
@@ -90,13 +90,13 @@ 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 pkg.info file // Update info.yml file
if *updateInfo { if *updateInfo {
// Update download checksums // Update download checksums
for i, download := range pkgInfo.Downloads { for i, download := range pkgInfo.Downloads {
@@ -128,16 +128,16 @@ 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)
} }
} }
@@ -172,10 +172,12 @@ func createArchive() string {
} }
// 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()
+61 -12
View File
@@ -185,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, "recipes", 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, "recipes", 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, "recipes"), 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
@@ -212,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)
} }
@@ -294,7 +294,7 @@ func checkVersionsFunc(repo string) {
encoder.Encode(pkgInfo) encoder.Encode(pkgInfo)
// Write package information // Write package information
err := os.WriteFile(path.Join(dir, "pkg.info"), data.Bytes(), 0644) err := os.WriteFile(path.Join(dir, "info.yml"), data.Bytes(), 0644)
if err != nil { if err != nil {
log.Printf("Warning: could not write new version for package (%s) to file: %s", pkgInfo.Name, err) log.Printf("Warning: could not write new version for package (%s) to file: %s", pkgInfo.Name, err)
} }
@@ -379,8 +379,8 @@ func holdPackage(repo string) {
} }
// Ensure package exists // Ensure package exists
if _, err := os.Stat(path.Join(repo, "recipes", pkgName, "pkg.info")); err != nil { if _, err := os.Stat(path.Join(repo, "recipes", pkgName, "info.yml")); err != nil {
log.Fatalf("Error: could not find pkg.info file in directory (%s): %s", pkgName, err) log.Fatalf("Error: could not find info.yml file in directory (%s): %s", pkgName, err)
} }
// Read version cache // Read version cache
@@ -494,6 +494,13 @@ func compileAllPackagesFunc(repo string) {
pkgsMap := make(map[string]bpmutilsshared.PackageInfo) pkgsMap := make(map[string]bpmutilsshared.PackageInfo)
for _, pkg := range pkgs { for _, pkg := range pkgs {
pkgsMap[pkg.Name] = pkg pkgsMap[pkg.Name] = pkg
// Add split packages
for _, splitPkg := range pkg.SplitPackages {
if _, ok := pkgsMap[splitPkg.Name]; !ok {
pkgsMap[splitPkg.Name] = pkg
}
}
} }
// Read databases // Read databases
@@ -508,7 +515,7 @@ func compileAllPackagesFunc(repo string) {
if mark, _ := marked[pkgInfo.Name]; mark == 2 { if mark, _ := marked[pkgInfo.Name]; mark == 2 {
return nil return nil
} else if mark == 1 { } else if mark == 1 {
return fmt.Errorf("Circular dependency found!") return fmt.Errorf("circular dependency found")
} }
marked[pkgInfo.Name] = 1 marked[pkgInfo.Name] = 1
@@ -518,12 +525,15 @@ func compileAllPackagesFunc(repo string) {
depends = append(depends, pkgInfo.MakeDepends...) depends = append(depends, pkgInfo.MakeDepends...)
for _, depend := range depends { for _, depend := range depends {
dependName, _, _ := bpmutilsshared.SplitPkgNameAndVersion(depend)
// Find package in repository // Find package in repository
dependInfo, ok := pkgsMap[depend] dependInfo, ok := pkgsMap[dependName]
if !ok { if !ok {
// Search for virtual package // Search for virtual package
for _, pkg := range pkgsMap { for _, pkg := range pkgsMap {
if slices.Contains(pkg.Provides, depend) { if slices.Contains(pkg.Provides, dependName) {
dependInfo = pkg dependInfo = pkg
ok = true ok = true
break break
@@ -531,14 +541,25 @@ func compileAllPackagesFunc(repo string) {
} }
if !ok { 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 continue
} }
} }
err := visit(dependInfo) err := visit(dependInfo)
if err != nil && verbose { if err != nil {
if strings.Contains(err.Error(), "circular") {
if verbose {
fmt.Printf("Circular dependency found! (%s -> %s)\n", pkgInfo.Name, dependInfo.Name) 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 marked[pkgInfo.Name] = 2
@@ -560,6 +581,32 @@ func compileAllPackagesFunc(repo string) {
if modifiedOnly { if modifiedOnly {
skip = true 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 // Check if source database entry is not synced
if sourceDatabase != nil { if sourceDatabase != nil {
if len(pkgInfo.SplitPackages) != 0 { if len(pkgInfo.SplitPackages) != 0 {
@@ -634,6 +681,7 @@ func compileAllPackagesFunc(repo string) {
} }
// Ensure installed packages are up-to-date // Ensure installed packages are up-to-date
if !showOrder {
cmd := exec.Command(config.PrivilegeEscalatorCmd, "sh", "-c", "bpm u -y") cmd := exec.Command(config.PrivilegeEscalatorCmd, "sh", "-c", "bpm u -y")
cmd.Stdin = os.Stdin cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout cmd.Stdout = os.Stdout
@@ -642,6 +690,7 @@ func compileAllPackagesFunc(repo string) {
log.Fatalf("Error: could not update packages): %s", err) log.Fatalf("Error: could not update packages): %s", err)
} }
} }
}
func readEnvFile(repo string) error { func readEnvFile(repo string) error {
data, err := os.ReadFile(path.Join(repo, ".env")) data, err := os.ReadFile(path.Join(repo, ".env"))
+3 -3
View File
@@ -166,9 +166,9 @@ 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
@@ -187,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
+2 -2
View File
@@ -72,7 +72,7 @@ func GenerateDatabase(path string) error {
// Get package installed size // Get package installed size
if entry.PackageInfo.Type == "binary" { if entry.PackageInfo.Type == "binary" {
cmd := exec.Command("tar", "xf", packagePath, "pkg.files", "-O") cmd := exec.Command("tar", "xf", packagePath, "files.txt", "-O")
output, err := cmd.Output() output, err := cmd.Output()
if err != nil { if err != nil {
return err return err
@@ -85,7 +85,7 @@ func GenerateDatabase(path string) error {
} }
stringEntry := strings.Split(line, " ") stringEntry := strings.Split(line, " ")
if len(stringEntry) < 5 { if len(stringEntry) < 5 {
return fmt.Errorf("pkg.files is not formatted correctly") return fmt.Errorf("files.txt is not formatted correctly")
} }
size, err := strconv.ParseInt(stringEntry[len(stringEntry)-1], 10, 64) size, err := strconv.ParseInt(stringEntry[len(stringEntry)-1], 10, 64)
if err != nil { if err != nil {
+1 -1
View File
@@ -85,7 +85,7 @@ func (pkgInfo *PackageInfo) GetFullVersion() string {
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
+1 -1
View File
@@ -34,7 +34,7 @@ func ReadRepositoryRecipes(repository string) []PackageInfo {
pkgs := make([]PackageInfo, 0) pkgs := make([]PackageInfo, 0)
for _, dir := range recipeDirs { for _, dir := range recipeDirs {
pkgInfoPath := path.Join(repository, "recipes", dir.Name(), "pkg.info") pkgInfoPath := path.Join(repository, "recipes", dir.Name(), "info.yml")
if _, err := os.Stat(pkgInfoPath); err != nil { if _, err := os.Stat(pkgInfoPath); err != nil {
continue continue
} }