Krolyxon
Commit fb9b856

Branches

Refs →

aurora.configquickshellauroraUpdates.qml

87 lines · 3.5 KB · QML

1pragma Singleton
2import QtQuick
3import Quickshell
4import Quickshell.Io
5
6// pending package updates: checkupdates (pacman-contrib, syncs a private db copy) + paru -Qua (AUR).
7// Checked a minute after start, then every 2h; the sys tab asks for a fresh one when opened (check(false)
8// skips it if the last one is under 10 min old). upgrade() runs paru in foot, started through Hyprland so
9// restarting aurora can't kill a pacman transaction; the terminal calls the `updates` IPC when it closes.
10Singleton {
11 id: root
12 property bool available: false // checkupdates installed
13 property bool checking: false
14 property bool upgrading: false
15 property var list: [] // [{name, from, to, aur}], repo packages first
16 property int repo: 0
17 property int aur: 0
18 readonly property int count: repo + aur
19 property date lastCheck: new Date(0)
20 property string error: "" // checkupdates failed (offline, db locked...): the old list is kept
21
22 function check(force) {
23 if (!available || checking) return
24 if (!force && Date.now() - lastCheck.getTime() < 600000) return
25 checking = true
26 checkProc.running = true
27 }
28
29 function upgrade() {
30 if (upgrading) return
31 upgrading = true
32 upgradeGuard.restart()
33 Quickshell.execDetached(["hyprctl", "dispatch", "hl.dsp.exec_cmd([[foot -T 'system upgrade' -e sh -c "
34 + "'paru; printf \"\\ndone, press enter to close\"; read _; qs -c aurora ipc call shell updates']])"])
35 }
36 // called by the upgrade terminal when it closes (and usable by hand after updating elsewhere)
37 function finished() {
38 upgrading = false
39 upgradeGuard.stop()
40 check(true)
41 }
42
43 // "name old -> new [ignored]" lines; @repo <exit code> separates the two lists
44 function parse(text) {
45 var out = [], nr = 0, na = 0, isAur = false, code = 0
46 var lines = text.split("\n")
47 for (var i = 0; i < lines.length; i++) {
48 var l = lines[i].trim()
49 var c = l.match(/^@repo (\d+)$/)
50 if (c) { code = parseInt(c[1]); isAur = true; continue }
51 var m = l.match(/^(\S+)\s+(\S+)\s+->\s+(\S+)/)
52 if (!m || l.indexOf("[ignored]") >= 0) continue
53 out.push({ name: m[1], from: m[2], to: m[3], aur: isAur })
54 if (isAur) na++; else nr++
55 }
56 // checkupdates: 0 = updates, 2 = none, anything else = failed
57 if (code !== 0 && code !== 2) {
58 error = "checkupdates failed (" + code + ")"
59 out = list.filter(function (p) { return !p.aur }).concat(out.filter(function (p) { return p.aur }))
60 nr = repo
61 } else {
62 error = ""
63 }
64 list = out
65 repo = nr
66 aur = na
67 lastCheck = new Date()
68 }
69
70 Process {
71 command: ["sh", "-c", "command -v checkupdates"]
72 running: true
73 onExited: code => root.available = code === 0
74 }
75
76 Process {
77 id: checkProc
78 command: ["sh", "-c", 'checkupdates 2>/dev/null; echo "@repo $?"; command -v paru >/dev/null && paru -Qua 2>/dev/null; true']
79 stdout: StdioCollector { onStreamFinished: { root.parse(text); root.checking = false } }
80 }
81
82 // the terminal may be closed with the window's X, skipping the IPC call
83 Timer { id: upgradeGuard; interval: 3600000; onTriggered: root.upgrading = false }
84
85 Timer { interval: 60000; running: root.available; onTriggered: root.check(true) }
86 Timer { interval: 7200000; running: root.available; repeat: true; onTriggered: root.check(true) }
87}