mirror of
https://github.com/gogrlx/snack.git
synced 2026-04-02 05:08:42 -07:00
feat(flatpak): add VersionQuerier
This commit is contained in:
@@ -10,6 +10,7 @@ import (
|
|||||||
var (
|
var (
|
||||||
_ snack.Cleaner = (*Flatpak)(nil)
|
_ snack.Cleaner = (*Flatpak)(nil)
|
||||||
_ snack.RepoManager = (*Flatpak)(nil)
|
_ snack.RepoManager = (*Flatpak)(nil)
|
||||||
|
_ snack.VersionQuerier = (*Flatpak)(nil)
|
||||||
)
|
)
|
||||||
|
|
||||||
// Autoremove removes unused runtimes and extensions.
|
// Autoremove removes unused runtimes and extensions.
|
||||||
@@ -42,3 +43,25 @@ func (f *Flatpak) RemoveRepo(ctx context.Context, id string) error {
|
|||||||
defer f.Unlock()
|
defer f.Unlock()
|
||||||
return removeRepo(ctx, id)
|
return removeRepo(ctx, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LatestVersion returns the latest available version of a flatpak from
|
||||||
|
// configured remotes.
|
||||||
|
func (f *Flatpak) LatestVersion(ctx context.Context, pkg string) (string, error) {
|
||||||
|
return latestVersion(ctx, pkg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListUpgrades returns flatpaks that have newer versions available.
|
||||||
|
func (f *Flatpak) ListUpgrades(ctx context.Context) ([]snack.Package, error) {
|
||||||
|
return listUpgrades(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpgradeAvailable reports whether a newer version is available.
|
||||||
|
func (f *Flatpak) UpgradeAvailable(ctx context.Context, pkg string) (bool, error) {
|
||||||
|
return upgradeAvailable(ctx, pkg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// VersionCmp compares two version strings using basic semver comparison.
|
||||||
|
// Flatpak has no native version comparison tool.
|
||||||
|
func (f *Flatpak) VersionCmp(ctx context.Context, ver1, ver2 string) (int, error) {
|
||||||
|
return versionCmp(ctx, ver1, ver2)
|
||||||
|
}
|
||||||
|
|||||||
56
flatpak/capabilities_linux.go
Normal file
56
flatpak/capabilities_linux.go
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
//go:build linux
|
||||||
|
|
||||||
|
package flatpak
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/gogrlx/snack"
|
||||||
|
)
|
||||||
|
|
||||||
|
func latestVersion(ctx context.Context, pkg string) (string, error) {
|
||||||
|
out, err := run(ctx, []string{"remote-info", "flathub", pkg})
|
||||||
|
if err != nil {
|
||||||
|
if strings.Contains(err.Error(), "exit status 1") {
|
||||||
|
return "", fmt.Errorf("flatpak latestVersion %s: %w", pkg, snack.ErrNotFound)
|
||||||
|
}
|
||||||
|
return "", fmt.Errorf("flatpak latestVersion: %w", err)
|
||||||
|
}
|
||||||
|
// remote-info output is key:value like `flatpak info`
|
||||||
|
p := parseInfo(out)
|
||||||
|
if p == nil || p.Version == "" {
|
||||||
|
return "", fmt.Errorf("flatpak latestVersion %s: %w", pkg, snack.ErrNotFound)
|
||||||
|
}
|
||||||
|
return p.Version, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func listUpgrades(ctx context.Context) ([]snack.Package, error) {
|
||||||
|
out, err := run(ctx, []string{"remote-ls", "--updates", "--columns=name,application,version,origin"})
|
||||||
|
if err != nil {
|
||||||
|
// No updates available may produce an error on some versions
|
||||||
|
if strings.Contains(err.Error(), "No updates") {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("flatpak listUpgrades: %w", err)
|
||||||
|
}
|
||||||
|
return parseList(out), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func upgradeAvailable(ctx context.Context, pkg string) (bool, error) {
|
||||||
|
upgrades, err := listUpgrades(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
for _, u := range upgrades {
|
||||||
|
if u.Name == pkg || u.Description == pkg {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func versionCmp(_ context.Context, ver1, ver2 string) (int, error) {
|
||||||
|
return semverCmp(ver1, ver2), nil
|
||||||
|
}
|
||||||
25
flatpak/capabilities_other.go
Normal file
25
flatpak/capabilities_other.go
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
//go:build !linux
|
||||||
|
|
||||||
|
package flatpak
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/gogrlx/snack"
|
||||||
|
)
|
||||||
|
|
||||||
|
func latestVersion(_ context.Context, _ string) (string, error) {
|
||||||
|
return "", snack.ErrUnsupportedPlatform
|
||||||
|
}
|
||||||
|
|
||||||
|
func listUpgrades(_ context.Context) ([]snack.Package, error) {
|
||||||
|
return nil, snack.ErrUnsupportedPlatform
|
||||||
|
}
|
||||||
|
|
||||||
|
func upgradeAvailable(_ context.Context, _ string) (bool, error) {
|
||||||
|
return false, snack.ErrUnsupportedPlatform
|
||||||
|
}
|
||||||
|
|
||||||
|
func versionCmp(_ context.Context, _, _ string) (int, error) {
|
||||||
|
return 0, snack.ErrUnsupportedPlatform
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package flatpak
|
package flatpak
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/gogrlx/snack"
|
"github.com/gogrlx/snack"
|
||||||
@@ -127,3 +128,42 @@ func parseRemotes(output string) []snack.Repository {
|
|||||||
}
|
}
|
||||||
return repos
|
return repos
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// semverCmp does a basic semver-ish comparison.
|
||||||
|
// Returns -1 if a < b, 0 if equal, 1 if a > b.
|
||||||
|
func semverCmp(a, b string) int {
|
||||||
|
partsA := strings.Split(a, ".")
|
||||||
|
partsB := strings.Split(b, ".")
|
||||||
|
|
||||||
|
maxLen := len(partsA)
|
||||||
|
if len(partsB) > maxLen {
|
||||||
|
maxLen = len(partsB)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < maxLen; i++ {
|
||||||
|
var numA, numB int
|
||||||
|
if i < len(partsA) {
|
||||||
|
numA, _ = strconv.Atoi(stripNonNumeric(partsA[i]))
|
||||||
|
}
|
||||||
|
if i < len(partsB) {
|
||||||
|
numB, _ = strconv.Atoi(stripNonNumeric(partsB[i]))
|
||||||
|
}
|
||||||
|
if numA < numB {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
if numA > numB {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// stripNonNumeric keeps only leading digits from a string.
|
||||||
|
func stripNonNumeric(s string) string {
|
||||||
|
for i, c := range s {
|
||||||
|
if c < '0' || c > '9' {
|
||||||
|
return s[:i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user