Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,10 @@ jobs:
if: needs.changes.outputs.scripts == 'true'
run: bash -n scripts/install.sh

- name: Check Linux installer with isolated release assets
if: needs.changes.outputs.scripts == 'true'
run: python3 scripts/test-install-linux.py

- name: Check CI change matcher
if: needs.changes.outputs.scripts == 'true'
run: bash scripts/test-ci-relevant-changes.sh
Expand Down
43 changes: 39 additions & 4 deletions docs/install.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ against the release's `SHA256SUMS`:
| --- | --- | --- |
| macOS (Apple Silicon) | `RustCode-<ver>-macos-aarch64.app.zip` | `/Applications/RustCode.app` (`~/Applications` when `/Applications` is not writable) |
| Windows x64 | `RustCode-<ver>-windows-x64-setup.exe` | per-user install in `%LOCALAPPDATA%\RustCode`, Start menu entry |
| Linux x86_64 | `RustCode-<ver>-linux-x86_64.AppImage` | `~/Applications/RustCode.AppImage`, menu entry and icon in `~/.local/share` |
| Linux x86_64 (system WebKitGTK 4.1 available) | `RustCode-<ver>-linux-x86_64.tar.gz` | `~/.local/share/rustcode/desktop`, menu entry and shared CLI engine |
| Linux x86_64 (`--appimage`, or no system WebKitGTK) | `RustCode-<ver>-linux-x86_64.AppImage` | `~/Applications/RustCode.AppImage`, menu entry and icon in `~/.local/share` |
| Linux x86_64 (`--deb`) | `RustCode-<ver>-linux-x86_64.deb` | system package via `apt-get`/`dpkg` (asks for sudo) |

The app carries its own engine (`rustcode --acp`) inside the bundle, so it
Expand All @@ -69,6 +70,8 @@ Options (`curl … | bash -s -- <options>` on macOS and Linux):
| `--no-app` | `-NoApp` or `$env:RUSTCODE_NO_APP = "1"` | CLI only, as before |
| `--no-cli` | `-NoCli` or `$env:RUSTCODE_NO_CLI = "1"` | app only |
| `--deb` | | Linux: the `.deb` instead of the AppImage |
| `--system-webkit` | | Linux: require system WebKitGTK 4.1 and install the smaller archive |
| `--appimage` | | Linux: use the portable AppImage even with system WebKitGTK installed |
| `--bin-dir DIR` | | CLI to `DIR` instead of `/usr/local/bin` or `~/.local/bin` |
| `--version 1.31.4` or `$RUSTCODE_VERSION` | `-Version 1.31.4` or `$env:RUSTCODE_VERSION` | that release instead of the latest (`v` optional, a beta like `1.32.0-beta.2` too); a release that does not exist stops with its URL. `rustcode machines add-ssh` uses it to put the other computer on this one's version |

Expand Down Expand Up @@ -112,10 +115,13 @@ RUSTCODE_INSTALL_ARTIFACTS=/tmp/rc/art bash ../../scripts/install.sh --bin-dir /
it with `pkexec apt-get install -y` (or `pkexec dpkg -i`), which asks for
your password through polkit, then reopens. Without `pkexec` or a polkit
agent, install the new `.deb` yourself (`sudo apt install ./RustCode-<ver>-linux-x86_64.deb`).
- Linux system-WebKitGTK archive: **Update to X** verifies the archive,
replaces both binaries and reopens. The CLI symlink follows the updated
engine. No root access is needed.
- Windows: **Update to X** downloads the setup, checks it, runs it silently
(`/S /UPDATE /R`) and quits; the installer replaces the app in place and
reopens it. No administrator prompt.
- Other installs (a tarball, Flatpak, a folder RustCode cannot write, arm
- Other installs (an unrecognised folder layout, Flatpak, a folder RustCode cannot write, arm
Linux or Windows): the button links to the release;
run the installer again to update.

Expand All @@ -132,6 +138,9 @@ RUSTCODE_INSTALL_ARTIFACTS=/tmp/rc/art bash ../../scripts/install.sh --bin-dir /
`~/.local/share/applications/rustcode.desktop` and
`~/.local/share/icons/hicolor/128x128/apps/rustcode.png`.
- Linux `.deb`: `sudo apt remove rustcode` (the package name `dpkg -l | grep -i rustcode` shows).
- Linux system-WebKitGTK: remove `~/.local/share/rustcode/desktop`, its
`rustcode` CLI symlink, and the menu entry and icon listed for AppImage above.
A custom `XDG_DATA_HOME` replaces `~/.local/share`.

### Taking over from the SwiftUI app

Expand Down Expand Up @@ -204,8 +213,34 @@ continue to use `brew upgrade rustcode`.

### Arch Linux: system WebKitGTK

For smaller downloads (under 50 MB), install the system web view with
`sudo pacman -S webkit2gtk-4.1`. Download
For smaller downloads (under 50 MB), install the system web view, then run
the installer:

```sh
sudo pacman -S webkit2gtk-4.1
curl -fsSL https://rustcode.lhagfoss.com/install.sh | bash -s -- --system-webkit
```

The installer checks the release checksum and the app's shared-library
dependencies before installing. By default it selects this archive when
WebKitGTK 4.1 is available; `--system-webkit` requires it and fails with
installation guidance when it is missing. `--appimage` explicitly keeps the
portable bundle. No system packages are installed automatically.

The app lives in `${XDG_DATA_HOME:-~/.local/share}/rustcode/desktop` with a
menu entry. When the CLI is requested, the installer links it to the app's
engine instead of downloading another copy. A background server installed
from this app also uses that stable engine without copying it.

To migrate an AppImage installation, run the command above, close the old app
and open RustCode from the applications menu. Reinstall an existing background
server from the new app so it uses the new engine path. After checking that
the app, CLI and server work, remove `~/Applications/RustCode.AppImage` and
the old service engine at `~/.local/share/rustcode/bin/rustcode`. The installer
leaves these files intact because an existing process or service may use them.
`--no-cli` preserves the existing terminal command.

For a manual installation, download
`RustCode-<ver>-linux-x86_64.tar.gz` and `SHA256SUMS` from the same release,
then verify the archive with `sha256sum --ignore-missing -c SHA256SUMS`.
Unpack it into a folder you own:
Expand Down
131 changes: 115 additions & 16 deletions scripts/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
# curl -fsSL https://rustcode.lhagfoss.com/install.sh | bash -s -- --no-app
#
# Installs the `rustcode` CLI and the RustCode desktop app (macOS:
# /Applications/RustCode.app; Linux: an AppImage with a menu entry, or the
# .deb with --deb). Every download is checked against the release SHA256SUMS.
# /Applications/RustCode.app; Linux: a system-WebKitGTK app when available,
# otherwise AppImage, or .deb with --deb). Downloads are checksum-verified.
# Run with --help for the options; docs/install.md has the details.

set -euo pipefail
Expand All @@ -15,6 +15,8 @@ APP_BUNDLE_ID="com.lhagfoss.rustcode.desktop"
INSTALL_CLI=1
INSTALL_APP=1
USE_DEB=0
LINUX_APP_FORMAT=auto
CLI_SHARED=0
BIN_DIR=""
# A release to install instead of the latest one ("1.31.4" or "v1.31.4").
VERSION="${RUSTCODE_VERSION:-}"
Expand All @@ -26,12 +28,16 @@ usage() {
cat <<'USAGE'
Install the RustCode CLI and desktop app from the latest GitHub release, or
from the release --version names.
Linux uses the smaller system-WebKitGTK app when WebKitGTK 4.1 is available,
otherwise AppImage. The system app and CLI share one engine.

Options:
--no-app Install only the CLI.
--no-cli Install only the desktop app.
--deb Linux: install the desktop app's .deb with dpkg (asks for
sudo) instead of the AppImage.
--system-webkit Linux: require the smaller app using system WebKitGTK 4.1.
--appimage Linux: bundle the web view instead of using system libraries.
--bin-dir DIR Install the CLI to DIR (default /usr/local/bin when
writable, else ~/.local/bin).
--version X.Y.Z Install that release instead of the latest one.
Expand All @@ -49,6 +55,8 @@ while [ $# -gt 0 ]; do
--no-app) INSTALL_APP=0 ;;
--no-cli) INSTALL_CLI=0 ;;
--deb) USE_DEB=1 ;;
--system-webkit) LINUX_APP_FORMAT=system ;;
--appimage) LINUX_APP_FORMAT=appimage ;;
--bin-dir)
[ $# -ge 2 ] || { echo "--bin-dir needs a directory" >&2; exit 2; }
BIN_DIR="$2"
Expand All @@ -66,6 +74,10 @@ while [ $# -gt 0 ]; do
esac
shift
done
if [ "$USE_DEB" = 1 ] && [ "$LINUX_APP_FORMAT" != auto ]; then
echo "--deb cannot be combined with --system-webkit or --appimage." >&2
exit 2
fi
if [ "$INSTALL_CLI" = 0 ] && [ "$INSTALL_APP" = 0 ]; then
echo "Nothing to install: --no-app and --no-cli together." >&2
exit 2
Expand Down Expand Up @@ -363,6 +375,19 @@ manifest_asset() {
printf '%s\n' "$found"
}

select_cli_directory() {
if [ -n "$BIN_DIR" ]; then
INSTALL_DIR="$BIN_DIR"
elif [ -w /usr/local/bin ]; then
INSTALL_DIR=/usr/local/bin
else
INSTALL_DIR="${HOME}/.local/bin"
fi
mkdir -p "$INSTALL_DIR"
INSTALL_DIR="$(cd "$INSTALL_DIR" && pwd)"
TARGET_EXE="${INSTALL_DIR}/rustcode"
}

install_cli() {
local archive extracted
if ! fetch_verified "$ASSET_NAME"; then
Expand All @@ -385,17 +410,7 @@ install_cli() {

chmod +x "$extracted"

# Target installation directory
if [ -n "$BIN_DIR" ]; then
INSTALL_DIR="$BIN_DIR"
elif [ -w "/usr/local/bin" ]; then
INSTALL_DIR="/usr/local/bin"
else
INSTALL_DIR="${HOME}/.local/bin"
fi

mkdir -p "$INSTALL_DIR"
TARGET_EXE="${INSTALL_DIR}/rustcode"
select_cli_directory

if ! run_with_spinner "Installing to ${TARGET_EXE}..." cp "$extracted" "$TARGET_EXE"; then
error "Could not install RustCode to ${TARGET_EXE}."
Expand Down Expand Up @@ -555,6 +570,73 @@ install_app_macos() {
success "RustCode.app installed to ${dest}. Open it from Launchpad, Spotlight or: open -a RustCode"
}

system_webkit_available() {
command -v ldconfig >/dev/null 2>&1 || return 1
# Read the whole stream: grep -q can SIGPIPE ldconfig under pipefail.
ldconfig -p 2>/dev/null | grep 'libwebkit2gtk-4.1.so.0 ' >/dev/null
}

install_app_linux_system() {
local name="$1" stage target data missing icon pending link_stage
fetch_verified "$name" || error "Could not download ${name}."
stage="${TMP_DIR}/system-app"
mkdir -p "$stage"
tar -xzf "$VERIFIED_PATH" -C "$stage" || error "Could not extract ${name}."
[ -x "$stage/usr/bin/rustcode" ] && [ -x "$stage/usr/bin/rustcode-desktop" ] || error "${name} is missing the app or engine."
# Check the actual release's dependencies, not just the WebKit SONAME.
missing="$(ldd "$stage/usr/bin/rustcode-desktop" 2>&1)" || error "Could not inspect app dependencies: ${missing}"
if printf '%s\n' "$missing" | grep 'not found' >/dev/null; then
error "System libraries are missing: ${missing}. On Arch: sudo pacman -S webkit2gtk-4.1. Or use --appimage."
fi
data="${XDG_DATA_HOME:-${HOME}/.local/share}"
mkdir -p "$data"
data="$(cd "$data" && pwd)"
target="${data}/rustcode/desktop"
mkdir -p "$target/usr/bin" "$data/applications" "$data/icons/hicolor/128x128/apps"
pending="$(mktemp -d "$target/.install.XXXXXX")"
# Rename each executable rather than overwriting a running file or following
# an old symlink. The updater recognises this usr/bin layout.
for name in rustcode rustcode-desktop; do
install -m 755 "$stage/usr/bin/$name" "$pending/$name"
done
for name in rustcode rustcode-desktop; do
mv -fT "$pending/$name" "$target/usr/bin/$name"
done
rmdir "$pending"
icon="$(find "$stage/usr/share/icons" -path '*128x128/apps/*.png' 2>/dev/null | head -n 1 || true)"
[ -z "$icon" ] || cp "$icon" "$data/icons/hicolor/128x128/apps/rustcode.png"
cat > "$data/applications/rustcode.desktop" <<DESKTOP
[Desktop Entry]
Type=Application
Name=RustCode
Comment=The local coding agent
Exec="${target}/usr/bin/rustcode-desktop" %U
Icon=rustcode
Terminal=false
Categories=Development;
MimeType=x-scheme-handler/rustcode;
DESKTOP
command -v update-desktop-database >/dev/null 2>&1 && update-desktop-database "$data/applications" >/dev/null 2>&1 || true
if [ "$INSTALL_CLI" = 1 ]; then
select_cli_directory
link_stage="$(mktemp -d "$INSTALL_DIR/.rustcode-link.XXXXXX")"
ln -s "$target/usr/bin/rustcode" "$link_stage/rustcode"
mv -fT "$link_stage/rustcode" "$TARGET_EXE"
rmdir "$link_stage"
CLI_SHARED=1
success "CLI linked to the app's engine at ${TARGET_EXE}; no separate CLI download needed."
case ":$PATH:" in
*":${INSTALL_DIR}:"*) ;;
*) warn "Add ${INSTALL_DIR} to your PATH to run rustcode from the terminal." ;;
esac
fi
success "RustCode installed to ${target}, using system WebKitGTK and a menu entry."
if [ -f "$HOME/Applications/RustCode.AppImage" ]; then
warn "The old AppImage is still at ~/Applications/RustCode.AppImage. Close it and launch RustCode from the menu to use this installation; remove the old AppImage after verifying it works."
warn "If you installed a background server from the AppImage, reinstall that server from the new app before removing its old engine copy."
fi
}

install_app_linux() {
local machine name file
machine="$TARGET_ARCH"
Expand All @@ -578,6 +660,20 @@ install_app_linux() {
return 0
fi

if [ "$LINUX_APP_FORMAT" != appimage ]; then
if system_webkit_available; then
if name="$(manifest_asset "^RustCode-[0-9][^ ]*-linux-${machine}\\.tar\\.gz\$")"; then
install_app_linux_system "$name"
return 0
elif [ "$LINUX_APP_FORMAT" = system ]; then
error "Release ${LATEST_TAG} has no system-WebKitGTK app for Linux ${machine}."
fi
elif [ "$LINUX_APP_FORMAT" = system ]; then
error "WebKitGTK 4.1 is required. On Arch: sudo pacman -S webkit2gtk-4.1. Then rerun this installer, or use --appimage."
fi
info "Using AppImage; install system WebKitGTK 4.1 and rerun with --system-webkit for smaller downloads."
fi

if ! name="$(manifest_asset "^RustCode-[0-9][^ ]*-linux-${machine}\\.AppImage\$")"; then
warn "Release ${LATEST_TAG} has no desktop AppImage for Linux ${machine}; skipping the app."
return 0
Expand Down Expand Up @@ -621,15 +717,18 @@ DESKTOP
fi
}

if [ "$INSTALL_CLI" = 1 ]; then
# Linux's system-WebKitGTK app provides the CLI too. Install it first so we
# avoid downloading another engine. macOS retains its existing install order.
if [ "$INSTALL_APP" = 1 ] && [ "$TARGET_OS" = linux ]; then
install_app_linux
fi
if [ "$INSTALL_CLI" = 1 ] && [ "$CLI_SHARED" = 0 ]; then
install_cli
fi

if [ "$INSTALL_APP" = 1 ]; then
if [ "$TARGET_OS" = "macos" ]; then
install_app_macos
else
install_app_linux
fi
fi

Expand Down
Loading
Loading