mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-04-30 01:22:06 -04:00
system update: general fixes to flatpak parsing
This commit is contained in:
@@ -45,7 +45,11 @@ func (aptBackend) Upgrade(ctx context.Context, opts UpgradeOptions, onLine func(
|
|||||||
OnLine: onLine,
|
OnLine: onLine,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
argv := []string{"pkexec", "env", "DEBIAN_FRONTEND=noninteractive", "LC_ALL=C", bin, "upgrade", "-y"}
|
names := pickTargetNames(opts.Targets, "apt", true)
|
||||||
|
if len(names) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
argv := append([]string{"pkexec", "env", "DEBIAN_FRONTEND=noninteractive", "LC_ALL=C", bin, "install", "-y", "--only-upgrade"}, names...)
|
||||||
return Run(ctx, argv, RunOptions{OnLine: onLine})
|
return Run(ctx, argv, RunOptions{OnLine: onLine})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,12 @@ func (b dnfBackend) Upgrade(ctx context.Context, opts UpgradeOptions, onLine fun
|
|||||||
if opts.DryRun {
|
if opts.DryRun {
|
||||||
return Run(ctx, []string{b.bin, "upgrade", "--assumeno"}, RunOptions{OnLine: onLine})
|
return Run(ctx, []string{b.bin, "upgrade", "--assumeno"}, RunOptions{OnLine: onLine})
|
||||||
}
|
}
|
||||||
return Run(ctx, []string{"pkexec", b.bin, "upgrade", "-y"}, RunOptions{OnLine: onLine})
|
names := pickTargetNames(opts.Targets, b.bin, true)
|
||||||
|
if len(names) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
argv := append([]string{"pkexec", b.bin, "upgrade", "-y"}, names...)
|
||||||
|
return Run(ctx, argv, RunOptions{OnLine: onLine})
|
||||||
}
|
}
|
||||||
|
|
||||||
func dnfListUpgrades(ctx context.Context, bin string) (string, error) {
|
func dnfListUpgrades(ctx context.Context, bin string) (string, error) {
|
||||||
@@ -88,14 +93,14 @@ func parseDnfList(text, backendID string, installed map[string]string) []Package
|
|||||||
}
|
}
|
||||||
nameArch := fields[0]
|
nameArch := fields[0]
|
||||||
version := fields[1]
|
version := fields[1]
|
||||||
switch nameArch {
|
dot := strings.LastIndex(nameArch, ".")
|
||||||
case "Available", "Upgrades":
|
if dot <= 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
name := nameArch
|
if !looksLikeRpmVersion(version) {
|
||||||
if dot := strings.LastIndex(nameArch, "."); dot > 0 {
|
continue
|
||||||
name = nameArch[:dot]
|
|
||||||
}
|
}
|
||||||
|
name := nameArch[:dot]
|
||||||
pkgs = append(pkgs, Package{
|
pkgs = append(pkgs, Package{
|
||||||
Name: nameArch,
|
Name: nameArch,
|
||||||
Repo: RepoSystem,
|
Repo: RepoSystem,
|
||||||
@@ -106,3 +111,15 @@ func parseDnfList(text, backendID string, installed map[string]string) []Package
|
|||||||
}
|
}
|
||||||
return pkgs
|
return pkgs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func looksLikeRpmVersion(s string) bool {
|
||||||
|
if s == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, r := range s {
|
||||||
|
if r >= '0' && r <= '9' {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|||||||
@@ -56,12 +56,15 @@ bash.x86_64 5.2.40-1.fc41 updates`,
|
|||||||
want: nil,
|
want: nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "package without arch suffix",
|
name: "skips dnf5 banner / column header lines",
|
||||||
input: "noarchpkg 1.2.3 updates",
|
input: `Updates available
|
||||||
|
Last metadata expiration check: 0:01:23 ago on Tue Apr 29 14:00:00 2026.
|
||||||
|
Package Version Repository Size
|
||||||
|
bash.x86_64 5.2.40-1.fc41 updates`,
|
||||||
backendID: "dnf",
|
backendID: "dnf",
|
||||||
installed: map[string]string{"noarchpkg": "1.2.0"},
|
installed: nil,
|
||||||
want: []Package{
|
want: []Package{
|
||||||
{Name: "noarchpkg", Repo: RepoSystem, Backend: "dnf", FromVersion: "1.2.0", ToVersion: "1.2.3"},
|
{Name: "bash.x86_64", Repo: RepoSystem, Backend: "dnf", FromVersion: "", ToVersion: "5.2.40-1.fc41"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,13 +70,32 @@ type flatpakInstalledEntry struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (flatpakBackend) Upgrade(ctx context.Context, opts UpgradeOptions, onLine func(string)) error {
|
func (flatpakBackend) Upgrade(ctx context.Context, opts UpgradeOptions, onLine func(string)) error {
|
||||||
argv := []string{"flatpak", "update", "-y", "--noninteractive"}
|
|
||||||
if opts.DryRun {
|
if opts.DryRun {
|
||||||
argv = []string{"flatpak", "update", "--no-deploy", "-y"}
|
return Run(ctx, []string{"flatpak", "update", "--no-deploy", "-y"}, RunOptions{OnLine: onLine})
|
||||||
}
|
}
|
||||||
|
refs := flatpakTargetRefs(opts.Targets)
|
||||||
|
if len(refs) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
argv := append([]string{"flatpak", "update", "-y", "--noninteractive"}, refs...)
|
||||||
return Run(ctx, argv, RunOptions{OnLine: onLine})
|
return Run(ctx, argv, RunOptions{OnLine: onLine})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func flatpakTargetRefs(targets []Package) []string {
|
||||||
|
out := make([]string, 0, len(targets))
|
||||||
|
for _, p := range targets {
|
||||||
|
if p.Backend != "flatpak" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ref := p.Ref
|
||||||
|
if ref == "" {
|
||||||
|
ref = p.Name
|
||||||
|
}
|
||||||
|
out = append(out, ref)
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
func parseFlatpakUpdates(text string, installed map[string]flatpakInstalledEntry) []Package {
|
func parseFlatpakUpdates(text string, installed map[string]flatpakInstalledEntry) []Package {
|
||||||
if text == "" {
|
if text == "" {
|
||||||
return nil
|
return nil
|
||||||
@@ -111,14 +130,25 @@ func parseFlatpakUpdates(text string, installed map[string]flatpakInstalledEntry
|
|||||||
key = appID + "//" + branch
|
key = appID + "//" + branch
|
||||||
}
|
}
|
||||||
inst := installed[key]
|
inst := installed[key]
|
||||||
|
|
||||||
|
if inst.commit != "" && commit != "" && strings.HasPrefix(commit, inst.commit) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
from, to := flatpakVersionPair(inst.version, inst.commit, version, commit)
|
from, to := flatpakVersionPair(inst.version, inst.commit, version, commit)
|
||||||
|
|
||||||
|
ref := appID
|
||||||
|
if branch != "" {
|
||||||
|
ref = appID + "//" + branch
|
||||||
|
}
|
||||||
|
|
||||||
pkgs = append(pkgs, Package{
|
pkgs = append(pkgs, Package{
|
||||||
Name: display,
|
Name: display,
|
||||||
Repo: RepoFlatpak,
|
Repo: RepoFlatpak,
|
||||||
Backend: "flatpak",
|
Backend: "flatpak",
|
||||||
FromVersion: from,
|
FromVersion: from,
|
||||||
ToVersion: to,
|
ToVersion: to,
|
||||||
|
Ref: ref,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return pkgs
|
return pkgs
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ func TestParseFlatpakUpdates(t *testing.T) {
|
|||||||
Backend: "flatpak",
|
Backend: "flatpak",
|
||||||
FromVersion: "8b16fa1a",
|
FromVersion: "8b16fa1a",
|
||||||
ToVersion: "43a1e5d2",
|
ToVersion: "43a1e5d2",
|
||||||
|
Ref: "com.discordapp.Discord//stable",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -47,6 +48,7 @@ func TestParseFlatpakUpdates(t *testing.T) {
|
|||||||
Backend: "flatpak",
|
Backend: "flatpak",
|
||||||
FromVersion: "1.4.2",
|
FromVersion: "1.4.2",
|
||||||
ToVersion: "1.5.0",
|
ToVersion: "1.5.0",
|
||||||
|
Ref: "com.example.App//stable",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -61,6 +63,7 @@ func TestParseFlatpakUpdates(t *testing.T) {
|
|||||||
Backend: "flatpak",
|
Backend: "flatpak",
|
||||||
FromVersion: "",
|
FromVersion: "",
|
||||||
ToVersion: "badcd4af",
|
ToVersion: "badcd4af",
|
||||||
|
Ref: "org.gnome.Platform//49",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -74,6 +77,7 @@ func TestParseFlatpakUpdates(t *testing.T) {
|
|||||||
Backend: "flatpak",
|
Backend: "flatpak",
|
||||||
FromVersion: "",
|
FromVersion: "",
|
||||||
ToVersion: "2.0",
|
ToVersion: "2.0",
|
||||||
|
Ref: "com.example.NoName//stable",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -87,9 +91,18 @@ func TestParseFlatpakUpdates(t *testing.T) {
|
|||||||
Backend: "flatpak",
|
Backend: "flatpak",
|
||||||
FromVersion: "",
|
FromVersion: "",
|
||||||
ToVersion: "1.0",
|
ToVersion: "1.0",
|
||||||
|
Ref: "org.real.App//stable",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "skips phantom updates where remote commit matches installed",
|
||||||
|
input: "com.phantom.App\t\tstable\tabc12345deadbeef\tPhantom",
|
||||||
|
installed: map[string]flatpakInstalledEntry{
|
||||||
|
"com.phantom.App//stable": {commit: "abc12345"},
|
||||||
|
},
|
||||||
|
want: nil,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
|
|||||||
@@ -43,17 +43,24 @@ func (b pacmanBackend) Upgrade(ctx context.Context, opts UpgradeOptions, onLine
|
|||||||
if opts.DryRun {
|
if opts.DryRun {
|
||||||
return Run(ctx, []string{"pacman", "-Sup"}, RunOptions{OnLine: onLine})
|
return Run(ctx, []string{"pacman", "-Sup"}, RunOptions{OnLine: onLine})
|
||||||
}
|
}
|
||||||
return Run(ctx, []string{"pkexec", "pacman", "-Syu", "--noconfirm"}, RunOptions{OnLine: onLine})
|
names := pickTargetNames(opts.Targets, b.ID(), opts.IncludeAUR)
|
||||||
|
if len(names) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
argv := append([]string{"pkexec", "pacman", "-Sy", "--noconfirm", "--needed"}, names...)
|
||||||
|
return Run(ctx, argv, RunOptions{OnLine: onLine})
|
||||||
}
|
}
|
||||||
|
|
||||||
type archHelperBackend struct {
|
type archHelperBackend struct {
|
||||||
id string
|
id string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b archHelperBackend) ID() string { return b.id }
|
func (b archHelperBackend) ID() string { return b.id }
|
||||||
func (b archHelperBackend) Repo() RepoKind { return RepoSystem }
|
func (b archHelperBackend) Repo() RepoKind { return RepoSystem }
|
||||||
func (b archHelperBackend) NeedsAuth() bool { return true }
|
func (b archHelperBackend) NeedsAuth() bool { return true }
|
||||||
func (b archHelperBackend) RunsInTerminal() bool { return true }
|
func (b archHelperBackend) RunsInTerminal() bool {
|
||||||
|
return os.Getenv("DMS_FORCE_PKEXEC") != "1"
|
||||||
|
}
|
||||||
func (b archHelperBackend) IsAvailable(_ context.Context) bool { return commandExists(b.id) }
|
func (b archHelperBackend) IsAvailable(_ context.Context) bool { return commandExists(b.id) }
|
||||||
|
|
||||||
func (b archHelperBackend) DisplayName() string {
|
func (b archHelperBackend) DisplayName() string {
|
||||||
@@ -86,18 +93,37 @@ func (b archHelperBackend) Upgrade(ctx context.Context, opts UpgradeOptions, onL
|
|||||||
if opts.DryRun {
|
if opts.DryRun {
|
||||||
return Run(ctx, []string{b.id, "-Sup"}, RunOptions{OnLine: onLine})
|
return Run(ctx, []string{b.id, "-Sup"}, RunOptions{OnLine: onLine})
|
||||||
}
|
}
|
||||||
|
names := pickTargetNames(opts.Targets, b.id, opts.IncludeAUR)
|
||||||
|
if len(names) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if os.Getenv("DMS_FORCE_PKEXEC") == "1" {
|
||||||
|
argv := append([]string{"pkexec", b.id, "-Sy", "--noconfirm", "--needed"}, names...)
|
||||||
|
return Run(ctx, argv, RunOptions{OnLine: onLine})
|
||||||
|
}
|
||||||
term := findTerminal(opts.Terminal)
|
term := findTerminal(opts.Terminal)
|
||||||
if term == "" {
|
if term == "" {
|
||||||
return fmt.Errorf("no terminal found (pick one in DMS settings, set $TERMINAL, or install kitty/ghostty/foot/alacritty)")
|
return fmt.Errorf("no terminal found (pick one in DMS settings, set $TERMINAL, or install kitty/ghostty/foot/alacritty)")
|
||||||
}
|
}
|
||||||
cmd := fmt.Sprintf("%s -Syu", b.id)
|
cmd := fmt.Sprintf("%s -Sy --noconfirm --needed %s", b.id, strings.Join(names, " "))
|
||||||
if !opts.IncludeAUR {
|
|
||||||
cmd += " --repo"
|
|
||||||
}
|
|
||||||
title := fmt.Sprintf("DMS — System Update (%s)", b.id)
|
title := fmt.Sprintf("DMS — System Update (%s)", b.id)
|
||||||
return Run(ctx, wrapInTerminal(term, title, cmd), RunOptions{OnLine: onLine})
|
return Run(ctx, wrapInTerminal(term, title, cmd), RunOptions{OnLine: onLine})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func pickTargetNames(targets []Package, backendID string, includeAUR bool) []string {
|
||||||
|
out := make([]string, 0, len(targets))
|
||||||
|
for _, p := range targets {
|
||||||
|
if p.Backend != backendID {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !includeAUR && p.Repo == RepoAUR {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
out = append(out, p.Name)
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
func pacmanRepoUpdates(ctx context.Context) (string, error) {
|
func pacmanRepoUpdates(ctx context.Context) (string, error) {
|
||||||
if commandExists("checkupdates") {
|
if commandExists("checkupdates") {
|
||||||
return capturePermissive(ctx, "checkupdates")
|
return capturePermissive(ctx, "checkupdates")
|
||||||
|
|||||||
@@ -74,5 +74,10 @@ func (zypperBackend) Upgrade(ctx context.Context, opts UpgradeOptions, onLine fu
|
|||||||
if opts.DryRun {
|
if opts.DryRun {
|
||||||
return Run(ctx, []string{"zypper", "--non-interactive", "--dry-run", "update"}, RunOptions{OnLine: onLine})
|
return Run(ctx, []string{"zypper", "--non-interactive", "--dry-run", "update"}, RunOptions{OnLine: onLine})
|
||||||
}
|
}
|
||||||
return Run(ctx, []string{"pkexec", "zypper", "--non-interactive", "update"}, RunOptions{OnLine: onLine})
|
names := pickTargetNames(opts.Targets, "zypper", true)
|
||||||
|
if len(names) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
argv := append([]string{"pkexec", "zypper", "--non-interactive", "update"}, names...)
|
||||||
|
return Run(ctx, argv, RunOptions{OnLine: onLine})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"sync"
|
"sync"
|
||||||
|
"syscall"
|
||||||
)
|
)
|
||||||
|
|
||||||
type RunOptions struct {
|
type RunOptions struct {
|
||||||
@@ -24,6 +25,13 @@ func Run(ctx context.Context, argv []string, opts RunOptions) error {
|
|||||||
if len(opts.Env) > 0 {
|
if len(opts.Env) > 0 {
|
||||||
cmd.Env = append(cmd.Environ(), opts.Env...)
|
cmd.Env = append(cmd.Environ(), opts.Env...)
|
||||||
}
|
}
|
||||||
|
cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
|
||||||
|
cmd.Cancel = func() error {
|
||||||
|
if cmd.Process == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL)
|
||||||
|
}
|
||||||
|
|
||||||
stdout, err := cmd.StdoutPipe()
|
stdout, err := cmd.StdoutPipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -309,6 +309,12 @@ func (m *Manager) runUpgrade(ctx context.Context, opts UpgradeOptions) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(opts.Targets) == 0 {
|
||||||
|
m.mu.RLock()
|
||||||
|
opts.Targets = append([]Package(nil), m.state.Packages...)
|
||||||
|
m.mu.RUnlock()
|
||||||
|
}
|
||||||
|
|
||||||
opID := fmt.Sprintf("op-%d", time.Now().UnixNano())
|
opID := fmt.Sprintf("op-%d", time.Now().UnixNano())
|
||||||
m.mu.Lock()
|
m.mu.Lock()
|
||||||
m.state.Phase = PhaseUpgrading
|
m.state.Phase = PhaseUpgrading
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ type Package struct {
|
|||||||
ToVersion string `json:"toVersion,omitempty"`
|
ToVersion string `json:"toVersion,omitempty"`
|
||||||
SizeBytes int64 `json:"sizeBytes,omitempty"`
|
SizeBytes int64 `json:"sizeBytes,omitempty"`
|
||||||
ChangelogURL string `json:"changelogUrl,omitempty"`
|
ChangelogURL string `json:"changelogUrl,omitempty"`
|
||||||
|
Ref string `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type BackendInfo struct {
|
type BackendInfo struct {
|
||||||
@@ -77,6 +78,7 @@ type UpgradeOptions struct {
|
|||||||
DryRun bool
|
DryRun bool
|
||||||
CustomCommand string
|
CustomCommand string
|
||||||
Terminal string
|
Terminal string
|
||||||
|
Targets []Package
|
||||||
}
|
}
|
||||||
|
|
||||||
type RefreshOptions struct {
|
type RefreshOptions struct {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
|
import Quickshell.Wayland
|
||||||
import qs.Common
|
import qs.Common
|
||||||
import qs.Services
|
import qs.Services
|
||||||
import qs.Widgets
|
import qs.Widgets
|
||||||
@@ -17,6 +18,21 @@ DankPopout {
|
|||||||
|
|
||||||
property bool _reopenAfterUpgrade: false
|
property bool _reopenAfterUpgrade: false
|
||||||
|
|
||||||
|
readonly property bool polkitModalOpen: PopoutService.polkitAuthModal?.visible ?? false
|
||||||
|
readonly property bool anyModalOpen: polkitModalOpen
|
||||||
|
|
||||||
|
backgroundInteractive: !anyModalOpen
|
||||||
|
|
||||||
|
customKeyboardFocus: {
|
||||||
|
if (!shouldBeVisible)
|
||||||
|
return WlrKeyboardFocus.None;
|
||||||
|
if (anyModalOpen)
|
||||||
|
return WlrKeyboardFocus.None;
|
||||||
|
if (CompositorService.useHyprlandFocusGrab)
|
||||||
|
return WlrKeyboardFocus.OnDemand;
|
||||||
|
return WlrKeyboardFocus.Exclusive;
|
||||||
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: SystemUpdateService
|
target: SystemUpdateService
|
||||||
function onIsUpgradingChanged() {
|
function onIsUpgradingChanged() {
|
||||||
@@ -38,7 +54,11 @@ DankPopout {
|
|||||||
screen: triggerScreen
|
screen: triggerScreen
|
||||||
shouldBeVisible: false
|
shouldBeVisible: false
|
||||||
|
|
||||||
onBackgroundClicked: close()
|
onBackgroundClicked: {
|
||||||
|
if (anyModalOpen)
|
||||||
|
return;
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
onShouldBeVisibleChanged: {
|
onShouldBeVisibleChanged: {
|
||||||
if (!shouldBeVisible) {
|
if (!shouldBeVisible) {
|
||||||
@@ -290,7 +310,7 @@ DankPopout {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
font.pixelSize: Theme.fontSizeMedium
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
color: SystemUpdateService.hasError ? Theme.errorText : Theme.surfaceText
|
color: SystemUpdateService.hasError ? Theme.error : Theme.surfaceText
|
||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user