1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-04-30 01:22:06 -04:00

Revert "system updater: make all distros use terminal"

This reverts commit 1467f5dba9.
This commit is contained in:
bbedward
2026-04-29 14:56:54 -04:00
parent 1467f5dba9
commit 3b96c6ab22
15 changed files with 222 additions and 98 deletions

View File

@@ -7,8 +7,6 @@ This file is more of a quick reference so I know what to account for before next
- Terminal mux - Terminal mux
- Locale overrides - Locale overrides
- new neovim theming - new neovim theming
- system upder overhaul
- New Log system, remember to update all plugins after release as it breaks compat
# 1.4.0 # 1.4.0

View File

@@ -6,7 +6,6 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"os" "os"
"os/exec"
"strings" "strings"
"time" "time"
@@ -184,20 +183,10 @@ func runSystemUpdateApply() {
DryRun: sysUpdateDry, DryRun: sysUpdateDry,
} }
onLine := func(line string) { fmt.Println(line) }
for _, b := range backends { for _, b := range backends {
cmd, err := b.UpgradeCommand(opts) fmt.Printf("\n== %s ==\n", b.DisplayName())
if err != nil { if err := b.Upgrade(ctx, opts, onLine); err != nil {
log.Fatalf("%s: %v", b.ID(), err)
}
if cmd == "" {
continue
}
fmt.Printf("\n== %s ==\n$ %s\n\n", b.DisplayName(), cmd)
shell := exec.CommandContext(ctx, "sh", "-c", cmd)
shell.Stdin = os.Stdin
shell.Stdout = os.Stdout
shell.Stderr = os.Stderr
if err := shell.Run(); err != nil {
log.Fatalf("%s upgrade failed: %v", b.ID(), err) log.Fatalf("%s upgrade failed: %v", b.ID(), err)
} }
} }

View File

@@ -12,8 +12,9 @@ type Backend interface {
Repo() RepoKind Repo() RepoKind
IsAvailable(ctx context.Context) bool IsAvailable(ctx context.Context) bool
NeedsAuth() bool NeedsAuth() bool
RunsInTerminal() bool
CheckUpdates(ctx context.Context) ([]Package, error) CheckUpdates(ctx context.Context) ([]Package, error)
UpgradeCommand(opts UpgradeOptions) (string, error) Upgrade(ctx context.Context, opts UpgradeOptions, onLine func(string)) error
} }
type Selection struct { type Selection struct {
@@ -36,10 +37,11 @@ func (s Selection) Info() []BackendInfo {
out := make([]BackendInfo, 0, len(all)) out := make([]BackendInfo, 0, len(all))
for _, b := range all { for _, b := range all {
out = append(out, BackendInfo{ out = append(out, BackendInfo{
ID: b.ID(), ID: b.ID(),
DisplayName: b.DisplayName(), DisplayName: b.DisplayName(),
Repo: b.Repo(), Repo: b.Repo(),
NeedsAuth: b.NeedsAuth(), NeedsAuth: b.NeedsAuth(),
RunsInTerminal: b.RunsInTerminal(),
}) })
} }
return out return out

View File

@@ -15,10 +15,11 @@ var aptUpgradableLine = regexp.MustCompile(`^([^/]+)/\S+\s+(\S+)\s+\S+\s+\[upgra
type aptBackend struct{} type aptBackend struct{}
func (aptBackend) ID() string { return "apt" } func (aptBackend) ID() string { return "apt" }
func (aptBackend) DisplayName() string { return "APT" } func (aptBackend) DisplayName() string { return "APT" }
func (aptBackend) Repo() RepoKind { return RepoSystem } func (aptBackend) Repo() RepoKind { return RepoSystem }
func (aptBackend) NeedsAuth() bool { return true } func (aptBackend) NeedsAuth() bool { return true }
func (aptBackend) RunsInTerminal() bool { return false }
func (aptBackend) IsAvailable(_ context.Context) bool { func (aptBackend) IsAvailable(_ context.Context) bool {
return commandExists("apt") || commandExists("apt-get") return commandExists("apt") || commandExists("apt-get")
} }
@@ -33,16 +34,19 @@ func (aptBackend) CheckUpdates(ctx context.Context) ([]Package, error) {
return parseAptUpgradable(string(out)), nil return parseAptUpgradable(string(out)), nil
} }
func (aptBackend) UpgradeCommand(opts UpgradeOptions) (string, error) { func (aptBackend) Upgrade(ctx context.Context, opts UpgradeOptions, onLine func(string)) error {
bin := "apt-get" bin := "apt-get"
if !commandExists(bin) { if !commandExists(bin) {
bin = "apt" bin = "apt"
} }
env := "DEBIAN_FRONTEND=noninteractive LC_ALL=C "
if opts.DryRun { if opts.DryRun {
return env + bin + " upgrade --dry-run", nil return Run(ctx, []string{bin, "upgrade", "--dry-run"}, RunOptions{
Env: []string{"DEBIAN_FRONTEND=noninteractive", "LC_ALL=C"},
OnLine: onLine,
})
} }
return "sudo " + env + bin + " upgrade -y", nil argv := []string{"pkexec", "env", "DEBIAN_FRONTEND=noninteractive", "LC_ALL=C", bin, "upgrade", "-y"}
return Run(ctx, argv, RunOptions{OnLine: onLine})
} }
func parseAptUpgradable(text string) []Package { func parseAptUpgradable(text string) []Package {

View File

@@ -3,7 +3,6 @@ package sysupdate
import ( import (
"context" "context"
"errors" "errors"
"fmt"
"os/exec" "os/exec"
"strings" "strings"
) )
@@ -17,10 +16,11 @@ type dnfBackend struct {
bin string bin string
} }
func (b dnfBackend) ID() string { return b.bin } func (b dnfBackend) ID() string { return b.bin }
func (b dnfBackend) DisplayName() string { return strings.ToUpper(b.bin) } func (b dnfBackend) DisplayName() string { return strings.ToUpper(b.bin) }
func (b dnfBackend) Repo() RepoKind { return RepoSystem } func (b dnfBackend) Repo() RepoKind { return RepoSystem }
func (b dnfBackend) NeedsAuth() bool { return true } func (b dnfBackend) NeedsAuth() bool { return true }
func (b dnfBackend) RunsInTerminal() bool { return false }
func (b dnfBackend) IsAvailable(ctx context.Context) bool { func (b dnfBackend) IsAvailable(ctx context.Context) bool {
if !commandExists(b.bin) { if !commandExists(b.bin) {
@@ -41,11 +41,11 @@ func (b dnfBackend) CheckUpdates(ctx context.Context) ([]Package, error) {
return parseDnfList(out, b.bin, installed), nil return parseDnfList(out, b.bin, installed), nil
} }
func (b dnfBackend) UpgradeCommand(opts UpgradeOptions) (string, error) { func (b dnfBackend) Upgrade(ctx context.Context, opts UpgradeOptions, onLine func(string)) error {
if opts.DryRun { if opts.DryRun {
return fmt.Sprintf("%s upgrade --assumeno", b.bin), nil return Run(ctx, []string{b.bin, "upgrade", "--assumeno"}, RunOptions{OnLine: onLine})
} }
return fmt.Sprintf("sudo %s upgrade -y", b.bin), nil return Run(ctx, []string{"pkexec", b.bin, "upgrade", "-y"}, RunOptions{OnLine: onLine})
} }
func dnfListUpgrades(ctx context.Context, bin string) (string, error) { func dnfListUpgrades(ctx context.Context, bin string) (string, error) {

View File

@@ -16,6 +16,7 @@ func (flatpakBackend) ID() string { return "flatpak" }
func (flatpakBackend) DisplayName() string { return "Flatpak" } func (flatpakBackend) DisplayName() string { return "Flatpak" }
func (flatpakBackend) Repo() RepoKind { return RepoFlatpak } func (flatpakBackend) Repo() RepoKind { return RepoFlatpak }
func (flatpakBackend) NeedsAuth() bool { return false } func (flatpakBackend) NeedsAuth() bool { return false }
func (flatpakBackend) RunsInTerminal() bool { return false }
func (flatpakBackend) IsAvailable(_ context.Context) bool { return commandExists("flatpak") } func (flatpakBackend) IsAvailable(_ context.Context) bool { return commandExists("flatpak") }
func (flatpakBackend) CheckUpdates(ctx context.Context) ([]Package, error) { func (flatpakBackend) CheckUpdates(ctx context.Context) ([]Package, error) {
@@ -68,11 +69,12 @@ type flatpakInstalledEntry struct {
commit string commit string
} }
func (flatpakBackend) UpgradeCommand(opts UpgradeOptions) (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 {
return "flatpak update --no-deploy -y", nil argv = []string{"flatpak", "update", "--no-deploy", "-y"}
} }
return "flatpak update -y --noninteractive", nil return Run(ctx, argv, RunOptions{OnLine: onLine})
} }
func parseFlatpakUpdates(text string, installed map[string]flatpakInstalledEntry) []Package { func parseFlatpakUpdates(text string, installed map[string]flatpakInstalledEntry) []Package {

View File

@@ -28,6 +28,7 @@ func (pacmanBackend) ID() string { return "pacman" }
func (pacmanBackend) DisplayName() string { return "Pacman" } func (pacmanBackend) DisplayName() string { return "Pacman" }
func (pacmanBackend) Repo() RepoKind { return RepoSystem } func (pacmanBackend) Repo() RepoKind { return RepoSystem }
func (pacmanBackend) NeedsAuth() bool { return true } func (pacmanBackend) NeedsAuth() bool { return true }
func (pacmanBackend) RunsInTerminal() bool { return false }
func (pacmanBackend) IsAvailable(_ context.Context) bool { return commandExists("pacman") } func (pacmanBackend) IsAvailable(_ context.Context) bool { return commandExists("pacman") }
func (b pacmanBackend) CheckUpdates(ctx context.Context) ([]Package, error) { func (b pacmanBackend) CheckUpdates(ctx context.Context) ([]Package, error) {
@@ -38,11 +39,11 @@ func (b pacmanBackend) CheckUpdates(ctx context.Context) ([]Package, error) {
return parseArchUpdates(out, b.ID(), RepoSystem), nil return parseArchUpdates(out, b.ID(), RepoSystem), nil
} }
func (pacmanBackend) UpgradeCommand(opts UpgradeOptions) (string, error) { func (b pacmanBackend) Upgrade(ctx context.Context, opts UpgradeOptions, onLine func(string)) error {
if opts.DryRun { if opts.DryRun {
return "pacman -Sup", nil return Run(ctx, []string{"pacman", "-Sup"}, RunOptions{OnLine: onLine})
} }
return "sudo pacman -Syu --noconfirm", nil return Run(ctx, []string{"pkexec", "pacman", "-Syu", "--noconfirm"}, RunOptions{OnLine: onLine})
} }
type archHelperBackend struct { type archHelperBackend struct {
@@ -52,6 +53,7 @@ type archHelperBackend struct {
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) 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 {
@@ -80,15 +82,20 @@ func (b archHelperBackend) CheckUpdates(ctx context.Context) ([]Package, error)
return pkgs, nil return pkgs, nil
} }
func (b archHelperBackend) UpgradeCommand(opts UpgradeOptions) (string, error) { func (b archHelperBackend) Upgrade(ctx context.Context, opts UpgradeOptions, onLine func(string)) error {
if opts.DryRun { if opts.DryRun {
return fmt.Sprintf("%s -Sup", b.id), nil return Run(ctx, []string{b.id, "-Sup"}, RunOptions{OnLine: onLine})
} }
cmd := fmt.Sprintf("%s -Syu --noconfirm", b.id) term := findTerminal(opts.Terminal)
if term == "" {
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)
if !opts.IncludeAUR { if !opts.IncludeAUR {
cmd += " --repo" cmd += " --repo"
} }
return cmd, nil title := fmt.Sprintf("DMS — System Update (%s)", b.id)
return Run(ctx, wrapInTerminal(term, title, cmd), RunOptions{OnLine: onLine})
} }
func pacmanRepoUpdates(ctx context.Context) (string, error) { func pacmanRepoUpdates(ctx context.Context) (string, error) {

View File

@@ -15,10 +15,11 @@ func init() {
type rpmOstreeBackend struct{} type rpmOstreeBackend struct{}
func (rpmOstreeBackend) ID() string { return "rpm-ostree" } func (rpmOstreeBackend) ID() string { return "rpm-ostree" }
func (rpmOstreeBackend) DisplayName() string { return "rpm-ostree" } func (rpmOstreeBackend) DisplayName() string { return "rpm-ostree" }
func (rpmOstreeBackend) Repo() RepoKind { return RepoOSTree } func (rpmOstreeBackend) Repo() RepoKind { return RepoOSTree }
func (rpmOstreeBackend) NeedsAuth() bool { return true } func (rpmOstreeBackend) NeedsAuth() bool { return true }
func (rpmOstreeBackend) RunsInTerminal() bool { return false }
func (b rpmOstreeBackend) IsAvailable(ctx context.Context) bool { func (b rpmOstreeBackend) IsAvailable(ctx context.Context) bool {
if !commandExists("rpm-ostree") { if !commandExists("rpm-ostree") {
@@ -115,9 +116,10 @@ func bootedDeployment(deps []ostreeDeployment) *ostreeDeployment {
return nil return nil
} }
func (rpmOstreeBackend) UpgradeCommand(opts UpgradeOptions) (string, error) { func (rpmOstreeBackend) Upgrade(ctx context.Context, opts UpgradeOptions, onLine func(string)) error {
argv := []string{"rpm-ostree", "upgrade"}
if opts.DryRun { if opts.DryRun {
return "rpm-ostree upgrade --check", nil argv = append(argv, "--check")
} }
return "rpm-ostree upgrade", nil return Run(ctx, argv, RunOptions{OnLine: onLine})
} }

View File

@@ -17,6 +17,7 @@ func (zypperBackend) ID() string { return "zypper" }
func (zypperBackend) DisplayName() string { return "Zypper" } func (zypperBackend) DisplayName() string { return "Zypper" }
func (zypperBackend) Repo() RepoKind { return RepoSystem } func (zypperBackend) Repo() RepoKind { return RepoSystem }
func (zypperBackend) NeedsAuth() bool { return true } func (zypperBackend) NeedsAuth() bool { return true }
func (zypperBackend) RunsInTerminal() bool { return false }
func (zypperBackend) IsAvailable(_ context.Context) bool { return commandExists("zypper") } func (zypperBackend) IsAvailable(_ context.Context) bool { return commandExists("zypper") }
type zypperUpdateList struct { type zypperUpdateList struct {
@@ -69,9 +70,9 @@ func parseZypperXML(out []byte) ([]Package, error) {
return pkgs, nil return pkgs, nil
} }
func (zypperBackend) UpgradeCommand(opts UpgradeOptions) (string, error) { func (zypperBackend) Upgrade(ctx context.Context, opts UpgradeOptions, onLine func(string)) error {
if opts.DryRun { if opts.DryRun {
return "zypper --non-interactive --dry-run update", nil return Run(ctx, []string{"zypper", "--non-interactive", "--dry-run", "update"}, RunOptions{OnLine: onLine})
} }
return "sudo zypper --non-interactive update", nil return Run(ctx, []string{"pkexec", "zypper", "--non-interactive", "update"}, RunOptions{OnLine: onLine})
} }

View File

@@ -1,18 +1,63 @@
package sysupdate package sysupdate
import ( import (
"bufio"
"context" "context"
"fmt" "fmt"
"io"
"os" "os"
"os/exec" "os/exec"
"sync"
) )
func Run(ctx context.Context, argv []string) error { type RunOptions struct {
Env []string
OnLine func(string)
}
func Run(ctx context.Context, argv []string, opts RunOptions) error {
if len(argv) == 0 { if len(argv) == 0 {
return fmt.Errorf("sysupdate.Run: empty argv") return fmt.Errorf("sysupdate.Run: empty argv")
} }
cmd := exec.CommandContext(ctx, argv[0], argv[1:]...) cmd := exec.CommandContext(ctx, argv[0], argv[1:]...)
return cmd.Run() if len(opts.Env) > 0 {
cmd.Env = append(cmd.Environ(), opts.Env...)
}
stdout, err := cmd.StdoutPipe()
if err != nil {
return err
}
stderr, err := cmd.StderrPipe()
if err != nil {
return err
}
if err := cmd.Start(); err != nil {
return err
}
var wg sync.WaitGroup
wg.Add(2)
go pump(stdout, opts.OnLine, &wg)
go pump(stderr, opts.OnLine, &wg)
wg.Wait()
return cmd.Wait()
}
func pump(r io.Reader, onLine func(string), wg *sync.WaitGroup) {
defer wg.Done()
if onLine == nil {
_, _ = io.Copy(io.Discard, r)
return
}
scanner := bufio.NewScanner(r)
scanner.Buffer(make([]byte, 64*1024), 1024*1024)
for scanner.Scan() {
onLine(scanner.Text())
}
} }
func Capture(ctx context.Context, argv []string) (string, error) { func Capture(ctx context.Context, argv []string) (string, error) {

View File

@@ -18,6 +18,7 @@ import (
const ( const (
defaultIntervalSeconds = 30 * 60 defaultIntervalSeconds = 30 * 60
minIntervalSeconds = 5 * 60 minIntervalSeconds = 5 * 60
recentLogCapacity = 200
checkTimeout = 5 * time.Minute checkTimeout = 5 * time.Minute
upgradeTimeout = 30 * time.Minute upgradeTimeout = 30 * time.Minute
) )
@@ -239,6 +240,7 @@ func (m *Manager) runRefresh(parent context.Context) {
} }
m.state.Phase = PhaseRefreshing m.state.Phase = PhaseRefreshing
m.state.Error = nil m.state.Error = nil
m.state.RecentLog = nil
m.mu.Unlock() m.mu.Unlock()
m.markDirty() m.markDirty()
@@ -296,13 +298,57 @@ func (m *Manager) runUpgrade(ctx context.Context, opts UpgradeOptions) {
m.opMu.Unlock() m.opMu.Unlock()
}() }()
combined, err := buildBundledCommand(m.selection, opts) if opts.CustomCommand != "" {
if err != nil { m.runCustomUpgrade(ctx, opts.CustomCommand, opts.Terminal)
m.setError(ErrCodeNoBackend, err.Error())
return return
} }
term := findTerminal(opts.Terminal) backends := upgradeBackends(m.selection, opts)
if len(backends) == 0 {
m.setError(ErrCodeNoBackend, "no backend selected for upgrade")
return
}
opID := fmt.Sprintf("op-%d", time.Now().UnixNano())
m.mu.Lock()
m.state.Phase = PhaseUpgrading
m.state.OperationID = opID
m.state.OperationStarted = time.Now().Unix()
m.state.RecentLog = m.state.RecentLog[:0]
m.state.Error = nil
m.mu.Unlock()
m.markDirty()
onLine := func(line string) { m.appendLog(line) }
for _, b := range backends {
m.appendLog(fmt.Sprintf("== %s ==", b.DisplayName()))
if err := b.Upgrade(ctx, opts, onLine); err != nil {
code := ErrCodeBackendFailed
if errors.Is(ctx.Err(), context.DeadlineExceeded) {
code = ErrCodeTimeout
} else if errors.Is(ctx.Err(), context.Canceled) {
code = ErrCodeCancelled
}
m.mu.Lock()
m.state.Phase = PhaseError
m.state.Error = &ErrorInfo{Code: code, Message: fmt.Sprintf("%s: %v", b.ID(), err)}
m.mu.Unlock()
m.markDirty()
return
}
}
m.mu.Lock()
m.state.Phase = PhaseIdle
m.state.OperationID = ""
m.state.OperationStarted = 0
m.mu.Unlock()
m.markDirty()
go m.runRefresh(context.Background())
}
func (m *Manager) runCustomUpgrade(ctx context.Context, command, terminalOverride string) {
term := findTerminal(terminalOverride)
if term == "" { if term == "" {
m.setError(ErrCodeBackendFailed, "no terminal found (pick one in DMS settings, set $TERMINAL, or install kitty/ghostty/foot/alacritty)") m.setError(ErrCodeBackendFailed, "no terminal found (pick one in DMS settings, set $TERMINAL, or install kitty/ghostty/foot/alacritty)")
return return
@@ -313,12 +359,14 @@ func (m *Manager) runUpgrade(ctx context.Context, opts UpgradeOptions) {
m.state.Phase = PhaseUpgrading m.state.Phase = PhaseUpgrading
m.state.OperationID = opID m.state.OperationID = opID
m.state.OperationStarted = time.Now().Unix() m.state.OperationStarted = time.Now().Unix()
m.state.RecentLog = m.state.RecentLog[:0]
m.state.Error = nil m.state.Error = nil
m.mu.Unlock() m.mu.Unlock()
m.markDirty() m.markDirty()
argv := wrapInTerminal(term, "DMS — System Update", combined) onLine := func(line string) { m.appendLog(line) }
if err := Run(ctx, argv); err != nil { argv := wrapInTerminal(term, "DMS — System Update (custom)", command)
if err := Run(ctx, argv, RunOptions{OnLine: onLine}); err != nil {
code := ErrCodeBackendFailed code := ErrCodeBackendFailed
switch { switch {
case errors.Is(ctx.Err(), context.DeadlineExceeded): case errors.Is(ctx.Err(), context.DeadlineExceeded):
@@ -343,31 +391,6 @@ func (m *Manager) runUpgrade(ctx context.Context, opts UpgradeOptions) {
go m.runRefresh(context.Background()) go m.runRefresh(context.Background())
} }
func buildBundledCommand(sel Selection, opts UpgradeOptions) (string, error) {
if opts.CustomCommand != "" {
return opts.CustomCommand, nil
}
backends := upgradeBackends(sel, opts)
if len(backends) == 0 {
return "", errors.New("no backend selected for upgrade")
}
parts := make([]string, 0, len(backends))
for _, b := range backends {
cmd, err := b.UpgradeCommand(opts)
if err != nil {
return "", fmt.Errorf("%s: %w", b.ID(), err)
}
if cmd == "" {
continue
}
parts = append(parts, cmd)
}
if len(parts) == 0 {
return "", errors.New("no backend produced an upgrade command")
}
return strings.Join(parts, " && "), nil
}
func upgradeBackends(sel Selection, opts UpgradeOptions) []Backend { func upgradeBackends(sel Selection, opts UpgradeOptions) []Backend {
var out []Backend var out []Backend
if sel.System != nil { if sel.System != nil {
@@ -383,6 +406,20 @@ func upgradeBackends(sel Selection, opts UpgradeOptions) []Backend {
return out return out
} }
func (m *Manager) appendLog(line string) {
m.mu.Lock()
if cap(m.state.RecentLog) == 0 {
m.state.RecentLog = make([]string, 0, recentLogCapacity)
}
if len(m.state.RecentLog) >= recentLogCapacity {
copy(m.state.RecentLog, m.state.RecentLog[1:])
m.state.RecentLog = m.state.RecentLog[:recentLogCapacity-1]
}
m.state.RecentLog = append(m.state.RecentLog, line)
m.mu.Unlock()
m.markDirty()
}
func (m *Manager) setError(code ErrorCode, msg string) { func (m *Manager) setError(code ErrorCode, msg string) {
m.mu.Lock() m.mu.Lock()
m.state.Phase = PhaseError m.state.Phase = PhaseError
@@ -421,6 +458,7 @@ func cloneState(s State) State {
out := s out := s
out.Backends = append([]BackendInfo(nil), s.Backends...) out.Backends = append([]BackendInfo(nil), s.Backends...)
out.Packages = append([]Package(nil), s.Packages...) out.Packages = append([]Package(nil), s.Packages...)
out.RecentLog = append([]string(nil), s.RecentLog...)
if s.Error != nil { if s.Error != nil {
errCopy := *s.Error errCopy := *s.Error
out.Error = &errCopy out.Error = &errCopy

View File

@@ -41,10 +41,11 @@ type Package struct {
} }
type BackendInfo struct { type BackendInfo struct {
ID string `json:"id"` ID string `json:"id"`
DisplayName string `json:"displayName"` DisplayName string `json:"displayName"`
Repo RepoKind `json:"repo"` Repo RepoKind `json:"repo"`
NeedsAuth bool `json:"needsAuth"` NeedsAuth bool `json:"needsAuth"`
RunsInTerminal bool `json:"runsInTerminal"`
} }
type ErrorInfo struct { type ErrorInfo struct {
@@ -66,6 +67,7 @@ type State struct {
NextCheckUnix int64 `json:"nextCheckUnix,omitempty"` NextCheckUnix int64 `json:"nextCheckUnix,omitempty"`
OperationID string `json:"operationId,omitempty"` OperationID string `json:"operationId,omitempty"`
OperationStarted int64 `json:"operationStartedUnix,omitempty"` OperationStarted int64 `json:"operationStartedUnix,omitempty"`
RecentLog []string `json:"recentLog,omitempty"`
Error *ErrorInfo `json:"error,omitempty"` Error *ErrorInfo `json:"error,omitempty"`
} }

View File

@@ -57,6 +57,8 @@ DankPopout {
color: "transparent" color: "transparent"
focus: true focus: true
readonly property bool hasTerminalBackend: (SystemUpdateService.backends || []).some(b => b.runsInTerminal === true)
Keys.onPressed: event => { Keys.onPressed: event => {
if (event.key === Qt.Key_Escape) { if (event.key === Qt.Key_Escape) {
systemUpdatePopout.close(); systemUpdatePopout.close();
@@ -206,9 +208,13 @@ DankPopout {
includeAUR: SettingsData.updaterAllowAUR, includeAUR: SettingsData.updaterAllowAUR,
terminal: SessionData.terminalOverride terminal: SessionData.terminalOverride
}; };
systemUpdatePopout._reopenAfterUpgrade = true; if (updaterPanel.hasTerminalBackend) {
systemUpdatePopout._reopenAfterUpgrade = true;
SystemUpdateService.runUpdates(opts);
systemUpdatePopout.close();
return;
}
SystemUpdateService.runUpdates(opts); SystemUpdateService.runUpdates(opts);
systemUpdatePopout.close();
} }
} }
@@ -377,7 +383,7 @@ DankPopout {
anchors.fill: parent anchors.fill: parent
anchors.margins: Theme.spacingM anchors.margins: Theme.spacingM
spacing: Theme.spacingS spacing: Theme.spacingS
visible: SystemUpdateService.isUpgrading visible: SystemUpdateService.isUpgrading && updaterPanel.hasTerminalBackend
DankIcon { DankIcon {
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
@@ -397,13 +403,38 @@ DankPopout {
StyledText { StyledText {
width: parent.width width: parent.width
text: I18n.tr("See the terminal window for prompts. This popout will return when the upgrade exits.") text: I18n.tr("AUR helpers are interactive — see the terminal window for prompts. This popout will return to idle when the upgrade exits.")
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText color: Theme.surfaceVariantText
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
} }
} }
DankFlickable {
anchors.fill: parent
anchors.margins: Theme.spacingM
visible: SystemUpdateService.isUpgrading && !updaterPanel.hasTerminalBackend
contentWidth: width
contentHeight: logText.implicitHeight
clip: true
onContentHeightChanged: {
if (contentHeight > height) {
contentY = contentHeight - height;
}
}
StyledText {
id: logText
width: parent.width
text: (SystemUpdateService.recentLog || []).join("\n")
font.family: Theme.monoFontFamily || "monospace"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
wrapMode: Text.NoWrap
}
}
} }
} }
} }

View File

@@ -9,6 +9,7 @@ Rectangle {
property string iconName: "" property string iconName: ""
property string text: "" property string text: ""
property bool isDestructive: false property bool isDestructive: false
property bool enabled: true
signal triggered signal triggered

View File

@@ -24,6 +24,7 @@ Singleton {
property string distributionPretty: "" property string distributionPretty: ""
property string pkgManager: "" property string pkgManager: ""
property bool distributionSupported: false property bool distributionSupported: false
property var recentLog: []
property int intervalSeconds: 1800 property int intervalSeconds: 1800
property int lastCheckUnix: 0 property int lastCheckUnix: 0
property int nextCheckUnix: 0 property int nextCheckUnix: 0
@@ -88,6 +89,7 @@ Singleton {
distribution = data.distro || ""; distribution = data.distro || "";
distributionPretty = data.distroPretty || ""; distributionPretty = data.distroPretty || "";
distributionSupported = (backends.length > 0); distributionSupported = (backends.length > 0);
recentLog = data.recentLog || [];
intervalSeconds = data.intervalSeconds || 1800; intervalSeconds = data.intervalSeconds || 1800;
lastCheckUnix = data.lastCheckUnix || 0; lastCheckUnix = data.lastCheckUnix || 0;
nextCheckUnix = data.nextCheckUnix || 0; nextCheckUnix = data.nextCheckUnix || 0;