diff --git a/apk/apk_test.go b/apk/apk_test.go index 2808116..bc6b8c6 100644 --- a/apk/apk_test.go +++ b/apk/apk_test.go @@ -23,7 +23,7 @@ func TestSplitNameVersion(t *testing.T) { {"my-pkg-name-0.1-r0", "my-pkg-name", "0.1-r0"}, {"a-b-c-3.0", "a-b-c", "3.0"}, {"single", "single", ""}, - {"-1.0", "-1.0", ""}, // no digit follows last hyphen at position > 0 + {"-1.0", "-1.0", ""}, // no digit follows last hyphen at position > 0 {"pkg-0", "pkg", "0"}, } for _, tt := range tests { @@ -289,10 +289,10 @@ func TestParseInfoEdgeCases(t *testing.T) { func TestParseInfoNameVersion(t *testing.T) { tests := []struct { - name string - input string - wantN string - wantV string + name string + input string + wantN string + wantV string }{ { name: "standard", @@ -435,8 +435,8 @@ func TestParseUpgradeSimulation(t *testing.T) { wantLen: 0, }, { - name: "single upgrade", - input: "(1/1) Upgrading curl (8.5.0-r0 -> 8.6.0-r0)\n", + name: "single upgrade", + input: "(1/1) Upgrading curl (8.5.0-r0 -> 8.6.0-r0)\n", wantLen: 1, wantPkgs: []snack.Package{ {Name: "curl", Version: "8.6.0-r0", Installed: true}, @@ -462,8 +462,8 @@ OK: 123 MiB in 45 packages wantLen: 0, }, { - name: "upgrade without version parens", - input: "(1/1) Upgrading busybox\n", + name: "upgrade without version parens", + input: "(1/1) Upgrading busybox\n", wantLen: 1, wantPkgs: []snack.Package{ {Name: "busybox", Version: "", Installed: true}, diff --git a/apk/normalize.go b/apk/normalize.go index 1bfce06..97094be 100644 --- a/apk/normalize.go +++ b/apk/normalize.go @@ -17,14 +17,14 @@ func normalizeName(name string) string { // - package-aarch64 func parseArchNormalize(name string) (string, string) { knownArchs := map[string]bool{ - "x86_64": true, - "x86": true, - "aarch64": true, - "armhf": true, - "armv7": true, - "ppc64le": true, - "s390x": true, - "riscv64": true, + "x86_64": true, + "x86": true, + "aarch64": true, + "armhf": true, + "armv7": true, + "ppc64le": true, + "s390x": true, + "riscv64": true, "loongarch64": true, } diff --git a/apk/normalize_test.go b/apk/normalize_test.go new file mode 100644 index 0000000..ed8bcdc --- /dev/null +++ b/apk/normalize_test.go @@ -0,0 +1,71 @@ +package apk + +import ( + "testing" +) + +func TestNormalizeName(t *testing.T) { + tests := []struct { + input string + want string + }{ + {"curl", "curl"}, + {"curl-x86_64", "curl"}, + {"openssl-aarch64", "openssl"}, + {"musl-armhf", "musl"}, + {"busybox-armv7", "busybox"}, + {"lib-ssl-dev-x86", "lib-ssl-dev"}, + {"zlib-ppc64le", "zlib"}, + {"kernel-s390x", "kernel"}, + {"toolchain-riscv64", "toolchain"}, + {"app-loongarch64", "app"}, + // No arch suffix — unchanged + {"python", "python"}, + {"go", "go"}, + {"", ""}, + // Suffix that isn't an arch — unchanged + {"my-pkg-foo", "my-pkg-foo"}, + {"libfoo-1.0", "libfoo-1.0"}, + } + for _, tt := range tests { + t.Run(tt.input, func(t *testing.T) { + got := normalizeName(tt.input) + if got != tt.want { + t.Errorf("normalizeName(%q) = %q, want %q", tt.input, got, tt.want) + } + }) + } +} + +func TestParseArchNormalize(t *testing.T) { + tests := []struct { + name string + input string + wantName string + wantArch string + }{ + {"x86_64", "curl-x86_64", "curl", "x86_64"}, + {"x86", "musl-x86", "musl", "x86"}, + {"aarch64", "openssl-aarch64", "openssl", "aarch64"}, + {"armhf", "busybox-armhf", "busybox", "armhf"}, + {"armv7", "lib-armv7", "lib", "armv7"}, + {"ppc64le", "app-ppc64le", "app", "ppc64le"}, + {"s390x", "pkg-s390x", "pkg", "s390x"}, + {"riscv64", "tool-riscv64", "tool", "riscv64"}, + {"loongarch64", "gcc-loongarch64", "gcc", "loongarch64"}, + {"no arch", "curl", "curl", ""}, + {"unknown suffix", "pkg-foobar", "pkg-foobar", ""}, + {"empty", "", "", ""}, + {"hyphen but not arch", "lib-ssl-dev", "lib-ssl-dev", ""}, + {"multi hyphen with arch", "lib-ssl-dev-x86_64", "lib-ssl-dev", "x86_64"}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + gotName, gotArch := parseArchNormalize(tt.input) + if gotName != tt.wantName || gotArch != tt.wantArch { + t.Errorf("parseArchNormalize(%q) = (%q, %q), want (%q, %q)", + tt.input, gotName, gotArch, tt.wantName, tt.wantArch) + } + }) + } +} diff --git a/apt/capabilities_linux.go b/apt/capabilities_linux.go index 9ff59c5..3195488 100644 --- a/apt/capabilities_linux.go +++ b/apt/capabilities_linux.go @@ -191,7 +191,6 @@ func listRepos(_ context.Context) ([]snack.Repository, error) { return repos, nil } - func addRepo(ctx context.Context, repo snack.Repository) error { repoLine := repo.URL if repo.Type != "" { diff --git a/apt/parse_test.go b/apt/parse_test.go index 9bee887..b76a914 100644 --- a/apt/parse_test.go +++ b/apt/parse_test.go @@ -14,8 +14,8 @@ func TestParseList_EdgeCases(t *testing.T) { }{ {"empty", "", 0}, {"whitespace_only", " \n \n ", 0}, - {"single_tab_field", "bash", 0}, // needs at least 2 tab-separated fields - {"no_description", "bash\t5.2-1", 1}, // 2 fields is OK + {"single_tab_field", "bash", 0}, // needs at least 2 tab-separated fields + {"no_description", "bash\t5.2-1", 1}, // 2 fields is OK {"with_description", "bash\t5.2-1\tGNU Bourne Again SHell", 1}, {"blank_lines_mixed", "\nbash\t5.2-1\n\ncurl\t7.88\n\n", 2}, {"trailing_newline", "bash\t5.2-1\n", 1}, diff --git a/aur/aur_linux.go b/aur/aur_linux.go index aef5cc9..616f4c5 100644 --- a/aur/aur_linux.go +++ b/aur/aur_linux.go @@ -378,5 +378,3 @@ func upgradePackages(ctx context.Context, pkgs []snack.Target, opts ...snack.Opt allOpts := append([]snack.Option{snack.WithReinstall()}, opts...) return install(ctx, pkgs, allOpts...) } - - diff --git a/aur/rpc.go b/aur/rpc.go index 87d173d..e276c26 100644 --- a/aur/rpc.go +++ b/aur/rpc.go @@ -115,4 +115,3 @@ func rpcInfo(ctx context.Context, pkg string) (*snack.Package, error) { p := resp.Results[0].toPackage() return &p, nil } - diff --git a/brew/brew_unix.go b/brew/brew_unix.go index 1ad275f..4497bc5 100644 --- a/brew/brew_unix.go +++ b/brew/brew_unix.go @@ -235,10 +235,10 @@ func clean(ctx context.Context) error { // brewInfoJSON represents the JSON output from `brew info --json=v2`. type brewInfoJSON struct { Formulae []struct { - Name string `json:"name"` - FullName string `json:"full_name"` - Desc string `json:"desc"` - Versions struct { + Name string `json:"name"` + FullName string `json:"full_name"` + Desc string `json:"desc"` + Versions struct { Stable string `json:"stable"` } `json:"versions"` Installed []struct { @@ -246,24 +246,24 @@ type brewInfoJSON struct { } `json:"installed"` } `json:"formulae"` Casks []struct { - Token string `json:"token"` + Token string `json:"token"` Name []string `json:"name"` - Desc string `json:"desc"` - Version string `json:"version"` + Desc string `json:"desc"` + Version string `json:"version"` } `json:"casks"` } // brewOutdatedJSON represents the JSON output from `brew outdated --json=v2`. type brewOutdatedJSON struct { Formulae []struct { - Name string `json:"name"` + Name string `json:"name"` InstalledVersions []string `json:"installed_versions"` - CurrentVersion string `json:"current_version"` + CurrentVersion string `json:"current_version"` } `json:"formulae"` Casks []struct { - Name string `json:"name"` + Name string `json:"name"` InstalledVersions string `json:"installed_versions"` - CurrentVersion string `json:"current_version"` + CurrentVersion string `json:"current_version"` } `json:"casks"` } diff --git a/capabilities.go b/capabilities.go index 76027f5..79ab47f 100644 --- a/capabilities.go +++ b/capabilities.go @@ -4,16 +4,16 @@ package snack // Useful for grlx to determine what operations are available before // attempting them. type Capabilities struct { - VersionQuery bool - Hold bool - Clean bool - FileOwnership bool - RepoManagement bool - KeyManagement bool - Groups bool - NameNormalize bool - DryRun bool - PackageUpgrade bool + VersionQuery bool + Hold bool + Clean bool + FileOwnership bool + RepoManagement bool + KeyManagement bool + Groups bool + NameNormalize bool + DryRun bool + PackageUpgrade bool } // GetCapabilities probes a Manager for all optional interface support. @@ -29,15 +29,15 @@ func GetCapabilities(m Manager) Capabilities { _, dr := m.(DryRunner) _, pu := m.(PackageUpgrader) return Capabilities{ - VersionQuery: vq, - Hold: h, - Clean: c, - FileOwnership: fo, - RepoManagement: rm, - KeyManagement: km, - Groups: g, - NameNormalize: nn, - DryRun: dr, - PackageUpgrade: pu, + VersionQuery: vq, + Hold: h, + Clean: c, + FileOwnership: fo, + RepoManagement: rm, + KeyManagement: km, + Groups: g, + NameNormalize: nn, + DryRun: dr, + PackageUpgrade: pu, } } diff --git a/capabilities_test.go b/capabilities_test.go index bbed6b8..ffd735c 100644 --- a/capabilities_test.go +++ b/capabilities_test.go @@ -18,15 +18,15 @@ func (m *mockManager) Remove(context.Context, []snack.Target, ...snack.Option) ( return snack.RemoveResult{}, nil } func (m *mockManager) Purge(context.Context, []snack.Target, ...snack.Option) error { return nil } -func (m *mockManager) Upgrade(context.Context, ...snack.Option) error { return nil } -func (m *mockManager) Update(context.Context) error { return nil } -func (m *mockManager) List(context.Context) ([]snack.Package, error) { return nil, nil } -func (m *mockManager) Search(context.Context, string) ([]snack.Package, error) { return nil, nil } -func (m *mockManager) Info(context.Context, string) (*snack.Package, error) { return nil, nil } -func (m *mockManager) IsInstalled(context.Context, string) (bool, error) { return false, nil } -func (m *mockManager) Version(context.Context, string) (string, error) { return "", nil } -func (m *mockManager) Available() bool { return true } -func (m *mockManager) Name() string { return "mock" } +func (m *mockManager) Upgrade(context.Context, ...snack.Option) error { return nil } +func (m *mockManager) Update(context.Context) error { return nil } +func (m *mockManager) List(context.Context) ([]snack.Package, error) { return nil, nil } +func (m *mockManager) Search(context.Context, string) ([]snack.Package, error) { return nil, nil } +func (m *mockManager) Info(context.Context, string) (*snack.Package, error) { return nil, nil } +func (m *mockManager) IsInstalled(context.Context, string) (bool, error) { return false, nil } +func (m *mockManager) Version(context.Context, string) (string, error) { return "", nil } +func (m *mockManager) Available() bool { return true } +func (m *mockManager) Name() string { return "mock" } // fullMockManager implements Manager plus all optional interfaces. type fullMockManager struct { diff --git a/dnf/dnf_test.go b/dnf/dnf_test.go index 6b1b364..9eaf7ed 100644 --- a/dnf/dnf_test.go +++ b/dnf/dnf_test.go @@ -8,16 +8,16 @@ import ( // Compile-time interface assertions — DNF implements all optional interfaces. var ( - _ snack.Manager = (*DNF)(nil) - _ snack.VersionQuerier = (*DNF)(nil) - _ snack.Holder = (*DNF)(nil) - _ snack.Cleaner = (*DNF)(nil) - _ snack.FileOwner = (*DNF)(nil) - _ snack.RepoManager = (*DNF)(nil) - _ snack.KeyManager = (*DNF)(nil) - _ snack.Grouper = (*DNF)(nil) - _ snack.NameNormalizer = (*DNF)(nil) - _ snack.DryRunner = (*DNF)(nil) + _ snack.Manager = (*DNF)(nil) + _ snack.VersionQuerier = (*DNF)(nil) + _ snack.Holder = (*DNF)(nil) + _ snack.Cleaner = (*DNF)(nil) + _ snack.FileOwner = (*DNF)(nil) + _ snack.RepoManager = (*DNF)(nil) + _ snack.KeyManager = (*DNF)(nil) + _ snack.Grouper = (*DNF)(nil) + _ snack.NameNormalizer = (*DNF)(nil) + _ snack.DryRunner = (*DNF)(nil) _ snack.PackageUpgrader = (*DNF)(nil) ) diff --git a/go.mod b/go.mod index 15ef92b..18cb8ea 100644 --- a/go.mod +++ b/go.mod @@ -1,10 +1,9 @@ module github.com/gogrlx/snack -go 1.26.0 +go 1.26.1 require ( github.com/charmbracelet/fang v0.4.4 - github.com/go-git/go-git/v5 v5.17.0 github.com/spf13/cobra v1.10.2 github.com/stretchr/testify v1.11.1 github.com/testcontainers/testcontainers-go v0.40.0 @@ -15,48 +14,39 @@ require ( dario.cat/mergo v1.0.2 // indirect github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect - github.com/ProtonMail/go-crypto v1.1.6 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/charmbracelet/colorprofile v0.4.2 // indirect github.com/charmbracelet/ultraviolet v0.0.0-20260303162955-0b88c25f3fff // indirect github.com/charmbracelet/x/ansi v0.11.6 // indirect - github.com/charmbracelet/x/exp/charmtone v0.0.0-20260304213900-0e78e2954235 // indirect + github.com/charmbracelet/x/exp/charmtone v0.0.0-20260305213658-fe36e8c10185 // indirect github.com/charmbracelet/x/term v0.2.2 // indirect github.com/charmbracelet/x/termios v0.1.1 // indirect github.com/charmbracelet/x/windows v0.2.2 // indirect github.com/clipperhouse/displaywidth v0.11.0 // indirect github.com/clipperhouse/uax29/v2 v2.7.0 // indirect - github.com/cloudflare/circl v1.6.3 // indirect github.com/containerd/errdefs v1.0.0 // indirect github.com/containerd/errdefs/pkg v0.3.0 // indirect github.com/containerd/log v0.1.0 // indirect github.com/containerd/platforms v0.2.1 // indirect github.com/cpuguy83/dockercfg v0.3.2 // indirect - github.com/cyphar/filepath-securejoin v0.4.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/distribution/reference v0.6.0 // indirect github.com/docker/docker v28.5.1+incompatible // indirect github.com/docker/go-connections v0.6.0 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/ebitengine/purego v0.8.4 // indirect - github.com/emirpasic/gods v1.18.1 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect - github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect - github.com/go-git/go-billy/v5 v5.8.0 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.2.6 // indirect - github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect github.com/google/uuid v1.6.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect - github.com/kevinburke/ssh_config v1.2.0 // indirect github.com/klauspost/compress v1.18.0 // indirect github.com/lucasb-eyer/go-colorful v1.3.0 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/magiconair/properties v1.8.10 // indirect - github.com/mattn/go-runewidth v0.0.20 // indirect + github.com/mattn/go-runewidth v0.0.21 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/go-archive v0.1.0 // indirect github.com/moby/patternmatcher v0.6.0 // indirect @@ -72,19 +62,15 @@ require ( github.com/muesli/roff v0.1.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.1 // indirect - github.com/pjbgf/sha1cd v0.3.2 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect github.com/rivo/uniseg v0.4.7 // indirect - github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect github.com/shirou/gopsutil/v4 v4.25.6 // indirect github.com/sirupsen/logrus v1.9.3 // indirect - github.com/skeema/knownhosts v1.3.1 // indirect github.com/spf13/pflag v1.0.10 // indirect github.com/tklauser/go-sysconf v0.3.12 // indirect github.com/tklauser/numcpus v0.6.1 // indirect - github.com/xanzy/ssh-agent v0.3.3 // indirect github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect @@ -96,11 +82,10 @@ require ( go.opentelemetry.io/otel/trace v1.40.0 // indirect go.opentelemetry.io/proto/otlp v1.9.0 // indirect golang.org/x/crypto v0.45.0 // indirect - golang.org/x/net v0.47.0 // indirect - golang.org/x/sync v0.19.0 // indirect - golang.org/x/sys v0.41.0 // indirect + golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect + golang.org/x/sync v0.20.0 // indirect + golang.org/x/sys v0.42.0 // indirect golang.org/x/text v0.34.0 // indirect google.golang.org/protobuf v1.36.11 // indirect - gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 568677f..8be88b8 100644 --- a/go.sum +++ b/go.sum @@ -6,15 +6,8 @@ github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8af github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= -github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= -github.com/ProtonMail/go-crypto v1.1.6 h1:ZcV+Ropw6Qn0AX9brlQLAUXfqLBc7Bl+f/DmNxpLfdw= -github.com/ProtonMail/go-crypto v1.1.6/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE= -github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= -github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= -github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= -github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/aymanbagabas/go-udiff v0.4.0 h1:TKnLPh7IbnizJIBKFWa9mKayRUBQ9Kh1BPCk6w2PnYM= github.com/aymanbagabas/go-udiff v0.4.0/go.mod h1:0L9PGwj20lrtmEMeyw4WKJ/TMyDtvAoK9bf2u/mNo3w= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= @@ -29,8 +22,8 @@ github.com/charmbracelet/ultraviolet v0.0.0-20260303162955-0b88c25f3fff h1:uY7A6 github.com/charmbracelet/ultraviolet v0.0.0-20260303162955-0b88c25f3fff/go.mod h1:E6/0abq9uG2SnM8IbLB9Y5SW09uIgfaFETk8aRzgXUQ= github.com/charmbracelet/x/ansi v0.11.6 h1:GhV21SiDz/45W9AnV2R61xZMRri5NlLnl6CVF7ihZW8= github.com/charmbracelet/x/ansi v0.11.6/go.mod h1:2JNYLgQUsyqaiLovhU2Rv/pb8r6ydXKS3NIttu3VGZQ= -github.com/charmbracelet/x/exp/charmtone v0.0.0-20260304213900-0e78e2954235 h1:G96IHDV9QdhxyJZN/UBk6RiVsyejQBrKl6XxP5rvydE= -github.com/charmbracelet/x/exp/charmtone v0.0.0-20260304213900-0e78e2954235/go.mod h1:nsExn0DGyX0lh9LwLHTn2Gg+hafdzfSXnC+QmEJTZFY= +github.com/charmbracelet/x/exp/charmtone v0.0.0-20260305213658-fe36e8c10185 h1:/192monmpmRICpSPrFRzkIO+xfhioV6/nwrQdkDTj10= +github.com/charmbracelet/x/exp/charmtone v0.0.0-20260305213658-fe36e8c10185/go.mod h1:nsExn0DGyX0lh9LwLHTn2Gg+hafdzfSXnC+QmEJTZFY= github.com/charmbracelet/x/exp/golden v0.0.0-20250806222409-83e3a29d542f h1:pk6gmGpCE7F3FcjaOEKYriCvpmIN4+6OS/RD0vm4uIA= github.com/charmbracelet/x/exp/golden v0.0.0-20250806222409-83e3a29d542f/go.mod h1:IfZAMTHB6XkZSeXUqriemErjAWCCzT0LwjKFYCZyw0I= github.com/charmbracelet/x/term v0.2.2 h1:xVRT/S2ZcKdhhOuSP4t5cLi5o+JxklsoEObBSgfgZRk= @@ -43,8 +36,6 @@ github.com/clipperhouse/displaywidth v0.11.0 h1:lBc6kY44VFw+TDx4I8opi/EtL9m20WSE github.com/clipperhouse/displaywidth v0.11.0/go.mod h1:bkrFNkf81G8HyVqmKGxsPufD3JhNl3dSqnGhOoSD/o0= github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJv2v7Vk= github.com/clipperhouse/uax29/v2 v2.7.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM= -github.com/cloudflare/circl v1.6.3 h1:9GPOhQGF9MCYUeXyMYlqTR6a5gTrgR/fBLXvUgtVcg8= -github.com/cloudflare/circl v1.6.3/go.mod h1:2eXP6Qfat4O/Yhh8BznvKnJ+uzEoTQ6jVKJRn81BiS4= github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI= github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M= github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE= @@ -58,8 +49,6 @@ github.com/cpuguy83/dockercfg v0.3.2/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHf github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= -github.com/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s= -github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI= 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= @@ -73,22 +62,8 @@ github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4 github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/ebitengine/purego v0.8.4 h1:CF7LEKg5FFOsASUj0+QwaXf8Ht6TlFxg09+S9wz0omw= github.com/ebitengine/purego v0.8.4/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= -github.com/elazarl/goproxy v1.7.2 h1:Y2o6urb7Eule09PjlhQRGNsqRfPmYI3KKQLFpCAV3+o= -github.com/elazarl/goproxy v1.7.2/go.mod h1:82vkLNir0ALaW14Rc399OTTjyNREgmdL2cVoIbS6XaE= -github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= -github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c= -github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU= -github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= -github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= -github.com/go-git/go-billy/v5 v5.8.0 h1:I8hjc3LbBlXTtVuFNJuwYuMiHvQJDq1AT6u4DwDzZG0= -github.com/go-git/go-billy/v5 v5.8.0/go.mod h1:RpvI/rw4Vr5QA+Z60c6d6LXH0rYJo0uD5SqfmrrheCY= -github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4= -github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII= -github.com/go-git/go-git/v5 v5.17.0 h1:AbyI4xf+7DsjINHMu35quAh4wJygKBKBuXVjV/pxesM= -github.com/go-git/go-git/v5 v5.17.0/go.mod h1:f82C4YiLx+Lhi8eHxltLeGC5uBTXSFa6PC5WW9o4SjI= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= @@ -96,8 +71,6 @@ github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= -github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ= -github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= @@ -107,17 +80,10 @@ github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnV github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2/go.mod h1:pkJQ2tZHJ0aFOVEEot6oZmaVEZcRme73eIFmhiVuRWs= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= -github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= -github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= -github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lucasb-eyer/go-colorful v1.3.0 h1:2/yBRLdWBZKrf7gB40FoiKfAWYQ0lqNcbuQwVHXptag= @@ -126,8 +92,8 @@ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE= github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= -github.com/mattn/go-runewidth v0.0.20 h1:WcT52H91ZUAwy8+HUkdM3THM6gXqXuLJi9O3rjcQQaQ= -github.com/mattn/go-runewidth v0.0.20/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs= +github.com/mattn/go-runewidth v0.0.21 h1:jJKAZiQH+2mIinzCJIaIG9Be1+0NR+5sz/lYEEjdM8w= +github.com/mattn/go-runewidth v0.0.21/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/go-archive v0.1.0 h1:Kk/5rdW/g+H8NHdJW2gsXyZ7UnzvJNOy6VKJqueWdcQ= @@ -156,14 +122,10 @@ github.com/muesli/mango-pflag v0.2.0 h1:QViokgKDZQCzKhYe1zH8D+UlPJzBSGoP9yx0hBG0 github.com/muesli/mango-pflag v0.2.0/go.mod h1:X9LT1p/pbGA1wjvEbtwnixujKErkP0jVmrxwrw3fL0Y= github.com/muesli/roff v0.1.0 h1:YD0lalCotmYuF5HhZliKWlIx7IEhiXeSfq7hNjFqGF8= github.com/muesli/roff v0.1.0/go.mod h1:pjAHQM9hdUUwm/krAfrLGgJkXJ+YuhtsfZ42kieB2Ig= -github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k= -github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= -github.com/pjbgf/sha1cd v0.3.2 h1:a9wb0bp1oC2TGwStyn0Umc/IGKQnEgF0vVaZ8QF8eo4= -github.com/pjbgf/sha1cd v0.3.2/go.mod h1:zQWigSxVmsHEZow5qaLtPYxpcKMMQpa09ixqBxuCS6A= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -175,15 +137,10 @@ github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUc github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= -github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= github.com/shirou/gopsutil/v4 v4.25.6 h1:kLysI2JsKorfaFPcYmcJqbzROzsBWEOAtw6A7dIfqXs= github.com/shirou/gopsutil/v4 v4.25.6/go.mod h1:PfybzyydfZcN+JMMjkF6Zb8Mq1A/VcogFFg7hj50W9c= -github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/skeema/knownhosts v1.3.1 h1:X2osQ+RAjK76shCbvhHHHVl3ZlgDm8apHEHFqRjnBY8= -github.com/skeema/knownhosts v1.3.1/go.mod h1:r7KTdC8l4uxWRyK2TpQZ/1o5HaSzh06ePQNxPwTcfiY= github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU= github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4= github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= @@ -192,8 +149,6 @@ github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3A github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= @@ -203,8 +158,6 @@ github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFA github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= -github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= -github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= @@ -228,38 +181,28 @@ go.opentelemetry.io/otel/trace v1.40.0/go.mod h1:zeAhriXecNGP/s2SEG3+Y8X9ujcJOTq go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A= go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= -golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= -golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= -golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= +golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/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-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= -golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= +golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44= golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 h1:BIRfGDEjiHRrk0QKZe3Xv2ieMhtgRGeLcZQ0mIVn4EY= google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5/go.mod h1:j3QtIyytwqGr1JUDtYXwtMXWPKsEa5LtzIFN1Wn5WvE= @@ -270,13 +213,8 @@ google.golang.org/grpc v1.75.1/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= -gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 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/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/rpm/parse_test.go b/rpm/parse_test.go index 09bcf76..6030051 100644 --- a/rpm/parse_test.go +++ b/rpm/parse_test.go @@ -4,182 +4,25 @@ import ( "testing" ) -func TestParseList(t *testing.T) { - input := "bash\t5.1.8-6.el9\tThe GNU Bourne Again shell\ncurl\t7.76.1-23.el9\tA utility for getting files from remote servers\n" - pkgs := parseList(input) - if len(pkgs) != 2 { - t.Fatalf("expected 2 packages, got %d", len(pkgs)) - } - if pkgs[0].Name != "bash" || pkgs[0].Version != "5.1.8-6.el9" { - t.Errorf("unexpected pkg[0]: %+v", pkgs[0]) - } - if pkgs[0].Description != "The GNU Bourne Again shell" { - t.Errorf("unexpected description: %q", pkgs[0].Description) - } - if !pkgs[0].Installed { - t.Error("expected Installed=true") - } -} - -func TestParseInfo(t *testing.T) { - input := `Name : bash -Version : 5.1.8 -Release : 6.el9 -Architecture: x86_64 -Install Date: Mon 01 Jan 2024 12:00:00 AM UTC -Group : System Environment/Shells -Size : 7896043 -License : GPLv3+ -Signature : RSA/SHA256, Mon 01 Jan 2024 12:00:00 AM UTC, Key ID abc123 -Source RPM : bash-5.1.8-6.el9.src.rpm -Build Date : Mon 01 Jan 2024 12:00:00 AM UTC -Build Host : builder.example.com -Packager : CentOS Buildsys -Vendor : CentOS -URL : https://www.gnu.org/software/bash -Summary : The GNU Bourne Again shell -Description : -The GNU Bourne Again shell (Bash) is a shell or command language -interpreter that is compatible with the Bourne shell (sh). -` - p := parseInfo(input) - if p == nil { - t.Fatal("expected package, got nil") - } - if p.Name != "bash" { - t.Errorf("Name = %q, want bash", p.Name) - } - if p.Version != "5.1.8-6.el9" { - t.Errorf("Version = %q, want 5.1.8-6.el9", p.Version) - } - if p.Arch != "x86_64" { - t.Errorf("Arch = %q, want x86_64", p.Arch) - } - if p.Description != "The GNU Bourne Again shell" { - t.Errorf("Description = %q, want 'The GNU Bourne Again shell'", p.Description) - } -} - func TestNormalizeName(t *testing.T) { tests := []struct { - input, want string + input string + want string }{ + {"nginx", "nginx"}, {"nginx.x86_64", "nginx"}, - {"curl.aarch64", "curl"}, - {"bash.noarch", "bash"}, - {"python3", "python3"}, - } - for _, tt := range tests { - got := normalizeName(tt.input) - if got != tt.want { - t.Errorf("normalizeName(%q) = %q, want %q", tt.input, got, tt.want) - } - } -} - -func TestParseArchSuffix(t *testing.T) { - tests := []struct { - input, wantName, wantArch string - }{ - {"nginx.x86_64", "nginx", "x86_64"}, - {"bash", "bash", ""}, - {"glibc.i686", "glibc", "i686"}, - } - for _, tt := range tests { - name, arch := parseArchSuffix(tt.input) - if name != tt.wantName || arch != tt.wantArch { - t.Errorf("parseArchSuffix(%q) = (%q, %q), want (%q, %q)", tt.input, name, arch, tt.wantName, tt.wantArch) - } - } -} - -// --- Edge case tests --- - -func TestParseListEmpty(t *testing.T) { - pkgs := parseList("") - if len(pkgs) != 0 { - t.Errorf("expected 0 packages from empty input, got %d", len(pkgs)) - } -} - -func TestParseListSinglePackage(t *testing.T) { - input := "curl\t7.76.1-23.el9\tA utility\n" - pkgs := parseList(input) - if len(pkgs) != 1 { - t.Fatalf("expected 1 package, got %d", len(pkgs)) - } - if pkgs[0].Name != "curl" { - t.Errorf("Name = %q, want curl", pkgs[0].Name) - } -} - -func TestParseListNoDescription(t *testing.T) { - input := "bash\t5.1.8-6.el9\n" - pkgs := parseList(input) - if len(pkgs) != 1 { - t.Fatalf("expected 1 package, got %d", len(pkgs)) - } - if pkgs[0].Description != "" { - t.Errorf("Description = %q, want empty", pkgs[0].Description) - } -} - -func TestParseListMalformedLines(t *testing.T) { - input := "bash\t5.1.8-6.el9\tShell\nno-tab-here\ncurl\t7.76.1\tHTTP tool\n" - pkgs := parseList(input) - if len(pkgs) != 2 { - t.Fatalf("expected 2 packages (skip malformed), got %d", len(pkgs)) - } -} - -func TestParseInfoEmpty(t *testing.T) { - p := parseInfo("") - if p != nil { - t.Errorf("expected nil from empty input, got %+v", p) - } -} - -func TestParseInfoNoName(t *testing.T) { - input := `Version : 1.0 -Architecture: x86_64 -` - p := parseInfo(input) - if p != nil { - t.Errorf("expected nil when no Name field, got %+v", p) - } -} - -func TestParseInfoArchField(t *testing.T) { - // Test both "Architecture" and "Arch" key forms - input := `Name : test -Version : 1.0 -Release : 1.el9 -Arch : aarch64 -Summary : Test package -` - p := parseInfo(input) - if p == nil { - t.Fatal("expected non-nil package") - } - if p.Arch != "aarch64" { - t.Errorf("Arch = %q, want aarch64", p.Arch) - } -} - -func TestNormalizeNameEdgeCases(t *testing.T) { - tests := []struct { - input, want string - }{ + {"curl.noarch", "curl"}, + {"kernel.aarch64", "kernel"}, + {"bash.i686", "bash"}, + {"glibc.i386", "glibc"}, + {"libfoo.armv7hl", "libfoo"}, + {"module.ppc64le", "module"}, + {"app.s390x", "app"}, + {"source.src", "source"}, + {"nodot", "nodot"}, {"", ""}, - {"pkg.unknown.ext", "pkg.unknown.ext"}, - {"name.with.dots.x86_64", "name.with.dots"}, - {"python3.11", "python3.11"}, - {"glibc.s390x", "glibc"}, - {"kernel.src", "kernel"}, - {".x86_64", ""}, - {"pkg.ppc64le", "pkg"}, - {"pkg.armv7hl", "pkg"}, - {"pkg.i386", "pkg"}, + {"pkg.unknown", "pkg.unknown"}, + {"multi.dot.x86_64", "multi.dot"}, } for _, tt := range tests { t.Run(tt.input, func(t *testing.T) { @@ -191,30 +34,202 @@ func TestNormalizeNameEdgeCases(t *testing.T) { } } -func TestParseArchSuffixEdgeCases(t *testing.T) { +func TestParseArchSuffix(t *testing.T) { tests := []struct { - input, wantName, wantArch string + name string + input string + wantName string + wantArch string }{ - {"", "", ""}, - {"pkg.i386", "pkg", "i386"}, - {"pkg.ppc64le", "pkg", "ppc64le"}, - {"pkg.s390x", "pkg", "s390x"}, - {"pkg.armv7hl", "pkg", "armv7hl"}, - {"pkg.src", "pkg", "src"}, - {"pkg.aarch64", "pkg", "aarch64"}, - {"pkg.noarch", "pkg", "noarch"}, - {"pkg.unknown", "pkg.unknown", ""}, - {"name.with.many.dots.noarch", "name.with.many.dots", "noarch"}, - {".noarch", "", "noarch"}, - {"pkg.x86_64.extra", "pkg.x86_64.extra", ""}, + {"x86_64", "nginx.x86_64", "nginx", "x86_64"}, + {"noarch", "bash.noarch", "bash", "noarch"}, + {"aarch64", "kernel.aarch64", "kernel", "aarch64"}, + {"i686", "glibc.i686", "glibc", "i686"}, + {"i386", "compat.i386", "compat", "i386"}, + {"armv7hl", "lib.armv7hl", "lib", "armv7hl"}, + {"ppc64le", "app.ppc64le", "app", "ppc64le"}, + {"s390x", "z.s390x", "z", "s390x"}, + {"src", "pkg.src", "pkg", "src"}, + {"no dot", "curl", "curl", ""}, + {"unknown arch", "pkg.foobar", "pkg.foobar", ""}, + {"empty", "", "", ""}, + {"multiple dots", "a.b.x86_64", "a.b", "x86_64"}, + {"dot but not arch", "libfoo.so", "libfoo.so", ""}, } for _, tt := range tests { - t.Run(tt.input, func(t *testing.T) { - name, arch := parseArchSuffix(tt.input) - if name != tt.wantName || arch != tt.wantArch { + t.Run(tt.name, func(t *testing.T) { + gotName, gotArch := parseArchSuffix(tt.input) + if gotName != tt.wantName || gotArch != tt.wantArch { t.Errorf("parseArchSuffix(%q) = (%q, %q), want (%q, %q)", - tt.input, name, arch, tt.wantName, tt.wantArch) + tt.input, gotName, gotArch, tt.wantName, tt.wantArch) } }) } } + +func TestParseList(t *testing.T) { + input := "bash\t5.2.15-3.fc38\tThe GNU Bourne Again shell\n" + + "curl\t8.0.1-1.fc38\tA utility for getting files from remote servers\n" + pkgs := parseList(input) + if len(pkgs) != 2 { + t.Fatalf("expected 2 packages, got %d", len(pkgs)) + } + if pkgs[0].Name != "bash" || pkgs[0].Version != "5.2.15-3.fc38" { + t.Errorf("unexpected first package: %+v", pkgs[0]) + } + if pkgs[0].Description != "The GNU Bourne Again shell" { + t.Errorf("unexpected description: %q", pkgs[0].Description) + } + if !pkgs[0].Installed { + t.Error("expected Installed=true") + } +} + +func TestParseListEdgeCases(t *testing.T) { + t.Run("empty input", func(t *testing.T) { + pkgs := parseList("") + if len(pkgs) != 0 { + t.Errorf("expected 0 packages, got %d", len(pkgs)) + } + }) + + t.Run("whitespace only", func(t *testing.T) { + pkgs := parseList(" \n\n \n") + if len(pkgs) != 0 { + t.Errorf("expected 0 packages, got %d", len(pkgs)) + } + }) + + t.Run("single entry no description", func(t *testing.T) { + pkgs := parseList("vim\t9.0.1\n") + if len(pkgs) != 1 { + t.Fatalf("expected 1 package, got %d", len(pkgs)) + } + if pkgs[0].Name != "vim" || pkgs[0].Version != "9.0.1" { + t.Errorf("unexpected package: %+v", pkgs[0]) + } + if pkgs[0].Description != "" { + t.Errorf("expected empty description, got %q", pkgs[0].Description) + } + }) + + t.Run("single field line skipped", func(t *testing.T) { + pkgs := parseList("justname\n") + if len(pkgs) != 0 { + t.Errorf("expected 0 packages (need >=2 tab fields), got %d", len(pkgs)) + } + }) + + t.Run("description with tabs", func(t *testing.T) { + pkgs := parseList("pkg\t1.0\tA description\twith tabs\n") + if len(pkgs) != 1 { + t.Fatalf("expected 1 package, got %d", len(pkgs)) + } + // SplitN with 3 means the third part includes everything after the second tab + if pkgs[0].Description != "A description\twith tabs" { + t.Errorf("unexpected description: %q", pkgs[0].Description) + } + }) +} + +func TestParseInfo(t *testing.T) { + input := `Name : curl +Version : 8.0.1 +Release : 1.fc38 +Architecture: x86_64 +Summary : A utility for getting files from remote servers +` + pkg := parseInfo(input) + if pkg == nil { + t.Fatal("expected non-nil package") + } + if pkg.Name != "curl" { + t.Errorf("expected name 'curl', got %q", pkg.Name) + } + if pkg.Version != "8.0.1-1.fc38" { + t.Errorf("expected version '8.0.1-1.fc38', got %q", pkg.Version) + } + if pkg.Arch != "x86_64" { + t.Errorf("expected arch 'x86_64', got %q", pkg.Arch) + } + if pkg.Description != "A utility for getting files from remote servers" { + t.Errorf("unexpected description: %q", pkg.Description) + } +} + +func TestParseInfoEdgeCases(t *testing.T) { + t.Run("empty input", func(t *testing.T) { + pkg := parseInfo("") + if pkg != nil { + t.Error("expected nil for empty input") + } + }) + + t.Run("name only", func(t *testing.T) { + pkg := parseInfo("Name : bash\n") + if pkg == nil { + t.Fatal("expected non-nil") + } + if pkg.Name != "bash" { + t.Errorf("expected bash, got %q", pkg.Name) + } + }) + + t.Run("no name returns nil", func(t *testing.T) { + pkg := parseInfo("Version : 1.0\nArch : x86_64\n") + if pkg != nil { + t.Error("expected nil when no Name field") + } + }) + + t.Run("version without release", func(t *testing.T) { + pkg := parseInfo("Name : test\nVersion : 2.5\n") + if pkg == nil { + t.Fatal("expected non-nil") + } + if pkg.Version != "2.5" { + t.Errorf("expected version '2.5', got %q", pkg.Version) + } + }) + + t.Run("release without version", func(t *testing.T) { + // Release only appends if version is non-empty + pkg := parseInfo("Name : test\nRelease : 3.el9\n") + if pkg == nil { + t.Fatal("expected non-nil") + } + if pkg.Version != "" { + t.Errorf("expected empty version (release alone shouldn't set it), got %q", pkg.Version) + } + }) + + t.Run("arch key variant", func(t *testing.T) { + pkg := parseInfo("Name : test\nArch : aarch64\n") + if pkg == nil { + t.Fatal("expected non-nil") + } + if pkg.Arch != "aarch64" { + t.Errorf("expected aarch64, got %q", pkg.Arch) + } + }) + + t.Run("no colon lines ignored", func(t *testing.T) { + pkg := parseInfo("Name : test\nrandom line\nSummary : A tool\n") + if pkg == nil { + t.Fatal("expected non-nil") + } + if pkg.Description != "A tool" { + t.Errorf("unexpected description: %q", pkg.Description) + } + }) + + t.Run("value with colons", func(t *testing.T) { + pkg := parseInfo("Name : myapp\nSummary : A tool: does things: well\n") + if pkg == nil { + t.Fatal("expected non-nil") + } + if pkg.Description != "A tool: does things: well" { + t.Errorf("unexpected description: %q", pkg.Description) + } + }) +}