[WIP] v0.7.0
Some checks failed
ci/woodpecker/push/go-lint Pipeline failed

This commit is contained in:
2025-01-14 09:42:43 -06:00
parent aee513f786
commit 5c2bfcc940
34 changed files with 1072 additions and 353 deletions

View File

@ -2,6 +2,8 @@ package apt
import (
"fmt"
"regexp"
"strings"
"git.andrewnw.xyz/CyberShell/backy/pkg/pkgman/pkgcommon"
)
@ -10,6 +12,7 @@ import (
type AptManager struct {
useAuth bool // Whether to use an authentication command
authCommand string // The authentication command, e.g., "sudo"
Parser pkgcommon.PackageParser
}
// DefaultAuthCommand is the default command used for authentication.
@ -62,6 +65,14 @@ func (a *AptManager) Upgrade(pkg, version string) (string, []string) {
return baseCmd, baseArgs
}
// CheckVersion returns the command and arguments for checking the info of a specific package.
func (a *AptManager) CheckVersion(pkg, version string) (string, []string) {
baseCmd := a.prependAuthCommand("apt-cache")
baseArgs := []string{"policy", pkg}
return baseCmd, baseArgs
}
// UpgradeAll returns the command and arguments for upgrading all packages.
func (a *AptManager) UpgradeAll() (string, []string) {
baseCmd := a.prependAuthCommand(DefaultPackageCommand)
@ -93,3 +104,32 @@ func (a *AptManager) SetUseAuth(useAuth bool) {
func (a *AptManager) SetAuthCommand(authCommand string) {
a.authCommand = authCommand
}
// SetPackageParser assigns a PackageParser.
func (a *AptManager) SetPackageParser(parser pkgcommon.PackageParser) {
a.Parser = parser
}
// Parse parses the apt-cache policy output to extract Installed and Candidate versions.
func (a *AptManager) Parse(output string) (*pkgcommon.PackageVersion, error) {
// Check for error message in the output
if strings.Contains(output, "Unable to locate package") {
return nil, fmt.Errorf("error: %s", strings.TrimSpace(output))
}
reInstalled := regexp.MustCompile(`Installed:\s*([^\s]+)`)
reCandidate := regexp.MustCompile(`Candidate:\s*([^\s]+)`)
installedMatch := reInstalled.FindStringSubmatch(output)
candidateMatch := reCandidate.FindStringSubmatch(output)
if len(installedMatch) < 2 || len(candidateMatch) < 2 {
return nil, fmt.Errorf("failed to parse Installed or Candidate versions from apt output. check package name")
}
return &pkgcommon.PackageVersion{
Installed: strings.TrimSpace(installedMatch[1]),
Candidate: strings.TrimSpace(candidateMatch[1]),
Match: installedMatch[1] == candidateMatch[1],
}, nil
}

View File

@ -2,6 +2,8 @@ package dnf
import (
"fmt"
"regexp"
"strings"
"git.andrewnw.xyz/CyberShell/backy/pkg/pkgman/pkgcommon"
)
@ -74,6 +76,50 @@ func (y *DnfManager) UpgradeAll() (string, []string) {
return baseCmd, baseArgs
}
// CheckVersion returns the command and arguments for checking the info of a specific package.
func (d *DnfManager) CheckVersion(pkg, version string) (string, []string) {
baseCmd := d.prependAuthCommand("dnf")
baseArgs := []string{"info", pkg}
return baseCmd, baseArgs
}
// Parse parses the dnf info output to extract Installed and Candidate versions.
func (d DnfManager) Parse(output string) (*pkgcommon.PackageVersion, error) {
// Check for error message in the output
if strings.Contains(output, "No matching packages to list") {
return nil, fmt.Errorf("error: package not listed")
}
// Define regular expressions to capture installed and available versions
reInstalled := regexp.MustCompile(`(?m)^Installed packages\s*Name\s*:\s*\S+\s*Epoch\s*:\s*\S+\s*Version\s*:\s*([^\s]+)\s*Release\s*:\s*([^\s]+)`)
reAvailable := regexp.MustCompile(`(?m)^Available packages\s*Name\s*:\s*\S+\s*Epoch\s*:\s*\S+\s*Version\s*:\s*([^\s]+)\s*Release\s*:\s*([^\s]+)`)
installedMatch := reInstalled.FindStringSubmatch(output)
candidateMatch := reAvailable.FindStringSubmatch(output)
installedVersion := ""
candidateVersion := ""
if len(installedMatch) >= 3 {
installedVersion = fmt.Sprintf("%s-%s", installedMatch[1], installedMatch[2])
}
if len(candidateMatch) >= 3 {
candidateVersion = fmt.Sprintf("%s-%s", candidateMatch[1], candidateMatch[2])
}
if installedVersion == "" && candidateVersion == "" {
return nil, fmt.Errorf("failed to parse versions from dnf output")
}
return &pkgcommon.PackageVersion{
Installed: installedVersion,
Candidate: candidateVersion,
}, nil
}
// prependAuthCommand prepends the authentication command if UseAuth is true.
func (y *DnfManager) prependAuthCommand(baseCmd string) string {
if y.useAuth {

View File

@ -2,3 +2,16 @@ package pkgcommon
// PackageManagerOption defines a functional option for configuring a PackageManager.
type PackageManagerOption func(interface{})
// PackageParser defines an interface for parsing package version information.
type PackageParser interface {
Parse(output string) (*PackageVersion, error)
}
// PackageVersion represents the installed and candidate versions of a package.
type PackageVersion struct {
Installed string
Candidate string
Match bool
Message string
}

View File

@ -15,7 +15,8 @@ type PackageManager interface {
Remove(pkg string, args []string) (string, []string)
Upgrade(pkg, version string) (string, []string) // Upgrade a specific package
UpgradeAll() (string, []string)
CheckVersion(pkg, version string) (string, []string)
Parse(output string) (*pkgcommon.PackageVersion, error)
// Configure applies functional options to customize the package manager.
Configure(options ...pkgcommon.PackageManagerOption)
}
@ -67,6 +68,8 @@ func WithoutAuth() pkgcommon.PackageManagerOption {
// ConfigurablePackageManager defines methods for setting configuration options.
type ConfigurablePackageManager interface {
pkgcommon.PackageParser
SetUseAuth(useAuth bool)
SetAuthCommand(authCommand string)
SetPackageParser(parser pkgcommon.PackageParser)
}

View File

@ -2,6 +2,7 @@ package yum
import (
"fmt"
"regexp"
"git.andrewnw.xyz/CyberShell/backy/pkg/pkgman/pkgcommon"
)
@ -74,6 +75,43 @@ func (y *YumManager) UpgradeAll() (string, []string) {
return baseCmd, baseArgs
}
// CheckVersion returns the command and arguments for checking the info of a specific package.
func (y *YumManager) CheckVersion(pkg, version string) (string, []string) {
baseCmd := y.prependAuthCommand("yum")
baseArgs := []string{"info", pkg}
return baseCmd, baseArgs
}
// Parse parses the dnf info output to extract Installed and Candidate versions.
func (y YumManager) Parse(output string) (*pkgcommon.PackageVersion, error) {
reInstalled := regexp.MustCompile(`(?m)^Installed Packages\s*Name\s*:\s*\S+\s*Version\s*:\s*([^\s]+)\s*Release\s*:\s*([^\s]+)`)
reAvailable := regexp.MustCompile(`(?m)^Available Packages\s*Name\s*:\s*\S+\s*Version\s*:\s*([^\s]+)\s*Release\s*:\s*([^\s]+)`)
installedMatch := reInstalled.FindStringSubmatch(output)
candidateMatch := reAvailable.FindStringSubmatch(output)
installedVersion := ""
candidateVersion := ""
if len(installedMatch) >= 3 {
installedVersion = fmt.Sprintf("%s-%s", installedMatch[1], installedMatch[2])
}
if len(candidateMatch) >= 3 {
candidateVersion = fmt.Sprintf("%s-%s", candidateMatch[1], candidateMatch[2])
}
if installedVersion == "" && candidateVersion == "" {
return nil, fmt.Errorf("failed to parse versions from dnf output")
}
return &pkgcommon.PackageVersion{
Installed: installedVersion,
Candidate: candidateVersion,
}, nil
}
// prependAuthCommand prepends the authentication command if UseAuth is true.
func (y *YumManager) prependAuthCommand(baseCmd string) string {
if y.useAuth {