From 548b2476bdf93322fbfc0f4f9844bb2369be8866 Mon Sep 17 00:00:00 2001 From: EnumDev Date: Fri, 26 Dec 2025 12:34:08 +0200 Subject: [PATCH] Reduce memory usage for the 'list' subcommand --- src/bpm/main.go | 55 ++++++++++++++++++++++--------- src/bpmlib/databases.go | 2 +- src/bpmlib/dependencies.go | 44 +++++++++---------------- src/bpmlib/operations.go | 6 ++-- src/bpmlib/packages.go | 66 ++++++++++++++++---------------------- src/bpmlib/utils.go | 2 +- 6 files changed, 88 insertions(+), 87 deletions(-) diff --git a/src/bpm/main.go b/src/bpm/main.go index ad55681..14fefb9 100644 --- a/src/bpm/main.go +++ b/src/bpm/main.go @@ -254,7 +254,14 @@ func showPackageInfo() { } fmt.Println("File: " + abs) } - fmt.Println(bpmpkg.CreateReadableInfo(rootDir, showHumanReadableSize)) + fmt.Println(bpmpkg.PkgInfo.CreateReadableInfo(rootDir)) + if bpmpkg.PkgInfo.Type == "binary" { + if !showHumanReadableSize { + fmt.Printf("Installed size: %d\n", bpmpkg.GetInstalledSize()) + } else { + fmt.Printf("Installed size: %s\n", bpmlib.BytesToHumanReadable(bpmpkg.GetInstalledSize())) + } + } } } @@ -292,9 +299,21 @@ func showPackageList() { return } - installedPackages := make([]*bpmlib.BPMPackage, len(installedPackageNames)) + installedPackages := make([]struct { + pkgInfo bpmlib.PackageInfo + installedSize int64 + }, len(installedPackageNames)) for i, pkgName := range installedPackageNames { - installedPackages[i] = bpmlib.GetPackage(pkgName, rootDir) + pkgInfo := *bpmlib.GetPackageInfo(pkgName, rootDir) + installedSize := bpmlib.GetPackage(pkgName, rootDir).GetInstalledSize() + + installedPackages[i] = struct { + pkgInfo bpmlib.PackageInfo + installedSize int64 + }{ + pkgInfo: pkgInfo, + installedSize: installedSize, + } } databaseEntries := make([]*bpmlib.BPMDatabaseEntry, 0) @@ -305,8 +324,11 @@ func showPackageList() { switch sortPackages { case "", "name": case "size": - slices.SortFunc(installedPackages, func(a, b *bpmlib.BPMPackage) int { - return int(b.GetInstalledSize() - a.GetInstalledSize()) + slices.SortFunc(installedPackages, func(a, b struct { + pkgInfo bpmlib.PackageInfo + installedSize int64 + }) int { + return int(b.installedSize - a.installedSize) }) slices.SortFunc(databaseEntries, func(a, b *bpmlib.BPMDatabaseEntry) int { return int(b.InstalledSize - a.InstalledSize) @@ -335,7 +357,7 @@ func showPackageList() { } } else { for _, pkg := range installedPackages { - installationReason := bpmlib.GetInstallationReason(pkg.PkgInfo.Name, rootDir) + installationReason := bpmlib.GetInstallationReason(pkg.pkgInfo.Name, rootDir) if installationReason == bpmlib.InstallationReasonManual && !showManual { continue } else if installationReason == bpmlib.InstallationReasonDependency && !showDepends { @@ -346,7 +368,7 @@ func showPackageList() { continue } - fmt.Println(pkg.PkgInfo.Name) + fmt.Println(pkg.pkgInfo.Name) } } } else { @@ -366,13 +388,8 @@ func showPackageList() { fmt.Println("No packages have been installed") return } - for n, bpmpkg := range installedPackages { - if bpmpkg == nil { - fmt.Printf("Package (%s) could not be found\n", installedPackageNames[n]) - continue - } - - installationReason := bpmlib.GetInstallationReason(bpmpkg.PkgInfo.Name, rootDir) + for n, pkg := range installedPackages { + installationReason := bpmlib.GetInstallationReason(pkg.pkgInfo.Name, rootDir) if installationReason == bpmlib.InstallationReasonManual && !showManual { continue } else if installationReason == bpmlib.InstallationReasonDependency && !showDepends { @@ -386,7 +403,15 @@ func showPackageList() { if n != 0 { fmt.Println() } - fmt.Println(bpmpkg.CreateReadableInfo(rootDir, showHumanReadableSize)) + + fmt.Println(pkg.pkgInfo.CreateReadableInfo(rootDir)) + if pkg.pkgInfo.Type == "binary" { + if !showHumanReadableSize { + fmt.Printf("Installed size: %d\n", pkg.installedSize) + } else { + fmt.Printf("Installed size: %s\n", bpmlib.BytesToHumanReadable(pkg.installedSize)) + } + } } } } diff --git a/src/bpmlib/databases.go b/src/bpmlib/databases.go index e120082..c02d059 100644 --- a/src/bpmlib/databases.go +++ b/src/bpmlib/databases.go @@ -403,7 +403,7 @@ func (entry *BPMDatabaseEntry) CreateReadableInfo(rootDir string, humanReadableS installedSize := entry.InstalledSize var installedSizeStr string if humanReadableSize { - installedSizeStr = bytesToHumanReadable(installedSize) + installedSizeStr = BytesToHumanReadable(installedSize) } else { installedSizeStr = strconv.FormatInt(installedSize, 10) } diff --git a/src/bpmlib/dependencies.go b/src/bpmlib/dependencies.go index 5e623c2..bb9195a 100644 --- a/src/bpmlib/dependencies.go +++ b/src/bpmlib/dependencies.go @@ -177,39 +177,33 @@ func resolvePackageDependenciesFromDatabase(resolved *[]pkgInstallationReason, u func (pkgInfo *PackageInfo) GetPackageDependants(rootDir string) (dependants []string) { // Get installed package names - pkgs, err := GetInstalledPackages(rootDir) - if err != nil { + pkgs, ok := localPackageInformation[rootDir] + if !ok { return nil } // Loop through all installed packages - for _, installedPkgName := range pkgs { - // Get installed BPM package - installedPkg := GetPackage(installedPkgName, rootDir) - if installedPkg == nil { - return nil - } - + for _, installedPkg := range pkgs { // Skip iteration if comparing the same packages - if installedPkg.PkgInfo.Name == pkgInfo.Name { + if installedPkg.Name == pkgInfo.Name { continue } // Add installed package to list if its dependencies include pkgName - if slices.ContainsFunc(installedPkg.PkgInfo.Depends, func(n string) bool { + if slices.ContainsFunc(installedPkg.Depends, func(n string) bool { return n == pkgInfo.Name }) { - dependants = append(dependants, installedPkgName) + dependants = append(dependants, installedPkg.Name) 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 { + if slices.ContainsFunc(installedPkg.Depends, func(n string) bool { return n == vpkg }) { - dependants = append(dependants, installedPkgName) + dependants = append(dependants, installedPkg.Name) break } } @@ -220,39 +214,33 @@ func (pkgInfo *PackageInfo) GetPackageDependants(rootDir string) (dependants []s func (pkgInfo *PackageInfo) GetPackageOptionalDependants(rootDir string) (dependants []string) { // Get installed package names - pkgs, err := GetInstalledPackages(rootDir) - if err != nil { + pkgs, ok := localPackageInformation[rootDir] + if !ok { return nil } // Loop through all installed packages - for _, installedPkgName := range pkgs { - // Get installed BPM package - installedPkg := GetPackage(installedPkgName, rootDir) - if installedPkg == nil { - return nil - } - + for _, installedPkg := range pkgs { // Skip iteration if comparing the same packages - if installedPkg.PkgInfo.Name == pkgInfo.Name { + if installedPkg.Name == pkgInfo.Name { continue } // Add installed package to list if its optional dependencies include pkgName - if slices.ContainsFunc(installedPkg.PkgInfo.OptionalDepends, func(n string) bool { + if slices.ContainsFunc(installedPkg.OptionalDepends, func(n string) bool { return n == pkgInfo.Name }) { - dependants = append(dependants, installedPkgName) + dependants = append(dependants, installedPkg.Name) continue } // Loop through each virtual package for _, vpkg := range pkgInfo.Provides { // Add installed package to list if its optional dependencies contain a provided virtual package - if slices.ContainsFunc(installedPkg.PkgInfo.OptionalDepends, func(n string) bool { + if slices.ContainsFunc(installedPkg.OptionalDepends, func(n string) bool { return n == vpkg }) { - dependants = append(dependants, installedPkgName) + dependants = append(dependants, installedPkg.Name) break } } diff --git a/src/bpmlib/operations.go b/src/bpmlib/operations.go index 0706109..c4824f3 100644 --- a/src/bpmlib/operations.go +++ b/src/bpmlib/operations.go @@ -429,12 +429,12 @@ func (operation *BPMOperation) ShowOperationSummary() { fmt.Println("Warning: Operating in " + operation.RootDir) } if operation.GetTotalDownloadSize() > 0 { - fmt.Printf("%s will be downloaded to complete this operation\n", bytesToHumanReadable(operation.GetTotalDownloadSize())) + fmt.Printf("%s will be downloaded to complete this operation\n", BytesToHumanReadable(operation.GetTotalDownloadSize())) } if operation.GetFinalActionSize(operation.RootDir) > 0 { - fmt.Printf("A total of %s will be installed after the operation finishes\n", bytesToHumanReadable(operation.GetFinalActionSize(operation.RootDir))) + fmt.Printf("A total of %s will be installed after the operation finishes\n", BytesToHumanReadable(operation.GetFinalActionSize(operation.RootDir))) } else if operation.GetFinalActionSize(operation.RootDir) < 0 { - fmt.Printf("A total of %s will be freed after the operation finishes\n", strings.TrimPrefix(bytesToHumanReadable(operation.GetFinalActionSize(operation.RootDir)), "-")) + fmt.Printf("A total of %s will be freed after the operation finishes\n", strings.TrimPrefix(BytesToHumanReadable(operation.GetFinalActionSize(operation.RootDir)), "-")) } } diff --git a/src/bpmlib/packages.go b/src/bpmlib/packages.go index 13d9a89..af3634c 100644 --- a/src/bpmlib/packages.go +++ b/src/bpmlib/packages.go @@ -536,60 +536,57 @@ func ReadPackageInfo(contents string) (*PackageInfo, error) { return pkgInfo, nil } -func (bpmpkg *BPMPackage) CreateReadableInfo(rootDir string, humanReadableSize bool) string { +func (pkgInfo *PackageInfo) CreateReadableInfo(rootDir string) string { ret := make([]string, 0) appendArray := func(label string, array []string) { if len(array) == 0 { return } - // Sort array - slices.Sort(array) - ret = append(ret, fmt.Sprintf("%s: %s", label, strings.Join(array, ", "))) } - ret = append(ret, "Name: "+bpmpkg.PkgInfo.Name) - ret = append(ret, "Description: "+bpmpkg.PkgInfo.Description) - ret = append(ret, "Version: "+bpmpkg.PkgInfo.GetFullVersion()) - if bpmpkg.PkgInfo.Url != "" { - ret = append(ret, "URL: "+bpmpkg.PkgInfo.Url) + ret = append(ret, "Name: "+pkgInfo.Name) + ret = append(ret, "Description: "+pkgInfo.Description) + ret = append(ret, "Version: "+pkgInfo.GetFullVersion()) + if pkgInfo.Url != "" { + ret = append(ret, "URL: "+pkgInfo.Url) } - if bpmpkg.PkgInfo.License != "" { - ret = append(ret, "License: "+bpmpkg.PkgInfo.License) + if pkgInfo.License != "" { + ret = append(ret, "License: "+pkgInfo.License) } - ret = append(ret, "Architecture: "+bpmpkg.PkgInfo.Arch) - if bpmpkg.PkgInfo.Type == "source" && bpmpkg.PkgInfo.OutputArch != "" && bpmpkg.PkgInfo.OutputArch != GetArch() { - ret = append(ret, "Output architecture: "+bpmpkg.PkgInfo.Arch) + ret = append(ret, "Architecture: "+pkgInfo.Arch) + if pkgInfo.Type == "source" && pkgInfo.OutputArch != "" && pkgInfo.OutputArch != GetArch() { + ret = append(ret, "Output architecture: "+pkgInfo.Arch) } - ret = append(ret, "Type: "+bpmpkg.PkgInfo.Type) - appendArray("Dependencies", bpmpkg.PkgInfo.Depends) - if bpmpkg.PkgInfo.Type == "source" { - appendArray("Make Dependencies", bpmpkg.PkgInfo.MakeDepends) + ret = append(ret, "Type: "+pkgInfo.Type) + appendArray("Dependencies", pkgInfo.Depends) + if pkgInfo.Type == "source" { + appendArray("Make Dependencies", pkgInfo.MakeDepends) } - appendArray("Optional dependencies", bpmpkg.PkgInfo.OptionalDepends) - dependants := bpmpkg.PkgInfo.GetPackageDependants(rootDir) + appendArray("Optional dependencies", pkgInfo.OptionalDepends) + dependants := pkgInfo.GetPackageDependants(rootDir) if len(dependants) > 0 { appendArray("Dependant packages", dependants) } - optionalDependants := bpmpkg.PkgInfo.GetPackageOptionalDependants(rootDir) + optionalDependants := pkgInfo.GetPackageOptionalDependants(rootDir) if len(optionalDependants) > 0 { appendArray("Optionally dependant packages", optionalDependants) } - appendArray("Conflicting packages", bpmpkg.PkgInfo.Conflicts) - appendArray("Provided packages", bpmpkg.PkgInfo.Provides) - appendArray("Replaces packages", bpmpkg.PkgInfo.Replaces) + appendArray("Conflicting packages", pkgInfo.Conflicts) + appendArray("Provided packages", pkgInfo.Provides) + appendArray("Replaces packages", pkgInfo.Replaces) - if bpmpkg.PkgInfo.Type == "source" && len(bpmpkg.PkgInfo.SplitPackages) != 0 { - splitPkgs := make([]string, len(bpmpkg.PkgInfo.SplitPackages)) - for i, splitPkgInfo := range bpmpkg.PkgInfo.SplitPackages { + if pkgInfo.Type == "source" && len(pkgInfo.SplitPackages) != 0 { + splitPkgs := make([]string, len(pkgInfo.SplitPackages)) + for i, splitPkgInfo := range pkgInfo.SplitPackages { splitPkgs[i] = splitPkgInfo.Name } appendArray("Split Packages", splitPkgs) } - if rootDir != "" && IsPackageInstalled(bpmpkg.PkgInfo.Name, rootDir) { - installationReason := GetInstallationReason(bpmpkg.PkgInfo.Name, rootDir) + if rootDir != "" && IsPackageInstalled(pkgInfo.Name, rootDir) { + installationReason := GetInstallationReason(pkgInfo.Name, rootDir) var installationReasonString string switch installationReason { case InstallationReasonManual: @@ -603,16 +600,7 @@ func (bpmpkg *BPMPackage) CreateReadableInfo(rootDir string, humanReadableSize b } ret = append(ret, "Installation Reason: "+installationReasonString) } - if bpmpkg.PkgInfo.Type == "binary" { - installedSize := bpmpkg.GetInstalledSize() - var installedSizeStr string - if humanReadableSize { - installedSizeStr = bytesToHumanReadable(installedSize) - } else { - installedSizeStr = strconv.FormatInt(installedSize, 10) - } - ret = append(ret, "Installed size: "+installedSizeStr) - } + return strings.Join(ret, "\n") } diff --git a/src/bpmlib/utils.go b/src/bpmlib/utils.go index 7b96095..b8f2ee4 100644 --- a/src/bpmlib/utils.go +++ b/src/bpmlib/utils.go @@ -119,7 +119,7 @@ func stringSliceRemove(s []string, r string) []string { return s } -func bytesToHumanReadable(b int64) string { +func BytesToHumanReadable(b int64) string { bf := float64(b) for _, unit := range []string{"", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi"} { if math.Abs(bf) < 1024.0 {