From 5b5d41acf8f69398eb6255a0cb5e9a29800def9c Mon Sep 17 00:00:00 2001 From: Ly-sec Date: Sun, 30 Nov 2025 11:32:54 +0100 Subject: [PATCH] AboutTab: possible fix for arch commit with git versions --- Assets/Translations/de.json | 1 - Assets/Translations/en.json | 1 - Assets/Translations/es.json | 1 - Assets/Translations/fr.json | 1 - Assets/Translations/ja.json | 1 - Assets/Translations/nl.json | 1 - Assets/Translations/pt.json | 1 - Assets/Translations/ru.json | 1 - Assets/Translations/tr.json | 1 - Assets/Translations/uk-UA.json | 1 - Assets/Translations/zh-CN.json | 1 - Modules/Panels/Settings/Tabs/AboutTab.qml | 172 ++++++++++------------ Services/Noctalia/GitHubService.qml | 117 +++------------ 13 files changed, 91 insertions(+), 209 deletions(-) diff --git a/Assets/Translations/de.json b/Assets/Translations/de.json index 70eff142..6ebd6d59 100644 --- a/Assets/Translations/de.json +++ b/Assets/Translations/de.json @@ -792,7 +792,6 @@ "noctalia": { "download-latest": "Neueste Version herunterladen", "git-commit": "Git-Commit:", - "git-commit-copy": "Commit-Hash kopieren", "git-commit-loading": "Lädt...", "installed-version": "Installierte Version:", "latest-version": "Neueste Version:", diff --git a/Assets/Translations/en.json b/Assets/Translations/en.json index c1bad06b..f9f21cd7 100644 --- a/Assets/Translations/en.json +++ b/Assets/Translations/en.json @@ -792,7 +792,6 @@ "noctalia": { "download-latest": "Download latest release", "git-commit": "Git commit:", - "git-commit-copy": "Copy commit hash", "git-commit-loading": "Loading...", "installed-version": "Installed version:", "latest-version": "Latest version:", diff --git a/Assets/Translations/es.json b/Assets/Translations/es.json index 4a4c2dfb..aed6aecc 100644 --- a/Assets/Translations/es.json +++ b/Assets/Translations/es.json @@ -792,7 +792,6 @@ "noctalia": { "download-latest": "Descargar la última versión", "git-commit": "Commit de Git:", - "git-commit-copy": "Copiar hash del commit", "git-commit-loading": "Cargando...", "installed-version": "Versión instalada:", "latest-version": "Última versión:", diff --git a/Assets/Translations/fr.json b/Assets/Translations/fr.json index aa23424c..4fde4b94 100644 --- a/Assets/Translations/fr.json +++ b/Assets/Translations/fr.json @@ -792,7 +792,6 @@ "noctalia": { "download-latest": "Télécharger la dernière version", "git-commit": "Commit Git :", - "git-commit-copy": "Copier le hash du commit", "git-commit-loading": "Chargement...", "installed-version": "Version installée :", "latest-version": "Dernière version :", diff --git a/Assets/Translations/ja.json b/Assets/Translations/ja.json index 69d6db83..6726d7d9 100644 --- a/Assets/Translations/ja.json +++ b/Assets/Translations/ja.json @@ -792,7 +792,6 @@ "noctalia": { "download-latest": "最新版をダウンロード", "git-commit": "Gitコミット:", - "git-commit-copy": "コミットハッシュをコピー", "git-commit-loading": "読み込み中...", "installed-version": "現在のバージョン:", "latest-version": "最新のバージョン:", diff --git a/Assets/Translations/nl.json b/Assets/Translations/nl.json index 87e010cc..6b88a794 100644 --- a/Assets/Translations/nl.json +++ b/Assets/Translations/nl.json @@ -792,7 +792,6 @@ "noctalia": { "download-latest": "Nieuwste release downloaden", "git-commit": "Git commit:", - "git-commit-copy": "Commit hash kopiëren", "git-commit-loading": "Laden...", "installed-version": "Geïnstalleerde versie:", "latest-version": "Nieuwste versie:", diff --git a/Assets/Translations/pt.json b/Assets/Translations/pt.json index 9aea8add..48aa5353 100644 --- a/Assets/Translations/pt.json +++ b/Assets/Translations/pt.json @@ -792,7 +792,6 @@ "noctalia": { "download-latest": "Baixar a versão mais recente", "git-commit": "Commit Git:", - "git-commit-copy": "Copiar hash do commit", "git-commit-loading": "Carregando...", "installed-version": "Versão instalada:", "latest-version": "Última versão:", diff --git a/Assets/Translations/ru.json b/Assets/Translations/ru.json index cff9d09f..fc528711 100644 --- a/Assets/Translations/ru.json +++ b/Assets/Translations/ru.json @@ -792,7 +792,6 @@ "noctalia": { "download-latest": "Скачать последний выпуск", "git-commit": "Git коммит:", - "git-commit-copy": "Скопировать хеш коммита", "git-commit-loading": "Загрузка...", "installed-version": "Установленная версия:", "latest-version": "Последняя версия:", diff --git a/Assets/Translations/tr.json b/Assets/Translations/tr.json index 0541b48a..7adb3b0a 100644 --- a/Assets/Translations/tr.json +++ b/Assets/Translations/tr.json @@ -792,7 +792,6 @@ "noctalia": { "download-latest": "En son sürümü indir", "git-commit": "Git commit:", - "git-commit-copy": "Commit hash'ini kopyala", "git-commit-loading": "Yükleniyor...", "installed-version": "Yüklü sürüm:", "latest-version": "En son sürüm:", diff --git a/Assets/Translations/uk-UA.json b/Assets/Translations/uk-UA.json index d78f4a2c..f369df8e 100644 --- a/Assets/Translations/uk-UA.json +++ b/Assets/Translations/uk-UA.json @@ -792,7 +792,6 @@ "noctalia": { "download-latest": "Завантажити останній реліз", "git-commit": "Git коміт:", - "git-commit-copy": "Скопіювати хеш коміту", "git-commit-loading": "Завантаження...", "installed-version": "Встановлена версія:", "latest-version": "Остання версія:", diff --git a/Assets/Translations/zh-CN.json b/Assets/Translations/zh-CN.json index 287c16de..ec4b507d 100644 --- a/Assets/Translations/zh-CN.json +++ b/Assets/Translations/zh-CN.json @@ -792,7 +792,6 @@ "noctalia": { "download-latest": "下载最新版本", "git-commit": "Git提交:", - "git-commit-copy": "复制提交哈希", "git-commit-loading": "加载中...", "installed-version": "已安装版本:", "latest-version": "最新版本:", diff --git a/Modules/Panels/Settings/Tabs/AboutTab.qml b/Modules/Panels/Settings/Tabs/AboutTab.qml index e41400df..40fef4e3 100644 --- a/Modules/Panels/Settings/Tabs/AboutTab.qml +++ b/Modules/Panels/Settings/Tabs/AboutTab.qml @@ -13,12 +13,11 @@ ColumnLayout { property string latestVersion: GitHubService.latestVersion property string currentVersion: UpdateService.currentVersion - property string displayVersion: "" // The version to display (pacman or UpdateService) property var contributors: GitHubService.contributors - property string gitCommitHash: "" + property string commitInfo: "" readonly property int topContributorsCount: 20 - readonly property bool isGitVersion: root.displayVersion.endsWith("-git") || root.hasArchGitVersion() + readonly property bool isGitVersion: root.currentVersion.endsWith("-git") property int _gitSearchDepth: 0 readonly property int _maxGitSearchDepth: 5 @@ -26,45 +25,46 @@ ColumnLayout { spacing: Style.marginL Component.onCompleted: { - GitHubService.ensureDataFresh(); - - // Try to get version from pacman first (for Arch) - pacmanVersionProcess.running = true; + Logger.d("AboutTab", "Current version:", root.currentVersion); + Logger.d("AboutTab", "Is git version:", root.isGitVersion); + // Only fetch commit info for -git versions + if (root.isGitVersion) { + // Try to get Arch package version first (which includes commit hash) + Logger.d("AboutTab", "Fetching commit info for git version"); + pacmanProcess.running = true; + } else { + Logger.d("AboutTab", "Not a git version, skipping commit info fetch"); + } } Process { - id: pacmanVersionProcess - command: ["pacman", "-Q", "noctalia"] // Replace "noctalia" with your actual package name + id: pacmanProcess + command: ["pacman", "-Q", "noctalia-shell"] running: false onExited: function (exitCode) { if (exitCode === 0) { - // Output format: "noctalia 3.4.0.r113.g6aca04cd-1" var output = stdout.text.trim(); - var parts = output.split(" "); - if (parts.length >= 2) { - var version = parts[1]; - root.displayVersion = version; - Logger.d("AboutTab", "Pacman version:", version); - - // Now check if it's a git version and extract hash - if (root.isGitVersion) { - var archHash = root.extractCommitFromArchVersion(); - if (archHash) { - root.gitCommitHash = archHash; - Logger.d("AboutTab", "Extracted hash from pacman version:", archHash); - } else { - // If we couldn't extract from version string, try git command - fetchGitCommit(); - } + var match = output.match(/noctalia-shell\s+(.+)/); + if (match && match[1]) { + // For Arch packages, the version format might be like: 3.4.0.r112.g3f00bec8-1 + // Extract just the commit hash part if it exists + var version = match[1]; + var commitMatch = version.match(/\.g([0-9a-f]{7,})/i); + if (commitMatch && commitMatch[1]) { + // Show short hash (first 7 characters) + root.commitInfo = commitMatch[1].substring(0, 7); + Logger.d("AboutTab", "Arch package commit hash:", root.commitInfo); + } else { + // If no commit hash in version, use full version + root.commitInfo = version; + Logger.d("AboutTab", "Arch package version:", version); } - } else { - Logger.w("AboutTab", "Unexpected pacman output format:", output); - fallbackToUpdateService(); } } else { - Logger.d("AboutTab", "Pacman not available or package not found, using UpdateService version"); - fallbackToUpdateService(); + // If not on Arch, try to get git commit + Logger.d("AboutTab", "Pacman not available or package not found, trying git"); + fetchGitCommit(); } } @@ -72,41 +72,6 @@ ColumnLayout { stderr: StdioCollector {} } - function fallbackToUpdateService() { - // Fall back to UpdateService version - root.displayVersion = root.currentVersion; - - if (root.isGitVersion) { - fetchGitCommit(); - } - } - - function hasArchGitVersion() { - // Check if version matches Arch package format: X.Y.Z.rN.gHASH-REV - // Pattern: version.r.g- - // Handle both with and without "v" prefix: v3.4.0.r112.g3f00bec8-1 or 3.4.0.r112.g3f00bec8-1 - var version = root.displayVersion.replace(/^v/, ""); // Remove "v" prefix if present - return /\.r\d+\.g[0-9a-fA-F]+-/.test(version); - } - - function extractCommitFromArchVersion() { - // Extract commit hash from Arch package version format - // Format: 3.4.0.r112.g3f00bec8-1 or v3.4.0.r112.g3f00bec8-1 - // We want to extract the hash after ".g" and before "-" - var version = root.displayVersion.replace(/^v/, ""); // Remove "v" prefix if present - Logger.d("AboutTab", "Extracting from version:", version); - var match = version.match(/\.g([0-9a-fA-F]+)-/i); - Logger.d("AboutTab", "Match result:", match ? match[1] : "no match"); - if (match && match[1]) { - // Return up to 7 characters (or less if hash is shorter) - var hashLength = Math.min(7, match[1].length); - var hash = match[1].substring(0, hashLength); - Logger.d("AboutTab", "Extracted hash:", hash); - return hash; - } - return ""; - } - function fetchGitCommit() { // Try to find git repository starting from shellDir and going up var searchDir = Quickshell.shellDir || ""; @@ -119,32 +84,31 @@ ColumnLayout { root._gitSearchDepth = 0; // Try current directory first, then parent directories - gitCommitProcess.workingDirectory = searchDir; - gitCommitProcess.running = true; + gitProcess.workingDirectory = searchDir; + gitProcess.running = true; } Process { - id: gitCommitProcess - command: ["git", "rev-parse", "HEAD"] + id: gitProcess + command: ["git", "rev-parse", "--short", "HEAD"] running: false onExited: function (exitCode) { if (exitCode === 0) { - var commitHash = stdout.text.trim(); - if (commitHash) { - // Show short hash (first 7 characters) - root.gitCommitHash = commitHash.substring(0, 7); - Logger.d("AboutTab", "Git commit hash:", root.gitCommitHash); + var gitOutput = stdout.text.trim(); + if (gitOutput) { + root.commitInfo = gitOutput; + Logger.d("AboutTab", "Git commit hash:", gitOutput); } } else { // If git command fails, try parent directory (up to max depth) if (root._gitSearchDepth < root._maxGitSearchDepth) { - var currentDir = gitCommitProcess.workingDirectory || ""; + var currentDir = gitProcess.workingDirectory || ""; var parentDir = currentDir.split("/").slice(0, -1).join("/"); if (parentDir && parentDir !== currentDir && parentDir.length > 0) { root._gitSearchDepth++; - gitCommitProcess.workingDirectory = parentDir; - gitCommitProcess.running = true; + gitProcess.workingDirectory = parentDir; + gitProcess.running = true; } else { Logger.d("AboutTab", "Could not find git repository"); } @@ -189,40 +153,52 @@ ColumnLayout { } NText { - text: root.displayVersion || root.currentVersion + text: root.currentVersion color: Color.mOnSurface font.weight: Style.fontWeightBold } - // Git commit hash (only shown for -git versions) NText { visible: root.isGitVersion text: I18n.tr("settings.about.noctalia.git-commit") color: Color.mOnSurface } - RowLayout { + NText { visible: root.isGitVersion - spacing: Style.marginXS + text: root.commitInfo || I18n.tr("settings.about.noctalia.git-commit-loading") + color: Color.mOnSurface + font.weight: Style.fontWeightBold + font.family: root.commitInfo ? "monospace" : "" + pointSize: Style.fontSizeXS + } + } - NText { - text: root.gitCommitHash || I18n.tr("settings.about.noctalia.git-commit-loading") - color: Color.mOnSurface - font.weight: Style.fontWeightBold - font.family: "monospace" - } + // Update button + NButton { + visible: { + if (root.latestVersion === "Unknown") + return false; - NIconButton { - visible: root.gitCommitHash !== "" - icon: "clipboard-copy" - tooltipText: I18n.tr("settings.about.noctalia.git-commit-copy") - baseSize: Style.baseWidgetSize * 0.7 - onClicked: { - if (root.gitCommitHash) { - Quickshell.execDetached(["sh", "-c", `echo -n "${root.gitCommitHash}" | wl-copy`]); - } - } + const latest = root.latestVersion.replace("v", "").split("."); + const current = root.currentVersion.replace("v", "").split("."); + for (var i = 0; i < Math.max(latest.length, current.length); i++) { + const l = parseInt(latest[i] || "0"); + const c = parseInt(current[i] || "0"); + if (l > c) + return true; + + if (l < c) + return false; } + return false; + } + icon: "download" + text: I18n.tr("settings.about.noctalia.download-latest") + outlined: !hovered + fontSize: Style.fontSizeXS + onClicked: { + Quickshell.execDetached(["xdg-open", "https://github.com/Ly-sec/Noctalia/releases/latest"]); } } } diff --git a/Services/Noctalia/GitHubService.qml b/Services/Noctalia/GitHubService.qml index bd285f17..ea8d103a 100644 --- a/Services/Noctalia/GitHubService.qml +++ b/Services/Noctalia/GitHubService.qml @@ -14,10 +14,6 @@ Singleton { property bool isFetchingData: false readonly property alias data: adapter // Used to access via GitHubService.data.xxx.yyy - // GitHub API authentication - readonly property string githubToken: Quickshell.env("GITHUB_TOKEN") || "" - readonly property bool hasAuth: githubToken !== "" - // Public properties for easy access property string latestVersion: I18n.tr("system.unknown-version") property var contributors: [] @@ -48,11 +44,10 @@ Singleton { } onLoadFailed: function (error) { if (error.toString().includes("No such file") || error === 2) { - // File doesn't exist - don't fetch on startup, just initialize empty - Logger.d("GitHub", "Cache file doesn't exist, will fetch when needed"); - data.version = I18n.tr("system.unknown-version"); - data.contributors = []; - data.timestamp = 0; + // Fetch data after a short delay to ensure file is created + Qt.callLater(() => { + fetchFromGitHub(); + }); } } @@ -77,7 +72,7 @@ Singleton { var needsRefetch = false; if (!data.timestamp || (now >= data.timestamp + githubUpdateFrequency)) { needsRefetch = true; - Logger.d("GitHub", "Cache expired or missing, will fetch when needed"); + Logger.d("GitHub", "Cache expired or missing, scheduling fetch"); } else { Logger.d("GitHub", "Loading cached GitHub data (age:", Math.round((now - data.timestamp) / 60), "minutes)"); } @@ -89,16 +84,7 @@ Singleton { root.contributors = data.contributors; } - // Don't fetch on startup - only fetch when explicitly requested (e.g., when About tab opens) - // This prevents rate limiting on startup - } - - // -------------------------------- - function ensureDataFresh() { - // Check if we need to fetch and do so if needed - const now = Time.timestamp; - if (!data.timestamp || (now >= data.timestamp + githubUpdateFrequency)) { - Logger.d("GitHub", "Cache expired, fetching fresh data"); + if (needsRefetch) { fetchFromGitHub(); } } @@ -150,19 +136,6 @@ Singleton { fetchFromGitHub(); } - // -------------------------------- - function handleRateLimit() { - Logger.w("GitHub", "Rate limit hit - extending cache expiration to avoid further requests"); - // Extend cache expiration by 1 hour to avoid hitting rate limit again - if (data.timestamp) { - data.timestamp = Time.timestamp + githubUpdateFrequency; - } - - if (!root.hasAuth) { - Logger.w("GitHub", "Consider setting GITHUB_TOKEN environment variable to increase rate limit from 60 to 5000 requests/hour"); - } - } - // -------------------------------- // Avatar Caching Functions // -------------------------------- @@ -446,42 +419,14 @@ Singleton { Process { id: versionProcess - command: root.hasAuth ? ["sh", "-c", "curl -s -w '\\n%{http_code}' -H 'Authorization: token " + root.githubToken + "' 'https://api.github.com/repos/noctalia-dev/noctalia-shell/releases/latest'"] : ["sh", "-c", "curl -s -w '\\n%{http_code}' 'https://api.github.com/repos/noctalia-dev/noctalia-shell/releases/latest'"] + command: ["curl", "-s", "https://api.github.com/repos/noctalia-dev/noctalia-shell/releases/latest"] stdout: StdioCollector { onStreamFinished: { try { - var response = text; - if (!response || !response.trim()) { - Logger.w("GitHub", "Empty response from GitHub API"); - checkAndSaveData(); - return; - } - - // Extract HTTP status code (last line) and response body - var lines = response.trim().split('\n'); - var statusCode = lines.length > 1 ? parseInt(lines[lines.length - 1]) : 200; - var responseBody = lines.length > 1 ? lines.slice(0, -1).join('\n') : response; - - // Check for rate limit status codes - if (statusCode === 403 || statusCode === 429) { - Logger.w("GitHub", "Rate limit hit (HTTP", statusCode + ")"); - root.handleRateLimit(); - checkAndSaveData(); - return; - } - - if (responseBody && responseBody.trim()) { - const data = JSON.parse(responseBody); - - // Check for rate limit in response message - if (data.message && (data.message.includes("API rate limit") || data.message.includes("rate limit"))) { - Logger.w("GitHub", "Rate limit exceeded:", data.message); - root.handleRateLimit(); - checkAndSaveData(); - return; - } - + const response = text; + if (response && response.trim()) { + const data = JSON.parse(response); if (data.tag_name) { const version = data.tag_name; root.data.version = version; @@ -492,6 +437,8 @@ Singleton { } else { Logger.w("GitHub", "No tag_name in GitHub response"); } + } else { + Logger.w("GitHub", "Empty response from GitHub API"); } } catch (e) { Logger.e("GitHub", "Failed to parse version:", e); @@ -506,51 +453,21 @@ Singleton { Process { id: contributorsProcess - command: root.hasAuth ? ["sh", "-c", "curl -s -w '\\n%{http_code}' -H 'Authorization: token " + root.githubToken + "' 'https://api.github.com/repos/noctalia-dev/noctalia-shell/contributors?per_page=100'"] : ["sh", "-c", "curl -s -w '\\n%{http_code}' 'https://api.github.com/repos/noctalia-dev/noctalia-shell/contributors?per_page=100'"] + command: ["curl", "-s", "https://api.github.com/repos/noctalia-dev/noctalia-shell/contributors?per_page=100"] stdout: StdioCollector { onStreamFinished: { try { - var response = text; + const response = text; Logger.d("GitHub", "Raw contributors response length:", response ? response.length : 0); - - if (!response || !response.trim()) { - Logger.w("GitHub", "Empty response from GitHub API for contributors"); - root.data.contributors = []; - root.contributors = []; - checkAndSaveData(); - return; - } - - // Extract HTTP status code (last line) and response body - var lines = response.trim().split('\n'); - var statusCode = lines.length > 1 ? parseInt(lines[lines.length - 1]) : 200; - var responseBody = lines.length > 1 ? lines.slice(0, -1).join('\n') : response; - - // Check for rate limit status codes - if (statusCode === 403 || statusCode === 429) { - Logger.w("GitHub", "Rate limit hit (HTTP", statusCode + ")"); - root.handleRateLimit(); - checkAndSaveData(); - return; - } - - if (responseBody && responseBody.trim()) { - const data = JSON.parse(responseBody); - - // Check for rate limit in response message - if (data.message && (data.message.includes("API rate limit") || data.message.includes("rate limit"))) { - Logger.w("GitHub", "Rate limit exceeded:", data.message); - root.handleRateLimit(); - checkAndSaveData(); - return; - } - + if (response && response.trim()) { + const data = JSON.parse(response); Logger.d("GitHub", "Parsed contributors data type:", typeof data, "length:", Array.isArray(data) ? data.length : "not array"); root.data.contributors = data || []; root.contributors = root.data.contributors; Logger.d("GitHub", "Contributors fetched from GitHub:", root.contributors.length); } else { + Logger.w("GitHub", "Empty response from GitHub API for contributors"); root.data.contributors = []; root.contributors = []; }