Redo dependency resolution and cache installed package information

This commit is contained in:
2025-05-13 20:26:55 +03:00
parent f2bc7c8968
commit 5f03a6a1ad
7 changed files with 420 additions and 319 deletions
+3 -309
View File
@@ -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
})