diff --git a/Makefile b/Makefile index b8cff08..5f2eea9 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,15 @@ BINARY := lazy-update-manager PREFIX ?= $(HOME)/.local +# Versioning: try to use git describe, fall back to 'dev' +VERSION := $(shell git describe --tags --always --dirty 2>/dev/null || echo dev) +BUILD_TIME := $(shell date -u +"%Y-%m-%dT%H:%M:%SZ") + .PHONY: build desktop desktop-dist install install-user-service enable-user-service test fmt clean build: - go build -buildvcs=false -o bin/$(BINARY) ./cmd/lazy-update-manager + @echo "Building $(BINARY) (version: $(VERSION), build time: $(BUILD_TIME))" + go build -buildvcs=false -ldflags "-X 'lazy-update-manager/internal/version.Version=$(VERSION)' -X 'lazy-update-manager/internal/version.BuildTime=$(BUILD_TIME)'" -o bin/$(BINARY) ./cmd/lazy-update-manager desktop: npm run start @@ -13,8 +18,22 @@ desktop-dist: npm run dist install: build - install -Dm755 bin/$(BINARY) $(PREFIX)/bin/$(BINARY) - install -Dm644 systemd/lazy-update-manager.desktop $(PREFIX)/share/applications/lazy-update-manager.desktop + @mkdir -p $(PREFIX)/bin + @mkdir -p $(PREFIX)/share/applications + @echo "Installing $(BINARY) to $(PREFIX)/bin" + @if [ -f "$(PREFIX)/bin/$(BINARY)" ]; then \ + if cmp -s bin/$(BINARY) "$(PREFIX)/bin/$(BINARY)"; then \ + echo "Existing binary is identical; skipping overwrite."; \ + exit 0; \ + else \ + ts=$$(date +%Y%m%d%H%M%S); \ + mv "$(PREFIX)/bin/$(BINARY)" "$(PREFIX)/bin/$(BINARY)-$$ts.bak"; \ + echo "Backed up previous binary to $(PREFIX)/bin/$(BINARY)-$$ts.bak"; \ + fi; \ + fi; \ + install -Dm755 bin/$(BINARY) $(PREFIX)/bin/$(BINARY); \ + install -Dm644 systemd/lazy-update-manager.desktop $(PREFIX)/share/applications/lazy-update-manager.desktop; \ + echo "Installed $(BINARY) to $(PREFIX)/bin" install-user-service: install install -Dm644 systemd/lazy-update-manager.service $(HOME)/.config/systemd/user/lazy-update-manager.service diff --git a/README.md b/README.md index 81235ba..752cf36 100644 --- a/README.md +++ b/README.md @@ -90,9 +90,31 @@ make desktop-dist make install ``` -This installs the binary to `~/.local/bin/lazy-update-manager`. +This installs the binary to `~/.local/bin/lazy-update-manager` and a desktop launcher to `~/.local/share/applications/lazy-update-manager.desktop`. -It also installs a desktop launcher to `~/.local/share/applications/lazy-update-manager.desktop`. +The install target now preserves the previous binary by backing it up when it differs, so installations are safe and reversible. + +### Check version and update + +After installing, check the installed version with: + +```sh +lazy-update-manager version +``` + +To update to the latest version from this repository: + +```sh +git pull --ff-only +make build +make install +``` + +If you prefer to test the local build without installing, run the bundled binary directly: + +```sh +./bin/lazy-update-manager gui +``` ## Enable Weekly Reminder diff --git a/cmd/lazy-update-manager/main.go b/cmd/lazy-update-manager/main.go index 6877448..5d10cde 100644 --- a/cmd/lazy-update-manager/main.go +++ b/cmd/lazy-update-manager/main.go @@ -17,6 +17,7 @@ import ( "lazy-update-manager/internal/notify" "lazy-update-manager/internal/state" "lazy-update-manager/internal/updater" + "lazy-update-manager/internal/version" ) func main() { @@ -39,6 +40,9 @@ func run(args []string) int { return runGUI(args[1:]) case "update": return update() + case "version": + fmt.Println(version.String()) + return 0 case "help", "-h", "--help": usage() return 0 @@ -174,6 +178,14 @@ func runGUI(args []string) int { fs := flag.NewFlagSet("gui", flag.ContinueOnError) fs.SetOutput(os.Stderr) noOpen := fs.Bool("no-open", false, "start the GUI server without opening a browser") + + // Support positional "web" argument: `lazy-update-manager gui web` + forceWeb := false + if len(args) > 0 && args[0] == "web" { + forceWeb = true + args = args[1:] + } + if err := fs.Parse(args); err != nil { return 2 } @@ -184,8 +196,19 @@ func runGUI(args []string) int { return 1 } - // Check if Electron is preferred and available - if cfg.PreferElectron && runtime.GOOS == "linux" { + // If the user explicitly requested the web interface, skip Electron + if forceWeb { + if err := gui.Run(defaultConfigPath(), defaultStatePath(), !*noOpen); err != nil { + fmt.Fprintln(os.Stderr, err) + return 1 + } + return 0 + } + + // Only try launching the Electron desktop when the caller did not request + // "-no-open" (used by the Electron wrapper to start the backend). + // This avoids the Electron<->backend launch loop. + if !*noOpen && cfg.PreferElectron && runtime.GOOS == "linux" { if err := tryElectronApp(); err == nil { return 0 } @@ -289,14 +312,16 @@ Usage: lazy-update-manager status lazy-update-manager check [-quiet] lazy-update-manager notify [-force] - lazy-update-manager gui [-no-open] + lazy-update-manager gui [web] [-no-open] lazy-update-manager update + lazy-update-manager version Commands: status Show available pacman and AUR updates check Check updates, useful for scripts and status bars notify Send a weekly desktop notification when updates exist - gui Start the graphical web interface + gui Start the graphical web interface (use 'web' to force opening in the browser) update Run paru/yay -Syu when available, otherwise sudo pacman -Syu + version Print the installed version and build time `)) } diff --git a/electron/main.cjs b/electron/main.cjs index 878e969..deddb5f 100644 --- a/electron/main.cjs +++ b/electron/main.cjs @@ -37,22 +37,29 @@ function startBackend() { let stderr = ""; const rl = readline.createInterface({ input: backendProcess.stdout }); + // Give the backend more time to start and report the URL (20s) const timeout = setTimeout(() => { - reject(new Error("Backend did not report a GUI URL.")); - }, 8000); + // include any captured stderr to aid debugging + const detail = stderr ? ("\nBackend stderr:\n" + stderr) : ""; + reject(new Error("Backend did not report a GUI URL." + detail)); + }, 20000); rl.on("line", (line) => { + console.log("backend stdout:", line); const match = line.match(/LazyUpdateManager GUI:\s+(http:\/\/127\.0\.0\.1:\d+)/); if (!match) { return; } clearTimeout(timeout); + console.log("backend reported GUI URL:", match[1]); resolve(match[1]); }); backendProcess.stderr.on("data", (chunk) => { - stderr += chunk.toString(); + const s = chunk.toString(); + stderr += s; + console.error("backend stderr:", s); }); backendProcess.on("error", (error) => { @@ -71,7 +78,13 @@ function startBackend() { } async function createWindow() { - const url = await startBackend(); + // If LAZY_BACKEND_URL is set, use it (helps debugging a separately started backend) + let url = process.env.LAZY_BACKEND_URL || null; + if (!url) { + url = await startBackend(); + } else { + console.log('Using LAZY_BACKEND_URL:', url); + } mainWindow = new BrowserWindow({ width: 1180, @@ -109,12 +122,8 @@ app.whenReady().then(async () => { try { await createWindow(); } catch (error) { - await dialog.showMessageBox({ - type: "error", - title: "LazyUpdateManager", - message: "Die Desktop-App konnte nicht gestartet werden.", - detail: error.message, - }); + // Avoid noisy GUI popups when the backend fails. Log the error and quit. + console.error('Desktop app startup failed:', error && error.message ? error.message : error); app.quit(); } }); diff --git a/internal/version/version.go b/internal/version/version.go new file mode 100644 index 0000000..7ff762c --- /dev/null +++ b/internal/version/version.go @@ -0,0 +1,10 @@ +package version + +// Version and BuildTime are set at build time using -ldflags. Defaults are provided +// for development builds. +var Version = "dev" +var BuildTime = "unknown" + +func String() string { +return Version + " (" + BuildTime + ")" +}