diff --git a/README.md b/README.md index 720d80e..22ddc90 100644 --- a/README.md +++ b/README.md @@ -52,44 +52,37 @@ bpm help Creating a package for BPM is simple -To create a package you need to -1) Create a working directory +1) Make sure you have installed the bpm-utils package from the test-packages directory in the repository +2) Run the following command (You can run the comamnd with no arguments to see available options) ``` -mkdir my_bpm_package +bpm-setup -D my_bpm_package -t ``` -2) Create a pkg.info file following this format (You can find examples in the test_packages directory) +3) This will create a directory named 'my_bpm_package' under the current directory with all the required files for the chosen package type +4) You are able to edit the pkg.info descriptor file inside the newly created directory to your liking. Here's an example of what a descriptor file could look like ``` name: my_package description: My package's description version: 1.0 architecture: x86_64 +url: https://www.my-website.com/ (Optional) +license: MyLicense (Optional) type: -depends: dependency1,dependency2 -make_depends: make_depend1,make_depend2 +depends: dependency1,dependency2 (Optional) +make_depends: make_depend1,make_depend2 (Optional) ``` -depends and make depends are optional fields, you may skip them if you'd like ### Binary Packages -3) If you are making a binary package, simply create a 'files' directory +3) If you are making a binary package, copy all your binaries along with the directories they reside in (i.e files/usr/bin/my_binary) +6) Run the following to create a package archive ``` -mkdir files -``` -4) Copy all your binaries along with the directories they reside in (i.e files/usr/bin/my_binary) -5) Either copy the bpm-create script from the bpm-utils test package into your /usr/local/bin directory or install the bpm-utils.bpm package -6) Run the following -``` -bpm-create +bpm-package ``` 7) It's done! You now hopefully have a working BPM package! ### Source Packages -3) If you are making a source package, you need to create a 'source.sh' file +3) If you would like to bundle patches or other files with your source package place them in the 'source-files' directory. They will be extracted to the same location as the source.sh file during compilation +4) You need to edit your 'source.sh' file, the default source.sh template should explain the basic process of compiling your program +5) Your goal is to download your program's source code with either git, wget, curl, etc. and put the binaries under a folder called 'output' in the root of the temp directory. There is a simple example script with helpful comments in the htop-src test package +6) When you are done making your source.sh script run the following to create a package archive ``` -touch source.sh +bpm-package ``` -4) If you would like to bundle patches or other files with your source package create a 'source-files' directory and place your files in there. They will be extracted to the same location as the source.sh file during compilation -5) You are able to run bash code in source.sh. BPM will extract this file in a directory under /tmp and it will be run there -6) Your goal is to download your program's source code with either git, wget, curl, etc. and put the binaries under a folder called 'output' in the root of the temp directory. There is a simple example script with helpful comments in the htop-src test package -7) When you are done making your source.sh script run the following to create a package archive -``` -bpm-create -``` -8) That's it! Your source package should now be compiling correctly! \ No newline at end of file +7) That's it! Your source package should now be compiling correctly! \ No newline at end of file diff --git a/bpm_utils/package_utils.go b/bpm_utils/package_utils.go index 32412f9..40db426 100644 --- a/bpm_utils/package_utils.go +++ b/bpm_utils/package_utils.go @@ -25,6 +25,7 @@ type PackageInfo struct { License string Arch string Type string + Keep []string Depends []string MakeDepends []string Provides []string @@ -203,6 +204,7 @@ func ExecutePackageScripts(filename, rootDir string, operation Operation, postOp cmd.Env = append(cmd.Env, fmt.Sprintf("BPM_PKG_DESC=%s", pkgInfo.Description)) cmd.Env = append(cmd.Env, fmt.Sprintf("BPM_PKG_VERSION=%s", pkgInfo.Version)) cmd.Env = append(cmd.Env, fmt.Sprintf("BPM_PKG_URL=%s", pkgInfo.Url)) + cmd.Env = append(cmd.Env, fmt.Sprintf("BPM_PKG_ARCH=%s", pkgInfo.Arch)) depends := make([]string, len(pkgInfo.Depends)) copy(depends, pkgInfo.Depends) for i := 0; i < len(depends); i++ { @@ -269,6 +271,7 @@ func ReadPackageInfo(contents string, defaultValues bool) (*PackageInfo, error) License: "", Arch: "", Type: "", + Keep: nil, Depends: nil, MakeDepends: nil, Provides: nil, @@ -308,6 +311,9 @@ func ReadPackageInfo(contents string, defaultValues bool) (*PackageInfo, error) pkgInfo.Arch = split[1] case "type": pkgInfo.Type = split[1] + case "keep": + pkgInfo.Keep = strings.Split(strings.Replace(split[1], " ", "", -1), ",") + pkgInfo.Keep = stringSliceRemoveEmpty(pkgInfo.Keep) case "depends": pkgInfo.Depends = strings.Split(strings.Replace(split[1], " ", "", -1), ",") pkgInfo.Depends = stringSliceRemoveEmpty(pkgInfo.Depends) @@ -335,7 +341,7 @@ func ReadPackageInfo(contents string, defaultValues bool) (*PackageInfo, error) return &pkgInfo, nil } -func CreateInfoFile(pkgInfo PackageInfo) string { +func CreateInfoFile(pkgInfo PackageInfo, keepSourceFields bool) string { ret := "" ret = ret + "name: " + pkgInfo.Name + "\n" ret = ret + "description: " + pkgInfo.Description + "\n" @@ -348,9 +354,15 @@ func CreateInfoFile(pkgInfo PackageInfo) string { } ret = ret + "architecture: " + pkgInfo.Arch + "\n" ret = ret + "type: " + pkgInfo.Type + "\n" + if len(pkgInfo.Keep) > 0 { + ret = ret + "keep (" + strconv.Itoa(len(pkgInfo.Keep)) + "): " + strings.Join(pkgInfo.Keep, ",") + "\n" + } if len(pkgInfo.Depends) > 0 { ret = ret + "depends (" + strconv.Itoa(len(pkgInfo.Depends)) + "): " + strings.Join(pkgInfo.Depends, ",") + "\n" } + if len(pkgInfo.MakeDepends) > 0 && keepSourceFields { + ret = ret + "make_depends (" + strconv.Itoa(len(pkgInfo.MakeDepends)) + "): " + strings.Join(pkgInfo.MakeDepends, ",") + "\n" + } if len(pkgInfo.Provides) > 0 { ret = ret + "provides (" + strconv.Itoa(len(pkgInfo.Provides)) + "): " + strings.Join(pkgInfo.Provides, ",") + "\n" } @@ -410,7 +422,8 @@ func InstallPackage(filename, installDir string, force, binaryPkgFromSrc, keepTe return err } if strings.HasPrefix(header.Name, "files/") && header.Name != "files/" { - extractFilename := path.Join(installDir, strings.TrimPrefix(header.Name, "files/")) + trimmedName := strings.TrimPrefix(header.Name, "files/") + extractFilename := path.Join(installDir, trimmedName) switch header.Typeflag { case tar.TypeDir: files = append(files, strings.TrimPrefix(header.Name, "files/")) @@ -422,6 +435,13 @@ func InstallPackage(filename, installDir string, force, binaryPkgFromSrc, keepTe fmt.Println("Creating Directory: " + extractFilename) } case tar.TypeReg: + if _, err := os.Stat(extractFilename); err == nil { + if slices.Contains(pkgInfo.Keep, trimmedName) { + fmt.Println("Skipping File: " + extractFilename + "(File is configured to be kept during installs/updates)") + files = append(files, trimmedName) + continue + } + } err := os.Remove(extractFilename) if err != nil && !os.IsNotExist(err) { return err @@ -571,6 +591,7 @@ func InstallPackage(filename, installDir string, force, binaryPkgFromSrc, keepTe cmd.Env = append(cmd.Env, fmt.Sprintf("BPM_PKG_DESC=%s", pkgInfo.Description)) cmd.Env = append(cmd.Env, fmt.Sprintf("BPM_PKG_VERSION=%s", pkgInfo.Version)) cmd.Env = append(cmd.Env, fmt.Sprintf("BPM_PKG_URL=%s", pkgInfo.Url)) + cmd.Env = append(cmd.Env, fmt.Sprintf("BPM_PKG_ARCH=%s", pkgInfo.Arch)) depends := make([]string, len(pkgInfo.Depends)) copy(depends, pkgInfo.Depends) for i := 0; i < len(depends); i++ { @@ -614,6 +635,13 @@ func InstallPackage(filename, installDir string, force, binaryPkgFromSrc, keepTe fmt.Println("Creating Directory: " + extractFilename) } } else if d.Type().IsRegular() { + if _, err := os.Stat(extractFilename); err == nil { + if slices.Contains(pkgInfo.Keep, relFilename) { + fmt.Println("Skipping File: " + extractFilename + "(File is configured to be kept during installs/updates)") + files = append(files, relFilename) + return nil + } + } err := os.Remove(extractFilename) if err != nil && !os.IsNotExist(err) { return err @@ -674,7 +702,7 @@ func InstallPackage(filename, installDir string, force, binaryPkgFromSrc, keepTe compiledInfo = *pkgInfo compiledInfo.Type = "binary" compiledInfo.Arch = GetArch() - err = os.WriteFile(path.Join(compiledDir, "pkg.info"), []byte(CreateInfoFile(compiledInfo)), 0644) + err = os.WriteFile(path.Join(compiledDir, "pkg.info"), []byte(CreateInfoFile(compiledInfo, false)), 0644) if err != nil { return err } @@ -1170,6 +1198,7 @@ func RemovePackage(pkg, rootDir string) error { cmd.Env = append(cmd.Env, fmt.Sprintf("BPM_PKG_DESC=%s", pkgInfo.Description)) cmd.Env = append(cmd.Env, fmt.Sprintf("BPM_PKG_VERSION=%s", pkgInfo.Version)) cmd.Env = append(cmd.Env, fmt.Sprintf("BPM_PKG_URL=%s", pkgInfo.Url)) + cmd.Env = append(cmd.Env, fmt.Sprintf("BPM_PKG_ARCH=%s", pkgInfo.Arch)) depends := make([]string, len(pkgInfo.Depends)) copy(depends, pkgInfo.Depends) for i := 0; i < len(depends); i++ { diff --git a/main.go b/main.go index 8a2fd09..0f1aaa9 100644 --- a/main.go +++ b/main.go @@ -17,7 +17,7 @@ import ( /* A simple-to-use package manager */ /* ---------------------------------- */ -var bpmVer = "0.1.7" +var bpmVer = "0.2.0" var subcommand = "help" var subcommandArgs []string @@ -84,7 +84,7 @@ func resolveCommand() { fmt.Printf("Package (%s) could not be found\n", pkg) continue } - fmt.Print("----------------\n" + bpm_utils.CreateInfoFile(*info)) + fmt.Print("----------------\n" + bpm_utils.CreateInfoFile(*info, true)) if n == len(packages)-1 { fmt.Println("----------------") } @@ -112,7 +112,7 @@ func resolveCommand() { fmt.Printf("Package (%s) could not be found\n", pkg) continue } - fmt.Print("----------------\n" + bpm_utils.CreateInfoFile(*info)) + fmt.Print("----------------\n" + bpm_utils.CreateInfoFile(*info, true)) if n == len(packages)-1 { fmt.Println("----------------") } @@ -133,7 +133,7 @@ func resolveCommand() { if err != nil { log.Fatalf("Could not read package\nError: %s\n", err) } - fmt.Print("----------------\n" + bpm_utils.CreateInfoFile(*pkgInfo)) + fmt.Print("----------------\n" + bpm_utils.CreateInfoFile(*pkgInfo, true)) fmt.Println("----------------") verb := "install" if pkgInfo.Type == "source" { @@ -149,14 +149,14 @@ func resolveCommand() { continue } if pkgInfo.Type == "source" { - if unresolved := bpm_utils.CheckMakeDependencies(pkgInfo, rootDir); len(unresolved) != 0 { + if unresolved := bpm_utils.CheckMakeDependencies(pkgInfo, "/"); len(unresolved) != 0 { fmt.Printf("skipping... cannot %s package (%s) due to missing make dependencies: %s\n", verb, pkgInfo.Name, strings.Join(unresolved, ", ")) continue } } } if rootDir != "/" { - fmt.Println("Warning: Installing to " + rootDir) + fmt.Println("Warning: Operating in " + rootDir) } if !yesAll { reader := bufio.NewReader(os.Stdin) @@ -231,10 +231,10 @@ func resolveCommand() { fmt.Printf("Package (%s) could not be found\n", pkg) continue } - fmt.Print("----------------\n" + bpm_utils.CreateInfoFile(*pkgInfo)) + fmt.Print("----------------\n" + bpm_utils.CreateInfoFile(*pkgInfo, true)) fmt.Println("----------------") if rootDir != "/" { - fmt.Println("Warning: Installing to " + rootDir) + fmt.Println("Warning: Operating in " + rootDir) } if !yesAll { reader := bufio.NewReader(os.Stdin) @@ -305,11 +305,10 @@ func resolveCommand() { } func printHelp() { - fmt.Println("\033[1m------Help------\033[0m") - fmt.Println("\033[1m\\ Command Format /\033[0m") + fmt.Println("\033[1m---- Command Format ----\033[0m") fmt.Println("-> command format: bpm [-flags]...") fmt.Println("-> flags will be read if passed right after the subcommand otherwise they will be read as subcommand arguments") - fmt.Println("\033[1m\\ Command List /\033[0m") + fmt.Println("\033[1m---- Command List ----\033[0m") fmt.Println("-> bpm version | shows information on the installed version of bpm") fmt.Println("-> bpm info [-R] | shows information on an installed package") fmt.Println(" -R= lets you define the root path which will be used") diff --git a/test_packages/x86_64/bpm-utils/bpm-utils.bpm b/test_packages/x86_64/bpm-utils/bpm-utils.bpm index fd349ac..310fd4a 100644 Binary files a/test_packages/x86_64/bpm-utils/bpm-utils.bpm and b/test_packages/x86_64/bpm-utils/bpm-utils.bpm differ diff --git a/test_packages/x86_64/bpm-utils/files/usr/bin/bpm-create b/test_packages/x86_64/bpm-utils/files/usr/bin/bpm-create deleted file mode 100755 index dd887c3..0000000 --- a/test_packages/x86_64/bpm-utils/files/usr/bin/bpm-create +++ /dev/null @@ -1,77 +0,0 @@ -#!/bin/bash -if [ $# -eq 0 ] -then - echo "No output package name given!" - exit 1 -fi - -output=$1 - -if [[ ! "$output" =~ ^[a-z.A-Z0-9_-]{1,}$ ]]; then - echo "Invalid output name! The name must only contain letters, numbers, hyphens or underscores!" - exit 1 -fi - -type="binary" -toCompress=("pkg.info") - -echo "Creating package with the name $output..." - -if [ -d files ]; then - echo "files/ directory found" - toCompress+=("files/") -else - if [ -f source.sh ]; then - type="source" - echo "source.sh file found" - toCompress+=("source.sh") - if [ -f pre_update.sh ]; then - echo "pre_update.sh file found" - toCompress+=("pre_update.sh") - fi - if [ -f post_update.sh ]; then - echo "post_update.sh file found" - toCompress+=("post_update.sh") - fi - if [ -f pre_install.sh ]; then - echo "pre_install.sh file found" - toCompress+=("pre_install.sh") - fi - if [ -f post_install.sh ]; then - echo "post_install.sh file found" - toCompress+=("post_install.sh") - fi - if [ -f post_remove.sh ]; then - echo "post_remove.sh file found" - toCompress+=("post_remove.sh") - fi - if [ -d source-files ]; then - echo "source-files/ directory found" - toCompress+=("source-files/") - fi - else - echo "files/ directory or source.sh file not found in $PWD" - exit 1 - fi -fi - -if [ -f pkg.info ]; then - echo "pkg.info file found" -else - echo "pkg.info file not found in $PWD" - exit 1 -fi - -echo "Creating $type package as $output" - -tar -czf "$output" "${toCompress[@]}" - -#if [[ "$type" == "binary" ]]; then -# tar -czf "$output" files/ pkg.info -#else -# if [ -d source-files ]; then -# tar -czf "$output" source.sh source-files/ pkg.info -# else -# tar -czf "$output" source.sh pkg.info -# fi -#fi diff --git a/test_packages/x86_64/bpm-utils/files/usr/bin/bpm-setup b/test_packages/x86_64/bpm-utils/files/usr/bin/bpm-setup index 2c4948b..2c23ef7 100755 --- a/test_packages/x86_64/bpm-utils/files/usr/bin/bpm-setup +++ b/test_packages/x86_64/bpm-utils/files/usr/bin/bpm-setup @@ -1,66 +1,154 @@ #!/bin/bash -if [ $# -lt 2 ]; then - echo "Arguments missing! Try 'bpm-setup '" + +usage () { + echo "------BPM-Setup options------" + echo "bpm-setup -D | Path to package directory" + echo "bpm-setup -y | Skips confirmation prompt" + echo "bpm-setup -n | Set the package name (Defaults to \"package-name\")" + echo "bpm-setup -d | Set the package description (Defaults to \"Default package description\")" + echo "bpm-setup -v | Set the package version (Defaults to \"1.0\")" + echo "bpm-setup -u | Set the package URL (Optional)" + echo "bpm-setup -l | Set the package licenses (Optional)" + echo "bpm-setup -t | Set the package type to binary or source (Defaults to binary)" + echo "bpm-setup -s | Use a default template file (Defaults to /etc/bpm-utils/source.default)" +} + +if [ $# -eq 0 ]; then + usage + exit +fi + +NAME="package-name" +DESCRIPTION="Default package description" +VERSION="1.0" +#URL="https://my.project.url/ (Optional)" +#LICENSE="Your project's license (Optional)" +TYPE="binary" +SOURCE_FILE="/etc/bpm-utils/source.default" + +while getopts "D:n:d:v:u:l:t:s:y" o; do + case "${o}" in + D) + DIRECTORY="${OPTARG}" + ;; + y) + CONFIRM=yes + ;; + n) + NAME="${OPTARG}" + ;; + d) + DESCRIPTION="${OPTARG}" + ;; + v) + VERSION="${OPTARG}" + ;; + u) + URL="${OPTARG}" + ;; + l) + LICENSE="${OPTARG}" + ;; + t) + TYPE="${OPTARG}" + ;; + s) + SOURCE_FILE="$(realpath ${OPTARG})" + ;; + *) + usage + exit 1 + ;; + esac +done + +if [ -z "${DIRECTORY}" ]; then + echo "Required directory argument missing. Try 'bpm-setup -D [other options...]" exit 1 fi -output=$1 -type=$2 +if [[ ! "${DIRECTORY}" == "/"* ]]; then + DIRECTORY="${PWD}/${DIRECTORY}" +fi -if [[ ! "$output" =~ ^[a-zA-Z0-9_-]{1,}$ ]]; then - echo "Invalid output name! The name must only contain letters, numbers, hyphens or underscores!" +if [ -e "${DIRECTORY}" ]; then + echo "This path already exists" exit 1 fi -if [[ "$type" != "binary" ]] && [[ "$type" != "source" ]]; then +if [[ "$TYPE" != "binary" ]] && [[ "$TYPE" != "source" ]]; then echo "Invalid package type! Package type must be either 'binary' or 'source'" exit 1 fi -mkdir -pv $output -cd $output -if [[ "$type" == "binary" ]]; then - cat > pkg.info << EOF -name: package_name -description: Package Description -version: 1.0 -url: your package's website/repository url. Optonal -license: your package's license. Optional -architecture: $(uname -m) -type: binary -EOF +if [ -z "${CONFIRM}" ]; then + echo "Setting up package working directory at ${DIRECTORY} with the following information:" + echo "Package name: $NAME" + echo "Package description: $DESCRIPTION" + echo "Package version: $VERSION" + if [ -z "${URL}" ]; then + echo "Package URL: Not set" + else + echo "Package URL: $URL" + fi + if [ -z "${LICENSE}" ]; then + echo "Package license: Not set" + else + echo "Package license: $LICENSE" + fi + + echo "Package type: $TYPE" + read -p "Create package directory? [y/N]: " CREATE + case $CREATE in + [Yy]* ) + ;; + *) + echo "Exiting bpm-setup..." + exit + ;; + esac +fi + +if ! mkdir -pv $DIRECTORY; then + echo "Could not create $DIRECTORY!" + exit 1 +fi + +cd $DIRECTORY + +touch pkg.info +echo "name: ${NAME}" >> pkg.info +echo "description: ${DESCRIPTION}" >> pkg.info +echo "version: ${VERSION}" >> pkg.info +if [ ! -z "${URL}" ]; then echo "url: ${URL}" >> pkg.info; fi +if [ ! -z "${LICENSE}" ]; then echo "license: ${LICENSE}" >> pkg.info; fi + +if [[ "$TYPE" == "binary" ]]; then + echo "architecture: $(uname -m)" >> pkg.info + echo "type: binary" >> pkg.info mkdir -pv files echo "Package directory created successfully!" echo "Make sure to edit the pkg.info file with the appropriate information for your package" - echo "Add your binaries under the files/ directory. For example a binary called 'my_binary' should go under files/usr/bin/my_binary" + echo "Add your binaries under the 'files' directory. For example a binary called 'my_binary' should go under files/usr/bin/my_binary" echo "You can turn your package into a .bpm file use the 'bpm-create ' command" else - cat > pkg.info << EOF -name: package_name -description: Package Description -version: 1.0 -url: your package's website/repository url. Optional -license: your package's license. Optional -architecture: any -type: source -EOF - cat > source.sh << 'EOF' -# This is the source.sh script. It is executed by BPM in a temporary directory when compiling a source package -# BPM expects there to be an 'output' directory under the root of the temporary directory after this script finishes executing, otherwise your program may not be correctly installed -# It is recommended you create the 'output' directory along with a 'source' directory in the root of the temporary directory like this -echo "Compiling my_program..." -# Creating 'source' and 'output' directory variables -source=$(pwd)/source -output=$(pwd)/output -# Creating the 'source' and 'output' directories -mkdir $source -mkdir $output -# Downloading files -git clone https://myrepo.com/repo.git source -EOF + echo "architecture: any" >> pkg.info + echo "type: source" >> pkg.info + mkdir -pv source-files + if [ -f "${SOURCE_FILE}" ]; then + touch source.temp + cat "${SOURCE_FILE}" > source.temp + export NAME DESCRIPTION VERSION URL LICENSE TYPE + envsubst '$NAME:$DESCRIPTION:$VERSION:$URL:$LICENSE:$TYPE' < source.temp > source.sh + rm source.temp + else + echo "Source file at ${SOURCE_FILE} does not exist! Creating empty source.sh instead..." + touch source.sh + fi echo "Package directory created successfully!" echo "Make sure to edit the pkg.info file with the appropriate information for your package" - echo "Add your compilation code in the source.sh file. Follow the instructions on the template file on how to do properly compile your program" - echo "You can turn your package into a .bpm file use the 'bpm-create ' command" + echo "Add your compilation code in the source.sh file. Follow the instructions on the template file on how to properly create your compilation script" + echo "You can add additional files that will be used during compilation to the 'source-files' directory" + echo "You can turn your package into a .bpm file use the 'bpm-package ' command" fi diff --git a/test_packages/x86_64/bpm-utils/pkg.info b/test_packages/x86_64/bpm-utils/pkg.info index fc302ae..f54fdd1 100644 --- a/test_packages/x86_64/bpm-utils/pkg.info +++ b/test_packages/x86_64/bpm-utils/pkg.info @@ -1,7 +1,8 @@ name: bpm-utils description: Utilities to create BPM packages -version: 1.4.0 +version: 2.0.0 url: https://gitlab.com/bubble-package-manager/bpm/ license: GPL3 -architecture: x86_64 -type: binary \ No newline at end of file +architecture: any +keep: etc/bpm-utils/source.default +type: binary diff --git a/test_packages/x86_64/bpm/bpm.bpm b/test_packages/x86_64/bpm/bpm.bpm index 85b64a6..49eb8ec 100644 Binary files a/test_packages/x86_64/bpm/bpm.bpm and b/test_packages/x86_64/bpm/bpm.bpm differ diff --git a/test_packages/x86_64/bpm/files/usr/bin/bpm b/test_packages/x86_64/bpm/files/usr/bin/bpm index 86e8164..670308f 100755 Binary files a/test_packages/x86_64/bpm/files/usr/bin/bpm and b/test_packages/x86_64/bpm/files/usr/bin/bpm differ diff --git a/test_packages/x86_64/bpm/pkg.info b/test_packages/x86_64/bpm/pkg.info index 7e8cac3..bf3de5d 100644 --- a/test_packages/x86_64/bpm/pkg.info +++ b/test_packages/x86_64/bpm/pkg.info @@ -1,6 +1,6 @@ name: bpm description: The Bubble Package Manager -version: 0.1.7 +version: 0.2.0 url: https://gitlab.com/bubble-package-manager/bpm/ license: GPL3 architecture: x86_64