Compare commits
10 Commits
5085981f52
...
1329109810
Author | SHA1 | Date | |
---|---|---|---|
1329109810 | |||
4a8c4e22ec | |||
eb8db1bc99 | |||
4f1eeeb11d | |||
2e416b9e6f | |||
d8a42c780d | |||
b1bb8de661 | |||
c425b263fe | |||
5776784021 | |||
903c7dce3e |
@ -45,7 +45,7 @@ You can remove an installed package by typing the following
|
||||
bpm remove package_name
|
||||
```
|
||||
|
||||
To remove all unused dependencies try using the cleanup command
|
||||
To remove all unused dependencies and clean cached files try using the cleanup command
|
||||
```sh
|
||||
bpm cleanup
|
||||
```
|
||||
|
162
src/bpm/main.go
162
src/bpm/main.go
@ -42,7 +42,11 @@ var doCleanup = false
|
||||
var showRepoInfo = false
|
||||
var installSrcPkgDepends = false
|
||||
var skipChecks = false
|
||||
var outputFilename = ""
|
||||
var outputDirectory = ""
|
||||
var cleanupDependencies = false
|
||||
var cleanupCompilationFiles = false
|
||||
var cleanupCompiledPackages = false
|
||||
var cleanupFetchedPackages = false
|
||||
|
||||
func main() {
|
||||
err := bpmlib.ReadConfig()
|
||||
@ -456,51 +460,58 @@ func resolveCommand() {
|
||||
log.Fatalf("Error: this subcommand needs to be run with superuser permissions")
|
||||
}
|
||||
|
||||
// Read local databases
|
||||
err := bpmlib.ReadLocalDatabases()
|
||||
err := bpmlib.CleanupCache(rootDir, cleanupCompilationFiles, cleanupCompiledPackages, cleanupFetchedPackages, verbose)
|
||||
if err != nil {
|
||||
log.Fatalf("Error: could not read local databases: %s", err)
|
||||
log.Fatalf("Error: could not complete cache cleanup: %s", err)
|
||||
}
|
||||
|
||||
// Create cleanup operation
|
||||
operation, err := bpmlib.CleanupPackages(rootDir, verbose)
|
||||
if errors.As(err, &bpmlib.PackageNotFoundErr{}) || errors.As(err, &bpmlib.DependencyNotFoundErr{}) || errors.As(err, &bpmlib.PackageConflictErr{}) {
|
||||
log.Fatalf("Error: %s", err)
|
||||
} else if err != nil {
|
||||
log.Fatalf("Error: could not setup operation: %s\n", err)
|
||||
}
|
||||
|
||||
// Exit if operation contains no actions
|
||||
if len(operation.Actions) == 0 {
|
||||
fmt.Println("No action needs to be taken")
|
||||
return
|
||||
}
|
||||
|
||||
// Show operation summary
|
||||
operation.ShowOperationSummary()
|
||||
|
||||
// Confirmation Prompt
|
||||
if !yesAll {
|
||||
fmt.Printf("Are you sure you wish to remove all %d packages? [y\\N] ", len(operation.Actions))
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
text, _ := reader.ReadString('\n')
|
||||
if strings.TrimSpace(strings.ToLower(text)) != "y" && strings.TrimSpace(strings.ToLower(text)) != "yes" {
|
||||
fmt.Println("Cancelling package removal...")
|
||||
os.Exit(1)
|
||||
if cleanupDependencies {
|
||||
// Read local databases
|
||||
err := bpmlib.ReadLocalDatabases()
|
||||
if err != nil {
|
||||
log.Fatalf("Error: could not read local databases: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Execute operation
|
||||
err = operation.Execute(verbose, force)
|
||||
if err != nil {
|
||||
log.Fatalf("Error: could not complete operation: %s\n", err)
|
||||
}
|
||||
// Create cleanup operation
|
||||
operation, err := bpmlib.CleanupPackages(rootDir, verbose)
|
||||
if errors.As(err, &bpmlib.PackageNotFoundErr{}) || errors.As(err, &bpmlib.DependencyNotFoundErr{}) || errors.As(err, &bpmlib.PackageConflictErr{}) {
|
||||
log.Fatalf("Error: %s", err)
|
||||
} else if err != nil {
|
||||
log.Fatalf("Error: could not setup operation: %s\n", err)
|
||||
}
|
||||
|
||||
// Executing hooks
|
||||
fmt.Println("Running hooks...")
|
||||
err = operation.RunHooks(verbose)
|
||||
if err != nil {
|
||||
log.Fatalf("Error: could not run hooks: %s\n", err)
|
||||
// Exit if operation contains no actions
|
||||
if len(operation.Actions) == 0 {
|
||||
fmt.Println("No action needs to be taken")
|
||||
return
|
||||
}
|
||||
|
||||
// Show operation summary
|
||||
operation.ShowOperationSummary()
|
||||
|
||||
// Confirmation Prompt
|
||||
if !yesAll {
|
||||
fmt.Printf("Are you sure you wish to remove all %d packages? [y\\N] ", len(operation.Actions))
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
text, _ := reader.ReadString('\n')
|
||||
if strings.TrimSpace(strings.ToLower(text)) != "y" && strings.TrimSpace(strings.ToLower(text)) != "yes" {
|
||||
fmt.Println("Cancelling package removal...")
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
// Execute operation
|
||||
err = operation.Execute(verbose, force)
|
||||
if err != nil {
|
||||
log.Fatalf("Error: could not complete operation: %s\n", err)
|
||||
}
|
||||
|
||||
// Executing hooks
|
||||
fmt.Println("Running hooks...")
|
||||
err = operation.RunHooks(verbose)
|
||||
if err != nil {
|
||||
log.Fatalf("Error: could not run hooks: %s\n", err)
|
||||
}
|
||||
}
|
||||
case file:
|
||||
files := subcommandArgs
|
||||
@ -609,7 +620,9 @@ func resolveCommand() {
|
||||
}
|
||||
|
||||
// Run 'bpm install' using the set privilege escalator command
|
||||
cmd := exec.Command(bpmlib.BPMConfig.PrivilegeEscalatorCmd, executable, "install", "--installation-reason=dependency", strings.Join(unmetDepends, " "))
|
||||
args := []string{executable, "install", "--installation-reason=dependency"}
|
||||
args = append(args, unmetDepends...)
|
||||
cmd := exec.Command(bpmlib.BPMConfig.PrivilegeEscalatorCmd, args...)
|
||||
if yesAll {
|
||||
cmd.Args = slices.Insert(cmd.Args, 3, "-y")
|
||||
}
|
||||
@ -642,36 +655,40 @@ func resolveCommand() {
|
||||
log.Fatalf("Error: could not get user home directory: %s", err)
|
||||
}
|
||||
|
||||
// Trim output filename
|
||||
outputFilename = strings.TrimSpace(outputFilename)
|
||||
if outputFilename != "/" {
|
||||
outputFilename = strings.TrimSuffix(outputFilename, "/")
|
||||
// Trim output directory
|
||||
outputDirectory = strings.TrimSpace(outputDirectory)
|
||||
if outputDirectory != "/" {
|
||||
outputDirectory = strings.TrimSuffix(outputDirectory, "/")
|
||||
}
|
||||
|
||||
// Set output filename if empty
|
||||
if outputFilename == "" {
|
||||
outputFilename = path.Join(workdir, fmt.Sprintf("%s-%s-%d.bpm", bpmpkg.PkgInfo.Name, bpmpkg.PkgInfo.Version, bpmpkg.PkgInfo.Revision))
|
||||
// Set output directory if empty
|
||||
if outputDirectory == "" {
|
||||
outputDirectory = workdir
|
||||
}
|
||||
|
||||
// Replace first tilde with user home directory
|
||||
if strings.Split(outputFilename, "/")[0] == "~" {
|
||||
outputFilename = strings.Replace(outputFilename, "~", homedir, 1)
|
||||
if strings.Split(outputDirectory, "/")[0] == "~" {
|
||||
outputDirectory = strings.Replace(outputDirectory, "~", homedir, 1)
|
||||
}
|
||||
|
||||
// Prepend current working directory to output filename if not an absolute path
|
||||
if outputFilename != "" && !strings.HasPrefix(outputFilename, "/") {
|
||||
outputFilename = filepath.Join(workdir, outputFilename)
|
||||
// Prepend current working directory to output directory if not an absolute path
|
||||
if outputDirectory != "" && !strings.HasPrefix(outputDirectory, "/") {
|
||||
outputDirectory = filepath.Join(workdir, outputDirectory)
|
||||
}
|
||||
|
||||
// Clean path
|
||||
path.Clean(outputFilename)
|
||||
path.Clean(outputDirectory)
|
||||
|
||||
// Append archive filename if path is set to a directory
|
||||
if stat, err := os.Stat(outputFilename); err == nil && stat.IsDir() {
|
||||
outputFilename = path.Join(outputFilename, fmt.Sprintf("%s-%s-%d.bpm", bpmpkg.PkgInfo.Name, bpmpkg.PkgInfo.Version, bpmpkg.PkgInfo.Revision))
|
||||
// Ensure output directory exists and is a directory
|
||||
stat, err := os.Stat(outputDirectory)
|
||||
if err != nil {
|
||||
log.Fatalf("Error: could not stat output directory (%s): %s", outputDirectory, err)
|
||||
}
|
||||
if !stat.IsDir() {
|
||||
log.Fatalf("Error: output directory (%s) is not a directory", outputDirectory)
|
||||
}
|
||||
|
||||
outputBpmPackages, err := bpmlib.CompileSourcePackage(sourcePackage, outputFilename, skipChecks)
|
||||
outputBpmPackages, err := bpmlib.CompileSourcePackage(sourcePackage, outputDirectory, skipChecks)
|
||||
if err != nil {
|
||||
log.Fatalf("Error: could not compile source package (%s): %s", sourcePackage, err)
|
||||
}
|
||||
@ -725,12 +742,11 @@ func printHelp() {
|
||||
fmt.Println(" -c lists the amount of installed packages")
|
||||
fmt.Println(" -n lists only the names of installed packages")
|
||||
fmt.Println("-> bpm search <search terms...> | Searches for packages through declared repositories")
|
||||
fmt.Println("-> bpm install [-R, -v, -y, -f, -o, -c, -b, -k, --reinstall, --reinstall-all, --no-optional, --installation-reason] <packages...> | installs the following files")
|
||||
fmt.Println("-> bpm install [-R, -v, -y, -f, --reinstall, --reinstall-all, --no-optional, --installation-reason] <packages...> | installs the following files")
|
||||
fmt.Println(" -R=<path> lets you define the root path which will be used")
|
||||
fmt.Println(" -v Show additional information about what BPM is doing")
|
||||
fmt.Println(" -y skips the confirmation prompt")
|
||||
fmt.Println(" -f skips dependency, conflict and architecture checking")
|
||||
fmt.Println(" -k keeps the compilation directory created by BPM after source package installation")
|
||||
fmt.Println(" --reinstall Reinstalls packages even if they do not have a newer version available")
|
||||
fmt.Println(" --reinstall-all Same as --reinstall but also reinstalls dependencies")
|
||||
fmt.Println(" --no-optional Prevents installation of optional dependencies")
|
||||
@ -752,17 +768,21 @@ func printHelp() {
|
||||
fmt.Println(" -y skips the confirmation prompt")
|
||||
fmt.Println(" --unused removes only packages that aren't required as dependencies by other packages")
|
||||
fmt.Println(" --cleanup performs a dependency cleanup")
|
||||
fmt.Println("-> bpm cleanup [-R, -v, -y] | remove all unused dependency packages")
|
||||
fmt.Println("-> bpm cleanup [-R, -v, -y, --depends, --compilation-files, --compiled-pkgs, --fetched-pkgs] | remove all unused dependencies and cache directories")
|
||||
fmt.Println(" -v Show additional information about what BPM is doing")
|
||||
fmt.Println(" -R=<path> lets you define the root path which will be used")
|
||||
fmt.Println(" -y skips the confirmation prompt")
|
||||
fmt.Println(" --depends performs a dependency cleanup")
|
||||
fmt.Println(" --compilation-files performs a cleanup of compilation files")
|
||||
fmt.Println(" --compiled-pkgs performs a cleanup of compilation compiled binary packages")
|
||||
fmt.Println(" --fetched-pkgs performs a cleanup of fetched packages from repositories")
|
||||
fmt.Println("-> bpm file [-R] <files...> | shows what packages the following packages are managed by")
|
||||
fmt.Println(" -R=<root_path> lets you define the root path which will be used")
|
||||
fmt.Println("-> bpm compile [-d, -s, -o] <source packages...> | Compile source BPM package")
|
||||
fmt.Println(" -v Show additional information about what BPM is doing")
|
||||
fmt.Println(" -d installs required dependencies for package compilation")
|
||||
fmt.Println(" -s skips the check function in source.sh scripts")
|
||||
fmt.Println(" -o sets output filename")
|
||||
fmt.Println(" -o sets output directory")
|
||||
fmt.Println(" -y skips the confirmation prompt")
|
||||
|
||||
fmt.Println("\033[1m----------------\033[0m")
|
||||
@ -818,6 +838,10 @@ func resolveFlags() {
|
||||
cleanupFlagSet.StringVar(&rootDir, "R", "/", "Set the destination root")
|
||||
cleanupFlagSet.BoolVar(&verbose, "v", false, "Show additional information about what BPM is doing")
|
||||
cleanupFlagSet.BoolVar(&yesAll, "y", false, "Skip confirmation prompts")
|
||||
cleanupFlagSet.BoolVar(&cleanupDependencies, "depends", false, "Perform a dependency cleanup")
|
||||
cleanupFlagSet.BoolVar(&cleanupCompilationFiles, "compilation-files", false, "Perform a cleanup of compilation files")
|
||||
cleanupFlagSet.BoolVar(&cleanupCompiledPackages, "compiled-pkgs", false, "Perform a cleanup of compilation compiled binary packages")
|
||||
cleanupFlagSet.BoolVar(&cleanupFetchedPackages, "fetched-pkgs", false, "Perform a cleanup of fetched packages from repositories")
|
||||
cleanupFlagSet.Usage = printHelp
|
||||
// File flags
|
||||
fileFlagSet := flag.NewFlagSet("Remove flags", flag.ExitOnError)
|
||||
@ -827,7 +851,7 @@ func resolveFlags() {
|
||||
compileFlagSet := flag.NewFlagSet("Compile flags", flag.ExitOnError)
|
||||
compileFlagSet.BoolVar(&installSrcPkgDepends, "d", false, "Install required dependencies for package compilation")
|
||||
compileFlagSet.BoolVar(&skipChecks, "s", false, "Skip the check function in source.sh scripts")
|
||||
compileFlagSet.StringVar(&outputFilename, "o", "", "Set output filename")
|
||||
compileFlagSet.StringVar(&outputDirectory, "o", "", "Set output directory")
|
||||
compileFlagSet.BoolVar(&verbose, "v", false, "Show additional information about what BPM is doing")
|
||||
compileFlagSet.BoolVar(&yesAll, "y", false, "Skip confirmation prompts")
|
||||
|
||||
@ -873,6 +897,18 @@ func resolveFlags() {
|
||||
return
|
||||
}
|
||||
subcommandArgs = removeFlagSet.Args()
|
||||
} else if getCommandType() == cleanup {
|
||||
err := cleanupFlagSet.Parse(subcommandArgs)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if !cleanupDependencies && !cleanupCompilationFiles && !cleanupCompiledPackages && !cleanupFetchedPackages {
|
||||
cleanupDependencies = true
|
||||
cleanupCompilationFiles = true
|
||||
cleanupCompiledPackages = true
|
||||
cleanupFetchedPackages = true
|
||||
}
|
||||
subcommandArgs = cleanupFlagSet.Args()
|
||||
} else if getCommandType() == file {
|
||||
err := fileFlagSet.Parse(subcommandArgs)
|
||||
if err != nil {
|
||||
|
@ -15,7 +15,7 @@ import (
|
||||
var rootCompilationUID = "65534"
|
||||
var rootCompilationGID = "65534"
|
||||
|
||||
func CompileSourcePackage(archiveFilename, outputFilename string, skipChecks bool) (outputBpmPackages map[string]string, err error) {
|
||||
func CompileSourcePackage(archiveFilename, outputDirectory string, skipChecks bool) (outputBpmPackages map[string]string, err error) {
|
||||
// Initialize map
|
||||
outputBpmPackages = make(map[string]string)
|
||||
|
||||
@ -60,7 +60,13 @@ func CompileSourcePackage(archiveFilename, outputFilename string, skipChecks boo
|
||||
gid = os.Getgid()
|
||||
}
|
||||
|
||||
tempDirectory := path.Join(homeDir, ".cache/bpm/compilation/", bpmpkg.PkgInfo.Name)
|
||||
// Set temporary directory
|
||||
var tempDirectory string
|
||||
if os.Getuid() == 0 {
|
||||
tempDirectory = path.Join("/var/cache/bpm/compilation/", bpmpkg.PkgInfo.Name)
|
||||
} else {
|
||||
tempDirectory = path.Join(homeDir, ".cache/bpm/compilation/", bpmpkg.PkgInfo.Name)
|
||||
}
|
||||
|
||||
// Ensure temporary directory does not exist
|
||||
if _, err := os.Stat(tempDirectory); err == nil {
|
||||
@ -144,8 +150,10 @@ func CompileSourcePackage(archiveFilename, outputFilename string, skipChecks boo
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
cmd.Env = env
|
||||
cmd.SysProcAttr = &syscall.SysProcAttr{}
|
||||
cmd.SysProcAttr.Credential = &syscall.Credential{Uid: uint32(uid), Gid: uint32(gid)}
|
||||
if os.Getuid() == 0 {
|
||||
cmd.SysProcAttr = &syscall.SysProcAttr{}
|
||||
cmd.SysProcAttr.Credential = &syscall.Credential{Uid: uint32(uid), Gid: uint32(gid)}
|
||||
}
|
||||
err = cmd.Run()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -163,29 +171,27 @@ func CompileSourcePackage(archiveFilename, outputFilename string, skipChecks boo
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
cmd.Env = env
|
||||
cmd.SysProcAttr = &syscall.SysProcAttr{}
|
||||
cmd.SysProcAttr.Credential = &syscall.Credential{Uid: uint32(uid), Gid: uint32(gid)}
|
||||
if os.Getuid() == 0 {
|
||||
cmd.SysProcAttr = &syscall.SysProcAttr{}
|
||||
cmd.SysProcAttr.Credential = &syscall.Credential{Uid: uint32(uid), Gid: uint32(gid)}
|
||||
}
|
||||
err = cmd.Run()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Variable that will be used later
|
||||
isSplitPkg := true
|
||||
|
||||
// Get all packages to compile
|
||||
packagesToCompile := bpmpkg.PkgInfo.SplitPackages
|
||||
if len(packagesToCompile) == 0 {
|
||||
if !bpmpkg.PkgInfo.IsSplitPackage() {
|
||||
packagesToCompile = append(packagesToCompile, bpmpkg.PkgInfo)
|
||||
isSplitPkg = false
|
||||
}
|
||||
|
||||
// Compile each package
|
||||
for _, pkg := range packagesToCompile {
|
||||
// Get package function name
|
||||
packageFunctionName := "package"
|
||||
if isSplitPkg {
|
||||
if bpmpkg.PkgInfo.IsSplitPackage() {
|
||||
packageFunctionName = "package_" + pkg.Name
|
||||
}
|
||||
|
||||
@ -221,8 +227,10 @@ func CompileSourcePackage(archiveFilename, outputFilename string, skipChecks boo
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
cmd.Env = env
|
||||
cmd.SysProcAttr = &syscall.SysProcAttr{}
|
||||
cmd.SysProcAttr.Credential = &syscall.Credential{Uid: uint32(uid), Gid: uint32(gid)}
|
||||
if os.Getuid() == 0 {
|
||||
cmd.SysProcAttr = &syscall.SysProcAttr{}
|
||||
cmd.SysProcAttr.Credential = &syscall.Credential{Uid: uint32(uid), Gid: uint32(gid)}
|
||||
}
|
||||
err = cmd.Run()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -234,36 +242,17 @@ func CompileSourcePackage(archiveFilename, outputFilename string, skipChecks boo
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
cmd.Env = env
|
||||
cmd.SysProcAttr = &syscall.SysProcAttr{}
|
||||
cmd.SysProcAttr.Credential = &syscall.Credential{Uid: uint32(uid), Gid: uint32(gid)}
|
||||
if os.Getuid() == 0 {
|
||||
cmd.SysProcAttr = &syscall.SysProcAttr{}
|
||||
cmd.SysProcAttr.Credential = &syscall.Credential{Uid: uint32(uid), Gid: uint32(gid)}
|
||||
}
|
||||
err = cmd.Run()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("files.tar.gz archive could not be created: %s", err)
|
||||
}
|
||||
|
||||
// Clone source package info
|
||||
var pkgInfo PackageInfo
|
||||
if !isSplitPkg {
|
||||
pkgInfo = *bpmpkg.PkgInfo
|
||||
} else {
|
||||
pkgInfo = *pkg
|
||||
|
||||
// Ensure required fields are set
|
||||
if strings.TrimSpace(pkgInfo.Name) == "" {
|
||||
return nil, fmt.Errorf("split package name is empty")
|
||||
}
|
||||
|
||||
// Copy data from main source package
|
||||
if pkgInfo.Description == "" {
|
||||
pkgInfo.Description = bpmpkg.PkgInfo.Description
|
||||
}
|
||||
pkgInfo.Version = bpmpkg.PkgInfo.Version
|
||||
pkgInfo.Revision = bpmpkg.PkgInfo.Revision
|
||||
pkgInfo.Url = bpmpkg.PkgInfo.Url
|
||||
if pkgInfo.License == "" {
|
||||
pkgInfo.License = bpmpkg.PkgInfo.License
|
||||
}
|
||||
}
|
||||
pkgInfo := *pkg
|
||||
|
||||
// Set package type to binary
|
||||
pkgInfo.Type = "binary"
|
||||
@ -313,8 +302,10 @@ func CompileSourcePackage(archiveFilename, outputFilename string, skipChecks boo
|
||||
return nil, err
|
||||
}
|
||||
cmd.Env = append(env, "CURRENT_DIR="+currentDir)
|
||||
cmd.SysProcAttr = &syscall.SysProcAttr{}
|
||||
cmd.SysProcAttr.Credential = &syscall.Credential{Uid: uint32(uid), Gid: uint32(gid)}
|
||||
if os.Getuid() == 0 {
|
||||
cmd.SysProcAttr = &syscall.SysProcAttr{}
|
||||
cmd.SysProcAttr.Credential = &syscall.Credential{Uid: uint32(uid), Gid: uint32(gid)}
|
||||
}
|
||||
err = cmd.Run()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("BPM archive could not be created: %s", err)
|
||||
@ -326,16 +317,8 @@ func CompileSourcePackage(archiveFilename, outputFilename string, skipChecks boo
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Set output filename if split package
|
||||
if len(bpmpkg.PkgInfo.SplitPackages) != 1 {
|
||||
// Get current working directory
|
||||
workdir, err := os.Getwd()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not get working directory: %s", err)
|
||||
}
|
||||
|
||||
outputFilename = path.Join(workdir, fmt.Sprintf("%s-%s-%d.bpm", pkgInfo.Name, pkgInfo.Version, pkgInfo.Revision))
|
||||
}
|
||||
// Set output filename
|
||||
outputFilename := path.Join(outputDirectory, fmt.Sprintf("%s-%s-%d-%s.bpm", pkgInfo.Name, pkgInfo.Version, pkgInfo.Revision, pkgInfo.Arch))
|
||||
|
||||
// Move final BPM archive
|
||||
err = os.Rename(path.Join(tempDirectory, "final-archive.bpm"), outputFilename)
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
"slices"
|
||||
)
|
||||
|
||||
@ -25,6 +26,7 @@ func InstallPackages(rootDir string, installationReason InstallationReason, rein
|
||||
Changes: make(map[string]string),
|
||||
RootDir: rootDir,
|
||||
ForceInstallationReason: installationReason,
|
||||
compiledPackages: make(map[string]string),
|
||||
}
|
||||
|
||||
// Resolve packages
|
||||
@ -35,12 +37,25 @@ func InstallPackages(rootDir string, installationReason InstallationReason, rein
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not read package: %s", err)
|
||||
}
|
||||
if reinstallMethod == ReinstallMethodNone && IsPackageInstalled(bpmpkg.PkgInfo.Name, rootDir) && GetPackageInfo(bpmpkg.PkgInfo.Name, rootDir).GetFullVersion() == bpmpkg.PkgInfo.GetFullVersion() {
|
||||
|
||||
if bpmpkg.PkgInfo.Type == "source" && bpmpkg.PkgInfo.IsSplitPackage() {
|
||||
for _, splitPkg := range bpmpkg.PkgInfo.SplitPackages {
|
||||
if reinstallMethod == ReinstallMethodNone && IsPackageInstalled(splitPkg.Name, rootDir) && GetPackageInfo(splitPkg.Name, rootDir).GetFullVersion() == splitPkg.GetFullVersion() {
|
||||
continue
|
||||
}
|
||||
|
||||
operation.AppendAction(&InstallPackageAction{
|
||||
File: pkg,
|
||||
IsDependency: false,
|
||||
BpmPackage: bpmpkg,
|
||||
SplitPackageToInstall: splitPkg.Name,
|
||||
})
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if bpmpkg.PkgInfo.Type == "source" && len(bpmpkg.PkgInfo.SplitPackages) != 0 {
|
||||
return nil, fmt.Errorf("direct source package installation has not been implemented")
|
||||
if reinstallMethod == ReinstallMethodNone && IsPackageInstalled(bpmpkg.PkgInfo.Name, rootDir) && GetPackageInfo(bpmpkg.PkgInfo.Name, rootDir).GetFullVersion() == bpmpkg.PkgInfo.GetFullVersion() {
|
||||
continue
|
||||
}
|
||||
|
||||
operation.AppendAction(&InstallPackageAction{
|
||||
@ -69,10 +84,6 @@ func InstallPackages(rootDir string, installationReason InstallationReason, rein
|
||||
continue
|
||||
}
|
||||
|
||||
if entry.Info.Type == "source" && len(entry.Info.SplitPackages) != 0 {
|
||||
return nil, fmt.Errorf("direct source package installation has not been implemented")
|
||||
}
|
||||
|
||||
operation.AppendAction(&FetchPackageAction{
|
||||
IsDependency: false,
|
||||
RepositoryEntry: entry,
|
||||
@ -128,6 +139,7 @@ func RemovePackages(rootDir string, removeUnusedPackagesOnly, cleanupDependencie
|
||||
UnresolvedDepends: make([]string, 0),
|
||||
Changes: make(map[string]string),
|
||||
RootDir: rootDir,
|
||||
compiledPackages: make(map[string]string),
|
||||
}
|
||||
|
||||
// Search for packages
|
||||
@ -164,6 +176,7 @@ func CleanupPackages(rootDir string, verbose bool) (operation *BPMOperation, err
|
||||
UnresolvedDepends: make([]string, 0),
|
||||
Changes: make(map[string]string),
|
||||
RootDir: rootDir,
|
||||
compiledPackages: make(map[string]string),
|
||||
}
|
||||
|
||||
// Do package cleanup
|
||||
@ -175,6 +188,88 @@ func CleanupPackages(rootDir string, verbose bool) (operation *BPMOperation, err
|
||||
return operation, nil
|
||||
}
|
||||
|
||||
func CleanupCache(rootDir string, cleanupCompilationFiles, cleanupCompiledPackages, cleanupFetchedPackages, verbose bool) error {
|
||||
if cleanupCompilationFiles {
|
||||
globalCompilationCacheDir := path.Join(rootDir, "var/cache/bpm/compilation")
|
||||
|
||||
// Ensure path exists and is a directory
|
||||
if stat, err := os.Stat(globalCompilationCacheDir); err == nil && stat.IsDir() {
|
||||
// Delete directory
|
||||
if verbose {
|
||||
log.Printf("Removing directory (%s)\n", globalCompilationCacheDir)
|
||||
}
|
||||
err = os.RemoveAll(globalCompilationCacheDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Get home directories of users in root directory
|
||||
homeDirs, err := os.ReadDir(path.Join(rootDir, "home"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Loop through all home directories
|
||||
for _, homeDir := range homeDirs {
|
||||
// Skip if not a directory
|
||||
if !homeDir.IsDir() {
|
||||
continue
|
||||
}
|
||||
|
||||
localCompilationDir := path.Join(rootDir, "home", homeDir.Name(), ".cache/bpm/compilation")
|
||||
|
||||
// Ensure path exists and is a directory
|
||||
if stat, err := os.Stat(localCompilationDir); err != nil || !stat.IsDir() {
|
||||
continue
|
||||
}
|
||||
|
||||
// Delete directory
|
||||
if verbose {
|
||||
log.Printf("Removing directory (%s)\n", localCompilationDir)
|
||||
}
|
||||
err = os.RemoveAll(localCompilationDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if cleanupCompiledPackages {
|
||||
dirToRemove := path.Join(rootDir, "var/cache/bpm/compiled")
|
||||
|
||||
// Ensure path exists and is a directory
|
||||
if stat, err := os.Stat(dirToRemove); err == nil && stat.IsDir() {
|
||||
// Delete directory
|
||||
if verbose {
|
||||
log.Printf("Removing directory (%s)\n", dirToRemove)
|
||||
}
|
||||
err = os.RemoveAll(dirToRemove)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if cleanupFetchedPackages {
|
||||
dirToRemove := path.Join(rootDir, "var/cache/bpm/fetched")
|
||||
|
||||
// Ensure path exists and is a directory
|
||||
if stat, err := os.Stat(dirToRemove); err == nil && stat.IsDir() {
|
||||
// Delete directory
|
||||
if verbose {
|
||||
log.Printf("Removing directory (%s)\n", dirToRemove)
|
||||
}
|
||||
err = os.RemoveAll(dirToRemove)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdatePackages fetches the newest versions of all installed packages from
|
||||
func UpdatePackages(rootDir string, syncDatabase bool, installOptionalDependencies, forceInstallation, verbose bool) (operation *BPMOperation, err error) {
|
||||
// Sync repositories
|
||||
@ -206,6 +301,7 @@ func UpdatePackages(rootDir string, syncDatabase bool, installOptionalDependenci
|
||||
Changes: make(map[string]string),
|
||||
RootDir: rootDir,
|
||||
ForceInstallationReason: InstallationReasonUnknown,
|
||||
compiledPackages: make(map[string]string),
|
||||
}
|
||||
|
||||
// Search for packages
|
||||
|
@ -16,6 +16,7 @@ type BPMOperation struct {
|
||||
Changes map[string]string
|
||||
RootDir string
|
||||
ForceInstallationReason InstallationReason
|
||||
compiledPackages map[string]string
|
||||
}
|
||||
|
||||
func (operation *BPMOperation) ActionsContainPackage(pkg string) bool {
|
||||
@ -337,6 +338,9 @@ func (operation *BPMOperation) ShowOperationSummary() {
|
||||
var pkgInfo *PackageInfo
|
||||
if value.GetActionType() == "install" {
|
||||
pkgInfo = value.(*InstallPackageAction).BpmPackage.PkgInfo
|
||||
if value.(*InstallPackageAction).SplitPackageToInstall != "" {
|
||||
pkgInfo = pkgInfo.GetSplitPackageInfo(value.(*InstallPackageAction).SplitPackageToInstall)
|
||||
}
|
||||
} else if value.GetActionType() == "fetch" {
|
||||
pkgInfo = value.(*FetchPackageAction).RepositoryEntry.Info
|
||||
} else {
|
||||
@ -409,30 +413,68 @@ func (operation *BPMOperation) RunHooks(verbose bool) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (operation *BPMOperation) Execute(verbose, force bool) error {
|
||||
func (operation *BPMOperation) Execute(verbose, force bool) (err error) {
|
||||
// Fetch packages from repositories
|
||||
if slices.ContainsFunc(operation.Actions, func(action OperationAction) bool {
|
||||
return action.GetActionType() == "fetch"
|
||||
}) {
|
||||
fmt.Println("Fetching packages from available repositories...")
|
||||
|
||||
// Create map for fetched packages
|
||||
fetchedPackages := make(map[string]string)
|
||||
|
||||
for i, action := range operation.Actions {
|
||||
if action.GetActionType() != "fetch" {
|
||||
continue
|
||||
}
|
||||
|
||||
// Get repository entry
|
||||
entry := action.(*FetchPackageAction).RepositoryEntry
|
||||
fetchedPackage, err := entry.Repository.FetchPackage(entry.Info.Name)
|
||||
if err != nil {
|
||||
return errors.New(fmt.Sprintf("could not fetch package (%s): %s\n", entry.Info.Name, err))
|
||||
|
||||
// Create bpmpkg variable
|
||||
var bpmpkg *BPMPackage
|
||||
|
||||
// Check if package has already been fetched from download link
|
||||
if _, ok := fetchedPackages[entry.Download]; !ok {
|
||||
// Fetch package from repository
|
||||
fetchedPackage, err := entry.Repository.FetchPackage(entry.Info.Name)
|
||||
if err != nil {
|
||||
return errors.New(fmt.Sprintf("could not fetch package (%s): %s\n", entry.Info.Name, err))
|
||||
}
|
||||
|
||||
// Read fetched package
|
||||
bpmpkg, err = ReadPackage(fetchedPackage)
|
||||
if err != nil {
|
||||
return errors.New(fmt.Sprintf("could not fetch package (%s): %s\n", entry.Info.Name, err))
|
||||
}
|
||||
|
||||
// Add fetched package to map
|
||||
fetchedPackages[entry.Download] = fetchedPackage
|
||||
|
||||
fmt.Printf("Package (%s) was successfully fetched!\n", entry.Info.Name)
|
||||
} else {
|
||||
// Read fetched package
|
||||
bpmpkg, err = ReadPackage(fetchedPackages[entry.Download])
|
||||
if err != nil {
|
||||
return errors.New(fmt.Sprintf("could not read package (%s): %s\n", entry.Info.Name, err))
|
||||
}
|
||||
|
||||
fmt.Printf("Package (%s) was successfully fetched!\n", entry.Info.Name)
|
||||
}
|
||||
bpmpkg, err := ReadPackage(fetchedPackage)
|
||||
if err != nil {
|
||||
return errors.New(fmt.Sprintf("could not fetch package (%s): %s\n", entry.Info.Name, err))
|
||||
}
|
||||
fmt.Printf("Package (%s) was successfully fetched!\n", bpmpkg.PkgInfo.Name)
|
||||
operation.Actions[i] = &InstallPackageAction{
|
||||
File: fetchedPackage,
|
||||
IsDependency: action.(*FetchPackageAction).IsDependency,
|
||||
BpmPackage: bpmpkg,
|
||||
|
||||
if bpmpkg.PkgInfo.IsSplitPackage() {
|
||||
operation.Actions[i] = &InstallPackageAction{
|
||||
File: fetchedPackages[entry.Download],
|
||||
IsDependency: action.(*FetchPackageAction).IsDependency,
|
||||
BpmPackage: bpmpkg,
|
||||
SplitPackageToInstall: entry.Info.Name,
|
||||
}
|
||||
} else {
|
||||
operation.Actions[i] = &InstallPackageAction{
|
||||
File: fetchedPackages[entry.Download],
|
||||
IsDependency: action.(*FetchPackageAction).IsDependency,
|
||||
BpmPackage: bpmpkg,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -473,9 +515,8 @@ func (operation *BPMOperation) Execute(verbose, force bool) error {
|
||||
|
||||
// Compile package if type is 'source'
|
||||
if bpmpkg.PkgInfo.Type == "source" {
|
||||
// Get path to compiled package directory and output filename
|
||||
compiledDir := path.Join(operation.RootDir, "/var/lib/bpm/compiled/")
|
||||
outputFilename := path.Join(compiledDir, fmt.Sprintf("%s-%s-%d.bpm", bpmpkg.PkgInfo.Name, bpmpkg.PkgInfo.Version, bpmpkg.PkgInfo.Revision))
|
||||
// Get path to compiled package directory
|
||||
compiledDir := path.Join(operation.RootDir, "/var/cache/bpm/compiled/")
|
||||
|
||||
// Create compiled package directory if not exists
|
||||
if _, err := os.Stat(compiledDir); err != nil {
|
||||
@ -485,15 +526,28 @@ func (operation *BPMOperation) Execute(verbose, force bool) error {
|
||||
}
|
||||
}
|
||||
|
||||
// Compile source package
|
||||
outputBpmPackages, err := CompileSourcePackage(value.File, outputFilename, false)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not compile source package (%s): %s\n", value.File, err)
|
||||
// Get package name to install
|
||||
pkgNameToInstall := bpmpkg.PkgInfo.Name
|
||||
if bpmpkg.PkgInfo.IsSplitPackage() {
|
||||
pkgNameToInstall = value.SplitPackageToInstall
|
||||
}
|
||||
|
||||
// Compile source package if not compiled already
|
||||
if _, ok := operation.compiledPackages[pkgNameToInstall]; !ok {
|
||||
outputBpmPackages, err := CompileSourcePackage(value.File, compiledDir, false)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not compile source package (%s): %s\n", value.File, err)
|
||||
}
|
||||
|
||||
// Add compiled packages to slice
|
||||
for pkgName, pkgFile := range outputBpmPackages {
|
||||
operation.compiledPackages[pkgName] = pkgFile
|
||||
}
|
||||
}
|
||||
|
||||
// Set values
|
||||
fileToInstall = outputBpmPackages[bpmpkg.PkgInfo.Name]
|
||||
bpmpkg, err = ReadPackage(outputFilename)
|
||||
fileToInstall = operation.compiledPackages[pkgNameToInstall]
|
||||
bpmpkg, err = ReadPackage(fileToInstall)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not read package (%s): %s\n", fileToInstall, err)
|
||||
}
|
||||
@ -531,9 +585,10 @@ type OperationAction interface {
|
||||
}
|
||||
|
||||
type InstallPackageAction struct {
|
||||
File string
|
||||
IsDependency bool
|
||||
BpmPackage *BPMPackage
|
||||
File string
|
||||
IsDependency bool
|
||||
SplitPackageToInstall string
|
||||
BpmPackage *BPMPackage
|
||||
}
|
||||
|
||||
func (action *InstallPackageAction) GetActionType() string {
|
||||
|
@ -70,6 +70,25 @@ func (pkgInfo *PackageInfo) GetFullVersion() string {
|
||||
return pkgInfo.Version + "-" + strconv.Itoa(pkgInfo.Revision)
|
||||
}
|
||||
|
||||
func (pkgInfo *PackageInfo) IsSplitPackage() bool {
|
||||
// Return false if not a source package
|
||||
if pkgInfo.Type != "source" {
|
||||
return false
|
||||
}
|
||||
|
||||
return len(pkgInfo.SplitPackages) > 0
|
||||
}
|
||||
|
||||
func (pkgInfo *PackageInfo) GetSplitPackageInfo(splitPkg string) *PackageInfo {
|
||||
for _, splitPkgInfo := range pkgInfo.SplitPackages {
|
||||
if splitPkgInfo.Name == splitPkg {
|
||||
return splitPkgInfo
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type InstallationReason string
|
||||
|
||||
const (
|
||||
@ -149,7 +168,6 @@ func ReadPackage(filename string) (*BPMPackage, error) {
|
||||
var pkgFiles []*PackageFileEntry
|
||||
|
||||
if _, err := os.Stat(filename); os.IsNotExist(err) {
|
||||
fmt.Println("a")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -388,7 +406,7 @@ func executePackageScripts(filename, rootDir string, operation packageOperation,
|
||||
}
|
||||
|
||||
func ReadPackageInfo(contents string) (*PackageInfo, error) {
|
||||
pkgInfo := PackageInfo{
|
||||
pkgInfo := &PackageInfo{
|
||||
Name: "",
|
||||
Description: "",
|
||||
Version: "",
|
||||
@ -410,6 +428,8 @@ func ReadPackageInfo(contents string) (*PackageInfo, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Ensure required fields are set properly
|
||||
if pkgInfo.Name == "" {
|
||||
return nil, errors.New("this package contains no name")
|
||||
} else if pkgInfo.Description == "" {
|
||||
@ -423,10 +443,46 @@ func ReadPackageInfo(contents string) (*PackageInfo, error) {
|
||||
} else if pkgInfo.Type == "" {
|
||||
return nil, errors.New("this package contains no type")
|
||||
}
|
||||
for i := 0; i < len(pkgInfo.Keep); i++ {
|
||||
pkgInfo.Keep[i] = strings.TrimPrefix(pkgInfo.Keep[i], "/")
|
||||
for _, val := range pkgInfo.Keep {
|
||||
if strings.HasPrefix(val, "/") {
|
||||
return nil, fmt.Errorf("cannot keep file (%s) after update because it starts with a slash", val)
|
||||
}
|
||||
}
|
||||
return &pkgInfo, nil
|
||||
|
||||
// Setup split package information
|
||||
for i, splitPkg := range pkgInfo.SplitPackages {
|
||||
// Ensure split package contains a name and one that is different from the main package name
|
||||
if splitPkg.Name == "" || splitPkg.Name == pkgInfo.Name {
|
||||
return nil, fmt.Errorf("invalid split package name: %s", splitPkg.Name)
|
||||
}
|
||||
|
||||
// Turn split package into json data
|
||||
splitPkgJson, err := yaml.Marshal(splitPkg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Clone all main package fields onto split package
|
||||
pkgInfoClone := *pkgInfo
|
||||
pkgInfo.SplitPackages[i] = &pkgInfoClone
|
||||
|
||||
// Set make depends and split package field of split package to nil
|
||||
pkgInfo.SplitPackages[i].MakeDepends = nil
|
||||
pkgInfo.SplitPackages[i].SplitPackages = nil
|
||||
|
||||
// Unmarshal json data back to struct
|
||||
err = yaml.Unmarshal(splitPkgJson, &pkgInfo.SplitPackages[i])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Force set split package version, revision and URL
|
||||
pkgInfo.SplitPackages[i].Version = pkgInfo.Version
|
||||
pkgInfo.SplitPackages[i].Revision = pkgInfo.Revision
|
||||
pkgInfo.SplitPackages[i].Url = pkgInfo.Url
|
||||
}
|
||||
|
||||
return pkgInfo, nil
|
||||
}
|
||||
|
||||
func CreateReadableInfo(showArchitecture, showType, showPackageRelations bool, pkgInfo *PackageInfo, rootDir string) string {
|
||||
|
@ -73,10 +73,56 @@ func (repo *Repository) ReadLocalDatabase() error {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, p := range entry.Info.Provides {
|
||||
repo.VirtualPackages[p] = append(repo.VirtualPackages[p], entry.Info.Name)
|
||||
// Create repository entries
|
||||
if entry.Info.IsSplitPackage() {
|
||||
for _, splitPkg := range entry.Info.SplitPackages {
|
||||
// Turn split package into json data
|
||||
splitPkgJson, err := yaml.Marshal(splitPkg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Clone all main package fields onto split package
|
||||
splitPkgClone := *entry.Info
|
||||
|
||||
// Set split package field of split package to nil
|
||||
splitPkgClone.SplitPackages = nil
|
||||
|
||||
// Unmarshal json data back to struct
|
||||
err = yaml.Unmarshal(splitPkgJson, &splitPkgClone)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Force set split package version, revision and URL
|
||||
splitPkgClone.Version = entry.Info.Version
|
||||
splitPkgClone.Revision = entry.Info.Revision
|
||||
splitPkgClone.Url = entry.Info.Url
|
||||
|
||||
// Create entry for split package
|
||||
repo.Entries[splitPkg.Name] = &RepositoryEntry{
|
||||
Info: &splitPkgClone,
|
||||
Download: entry.Download,
|
||||
DownloadSize: entry.DownloadSize,
|
||||
InstalledSize: 0,
|
||||
Repository: repo,
|
||||
}
|
||||
|
||||
// Add virtual packages to repository
|
||||
for _, p := range splitPkg.Provides {
|
||||
repo.VirtualPackages[p] = append(repo.VirtualPackages[p], splitPkg.Name)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Create entry for package
|
||||
repo.Entries[entry.Info.Name] = &entry
|
||||
|
||||
// Add virtual packages to repository
|
||||
for _, p := range entry.Info.Provides {
|
||||
repo.VirtualPackages[p] = append(repo.VirtualPackages[p], entry.Info.Name)
|
||||
}
|
||||
}
|
||||
repo.Entries[entry.Info.Name] = &entry
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -220,16 +266,16 @@ func (repo *Repository) FetchPackage(pkg string) (string, error) {
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
err = os.MkdirAll("/var/cache/bpm/packages/", 0755)
|
||||
err = os.MkdirAll("/var/cache/bpm/fetched/", 0755)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
out, err := os.Create("/var/cache/bpm/packages/" + path.Base(entry.Download))
|
||||
out, err := os.Create("/var/cache/bpm/fetched/" + path.Base(entry.Download))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer out.Close()
|
||||
|
||||
_, err = io.Copy(out, resp.Body)
|
||||
return "/var/cache/bpm/packages/" + path.Base(entry.Download), nil
|
||||
return "/var/cache/bpm/fetched/" + path.Base(entry.Download), nil
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user