Move installation reason to package local info

This commit is contained in:
2026-02-04 14:48:52 +02:00
parent e4d94e378f
commit ee80640153
6 changed files with 235 additions and 67 deletions
+82 -5
View File
@@ -177,6 +177,18 @@ func main() {
setupFlagsAndHelp(currentFlagSet, fmt.Sprintf("bpm %s <options>", subcommand), "Compare two version numbers", os.Args[2:])
compareVersions()
case "upgrade-persistent-data":
currentFlagSet = flag.NewFlagSet("upgrade-persistent-data", flag.ExitOnError)
currentFlagSet.StringP("root", "R", "/", "Operate on specified root directory")
setupFlagsAndHelp(currentFlagSet, fmt.Sprintf("bpm %s <options>", subcommand), "Upgrade BPM's persistent data directory contents", os.Args[2:])
rootDir, _ := currentFlagSet.GetString("root")
err = bpmlib.UpgradePersistentData(rootDir)
if err != nil {
log.Printf("Error: could not upgrade persistent data directory: %s", err)
exitCode = 1
return
}
default:
printUsage()
exitCode = 1
@@ -193,6 +205,14 @@ func showPackageInfo() {
showDatabaseInfo, _ := currentFlagSet.GetBool("database")
showHumanReadableSize, _ := currentFlagSet.GetBool("human-readable")
// Initialize installed packages map
err := bpmlib.InitializeLocalPackageInformation(rootDir)
if err != nil {
log.Printf("Error: %s", err)
exitCode = 1
return
}
// Get packages
packages := currentFlagSet.Args()
if len(packages) == 0 {
@@ -201,7 +221,7 @@ func showPackageInfo() {
}
// Read local databases
err := bpmlib.ReadLocalDatabaseFiles()
err = bpmlib.ReadLocalDatabaseFiles()
if err != nil {
log.Printf("Error: could not read local databases: %s", err)
exitCode = 1
@@ -301,8 +321,16 @@ func showPackageList() {
showMakeDepends = true
}
// Initialize installed packages map
err := bpmlib.InitializeLocalPackageInformation(rootDir)
if err != nil {
log.Printf("Error: %s", err)
exitCode = 1
return
}
// Read local databases
err := bpmlib.ReadLocalDatabaseFiles()
err = bpmlib.ReadLocalDatabaseFiles()
if err != nil {
log.Printf("Error: could not read local databases: %s", err)
exitCode = 1
@@ -374,7 +402,7 @@ func showPackageList() {
}
} else {
for _, pkg := range installedPackages {
installationReason := bpmlib.GetInstallationReason(pkg.pkgInfo.Name, rootDir)
installationReason := bpmlib.GetPackage(pkg.pkgInfo.Name, rootDir).LocalInfo.GetInstallationReason()
if installationReason == bpmlib.InstallationReasonManual && !showManual {
continue
} else if installationReason == bpmlib.InstallationReasonDependency && !showDepends {
@@ -406,7 +434,7 @@ func showPackageList() {
return
}
for n, pkg := range installedPackages {
installationReason := bpmlib.GetInstallationReason(pkg.pkgInfo.Name, rootDir)
installationReason := bpmlib.GetPackage(pkg.pkgInfo.Name, rootDir).LocalInfo.GetInstallationReason()
if installationReason == bpmlib.InstallationReasonManual && !showManual {
continue
} else if installationReason == bpmlib.InstallationReasonDependency && !showDepends {
@@ -560,6 +588,14 @@ func installPackages() {
}
defer fileLock.Unlock()
// Initialize installed packages map
err = bpmlib.InitializeLocalPackageInformation(rootDir)
if err != nil {
log.Printf("Error: %s", err)
exitCode = 1
return
}
// Read local databases
err = bpmlib.ReadLocalDatabaseFiles()
if err != nil {
@@ -693,6 +729,14 @@ func removePackages() {
}
defer fileLock.Unlock()
// Initialize installed packages map
err = bpmlib.InitializeLocalPackageInformation(rootDir)
if err != nil {
log.Printf("Error: %s", err)
exitCode = 1
return
}
// Read local databases
err = bpmlib.ReadLocalDatabaseFiles()
if err != nil {
@@ -806,6 +850,14 @@ func doCleanup() {
}
defer fileLock.Unlock()
// Initialize installed packages map
err = bpmlib.InitializeLocalPackageInformation(rootDir)
if err != nil {
log.Printf("Error: %s", err)
exitCode = 1
return
}
err = bpmlib.CleanupCache(rootDir, cleanupCompilationFiles, cleanupBinaryPackages, cleanupFetchedPackages, verbose)
if err != nil {
log.Printf("Error: could not complete cache cleanup: %s", err)
@@ -946,6 +998,14 @@ func updatePackages() {
}
defer fileLock.Unlock()
// Initialize installed packages map
err = bpmlib.InitializeLocalPackageInformation(rootDir)
if err != nil {
log.Printf("Error: %s", err)
exitCode = 1
return
}
// Read local databases if no sync
if noSync {
err := bpmlib.ReadLocalDatabaseFiles()
@@ -1067,6 +1127,14 @@ func getFileOwner() {
// Get flags
rootDir, _ := currentFlagSet.GetString("root")
// Initialize installed packages map
err := bpmlib.InitializeLocalPackageInformation(rootDir)
if err != nil {
log.Printf("Error: %s", err)
exitCode = 1
return
}
// Get files
files := currentFlagSet.Args()
if len(files) == 0 {
@@ -1160,6 +1228,14 @@ func compilePackage() {
outputFd, _ := currentFlagSet.GetInt("output-fd")
compilationJobs, _ := currentFlagSet.GetInt("jobs")
// Initialize installed packages map
err := bpmlib.InitializeLocalPackageInformation(rootDir)
if err != nil {
log.Printf("Error: %s", err)
exitCode = 1
return
}
// Get files
sourcePackages := currentFlagSet.Args()
if len(sourcePackages) == 0 {
@@ -1168,7 +1244,7 @@ func compilePackage() {
}
// Read local databases
err := bpmlib.ReadLocalDatabaseFiles()
err = bpmlib.ReadLocalDatabaseFiles()
if err != nil {
log.Printf("Error: could not read local databases: %s", err)
exitCode = 1
@@ -1409,6 +1485,7 @@ func printUsage() {
fmt.Println(" o, owner Show what packages own the specified paths")
fmt.Println(" c, compile Compile source packages and convert them to binary ones")
fmt.Println(" p, vercmp Compare package version numbers")
}
func setupFlagsAndHelp(flagset *flag.FlagSet, usage, desc string, args []string) {
+1 -1
View File
@@ -398,7 +398,7 @@ func (entry *BPMDatabaseEntry) CreateReadableInfo(rootDir string, humanReadableS
// Installation reason
if rootDir != "" && IsPackageInstalled(entry.Info.Name, rootDir) {
installationReason := GetInstallationReason(entry.Info.Name, rootDir)
installationReason := GetPackage(entry.Info.Name, rootDir).LocalInfo.GetInstallationReason()
var installationReasonString string
switch installationReason {
case InstallationReasonManual:
+4 -4
View File
@@ -53,7 +53,7 @@ func InstallPackages(rootDir string, forceInstallationReason InstallationReason,
installationReason := forceInstallationReason
if installationReason == InstallationReasonUnknown {
if IsPackageInstalled(splitPkg.Name, rootDir) {
installationReason = GetInstallationReason(splitPkg.Name, rootDir)
installationReason = GetPackage(splitPkg.Name, rootDir).LocalInfo.GetInstallationReason()
} else {
installationReason = InstallationReasonManual
}
@@ -77,7 +77,7 @@ func InstallPackages(rootDir string, forceInstallationReason InstallationReason,
installationReason := forceInstallationReason
if installationReason == InstallationReasonUnknown {
if IsPackageInstalled(bpmpkg.PkgInfo.Name, rootDir) {
installationReason = GetInstallationReason(bpmpkg.PkgInfo.Name, rootDir)
installationReason = GetPackage(bpmpkg.PkgInfo.Name, rootDir).LocalInfo.GetInstallationReason()
} else {
installationReason = InstallationReasonManual
}
@@ -113,7 +113,7 @@ func InstallPackages(rootDir string, forceInstallationReason InstallationReason,
installationReason := forceInstallationReason
if installationReason == InstallationReasonUnknown {
if IsPackageInstalled(entry.Info.Name, rootDir) {
installationReason = GetInstallationReason(entry.Info.Name, rootDir)
installationReason = GetPackage(entry.Info.Name, rootDir).LocalInfo.GetInstallationReason()
} else {
installationReason = InstallationReasonManual
}
@@ -423,7 +423,7 @@ func UpdatePackages(rootDir string, syncDatabase bool, allowDowngrades bool, ins
comparison := CompareVersions(entry.Info.GetFullVersion(), installedInfo.GetFullVersion())
if (!allowDowngrades && comparison > 0) || (allowDowngrades && comparison != 0) {
operation.AppendAction(&FetchPackageAction{
InstallationReason: GetInstallationReason(pkg, rootDir),
InstallationReason: GetPackage(pkg, rootDir).LocalInfo.GetInstallationReason(),
DatabaseEntry: entry,
})
}
+126 -9
View File
@@ -11,9 +11,11 @@ import (
"gopkg.in/yaml.v3"
)
var persistentDataVersion int = 1
var localPackageInformation map[string]map[string]*PackageInfo = make(map[string]map[string]*PackageInfo)
func initializeLocalPackageInformation(rootDir string) (err error) {
func InitializeLocalPackageInformation(rootDir string) (err error) {
// Return if information is already initialized
if _, ok := localPackageInformation[rootDir]; ok {
return nil
@@ -21,8 +23,24 @@ func initializeLocalPackageInformation(rootDir string) (err error) {
tempPackageInformation := make(map[string]*PackageInfo)
// Get path to installed package information directory
installedDir := path.Join(rootDir, "var/lib/bpm/installed/")
// Get paths
persistentDataDir := path.Join(rootDir, "var/lib/bpm")
installedDir := path.Join(persistentDataDir, "installed")
// Ensure persistent data directory is up-to-date
if _, err := os.Stat(persistentDataDir); err == nil {
data, err := os.ReadFile(path.Join(persistentDataDir, ".version"))
if err != nil {
return fmt.Errorf("persistent data is not up-to-date! Please run 'bpm upgrade-persistent-data' first")
}
currentPersistentDataVersion, err := strconv.Atoi(strings.TrimSpace(string(data)))
if err != nil {
return fmt.Errorf("persistent data is not up-to-date! Please run 'bpm upgrade-persistent-data' first")
}
if currentPersistentDataVersion != persistentDataVersion {
return fmt.Errorf("persistent data is not up-to-date! Please run 'bpm upgrade-persistent-data' first")
}
}
// Get directory content
items, err := os.ReadDir(installedDir)
@@ -61,7 +79,7 @@ func initializeLocalPackageInformation(rootDir string) (err error) {
func GetInstalledPackages(rootDir string) (ret []string, err error) {
// Initialize local package information
err = initializeLocalPackageInformation(rootDir)
err = InitializeLocalPackageInformation(rootDir)
if err != nil {
return nil, err
}
@@ -79,7 +97,7 @@ func GetInstalledPackages(rootDir string) (ret []string, err error) {
func IsPackageInstalled(pkg, rootDir string) bool {
// Initialize local package information
err := initializeLocalPackageInformation(rootDir)
err := InitializeLocalPackageInformation(rootDir)
if err != nil {
return false
}
@@ -131,7 +149,7 @@ func IsPackageProvided(pkg, rootDir string) bool {
}
func GetPackageInfo(pkg string, rootDir string) *PackageInfo {
err := initializeLocalPackageInformation(rootDir)
err := InitializeLocalPackageInformation(rootDir)
if err != nil {
return nil
}
@@ -244,13 +262,13 @@ func getPackageLocalInfo(pkg, rootDir string) PackageLocalInfo {
installedDir := path.Join(rootDir, "var/lib/bpm/installed/")
pkgDir := path.Join(installedDir, pkg)
files := path.Join(pkgDir, "local")
localInfoFile := path.Join(path.Join(pkgDir, "local"))
if _, err := os.Stat(files); os.IsNotExist(err) {
if _, err := os.Stat(localInfoFile); os.IsNotExist(err) {
return localInfo
}
file, err := os.Open(files)
file, err := os.Open(localInfoFile)
if err != nil {
return localInfo
}
@@ -263,3 +281,102 @@ func getPackageLocalInfo(pkg, rootDir string) PackageLocalInfo {
return localInfo
}
func SetPackageLocalInfo(pkg string, localInfo PackageLocalInfo, rootDir string) error {
installedDir := path.Join(rootDir, "var/lib/bpm/installed/")
pkgDir := path.Join(installedDir, pkg)
localFile, err := os.OpenFile(path.Join(pkgDir, "local"), os.O_WRONLY|os.O_CREATE, 0644)
if err != nil {
return err
}
defer localFile.Close()
err = yaml.NewEncoder(localFile).Encode(localInfo)
if err != nil {
return err
}
return nil
}
func UpgradePersistentData(rootDir string) error {
persistentDataDir := path.Join(rootDir, "var/lib/bpm")
// Create persistent data directory
os.MkdirAll(persistentDataDir, 0755)
// Upgrade installed package directories
dirEntries, err := os.ReadDir(path.Join(persistentDataDir, "installed"))
if err != nil && !os.IsNotExist(err) {
return err
} else if err == nil {
for _, entry := range dirEntries {
pkgDir := path.Join(persistentDataDir, "installed", entry.Name())
// Generate default local package information file
if _, err := os.Stat(path.Join(pkgDir, "local")); err != nil && !os.IsNotExist(err) {
return err
} else if os.IsNotExist(err) {
fmt.Printf("Generating local package information for package (%s)\n", entry.Name())
out, err := yaml.Marshal(PackageLocalInfo{
InstallationReason: "unknown",
InstalledOn: 0,
LastUpdatedOn: 0,
})
if err != nil {
return err
}
err = os.WriteFile(path.Join(pkgDir, "local"), out, 0644)
if err != nil {
return err
}
}
// Move installation reason to local package information file
if installationReason, err := os.ReadFile(path.Join(pkgDir, "installation_reason")); err != nil && !os.IsNotExist(err) {
return err
} else if err == nil {
fmt.Printf("Moving installation reason to local package information for package (%s)\n", entry.Name())
data, err := os.ReadFile(path.Join(pkgDir, "local"))
if err != nil {
return err
}
localInfo := &PackageLocalInfo{}
err = yaml.Unmarshal(data, localInfo)
if err != nil {
return err
}
localInfo.InstallationReason = strings.TrimSpace(string(installationReason))
out, err := yaml.Marshal(localInfo)
if err != nil {
return err
}
err = os.WriteFile(path.Join(pkgDir, "local"), out, 0644)
if err != nil {
return err
}
err = os.Remove(path.Join(pkgDir, "installation_reason"))
if err != nil {
return err
}
}
}
}
// Set persistent data version number
err = os.WriteFile(path.Join(persistentDataDir, ".version"), []byte(strconv.Itoa(persistentDataVersion)), 0644)
if err != nil {
return err
}
return nil
}
+3 -9
View File
@@ -223,7 +223,7 @@ func (operation *BPMOperation) Cleanup(cleanupMakeDepends bool) error {
// Get manually installed packages, resolve all their dependencies and add them to the keepPackages slice
keepPackages := make([]string, 0)
for _, pkg := range slices.Clone(installedPackages) {
if GetInstallationReason(pkg.Name, operation.RootDir) != InstallationReasonManual {
if getPackageLocalInfo(pkg.Name, operation.RootDir).GetInstallationReason() != InstallationReasonManual {
continue
}
@@ -701,19 +701,13 @@ func (operation *BPMOperation) Execute(verbose, force bool) (err error) {
}
if value.InstallationReason != InstallationReasonManual {
err = installPackage(fileToInstall, operation.RootDir, verbose, true)
err = installPackage(fileToInstall, value.InstallationReason, operation.RootDir, verbose, true)
} else {
err = installPackage(fileToInstall, operation.RootDir, verbose, force)
err = installPackage(fileToInstall, value.InstallationReason, operation.RootDir, verbose, force)
}
if err != nil {
return fmt.Errorf("could not install package (%s): %s\n", bpmpkg.PkgInfo.Name, err)
}
// Set installed package's installation reason
err = SetInstallationReason(bpmpkg.PkgInfo.Name, value.InstallationReason, operation.RootDir)
if err != nil {
return fmt.Errorf("could not set installation reason for package (%s): %s\n", value.BpmPackage.PkgInfo.Name, err)
}
}
}
fmt.Println("Operation complete!")
+17 -37
View File
@@ -78,6 +78,7 @@ type PackageFileEntry struct {
}
type PackageLocalInfo struct {
InstallationReason string `yaml:"installation_reason"`
InstalledOn int64 `yaml:"installed_on"`
LastUpdatedOn int64 `yaml:"last_updated_on"`
}
@@ -130,19 +131,8 @@ const (
InstallationReasonUnknown InstallationReason = "unknown"
)
func GetInstallationReason(pkg, rootDir string) InstallationReason {
installedDir := path.Join(rootDir, "var/lib/bpm/installed/")
pkgDir := path.Join(installedDir, pkg)
if stat, err := os.Stat(path.Join(pkgDir, "installation_reason")); err != nil || stat.IsDir() {
return InstallationReasonManual
}
b, err := os.ReadFile(path.Join(pkgDir, "installation_reason"))
if err != nil {
return InstallationReasonUnknown
}
reason := strings.TrimSpace(string(b))
switch reason {
func (localInfo PackageLocalInfo) GetInstallationReason() InstallationReason {
switch localInfo.InstallationReason {
case "manual":
return InstallationReasonManual
case "dependency":
@@ -154,16 +144,6 @@ func GetInstallationReason(pkg, rootDir string) InstallationReason {
}
}
func SetInstallationReason(pkg string, reason InstallationReason, rootDir string) error {
installedDir := path.Join(rootDir, "var/lib/bpm/installed/")
pkgDir := path.Join(installedDir, pkg)
err := os.WriteFile(path.Join(pkgDir, "installation_reason"), []byte(reason), 0644)
if err != nil {
return err
}
return nil
}
func GetPackageInfoRaw(filename string) (string, error) {
if _, err := os.Stat(filename); os.IsNotExist(err) {
return "", err
@@ -623,7 +603,7 @@ func (pkgInfo *PackageInfo) CreateReadableInfo(rootDir string) string {
// Installation reason
if rootDir != "" && IsPackageInstalled(pkgInfo.Name, rootDir) {
installationReason := GetInstallationReason(pkgInfo.Name, rootDir)
installationReason := GetPackage(pkgInfo.Name, rootDir).LocalInfo.GetInstallationReason()
var installationReasonString string
switch installationReason {
case InstallationReasonManual:
@@ -802,7 +782,7 @@ func extractPackage(bpmpkg *BPMPackage, verbose bool, filename, rootDir string)
return nil
}
func installPackage(filename, rootDir string, verbose, force bool) error {
func installPackage(filename string, installationReason InstallationReason, rootDir string, verbose, force bool) error {
if _, err := os.Stat(filename); os.IsNotExist(err) {
return err
}
@@ -992,17 +972,9 @@ func installPackage(filename, rootDir string, verbose, force bool) error {
localInfo.InstalledOn = time.Now().Unix()
}
localInfo.LastUpdatedOn = time.Now().Unix()
localInfo.InstallationReason = string(installationReason)
localFile, err := os.OpenFile(path.Join(pkgDir, "local"), os.O_WRONLY|os.O_CREATE, 0644)
if err != nil {
return err
}
defer localFile.Close()
err = yaml.NewEncoder(localFile).Encode(localInfo)
if err != nil {
return err
}
SetPackageLocalInfo(bpmpkg.PkgInfo.Name, localInfo, rootDir)
// Save remove package scripts
packageScripts, err := ReadPackageScripts(filename)
@@ -1043,8 +1015,16 @@ func installPackage(filename, rootDir string, verbose, force bool) error {
}
}
// Write persistent data version number
if _, err := os.Stat(path.Join(rootDir, "var/lib/bpm/.version")); err != nil {
err = os.WriteFile(path.Join(rootDir, "var/lib/bpm/.version"), []byte(strconv.Itoa(persistentDataVersion)), 0644)
if err != nil {
return err
}
}
// Ensure local package information has been initialized for rootDir
err = initializeLocalPackageInformation(rootDir)
err = InitializeLocalPackageInformation(rootDir)
if err != nil {
return err
}
@@ -1164,7 +1144,7 @@ func removePackage(pkg string, verbose bool, rootDir string) error {
}
// Ensure local package information has been initialized for rootDir
err = initializeLocalPackageInformation(rootDir)
err = InitializeLocalPackageInformation(rootDir)
if err != nil {
return err
}