mirror of
https://github.com/EnumeratedDev/bpm.git
synced 2026-09-16 10:36:12 +00:00
214 lines
6.6 KiB
Go
214 lines
6.6 KiB
Go
package bpmlib
|
|
|
|
import (
|
|
"fmt"
|
|
"slices"
|
|
)
|
|
|
|
type pkgInstallationReason struct {
|
|
PkgName string
|
|
InstallationReason InstallationReason
|
|
}
|
|
|
|
func (pkgInfo *PackageInfo) GetDependencies(includeMakeDepends, includeOptionalDepends bool) []pkgInstallationReason {
|
|
allDepends := make([]pkgInstallationReason, 0)
|
|
|
|
for _, depend := range pkgInfo.Depends {
|
|
if !slices.ContainsFunc(allDepends, func(p pkgInstallationReason) bool {
|
|
return p.PkgName == depend
|
|
}) {
|
|
allDepends = append(allDepends, pkgInstallationReason{
|
|
PkgName: depend,
|
|
InstallationReason: InstallationReasonDependency,
|
|
})
|
|
}
|
|
}
|
|
if includeOptionalDepends {
|
|
for _, depend := range pkgInfo.OptionalDepends {
|
|
if !slices.ContainsFunc(allDepends, func(p pkgInstallationReason) bool {
|
|
return p.PkgName == depend
|
|
}) {
|
|
allDepends = append(allDepends, pkgInstallationReason{
|
|
PkgName: depend,
|
|
InstallationReason: InstallationReasonManual,
|
|
})
|
|
}
|
|
}
|
|
}
|
|
if includeMakeDepends {
|
|
for _, depend := range pkgInfo.MakeDepends {
|
|
if !slices.ContainsFunc(allDepends, func(p pkgInstallationReason) bool {
|
|
return p.PkgName == depend
|
|
}) {
|
|
allDepends = append(allDepends, pkgInstallationReason{
|
|
PkgName: depend,
|
|
InstallationReason: InstallationReasonMakeDependency,
|
|
})
|
|
}
|
|
}
|
|
}
|
|
return allDepends
|
|
}
|
|
|
|
func (pkgInfo *PackageInfo) GetDependenciesRecursive(includeMakeDepends bool, rootDir string) (resolved []string) {
|
|
// Initialize slices
|
|
resolved = make([]string, 0)
|
|
unresolved := make([]string, 0)
|
|
|
|
// Call unexported function
|
|
pkgInfo.getDependenciesRecursive(&resolved, &unresolved, includeMakeDepends, rootDir)
|
|
|
|
return resolved
|
|
}
|
|
|
|
func (pkgInfo *PackageInfo) getDependenciesRecursive(resolved *[]string, unresolved *[]string, includeMakeDepends bool, rootDir string) {
|
|
// Add current package name to unresolved slice
|
|
*unresolved = append(*unresolved, pkgInfo.Name)
|
|
|
|
// Loop through all dependencies
|
|
for _, pkgIR := range pkgInfo.GetDependencies(includeMakeDepends, false) {
|
|
depend := pkgIR.PkgName
|
|
|
|
if isVirtual, p := IsVirtualPackage(depend, rootDir); isVirtual {
|
|
depend = p
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
dependInfo := GetPackageInfo(depend, rootDir)
|
|
|
|
if dependInfo != nil {
|
|
dependInfo.getDependenciesRecursive(resolved, unresolved, includeMakeDepends, rootDir)
|
|
}
|
|
}
|
|
}
|
|
if !slices.Contains(*resolved, pkgInfo.Name) {
|
|
*resolved = append(*resolved, pkgInfo.Name)
|
|
}
|
|
*unresolved = stringSliceRemove(*unresolved, pkgInfo.Name)
|
|
}
|
|
|
|
func ResolveAllPackageDependenciesFromDatabases(pkgInfo *PackageInfo, checkMake, checkOptional, ignoreInstalled, verbose bool, rootDir string) (resolved []pkgInstallationReason, unresolved []string) {
|
|
// Initialize slices
|
|
resolved = make([]pkgInstallationReason, 0)
|
|
unresolved = make([]string, 0)
|
|
|
|
// Call unexported function
|
|
resolvePackageDependenciesFromDatabase(&resolved, &unresolved, pkgInfo, checkMake, checkOptional, ignoreInstalled, verbose, rootDir)
|
|
|
|
// Remove main package from unresolved slice
|
|
unresolved = stringSliceRemove(unresolved, pkgInfo.Name)
|
|
|
|
return resolved, unresolved
|
|
}
|
|
|
|
func resolvePackageDependenciesFromDatabase(resolved *[]pkgInstallationReason, 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 _, pkgIR := range pkgInfo.GetDependencies(pkgInfo.Type == "source", checkOptional) {
|
|
// 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
|
|
if slices.Contains(*unresolved, pkgIR.PkgName) {
|
|
if verbose {
|
|
fmt.Printf("Circular dependency was detected (%s -> %s). Installing %s first\n", pkgInfo.Name, pkgIR.PkgName, pkgIR.PkgName)
|
|
}
|
|
|
|
*resolved = append(*resolved, pkgInstallationReason{
|
|
PkgName: pkgIR.PkgName,
|
|
InstallationReason: pkgIR.InstallationReason,
|
|
})
|
|
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 entry *BPMDatabaseEntry
|
|
entry, _, err = GetDatabaseEntry(pkgIR.PkgName)
|
|
if err != nil {
|
|
if entry = ResolveVirtualPackage(pkgIR.PkgName); entry == nil {
|
|
if !slices.Contains(*unresolved, pkgIR.PkgName) {
|
|
*unresolved = append(*unresolved, pkgIR.PkgName)
|
|
}
|
|
continue
|
|
}
|
|
}
|
|
|
|
// Resolve the dependencies of this dependency
|
|
resolvePackageDependenciesFromDatabase(resolved, unresolved, entry.Info, checkMake, false, 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)
|
|
}
|
|
}
|
|
|
|
func (pkgInfo *PackageInfo) GetPackageDependants(rootDir string) (dependants []string) {
|
|
// Get installed package names
|
|
pkgs, err := GetInstalledPackages(rootDir)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
|
|
// Loop through all installed packages
|
|
for _, installedPkgName := range pkgs {
|
|
// Get installed BPM package
|
|
installedPkg := GetPackage(installedPkgName, rootDir)
|
|
if installedPkg == nil {
|
|
return nil
|
|
}
|
|
|
|
// Skip iteration if comparing the same packages
|
|
if installedPkg.PkgInfo.Name == pkgInfo.Name {
|
|
continue
|
|
}
|
|
|
|
// Add installed package to list if its dependencies include pkgName
|
|
if slices.ContainsFunc(installedPkg.PkgInfo.Depends, func(n string) bool {
|
|
return n == pkgInfo.Name
|
|
}) {
|
|
dependants = append(dependants, installedPkgName)
|
|
continue
|
|
}
|
|
|
|
// Loop through each virtual package
|
|
for _, vpkg := range pkgInfo.Provides {
|
|
// Add installed package to list if its dependencies contain a provided virtual package
|
|
if slices.ContainsFunc(installedPkg.PkgInfo.Depends, func(n string) bool {
|
|
return n == vpkg
|
|
}) {
|
|
dependants = append(dependants, installedPkgName)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
return dependants
|
|
}
|