Redo dependency resolution and cache installed package information
This commit is contained in:
parent
f2bc7c8968
commit
5f03a6a1ad
@ -547,7 +547,7 @@ func resolveCommand() {
|
||||
|
||||
var pkgList []string
|
||||
for _, pkg := range pkgs {
|
||||
if slices.ContainsFunc(bpmlib.GetPackageFiles(pkg, rootDir), func(entry *bpmlib.PackageFileEntry) bool {
|
||||
if slices.ContainsFunc(bpmlib.GetPackage(pkg, rootDir).PkgFiles, func(entry *bpmlib.PackageFileEntry) bool {
|
||||
return entry.Path == absFile
|
||||
}) {
|
||||
pkgList = append(pkgList, pkg)
|
||||
@ -593,7 +593,7 @@ func resolveCommand() {
|
||||
|
||||
// Get direct runtime and make dependencies
|
||||
totalDepends := make([]string, 0)
|
||||
for _, depend := range bpmpkg.PkgInfo.GetAllDependencies(true, false) {
|
||||
for _, depend := range bpmpkg.PkgInfo.GetDependencies(true, false) {
|
||||
if !slices.Contains(totalDepends, depend) {
|
||||
totalDepends = append(totalDepends, depend)
|
||||
}
|
||||
|
164
src/bpmlib/dependencies.go
Normal file
164
src/bpmlib/dependencies.go
Normal file
@ -0,0 +1,164 @@
|
||||
package bpmlib
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"slices"
|
||||
)
|
||||
|
||||
func (pkgInfo *PackageInfo) GetDependencies(includeMakeDepends, includeOptionalDepends bool) []string {
|
||||
allDepends := make([]string, 0)
|
||||
allDepends = append(allDepends, pkgInfo.Depends...)
|
||||
if includeMakeDepends {
|
||||
allDepends = append(allDepends, pkgInfo.MakeDepends...)
|
||||
}
|
||||
if includeOptionalDepends {
|
||||
allDepends = append(allDepends, pkgInfo.OptionalDepends...)
|
||||
}
|
||||
return allDepends
|
||||
}
|
||||
|
||||
func (pkgInfo *PackageInfo) GetAllDependencies(includeMakeDepends, includeOptionalDepends bool, rootDir string) (resolved []string) {
|
||||
// Initialize slices
|
||||
resolved = make([]string, 0)
|
||||
unresolved := make([]string, 0)
|
||||
|
||||
// Call unexported function
|
||||
pkgInfo.getAllDependencies(&resolved, &unresolved, includeMakeDepends, includeOptionalDepends, rootDir)
|
||||
|
||||
return resolved
|
||||
}
|
||||
|
||||
func (pkgInfo *PackageInfo) getAllDependencies(resolved *[]string, unresolved *[]string, includeMakeDepends, includeOptionalDepends bool, rootDir string) {
|
||||
// Add current package name to unresolved slice
|
||||
*unresolved = append(*unresolved, pkgInfo.Name)
|
||||
|
||||
// Loop through all dependencies
|
||||
for _, depend := range pkgInfo.GetDependencies(includeMakeDepends, includeOptionalDepends) {
|
||||
if !slices.Contains(*resolved, depend) {
|
||||
// Add current dependency to resolved slice when circular dependency is detected
|
||||
if slices.Contains(*unresolved, depend) {
|
||||
if !slices.Contains(*resolved, depend) {
|
||||
*resolved = append(*resolved, depend)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
var dependInfo *PackageInfo
|
||||
|
||||
if isVirtual, p := IsVirtualPackage(depend, rootDir); isVirtual {
|
||||
dependInfo = GetPackageInfo(p, rootDir)
|
||||
} else {
|
||||
dependInfo = GetPackageInfo(depend, rootDir)
|
||||
}
|
||||
|
||||
if dependInfo != nil {
|
||||
dependInfo.getAllDependencies(resolved, unresolved, includeMakeDepends, includeOptionalDepends, rootDir)
|
||||
}
|
||||
}
|
||||
}
|
||||
if !slices.Contains(*resolved, pkgInfo.Name) {
|
||||
*resolved = append(*resolved, pkgInfo.Name)
|
||||
}
|
||||
*unresolved = stringSliceRemove(*unresolved, pkgInfo.Name)
|
||||
}
|
||||
|
||||
func ResolvePackageDependenciesFromDatabases(pkgInfo *PackageInfo, checkMake, checkOptional, ignoreInstalled, verbose bool, rootDir string) (resolved []string, unresolved []string) {
|
||||
// Initialize slices
|
||||
resolved = make([]string, 0)
|
||||
unresolved = make([]string, 0)
|
||||
|
||||
// Call unexported function
|
||||
resolvePackageDependenciesFromDatabase(&resolved, &unresolved, pkgInfo, checkMake, checkOptional, ignoreInstalled, verbose, rootDir)
|
||||
|
||||
return resolved, unresolved
|
||||
}
|
||||
|
||||
func resolvePackageDependenciesFromDatabase(resolved, unresolved *[]string, pkgInfo *PackageInfo, checkMake, checkOptional, ignoreInstalled, verbose bool, rootDir string) {
|
||||
// Add current package name to unresolved slice
|
||||
*unresolved = append(*unresolved, pkgInfo.Name)
|
||||
|
||||
// Loop through all dependencies
|
||||
for _, depend := range pkgInfo.GetDependencies(checkMake, checkOptional) {
|
||||
if !slices.Contains(*resolved, depend) {
|
||||
// Add current dependency to resolved slice when circular dependency is detected
|
||||
if slices.Contains(*unresolved, depend) {
|
||||
if verbose {
|
||||
fmt.Printf("Circular dependency was detected (%s -> %s). Installing %s first\n", pkgInfo.Name, depend, depend)
|
||||
}
|
||||
if !slices.Contains(*resolved, depend) {
|
||||
*resolved = append(*resolved, depend)
|
||||
}
|
||||
continue
|
||||
} else if ignoreInstalled && IsPackageProvided(depend, rootDir) {
|
||||
continue
|
||||
}
|
||||
var err error
|
||||
var entry *RepositoryEntry
|
||||
entry, _, err = GetRepositoryEntry(depend)
|
||||
if err != nil {
|
||||
if entry = ResolveVirtualPackage(depend); entry == nil {
|
||||
if !slices.Contains(*unresolved, depend) {
|
||||
*unresolved = append(*unresolved, depend)
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
resolvePackageDependenciesFromDatabase(resolved, unresolved, entry.Info, checkMake, checkOptional, ignoreInstalled, verbose, rootDir)
|
||||
}
|
||||
}
|
||||
if !slices.Contains(*resolved, pkgInfo.Name) {
|
||||
*resolved = append(*resolved, pkgInfo.Name)
|
||||
}
|
||||
*unresolved = stringSliceRemove(*unresolved, pkgInfo.Name)
|
||||
}
|
||||
|
||||
func GetPackageDependants(pkgName string, rootDir string) ([]string, error) {
|
||||
ret := make([]string, 0)
|
||||
|
||||
// Get BPM package
|
||||
pkg := GetPackage(pkgName, rootDir)
|
||||
if pkg == nil {
|
||||
return nil, errors.New("package not found: " + pkgName)
|
||||
}
|
||||
|
||||
// Get installed package names
|
||||
pkgs, err := GetInstalledPackages(rootDir)
|
||||
if err != nil {
|
||||
return nil, errors.New("could not get installed packages")
|
||||
}
|
||||
|
||||
// Loop through all installed packages
|
||||
for _, installedPkgName := range pkgs {
|
||||
// Get installed BPM package
|
||||
installedPkg := GetPackage(installedPkgName, rootDir)
|
||||
if installedPkg == nil {
|
||||
return nil, errors.New("package not found: " + installedPkgName)
|
||||
}
|
||||
|
||||
// Skip iteration if comparing the same packages
|
||||
if installedPkg.PkgInfo.Name == pkgName {
|
||||
continue
|
||||
}
|
||||
|
||||
// Get installed package dependencies
|
||||
dependencies := installedPkg.PkgInfo.GetDependencies(false, true)
|
||||
|
||||
// Add installed package to list if its dependencies include pkgName
|
||||
if slices.Contains(dependencies, pkgName) {
|
||||
ret = append(ret, installedPkgName)
|
||||
continue
|
||||
}
|
||||
|
||||
// Loop through each virtual package
|
||||
for _, vpkg := range pkg.PkgInfo.Provides {
|
||||
// Add installed package to list if its dependencies contain a provided virtual package
|
||||
if slices.Contains(dependencies, vpkg) {
|
||||
ret = append(ret, installedPkgName)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
@ -161,7 +161,7 @@ func RemovePackages(rootDir string, removeUnusedPackagesOnly, cleanupDependencie
|
||||
|
||||
// Do package cleanup
|
||||
if cleanupDependencies {
|
||||
err := operation.Cleanup(verbose)
|
||||
err := operation.Cleanup()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not perform cleanup for operation: %s", err)
|
||||
}
|
||||
@ -180,7 +180,7 @@ func CleanupPackages(rootDir string, verbose bool) (operation *BPMOperation, err
|
||||
}
|
||||
|
||||
// Do package cleanup
|
||||
err = operation.Cleanup(verbose)
|
||||
err = operation.Cleanup()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not perform cleanup for operation: %s", err)
|
||||
}
|
||||
|
@ -99,7 +99,7 @@ func (hook *BPMHook) Execute(packageChanges map[string]string, verbose bool, roo
|
||||
// Get modified files slice
|
||||
modifiedFiles := make([]*PackageFileEntry, 0)
|
||||
for pkg := range packageChanges {
|
||||
modifiedFiles = append(modifiedFiles, GetPackageFiles(pkg, rootDir)...)
|
||||
modifiedFiles = append(modifiedFiles, GetPackage(pkg, rootDir).PkgFiles...)
|
||||
}
|
||||
|
||||
// Check if any targets are met
|
||||
|
243
src/bpmlib/installed_packages.go
Normal file
243
src/bpmlib/installed_packages.go
Normal file
@ -0,0 +1,243 @@
|
||||
package bpmlib
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var localPackageInformation map[string]map[string]*BPMPackage = make(map[string]map[string]*BPMPackage)
|
||||
|
||||
func initializeLocalPackageInformation(rootDir string) (err error) {
|
||||
// Return if information is already initialized
|
||||
if _, ok := localPackageInformation[rootDir]; ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
tempPackageInformation := make(map[string]*BPMPackage)
|
||||
|
||||
// Get path to installed package information directory
|
||||
installedDir := path.Join(rootDir, "var/lib/bpm/installed/")
|
||||
|
||||
// Get directory content
|
||||
items, err := os.ReadDir(installedDir)
|
||||
if os.IsNotExist(err) {
|
||||
localPackageInformation[rootDir] = make(map[string]*BPMPackage)
|
||||
return nil
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Loop through each subdirectory
|
||||
for _, item := range items {
|
||||
// Skip if not a directory
|
||||
if !item.IsDir() {
|
||||
continue
|
||||
}
|
||||
|
||||
// Read package info
|
||||
infoData, err := os.ReadFile(path.Join(installedDir, item.Name(), "info"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
info, err := ReadPackageInfo(string(infoData))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Read package files
|
||||
files := getPackageFiles(info.Name, rootDir)
|
||||
|
||||
// Add package to slice
|
||||
tempPackageInformation[info.Name] = &BPMPackage{
|
||||
PkgInfo: info,
|
||||
PkgFiles: files,
|
||||
}
|
||||
}
|
||||
|
||||
localPackageInformation[rootDir] = tempPackageInformation
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetInstalledPackages(rootDir string) (ret []string, err error) {
|
||||
// Initialize local package information
|
||||
err = initializeLocalPackageInformation(rootDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Loop through each package and add it to slice
|
||||
for _, bpmpkg := range localPackageInformation[rootDir] {
|
||||
ret = append(ret, bpmpkg.PkgInfo.Name)
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func IsPackageInstalled(pkg, rootDir string) bool {
|
||||
// Initialize local package information
|
||||
err := initializeLocalPackageInformation(rootDir)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if _, ok := localPackageInformation[rootDir][pkg]; !ok {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func GetPackageInfo(pkg string, rootDir string) *PackageInfo {
|
||||
// Get BPM package
|
||||
bpmpkg := GetPackage(pkg, rootDir)
|
||||
|
||||
// Return nil if not found
|
||||
if bpmpkg == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return bpmpkg.PkgInfo
|
||||
}
|
||||
|
||||
func IsVirtualPackage(pkg, rootDir string) (bool, string) {
|
||||
pkgs, err := GetInstalledPackages(rootDir)
|
||||
if err != nil {
|
||||
return false, ""
|
||||
}
|
||||
for _, p := range pkgs {
|
||||
if p == pkg {
|
||||
return false, ""
|
||||
}
|
||||
i := GetPackageInfo(p, rootDir)
|
||||
if i == nil {
|
||||
continue
|
||||
}
|
||||
if slices.Contains(i.Provides, pkg) {
|
||||
return true, p
|
||||
}
|
||||
}
|
||||
return false, ""
|
||||
}
|
||||
|
||||
func IsPackageProvided(pkg, rootDir string) bool {
|
||||
pkgs, err := GetInstalledPackages(rootDir)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
for _, p := range pkgs {
|
||||
if p == pkg {
|
||||
return true
|
||||
}
|
||||
i := GetPackageInfo(p, rootDir)
|
||||
if i == nil {
|
||||
continue
|
||||
}
|
||||
if slices.Contains(i.Provides, pkg) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func GetPackage(pkg, rootDir string) *BPMPackage {
|
||||
err := initializeLocalPackageInformation(rootDir)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
bpmpkg := localPackageInformation[rootDir][pkg]
|
||||
|
||||
return bpmpkg
|
||||
}
|
||||
|
||||
func GetAllPackageFiles(rootDir string, excludePackages ...string) (map[string][]*BPMPackage, error) {
|
||||
ret := make(map[string][]*BPMPackage)
|
||||
|
||||
pkgNames, err := GetInstalledPackages(rootDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, pkgName := range pkgNames {
|
||||
if slices.Contains(excludePackages, pkgName) {
|
||||
continue
|
||||
}
|
||||
bpmpkg := GetPackage(pkgName, rootDir)
|
||||
if bpmpkg == nil {
|
||||
return nil, errors.New(fmt.Sprintf("could not get BPM package (%s)", pkgName))
|
||||
}
|
||||
for _, entry := range bpmpkg.PkgFiles {
|
||||
if _, ok := ret[entry.Path]; ok {
|
||||
ret[entry.Path] = append(ret[entry.Path], bpmpkg)
|
||||
} else {
|
||||
ret[entry.Path] = []*BPMPackage{bpmpkg}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func getPackageFiles(pkg, rootDir string) []*PackageFileEntry {
|
||||
var pkgFiles []*PackageFileEntry
|
||||
installedDir := path.Join(rootDir, "var/lib/bpm/installed/")
|
||||
pkgDir := path.Join(installedDir, pkg)
|
||||
files := path.Join(pkgDir, "files")
|
||||
if _, err := os.Stat(installedDir); os.IsNotExist(err) {
|
||||
return nil
|
||||
}
|
||||
if _, err := os.Stat(pkgDir); os.IsNotExist(err) {
|
||||
return nil
|
||||
}
|
||||
bs, err := os.ReadFile(files)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, line := range strings.Split(string(bs), "\n") {
|
||||
if strings.TrimSpace(line) == "" {
|
||||
continue
|
||||
}
|
||||
stringEntry := strings.Split(strings.TrimSpace(line), " ")
|
||||
if len(stringEntry) < 5 {
|
||||
pkgFiles = append(pkgFiles, &PackageFileEntry{
|
||||
Path: strings.TrimSuffix(line, "/"),
|
||||
OctalPerms: 0,
|
||||
UserID: 0,
|
||||
GroupID: 0,
|
||||
SizeInBytes: 0,
|
||||
})
|
||||
continue
|
||||
}
|
||||
uid, err := strconv.ParseInt(stringEntry[len(stringEntry)-4], 0, 32)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
octalPerms, err := strconv.ParseInt(stringEntry[len(stringEntry)-3], 0, 32)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
gid, err := strconv.ParseInt(stringEntry[len(stringEntry)-2], 0, 32)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
size, err := strconv.ParseUint(stringEntry[len(stringEntry)-1], 0, 64)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
pkgFiles = append(pkgFiles, &PackageFileEntry{
|
||||
Path: strings.TrimSuffix(strings.Join(stringEntry[:len(stringEntry)-4], " "), "/"),
|
||||
OctalPerms: uint32(octalPerms),
|
||||
UserID: int(uid),
|
||||
GroupID: int(gid),
|
||||
SizeInBytes: size,
|
||||
})
|
||||
}
|
||||
|
||||
return pkgFiles
|
||||
}
|
@ -139,7 +139,7 @@ func (operation *BPMOperation) ResolveDependencies(reinstallDependencies, instal
|
||||
continue
|
||||
}
|
||||
|
||||
resolved, unresolved := pkgInfo.ResolveDependencies(&[]string{}, &[]string{}, pkgInfo.Type == "source", installOptionalDependencies, !reinstallDependencies, verbose, operation.RootDir)
|
||||
resolved, unresolved := ResolvePackageDependenciesFromDatabases(pkgInfo, pkgInfo.Type == "source", installOptionalDependencies, !reinstallDependencies, verbose, operation.RootDir)
|
||||
|
||||
operation.UnresolvedDepends = append(operation.UnresolvedDepends, unresolved...)
|
||||
|
||||
@ -174,7 +174,7 @@ func (operation *BPMOperation) RemoveNeededPackages() error {
|
||||
}
|
||||
|
||||
for pkg, action := range removeActions {
|
||||
dependants, err := action.BpmPackage.PkgInfo.GetDependants(operation.RootDir)
|
||||
dependants, err := GetPackageDependants(action.BpmPackage.PkgInfo.Name, operation.RootDir)
|
||||
if err != nil {
|
||||
return errors.New("could not get dependant packages for package (" + pkg + ")")
|
||||
}
|
||||
@ -192,7 +192,7 @@ func (operation *BPMOperation) RemoveNeededPackages() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (operation *BPMOperation) Cleanup(verbose bool) error {
|
||||
func (operation *BPMOperation) Cleanup() error {
|
||||
// Get all installed packages
|
||||
installedPackageNames, err := GetInstalledPackages(operation.RootDir)
|
||||
if err != nil {
|
||||
@ -228,9 +228,9 @@ func (operation *BPMOperation) Cleanup(verbose bool) error {
|
||||
}
|
||||
|
||||
keepPackages = append(keepPackages, pkg.Name)
|
||||
resolved, _ := pkg.ResolveDependencies(&[]string{}, &[]string{}, false, true, false, verbose, operation.RootDir)
|
||||
resolved := pkg.GetAllDependencies(false, true, operation.RootDir)
|
||||
for _, value := range resolved {
|
||||
if !slices.Contains(keepPackages, value) && slices.Contains(installedPackageNames, value) {
|
||||
if !slices.Contains(keepPackages, value) {
|
||||
keepPackages = append(keepPackages, value)
|
||||
}
|
||||
}
|
||||
|
@ -509,7 +509,7 @@ func CreateReadableInfo(showArchitecture, showType, showPackageRelations bool, p
|
||||
appendArray("Make Dependencies", pkgInfo.MakeDepends)
|
||||
}
|
||||
appendArray("Optional dependencies", pkgInfo.OptionalDepends)
|
||||
dependants, err := pkgInfo.GetDependants(rootDir)
|
||||
dependants, err := GetPackageDependants(pkgInfo.Name, rootDir)
|
||||
if err == nil {
|
||||
appendArray("Dependant packages", dependants)
|
||||
}
|
||||
@ -681,7 +681,7 @@ func installPackage(filename, rootDir string, verbose, force bool) error {
|
||||
// Check if package is installed and remove current files
|
||||
if packageInstalled {
|
||||
// Fetching and reversing package file entry list
|
||||
fileEntries := GetPackageFiles(bpmpkg.PkgInfo.Name, rootDir)
|
||||
fileEntries := GetPackage(bpmpkg.PkgInfo.Name, rootDir).PkgFiles
|
||||
sort.Slice(fileEntries, func(i, j int) bool {
|
||||
return fileEntries[i].Path < fileEntries[j].Path
|
||||
})
|
||||
@ -873,312 +873,6 @@ func installPackage(filename, rootDir string, verbose, force bool) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (pkgInfo *PackageInfo) GetAllDependencies(checkMake, checkOptional bool) []string {
|
||||
allDepends := make([]string, 0)
|
||||
allDepends = append(allDepends, pkgInfo.Depends...)
|
||||
if checkMake {
|
||||
allDepends = append(allDepends, pkgInfo.MakeDepends...)
|
||||
}
|
||||
if checkOptional {
|
||||
allDepends = append(allDepends, pkgInfo.OptionalDepends...)
|
||||
}
|
||||
return allDepends
|
||||
}
|
||||
|
||||
func (pkgInfo *PackageInfo) CheckDependencies(checkMake, checkOptional bool, rootDir string) []string {
|
||||
var ret []string
|
||||
for _, dependency := range pkgInfo.Depends {
|
||||
if !IsPackageProvided(dependency, rootDir) {
|
||||
ret = append(ret, dependency)
|
||||
}
|
||||
}
|
||||
if checkMake {
|
||||
for _, dependency := range pkgInfo.MakeDepends {
|
||||
if !IsPackageProvided(dependency, rootDir) {
|
||||
ret = append(ret, dependency)
|
||||
}
|
||||
}
|
||||
}
|
||||
if checkOptional {
|
||||
for _, dependency := range pkgInfo.OptionalDepends {
|
||||
if !IsPackageProvided(dependency, rootDir) {
|
||||
ret = append(ret, dependency)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func (pkgInfo *PackageInfo) GetDependants(rootDir string) ([]string, error) {
|
||||
ret := make([]string, 0)
|
||||
|
||||
pkgs, err := GetInstalledPackages(rootDir)
|
||||
if err != nil {
|
||||
return nil, errors.New("could not get installed packages")
|
||||
}
|
||||
for _, pkg := range pkgs {
|
||||
bpmpkg := GetPackage(pkg, rootDir)
|
||||
if bpmpkg == nil {
|
||||
return nil, errors.New("package not found: " + pkg)
|
||||
}
|
||||
if bpmpkg.PkgInfo.Name == pkgInfo.Name {
|
||||
continue
|
||||
}
|
||||
|
||||
dependencies := bpmpkg.PkgInfo.GetAllDependencies(false, true)
|
||||
|
||||
if slices.Contains(dependencies, pkgInfo.Name) {
|
||||
ret = append(ret, pkg)
|
||||
continue
|
||||
}
|
||||
for _, vpkg := range pkgInfo.Provides {
|
||||
if slices.Contains(dependencies, vpkg) {
|
||||
ret = append(ret, pkg)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (pkgInfo *PackageInfo) CheckConflicts(rootDir string) []string {
|
||||
var ret []string
|
||||
for _, conflict := range pkgInfo.Conflicts {
|
||||
if IsPackageInstalled(conflict, rootDir) {
|
||||
ret = append(ret, conflict)
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (pkgInfo *PackageInfo) ResolveDependencies(resolved, unresolved *[]string, checkMake, checkOptional, ignoreInstalled, verbose bool, rootDir string) ([]string, []string) {
|
||||
*unresolved = append(*unresolved, pkgInfo.Name)
|
||||
for _, depend := range pkgInfo.GetAllDependencies(checkMake, checkOptional) {
|
||||
depend = strings.TrimSpace(depend)
|
||||
depend = strings.ToLower(depend)
|
||||
if !slices.Contains(*resolved, depend) {
|
||||
if slices.Contains(*unresolved, depend) {
|
||||
if verbose {
|
||||
fmt.Printf("Circular dependency was detected (%s -> %s). Installing %s first\n", pkgInfo.Name, depend, depend)
|
||||
}
|
||||
if !slices.Contains(*resolved, depend) {
|
||||
*resolved = append(*resolved, depend)
|
||||
}
|
||||
continue
|
||||
} else if ignoreInstalled && IsPackageProvided(depend, rootDir) {
|
||||
continue
|
||||
}
|
||||
var err error
|
||||
var entry *RepositoryEntry
|
||||
entry, _, err = GetRepositoryEntry(depend)
|
||||
if err != nil {
|
||||
if entry = ResolveVirtualPackage(depend); entry == nil {
|
||||
if !slices.Contains(*unresolved, depend) {
|
||||
*unresolved = append(*unresolved, depend)
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
entry.Info.ResolveDependencies(resolved, unresolved, checkMake, checkOptional, ignoreInstalled, verbose, rootDir)
|
||||
}
|
||||
}
|
||||
if !slices.Contains(*resolved, pkgInfo.Name) {
|
||||
*resolved = append(*resolved, pkgInfo.Name)
|
||||
}
|
||||
*unresolved = stringSliceRemove(*unresolved, pkgInfo.Name)
|
||||
return *resolved, *unresolved
|
||||
}
|
||||
|
||||
func IsPackageInstalled(pkg, rootDir string) bool {
|
||||
installedDir := path.Join(rootDir, "var/lib/bpm/installed/")
|
||||
pkgDir := path.Join(installedDir, pkg)
|
||||
if _, err := os.Stat(pkgDir); err != nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func IsVirtualPackage(pkg, rootDir string) (bool, string) {
|
||||
pkgs, err := GetInstalledPackages(rootDir)
|
||||
if err != nil {
|
||||
return false, ""
|
||||
}
|
||||
for _, p := range pkgs {
|
||||
if p == pkg {
|
||||
return false, ""
|
||||
}
|
||||
i := GetPackageInfo(p, rootDir)
|
||||
if i == nil {
|
||||
continue
|
||||
}
|
||||
if slices.Contains(i.Provides, pkg) {
|
||||
return true, p
|
||||
}
|
||||
}
|
||||
return false, ""
|
||||
}
|
||||
|
||||
func IsPackageProvided(pkg, rootDir string) bool {
|
||||
pkgs, err := GetInstalledPackages(rootDir)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
for _, p := range pkgs {
|
||||
if p == pkg {
|
||||
return true
|
||||
}
|
||||
i := GetPackageInfo(p, rootDir)
|
||||
if i == nil {
|
||||
continue
|
||||
}
|
||||
if slices.Contains(i.Provides, pkg) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func GetInstalledPackages(rootDir string) ([]string, error) {
|
||||
installedDir := path.Join(rootDir, "var/lib/bpm/installed/")
|
||||
items, err := os.ReadDir(installedDir)
|
||||
if os.IsNotExist(err) {
|
||||
return nil, nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var ret []string
|
||||
for _, item := range items {
|
||||
ret = append(ret, item.Name())
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func GetPackageFiles(pkg, rootDir string) []*PackageFileEntry {
|
||||
var pkgFiles []*PackageFileEntry
|
||||
installedDir := path.Join(rootDir, "var/lib/bpm/installed/")
|
||||
pkgDir := path.Join(installedDir, pkg)
|
||||
files := path.Join(pkgDir, "files")
|
||||
if _, err := os.Stat(installedDir); os.IsNotExist(err) {
|
||||
return nil
|
||||
}
|
||||
if _, err := os.Stat(pkgDir); os.IsNotExist(err) {
|
||||
return nil
|
||||
}
|
||||
bs, err := os.ReadFile(files)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, line := range strings.Split(string(bs), "\n") {
|
||||
if strings.TrimSpace(line) == "" {
|
||||
continue
|
||||
}
|
||||
stringEntry := strings.Split(strings.TrimSpace(line), " ")
|
||||
if len(stringEntry) < 5 {
|
||||
pkgFiles = append(pkgFiles, &PackageFileEntry{
|
||||
Path: strings.TrimSuffix(line, "/"),
|
||||
OctalPerms: 0,
|
||||
UserID: 0,
|
||||
GroupID: 0,
|
||||
SizeInBytes: 0,
|
||||
})
|
||||
continue
|
||||
}
|
||||
uid, err := strconv.ParseInt(stringEntry[len(stringEntry)-4], 0, 32)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
octalPerms, err := strconv.ParseInt(stringEntry[len(stringEntry)-3], 0, 32)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
gid, err := strconv.ParseInt(stringEntry[len(stringEntry)-2], 0, 32)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
size, err := strconv.ParseUint(stringEntry[len(stringEntry)-1], 0, 64)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
pkgFiles = append(pkgFiles, &PackageFileEntry{
|
||||
Path: strings.TrimSuffix(strings.Join(stringEntry[:len(stringEntry)-4], " "), "/"),
|
||||
OctalPerms: uint32(octalPerms),
|
||||
UserID: int(uid),
|
||||
GroupID: int(gid),
|
||||
SizeInBytes: size,
|
||||
})
|
||||
}
|
||||
|
||||
return pkgFiles
|
||||
}
|
||||
|
||||
func GetPackageInfo(pkg, rootDir string) *PackageInfo {
|
||||
installedDir := path.Join(rootDir, "var/lib/bpm/installed/")
|
||||
pkgDir := path.Join(installedDir, pkg)
|
||||
files := path.Join(pkgDir, "info")
|
||||
if _, err := os.Stat(installedDir); os.IsNotExist(err) {
|
||||
return nil
|
||||
}
|
||||
if _, err := os.Stat(pkgDir); os.IsNotExist(err) {
|
||||
return nil
|
||||
}
|
||||
file, err := os.Open(files)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
bs, err := io.ReadAll(file)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
info, err := ReadPackageInfo(string(bs))
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return info
|
||||
}
|
||||
|
||||
func GetPackage(pkg, rootDir string) *BPMPackage {
|
||||
if !IsPackageInstalled(pkg, rootDir) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &BPMPackage{
|
||||
PkgInfo: GetPackageInfo(pkg, rootDir),
|
||||
PkgFiles: GetPackageFiles(pkg, rootDir),
|
||||
}
|
||||
}
|
||||
|
||||
func GetAllPackageFiles(rootDir string, excludePackages ...string) (map[string][]*BPMPackage, error) {
|
||||
ret := make(map[string][]*BPMPackage)
|
||||
|
||||
pkgNames, err := GetInstalledPackages(rootDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, pkgName := range pkgNames {
|
||||
if slices.Contains(excludePackages, pkgName) {
|
||||
continue
|
||||
}
|
||||
bpmpkg := GetPackage(pkgName, rootDir)
|
||||
if bpmpkg == nil {
|
||||
return nil, errors.New(fmt.Sprintf("could not get BPM package (%s)", pkgName))
|
||||
}
|
||||
for _, entry := range bpmpkg.PkgFiles {
|
||||
if _, ok := ret[entry.Path]; ok {
|
||||
ret[entry.Path] = append(ret[entry.Path], bpmpkg)
|
||||
} else {
|
||||
ret[entry.Path] = []*BPMPackage{bpmpkg}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func removePackage(pkg string, verbose bool, rootDir string) error {
|
||||
installedDir := path.Join(rootDir, "var/lib/bpm/installed/")
|
||||
pkgDir := path.Join(installedDir, pkg)
|
||||
@ -1206,7 +900,7 @@ func removePackage(pkg string, verbose bool, rootDir string) error {
|
||||
}
|
||||
|
||||
// Fetching and reversing package file entry list
|
||||
fileEntries := GetPackageFiles(pkg, rootDir)
|
||||
fileEntries := GetPackage(pkg, rootDir).PkgFiles
|
||||
sort.Slice(fileEntries, func(i, j int) bool {
|
||||
return fileEntries[i].Path < fileEntries[j].Path
|
||||
})
|
||||
|
Loading…
x
Reference in New Issue
Block a user