From e8b7d3cee508d718a7463042815e2562e14e276d Mon Sep 17 00:00:00 2001 From: LanzelotSniper Date: Sun, 25 Jan 2026 13:56:45 +0100 Subject: [PATCH] added script to build, install and uninstall openwork on linux and updated .gitignore and README.md --- .gitignore | 3 + README.md | 12 +++ scripts/linux/build-openwork.sh | 122 ++++++++++++++++++++++++++++ scripts/linux/install-openwork.sh | 86 ++++++++++++++++++++ scripts/linux/uninstall-openwork.sh | 91 +++++++++++++++++++++ 5 files changed, 314 insertions(+) create mode 100755 scripts/linux/build-openwork.sh create mode 100755 scripts/linux/install-openwork.sh create mode 100755 scripts/linux/uninstall-openwork.sh diff --git a/.gitignore b/.gitignore index 00c3f22c..0b99e120 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,6 @@ vendor/opencode/ # OpenCode local deps .opencode/node_modules/ .opencode/bun.lock + +# Local caches +.cache/ diff --git a/README.md b/README.md index 747b64e2..3e6e648e 100644 --- a/README.md +++ b/README.md @@ -153,6 +153,18 @@ pnpm build:ui pnpm test:e2e ``` +## Linux Build/Install Helpers + +From the repo root: + +```bash +./scripts/linux/build-openwork.sh +./scripts/linux/install-openwork.sh +./scripts/linux/uninstall-openwork.sh +``` + +`install`/`uninstall` may prompt for `sudo`. + ## Troubleshooting ### Linux / Wayland (Hyprland) diff --git a/scripts/linux/build-openwork.sh b/scripts/linux/build-openwork.sh new file mode 100755 index 00000000..9bca5d63 --- /dev/null +++ b/scripts/linux/build-openwork.sh @@ -0,0 +1,122 @@ +#!/usr/bin/env bash +# Build helper for OpenWork on Linux/macOS. +# Checks required tooling and then runs `pnpm build`. +set -euo pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +export PATH="$HOME/.local/bin:$PATH" +export NVM_DIR="${NVM_DIR:-$HOME/.nvm}" + +log() { printf "[build] %s\n" "$*"; } +command_exists() { command -v "$1" >/dev/null 2>&1; } + +load_nvm() { + # shellcheck disable=SC1091 + if [ -s "$NVM_DIR/nvm.sh" ]; then + . "$NVM_DIR/nvm.sh" + fi +} + +install_node() { + log "Installing Node via nvm..." + if [ ! -d "$NVM_DIR" ]; then + curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash + fi + load_nvm + nvm install 20 --latest-npm + nvm use 20 + nvm alias default 20 >/dev/null +} + +ensure_node() { + if command_exists node; then + local ver major + ver="$(node -v | sed 's/^v//')" + major="${ver%%.*}" + if [ "$major" -ge 20 ]; then + return + fi + log "Found Node version v${ver} (<20) - upgrading." + else + log "Node not found." + fi + install_node +} + +ensure_pnpm() { + load_nvm + log "Activating pnpm@10.27.0 via corepack..." + export COREPACK_HOME="${COREPACK_HOME:-$ROOT/.cache/corepack}" + mkdir -p "$COREPACK_HOME" + corepack enable >/dev/null 2>&1 || true + if corepack prepare pnpm@10.27.0 --activate; then + return + fi + log "corepack prepare failed - fallback: npm install --prefix \"$ROOT/.cache/npm-global\" pnpm@10.27.0" + mkdir -p "$ROOT/.cache/npm-global" + npm install --prefix "$ROOT/.cache/npm-global" pnpm@10.27.0 + export PATH="$ROOT/.cache/npm-global/bin:$PATH" +} + +ensure_rust() { + if ! command_exists rustup; then + log "rustup not found - installing Rust toolchain..." + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y + fi + # shellcheck disable=SC1091 + if [ -s "$HOME/.cargo/env" ]; then + . "$HOME/.cargo/env" + fi +} + +ensure_tauri_cli() { + local required="2.0.0" + if command_exists tauri; then + local current + current="$(tauri -V | awk '{print $2}')" + if printf '%s\n%s\n' "$required" "$current" | sort -C -V 2>/dev/null; then + return + fi + log "Updating tauri-cli (found v${current}, need >= ${required})..." + else + log "tauri-cli not found - installing..." + fi + cargo install tauri-cli --locked --version "${required}" +} + +ensure_opencode() { + if command_exists opencode; then + return + fi + local sidecar="$ROOT/packages/desktop/src-tauri/sidecars/opencode-x86_64-unknown-linux-gnu" + if [ -x "$sidecar" ]; then + log "Installing opencode CLI from bundled sidecar..." + mkdir -p "$HOME/.local/bin" + cp "$sidecar" "$HOME/.local/bin/opencode" + chmod +x "$HOME/.local/bin/opencode" + else + log "Warning: opencode CLI missing and sidecar not found. Install manually: https://github.com/anomalyco/opencode/releases" + fi +} + +main() { + if [ "$(uname -s)" != "Linux" ] && [ "$(uname -s)" != "Darwin" ]; then + log "Warning: this script primarily targets Linux/macOS." + fi + + ensure_node + ensure_pnpm + ensure_rust + ensure_tauri_cli + ensure_opencode + + log "Installing JS dependencies (pnpm install)..." + cd "$ROOT" + pnpm install + + log "Starting build (pnpm build)..." + pnpm build + log "Build finished. Artifacts: packages/desktop/src-tauri/target/release/bundle/" +} + +main "$@" diff --git a/scripts/linux/install-openwork.sh b/scripts/linux/install-openwork.sh new file mode 100755 index 00000000..b7fa55d6 --- /dev/null +++ b/scripts/linux/install-openwork.sh @@ -0,0 +1,86 @@ +#!/usr/bin/env bash +# Install helper that uses artifacts from target/release/bundle. +set -euo pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +BUNDLE="$ROOT/packages/desktop/src-tauri/target/release/bundle" + +log() { printf "[install] %s\n" "$*"; } +die() { printf "[install] ERROR: %s\n" "$*" >&2; exit 1; } +latest_file() { + local pattern="$1" + ls -t ${pattern} 2>/dev/null | head -n1 || true +} + +install_linux() { + local deb appimage + deb="$(latest_file "$BUNDLE/deb/*.deb")" + appimage="$(latest_file "$BUNDLE/appimage/*.AppImage")" + + if [ -n "$deb" ] && command -v dpkg >/dev/null 2>&1; then + log "Installing Debian package: $deb" + sudo dpkg -i "$deb" + log "Done. OpenWork should now appear in your application menu." + return + fi + + if [ -n "$appimage" ]; then + log "No usable .deb found - falling back to AppImage: $appimage" + mkdir -p "$HOME/.local/bin" + cp "$appimage" "$HOME/.local/bin/openwork.AppImage" + chmod +x "$HOME/.local/bin/openwork.AppImage" + cat > "$HOME/.local/bin/openwork" <<'EOF' +#!/usr/bin/env bash +exec "$(dirname "$0")/openwork.AppImage" "$@" +EOF + chmod +x "$HOME/.local/bin/openwork" + log "AppImage installed to $HOME/.local/bin. Ensure $HOME/.local/bin is on PATH (for example via ~/.profile). Launch with: openwork" + return + fi + + die "No Linux artifacts found. Run scripts/linux/build-openwork.sh first." +} + +install_macos() { + local dmg + dmg="$(latest_file "$BUNDLE/macos/OpenWork_*.dmg")" + [ -n "$dmg" ] || die "No DMG found. Run the build script first." + + local mnt="/Volumes/OpenWorkInstaller" + log "Mounting DMG: $dmg" + hdiutil attach "$dmg" -mountpoint "$mnt" -quiet + trap 'hdiutil detach "$mnt" -quiet || true' EXIT + + if [ -d "$mnt/OpenWork.app" ]; then + log "Copying to /Applications..." + rm -rf /Applications/OpenWork.app + cp -R "$mnt/OpenWork.app" /Applications/ + else + die "OpenWork.app not found inside the DMG." + fi + + hdiutil detach "$mnt" -quiet + trap - EXIT + log "Installed. Launch OpenWork from /Applications." +} + +install_windows() { + local msi exe + msi="$(latest_file "$BUNDLE/msi/*.msi")" + exe="$(latest_file "$BUNDLE/nsis/*setup*.exe")" + if [ -z "$msi" ] && [ -z "$exe" ]; then + die "No Windows installers found. Run the build script first." + fi + log "Please run the installer manually (double-click): ${msi:-$exe}" +} + +main() { + case "$(uname -s)" in + Linux) install_linux ;; + Darwin) install_macos ;; + MINGW*|MSYS*|CYGWIN*|Windows_NT) install_windows ;; + *) die "Unsupported OS: $(uname -s)" ;; + esac +} + +main "$@" diff --git a/scripts/linux/uninstall-openwork.sh b/scripts/linux/uninstall-openwork.sh new file mode 100755 index 00000000..33ae3065 --- /dev/null +++ b/scripts/linux/uninstall-openwork.sh @@ -0,0 +1,91 @@ +#!/usr/bin/env bash +# Uninstall helper for OpenWork artifacts and packages. +set -euo pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +BUNDLE="$ROOT/packages/desktop/src-tauri/target/release/bundle" + +log() { printf "[uninstall] %s\n" "$*"; } +die() { printf "[uninstall] ERROR: %s\n" "$*" >&2; exit 1; } +latest_file() { + local pattern="$1" + ls -t ${pattern} 2>/dev/null | head -n1 || true +} + +detect_deb_package_name() { + local control_file pkg + control_file="$(latest_file "$BUNDLE/deb/"*/control/control)" + if [ -n "$control_file" ]; then + pkg="$(awk -F': ' '/^Package:/{print $2; exit}' "$control_file")" + if [ -n "$pkg" ]; then + printf "%s" "$pkg" + return + fi + fi + # Fallback for older builds or missing bundle metadata. + printf "open-work" +} + +remove_appimage_install() { + local removed=0 + if [ -f "$HOME/.local/bin/openwork" ]; then + rm -f "$HOME/.local/bin/openwork" + removed=1 + fi + if [ -f "$HOME/.local/bin/openwork.AppImage" ]; then + rm -f "$HOME/.local/bin/openwork.AppImage" + removed=1 + fi + if [ "$removed" -eq 1 ]; then + log "Removed AppImage launchers from $HOME/.local/bin." + fi +} + +uninstall_linux() { + command -v dpkg >/dev/null 2>&1 || die "dpkg not found." + + local pkg="open-work" + pkg="$(detect_deb_package_name)" + log "Detected Debian package name: $pkg" + + if dpkg -s "$pkg" >/dev/null 2>&1; then + if command -v apt-get >/dev/null 2>&1; then + log "Removing package via apt-get..." + sudo apt-get remove -y "$pkg" || sudo dpkg -r "$pkg" + else + log "Removing package via dpkg..." + sudo dpkg -r "$pkg" + fi + log "Package removed: $pkg" + else + log "Package not installed: $pkg" + fi + + remove_appimage_install + log "Linux uninstall complete." +} + +uninstall_macos() { + if [ -d "/Applications/OpenWork.app" ]; then + log "Removing /Applications/OpenWork.app..." + rm -rf /Applications/OpenWork.app + log "Removed /Applications/OpenWork.app" + else + log "OpenWork.app not found in /Applications." + fi +} + +uninstall_windows() { + log "Please uninstall OpenWork from Settings > Apps on Windows." +} + +main() { + case "$(uname -s)" in + Linux) uninstall_linux ;; + Darwin) uninstall_macos ;; + MINGW*|MSYS*|CYGWIN*|Windows_NT) uninstall_windows ;; + *) die "Unsupported OS: $(uname -s)" ;; + esac +} + +main "$@"