mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-08-02 11:38:30 -04:00
e4657aa5f9
- Added UI component & popout settings to manage ignored packages - Added CLI support available in danklinux docs Fixes: #2827 Closes: #2344, #1741 Port 1.5
103 lines
3.1 KiB
Go
103 lines
3.1 KiB
Go
package sysupdate
|
|
|
|
import (
|
|
"context"
|
|
"encoding/xml"
|
|
"errors"
|
|
"fmt"
|
|
"os/exec"
|
|
"strings"
|
|
)
|
|
|
|
func init() {
|
|
RegisterSystemBackend(func() Backend { return &zypperBackend{} })
|
|
}
|
|
|
|
type zypperBackend struct{}
|
|
|
|
func (zypperBackend) ID() string { return "zypper" }
|
|
func (zypperBackend) DisplayName() string { return "Zypper" }
|
|
func (zypperBackend) Repo() RepoKind { return RepoSystem }
|
|
func (zypperBackend) NeedsAuth() bool { return true }
|
|
func (zypperBackend) RunsInTerminal() bool { return false }
|
|
func (zypperBackend) IsAvailable(_ context.Context) bool { return commandExists("zypper") }
|
|
|
|
type zypperUpdateList struct {
|
|
XMLName xml.Name `xml:"stream"`
|
|
Updates []zypperUpdate `xml:"update-list>update"`
|
|
}
|
|
|
|
type zypperUpdate struct {
|
|
Name string `xml:"name,attr"`
|
|
Edition string `xml:"edition,attr"`
|
|
EditionOld string `xml:"edition-old,attr"`
|
|
Kind string `xml:"kind,attr"`
|
|
}
|
|
|
|
func (zypperBackend) CheckUpdates(ctx context.Context) ([]Package, error) {
|
|
cmd := exec.CommandContext(ctx, "zypper", "--non-interactive", "--xmlout", "list-updates")
|
|
out, err := cmd.Output()
|
|
if err != nil {
|
|
if exitErr, ok := errors.AsType[*exec.ExitError](err); ok {
|
|
switch exitErr.ExitCode() {
|
|
case 100, 101, 102, 103:
|
|
err = nil
|
|
}
|
|
}
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
return parseZypperXML(out)
|
|
}
|
|
|
|
func parseZypperXML(out []byte) ([]Package, error) {
|
|
var list zypperUpdateList
|
|
if err := xml.Unmarshal(out, &list); err != nil {
|
|
return nil, err
|
|
}
|
|
pkgs := make([]Package, 0, len(list.Updates))
|
|
for _, u := range list.Updates {
|
|
if u.Kind != "" && u.Kind != "package" {
|
|
continue
|
|
}
|
|
pkgs = append(pkgs, Package{
|
|
Name: u.Name,
|
|
Repo: RepoSystem,
|
|
Backend: "zypper",
|
|
FromVersion: u.EditionOld,
|
|
ToVersion: u.Edition,
|
|
})
|
|
}
|
|
return pkgs, nil
|
|
}
|
|
|
|
func (zypperBackend) Upgrade(ctx context.Context, opts UpgradeOptions, onLine func(string)) error {
|
|
if opts.DryRun {
|
|
return Run(ctx, []string{"zypper", "--non-interactive", "--dry-run", "update"}, RunOptions{OnLine: onLine})
|
|
}
|
|
if !BackendHasTargets(zypperBackend{}, opts.Targets, opts.IncludeAUR, opts.IncludeFlatpak) {
|
|
return nil
|
|
}
|
|
return Run(ctx, zypperUpgradeArgv(opts), RunOptions{OnLine: onLine, AttachStdio: opts.AttachStdio})
|
|
}
|
|
|
|
func zypperUpgradeArgv(opts UpgradeOptions) []string {
|
|
ignored := shellSafeNames(opts.Ignored)
|
|
if len(ignored) == 0 {
|
|
return privilegedArgv(opts, "zypper", "--non-interactive", "update")
|
|
}
|
|
return privilegedArgv(opts, "sh", "-c", zypperLockScript(ignored))
|
|
}
|
|
|
|
// zypperLockScript locks ignored packages only for the update, leaving pre-existing user locks untouched.
|
|
func zypperLockScript(ignored []string) string {
|
|
names := strings.Join(ignored, " ")
|
|
return fmt.Sprintf(
|
|
`new=""; for p in %s; do grep -qsE "^solvable_name:[[:space:]]*$p$" /etc/zypp/locks || new="$new $p"; done; `+
|
|
`[ -n "$new" ] && zypper --non-interactive al $new; `+
|
|
`zypper --non-interactive update; rc=$?; `+
|
|
`[ -n "$new" ] && zypper --non-interactive rl $new; exit $rc`,
|
|
names)
|
|
}
|