- Added a -b flag to the install subcommand that turns a source package into a binary one after compilation

- Reformatted the help subcommand
- Updated bpm-utils to add the ability to create source packages
- Source temporary directories will now be removed after installation unless the user passes the -k flag
- BPM will now not remove the old version of a package before installing an update which could cause libraries or programs required for installation to be missing. Obsolete files will now be removed after installation
- The version, list, info and help subcommands can now be run by any user without root permissions. Root permissions are still required for package installation and removal
- Removed installed package info fixing for now. It will be replaced by a better system in the future
This commit is contained in:
CapCreeperGR 2024-03-30 22:22:31 +02:00
parent 43c4a626f1
commit a9283037d8
9 changed files with 184 additions and 31 deletions

View File

@ -130,10 +130,16 @@ func ReadPackageInfo(contents string, defaultValues bool) (*PackageInfo, error)
split[1] = strings.Trim(split[1], " ")
switch split[0] {
case "name":
if strings.Contains(split[1], " ") {
return nil, errors.New("the " + split[0] + " field cannot contain spaces")
}
pkgInfo.Name = split[1]
case "description":
pkgInfo.Description = split[1]
case "version":
if strings.Contains(split[1], " ") {
return nil, errors.New("the " + split[0] + " field cannot contain spaces")
}
pkgInfo.Version = split[1]
case "url":
pkgInfo.Url = split[1]
@ -192,7 +198,7 @@ func CreateInfoFile(pkgInfo PackageInfo) string {
return ret
}
func InstallPackage(filename, installDir string, force bool) error {
func InstallPackage(filename, installDir string, force, binaryPkgFromSrc, keepTempDir bool) error {
if _, err := os.Stat(filename); os.IsNotExist(err) {
return err
}
@ -205,13 +211,17 @@ func InstallPackage(filename, installDir string, force bool) error {
return err
}
tr := tar.NewReader(archive)
var oldFiles []string
var files []string
pkgInfo, err := ReadPackage(filename)
if err != nil {
return err
}
if IsPackageInstalled(pkgInfo.Name, installDir) {
oldFiles = GetPackageFiles(pkgInfo.Name, installDir)
}
if !force {
if pkgInfo.Arch != GetArch() {
if pkgInfo.Arch != "any" && pkgInfo.Arch != GetArch() {
return errors.New("cannot install a package with a different architecture")
}
if unresolved := CheckDependencies(pkgInfo, installDir); len(unresolved) != 0 {
@ -307,7 +317,12 @@ func InstallPackage(filename, installDir string, force bool) error {
if err != nil {
return err
}
temp, err := os.MkdirTemp("/var/tmp/", "bpm_source-")
temp := "/var/tmp/bpm_source-" + pkgInfo.Name
err = os.RemoveAll(temp)
if err != nil {
return err
}
err = os.Mkdir(temp, 0755)
fmt.Println("Creating temp directory at: " + temp)
if err != nil {
return err
@ -352,6 +367,10 @@ func InstallPackage(filename, installDir string, force bool) error {
fmt.Println("Creating Directory: " + extractFilename)
}
} else if d.Type().IsRegular() {
err := os.Remove(extractFilename)
if err != nil && !os.IsNotExist(err) {
return err
}
outFile, err := os.Create(extractFilename)
fmt.Println("Creating File: " + extractFilename)
files = append(files, relFilename)
@ -385,6 +404,10 @@ func InstallPackage(filename, installDir string, force bool) error {
if err != nil {
return err
}
err = os.Remove(extractFilename)
if err != nil && !os.IsNotExist(err) {
return err
}
fmt.Println("Creating Symlink: "+extractFilename, " -> "+link)
files = append(files, relFilename)
err = os.Symlink(link, extractFilename)
@ -397,6 +420,39 @@ func InstallPackage(filename, installDir string, force bool) error {
if err != nil {
return err
}
if binaryPkgFromSrc {
compiledDir := path.Join(installDir, "var/lib/bpm/compiled/")
err = os.MkdirAll(compiledDir, 755)
compiledInfo := PackageInfo{}
compiledInfo = *pkgInfo
compiledInfo.Type = "binary"
compiledInfo.Arch = GetArch()
err = os.WriteFile(path.Join(compiledDir, "pkg.info"), []byte(CreateInfoFile(compiledInfo)), 0644)
if err != nil {
return err
}
sed := fmt.Sprintf("s/%s/files/", strings.Replace(strings.TrimPrefix(path.Join(temp, "/output/"), "/"), "/", `\/`, -1))
cmd := exec.Command("/usr/bin/tar", "-czvf", compiledInfo.Name+".bpm", "pkg.info", path.Join(temp, "/output/"), "--transform", sed)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Dir = compiledDir
fmt.Printf("running command: %s %s\n", cmd.Path, strings.Join(cmd.Args, " "))
err := cmd.Run()
if err != nil {
return err
}
err = os.Remove(path.Join(compiledDir, "pkg.info"))
if err != nil {
return err
}
}
if !keepTempDir {
err := os.RemoveAll(temp)
if err != nil {
return err
}
}
}
}
} else {
@ -405,6 +461,10 @@ func InstallPackage(filename, installDir string, force bool) error {
slices.Sort(files)
slices.Reverse(files)
filesDiff := slices.DeleteFunc(oldFiles, func(f string) bool {
return slices.Contains(files, f)
})
installedDir := path.Join(installDir, "var/lib/bpm/installed/")
err = os.MkdirAll(installedDir, 755)
if err != nil {
@ -460,6 +520,12 @@ func InstallPackage(filename, installDir string, force bool) error {
if err != nil {
return err
}
if len(filesDiff) != 0 {
fmt.Println("Removing obsolete files")
for _, f := range filesDiff {
fmt.Println("Removing: " + path.Join(installedDir, f))
}
}
return nil
}

49
main.go
View File

@ -6,9 +6,7 @@ import (
"fmt"
"log"
"os"
"path"
"slices"
"strconv"
"strings"
)
@ -17,11 +15,11 @@ import (
/* A simple-to-use package manager */
/* ---------------------------------- */
var bpmVer = "0.0.9"
var bpmVer = "0.1.0"
var rootDir = "/"
func main() {
errs, fixed := bpm_utils.FixInstalledPackages(rootDir)
/*errs, fixed := bpm_utils.FixInstalledPackages(rootDir)
if len(errs) != 0 {
for pkg, err := range errs {
fmt.Printf("Package (%s) could not be read properly\nError: %s\n", pkg, err.Error())
@ -32,11 +30,7 @@ func main() {
if fixed != 0 {
fmt.Println("Fixed " + strconv.Itoa(fixed) + " outdated package info files")
}
}
if os.Getuid() != 0 {
fmt.Println("BPM needs to be run with superuser permissions")
os.Exit(0)
}
}*/
resolveCommand()
}
@ -135,6 +129,10 @@ func resolveCommand() {
}
}
case install:
if os.Getuid() != 0 {
fmt.Println("This subcommand needs to be run with superuser permissions")
os.Exit(0)
}
flags, i := resolveFlags()
files := getArgs()[1+i:]
if len(files) == 0 {
@ -153,7 +151,7 @@ func resolveCommand() {
verb = "build"
}
if !slices.Contains(flags, "f") {
if pkgInfo.Arch != bpm_utils.GetArch() {
if pkgInfo.Arch != "any" && pkgInfo.Arch != bpm_utils.GetArch() {
fmt.Printf("skipping... cannot %s a package with a different architecture\n", verb)
continue
}
@ -203,10 +201,6 @@ func resolveCommand() {
continue
}
}
err := bpm_utils.RemovePackage(pkgInfo.Name, rootDir)
if err != nil {
log.Fatalf("Could not remove current version of the package\nError: %s\n", err)
}
} else if !slices.Contains(flags, "y") {
reader := bufio.NewReader(os.Stdin)
fmt.Printf("Do you wish to %s this package? [y\\N] ", verb)
@ -217,19 +211,23 @@ func resolveCommand() {
}
}
err = bpm_utils.InstallPackage(file, rootDir, slices.Contains(flags, "f"))
err = bpm_utils.InstallPackage(file, rootDir, slices.Contains(flags, "f"), slices.Contains(flags, "b"), slices.Contains(flags, "k"))
if err != nil {
if pkgInfo.Type == "source" {
fmt.Println("** It is recommended you delete the temporary bpm folder in /var/tmp **")
if pkgInfo.Type == "source" && slices.Contains(flags, "k") {
fmt.Println("BPM temp directory was created at /var/tmp/bpm_source-" + pkgInfo.Name)
}
log.Fatalf("Could not install package\nError: %s\n", err)
}
fmt.Printf("Package (%s) was successfully installed!\n", pkgInfo.Name)
if pkgInfo.Type == "source" {
if pkgInfo.Type == "source" && slices.Contains(flags, "k") {
fmt.Println("** It is recommended you delete the temporary bpm folder in /var/tmp **")
}
}
case remove:
if os.Getuid() != 0 {
fmt.Println("This subcommand needs to be run with superuser permissions")
os.Exit(0)
}
flags, i := resolveFlags()
packages := getArgs()[1+i:]
if len(packages) == 0 {
@ -268,9 +266,16 @@ func resolveCommand() {
fmt.Println("\033[1m\\ Command List /\033[0m")
fmt.Println("-> bpm version | shows information on the installed version of bpm")
fmt.Println("-> bpm info | shows information on an installed package")
fmt.Println("-> bpm list [-n, -l] | lists all installed packages. -n shows the number of packages. -l lists package names only")
fmt.Println("-> bpm install [-y, -f] <files...> | installs the following files. -y skips the confirmation prompt. -f skips dependency and architecture checking")
fmt.Println("-> bpm remove [-y] <packages...> | removes the following packages. -y skips the confirmation prompt")
fmt.Println("-> bpm list [-n, -l] | lists all installed packages")
fmt.Println(" -n shows the number of packages")
fmt.Println(" -l lists package names only")
fmt.Println("-> bpm install [-y, -f, -b] <files...> | installs the following files")
fmt.Println(" -y skips the confirmation prompt")
fmt.Println(" -f skips dependency and architecture checking")
fmt.Println(" -b creates a binary package for a source package after compilation and saves it in /var/lib/bpm/compiled")
fmt.Println(" -k keeps the temp directory created by BPM after source package installation")
fmt.Println("-> bpm remove [-y] <packages...> | removes the following packages")
fmt.Println(" -y skips the confirmation prompt")
fmt.Println("-> bpm cleanup | removes all unneeded dependencies")
fmt.Println("\033[1m----------------\033[0m")
}
@ -292,7 +297,7 @@ func resolveFlags() ([]string, int) {
}
ret = append(ret, f)
case install:
v := [...]string{"y", "f"}
v := [...]string{"y", "f", "b", "k"}
if !slices.Contains(v[:], f) {
log.Fatalf("Invalid flag " + flag)
}

View File

@ -7,13 +7,25 @@ fi
output=$1
if [[ ! "$output" =~ ^[a-zA-Z0-9_-]{1,}$ ]]; then
echo "Invalid output name! The name must only contain letters, numbers, hyphens or underscores!"
exit 1
fi
type="binary"
echo "Creating package with the name $output..."
if [ -d files ]; then
echo "files/ directory found"
else
echo "files/ directory not found in $PWD"
if [ -f source.sh ]; then
type="source"
echo "source.sh file found"
else
echo "files/ directory or source.sh file not found in $PWD"
exit 1
fi
fi
if [ -f pkg.info ]; then
@ -23,6 +35,10 @@ else
exit 1
fi
echo "Creating $output.bpm package..."
echo "Creating $type package as $output.bpm"
tar -czf $output.bpm files/ pkg.info
if [[ "$type" == "binary" ]]; then
tar -czf "$output".bpm files/ pkg.info
else
tar -czf "$output".bpm source.sh pkg.info
fi

View File

@ -0,0 +1,66 @@
#!/bin/bash
if [ $# -lt 2 ]; then
echo "Arguments missing! Try 'bpm-setup <directory> <binary/source>'"
exit 1
fi
output=$1
type=$2
if [[ ! "$output" =~ ^[a-zA-Z0-9_-]{1,}$ ]]; then
echo "Invalid output name! The name must only contain letters, numbers, hyphens or underscores!"
exit 1
fi
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
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 "You can turn your package into a .bpm file use the 'bpm-create <name>' 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 "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 <name>' command"
fi

View File

@ -1,6 +1,6 @@
name: bpm-utils
description: Utilities to create BPM packages
version: 1.0.0
version: 1.2.0
url: https://gitlab.com/bubble-package-manager/bpm/
license: GPL3
architecture: x86_64

Binary file not shown.

View File

@ -1,6 +1,6 @@
name: bpm
description: The Bubble Package Manager
version: 0.0.9
version: 0.1.0
url: https://gitlab.com/bubble-package-manager/bpm/
license: GPL3
architecture: x86_64