merge: resolve pacman capabilities conflict (keep both interfaces)

This commit is contained in:
2026-02-28 07:07:21 +00:00
8 changed files with 39 additions and 0 deletions

View File

@@ -11,8 +11,12 @@ var (
_ snack.VersionQuerier = (*Apk)(nil) _ snack.VersionQuerier = (*Apk)(nil)
_ snack.Cleaner = (*Apk)(nil) _ snack.Cleaner = (*Apk)(nil)
_ snack.FileOwner = (*Apk)(nil) _ snack.FileOwner = (*Apk)(nil)
_ snack.DryRunner = (*Apk)(nil)
) )
// SupportsDryRun reports that apk honors [snack.WithDryRun] via --simulate.
func (a *Apk) SupportsDryRun() bool { return true }
// LatestVersion returns the latest available version from configured repositories. // LatestVersion returns the latest available version from configured repositories.
func (a *Apk) LatestVersion(ctx context.Context, pkg string) (string, error) { func (a *Apk) LatestVersion(ctx context.Context, pkg string) (string, error) {
return latestVersion(ctx, pkg) return latestVersion(ctx, pkg)

View File

@@ -196,6 +196,9 @@ func (a *Apt) ParseArch(name string) (string, string) {
return parseArch(name) return parseArch(name)
} }
// SupportsDryRun reports that apt honors [snack.WithDryRun] via --dry-run.
func (a *Apt) SupportsDryRun() bool { return true }
// Compile-time interface checks. // Compile-time interface checks.
var ( var (
_ snack.Manager = (*Apt)(nil) _ snack.Manager = (*Apt)(nil)
@@ -206,4 +209,5 @@ var (
_ snack.RepoManager = (*Apt)(nil) _ snack.RepoManager = (*Apt)(nil)
_ snack.KeyManager = (*Apt)(nil) _ snack.KeyManager = (*Apt)(nil)
_ snack.NameNormalizer = (*Apt)(nil) _ snack.NameNormalizer = (*Apt)(nil)
_ snack.DryRunner = (*Apt)(nil)
) )

View File

@@ -12,6 +12,7 @@ type Capabilities struct {
KeyManagement bool KeyManagement bool
Groups bool Groups bool
NameNormalize bool NameNormalize bool
DryRun bool
} }
// GetCapabilities probes a Manager for all optional interface support. // GetCapabilities probes a Manager for all optional interface support.
@@ -24,6 +25,7 @@ func GetCapabilities(m Manager) Capabilities {
_, km := m.(KeyManager) _, km := m.(KeyManager)
_, g := m.(Grouper) _, g := m.(Grouper)
_, nn := m.(NameNormalizer) _, nn := m.(NameNormalizer)
_, dr := m.(DryRunner)
return Capabilities{ return Capabilities{
VersionQuery: vq, VersionQuery: vq,
Hold: h, Hold: h,
@@ -33,5 +35,6 @@ func GetCapabilities(m Manager) Capabilities {
KeyManagement: km, KeyManagement: km,
Groups: g, Groups: g,
NameNormalize: nn, NameNormalize: nn,
DryRun: dr,
} }
} }

View File

@@ -17,8 +17,12 @@ var (
_ snack.Grouper = (*DNF)(nil) _ snack.Grouper = (*DNF)(nil)
_ snack.GroupQuerier = (*DNF)(nil) _ snack.GroupQuerier = (*DNF)(nil)
_ snack.NameNormalizer = (*DNF)(nil) _ snack.NameNormalizer = (*DNF)(nil)
_ snack.DryRunner = (*DNF)(nil)
) )
// SupportsDryRun reports that dnf honors [snack.WithDryRun] via --setopt=tsflags=test.
func (d *DNF) SupportsDryRun() bool { return true }
// LatestVersion returns the latest available version from configured repositories. // LatestVersion returns the latest available version from configured repositories.
func (d *DNF) LatestVersion(ctx context.Context, pkg string) (string, error) { func (d *DNF) LatestVersion(ctx context.Context, pkg string) (string, error) {
return latestVersion(ctx, pkg, d.v5) return latestVersion(ctx, pkg, d.v5)

View File

@@ -101,9 +101,13 @@ func (d *Dpkg) ParseArch(name string) (string, string) {
return parseArch(name) return parseArch(name)
} }
// SupportsDryRun reports that dpkg honors [snack.WithDryRun] via --simulate.
func (d *Dpkg) SupportsDryRun() bool { return true }
// Compile-time interface checks. // Compile-time interface checks.
var ( var (
_ snack.Manager = (*Dpkg)(nil) _ snack.Manager = (*Dpkg)(nil)
_ snack.FileOwner = (*Dpkg)(nil) _ snack.FileOwner = (*Dpkg)(nil)
_ snack.NameNormalizer = (*Dpkg)(nil) _ snack.NameNormalizer = (*Dpkg)(nil)
_ snack.DryRunner = (*Dpkg)(nil)
) )

View File

@@ -13,12 +13,16 @@ var (
_ snack.FileOwner = (*Pacman)(nil) _ snack.FileOwner = (*Pacman)(nil)
_ snack.Grouper = (*Pacman)(nil) _ snack.Grouper = (*Pacman)(nil)
_ snack.GroupQuerier = (*Pacman)(nil) _ snack.GroupQuerier = (*Pacman)(nil)
_ snack.DryRunner = (*Pacman)(nil)
) )
// NOTE: snack.Holder is not implemented for pacman. While pacman supports // NOTE: snack.Holder is not implemented for pacman. While pacman supports
// IgnorePkg in /etc/pacman.conf, there is no clean CLI command to hold/unhold // IgnorePkg in /etc/pacman.conf, there is no clean CLI command to hold/unhold
// packages. pacman-contrib provides some tooling but it's not standard. // packages. pacman-contrib provides some tooling but it's not standard.
// SupportsDryRun reports that pacman honors [snack.WithDryRun] via --print.
func (p *Pacman) SupportsDryRun() bool { return true }
// LatestVersion returns the latest available version from configured repositories. // LatestVersion returns the latest available version from configured repositories.
func (p *Pacman) LatestVersion(ctx context.Context, pkg string) (string, error) { func (p *Pacman) LatestVersion(ctx context.Context, pkg string) (string, error) {
return latestVersion(ctx, pkg) return latestVersion(ctx, pkg)

View File

@@ -207,3 +207,18 @@ type NameNormalizer interface {
// Returns the name without arch and the arch string. // Returns the name without arch and the arch string.
ParseArch(name string) (string, string) ParseArch(name string) (string, string)
} }
// DryRunner reports whether a Manager backend natively supports dry-run mode.
// Backends that implement this interface honor [WithDryRun] in Install, Remove,
// Purge, and Upgrade and pass the appropriate flag to the underlying CLI
// (e.g. apt-get --dry-run, apk --simulate, dnf --setopt=tsflags=test,
// pacman --print).
//
// Backends that do NOT implement this interface (snap, flatpak, rpm, ports)
// silently ignore [WithDryRun].
//
// Supported by: apt, apk, dnf, pacman.
type DryRunner interface {
// SupportsDryRun reports whether this backend honors [WithDryRun].
SupportsDryRun() bool
}

View File

@@ -91,6 +91,7 @@ func TestGetCapabilities_NilSafe(t *testing.T) {
assert.False(t, caps.KeyManagement) assert.False(t, caps.KeyManagement)
assert.False(t, caps.Groups) assert.False(t, caps.Groups)
assert.False(t, caps.NameNormalize) assert.False(t, caps.NameNormalize)
assert.False(t, caps.DryRun)
} }
func TestErrors(t *testing.T) { func TestErrors(t *testing.T) {