Fix dependency installation order

This commit is contained in:
2025-07-06 21:21:55 +03:00
parent 458c091ac2
commit 8a627254c9
3 changed files with 105 additions and 53 deletions
+3 -3
View File
@@ -598,9 +598,9 @@ func resolveCommand() {
// Get direct runtime and make dependencies // Get direct runtime and make dependencies
totalDepends := make([]string, 0) totalDepends := make([]string, 0)
for depend := range bpmpkg.PkgInfo.GetDependencies(true, false) { for _, depend := range bpmpkg.PkgInfo.GetDependencies(true, false) {
if !slices.Contains(totalDepends, depend) { if !slices.Contains(totalDepends, depend.PkgName) {
totalDepends = append(totalDepends, depend) totalDepends = append(totalDepends, depend.PkgName)
} }
} }
+85 -33
View File
@@ -6,23 +6,45 @@ import (
"slices" "slices"
) )
func (pkgInfo *PackageInfo) GetDependencies(includeMakeDepends, includeOptionalDepends bool) map[string]InstallationReason { type pkgInstallationReason struct {
allDepends := make(map[string]InstallationReason) PkgName string
InstallationReason InstallationReason
}
func (pkgInfo *PackageInfo) GetDependencies(includeMakeDepends, includeOptionalDepends bool) []pkgInstallationReason {
allDepends := make([]pkgInstallationReason, 0)
for _, depend := range pkgInfo.Depends { for _, depend := range pkgInfo.Depends {
allDepends[depend] = InstallationReasonDependency if !slices.ContainsFunc(allDepends, func(p pkgInstallationReason) bool {
return p.PkgName == depend
}) {
allDepends = append(allDepends, pkgInstallationReason{
PkgName: depend,
InstallationReason: InstallationReasonDependency,
})
}
} }
if includeOptionalDepends { if includeOptionalDepends {
for _, depend := range pkgInfo.OptionalDepends { for _, depend := range pkgInfo.OptionalDepends {
if _, ok := allDepends[depend]; !ok { if !slices.ContainsFunc(allDepends, func(p pkgInstallationReason) bool {
allDepends[depend] = InstallationReasonDependency return p.PkgName == depend
}) {
allDepends = append(allDepends, pkgInstallationReason{
PkgName: depend,
InstallationReason: InstallationReasonDependency,
})
} }
} }
} }
if includeMakeDepends { if includeMakeDepends {
for _, depend := range pkgInfo.MakeDepends { for _, depend := range pkgInfo.MakeDepends {
if _, ok := allDepends[depend]; !ok { if !slices.ContainsFunc(allDepends, func(p pkgInstallationReason) bool {
allDepends[depend] = InstallationReasonMakeDependency return p.PkgName == depend
}) {
allDepends = append(allDepends, pkgInstallationReason{
PkgName: depend,
InstallationReason: InstallationReasonMakeDependency,
})
} }
} }
} }
@@ -45,10 +67,13 @@ func (pkgInfo *PackageInfo) getAllDependencies(resolved *[]string, unresolved *[
*unresolved = append(*unresolved, pkgInfo.Name) *unresolved = append(*unresolved, pkgInfo.Name)
// Loop through all dependencies // Loop through all dependencies
for depend := range pkgInfo.GetDependencies(includeMakeDepends, includeOptionalDepends) { for _, pkgIR := range pkgInfo.GetDependencies(includeMakeDepends, includeOptionalDepends) {
depend := pkgIR.PkgName
if isVirtual, p := IsVirtualPackage(depend, rootDir); isVirtual { if isVirtual, p := IsVirtualPackage(depend, rootDir); isVirtual {
depend = p depend = p
} }
if !slices.Contains(*resolved, depend) { if !slices.Contains(*resolved, depend) {
// Add current dependency to resolved slice when circular dependency is detected // Add current dependency to resolved slice when circular dependency is detected
if slices.Contains(*unresolved, depend) { if slices.Contains(*unresolved, depend) {
@@ -71,55 +96,78 @@ func (pkgInfo *PackageInfo) getAllDependencies(resolved *[]string, unresolved *[
*unresolved = stringSliceRemove(*unresolved, pkgInfo.Name) *unresolved = stringSliceRemove(*unresolved, pkgInfo.Name)
} }
func ResolveAllPackageDependenciesFromDatabases(pkgInfo *PackageInfo, checkMake, checkOptional, ignoreInstalled, verbose bool, rootDir string) (resolved map[string]InstallationReason, unresolved []string) { func ResolveAllPackageDependenciesFromDatabases(pkgInfo *PackageInfo, checkMake, checkOptional, ignoreInstalled, verbose bool, rootDir string) (resolved []pkgInstallationReason, unresolved []string) {
// Initialize slices // Initialize slices
resolved = make(map[string]InstallationReason) resolved = make([]pkgInstallationReason, 0)
unresolved = make([]string, 0) unresolved = make([]string, 0)
// Call unexported function // Call unexported function
resolvePackageDependenciesFromDatabase(resolved, &unresolved, pkgInfo, InstallationReasonDependency, checkMake, checkOptional, ignoreInstalled, verbose, rootDir) resolvePackageDependenciesFromDatabase(&resolved, &unresolved, pkgInfo, checkMake, checkOptional, ignoreInstalled, verbose, rootDir)
// Remove main package from unresolved slice
unresolved = stringSliceRemove(unresolved, pkgInfo.Name)
return resolved, unresolved return resolved, unresolved
} }
func resolvePackageDependenciesFromDatabase(resolved map[string]InstallationReason, unresolved *[]string, pkgInfo *PackageInfo, installationReason InstallationReason, checkMake, checkOptional, ignoreInstalled, verbose bool, rootDir string) { func resolvePackageDependenciesFromDatabase(resolved *[]pkgInstallationReason, unresolved *[]string, pkgInfo *PackageInfo, checkMake, checkOptional, ignoreInstalled, verbose 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 depend, ir := range pkgInfo.GetDependencies(pkgInfo.Type == "source", checkOptional) { for _, pkgIR := range pkgInfo.GetDependencies(pkgInfo.Type == "source", checkOptional) {
if _, ok := resolved[depend]; !ok { // Skip dependency if it has already been resolved
if slices.ContainsFunc(*resolved, func(p pkgInstallationReason) bool {
return p.PkgName == pkgIR.PkgName
}) {
continue
}
// Add current dependency to resolved slice when circular dependency is detected // Add current dependency to resolved slice when circular dependency is detected
if slices.Contains(*unresolved, depend) { if slices.Contains(*unresolved, pkgIR.PkgName) {
if verbose { if verbose {
fmt.Printf("Circular dependency was detected (%s -> %s). Installing %s first\n", pkgInfo.Name, depend, depend) fmt.Printf("Circular dependency was detected (%s -> %s). Installing %s first\n", pkgInfo.Name, pkgIR.PkgName, pkgIR.PkgName)
} }
if _, ok := resolved[depend]; !ok {
resolved[depend] = ir *resolved = append(*resolved, pkgInstallationReason{
} PkgName: pkgIR.PkgName,
continue InstallationReason: pkgIR.InstallationReason,
} else if ignoreInstalled && IsPackageProvided(depend, rootDir) { })
continue continue
} }
// Skip dependency if it is already installed or provided
if ignoreInstalled && IsPackageProvided(pkgIR.PkgName, rootDir) {
continue
}
// Get database entry for dependency
var err error var err error
var entry *BPMDatabaseEntry var entry *BPMDatabaseEntry
entry, _, err = GetDatabaseEntry(depend) entry, _, err = GetDatabaseEntry(pkgIR.PkgName)
if err != nil { if err != nil {
if entry = ResolveVirtualPackage(depend); entry == nil { if entry = ResolveVirtualPackage(pkgIR.PkgName); entry == nil {
if !slices.Contains(*unresolved, depend) { if !slices.Contains(*unresolved, pkgIR.PkgName) {
*unresolved = append(*unresolved, depend) *unresolved = append(*unresolved, pkgIR.PkgName)
} }
continue continue
} }
} }
resolvePackageDependenciesFromDatabase(resolved, unresolved, entry.Info, ir, checkMake, checkOptional, ignoreInstalled, verbose, rootDir)
}
}
if _, ok := resolved[pkgInfo.Name]; !ok { // Resolve the dependencies of this dependency
resolved[pkgInfo.Name] = installationReason resolvePackageDependenciesFromDatabase(resolved, unresolved, entry.Info, checkMake, checkOptional, ignoreInstalled, verbose, rootDir)
// Move dependency from the unresolved slice to the resolved slice
if !slices.ContainsFunc(*resolved, func(p pkgInstallationReason) bool {
return p.PkgName == entry.Info.Name
}) {
*resolved = append(*resolved, pkgInstallationReason{
PkgName: entry.Info.Name,
InstallationReason: pkgIR.InstallationReason,
})
}
*unresolved = stringSliceRemove(*unresolved, entry.Info.Name)
} }
*unresolved = stringSliceRemove(*unresolved, pkgInfo.Name)
} }
func GetPackageDependants(pkgName string, rootDir string) ([]string, error) { func GetPackageDependants(pkgName string, rootDir string) ([]string, error) {
@@ -154,7 +202,9 @@ func GetPackageDependants(pkgName string, rootDir string) ([]string, error) {
dependencies := installedPkg.PkgInfo.GetDependencies(false, true) dependencies := installedPkg.PkgInfo.GetDependencies(false, true)
// Add installed package to list if its dependencies include pkgName // Add installed package to list if its dependencies include pkgName
if _, ok := dependencies[pkgName]; ok { if slices.ContainsFunc(dependencies, func(p pkgInstallationReason) bool {
return p.PkgName == pkgName
}) {
ret = append(ret, installedPkgName) ret = append(ret, installedPkgName)
continue continue
} }
@@ -162,7 +212,9 @@ func GetPackageDependants(pkgName string, rootDir string) ([]string, error) {
// Loop through each virtual package // Loop through each virtual package
for _, vpkg := range pkg.PkgInfo.Provides { for _, vpkg := range pkg.PkgInfo.Provides {
// Add installed package to list if its dependencies contain a provided virtual package // Add installed package to list if its dependencies contain a provided virtual package
if _, ok := dependencies[vpkg]; ok { if slices.ContainsFunc(dependencies, func(p pkgInstallationReason) bool {
return p.PkgName == vpkg
}) {
ret = append(ret, installedPkgName) ret = append(ret, installedPkgName)
break break
} }
+6 -6
View File
@@ -142,17 +142,17 @@ func (operation *BPMOperation) ResolveDependencies(reinstallDependencies, instal
operation.UnresolvedDepends = append(operation.UnresolvedDepends, unresolved...) operation.UnresolvedDepends = append(operation.UnresolvedDepends, unresolved...)
for depend, installationReason := range resolved { for _, resolvedPkg := range resolved {
if !operation.ActionsContainPackage(depend) && depend != pkgInfo.Name { if !operation.ActionsContainPackage(resolvedPkg.PkgName) && resolvedPkg.PkgName != pkgInfo.Name {
if !reinstallDependencies && IsPackageInstalled(depend, operation.RootDir) { if !reinstallDependencies && IsPackageInstalled(resolvedPkg.PkgName, operation.RootDir) {
continue continue
} }
entry, _, err := GetDatabaseEntry(depend) entry, _, err := GetDatabaseEntry(resolvedPkg.PkgName)
if err != nil { if err != nil {
return errors.New("could not get database entry for package (" + depend + ")") return errors.New("could not get database entry for package (" + resolvedPkg.PkgName + ")")
} }
operation.InsertActionAt(pos, &FetchPackageAction{ operation.InsertActionAt(pos, &FetchPackageAction{
InstallationReason: installationReason, InstallationReason: resolvedPkg.InstallationReason,
DatabaseEntry: entry, DatabaseEntry: entry,
}) })
pos++ pos++