Greatly simplify dependency resolution

This commit is contained in:
2026-02-07 14:52:14 +02:00
parent 9ae2d3f893
commit 76ad8e77c5
3 changed files with 99 additions and 24 deletions
+60
View File
@@ -318,3 +318,63 @@ func (pkgInfo *PackageInfo) GetPackageOptionalDependants(rootDir string) (depend
return dependants
}
type ResolvedPackage struct {
DatabaseEntry *BPMDatabaseEntry
InstallationReason InstallationReason
}
func ResolveDependencies(pkgInfo *PackageInfo, resolvedVirtualPackages map[string]string, includeOptionalDepends bool, rootDir string) (resolved []ResolvedPackage, unresolved []string) {
visited := make([]string, 0)
var dfs func(resolvedPkg *PackageInfo)
dfs = func(pkgInfo *PackageInfo) {
checkDependencies := func(dependencies []string, installationReason InstallationReason) {
for _, depend := range dependencies {
// Ignore if package is already installed
if IsPackageInstalled(depend, rootDir) {
continue
} else if providers := GetVirtualPackageInfo(depend, rootDir); len(providers) > 0 {
continue
}
// Find database entry for dependency
var dependEntry *BPMDatabaseEntry
if resolvedVpkg, ok := resolvedVirtualPackages[depend]; ok {
dependEntry, _, _ = GetDatabaseEntry(resolvedVpkg)
} else if entry, _, _ := GetDatabaseEntry(depend); entry != nil {
dependEntry = entry
} else if providers := GetDatabaseVirtualPackageEntry(depend); len(providers) > 0 {
dependEntry = providers[0]
}
if dependEntry == nil {
unresolved = append(unresolved, depend)
continue
}
if !slices.Contains(visited, dependEntry.Info.Name) {
dfs(dependEntry.Info)
resolved = append(resolved, ResolvedPackage{DatabaseEntry: dependEntry, InstallationReason: installationReason})
}
}
}
visited = append(visited, pkgInfo.Name)
checkDependencies(pkgInfo.Depends, InstallationReasonDependency)
if pkgInfo.Type == "binary" {
checkDependencies(pkgInfo.RuntimeDepends, InstallationReasonDependency)
} else if pkgInfo.Type == "source" {
checkDependencies(pkgInfo.MakeDepends, InstallationReasonMakeDependency)
checkDependencies(pkgInfo.CheckDepends, InstallationReasonMakeDependency)
}
if includeOptionalDepends {
checkDependencies(pkgInfo.OptionalDepends, InstallationReasonManual)
}
}
dfs(pkgInfo)
return resolved, unresolved
}
+2 -8
View File
@@ -132,10 +132,7 @@ func InstallPackages(rootDir string, forceInstallationReason InstallationReason,
}
// Resolve dependencies
err = operation.ResolveDependencies(reinstallMethod == ReinstallMethodAll, installRuntimeDependencies, installOptionalDependencies, verbose)
if err != nil {
return nil, fmt.Errorf("could not resolve dependencies: %s", err)
}
operation.ResolveDependencies(reinstallMethod == ReinstallMethodAll, installOptionalDependencies)
if len(operation.UnresolvedDepends) != 0 {
if !forceInstallation {
return nil, DependencyNotFoundErr{operation.UnresolvedDepends}
@@ -431,10 +428,7 @@ func UpdatePackages(rootDir string, syncDatabase bool, allowDowngrades bool, ins
}
// Check for new dependencies in updated packages
err = operation.ResolveDependencies(false, true, installOptionalDependencies, verbose)
if err != nil {
return nil, fmt.Errorf("could not resolve dependencies: %s", err)
}
operation.ResolveDependencies(false, installOptionalDependencies)
if len(operation.UnresolvedDepends) != 0 {
if !forceInstallation {
return nil, DependencyNotFoundErr{operation.UnresolvedDepends}
+37 -16
View File
@@ -131,9 +131,9 @@ func (operation *BPMOperation) GetFinalActionSize(rootDir string) int64 {
return ret
}
func (operation *BPMOperation) ResolveDependencies(reinstallDependencies, installRuntimeDependencies, installOptionalDependencies, verbose bool) error {
pos := 0
resolvedVirtualPkgs := make(map[string]string, 0)
func (operation *BPMOperation) ResolveDependencies(reinstallDependencies, installOptionalDependencies bool) {
// Discover resolved virtual packages
resolvedVirtualPackages := make(map[string]string)
for _, value := range slices.Clone(operation.Actions) {
var pkgInfo *PackageInfo
if value.GetActionType() == "install" {
@@ -143,34 +143,55 @@ func (operation *BPMOperation) ResolveDependencies(reinstallDependencies, instal
action := value.(*FetchPackageAction)
pkgInfo = action.DatabaseEntry.Info
} else {
pos++
continue
}
resolved, unresolved := ResolveAllPackageDependenciesFromDatabases(pkgInfo, resolvedVirtualPkgs, pkgInfo.Type == "source", pkgInfo.Type == "source" && operation.RunChecks, installRuntimeDependencies, installOptionalDependencies, !reinstallDependencies, verbose, operation.RootDir)
for _, vpkg := range pkgInfo.Provides {
if _, ok := resolvedVirtualPackages[vpkg]; !ok {
resolvedVirtualPackages[vpkg] = pkgInfo.Name
}
}
}
// Discover all dependencies
pos := 0
for _, value := range slices.Clone(operation.Actions) {
var pkgInfo *PackageInfo
if value.GetActionType() == "install" {
action := value.(*InstallPackageAction)
pkgInfo = action.BpmPackage.PkgInfo
} else if value.GetActionType() == "fetch" {
action := value.(*FetchPackageAction)
pkgInfo = action.DatabaseEntry.Info
} else {
continue
}
resolved, unresolved := ResolveDependencies(pkgInfo, resolvedVirtualPackages, installOptionalDependencies, operation.RootDir)
// Append unresolved dependencies
operation.UnresolvedDepends = append(operation.UnresolvedDepends, unresolved...)
operation.UnresolvedDepends = removeDuplicates(operation.UnresolvedDepends)
for _, resolvedPkg := range resolved {
if !operation.ActionsContainPackage(resolvedPkg.PkgName) && resolvedPkg.PkgName != pkgInfo.Name {
if !reinstallDependencies && IsPackageInstalled(resolvedPkg.PkgName, operation.RootDir) {
continue
}
entry, _, err := GetDatabaseEntry(resolvedPkg.PkgName)
if err != nil {
return errors.New("could not get database entry for package (" + resolvedPkg.PkgName + ")")
}
if !operation.ActionsContainPackage(resolvedPkg.DatabaseEntry.Info.Name) && resolvedPkg.DatabaseEntry.Info.Name != pkgInfo.Name {
operation.InsertActionAt(pos, &FetchPackageAction{
InstallationReason: resolvedPkg.InstallationReason,
DatabaseEntry: entry,
DatabaseEntry: resolvedPkg.DatabaseEntry,
})
for _, vpkg := range resolvedPkg.DatabaseEntry.Info.Provides {
if _, ok := resolvedVirtualPackages[vpkg]; !ok {
resolvedVirtualPackages[vpkg] = resolvedPkg.DatabaseEntry.Info.Name
}
}
pos++
}
}
pos++
}
return nil
}
func (operation *BPMOperation) RemoveNeededPackages() error {