backy/pkg/pkgman/apt/apt.go

165 lines
4.9 KiB
Go

package apt
import (
"bufio"
"bytes"
"fmt"
"strings"
packagemanagercommon "git.andrewnw.xyz/CyberShell/backy/pkg/pkgman/common"
)
// AptManager implements PackageManager for systems using APT.
type AptManager struct {
useAuth bool // Whether to use an authentication command
authCommand string // The authentication command, e.g., "sudo"
Parser packagemanagercommon.PackageParser
}
// DefaultAuthCommand is the default command used for authentication.
const DefaultAuthCommand = "sudo"
const DefaultPackageCommand = "apt-get"
// NewAptManager creates a new AptManager with default settings.
func NewAptManager() *AptManager {
return &AptManager{
useAuth: true,
authCommand: DefaultAuthCommand,
}
}
// Install returns the command and arguments for installing a package.
func (a *AptManager) Install(pkgs []packagemanagercommon.Package, args []string) (string, []string) {
baseCmd := a.prependAuthCommand(DefaultPackageCommand)
baseArgs := []string{"update", "&&", baseCmd, "install", "-y"}
for _, p := range pkgs {
baseArgs = append(baseArgs, p.Name)
}
if args != nil {
baseArgs = append(baseArgs, args...)
}
return baseCmd, baseArgs
}
// Remove returns the command and arguments for removing a package.
func (a *AptManager) Remove(pkgs []packagemanagercommon.Package, args []string) (string, []string) {
baseCmd := a.prependAuthCommand(DefaultPackageCommand)
baseArgs := []string{"remove", "-y"}
for _, p := range pkgs {
baseArgs = append(baseArgs, p.Name)
}
if args != nil {
baseArgs = append(baseArgs, args...)
}
return baseCmd, baseArgs
}
func (a *AptManager) Upgrade(pkgs []packagemanagercommon.Package) (string, []string) {
baseCmd := a.prependAuthCommand(DefaultPackageCommand)
baseArgs := []string{"update", "&&", baseCmd, "install", "--only-upgrade", "-y"}
for _, p := range pkgs {
baseArgs = append(baseArgs, p.Name)
}
return baseCmd, baseArgs
}
func (a *AptManager) CheckVersion(pkgs []packagemanagercommon.Package) (string, []string) {
baseCmd := a.prependAuthCommand("apt-cache")
baseArgs := []string{"policy"}
for _, p := range pkgs {
baseArgs = append(baseArgs, p.Name)
}
return baseCmd, baseArgs
}
// UpgradeAll returns the command and arguments for upgrading all packages.
func (a *AptManager) UpgradeAll() (string, []string) {
baseCmd := a.prependAuthCommand(DefaultPackageCommand)
baseArgs := []string{"update", "&&", baseCmd, "upgrade", "-y"}
return baseCmd, baseArgs
}
// Configure applies functional options to customize the package manager.
func (a *AptManager) Configure(options ...packagemanagercommon.PackageManagerOption) {
for _, opt := range options {
opt(a)
}
}
// prependAuthCommand prepends the authentication command if UseAuth is true.
func (a *AptManager) prependAuthCommand(baseCmd string) string {
if a.useAuth {
return a.authCommand + " " + baseCmd
}
return baseCmd
}
// SetUseAuth enables or disables authentication.
func (a *AptManager) SetUseAuth(useAuth bool) {
a.useAuth = useAuth
}
// SetAuthCommand sets the authentication command.
func (a *AptManager) SetAuthCommand(authCommand string) {
a.authCommand = authCommand
}
// Parse parses the apt-cache policy output to extract Installed and Candidate versions.
func (a *AptManager) ParseRemotePackageManagerVersionOutput(output string) ([]packagemanagercommon.Package, []error) {
var (
packageName string
installedString string
candidateString string
countRelevantLines int
)
// Check for error message in the output
if strings.Contains(output, "Unable to locate package") {
return nil, []error{fmt.Errorf("error: %s", strings.TrimSpace(output))}
}
packages := []packagemanagercommon.Package{}
outputBuf := bytes.NewBufferString(output)
outputScan := bufio.NewScanner(outputBuf)
for outputScan.Scan() {
line := outputScan.Text()
if !strings.HasPrefix(line, " ") && strings.HasSuffix(line, ":") {
// count++
packageName = strings.TrimSpace(strings.TrimSuffix(line, ":"))
}
if strings.Contains(line, "Installed:") {
countRelevantLines++
installedString = strings.TrimPrefix(strings.TrimSpace(line), "Installed:")
}
if strings.Contains(line, "Candidate:") {
countRelevantLines++
candidateString = strings.TrimPrefix(strings.TrimSpace(line), "Candidate:")
}
if countRelevantLines == 2 {
countRelevantLines = 0
packages = append(packages, packagemanagercommon.Package{
Name: packageName,
VersionCheck: packagemanagercommon.PackageVersion{
Installed: strings.TrimSpace(installedString),
Candidate: strings.TrimSpace(candidateString),
Match: installedString == candidateString,
}},
)
}
}
return packages, nil
}
func SearchPackages(pkgs []string, version string) (string, []string) {
baseCommand := "dpkg-query"
baseArgs := []string{"-W", "-f='${Package}\t${Architecture}\t${db:Status-Status}\t${Version}\t${Installed-Size}\t${Binary:summary}\n'"}
baseArgs = append(baseArgs, pkgs...)
return baseCommand, baseArgs
}