Removed ArchUpdateService
This commit is contained in:
parent
7d2eaa46e6
commit
5079fc78d3
1 changed files with 0 additions and 704 deletions
|
|
@ -1,704 +0,0 @@
|
||||||
pragma Singleton
|
|
||||||
|
|
||||||
import QtQuick
|
|
||||||
import Quickshell
|
|
||||||
import Quickshell.Io
|
|
||||||
import qs.Commons
|
|
||||||
|
|
||||||
Singleton {
|
|
||||||
id: updateService
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// CORE PROPERTIES
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
// Package data
|
|
||||||
property var repoPackages: []
|
|
||||||
property var aurPackages: []
|
|
||||||
property var selectedPackages: []
|
|
||||||
property int selectedPackagesCount: 0
|
|
||||||
property string allUpdatesOutput: ""
|
|
||||||
|
|
||||||
// Update state
|
|
||||||
property bool updateInProgress: false
|
|
||||||
property bool updateFailed: false
|
|
||||||
property string lastUpdateError: ""
|
|
||||||
property bool checkFailed: false
|
|
||||||
property string lastCheckError: ""
|
|
||||||
|
|
||||||
// Monitoring state
|
|
||||||
property string capturedErrorText: ""
|
|
||||||
property string capturedSuccessText: ""
|
|
||||||
|
|
||||||
// Computed properties
|
|
||||||
readonly property bool aurBusy: checkAurUpdatesProcess.running || checkAurOnlyProcess.running
|
|
||||||
readonly property int updates: repoPackages.length
|
|
||||||
readonly property int aurUpdates: aurPackages.length
|
|
||||||
readonly property int totalUpdates: updates + aurUpdates
|
|
||||||
|
|
||||||
// Terminal validation
|
|
||||||
readonly property bool terminalAvailable: Quickshell.env("TERMINAL") !== ""
|
|
||||||
readonly property string terminalError: "TERMINAL environment variable not set"
|
|
||||||
|
|
||||||
// AUR helper validation
|
|
||||||
readonly property bool aurHelperAvailable: cachedAurHelper !== ""
|
|
||||||
readonly property string aurHelperError: "No AUR helper found (yay or paru not installed)"
|
|
||||||
|
|
||||||
// Polling cooldown (prevent excessive polling)
|
|
||||||
property int lastPollTime: 0
|
|
||||||
readonly property int pollCooldownMs: 5 * 60 * 1000 // 5 minutes
|
|
||||||
readonly property bool canPoll: (Date.now() - lastPollTime) > pollCooldownMs
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// TIMERS
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
// Refresh timer for post-update polling
|
|
||||||
Timer {
|
|
||||||
id: refreshTimer
|
|
||||||
interval: 5000
|
|
||||||
repeat: false
|
|
||||||
onTriggered: {
|
|
||||||
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: {
|
|
||||||
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", "(yay|paru).*(-S|-Syu)"]
|
|
||||||
onExited: function (exitCode) {
|
|
||||||
if (exitCode !== 0 && updateInProgress) {
|
|
||||||
// No update processes found, update likely completed
|
|
||||||
updateInProgress = false
|
|
||||||
updateMonitorTimer.stop()
|
|
||||||
errorCheckTimer.stop()
|
|
||||||
successCheckTimer.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 'failed to build\\|could not resolve\\|unable to satisfy\\|failed to install\\|failed to upgrade\\|error:' /tmp/archupdater_output.log | grep -v 'ERROR_DETECTED' | tail -1; fi"]
|
|
||||||
onExited: function (exitCode) {
|
|
||||||
if (exitCode === 0 && updateInProgress && capturedErrorText.trim() !== "") {
|
|
||||||
// Error found in log
|
|
||||||
updateInProgress = false
|
|
||||||
updateFailed = true
|
|
||||||
updateCompleteTimer.stop()
|
|
||||||
updateMonitorTimer.stop()
|
|
||||||
errorCheckTimer.stop()
|
|
||||||
successCheckTimer.stop()
|
|
||||||
lastUpdateError = "Build or update error detected"
|
|
||||||
|
|
||||||
// Refresh to check actual state
|
|
||||||
Qt.callLater(() => {
|
|
||||||
doPoll()
|
|
||||||
}, 1000)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stdout: StdioCollector {
|
|
||||||
onStreamFinished: {
|
|
||||||
capturedErrorText = text || ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process to check for successful completion
|
|
||||||
Process {
|
|
||||||
id: successCheckProcess
|
|
||||||
command: ["sh", "-c", "if [ -f /tmp/archupdater_output.log ]; then grep -i 'Update complete!\\|:: Running post-transaction hooks\\|:: Processing package changes\\|upgrading.*\\.\\.\\.\\|installing.*\\.\\.\\.\\|removing.*\\.\\.\\.' /tmp/archupdater_output.log | tail -1; fi"]
|
|
||||||
onExited: function (exitCode) {
|
|
||||||
if (exitCode === 0 && updateInProgress && capturedSuccessText.trim() !== "") {
|
|
||||||
// Success indicators found
|
|
||||||
updateInProgress = false
|
|
||||||
updateFailed = false
|
|
||||||
updateCompleteTimer.stop()
|
|
||||||
updateMonitorTimer.stop()
|
|
||||||
errorCheckTimer.stop()
|
|
||||||
successCheckTimer.stop()
|
|
||||||
lastUpdateError = ""
|
|
||||||
|
|
||||||
// Refresh to check actual state
|
|
||||||
Qt.callLater(() => {
|
|
||||||
doPoll()
|
|
||||||
}, 1000)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stdout: StdioCollector {
|
|
||||||
onStreamFinished: {
|
|
||||||
capturedSuccessText = text || ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Timer to check for success more frequently when update is in progress
|
|
||||||
Timer {
|
|
||||||
id: successCheckTimer
|
|
||||||
interval: 5000 // Check every 5 seconds
|
|
||||||
repeat: true
|
|
||||||
running: updateInProgress
|
|
||||||
onTriggered: {
|
|
||||||
if (updateInProgress && !successCheckProcess.running) {
|
|
||||||
successCheckProcess.running = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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() {
|
|
||||||
updateInProgress = false
|
|
||||||
updateFailed = true
|
|
||||||
updateCompleteTimer.stop()
|
|
||||||
updateMonitorTimer.stop()
|
|
||||||
|
|
||||||
// Refresh to check actual state after a delay
|
|
||||||
Qt.callLater(() => {
|
|
||||||
doPoll()
|
|
||||||
}, 2000)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initial check
|
|
||||||
Component.onCompleted: {
|
|
||||||
// Start AUR helper detection
|
|
||||||
getAurHelper()
|
|
||||||
|
|
||||||
// Set up a fallback timer in case detection takes too long
|
|
||||||
Qt.callLater(() => {
|
|
||||||
if (cachedAurHelper === "" && !yayCheckProcess.running && !paruCheckProcess.running) {
|
|
||||||
// No AUR helper found after reasonable time and processes have finished
|
|
||||||
checkFailed = true
|
|
||||||
lastCheckError = "No AUR helper found (yay or paru not installed)"
|
|
||||||
Logger.warn("ArchUpdater", "No AUR helper found (yay or paru)")
|
|
||||||
}
|
|
||||||
}, 5000) // 5 second fallback
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// PACKAGE CHECKING PROCESSES
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
// Process for checking all updates with AUR helper (repo + AUR)
|
|
||||||
Process {
|
|
||||||
id: checkAurUpdatesProcess
|
|
||||||
command: []
|
|
||||||
onExited: function (exitCode) {
|
|
||||||
// For both yay and paru: exit code 0 = updates available, exit code 1 = no updates
|
|
||||||
if (exitCode !== 0 && exitCode !== 1) {
|
|
||||||
Logger.warn("ArchUpdater", "AUR helper check failed (code:", exitCode, ")")
|
|
||||||
checkFailed = true
|
|
||||||
lastCheckError = "Failed to check for updates (exit code: " + exitCode + ")"
|
|
||||||
aurPackages = []
|
|
||||||
repoPackages = []
|
|
||||||
}
|
|
||||||
// Don't clear checkFailed here - wait for the second process to complete
|
|
||||||
}
|
|
||||||
stdout: StdioCollector {
|
|
||||||
onStreamFinished: {
|
|
||||||
allUpdatesOutput = text
|
|
||||||
// Now get AUR-only updates to compare
|
|
||||||
checkAurOnlyProcess.running = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process for checking AUR-only updates (to separate from repo updates)
|
|
||||||
Process {
|
|
||||||
id: checkAurOnlyProcess
|
|
||||||
command: []
|
|
||||||
onExited: function (exitCode) {
|
|
||||||
// For both yay and paru: exit code 0 = updates available, exit code 1 = no updates
|
|
||||||
if (exitCode !== 0 && exitCode !== 1) {
|
|
||||||
Logger.warn("ArchUpdater", "AUR helper AUR-only check failed (code:", exitCode, ")")
|
|
||||||
checkFailed = true
|
|
||||||
lastCheckError = "Failed to check AUR updates (exit code: " + exitCode + ")"
|
|
||||||
aurPackages = []
|
|
||||||
repoPackages = []
|
|
||||||
} else {
|
|
||||||
// Only clear checkFailed if both processes succeeded
|
|
||||||
// Check if the first process also succeeded (no error was set)
|
|
||||||
if (!checkFailed) {
|
|
||||||
checkFailed = false
|
|
||||||
lastCheckError = ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stdout: StdioCollector {
|
|
||||||
onStreamFinished: {
|
|
||||||
parseAllUpdatesOutput(allUpdatesOutput, text)
|
|
||||||
Logger.log("ArchUpdater", "found", repoPackages.length, "repo package(s) and", aurPackages.length, "AUR package(s) to upgrade")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// PARSING FUNCTIONS
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
// Generic package parsing function
|
|
||||||
function parsePackageOutput(output, source) {
|
|
||||||
const lines = output.trim().split('\n').filter(line => line.trim())
|
|
||||||
const packages = []
|
|
||||||
|
|
||||||
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": source
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 all updates output (repo + AUR packages)
|
|
||||||
function parseAllUpdatesOutput(allOutput, aurOnlyOutput) {
|
|
||||||
const allLines = allOutput.trim().split('\n').filter(line => line.trim())
|
|
||||||
const aurOnlyLines = aurOnlyOutput.trim().split('\n').filter(line => line.trim())
|
|
||||||
|
|
||||||
// Create a set of AUR package names for quick lookup
|
|
||||||
const aurPackageNames = new Set()
|
|
||||||
for (const line of aurOnlyLines) {
|
|
||||||
const m = line.match(/^(\S+)\s+([^\s]+)\s+->\s+([^\s]+)$/)
|
|
||||||
if (m) {
|
|
||||||
aurPackageNames.add(m[1])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const repoPackages = []
|
|
||||||
const aurPackages = []
|
|
||||||
|
|
||||||
for (const line of allLines) {
|
|
||||||
const m = line.match(/^(\S+)\s+([^\s]+)\s+->\s+([^\s]+)$/)
|
|
||||||
if (m) {
|
|
||||||
const packageInfo = {
|
|
||||||
"name": m[1],
|
|
||||||
"oldVersion": m[2],
|
|
||||||
"newVersion": m[3],
|
|
||||||
"description": `${m[1]} ${m[2]} -> ${m[3]}`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if this package is in the AUR-only list
|
|
||||||
if (aurPackageNames.has(m[1])) {
|
|
||||||
packageInfo.source = "aur"
|
|
||||||
aurPackages.push(packageInfo)
|
|
||||||
} else {
|
|
||||||
packageInfo.source = "repo"
|
|
||||||
repoPackages.push(packageInfo)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the package lists
|
|
||||||
if (repoPackages.length > 0 || aurPackages.length > 0 || allOutput.trim() === "") {
|
|
||||||
updateService.repoPackages = repoPackages
|
|
||||||
updateService.aurPackages = aurPackages
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function doPoll() {
|
|
||||||
// Prevent excessive polling
|
|
||||||
if (aurBusy || !canPoll) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if we have a cached AUR helper
|
|
||||||
if (cachedAurHelper !== "") {
|
|
||||||
// Clear error state when helper is available
|
|
||||||
if (checkFailed && lastCheckError.includes("No AUR helper found")) {
|
|
||||||
checkFailed = false
|
|
||||||
lastCheckError = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
checkAurUpdatesProcess.command = [cachedAurHelper, "-Qu"]
|
|
||||||
checkAurOnlyProcess.command = [cachedAurHelper, getAurOnlyFlag()]
|
|
||||||
|
|
||||||
// Start AUR updates check (includes both repo and AUR packages)
|
|
||||||
checkAurUpdatesProcess.running = true
|
|
||||||
lastPollTime = Date.now()
|
|
||||||
} else {
|
|
||||||
// AUR helper detection is still in progress or failed
|
|
||||||
// Try to detect again if not already in progress
|
|
||||||
if (!yayCheckProcess.running && !paruCheckProcess.running) {
|
|
||||||
getAurHelper()
|
|
||||||
}
|
|
||||||
Logger.warn("ArchUpdater", "AUR helper detection in progress or failed")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// UPDATE FUNCTIONS
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
// 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()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset any previous error states
|
|
||||||
updateFailed = false
|
|
||||||
lastUpdateError = ""
|
|
||||||
updateInProgress = true
|
|
||||||
capturedErrorText = ""
|
|
||||||
capturedSuccessText = ""
|
|
||||||
|
|
||||||
const terminal = Quickshell.env("TERMINAL")
|
|
||||||
if (!terminal) {
|
|
||||||
updateInProgress = false
|
|
||||||
updateFailed = true
|
|
||||||
lastUpdateError = "TERMINAL environment variable not set"
|
|
||||||
ToastService.showWarning("ArchUpdater", "TERMINAL environment variable not set")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if we have an AUR helper for full system update
|
|
||||||
if (cachedAurHelper !== "" && (aurUpdates > 0 || updates > 0)) {
|
|
||||||
// Use AUR helper for full system update (handles both repo and AUR)
|
|
||||||
const command = generateUpdateCommand(cachedAurHelper + " -Syu")
|
|
||||||
Quickshell.execDetached([terminal, "-e", "bash", "-c", command])
|
|
||||||
} else if (cachedAurHelper === "") {
|
|
||||||
// No AUR helper found
|
|
||||||
updateInProgress = false
|
|
||||||
updateFailed = true
|
|
||||||
lastUpdateError = "No AUR helper found (yay or paru not installed)"
|
|
||||||
Logger.warn("ArchUpdater", "No AUR helper found for update")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start monitoring and timeout timers
|
|
||||||
refreshTimer.start()
|
|
||||||
updateCompleteTimer.start()
|
|
||||||
updateMonitorTimer.start()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update selected packages
|
|
||||||
function runSelectiveUpdate() {
|
|
||||||
if (selectedPackages.length === 0)
|
|
||||||
return
|
|
||||||
|
|
||||||
// Reset any previous error states
|
|
||||||
updateFailed = false
|
|
||||||
lastUpdateError = ""
|
|
||||||
updateInProgress = true
|
|
||||||
capturedErrorText = ""
|
|
||||||
capturedSuccessText = ""
|
|
||||||
|
|
||||||
const terminal = Quickshell.env("TERMINAL")
|
|
||||||
if (!terminal) {
|
|
||||||
updateInProgress = false
|
|
||||||
updateFailed = true
|
|
||||||
lastUpdateError = "TERMINAL environment variable not set"
|
|
||||||
ToastService.showWarning("ArchUpdater", "TERMINAL environment variable not set")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update all packages with AUR helper (handles both repo and AUR)
|
|
||||||
if (selectedPackages.length > 0) {
|
|
||||||
if (cachedAurHelper !== "") {
|
|
||||||
const packageList = selectedPackages.join(" ")
|
|
||||||
|
|
||||||
// Handle ghostty terminal differently due to command parsing issues
|
|
||||||
if (terminal.includes("ghostty")) {
|
|
||||||
const simpleCommand = cachedAurHelper + " -S " + packageList
|
|
||||||
Quickshell.execDetached([terminal, "-e", simpleCommand])
|
|
||||||
} else {
|
|
||||||
const command = generateUpdateCommand(cachedAurHelper + " -S " + packageList)
|
|
||||||
Quickshell.execDetached([terminal, "-e", "bash", "-c", command])
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
updateInProgress = false
|
|
||||||
updateFailed = true
|
|
||||||
lastUpdateError = "No AUR helper found (yay or paru not installed)"
|
|
||||||
Logger.warn("ArchUpdater", "No AUR helper found for packages:", selectedPackages.join(", "))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start monitoring and timeout timers
|
|
||||||
refreshTimer.start()
|
|
||||||
updateCompleteTimer.start()
|
|
||||||
updateMonitorTimer.start()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset update state (useful for manual recovery)
|
|
||||||
function resetUpdateState() {
|
|
||||||
// Clear all update states
|
|
||||||
updateInProgress = false
|
|
||||||
updateFailed = false
|
|
||||||
lastUpdateError = ""
|
|
||||||
checkFailed = false
|
|
||||||
lastCheckError = ""
|
|
||||||
updateCompleteTimer.stop()
|
|
||||||
updateMonitorTimer.stop()
|
|
||||||
refreshTimer.stop()
|
|
||||||
errorCheckTimer.stop()
|
|
||||||
successCheckTimer.stop()
|
|
||||||
|
|
||||||
// Refresh to get current state
|
|
||||||
doPoll()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Manual refresh function (bypasses cooldown)
|
|
||||||
function forceRefresh() {
|
|
||||||
// Prevent multiple simultaneous refreshes
|
|
||||||
if (aurBusy) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear error states when refreshing
|
|
||||||
updateFailed = false
|
|
||||||
lastUpdateError = ""
|
|
||||||
checkFailed = false
|
|
||||||
lastCheckError = ""
|
|
||||||
|
|
||||||
// Check if we have a cached AUR helper
|
|
||||||
if (cachedAurHelper !== "") {
|
|
||||||
// Clear error state when helper is available
|
|
||||||
if (checkFailed && lastCheckError.includes("No AUR helper found")) {
|
|
||||||
checkFailed = false
|
|
||||||
lastCheckError = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
checkAurUpdatesProcess.command = [cachedAurHelper, "-Qu"]
|
|
||||||
checkAurOnlyProcess.command = [cachedAurHelper, getAurOnlyFlag()]
|
|
||||||
|
|
||||||
// Force refresh by bypassing cooldown
|
|
||||||
checkAurUpdatesProcess.running = true
|
|
||||||
lastPollTime = Date.now()
|
|
||||||
} else {
|
|
||||||
// AUR helper detection is still in progress or failed
|
|
||||||
// Try to detect again if not already in progress
|
|
||||||
if (!yayCheckProcess.running && !paruCheckProcess.running) {
|
|
||||||
getAurHelper()
|
|
||||||
}
|
|
||||||
Logger.warn("ArchUpdater", "AUR helper detection in progress or failed")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// UTILITY PROCESSES
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
// Process for checking yay availability
|
|
||||||
Process {
|
|
||||||
id: yayCheckProcess
|
|
||||||
command: ["which", "yay"]
|
|
||||||
onExited: function (exitCode) {
|
|
||||||
if (exitCode === 0) {
|
|
||||||
cachedAurHelper = "yay"
|
|
||||||
Logger.log("ArchUpdater", "Found yay AUR helper (preferred)")
|
|
||||||
// Clear error state when helper is found
|
|
||||||
if (checkFailed && lastCheckError.includes("No AUR helper found")) {
|
|
||||||
checkFailed = false
|
|
||||||
lastCheckError = ""
|
|
||||||
}
|
|
||||||
// Trigger initial check when helper is found
|
|
||||||
triggerInitialCheck()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process for checking paru availability
|
|
||||||
Process {
|
|
||||||
id: paruCheckProcess
|
|
||||||
command: ["which", "paru"]
|
|
||||||
onExited: function (exitCode) {
|
|
||||||
if (exitCode === 0) {
|
|
||||||
// Only use paru if yay wasn't found (yay is preferred)
|
|
||||||
if (cachedAurHelper === "") {
|
|
||||||
cachedAurHelper = "paru"
|
|
||||||
Logger.log("ArchUpdater", "Found paru AUR helper")
|
|
||||||
// Clear error state when helper is found
|
|
||||||
if (checkFailed && lastCheckError.includes("No AUR helper found")) {
|
|
||||||
checkFailed = false
|
|
||||||
lastCheckError = ""
|
|
||||||
}
|
|
||||||
// Trigger initial check when helper is found
|
|
||||||
triggerInitialCheck()
|
|
||||||
} else {
|
|
||||||
Logger.log("ArchUpdater", "Found paru but using", cachedAurHelper, "(preferred)")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cached AUR helper detection
|
|
||||||
property string cachedAurHelper: ""
|
|
||||||
|
|
||||||
// Helper function to detect AUR helper
|
|
||||||
function getAurHelper() {
|
|
||||||
// Return cached result if available
|
|
||||||
if (cachedAurHelper !== "") {
|
|
||||||
return cachedAurHelper
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for AUR helpers using Process objects
|
|
||||||
Logger.log("ArchUpdater", "Detecting AUR helper...")
|
|
||||||
|
|
||||||
// Start the detection processes
|
|
||||||
yayCheckProcess.running = true
|
|
||||||
paruCheckProcess.running = true
|
|
||||||
|
|
||||||
// Return empty string to indicate no helper found yet
|
|
||||||
// The processes will update cachedAurHelper when they complete
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper function to get the correct AUR-only flag for the detected helper
|
|
||||||
function getAurOnlyFlag() {
|
|
||||||
if (cachedAurHelper === "yay") {
|
|
||||||
return "-Qua"
|
|
||||||
} else if (cachedAurHelper === "paru") {
|
|
||||||
return "-Qua" // paru uses the same flag but different exit code behavior
|
|
||||||
}
|
|
||||||
return "-Qua" // fallback
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper function to trigger the initial package check
|
|
||||||
function triggerInitialCheck() {
|
|
||||||
// Only trigger if this is the first time (no packages have been checked yet)
|
|
||||||
if (repoPackages.length === 0 && aurPackages.length === 0 && !aurBusy) {
|
|
||||||
// Clear any previous error state
|
|
||||||
checkFailed = false
|
|
||||||
lastCheckError = ""
|
|
||||||
|
|
||||||
// Wait a bit for the system to be ready before the first check
|
|
||||||
Qt.callLater(() => {
|
|
||||||
checkAurUpdatesProcess.command = [cachedAurHelper, "-Qu"]
|
|
||||||
checkAurOnlyProcess.command = [cachedAurHelper, getAurOnlyFlag()]
|
|
||||||
checkAurUpdatesProcess.running = true
|
|
||||||
lastPollTime = Date.now()
|
|
||||||
}, 1000)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// PACKAGE SELECTION FUNCTIONS
|
|
||||||
// ============================================================================
|
|
||||||
function togglePackageSelection(packageName) {
|
|
||||||
const index = selectedPackages.indexOf(packageName)
|
|
||||||
if (index > -1) {
|
|
||||||
selectedPackages.splice(index, 1)
|
|
||||||
} else {
|
|
||||||
selectedPackages.push(packageName)
|
|
||||||
}
|
|
||||||
selectedPackagesCount = selectedPackages.length
|
|
||||||
}
|
|
||||||
|
|
||||||
function selectAllPackages() {
|
|
||||||
selectedPackages = [...repoPackages.map(pkg => pkg.name), ...aurPackages.map(pkg => pkg.name)]
|
|
||||||
selectedPackagesCount = selectedPackages.length
|
|
||||||
}
|
|
||||||
|
|
||||||
function deselectAllPackages() {
|
|
||||||
selectedPackages = []
|
|
||||||
selectedPackagesCount = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
function isPackageSelected(packageName) {
|
|
||||||
return selectedPackages.indexOf(packageName) > -1
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// REFRESH FUNCTIONS
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// 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 (respects cooldown)
|
|
||||||
Timer {
|
|
||||||
interval: 15 * 60 * 1000 // 15 minutes
|
|
||||||
repeat: true
|
|
||||||
running: true
|
|
||||||
onTriggered: {
|
|
||||||
if (!updateInProgress && canPoll) {
|
|
||||||
doPoll()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue