Replace pkexec with terminal output (with TERMINAL environment var)
ArchUpdater:use terminal thanks to `TERMINAL` environment variable README: Add explanation for said environment var
This commit is contained in:
parent
6af915983c
commit
cdfed0fe94
3 changed files with 573 additions and 122 deletions
|
|
@ -15,8 +15,9 @@ NPanel {
|
|||
|
||||
// When the panel opens
|
||||
onOpened: {
|
||||
ArchUpdaterService.doPoll()
|
||||
ArchUpdaterService.doAurPoll()
|
||||
console.log("ArchUpdaterPanel: Panel opened, refreshing package lists...")
|
||||
// Always refresh when panel opens to ensure we have the latest data
|
||||
ArchUpdaterService.forceRefresh()
|
||||
}
|
||||
|
||||
panelContent: Rectangle {
|
||||
|
|
@ -47,6 +48,19 @@ NPanel {
|
|||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
// Reset button (only show if update failed)
|
||||
NIconButton {
|
||||
visible: ArchUpdaterService.updateFailed
|
||||
icon: "refresh"
|
||||
tooltipText: "Reset update state"
|
||||
sizeRatio: 0.8
|
||||
colorBg: Color.mError
|
||||
colorFg: Color.mOnError
|
||||
onClicked: {
|
||||
ArchUpdaterService.resetUpdateState()
|
||||
}
|
||||
}
|
||||
|
||||
NIconButton {
|
||||
icon: "close"
|
||||
tooltipText: "Close"
|
||||
|
|
@ -59,8 +73,10 @@ NPanel {
|
|||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
// Update summary
|
||||
// Update summary (only show when packages are available)
|
||||
NText {
|
||||
visible: !ArchUpdaterService.updateInProgress && !ArchUpdaterService.updateFailed && !ArchUpdaterService.busy
|
||||
&& !ArchUpdaterService.aurBusy && ArchUpdaterService.totalUpdates > 0
|
||||
text: ArchUpdaterService.totalUpdates + " package" + (ArchUpdaterService.totalUpdates !== 1 ? "s" : "") + " can be updated"
|
||||
font.pointSize: Style.fontSizeL * scaling
|
||||
font.weight: Style.fontWeightMedium
|
||||
|
|
@ -68,16 +84,184 @@ NPanel {
|
|||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
// Package selection info
|
||||
// Package selection info (only show when not updating and have packages)
|
||||
NText {
|
||||
visible: !ArchUpdaterService.updateInProgress && !ArchUpdaterService.updateFailed && !ArchUpdaterService.busy
|
||||
&& !ArchUpdaterService.aurBusy && ArchUpdaterService.totalUpdates > 0
|
||||
text: ArchUpdaterService.selectedPackagesCount + " of " + ArchUpdaterService.totalUpdates + " packages selected"
|
||||
font.pointSize: Style.fontSizeS * scaling
|
||||
color: Color.mOnSurfaceVariant
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
// Unified list
|
||||
// Update in progress state
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
visible: ArchUpdaterService.updateInProgress
|
||||
spacing: Style.marginM * scaling
|
||||
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
} // Spacer
|
||||
|
||||
NIcon {
|
||||
text: "hourglass_empty"
|
||||
font.pointSize: Style.fontSizeXXXL * scaling
|
||||
color: Color.mPrimary
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
}
|
||||
|
||||
NText {
|
||||
text: "Update in progress"
|
||||
font.pointSize: Style.fontSizeL * scaling
|
||||
color: Color.mOnSurface
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
}
|
||||
|
||||
NText {
|
||||
text: "Please check your terminal window for update progress and prompts."
|
||||
font.pointSize: Style.fontSizeNormal * scaling
|
||||
color: Color.mOnSurfaceVariant
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
wrapMode: Text.Wrap
|
||||
Layout.maximumWidth: 280 * scaling
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
} // Spacer
|
||||
}
|
||||
|
||||
// Update failed state
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
visible: ArchUpdaterService.updateFailed
|
||||
|
||||
ColumnLayout {
|
||||
anchors.centerIn: parent
|
||||
spacing: Style.marginM * scaling
|
||||
|
||||
NIcon {
|
||||
text: "error_outline"
|
||||
font.pointSize: Style.fontSizeXXXL * scaling
|
||||
color: Color.mError
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
}
|
||||
|
||||
NText {
|
||||
text: "Update failed"
|
||||
font.pointSize: Style.fontSizeL * scaling
|
||||
color: Color.mOnSurface
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
}
|
||||
|
||||
NText {
|
||||
text: "Check your terminal for error details and try again."
|
||||
font.pointSize: Style.fontSizeNormal * scaling
|
||||
color: Color.mOnSurfaceVariant
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
wrapMode: Text.Wrap
|
||||
Layout.maximumWidth: 280 * scaling
|
||||
}
|
||||
|
||||
// Prominent refresh button
|
||||
NIconButton {
|
||||
icon: "refresh"
|
||||
tooltipText: "Refresh and try again"
|
||||
sizeRatio: 1.2
|
||||
colorBg: Color.mPrimary
|
||||
colorFg: Color.mOnPrimary
|
||||
onClicked: {
|
||||
ArchUpdaterService.resetUpdateState()
|
||||
}
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.topMargin: Style.marginL * scaling
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No updates available state
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
visible: !ArchUpdaterService.updateInProgress && !ArchUpdaterService.updateFailed && !ArchUpdaterService.busy
|
||||
&& !ArchUpdaterService.aurBusy && ArchUpdaterService.totalUpdates === 0
|
||||
|
||||
ColumnLayout {
|
||||
anchors.centerIn: parent
|
||||
spacing: Style.marginM * scaling
|
||||
|
||||
NIcon {
|
||||
text: "check_circle"
|
||||
font.pointSize: Style.fontSizeXXXL * scaling
|
||||
color: Color.mPrimary
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
}
|
||||
|
||||
NText {
|
||||
text: "System is up to date"
|
||||
font.pointSize: Style.fontSizeL * scaling
|
||||
color: Color.mOnSurface
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
}
|
||||
|
||||
NText {
|
||||
text: "All packages are current. Check back later for updates."
|
||||
font.pointSize: Style.fontSizeNormal * scaling
|
||||
color: Color.mOnSurfaceVariant
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
wrapMode: Text.Wrap
|
||||
Layout.maximumWidth: 280 * scaling
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Checking for updates state
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
visible: (ArchUpdaterService.busy || ArchUpdaterService.aurBusy) && !ArchUpdaterService.updateInProgress
|
||||
&& !ArchUpdaterService.updateFailed
|
||||
|
||||
ColumnLayout {
|
||||
anchors.centerIn: parent
|
||||
spacing: Style.marginM * scaling
|
||||
|
||||
NIcon {
|
||||
text: "refresh"
|
||||
font.pointSize: Style.fontSizeXXXL * scaling
|
||||
color: Color.mPrimary
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
}
|
||||
|
||||
NText {
|
||||
text: "Checking for updates"
|
||||
font.pointSize: Style.fontSizeL * scaling
|
||||
color: Color.mOnSurface
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
}
|
||||
|
||||
NText {
|
||||
text: "Scanning package databases for available updates..."
|
||||
font.pointSize: Style.fontSizeNormal * scaling
|
||||
color: Color.mOnSurfaceVariant
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
wrapMode: Text.Wrap
|
||||
Layout.maximumWidth: 280 * scaling
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Package list (only show when not in any special state)
|
||||
NBox {
|
||||
visible: !ArchUpdaterService.updateInProgress && !ArchUpdaterService.updateFailed && !ArchUpdaterService.busy
|
||||
&& !ArchUpdaterService.aurBusy && ArchUpdaterService.totalUpdates > 0
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
|
|
@ -164,53 +348,52 @@ NPanel {
|
|||
}
|
||||
}
|
||||
|
||||
// Action buttons
|
||||
// Action buttons (only show when not updating)
|
||||
RowLayout {
|
||||
visible: !ArchUpdaterService.updateInProgress && !ArchUpdaterService.updateFailed
|
||||
Layout.fillWidth: true
|
||||
spacing: Style.marginL * scaling
|
||||
|
||||
NIconButton {
|
||||
icon: "refresh"
|
||||
tooltipText: "Check for updates"
|
||||
tooltipText: "Refresh package lists"
|
||||
onClicked: {
|
||||
ArchUpdaterService.doPoll()
|
||||
ArchUpdaterService.doAurPoll()
|
||||
ArchUpdaterService.forceRefresh()
|
||||
}
|
||||
colorBg: Color.mSurfaceVariant
|
||||
colorFg: Color.mOnSurface
|
||||
Layout.fillWidth: true
|
||||
enabled: !ArchUpdaterService.busy && !ArchUpdaterService.aurBusy
|
||||
}
|
||||
|
||||
NIconButton {
|
||||
icon: ArchUpdaterService.updateInProgress ? "hourglass_empty" : "system_update_alt"
|
||||
tooltipText: ArchUpdaterService.updateInProgress ? "Update in progress..." : "Update all packages"
|
||||
enabled: !ArchUpdaterService.updateInProgress
|
||||
icon: "system_update_alt"
|
||||
tooltipText: "Update all packages"
|
||||
enabled: ArchUpdaterService.totalUpdates > 0
|
||||
onClicked: {
|
||||
ArchUpdaterService.runUpdate()
|
||||
root.close()
|
||||
}
|
||||
colorBg: ArchUpdaterService.updateInProgress ? Color.mSurfaceVariant : Color.mPrimary
|
||||
colorFg: ArchUpdaterService.updateInProgress ? Color.mOnSurfaceVariant : Color.mOnPrimary
|
||||
colorBg: ArchUpdaterService.totalUpdates > 0 ? Color.mPrimary : Color.mSurfaceVariant
|
||||
colorFg: ArchUpdaterService.totalUpdates > 0 ? Color.mOnPrimary : Color.mOnSurfaceVariant
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
NIconButton {
|
||||
icon: ArchUpdaterService.updateInProgress ? "hourglass_empty" : "check_box"
|
||||
tooltipText: ArchUpdaterService.updateInProgress ? "Update in progress..." : "Update selected packages"
|
||||
enabled: !ArchUpdaterService.updateInProgress && ArchUpdaterService.selectedPackagesCount > 0
|
||||
icon: "check_box"
|
||||
tooltipText: "Update selected packages"
|
||||
enabled: ArchUpdaterService.selectedPackagesCount > 0
|
||||
onClicked: {
|
||||
if (ArchUpdaterService.selectedPackagesCount > 0) {
|
||||
ArchUpdaterService.runSelectiveUpdate()
|
||||
root.close()
|
||||
}
|
||||
}
|
||||
colorBg: ArchUpdaterService.updateInProgress ? Color.mSurfaceVariant : (ArchUpdaterService.selectedPackagesCount
|
||||
> 0 ? Color.mPrimary : Color.mSurfaceVariant)
|
||||
colorFg: ArchUpdaterService.updateInProgress ? Color.mOnSurfaceVariant : (ArchUpdaterService.selectedPackagesCount
|
||||
> 0 ? Color.mOnPrimary : Color.mOnSurfaceVariant)
|
||||
colorBg: ArchUpdaterService.selectedPackagesCount > 0 ? Color.mPrimary : Color.mSurfaceVariant
|
||||
colorFg: ArchUpdaterService.selectedPackagesCount > 0 ? Color.mOnPrimary : Color.mOnSurfaceVariant
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -64,6 +64,5 @@ NIconButton {
|
|||
|
||||
PanelService.getPanel("archUpdaterPanel").toggle(screen, this)
|
||||
ArchUpdaterService.doPoll()
|
||||
ArchUpdaterService.doAurPoll()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -8,28 +8,164 @@ import qs.Commons
|
|||
Singleton {
|
||||
id: updateService
|
||||
|
||||
// Core properties
|
||||
readonly property bool busy: checkupdatesProcess.running
|
||||
readonly property bool aurBusy: checkAurUpdatesProcess.running
|
||||
readonly property int updates: repoPackages.length
|
||||
readonly property int aurUpdates: aurPackages.length
|
||||
readonly property int totalUpdates: updates + aurUpdates
|
||||
// ============================================================================
|
||||
// CORE PROPERTIES
|
||||
// ============================================================================
|
||||
|
||||
// Package data
|
||||
property var repoPackages: []
|
||||
property var aurPackages: []
|
||||
property var selectedPackages: []
|
||||
property int selectedPackagesCount: 0
|
||||
|
||||
// Update state
|
||||
property bool updateInProgress: false
|
||||
property bool updateFailed: false
|
||||
property string lastUpdateError: ""
|
||||
|
||||
// Computed properties
|
||||
readonly property bool busy: checkupdatesProcess.running
|
||||
readonly property bool aurBusy: checkParuUpdatesProcess.running
|
||||
readonly property int updates: repoPackages.length
|
||||
readonly property int aurUpdates: aurPackages.length
|
||||
readonly property int totalUpdates: updates + aurUpdates
|
||||
|
||||
// ============================================================================
|
||||
// TIMERS
|
||||
// ============================================================================
|
||||
|
||||
// Refresh timer for post-update polling
|
||||
Timer {
|
||||
id: refreshTimer
|
||||
interval: 5000 // Increased delay to ensure updates complete
|
||||
repeat: false
|
||||
onTriggered: {
|
||||
console.log("ArchUpdater: Refreshing package lists after update...")
|
||||
// Just refresh package lists without syncing database
|
||||
doPoll()
|
||||
}
|
||||
}
|
||||
|
||||
// Timer to mark update as complete - with error handling
|
||||
Timer {
|
||||
id: updateCompleteTimer
|
||||
interval: 30000 // Increased to 30 seconds to allow more time
|
||||
repeat: false
|
||||
onTriggered: {
|
||||
console.log("ArchUpdater: Update timeout reached, checking for failures...")
|
||||
checkForUpdateFailures()
|
||||
}
|
||||
}
|
||||
|
||||
// Timer to check if update processes are still running
|
||||
Timer {
|
||||
id: updateMonitorTimer
|
||||
interval: 2000
|
||||
repeat: true
|
||||
running: updateInProgress
|
||||
onTriggered: {
|
||||
// Check if any update-related processes might still be running
|
||||
checkUpdateStatus()
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// MONITORING PROCESSES
|
||||
// ============================================================================
|
||||
|
||||
// Process to monitor update completion
|
||||
Process {
|
||||
id: updateStatusProcess
|
||||
command: ["pgrep", "-f", "(pacman|yay|paru).*(-S|-Syu)"]
|
||||
onExited: function (exitCode) {
|
||||
if (exitCode !== 0 && updateInProgress) {
|
||||
// No update processes found, update likely completed
|
||||
console.log("ArchUpdater: No update processes detected, marking update as complete")
|
||||
updateInProgress = false
|
||||
updateMonitorTimer.stop()
|
||||
|
||||
// Don't stop the complete timer - let it handle failures
|
||||
// If the update actually failed, the timer will trigger and set updateFailed = true
|
||||
|
||||
// Refresh package lists after a short delay
|
||||
Qt.callLater(() => {
|
||||
doPoll()
|
||||
}, 2000)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Process to check for errors in log file (only when update is in progress)
|
||||
Process {
|
||||
id: errorCheckProcess
|
||||
command: ["sh", "-c", "if [ -f /tmp/archupdater_output.log ]; then grep -i 'error\\|failed\\|failed to build\\|ERROR_DETECTED' /tmp/archupdater_output.log | tail -1; fi"]
|
||||
onExited: function (exitCode) {
|
||||
if (exitCode === 0 && updateInProgress) {
|
||||
// Error found in log
|
||||
console.log("ArchUpdater: Error detected in log file")
|
||||
updateInProgress = false
|
||||
updateFailed = true
|
||||
updateCompleteTimer.stop()
|
||||
updateMonitorTimer.stop()
|
||||
lastUpdateError = "Build or update error detected"
|
||||
|
||||
// Refresh to check actual state
|
||||
Qt.callLater(() => {
|
||||
doPoll()
|
||||
}, 1000)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Timer to check for errors more frequently when update is in progress
|
||||
Timer {
|
||||
id: errorCheckTimer
|
||||
interval: 5000 // Check every 5 seconds
|
||||
repeat: true
|
||||
running: updateInProgress
|
||||
onTriggered: {
|
||||
if (updateInProgress && !errorCheckProcess.running) {
|
||||
errorCheckProcess.running = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// MONITORING FUNCTIONS
|
||||
// ============================================================================
|
||||
function checkUpdateStatus() {
|
||||
if (updateInProgress && !updateStatusProcess.running) {
|
||||
updateStatusProcess.running = true
|
||||
}
|
||||
}
|
||||
|
||||
function checkForUpdateFailures() {
|
||||
console.log("ArchUpdater: Checking for update failures...")
|
||||
updateInProgress = false
|
||||
updateFailed = true
|
||||
updateCompleteTimer.stop()
|
||||
updateMonitorTimer.stop()
|
||||
|
||||
// Refresh to check actual state after a delay
|
||||
Qt.callLater(() => {
|
||||
doPoll()
|
||||
}, 2000)
|
||||
}
|
||||
|
||||
// Initial check
|
||||
Component.onCompleted: {
|
||||
getAurHelper()
|
||||
doPoll()
|
||||
doAurPoll()
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// PACKAGE CHECKING PROCESSES
|
||||
// ============================================================================
|
||||
|
||||
// Process for checking repo updates
|
||||
Process {
|
||||
id: checkupdatesProcess
|
||||
command: ["checkupdates"]
|
||||
command: ["checkupdates", "--nosync"]
|
||||
onExited: function (exitCode) {
|
||||
if (exitCode !== 0 && exitCode !== 2) {
|
||||
Logger.warn("ArchUpdater", "checkupdates failed (code:", exitCode, ")")
|
||||
|
|
@ -44,13 +180,13 @@ Singleton {
|
|||
}
|
||||
}
|
||||
|
||||
// Process for checking AUR updates
|
||||
// Process for checking AUR updates with paru specifically
|
||||
Process {
|
||||
id: checkAurUpdatesProcess
|
||||
command: ["sh", "-c", "command -v yay >/dev/null 2>&1 && yay -Qua || command -v paru >/dev/null 2>&1 && paru -Qua || echo ''"]
|
||||
id: checkParuUpdatesProcess
|
||||
command: ["paru", "-Qua"]
|
||||
onExited: function (exitCode) {
|
||||
if (exitCode !== 0) {
|
||||
Logger.warn("ArchUpdater", "AUR check failed (code:", exitCode, ")")
|
||||
Logger.warn("ArchUpdater", "paru check failed (code:", exitCode, ")")
|
||||
aurPackages = []
|
||||
}
|
||||
}
|
||||
|
|
@ -62,8 +198,12 @@ Singleton {
|
|||
}
|
||||
}
|
||||
|
||||
// Parse checkupdates output
|
||||
function parseCheckupdatesOutput(output) {
|
||||
// ============================================================================
|
||||
// PARSING FUNCTIONS
|
||||
// ============================================================================
|
||||
|
||||
// Generic package parsing function
|
||||
function parsePackageOutput(output, source) {
|
||||
const lines = output.trim().split('\n').filter(line => line.trim())
|
||||
const packages = []
|
||||
|
||||
|
|
@ -75,65 +215,83 @@ Singleton {
|
|||
"oldVersion": m[2],
|
||||
"newVersion": m[3],
|
||||
"description": `${m[1]} ${m[2]} -> ${m[3]}`,
|
||||
"source": "repo"
|
||||
"source": source
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
repoPackages = packages
|
||||
// Only update if we have new data or if this is a fresh check
|
||||
if (packages.length > 0 || output.trim() === "") {
|
||||
if (source === "repo") {
|
||||
repoPackages = packages
|
||||
} else {
|
||||
aurPackages = packages
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Parse checkupdates output
|
||||
function parseCheckupdatesOutput(output) {
|
||||
parsePackageOutput(output, "repo")
|
||||
}
|
||||
|
||||
// Parse AUR updates output
|
||||
function parseAurUpdatesOutput(output) {
|
||||
const lines = output.trim().split('\n').filter(line => line.trim())
|
||||
const packages = []
|
||||
parsePackageOutput(output, "aur")
|
||||
}
|
||||
|
||||
for (const line of lines) {
|
||||
const m = line.match(/^(\S+)\s+([^\s]+)\s+->\s+([^\s]+)$/)
|
||||
if (m) {
|
||||
packages.push({
|
||||
"name": m[1],
|
||||
"oldVersion": m[2],
|
||||
"newVersion": m[3],
|
||||
"description": `${m[1]} ${m[2]} -> ${m[3]}`,
|
||||
"source": "aur"
|
||||
})
|
||||
}
|
||||
function doPoll() {
|
||||
// Start repo updates check
|
||||
if (!busy) {
|
||||
checkupdatesProcess.running = true
|
||||
}
|
||||
|
||||
aurPackages = packages
|
||||
// Start AUR updates check
|
||||
if (!aurBusy) {
|
||||
checkParuUpdatesProcess.running = true
|
||||
}
|
||||
}
|
||||
|
||||
// Check for updates
|
||||
function doPoll() {
|
||||
if (busy)
|
||||
return
|
||||
checkupdatesProcess.running = true
|
||||
}
|
||||
// ============================================================================
|
||||
// UPDATE FUNCTIONS
|
||||
// ============================================================================
|
||||
|
||||
// Check for AUR updates
|
||||
function doAurPoll() {
|
||||
if (aurBusy)
|
||||
return
|
||||
checkAurUpdatesProcess.running = true
|
||||
// Helper function to generate update command with error detection
|
||||
function generateUpdateCommand(baseCommand) {
|
||||
return baseCommand + " 2>&1 | tee /tmp/archupdater_output.log; if [ $? -ne 0 ]; then echo 'ERROR_DETECTED'; fi; echo 'Update complete! Press Enter to close...'; read -p 'Press Enter to continue...'"
|
||||
}
|
||||
|
||||
// Update all packages (repo + AUR)
|
||||
function runUpdate() {
|
||||
if (totalUpdates === 0) {
|
||||
doPoll()
|
||||
doAurPoll()
|
||||
return
|
||||
}
|
||||
|
||||
// Reset any previous error states
|
||||
updateFailed = false
|
||||
lastUpdateError = ""
|
||||
updateInProgress = true
|
||||
// Update repos first, then AUR
|
||||
Quickshell.execDetached(["pkexec", "pacman", "-Syu", "--noconfirm"])
|
||||
Quickshell.execDetached(
|
||||
["sh", "-c", "command -v yay >/dev/null 2>&1 && yay -Sua --noconfirm || command -v paru >/dev/null 2>&1 && paru -Sua --noconfirm || true"])
|
||||
console.log("ArchUpdater: Starting full system update...")
|
||||
|
||||
// Refresh after updates with multiple attempts
|
||||
refreshAfterUpdate()
|
||||
const terminal = Quickshell.env("TERMINAL") || "xterm"
|
||||
|
||||
// Check if we have an AUR helper for full system update
|
||||
const aurHelper = getAurHelper()
|
||||
if (aurHelper && (aurUpdates > 0 || updates > 0)) {
|
||||
// Use AUR helper for full system update (handles both repo and AUR)
|
||||
const command = generateUpdateCommand(aurHelper + " -Syu")
|
||||
Quickshell.execDetached([terminal, "-e", "bash", "-c", command])
|
||||
} else if (updates > 0) {
|
||||
// Fallback to pacman if no AUR helper or only repo updates
|
||||
const command = generateUpdateCommand("sudo pacman -Syu")
|
||||
Quickshell.execDetached([terminal, "-e", "bash", "-c", command])
|
||||
}
|
||||
|
||||
// Start monitoring and timeout timers
|
||||
refreshTimer.start()
|
||||
updateCompleteTimer.start()
|
||||
updateMonitorTimer.start()
|
||||
}
|
||||
|
||||
// Update selected packages
|
||||
|
|
@ -141,7 +299,13 @@ Singleton {
|
|||
if (selectedPackages.length === 0)
|
||||
return
|
||||
|
||||
// Reset any previous error states
|
||||
updateFailed = false
|
||||
lastUpdateError = ""
|
||||
updateInProgress = true
|
||||
console.log("ArchUpdater: Starting selective update for", selectedPackages.length, "packages")
|
||||
|
||||
const terminal = Quickshell.env("TERMINAL") || "xterm"
|
||||
|
||||
// Split selected packages by source
|
||||
const repoPkgs = []
|
||||
|
|
@ -159,48 +323,140 @@ Singleton {
|
|||
}
|
||||
}
|
||||
|
||||
// Update repo packages
|
||||
// Update repo packages with sudo
|
||||
if (repoPkgs.length > 0) {
|
||||
const repoCommand = ["pkexec", "pacman", "-S", "--noconfirm"].concat(repoPkgs)
|
||||
Logger.log("ArchUpdater", "Running repo command:", repoCommand.join(" "))
|
||||
Quickshell.execDetached(repoCommand)
|
||||
const packageList = repoPkgs.join(" ")
|
||||
const command = generateUpdateCommand("sudo pacman -S " + packageList)
|
||||
Quickshell.execDetached([terminal, "-e", "bash", "-c", command])
|
||||
}
|
||||
|
||||
// Update AUR packages
|
||||
// Update AUR packages with yay/paru
|
||||
if (aurPkgs.length > 0) {
|
||||
const aurHelper = getAurHelper()
|
||||
if (aurHelper) {
|
||||
const aurCommand = [aurHelper, "-S", "--noconfirm"].concat(aurPkgs)
|
||||
Logger.log("ArchUpdater", "Running AUR command:", aurCommand.join(" "))
|
||||
Quickshell.execDetached(aurCommand)
|
||||
const packageList = aurPkgs.join(" ")
|
||||
const command = generateUpdateCommand(aurHelper + " -S " + packageList)
|
||||
Quickshell.execDetached([terminal, "-e", "bash", "-c", command])
|
||||
} else {
|
||||
Logger.warn("ArchUpdater", "No AUR helper found for packages:", aurPkgs.join(", "))
|
||||
}
|
||||
}
|
||||
|
||||
// Clear selection and refresh
|
||||
selectedPackages = []
|
||||
selectedPackagesCount = 0
|
||||
refreshAfterUpdate()
|
||||
// Start monitoring and timeout timers
|
||||
refreshTimer.start()
|
||||
updateCompleteTimer.start()
|
||||
updateMonitorTimer.start()
|
||||
}
|
||||
|
||||
// Reset update state (useful for manual recovery)
|
||||
function resetUpdateState() {
|
||||
// If update is in progress, mark it as failed first
|
||||
if (updateInProgress) {
|
||||
updateFailed = true
|
||||
}
|
||||
|
||||
updateInProgress = false
|
||||
lastUpdateError = ""
|
||||
updateCompleteTimer.stop()
|
||||
updateMonitorTimer.stop()
|
||||
refreshTimer.stop()
|
||||
|
||||
// Refresh to get current state
|
||||
doPoll()
|
||||
}
|
||||
|
||||
// Manual refresh function
|
||||
function forceRefresh() {
|
||||
// Prevent multiple simultaneous refreshes
|
||||
if (busy || aurBusy) {
|
||||
return
|
||||
}
|
||||
|
||||
// Clear error states when refreshing
|
||||
updateFailed = false
|
||||
lastUpdateError = ""
|
||||
|
||||
// Just refresh the package lists without syncing databases
|
||||
doPoll()
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// UTILITY PROCESSES
|
||||
// ============================================================================
|
||||
|
||||
// Process for checking yay availability
|
||||
Process {
|
||||
id: yayCheckProcess
|
||||
command: ["which", "yay"]
|
||||
onExited: function (exitCode) {
|
||||
if (exitCode === 0) {
|
||||
cachedAurHelper = "yay"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Process for checking paru availability
|
||||
Process {
|
||||
id: paruCheckProcess
|
||||
command: ["which", "paru"]
|
||||
onExited: function (exitCode) {
|
||||
if (exitCode === 0) {
|
||||
if (cachedAurHelper === "") {
|
||||
cachedAurHelper = "paru"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Process for syncing package databases with sudo
|
||||
Process {
|
||||
id: syncDatabaseProcess
|
||||
command: ["sudo", "pacman", "-Sy"]
|
||||
onStarted: {
|
||||
console.log("ArchUpdater: Starting database sync with sudo...")
|
||||
}
|
||||
onExited: function (exitCode) {
|
||||
console.log("ArchUpdater: Database sync exited with code:", exitCode)
|
||||
if (exitCode === 0) {
|
||||
console.log("ArchUpdater: Database sync successful")
|
||||
} else {
|
||||
console.log("ArchUpdater: Database sync failed")
|
||||
}
|
||||
|
||||
// After sync completes, wait a moment then refresh package lists
|
||||
console.log("ArchUpdater: Database sync complete, waiting before refresh...")
|
||||
Qt.callLater(() => {
|
||||
console.log("ArchUpdater: Refreshing package lists after database sync...")
|
||||
doPoll()
|
||||
}, 2000)
|
||||
}
|
||||
}
|
||||
|
||||
// Cached AUR helper detection
|
||||
property string cachedAurHelper: ""
|
||||
|
||||
// Helper function to detect AUR helper
|
||||
function getAurHelper() {
|
||||
// Check for yay first, then paru
|
||||
const yayCheck = Quickshell.exec("command -v yay", true)
|
||||
if (yayCheck.exitCode === 0 && yayCheck.stdout.trim()) {
|
||||
return "yay"
|
||||
// Return cached result if available
|
||||
if (cachedAurHelper !== "") {
|
||||
return cachedAurHelper
|
||||
}
|
||||
|
||||
const paruCheck = Quickshell.exec("command -v paru", true)
|
||||
if (paruCheck.exitCode === 0 && paruCheck.stdout.trim()) {
|
||||
return "paru"
|
||||
}
|
||||
// Check for AUR helpers using Process objects
|
||||
console.log("ArchUpdater: Detecting AUR helper...")
|
||||
|
||||
return null
|
||||
// Start the detection processes
|
||||
yayCheckProcess.running = true
|
||||
paruCheckProcess.running = true
|
||||
|
||||
// For now, return a default (will be updated by the processes)
|
||||
// In a real implementation, you'd want to wait for the processes to complete
|
||||
return "paru" // Default fallback
|
||||
}
|
||||
|
||||
// Package selection functions
|
||||
// ============================================================================
|
||||
// PACKAGE SELECTION FUNCTIONS
|
||||
// ============================================================================
|
||||
function togglePackageSelection(packageName) {
|
||||
const index = selectedPackages.indexOf(packageName)
|
||||
if (index > -1) {
|
||||
|
|
@ -225,47 +481,60 @@ Singleton {
|
|||
return selectedPackages.indexOf(packageName) > -1
|
||||
}
|
||||
|
||||
// Robust refresh after updates
|
||||
function refreshAfterUpdate() {
|
||||
// First refresh attempt after 3 seconds
|
||||
Qt.callLater(() => {
|
||||
doPoll()
|
||||
doAurPoll()
|
||||
}, 3000)
|
||||
// ============================================================================
|
||||
// REFRESH FUNCTIONS
|
||||
// ============================================================================
|
||||
|
||||
// Second refresh attempt after 8 seconds
|
||||
Qt.callLater(() => {
|
||||
doPoll()
|
||||
doAurPoll()
|
||||
}, 8000)
|
||||
|
||||
// Third refresh attempt after 15 seconds
|
||||
Qt.callLater(() => {
|
||||
doPoll()
|
||||
doAurPoll()
|
||||
updateInProgress = false
|
||||
}, 15000)
|
||||
|
||||
// Final refresh attempt after 30 seconds
|
||||
Qt.callLater(() => {
|
||||
doPoll()
|
||||
doAurPoll()
|
||||
}, 30000)
|
||||
// Function to manually sync package databases (separate from refresh)
|
||||
function syncPackageDatabases() {
|
||||
console.log("ArchUpdater: Manual database sync requested...")
|
||||
const terminal = Quickshell.env("TERMINAL") || "xterm"
|
||||
const command = "sudo pacman -Sy && echo 'Database sync complete! Press Enter to close...' && read -p 'Press Enter to continue...'"
|
||||
console.log("ArchUpdater: Executing sync command:", command)
|
||||
console.log("ArchUpdater: Terminal:", terminal)
|
||||
Quickshell.execDetached([terminal, "-e", "bash", "-c", command])
|
||||
}
|
||||
|
||||
// Function to force a complete refresh (sync + check)
|
||||
function forceCompleteRefresh() {
|
||||
console.log("ArchUpdater: Force complete refresh requested...")
|
||||
|
||||
// Start database sync process (will trigger refresh when complete)
|
||||
console.log("ArchUpdater: Starting complete refresh process...")
|
||||
syncDatabaseProcess.running = true
|
||||
}
|
||||
|
||||
// Function to sync database and refresh package lists
|
||||
function syncDatabaseAndRefresh() {
|
||||
console.log("ArchUpdater: Syncing database and refreshing package lists...")
|
||||
|
||||
// Start database sync process (will trigger refresh when complete)
|
||||
console.log("ArchUpdater: Starting database sync process...")
|
||||
syncDatabaseProcess.running = true
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// UTILITY FUNCTIONS
|
||||
// ============================================================================
|
||||
|
||||
// Notification helper
|
||||
function notify(title, body) {
|
||||
Quickshell.execDetached(["notify-send", "-a", "UpdateService", "-i", "system-software-update", title, body])
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// AUTO-POLL TIMER
|
||||
// ============================================================================
|
||||
|
||||
// Auto-poll every 15 minutes
|
||||
Timer {
|
||||
interval: 15 * 60 * 1000 // 15 minutes
|
||||
repeat: true
|
||||
running: true
|
||||
onTriggered: {
|
||||
doPoll()
|
||||
doAurPoll()
|
||||
if (!updateInProgress) {
|
||||
doPoll()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue