13 Commits
10 changed files with 367 additions and 122 deletions
+2 -1
View File
@@ -6,7 +6,7 @@ toolchain go1.23.7
require ( require (
git.enumerated.dev/bubble-package-manager/bpm/src/bpmlib v0.5.0 git.enumerated.dev/bubble-package-manager/bpm/src/bpmlib v0.5.0
github.com/adrg/strutil v0.3.1 github.com/lithammer/fuzzysearch v1.1.8
github.com/spf13/pflag v1.0.10 github.com/spf13/pflag v1.0.10
) )
@@ -15,5 +15,6 @@ replace git.enumerated.dev/bubble-package-manager/bpm/src/bpmlib => ../bpmlib
require ( require (
github.com/drone/envsubst v1.0.3 // indirect github.com/drone/envsubst v1.0.3 // indirect
github.com/knqyf263/go-rpm-version v0.0.0-20240918084003-2afd7dc6a38f // indirect github.com/knqyf263/go-rpm-version v0.0.0-20240918084003-2afd7dc6a38f // indirect
golang.org/x/text v0.9.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
) )
+34 -15
View File
@@ -1,27 +1,46 @@
github.com/adrg/strutil v0.3.1 h1:OLvSS7CSJO8lBii4YmBt8jiK9QOtB9CzCzwl4Ic/Fz4=
github.com/adrg/strutil v0.3.1/go.mod h1:8h90y18QLrs11IBffcGX3NW/GFBXCMcNg4M7H6MspPA=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/drone/envsubst v1.0.3 h1:PCIBwNDYjs50AsLZPYdfhSATKaRg/FJmDc2D6+C2x8g= github.com/drone/envsubst v1.0.3 h1:PCIBwNDYjs50AsLZPYdfhSATKaRg/FJmDc2D6+C2x8g=
github.com/drone/envsubst v1.0.3/go.mod h1:N2jZmlMufstn1KEqvbHjw40h1KyTmnVzHcSc9bFiJ2g= github.com/drone/envsubst v1.0.3/go.mod h1:N2jZmlMufstn1KEqvbHjw40h1KyTmnVzHcSc9bFiJ2g=
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ= github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/knqyf263/go-rpm-version v0.0.0-20240918084003-2afd7dc6a38f h1:xt29M2T6STgldg+WEP51gGePQCsQvklmP2eIhPIBK3g= github.com/knqyf263/go-rpm-version v0.0.0-20240918084003-2afd7dc6a38f h1:xt29M2T6STgldg+WEP51gGePQCsQvklmP2eIhPIBK3g=
github.com/knqyf263/go-rpm-version v0.0.0-20240918084003-2afd7dc6a38f/go.mod h1:i4sF0l1fFnY1aiw08QQSwVAFxHEm311Me3WsU/X7nL0= github.com/knqyf263/go-rpm-version v0.0.0-20240918084003-2afd7dc6a38f/go.mod h1:i4sF0l1fFnY1aiw08QQSwVAFxHEm311Me3WsU/X7nL0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/lithammer/fuzzysearch v1.1.8 h1:/HIuJnjHuXS8bKaiTMeeDlW2/AyIWk2brx1V8LFgLN4=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/lithammer/fuzzysearch v1.1.8/go.mod h1:IdqeyBClc3FFqSzYq/MXESsS4S0FsZ5ajtkr5xPLts4=
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+146 -46
View File
@@ -16,8 +16,7 @@ import (
"git.enumerated.dev/bubble-package-manager/bpm/src/bpmlib" "git.enumerated.dev/bubble-package-manager/bpm/src/bpmlib"
"github.com/adrg/strutil" "github.com/lithammer/fuzzysearch/fuzzy"
"github.com/adrg/strutil/metrics"
flag "github.com/spf13/pflag" flag "github.com/spf13/pflag"
) )
@@ -26,7 +25,7 @@ import (
/* A simple-to-use package manager */ /* A simple-to-use package manager */
/* ------------------------------------------------------- */ /* ------------------------------------------------------- */
var bpmVer = "0.6.0" var bpmVer = "0.6.1"
var currentFlagSet *flag.FlagSet var currentFlagSet *flag.FlagSet
@@ -45,7 +44,7 @@ func main() {
} }
switch subcommand { switch subcommand {
case "version": case "v", "version":
fmt.Println("Bubble Package Manager (BPM)") fmt.Println("Bubble Package Manager (BPM)")
fmt.Println("Version: " + bpmVer) fmt.Println("Version: " + bpmVer)
case "q", "query": case "q", "query":
@@ -53,6 +52,7 @@ func main() {
currentFlagSet = flag.NewFlagSet("query", flag.ExitOnError) currentFlagSet = flag.NewFlagSet("query", flag.ExitOnError)
currentFlagSet.StringP("root", "R", "/", "Operate on specified root directory") currentFlagSet.StringP("root", "R", "/", "Operate on specified root directory")
currentFlagSet.BoolP("database", "d", false, "Show package information from remote databases") currentFlagSet.BoolP("database", "d", false, "Show package information from remote databases")
currentFlagSet.BoolP("human-readable", "h", false, "Show package installed size in a human readable format")
setupFlagsAndHelp(currentFlagSet, fmt.Sprintf("bpm %s <options>", subcommand), "Show information on the specified packages", os.Args[2:]) setupFlagsAndHelp(currentFlagSet, fmt.Sprintf("bpm %s <options>", subcommand), "Show information on the specified packages", os.Args[2:])
showPackageInfo() showPackageInfo()
@@ -62,6 +62,13 @@ func main() {
currentFlagSet.StringP("root", "R", "/", "Operate on specified root directory") currentFlagSet.StringP("root", "R", "/", "Operate on specified root directory")
currentFlagSet.BoolP("count", "c", false, "Show total package count") currentFlagSet.BoolP("count", "c", false, "Show total package count")
currentFlagSet.BoolP("names", "n", false, "Show all package names") currentFlagSet.BoolP("names", "n", false, "Show all package names")
currentFlagSet.BoolP("database", "d", false, "Show packages from remote databases")
currentFlagSet.Bool("manual", false, "Show packages installed as dependencies")
currentFlagSet.Bool("depends", false, "Show packages installed as dependencies")
currentFlagSet.Bool("make-depends", false, "Show packages installed as make dependencies")
currentFlagSet.String("sort", "", "Sort listed packages by 'name' or 'size")
currentFlagSet.Bool("reverse", false, "Reverse the order in which packages are listed")
currentFlagSet.BoolP("human-readable", "h", false, "Show package installed size in a human readable format")
setupFlagsAndHelp(currentFlagSet, fmt.Sprintf("bpm %s <options>", subcommand), "List packages", os.Args[2:]) setupFlagsAndHelp(currentFlagSet, fmt.Sprintf("bpm %s <options>", subcommand), "List packages", os.Args[2:])
showPackageList() showPackageList()
@@ -149,6 +156,7 @@ func main() {
currentFlagSet.BoolP("yes", "y", false, "Enter 'yes' in all prompts") currentFlagSet.BoolP("yes", "y", false, "Enter 'yes' in all prompts")
currentFlagSet.BoolP("depends", "d", false, "Install required dependencies for package compilation") currentFlagSet.BoolP("depends", "d", false, "Install required dependencies for package compilation")
currentFlagSet.BoolP("skip-checks", "s", false, "Skip the check function in source.sh scripts") currentFlagSet.BoolP("skip-checks", "s", false, "Skip the check function in source.sh scripts")
currentFlagSet.BoolP("keep", "k", false, "Keep compilation files after successful package compilation")
currentFlagSet.BoolP("output-directory", "o", false, "Set the output directory for the binary packages") currentFlagSet.BoolP("output-directory", "o", false, "Set the output directory for the binary packages")
currentFlagSet.Int("output-fd", -1, "Set the file descriptor output package names will be written to") currentFlagSet.Int("output-fd", -1, "Set the file descriptor output package names will be written to")
setupFlagsAndHelp(currentFlagSet, fmt.Sprintf("bpm %s <options>", subcommand), "Compile source packages and convert them to binary ones", os.Args[2:]) setupFlagsAndHelp(currentFlagSet, fmt.Sprintf("bpm %s <options>", subcommand), "Compile source packages and convert them to binary ones", os.Args[2:])
@@ -167,6 +175,7 @@ func showPackageInfo() {
// Get flags // Get flags
rootDir, _ := currentFlagSet.GetString("root") rootDir, _ := currentFlagSet.GetString("root")
showDatabaseInfo, _ := currentFlagSet.GetBool("database") showDatabaseInfo, _ := currentFlagSet.GetBool("database")
showHumanReadableSize, _ := currentFlagSet.GetBool("human-readable")
// Get packages // Get packages
packages := currentFlagSet.Args() packages := currentFlagSet.Args()
@@ -184,9 +193,6 @@ func showPackageInfo() {
} }
for n, pkg := range packages { for n, pkg := range packages {
var info *bpmlib.PackageInfo
isFile := false
showInstallationReason := false
if showDatabaseInfo { if showDatabaseInfo {
var err error var err error
var entry *bpmlib.BPMDatabaseEntry var entry *bpmlib.BPMDatabaseEntry
@@ -198,25 +204,33 @@ func showPackageInfo() {
return return
} }
} }
info = entry.Info
} else if stat, err := os.Stat(pkg); err == nil && !stat.IsDir() { if n != 0 {
bpmpkg, err := bpmlib.ReadPackage(pkg) fmt.Println()
}
fmt.Println(entry.CreateReadableInfo(rootDir, showHumanReadableSize))
return
}
var bpmpkg *bpmlib.BPMPackage
isFile := false
if stat, err := os.Stat(pkg); err == nil && !stat.IsDir() {
bpmpkg, err = bpmlib.ReadPackage(pkg)
if err != nil { if err != nil {
log.Printf("Error: could not read package: %s\n", err) log.Printf("Error: could not read package: %s\n", err)
exitCode = 1 exitCode = 1
return return
} }
info = bpmpkg.PkgInfo
isFile = true isFile = true
} else { } else {
if isVirtual, p := bpmlib.IsVirtualPackage(pkg, rootDir); isVirtual { if isVirtual, p := bpmlib.IsVirtualPackage(pkg, rootDir); isVirtual {
info = bpmlib.GetPackageInfo(p, rootDir) bpmpkg = bpmlib.GetPackage(p, rootDir)
} else { } else {
info = bpmlib.GetPackageInfo(pkg, rootDir) bpmpkg = bpmlib.GetPackage(pkg, rootDir)
} }
showInstallationReason = true
} }
if info == nil { if bpmpkg == nil {
log.Printf("Error: package (%s) is not installed\n", pkg) log.Printf("Error: package (%s) is not installed\n", pkg)
exitCode = 1 exitCode = 1
return return
@@ -233,7 +247,7 @@ func showPackageInfo() {
} }
fmt.Println("File: " + abs) fmt.Println("File: " + abs)
} }
fmt.Println(bpmlib.CreateReadableInfo(true, true, true, showInstallationReason, info, rootDir)) fmt.Println(bpmpkg.CreateReadableInfo(rootDir, showHumanReadableSize))
} }
} }
@@ -242,6 +256,19 @@ func showPackageList() {
rootDir, _ := currentFlagSet.GetString("root") rootDir, _ := currentFlagSet.GetString("root")
showPkgCount, _ := currentFlagSet.GetBool("count") showPkgCount, _ := currentFlagSet.GetBool("count")
showPkgNames, _ := currentFlagSet.GetBool("names") showPkgNames, _ := currentFlagSet.GetBool("names")
showDatabase, _ := currentFlagSet.GetBool("database")
showManual, _ := currentFlagSet.GetBool("manual")
showDepends, _ := currentFlagSet.GetBool("depends")
showMakeDepends, _ := currentFlagSet.GetBool("make-depends")
sortPackages, _ := currentFlagSet.GetString("sort")
reversePackages, _ := currentFlagSet.GetBool("reverse")
showHumanReadableSize, _ := currentFlagSet.GetBool("human-readable")
if !isFlagSet(currentFlagSet, "manual") && !isFlagSet(currentFlagSet, "depends") && !isFlagSet(currentFlagSet, "make-depends") {
showManual = true
showDepends = true
showMakeDepends = true
}
// Read local databases // Read local databases
err := bpmlib.ReadLocalDatabaseFiles() err := bpmlib.ReadLocalDatabaseFiles()
@@ -251,33 +278,109 @@ func showPackageList() {
return return
} }
packages, err := bpmlib.GetInstalledPackages(rootDir) installedPackageNames, err := bpmlib.GetInstalledPackages(rootDir)
if err != nil { if err != nil {
log.Printf("Error: could not get installed packages: %s", err.Error()) log.Printf("Error: could not get installed packages: %s", err.Error())
exitCode = 1 exitCode = 1
return return
} }
installedPackages := make([]*bpmlib.BPMPackage, len(installedPackageNames))
for i, pkgName := range installedPackageNames {
installedPackages[i] = bpmlib.GetPackage(pkgName, rootDir)
}
databaseEntries := make([]*bpmlib.BPMDatabaseEntry, 0)
for _, db := range bpmlib.BPMDatabases {
databaseEntries = append(databaseEntries, slices.Collect(maps.Values(db.Entries))...)
}
switch sortPackages {
case "", "name":
case "size":
slices.SortFunc(installedPackages, func(a, b *bpmlib.BPMPackage) int {
return int(b.GetInstalledSize() - a.GetInstalledSize())
})
slices.SortFunc(databaseEntries, func(a, b *bpmlib.BPMDatabaseEntry) int {
return int(b.InstalledSize - a.InstalledSize)
})
default:
log.Printf("Error: cannot sort by '%s'", sortPackages)
exitCode = 1
return
}
if reversePackages {
slices.Reverse(installedPackages)
slices.Reverse(databaseEntries)
}
if showPkgCount { if showPkgCount {
fmt.Println(len(packages)) if showDatabase {
fmt.Println(len(databaseEntries))
} else {
fmt.Println(len(installedPackages))
}
} else if showPkgNames { } else if showPkgNames {
for _, pkg := range packages { if showDatabase {
fmt.Println(pkg) for _, entry := range databaseEntries {
fmt.Println(entry.Database.Name + "/" + entry.Info.Name)
}
} else {
for _, pkg := range installedPackages {
installationReason := bpmlib.GetInstallationReason(pkg.PkgInfo.Name, rootDir)
if installationReason == bpmlib.InstallationReasonManual && !showManual {
continue
} else if installationReason == bpmlib.InstallationReasonDependency && !showDepends {
continue
} else if installationReason == bpmlib.InstallationReasonMakeDependency && !showMakeDepends {
continue
} else if installationReason == bpmlib.InstallationReasonUnknown && (!showManual || !showDepends || !showMakeDepends) {
continue
}
fmt.Println(pkg.PkgInfo.Name)
}
} }
} else { } else {
if len(packages) == 0 { if showDatabase {
fmt.Println("No packages have been installed") if len(databaseEntries) == 0 {
return fmt.Println("There are no database entries available")
} return
for n, pkg := range packages {
info := bpmlib.GetPackageInfo(pkg, rootDir)
if info == nil {
fmt.Printf("Package (%s) could not be found\n", pkg)
continue
} }
if n != 0 { for n, entry := range databaseEntries {
fmt.Println() if n != 0 {
fmt.Println()
}
fmt.Println(entry.CreateReadableInfo(rootDir, showHumanReadableSize))
}
} else {
if len(installedPackages) == 0 {
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)
if installationReason == bpmlib.InstallationReasonManual && !showManual {
continue
} else if installationReason == bpmlib.InstallationReasonDependency && !showDepends {
continue
} else if installationReason == bpmlib.InstallationReasonMakeDependency && !showMakeDepends {
continue
} else if installationReason == bpmlib.InstallationReasonUnknown && (!showManual || !showDepends || !showMakeDepends) {
continue
}
if n != 0 {
fmt.Println()
}
fmt.Println(bpmpkg.CreateReadableInfo(rootDir, showHumanReadableSize))
} }
fmt.Println(bpmlib.CreateReadableInfo(true, true, true, true, info, rootDir))
} }
} }
} }
@@ -300,23 +403,19 @@ func searchForPackages() {
} }
for i, term := range searchTerms { for i, term := range searchTerms {
resultsMap := make(map[*bpmlib.PackageInfo]float64, 0) // Find matches
resultsMap := make(map[*bpmlib.BPMDatabaseEntry]int)
// Loop through all packages
for _, db := range bpmlib.BPMDatabases { for _, db := range bpmlib.BPMDatabases {
for _, entry := range db.Entries { for _, entry := range db.Entries {
// Calculate string similarity and add to map match := fuzzy.RankMatchNormalizedFold(term, entry.Info.Name)
similarity := strutil.Similarity(entry.Info.Name, term, metrics.NewSmithWatermanGotoh()) if match == -1 {
if similarity > 0.8 {
resultsMap[entry.Info] = similarity
continue continue
} }
similarity = strutil.Similarity(entry.Info.Description, term, metrics.NewSmithWatermanGotoh())
if similarity > 0.8 { resultsMap[entry] = match
resultsMap[entry.Info] = similarity
}
} }
} }
if len(resultsMap) == 0 { if len(resultsMap) == 0 {
log.Printf("Error: no results for term (%s) were found\n", term) log.Printf("Error: no results for term (%s) were found\n", term)
exitCode = 1 exitCode = 1
@@ -326,7 +425,7 @@ func searchForPackages() {
// Sort results // Sort results
results := slices.Collect(maps.Keys(resultsMap)) results := slices.Collect(maps.Keys(resultsMap))
sort.Slice(results, func(i, j int) bool { sort.Slice(results, func(i, j int) bool {
return resultsMap[results[i]] > resultsMap[results[j]] return resultsMap[results[i]] < resultsMap[results[j]]
}) })
// Print results // Print results
@@ -336,7 +435,7 @@ func searchForPackages() {
fmt.Printf("Results for term (%s)\n", term) fmt.Printf("Results for term (%s)\n", term)
for j := 0; j < 10 && j < len(results); j++ { for j := 0; j < 10 && j < len(results); j++ {
result := results[j] result := results[j]
fmt.Printf("%d) %s: %s (%s)\n", j+1, result.Name, result.Description, result.GetFullVersion()) fmt.Printf("%d) %s/%s: %s (%s)\n", j+1, result.Database.Name, result.Info.Name, result.Info.Description, result.Info.GetFullVersion())
} }
} }
} }
@@ -942,6 +1041,7 @@ func compilePackage() {
rootDir, _ := currentFlagSet.GetString("root") rootDir, _ := currentFlagSet.GetString("root")
verbose, _ := currentFlagSet.GetBool("verbose") verbose, _ := currentFlagSet.GetBool("verbose")
yesAll, _ := currentFlagSet.GetBool("yes") yesAll, _ := currentFlagSet.GetBool("yes")
keepCompilationFiles, _ := currentFlagSet.GetBool("keep")
installSrcPkgDepends, _ := currentFlagSet.GetBool("depends") installSrcPkgDepends, _ := currentFlagSet.GetBool("depends")
skipChecks, _ := currentFlagSet.GetBool("skip-checks") skipChecks, _ := currentFlagSet.GetBool("skip-checks")
outputDirectory, _ := currentFlagSet.GetString("output-directory") outputDirectory, _ := currentFlagSet.GetString("output-directory")
@@ -1139,7 +1239,7 @@ func compilePackage() {
return return
} }
outputBpmPackages, err := bpmlib.CompileSourcePackage(sourcePackage, outputDirectory, skipChecks) outputBpmPackages, err := bpmlib.CompileSourcePackage(sourcePackage, outputDirectory, skipChecks, keepCompilationFiles, verbose)
if err != nil { if err != nil {
// Remove unused packages // Remove unused packages
cleanupFunc() cleanupFunc()
+12 -4
View File
@@ -21,7 +21,7 @@ import (
var rootCompilationUID = "65534" var rootCompilationUID = "65534"
var rootCompilationGID = "65534" var rootCompilationGID = "65534"
func CompileSourcePackage(archiveFilename, outputDirectory string, skipChecks bool) (outputBpmPackages map[string]string, err error) { func CompileSourcePackage(archiveFilename, outputDirectory string, skipChecks, keepCompilationFiles, verbose bool) (outputBpmPackages map[string]string, err error) {
// Initialize map // Initialize map
outputBpmPackages = make(map[string]string) outputBpmPackages = make(map[string]string)
@@ -122,7 +122,7 @@ func CompileSourcePackage(archiveFilename, outputDirectory string, skipChecks bo
} }
// Download files // Download files
err = downloadPackageFiles(bpmpkg.PkgInfo, tempDirectory) err = downloadPackageFiles(bpmpkg.PkgInfo, tempDirectory, verbose)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -334,10 +334,15 @@ func CompileSourcePackage(archiveFilename, outputDirectory string, skipChecks bo
outputBpmPackages[pkgInfo.Name] = outputFilename outputBpmPackages[pkgInfo.Name] = outputFilename
} }
// Delete temporary directory
if !keepCompilationFiles {
os.RemoveAll(tempDirectory)
}
return outputBpmPackages, nil return outputBpmPackages, nil
} }
func downloadPackageFiles(pkgInfo *PackageInfo, tempDirectory string) error { func downloadPackageFiles(pkgInfo *PackageInfo, tempDirectory string, verbose bool) error {
for _, download := range pkgInfo.Downloads { for _, download := range pkgInfo.Downloads {
// Replace variables // Replace variables
replaceVars := func(s string) string { replaceVars := func(s string) string {
@@ -409,7 +414,10 @@ func downloadPackageFiles(pkgInfo *PackageInfo, tempDirectory string) error {
} }
if !download.NoExtract && (strings.Contains(filepath, ".tar") || strings.HasSuffix(filepath, ".tgz")) { if !download.NoExtract && (strings.Contains(filepath, ".tar") || strings.HasSuffix(filepath, ".tgz")) {
cmd := exec.Command("tar", "xvf", filepath, "--strip-components="+strconv.Itoa(download.ExtractStripComponents)) cmd := exec.Command("tar", "xf", filepath, "--strip-components="+strconv.Itoa(download.ExtractStripComponents))
if verbose {
cmd.Args[1] = "xvf"
}
cmd.Dir = tempDirectory cmd.Dir = tempDirectory
if extractTo != "" { if extractTo != "" {
err := os.MkdirAll(extractTo, 0755) err := os.MkdirAll(extractTo, 0755)
+112
View File
@@ -3,10 +3,12 @@ package bpmlib
import ( import (
"errors" "errors"
"fmt" "fmt"
"maps"
"net/url" "net/url"
"os" "os"
"path" "path"
"slices" "slices"
"strconv"
"strings" "strings"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
@@ -16,6 +18,7 @@ type BPMDatabase struct {
DatabaseVersion int `yaml:"database_version"` DatabaseVersion int `yaml:"database_version"`
Entries map[string]*BPMDatabaseEntry `yaml:"entries"` Entries map[string]*BPMDatabaseEntry `yaml:"entries"`
VirtualPackages map[string][]string VirtualPackages map[string][]string
Name string
Source string Source string
} }
@@ -54,6 +57,7 @@ func (db *configDatabase) ReadLocalDatabase() error {
// Initialize struct values // Initialize struct values
database.VirtualPackages = make(map[string][]string) database.VirtualPackages = make(map[string][]string)
database.Name = db.Name
database.Source = db.Source database.Source = db.Source
entriesToRemove := make([]string, 0) entriesToRemove := make([]string, 0)
@@ -247,3 +251,111 @@ func (db *BPMDatabase) FetchPackage(pkg string) (string, error) {
return path.Join("/var/cache/bpm/fetched/", path.Base(entry.Filepath)), nil return path.Join("/var/cache/bpm/fetched/", path.Base(entry.Filepath)), nil
} }
func (entry *BPMDatabaseEntry) GetEntryDependants() (dependants []string) {
dependantsMap := make(map[string][]string)
for _, db := range BPMDatabases {
for _, e := range db.Entries {
if slices.Contains(e.Info.Depends, entry.Info.Name) {
dependantsMap[e.Info.Name] = append(dependantsMap[e.Info.Name], e.Database.Name)
}
}
}
// Get keys
keySlice := slices.Collect(maps.Keys(dependantsMap))
slices.Sort(keySlice)
// Add all dependant entries to slice in alphabetical order
for _, entryName := range keySlice {
dbs := dependantsMap[entryName]
if len(dbs) > 1 {
for _, db := range dbs {
dependants = append(dependants, db+"/"+entryName)
}
} else {
dependants = append(dependants, entryName)
}
}
return dependants
}
func (entry *BPMDatabaseEntry) CreateReadableInfo(rootDir string, humanReadableSize bool) string {
ret := make([]string, 0)
appendArray := func(label string, array []string, sort bool) {
if len(array) == 0 {
return
}
if sort {
// Sort array
slices.Sort(array)
}
ret = append(ret, fmt.Sprintf("%s: %s", label, strings.Join(array, ", ")))
}
ret = append(ret, "Name: "+entry.Info.Name)
ret = append(ret, "Database: "+entry.Database.Name)
ret = append(ret, "Description: "+entry.Info.Description)
ret = append(ret, "Version: "+entry.Info.GetFullVersion())
if entry.Info.Url != "" {
ret = append(ret, "URL: "+entry.Info.Url)
}
if entry.Info.License != "" {
ret = append(ret, "License: "+entry.Info.License)
}
ret = append(ret, "Architecture: "+entry.Info.Arch)
if entry.Info.Type == "source" && entry.Info.OutputArch != "" && entry.Info.OutputArch != GetArch() {
ret = append(ret, "Output architecture: "+entry.Info.OutputArch)
}
ret = append(ret, "Type: "+entry.Info.Type)
appendArray("Dependencies", entry.Info.Depends, true)
if entry.Info.Type == "source" {
appendArray("Make Dependencies", entry.Info.MakeDepends, true)
}
appendArray("Optional dependencies", entry.Info.OptionalDepends, true)
dependants := entry.GetEntryDependants()
if len(dependants) > 0 {
appendArray("Dependant packages", dependants, false)
}
appendArray("Conflicting packages", entry.Info.Conflicts, true)
appendArray("Provided packages", entry.Info.Provides, true)
appendArray("Replaces packages", entry.Info.Replaces, true)
if entry.Info.Type == "source" && len(entry.Info.SplitPackages) != 0 {
splitPkgs := make([]string, len(entry.Info.SplitPackages))
for i, splitPkgInfo := range entry.Info.SplitPackages {
splitPkgs[i] = splitPkgInfo.Name
}
appendArray("Split Packages", splitPkgs, true)
}
if rootDir != "" && IsPackageInstalled(entry.Info.Name, rootDir) {
installationReason := GetInstallationReason(entry.Info.Name, rootDir)
var installationReasonString string
switch installationReason {
case InstallationReasonManual:
installationReasonString = "Manual"
case InstallationReasonDependency:
installationReasonString = "Dependency"
case InstallationReasonMakeDependency:
installationReasonString = "Make dependency"
default:
installationReasonString = "Unknown"
}
ret = append(ret, "Installation Reason: "+installationReasonString)
}
if entry.Info.Type == "binary" {
installedSize := int64(entry.InstalledSize)
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")
}
+9 -18
View File
@@ -1,7 +1,6 @@
package bpmlib package bpmlib
import ( import (
"errors"
"fmt" "fmt"
"slices" "slices"
) )
@@ -170,19 +169,11 @@ func resolvePackageDependenciesFromDatabase(resolved *[]pkgInstallationReason, u
} }
} }
func GetPackageDependants(pkgName string, rootDir string) ([]string, error) { func (pkgInfo *PackageInfo) GetPackageDependants(rootDir string) (dependants []string) {
ret := make([]string, 0)
// Get BPM package
pkg := GetPackage(pkgName, rootDir)
if pkg == nil {
return nil, errors.New("package not found: " + pkgName)
}
// Get installed package names // Get installed package names
pkgs, err := GetInstalledPackages(rootDir) pkgs, err := GetInstalledPackages(rootDir)
if err != nil { if err != nil {
return nil, errors.New("could not get installed packages") return nil
} }
// Loop through all installed packages // Loop through all installed packages
@@ -190,33 +181,33 @@ func GetPackageDependants(pkgName string, rootDir string) ([]string, error) {
// Get installed BPM package // Get installed BPM package
installedPkg := GetPackage(installedPkgName, rootDir) installedPkg := GetPackage(installedPkgName, rootDir)
if installedPkg == nil { if installedPkg == nil {
return nil, errors.New("package not found: " + installedPkgName) return nil
} }
// Skip iteration if comparing the same packages // Skip iteration if comparing the same packages
if installedPkg.PkgInfo.Name == pkgName { if installedPkg.PkgInfo.Name == pkgInfo.Name {
continue continue
} }
// Add installed package to list if its dependencies include pkgName // Add installed package to list if its dependencies include pkgName
if slices.ContainsFunc(installedPkg.PkgInfo.Depends, func(n string) bool { if slices.ContainsFunc(installedPkg.PkgInfo.Depends, func(n string) bool {
return n == pkgName return n == pkgInfo.Name
}) { }) {
ret = append(ret, installedPkgName) dependants = append(dependants, installedPkgName)
continue continue
} }
// Loop through each virtual package // Loop through each virtual package
for _, vpkg := range pkg.PkgInfo.Provides { for _, vpkg := range 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 slices.ContainsFunc(installedPkg.PkgInfo.Depends, func(n string) bool { if slices.ContainsFunc(installedPkg.PkgInfo.Depends, func(n string) bool {
return n == vpkg return n == vpkg
}) { }) {
ret = append(ret, installedPkgName) dependants = append(dependants, installedPkgName)
break break
} }
} }
} }
return ret, nil return dependants
} }
+1 -5
View File
@@ -221,11 +221,7 @@ func RemovePackages(rootDir string, force, cleanupDependencies bool, packages ..
// Get packages and their dependants // Get packages and their dependants
packageDepndants := make(map[string][]string, 0) packageDepndants := make(map[string][]string, 0)
for _, action := range operation.Actions { for _, action := range operation.Actions {
dependants, err := GetPackageDependants(action.(*RemovePackageAction).BpmPackage.PkgInfo.Name, rootDir) dependants := action.(*RemovePackageAction).BpmPackage.PkgInfo.GetPackageDependants(rootDir)
if err != nil {
return nil, fmt.Errorf("could not get package dependants: %s", err)
}
packageDepndants[action.(*RemovePackageAction).BpmPackage.PkgInfo.Name] = dependants packageDepndants[action.(*RemovePackageAction).BpmPackage.PkgInfo.Name] = dependants
} }
+3
View File
@@ -75,6 +75,9 @@ func GetInstalledPackages(rootDir string) (ret []string, err error) {
ret = append(ret, bpmpkg.PkgInfo.Name) ret = append(ret, bpmpkg.PkgInfo.Name)
} }
// Sort packages
slices.Sort(ret)
return ret, nil return ret, nil
} }
+2 -5
View File
@@ -176,10 +176,7 @@ func (operation *BPMOperation) RemoveNeededPackages() error {
} }
for pkg, action := range removeActions { for pkg, action := range removeActions {
dependants, err := GetPackageDependants(action.BpmPackage.PkgInfo.Name, operation.RootDir) dependants := action.BpmPackage.PkgInfo.GetPackageDependants(operation.RootDir)
if err != nil {
return errors.New("could not get dependant packages for package (" + pkg + ")")
}
dependants = slices.DeleteFunc(dependants, func(d string) bool { dependants = slices.DeleteFunc(dependants, func(d string) bool {
if _, ok := removeActions[d]; ok { if _, ok := removeActions[d]; ok {
return true return true
@@ -592,7 +589,7 @@ func (operation *BPMOperation) Execute(verbose, force bool) (err error) {
// Compile source package if not compiled already // Compile source package if not compiled already
if _, ok := operation.compiledPackages[pkgNameToInstall]; !ok { if _, ok := operation.compiledPackages[pkgNameToInstall]; !ok {
outputBpmPackages, err := CompileSourcePackage(value.File, compiledDir, false) outputBpmPackages, err := CompileSourcePackage(value.File, compiledDir, false, false, verbose)
if err != nil { if err != nil {
return fmt.Errorf("could not compile source package (%s): %s\n", value.File, err) return fmt.Errorf("could not compile source package (%s): %s\n", value.File, err)
} }
+46 -28
View File
@@ -507,48 +507,56 @@ func ReadPackageInfo(contents string) (*PackageInfo, error) {
return pkgInfo, nil return pkgInfo, nil
} }
func CreateReadableInfo(showArchitecture, showType, showPackageRelations, showInstallationReason bool, pkgInfo *PackageInfo, rootDir string) string { func (bpmpkg *BPMPackage) CreateReadableInfo(rootDir string, humanReadableSize bool) string {
ret := make([]string, 0) ret := make([]string, 0)
appendArray := func(label string, array []string) { appendArray := func(label string, array []string) {
if len(array) == 0 { if len(array) == 0 {
return return
} }
// Sort array
slices.Sort(array)
ret = append(ret, fmt.Sprintf("%s: %s", label, strings.Join(array, ", "))) ret = append(ret, fmt.Sprintf("%s: %s", label, strings.Join(array, ", ")))
} }
ret = append(ret, "Name: "+pkgInfo.Name)
ret = append(ret, "Description: "+pkgInfo.Description) ret = append(ret, "Name: "+bpmpkg.PkgInfo.Name)
ret = append(ret, "Version: "+pkgInfo.GetFullVersion()) ret = append(ret, "Description: "+bpmpkg.PkgInfo.Description)
ret = append(ret, "URL: "+pkgInfo.Url) ret = append(ret, "Version: "+bpmpkg.PkgInfo.GetFullVersion())
ret = append(ret, "License: "+pkgInfo.License) if bpmpkg.PkgInfo.Url != "" {
if showArchitecture { ret = append(ret, "URL: "+bpmpkg.PkgInfo.Url)
ret = append(ret, "Architecture: "+pkgInfo.Arch)
} }
if showType { if bpmpkg.PkgInfo.License != "" {
ret = append(ret, "Type: "+pkgInfo.Type) ret = append(ret, "License: "+bpmpkg.PkgInfo.License)
} }
if showPackageRelations { ret = append(ret, "Architecture: "+bpmpkg.PkgInfo.Arch)
appendArray("Dependencies", pkgInfo.Depends) if bpmpkg.PkgInfo.Type == "source" && bpmpkg.PkgInfo.OutputArch != "" && bpmpkg.PkgInfo.OutputArch != GetArch() {
if pkgInfo.Type == "source" { ret = append(ret, "Output architecture: "+bpmpkg.PkgInfo.Arch)
appendArray("Make Dependencies", pkgInfo.MakeDepends)
}
appendArray("Optional dependencies", pkgInfo.OptionalDepends)
dependants, err := GetPackageDependants(pkgInfo.Name, rootDir)
if err == nil {
appendArray("Dependant packages", dependants)
}
appendArray("Conflicting packages", pkgInfo.Conflicts)
appendArray("Provided packages", pkgInfo.Provides)
appendArray("Replaces packages", pkgInfo.Replaces)
} }
if pkgInfo.Type == "source" && len(pkgInfo.SplitPackages) != 0 { ret = append(ret, "Type: "+bpmpkg.PkgInfo.Type)
splitPkgs := make([]string, len(pkgInfo.SplitPackages)) appendArray("Dependencies", bpmpkg.PkgInfo.Depends)
for i, splitPkgInfo := range pkgInfo.SplitPackages { if bpmpkg.PkgInfo.Type == "source" {
appendArray("Make Dependencies", bpmpkg.PkgInfo.MakeDepends)
}
appendArray("Optional dependencies", bpmpkg.PkgInfo.OptionalDepends)
dependants := bpmpkg.PkgInfo.GetPackageDependants(rootDir)
if len(dependants) > 0 {
appendArray("Dependant packages", dependants)
}
appendArray("Conflicting packages", bpmpkg.PkgInfo.Conflicts)
appendArray("Provided packages", bpmpkg.PkgInfo.Provides)
appendArray("Replaces packages", bpmpkg.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 {
splitPkgs[i] = splitPkgInfo.Name splitPkgs[i] = splitPkgInfo.Name
} }
appendArray("Split Packages", splitPkgs) appendArray("Split Packages", splitPkgs)
} }
if IsPackageInstalled(pkgInfo.Name, rootDir) && showInstallationReason {
installationReason := GetInstallationReason(pkgInfo.Name, rootDir) if rootDir != "" && IsPackageInstalled(bpmpkg.PkgInfo.Name, rootDir) {
installationReason := GetInstallationReason(bpmpkg.PkgInfo.Name, rootDir)
var installationReasonString string var installationReasonString string
switch installationReason { switch installationReason {
case InstallationReasonManual: case InstallationReasonManual:
@@ -562,6 +570,16 @@ func CreateReadableInfo(showArchitecture, showType, showPackageRelations, showIn
} }
ret = append(ret, "Installation Reason: "+installationReasonString) ret = append(ret, "Installation Reason: "+installationReasonString)
} }
if bpmpkg.PkgInfo.Type == "binary" {
installedSize := int64(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") return strings.Join(ret, "\n")
} }