From 1298c05a194e3e6bb249b0fe5bf04adde87bd723 Mon Sep 17 00:00:00 2001 From: Alberto Massidda Date: Fri, 23 May 2025 19:15:29 +0200 Subject: [PATCH 1/2] fix GetPackageManager("") causing panic due to no pm autoselected according to the documentation, when GetPackageManager() is invoked with an empty name, "If the name is empty, the first available package manager will be returned.". But that was unimplemented --- syspkg.go | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/syspkg.go b/syspkg.go index bd47df4..9a73a2f 100644 --- a/syspkg.go +++ b/syspkg.go @@ -20,6 +20,7 @@ package syspkg import ( "errors" "log" + "sort" "github.com/bluet/syspkg/manager" "github.com/bluet/syspkg/manager/apt" @@ -97,8 +98,22 @@ func (s *sysPkgImpl) FindPackageManagers(include IncludeOptions) (map[string]Pac } // GetPackageManager returns a PackageManager instance by its name (e.g., "apt", "snap", "flatpak", etc.). +// if name is empty, return the first available func (s *sysPkgImpl) GetPackageManager(name string) PackageManager { - return s.pms[name] + var pm PackageManager + + if name == "" { + // get first pm available, lexicographically sorted + keys := make([]string, 0, len(s.pms)) + for k := range s.pms { + keys = append(keys, k) + } + sort.Strings(keys) + pm = s.pms[keys[0]] + } else { + pm = s.pms[name] + } + return pm } // RefreshPackageManagers refreshes the internal list of available package managers, and returns the new list. From 22a3705f2e3ded76863efb1021da54fbd02ed422 Mon Sep 17 00:00:00 2001 From: Alberto Massidda Date: Mon, 26 May 2025 13:55:49 +0000 Subject: [PATCH 2/2] fix syspkg.GetPackageManager never returning errors despite the documentation saying so --- interface.go | 2 +- syspkg.go | 16 +++++++++---- syspkg_test.go | 65 ++++++++++++++++++++++++++++++++++---------------- 3 files changed, 57 insertions(+), 26 deletions(-) diff --git a/interface.go b/interface.go index 29359be..407e78f 100644 --- a/interface.go +++ b/interface.go @@ -53,7 +53,7 @@ type SysPkg interface { // If the name is empty, the first available package manager will be returned. // If no suitable package manager is found, an error is returned. // Note: only package managers that are specified in the IncludeOptions when creating the SysPkg instance (with New() method) will be returned. If you want to use package managers that are not specified in the IncludeOptions, you should use the FindPackageManagers() method to get a list of all available package managers, or use RefreshPackageManagers() with the IncludeOptions parameter to refresh the package manager list. - GetPackageManager(name string) PackageManager + GetPackageManager(name string) (PackageManager, error) // Install(pkgs []string, opts *manager.Options) ([]manager.PackageInfo, error) // Delete(pkgs []string, opts *manager.Options) ([]manager.PackageInfo, error) diff --git a/syspkg.go b/syspkg.go index 9a73a2f..a86d07c 100644 --- a/syspkg.go +++ b/syspkg.go @@ -14,7 +14,7 @@ // if err != nil { // log.Fatal(err) // } -// aptManager := sysPkg.GetPackageManager("apt") +// aptManager,err := sysPkg.GetPackageManager("apt") package syspkg import ( @@ -99,9 +99,14 @@ func (s *sysPkgImpl) FindPackageManagers(include IncludeOptions) (map[string]Pac // GetPackageManager returns a PackageManager instance by its name (e.g., "apt", "snap", "flatpak", etc.). // if name is empty, return the first available -func (s *sysPkgImpl) GetPackageManager(name string) PackageManager { +func (s *sysPkgImpl) GetPackageManager(name string) (PackageManager,error) { var pm PackageManager + // if there are no package managers, return before accessing non existing properties + if len(s.pms) == 0 { + return nil, errors.New("no supported package manager detected") + } + if name == "" { // get first pm available, lexicographically sorted keys := make([]string, 0, len(s.pms)) @@ -111,9 +116,12 @@ func (s *sysPkgImpl) GetPackageManager(name string) PackageManager { sort.Strings(keys) pm = s.pms[keys[0]] } else { - pm = s.pms[name] + pm,found := s.pms[name] + if !found { + return pm, errors.New("no such package manager") + } } - return pm + return pm, nil } // RefreshPackageManagers refreshes the internal list of available package managers, and returns the new list. diff --git a/syspkg_test.go b/syspkg_test.go index 4aac5d1..d3c540c 100644 --- a/syspkg_test.go +++ b/syspkg_test.go @@ -30,7 +30,7 @@ func TestNewPackageManager(t *testing.T) { AllAvailable: true, }) if err != nil { - t.Fatalf("GetPackageManagers() error: %+v", err) + t.Fatalf("FindPackageManagers() error: %+v", err) } log.Printf("pms: %+v", pms) @@ -53,73 +53,96 @@ func TestNewPackageManager(t *testing.T) { // if we are on any other distro, we should have nothing if OSInfo.Distribution == "ubuntu" || OSInfo.Distribution == "debian" || OSInfo.Distribution == "mint" || OSInfo.Distribution == "PopOS" || OSInfo.Distribution == "elementary" || OSInfo.Distribution == "Zorin" || OSInfo.Distribution == "ChromeOS" { - if _, ok := pms["apt"]; !ok && s.GetPackageManager("apt") == nil { - if _, ok := pms["snap"]; !ok && s.GetPackageManager("snap") == nil { - if _, ok := pms["flatpak"]; !ok && s.GetPackageManager("flatpak") == nil { + pm,err:=s.GetPackageManager("apt") + + if err != nil && pm == nil { + pm,err:=s.GetPackageManager("snap") + + if err!=nil && pm == nil { + pm,err:=s.GetPackageManager("flatpak") + + if err!=nil && pm == nil { t.Fatalf("apt, snap, or flatpak package manager not found") } } } } else if OSInfo.Distribution == "fedora" || OSInfo.Distribution == "centos" || OSInfo.Distribution == "rhel" || OSInfo.Distribution == "rockylinux" || OSInfo.Distribution == "almalinux" || OSInfo.Distribution == "amazon linux" || OSInfo.Distribution == "oracle linux" || OSInfo.Distribution == "scientific linux" || OSInfo.Distribution == "cloudlinux" { - if _, ok := pms["dnf"]; !ok && s.GetPackageManager("dnf") == nil { - if _, ok := pms["yum"]; !ok && s.GetPackageManager("yum") == nil { + pm,err:=s.GetPackageManager("dnf") + if err != nil && pm == nil { + pm,err:=s.GetPackageManager("yum") + if err != nil && pm == nil { t.Fatalf("dnf or yum package manager not found") } } } else if OSInfo.Distribution == "opensuse" { - if _, ok := pms["zypper"]; !ok && s.GetPackageManager("zypper") == nil { + pm,err:=s.GetPackageManager("zypper") + if err != nil && pm == nil { t.Fatalf("zypper package manager not found") } } else if OSInfo.Distribution == "alpine" { - if _, ok := pms["apk"]; !ok && s.GetPackageManager("apk") == nil { + pm,err:=s.GetPackageManager("apk") + if err != nil && pm == nil { t.Fatalf("apk package manager not found") } } else if OSInfo.Distribution == "arch" { - if _, ok := pms["pacman"]; !ok && s.GetPackageManager("pacman") == nil { + pm,err:=s.GetPackageManager("pacman") + if err != nil && pm == nil { t.Fatalf("pacman package manager not found") } } else if OSInfo.Distribution == "gentoo" { - if _, ok := pms["emerge"]; !ok && s.GetPackageManager("emerge") == nil { + pm,err:=s.GetPackageManager("emerge") + if err != nil && pm == nil { t.Fatalf("emerge package manager not found") } } else if OSInfo.Distribution == "slackware" { - if _, ok := pms["slackpkg"]; !ok && s.GetPackageManager("slackpkg") == nil { + pm,err:=s.GetPackageManager("slackpkg") + if err != nil && pm == nil { t.Fatalf("slackpkg package manager not found") } } else if OSInfo.Distribution == "void" { - if _, ok := pms["xbps"]; !ok && s.GetPackageManager("xbps") == nil { + pm,err:=s.GetPackageManager("xbps") + if err != nil && pm == nil { t.Fatalf("xbps package manager not found") } } else if OSInfo.Distribution == "solus" { - if _, ok := pms["eopkg"]; !ok && s.GetPackageManager("eopkg") == nil { + pm,err:=s.GetPackageManager("eopkg") + if err != nil && pm == nil { t.Fatalf("eopkg package manager not found") } } else if OSInfo.Distribution == "freebsd" || OSInfo.Distribution == "dragonfly" || OSInfo.Distribution == "termux" { - if _, ok := pms["pkg"]; !ok && s.GetPackageManager("pkg") == nil { + pm,err:=s.GetPackageManager("pkg") + if err != nil && pm == nil { t.Fatalf("pkg package manager not found") } } else if OSInfo.Distribution == "openbsd" || OSInfo.Distribution == "netbsd" { - if _, ok := pms["pkg_add"]; !ok && s.GetPackageManager("pkg_add") == nil { + pm,err:=s.GetPackageManager("pkg_add") + if err != nil && pm == nil { t.Fatalf("pkg_add package manager not found") } } else if OSInfo.Distribution == "macos" { - if _, ok := pms["brew"]; !ok && s.GetPackageManager("brew") == nil { + pm,err:=s.GetPackageManager("brew") + if err != nil && pm == nil { t.Fatalf("brew package manager not found") } } else if OSInfo.Distribution == "windows" { - if _, ok := pms["chocolatey"]; !ok && s.GetPackageManager("chocolatey") == nil { - if _, ok := pms["scoop"]; !ok && s.GetPackageManager("scoop") == nil { - if _, ok := pms["winget"]; !ok && s.GetPackageManager("winget") == nil { + pm,err:=s.GetPackageManager("chocolatey") + if err != nil && pm == nil { + pm,err:=s.GetPackageManager("scoop") + if err != nil && pm == nil { + pm,err:=s.GetPackageManager("winget") + if err != nil && pm == nil { t.Fatalf("chocolatey, scoop, or winget package manager not found") } } } } else if OSInfo.Distribution == "android" { - if _, ok := pms["f-droid"]; !ok && s.GetPackageManager("f-droid") == nil { + pm,err:=s.GetPackageManager("f-droid") + if err != nil && pm == nil { t.Fatalf("f-droid package manager not found") } } else if OSInfo.Distribution == "ios" { - if _, ok := pms["cydia"]; !ok && s.GetPackageManager("cydia") == nil { + pm,err:=s.GetPackageManager("cydia") + if err != nil && pm == nil { t.Fatalf("cydia package manager not found") } } else {