7 Commits
4 changed files with 86 additions and 64 deletions
+54 -33
View File
@@ -93,7 +93,7 @@ func main() {
currentFlagSet.BoolP("force", "f", false, "Bypass warnings during package removal") currentFlagSet.BoolP("force", "f", false, "Bypass warnings during package removal")
currentFlagSet.BoolP("yes", "y", false, "Enter 'yes' in all prompts") currentFlagSet.BoolP("yes", "y", false, "Enter 'yes' in all prompts")
currentFlagSet.BoolP("unused", "u", false, "Remove packages only if they are not required as dependencies") currentFlagSet.BoolP("unused", "u", false, "Remove packages only if they are not required as dependencies")
currentFlagSet.BoolP("cleanup", "c", false, "Additionally remove all unused dependencies") currentFlagSet.BoolP("cleanup", "n", false, "Additionally remove all unused dependencies")
setupFlagsAndHelp(currentFlagSet, fmt.Sprintf("bpm %s <options>", subcommand), "Remove the specified packages", os.Args[2:]) setupFlagsAndHelp(currentFlagSet, fmt.Sprintf("bpm %s <options>", subcommand), "Remove the specified packages", os.Args[2:])
removePackages() removePackages()
@@ -103,6 +103,8 @@ func main() {
currentFlagSet.StringP("root", "R", "/", "Operate on specified root directory") currentFlagSet.StringP("root", "R", "/", "Operate on specified root directory")
currentFlagSet.BoolP("verbose", "v", false, "Show additional information about the current operation") currentFlagSet.BoolP("verbose", "v", false, "Show additional information about the current operation")
currentFlagSet.BoolP("force", "f", false, "Bypass warnings during package cleanup") currentFlagSet.BoolP("force", "f", false, "Bypass warnings during package cleanup")
currentFlagSet.BoolP("yes", "y", false, "Enter 'yes' in all prompts")
currentFlagSet.BoolP("all", "a", false, "Perform all types of cleanup")
currentFlagSet.BoolP("depends", "d", false, "Perform a dependency cleanup") currentFlagSet.BoolP("depends", "d", false, "Perform a dependency cleanup")
currentFlagSet.BoolP("make-depends", "m", false, "Perform a make dependency cleanup") currentFlagSet.BoolP("make-depends", "m", false, "Perform a make dependency cleanup")
currentFlagSet.BoolP("compilation-files", "c", false, "Perform a cleanup of compilation files") currentFlagSet.BoolP("compilation-files", "c", false, "Perform a cleanup of compilation files")
@@ -506,10 +508,6 @@ func removePackages() {
// Get packages // Get packages
packages := currentFlagSet.Args() packages := currentFlagSet.Args()
if len(packages) == 0 {
fmt.Println("No packages were given to remove")
return
}
// Check for required permissions // Check for required permissions
if os.Getuid() != 0 { if os.Getuid() != 0 {
@@ -592,6 +590,7 @@ func doCleanup() {
verbose, _ := currentFlagSet.GetBool("verbose") verbose, _ := currentFlagSet.GetBool("verbose")
force, _ := currentFlagSet.GetBool("force") force, _ := currentFlagSet.GetBool("force")
yesAll, _ := currentFlagSet.GetBool("yes") yesAll, _ := currentFlagSet.GetBool("yes")
all, _ := currentFlagSet.GetBool("all")
cleanupDepends, _ := currentFlagSet.GetBool("depends") cleanupDepends, _ := currentFlagSet.GetBool("depends")
cleanupMakeDepends, _ := currentFlagSet.GetBool("make-depends") cleanupMakeDepends, _ := currentFlagSet.GetBool("make-depends")
cleanupCompilationFiles, _ := currentFlagSet.GetBool("compilation-files") cleanupCompilationFiles, _ := currentFlagSet.GetBool("compilation-files")
@@ -599,7 +598,13 @@ func doCleanup() {
cleanupFetchedPackages, _ := currentFlagSet.GetBool("fetched-packages") cleanupFetchedPackages, _ := currentFlagSet.GetBool("fetched-packages")
// Set default behaviour // Set default behaviour
if !isFlagSet(currentFlagSet, "depends") && !isFlagSet(currentFlagSet, "make-depends") && !isFlagSet(currentFlagSet, "compilation-files") && !isFlagSet(currentFlagSet, "binary-packages") && !isFlagSet(currentFlagSet, "fetched-packages") { if all {
cleanupDepends = true
cleanupMakeDepends = bpmlib.MainBPMConfig.CleanupMakeDependencies
cleanupCompilationFiles = true
cleanupBinaryPackages = true
cleanupFetchedPackages = true
} else if !isFlagSet(currentFlagSet, "depends") && !isFlagSet(currentFlagSet, "make-depends") && !isFlagSet(currentFlagSet, "compilation-files") && !isFlagSet(currentFlagSet, "binary-packages") && !isFlagSet(currentFlagSet, "fetched-packages") {
cleanupDepends = true cleanupDepends = true
cleanupMakeDepends = bpmlib.MainBPMConfig.CleanupMakeDependencies cleanupMakeDepends = bpmlib.MainBPMConfig.CleanupMakeDependencies
cleanupCompilationFiles = false cleanupCompilationFiles = false
@@ -1044,9 +1049,39 @@ func compilePackage() {
} }
} }
// Setup cleanup function
cleanupFunc := func() {
if installSrcPkgDepends && len(unmetDepends) > 0 {
// Get path to current executable
executable, err := os.Executable()
if err != nil {
log.Printf("Warning: could not get path to executable: %s\n", err)
}
// Run 'bpm cleanup' using the set privilege escalator command
cmd := exec.Command(bpmlib.CompilationBPMConfig.PrivilegeEscalatorCmd, executable, "cleanup")
if yesAll {
cmd.Args = slices.Insert(cmd.Args, 3, "-y")
}
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Stdin = os.Stdin
if verbose {
fmt.Println("Running command: " + cmd.String())
}
err = cmd.Run()
if err != nil {
log.Printf("Warning: dependency cleanup command failed: %s\n", err)
}
}
}
// Get current working directory // Get current working directory
workdir, err := os.Getwd() workdir, err := os.Getwd()
if err != nil { if err != nil {
// Remove unused packages
cleanupFunc()
log.Printf("Error: could not get working directory: %s", err) log.Printf("Error: could not get working directory: %s", err)
exitCode = 1 exitCode = 1
return return
@@ -1055,6 +1090,9 @@ func compilePackage() {
// Get user home directory // Get user home directory
homedir, err := os.UserHomeDir() homedir, err := os.UserHomeDir()
if err != nil { if err != nil {
// Remove unused packages
cleanupFunc()
log.Printf("Error: could not get user home directory: %s", err) log.Printf("Error: could not get user home directory: %s", err)
exitCode = 1 exitCode = 1
return return
@@ -1087,11 +1125,17 @@ func compilePackage() {
// Ensure output directory exists and is a directory // Ensure output directory exists and is a directory
stat, err := os.Stat(outputDirectory) stat, err := os.Stat(outputDirectory)
if err != nil { if err != nil {
// Remove unused packages
cleanupFunc()
log.Printf("Error: could not stat output directory (%s): %s", outputDirectory, err) log.Printf("Error: could not stat output directory (%s): %s", outputDirectory, err)
exitCode = 1 exitCode = 1
return return
} }
if !stat.IsDir() { if !stat.IsDir() {
// Remove unused packages
cleanupFunc()
log.Printf("Error: output directory (%s) is not a directory", outputDirectory) log.Printf("Error: output directory (%s) is not a directory", outputDirectory)
exitCode = 1 exitCode = 1
return return
@@ -1099,6 +1143,9 @@ func compilePackage() {
outputBpmPackages, err := bpmlib.CompileSourcePackage(sourcePackage, outputDirectory, skipChecks) outputBpmPackages, err := bpmlib.CompileSourcePackage(sourcePackage, outputDirectory, skipChecks)
if err != nil { if err != nil {
// Remove unused packages
cleanupFunc()
log.Printf("Error: could not compile source package (%s): %s", sourcePackage, err) log.Printf("Error: could not compile source package (%s): %s", sourcePackage, err)
exitCode = 1 exitCode = 1
return return
@@ -1119,33 +1166,7 @@ func compilePackage() {
} }
// Remove unused packages // Remove unused packages
if installSrcPkgDepends && len(unmetDepends) > 0 { cleanupFunc()
// Get path to current executable
executable, err := os.Executable()
if err != nil {
log.Printf("Error: could not get path to executable: %s\n", err)
exitCode = 1
return
}
// Run 'bpm cleanup' using the set privilege escalator command
cmd := exec.Command(bpmlib.CompilationBPMConfig.PrivilegeEscalatorCmd, executable, "cleanup")
if yesAll {
cmd.Args = slices.Insert(cmd.Args, 3, "-y")
}
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Stdin = os.Stdin
if verbose {
fmt.Println("Running command: " + cmd.String())
}
err = cmd.Run()
if err != nil {
log.Printf("Error: dependency cleanup command failed: %s\n", err)
exitCode = 1
return
}
}
} }
} }
+24 -23
View File
@@ -132,7 +132,6 @@ func CompileSourcePackage(archiveFilename, outputDirectory string, skipChecks bo
env = append(env, "HOME="+tempDirectory) env = append(env, "HOME="+tempDirectory)
env = append(env, "BPM_WORKDIR="+tempDirectory) env = append(env, "BPM_WORKDIR="+tempDirectory)
env = append(env, "BPM_SOURCE="+path.Join(tempDirectory, "source")) env = append(env, "BPM_SOURCE="+path.Join(tempDirectory, "source"))
env = append(env, "BPM_OUTPUT="+path.Join(tempDirectory, "output"))
env = append(env, "BPM_PKG_NAME="+bpmpkg.PkgInfo.Name) env = append(env, "BPM_PKG_NAME="+bpmpkg.PkgInfo.Name)
env = append(env, "BPM_PKG_VERSION="+bpmpkg.PkgInfo.Version) env = append(env, "BPM_PKG_VERSION="+bpmpkg.PkgInfo.Version)
env = append(env, "BPM_PKG_REVISION="+strconv.Itoa(bpmpkg.PkgInfo.Revision)) env = append(env, "BPM_PKG_REVISION="+strconv.Itoa(bpmpkg.PkgInfo.Revision))
@@ -188,6 +187,21 @@ func CompileSourcePackage(archiveFilename, outputDirectory string, skipChecks bo
packagesToCompile = append(packagesToCompile, bpmpkg.PkgInfo) packagesToCompile = append(packagesToCompile, bpmpkg.PkgInfo)
} }
// Create output directories for each package
for _, pkg := range packagesToCompile {
// Create new output directory
err = os.Mkdir(path.Join(tempDirectory, "output_"+pkg.Name), 0755)
if err != nil {
return nil, err
}
// Change output directory owner
err = os.Chown(path.Join(tempDirectory, "output_"+pkg.Name), uid, gid)
if err != nil {
return nil, err
}
}
// Compile each package // Compile each package
for _, pkg := range packagesToCompile { for _, pkg := range packagesToCompile {
// Get package function name // Get package function name
@@ -196,26 +210,6 @@ func CompileSourcePackage(archiveFilename, outputDirectory string, skipChecks bo
packageFunctionName = "package_" + pkg.Name packageFunctionName = "package_" + pkg.Name
} }
// Remove output directory if it already exists
if _, err := os.Stat(path.Join(tempDirectory, "output")); err == nil {
err := os.RemoveAll(path.Join(tempDirectory, "output"))
if err != nil {
return nil, err
}
}
// Create new output directory
err = os.Mkdir(path.Join(tempDirectory, "output"), 0755)
if err != nil {
return nil, err
}
// Change output directory owner
err = os.Chown(path.Join(tempDirectory, "output"), uid, gid)
if err != nil {
return nil, err
}
// Execute package function in source.sh script and generate package file list // Execute package function in source.sh script and generate package file list
cmd = exec.Command("bash", "-c", cmd = exec.Command("bash", "-c",
"set -a\n"+ // Source and export functions and variables in source.sh script "set -a\n"+ // Source and export functions and variables in source.sh script
@@ -224,10 +218,11 @@ func CompileSourcePackage(archiveFilename, outputDirectory string, skipChecks bo
"echo \"Running "+packageFunctionName+"() function\"\n"+ "echo \"Running "+packageFunctionName+"() function\"\n"+
"( cd \"$BPM_SOURCE\" && fakeroot -s \"$BPM_WORKDIR\"/fakeroot_file bash -e -c '"+packageFunctionName+"' ) || exit 1\n"+ // Run package() function "( cd \"$BPM_SOURCE\" && fakeroot -s \"$BPM_WORKDIR\"/fakeroot_file bash -e -c '"+packageFunctionName+"' ) || exit 1\n"+ // Run package() function
"fakeroot -i \"$BPM_WORKDIR\"/fakeroot_file find \"$BPM_OUTPUT\" -mindepth 1 -printf \"%P %#m %U %G %s\\n\" > \"$BPM_WORKDIR\"/pkg.files") // Create package file list "fakeroot -i \"$BPM_WORKDIR\"/fakeroot_file find \"$BPM_OUTPUT\" -mindepth 1 -printf \"%P %#m %U %G %s\\n\" > \"$BPM_WORKDIR\"/pkg.files") // Create package file list
cmd.Dir = tempDirectory cmd.Dir = tempDirectory
cmd.Stdout = os.Stdout cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr cmd.Stderr = os.Stderr
cmd.Env = env cmd.Env = append(env, "BPM_OUTPUT="+path.Join(tempDirectory, "output_"+pkg.Name))
if os.Getuid() == 0 { if os.Getuid() == 0 {
cmd.SysProcAttr = &syscall.SysProcAttr{} cmd.SysProcAttr = &syscall.SysProcAttr{}
cmd.SysProcAttr.Credential = &syscall.Credential{Uid: uint32(uid), Gid: uint32(gid)} cmd.SysProcAttr.Credential = &syscall.Credential{Uid: uint32(uid), Gid: uint32(gid)}
@@ -238,7 +233,7 @@ func CompileSourcePackage(archiveFilename, outputDirectory string, skipChecks bo
} }
// Create gzip-compressed archive for the package files // Create gzip-compressed archive for the package files
cmd = exec.Command("bash", "-c", "find output -printf \"%P\\n\" | fakeroot -i \"$BPM_WORKDIR\"/fakeroot_file tar -czf files.tar.gz --no-recursion -C output -T -") cmd = exec.Command("bash", "-c", fmt.Sprintf("find %s -printf \"%%P\\n\" | fakeroot -i %s/fakeroot_file tar -czf files.tar.gz --no-recursion -C %s -T -", "output_"+pkg.Name, tempDirectory, "output_"+pkg.Name))
cmd.Dir = tempDirectory cmd.Dir = tempDirectory
cmd.Stdout = os.Stdout cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr cmd.Stderr = os.Stderr
@@ -330,6 +325,12 @@ func CompileSourcePackage(archiveFilename, outputDirectory string, skipChecks bo
return nil, err return nil, err
} }
// Remove output directory
err = os.RemoveAll(path.Join(tempDirectory, "output_"+pkg.Name))
if err != nil {
return nil, err
}
outputBpmPackages[pkgInfo.Name] = outputFilename outputBpmPackages[pkgInfo.Name] = outputFilename
} }
+7 -7
View File
@@ -31,7 +31,7 @@ func (pkgInfo *PackageInfo) GetDependencies(includeMakeDepends, includeOptionalD
}) { }) {
allDepends = append(allDepends, pkgInstallationReason{ allDepends = append(allDepends, pkgInstallationReason{
PkgName: depend, PkgName: depend,
InstallationReason: InstallationReasonDependency, InstallationReason: InstallationReasonManual,
}) })
} }
} }
@@ -51,23 +51,23 @@ func (pkgInfo *PackageInfo) GetDependencies(includeMakeDepends, includeOptionalD
return allDepends return allDepends
} }
func (pkgInfo *PackageInfo) GetAllDependencies(includeMakeDepends, includeOptionalDepends bool, rootDir string) (resolved []string) { func (pkgInfo *PackageInfo) GetDependenciesRecursive(includeMakeDepends bool, rootDir string) (resolved []string) {
// Initialize slices // Initialize slices
resolved = make([]string, 0) resolved = make([]string, 0)
unresolved := make([]string, 0) unresolved := make([]string, 0)
// Call unexported function // Call unexported function
pkgInfo.getAllDependencies(&resolved, &unresolved, includeMakeDepends, includeOptionalDepends, rootDir) pkgInfo.getDependenciesRecursive(&resolved, &unresolved, includeMakeDepends, rootDir)
return resolved return resolved
} }
func (pkgInfo *PackageInfo) getAllDependencies(resolved *[]string, unresolved *[]string, includeMakeDepends, includeOptionalDepends bool, rootDir string) { func (pkgInfo *PackageInfo) getDependenciesRecursive(resolved *[]string, unresolved *[]string, includeMakeDepends bool, rootDir string) {
// Add current package name to unresolved slice // Add current package name to unresolved slice
*unresolved = append(*unresolved, pkgInfo.Name) *unresolved = append(*unresolved, pkgInfo.Name)
// Loop through all dependencies // Loop through all dependencies
for _, pkgIR := range pkgInfo.GetDependencies(includeMakeDepends, includeOptionalDepends) { for _, pkgIR := range pkgInfo.GetDependencies(includeMakeDepends, false) {
depend := pkgIR.PkgName depend := pkgIR.PkgName
if isVirtual, p := IsVirtualPackage(depend, rootDir); isVirtual { if isVirtual, p := IsVirtualPackage(depend, rootDir); isVirtual {
@@ -86,7 +86,7 @@ func (pkgInfo *PackageInfo) getAllDependencies(resolved *[]string, unresolved *[
dependInfo := GetPackageInfo(depend, rootDir) dependInfo := GetPackageInfo(depend, rootDir)
if dependInfo != nil { if dependInfo != nil {
dependInfo.getAllDependencies(resolved, unresolved, includeMakeDepends, includeOptionalDepends, rootDir) dependInfo.getDependenciesRecursive(resolved, unresolved, includeMakeDepends, rootDir)
} }
} }
} }
@@ -155,7 +155,7 @@ func resolvePackageDependenciesFromDatabase(resolved *[]pkgInstallationReason, u
} }
// Resolve the dependencies of this dependency // Resolve the dependencies of this dependency
resolvePackageDependenciesFromDatabase(resolved, unresolved, entry.Info, checkMake, checkOptional, ignoreInstalled, verbose, rootDir) resolvePackageDependenciesFromDatabase(resolved, unresolved, entry.Info, checkMake, false, ignoreInstalled, verbose, rootDir)
// Move dependency from the unresolved slice to the resolved slice // Move dependency from the unresolved slice to the resolved slice
if !slices.ContainsFunc(*resolved, func(p pkgInstallationReason) bool { if !slices.ContainsFunc(*resolved, func(p pkgInstallationReason) bool {
+1 -1
View File
@@ -230,7 +230,7 @@ func (operation *BPMOperation) Cleanup(cleanupMakeDepends bool) error {
} }
keepPackages = append(keepPackages, pkg.Name) keepPackages = append(keepPackages, pkg.Name)
resolved := pkg.GetAllDependencies(!cleanupMakeDepends, true, operation.RootDir) resolved := pkg.GetDependenciesRecursive(!cleanupMakeDepends, operation.RootDir)
for _, value := range resolved { for _, value := range resolved {
if !slices.Contains(keepPackages, value) { if !slices.Contains(keepPackages, value) {
keepPackages = append(keepPackages, value) keepPackages = append(keepPackages, value)