Update Installer
Rolling release / release (push) Successful in 8m42s

This commit is contained in:
2026-09-11 21:34:34 -04:00
parent bd34ec49aa
commit 324f0d5e3a
4 changed files with 111 additions and 17 deletions
+2 -1
View File
@@ -238,7 +238,8 @@ bash packaging/uninstall.sh --yes --purge-data
Re-running the installer upgrades in place: it stops the old daemon, removes Re-running the installer upgrades in place: it stops the old daemon, removes
the previous application and extension files, then copies the new tree. the previous application and extension files, then copies the new tree.
Config, memory, and model cache are kept. Read Config, memory, and model cache are kept. Those steps are written to
`~/.local/state/jarvis/install.log`. Read
[Migration notes](docs/MIGRATIONS.md) before upgrading or moving an [Migration notes](docs/MIGRATIONS.md) before upgrading or moving an
installation. installation.
+3 -1
View File
@@ -12,7 +12,9 @@ leftover files from older versions cannot mix with the new tree. Failed staging
directories next to the install prefix are removed first. Existing config and directories next to the install prefix are removed first. Existing config and
data under `~/.config/jarvis`, `~/.local/share/jarvis`, and the model cache are data under `~/.config/jarvis`, `~/.local/share/jarvis`, and the model cache are
preserved. If the service was running, the installer restarts it after the preserved. If the service was running, the installer restarts it after the
replacement; `--enable` also enables the unit. Run replacement; `--enable` also enables the unit. Each of those steps is appended
to `~/.local/state/jarvis/install.log` (or `$XDG_STATE_HOME/jarvis/install.log`)
and to the system log as tag `jarvis-install`. Run
`systemctl --user daemon-reload` only when you install the service file by `systemctl --user daemon-reload` only when you install the service file by
hand. hand.
+92 -14
View File
@@ -7,11 +7,28 @@ EXT_DIR="${XDG_DATA_HOME:-${HOME}/.local/share}/gnome-shell/extensions/jarvis@qv
CONFIG_DIR="${HOME}/.config/jarvis" CONFIG_DIR="${HOME}/.config/jarvis"
CACHE_DIR="${XDG_CACHE_HOME:-${HOME}/.cache}/jarvis/models" CACHE_DIR="${XDG_CACHE_HOME:-${HOME}/.cache}/jarvis/models"
APP_PARENT="$(dirname "${APP_DIR}")" APP_PARENT="$(dirname "${APP_DIR}")"
mkdir -p "${APP_PARENT}" "${CONFIG_DIR}" "${HOME}/.config/systemd/user" "${CACHE_DIR}" LOG_DIR="${XDG_STATE_HOME:-${HOME}/.local/state}/jarvis"
LOG_FILE="${LOG_DIR}/install.log"
mkdir -p "${APP_PARENT}" "${CONFIG_DIR}" "${HOME}/.config/systemd/user" "${CACHE_DIR}" "${LOG_DIR}"
log() {
local line
line="$(date -Iseconds 2>/dev/null || date '+%Y-%m-%dT%H:%M:%S%z') jarvis-install: $*"
printf '%s\n' "${line}" | tee -a "${LOG_FILE}"
if command -v logger >/dev/null; then
logger --tag jarvis-install -- "$*" 2>/dev/null || logger -t jarvis-install -- "$*" 2>/dev/null || true
fi
}
STAGING="" STAGING=""
EXT_TMP_DIR="" EXT_TMP_DIR=""
cleanup_install() { rm -rf "${STAGING}" "${EXT_TMP_DIR}"; } cleanup_install() {
if [[ -n "${STAGING}" && -e "${STAGING}" ]]; then
log "removing unfinished staging directory ${STAGING}"
rm -rf "${STAGING}"
fi
rm -rf "${EXT_TMP_DIR}"
}
trap cleanup_install EXIT trap cleanup_install EXIT
has_bundled_bare() { has_bundled_bare() {
@@ -22,41 +39,82 @@ extract_tree() {
local dest="$1" local dest="$1"
mkdir -p "${dest}" mkdir -p "${dest}"
if has_bundled_bare; then if has_bundled_bare; then
log "staging bundled Bare tree from ${ROOT_DIR} into ${dest}"
tar --exclude='.git' --exclude='./.agents' --exclude='./.codex' --exclude='./dist' --exclude='./vendor/agent-harness/node_modules' --exclude='*/__pycache__' --exclude='*.pyc' -cf - -C "${ROOT_DIR}" . | tar -xf - -C "${dest}" tar --exclude='.git' --exclude='./.agents' --exclude='./.codex' --exclude='./dist' --exclude='./vendor/agent-harness/node_modules' --exclude='*/__pycache__' --exclude='*.pyc' -cf - -C "${ROOT_DIR}" . | tar -xf - -C "${dest}"
else else
log "staging source tree from ${ROOT_DIR} into ${dest} (excluding node_modules)"
tar --exclude='.git' --exclude='./.agents' --exclude='./.codex' --exclude='./dist' --exclude='./node_modules' --exclude='*/node_modules' --exclude='*/__pycache__' --exclude='*.pyc' -cf - -C "${ROOT_DIR}" . | tar -xf - -C "${dest}" tar --exclude='.git' --exclude='./.agents' --exclude='./.codex' --exclude='./dist' --exclude='./node_modules' --exclude='*/node_modules' --exclude='*/__pycache__' --exclude='*.pyc' -cf - -C "${ROOT_DIR}" . | tar -xf - -C "${dest}"
fi fi
} }
log "starting install from ${ROOT_DIR}"
log "application directory ${APP_DIR}; extension ${EXT_DIR}"
log "preserving config ${CONFIG_DIR}, cache ${CACHE_DIR}, and user data under ${HOME}/.local/share/jarvis"
PREVIOUSLY_ACTIVE=false PREVIOUSLY_ACTIVE=false
if command -v systemctl >/dev/null; then if command -v systemctl >/dev/null; then
if systemctl --user is-active --quiet jarvisd.service 2>/dev/null; then if systemctl --user is-active --quiet jarvisd.service 2>/dev/null; then
PREVIOUSLY_ACTIVE=true PREVIOUSLY_ACTIVE=true
systemctl --user stop jarvisd.service || true log "stopping running jarvisd.service before replacing files"
if systemctl --user stop jarvisd.service; then
log "stopped jarvisd.service"
else
log "warning: could not stop jarvisd.service; continuing with replacement"
fi
else
log "jarvisd.service was not running"
fi fi
else
log "systemctl not found; skipped service stop"
fi fi
if [[ -e "${APP_DIR}" || -e "${EXT_DIR}" ]]; then if [[ -e "${APP_DIR}" ]]; then
echo "Cleaning the previous JARVIS-QVAC install so this upgrade is a clean replacement." log "previous application tree found at ${APP_DIR}"
else
log "no previous application tree at ${APP_DIR}"
fi
if [[ -e "${EXT_DIR}" ]]; then
log "previous GNOME extension found at ${EXT_DIR}"
else
log "no previous GNOME extension at ${EXT_DIR}"
fi fi
if command -v gnome-extensions >/dev/null; then if command -v gnome-extensions >/dev/null; then
gnome-extensions disable [email protected] >/dev/null 2>&1 || true if gnome-extensions disable [email protected] >/dev/null 2>&1; then
gnome-extensions uninstall [email protected] >/dev/null 2>&1 || true log "disabled GNOME extension [email protected]"
else
log "GNOME extension [email protected] was not enabled or could not be disabled"
fi
if gnome-extensions uninstall [email protected] >/dev/null 2>&1; then
log "uninstalled GNOME extension [email protected]"
else
log "GNOME extension [email protected] was not registered or could not be uninstalled"
fi
else
log "gnome-extensions not found; removing extension files directly"
fi
if [[ -e "${EXT_DIR}" ]]; then
log "removing leftover extension files at ${EXT_DIR}"
rm -rf "${EXT_DIR}"
fi fi
rm -rf "${EXT_DIR}"
shopt -s nullglob shopt -s nullglob
for leftover in "${APP_PARENT}"/jarvis-qvac.staging.*; do for leftover in "${APP_PARENT}"/jarvis-qvac.staging.*; do
log "removing leftover staging directory ${leftover}"
rm -rf "${leftover}" rm -rf "${leftover}"
done done
shopt -u nullglob shopt -u nullglob
STAGING="$(mktemp -d "${APP_PARENT}/jarvis-qvac.staging.XXXXXX")" STAGING="$(mktemp -d "${APP_PARENT}/jarvis-qvac.staging.XXXXXX")"
extract_tree "${STAGING}" extract_tree "${STAGING}"
rm -rf "${APP_DIR}" if [[ -e "${APP_DIR}" ]]; then
log "removing previous application tree ${APP_DIR}"
rm -rf "${APP_DIR}"
fi
log "moving staged tree ${STAGING} into ${APP_DIR}"
mv "${STAGING}" "${APP_DIR}" mv "${STAGING}" "${APP_DIR}"
STAGING="" STAGING=""
log "application tree replaced at ${APP_DIR}"
case "$(uname -m)" in case "$(uname -m)" in
x86_64|amd64) BARE_BIN="${APP_DIR}/node_modules/bare-runtime-linux-x64/bin/bare" ;; x86_64|amd64) BARE_BIN="${APP_DIR}/node_modules/bare-runtime-linux-x64/bin/bare" ;;
@@ -65,40 +123,58 @@ case "$(uname -m)" in
esac esac
if [[ ! -x "${BARE_BIN}" ]]; then BARE_BIN="$(command -v bare || true)"; fi if [[ ! -x "${BARE_BIN}" ]]; then BARE_BIN="$(command -v bare || true)"; fi
if [[ -z "${BARE_BIN}" || ! -x "${BARE_BIN}" ]]; then if [[ -z "${BARE_BIN}" || ! -x "${BARE_BIN}" ]]; then
log "error: no Bare runtime for $(uname -m) in the installed bundle"
echo "The installed bundle does not contain a Bare runtime for $(uname -m). Install the official rolling bundle or build it with npm run package:bare." >&2 echo "The installed bundle does not contain a Bare runtime for $(uname -m). Install the official rolling bundle or build it with npm run package:bare." >&2
exit 1 exit 1
fi fi
chmod 755 "${BARE_BIN}" chmod 755 "${BARE_BIN}"
log "using Bare runtime ${BARE_BIN}"
EXT_TMP_DIR="$(mktemp -d "${TMPDIR:-/tmp}/jarvis-extension.XXXXXX")" EXT_TMP_DIR="$(mktemp -d "${TMPDIR:-/tmp}/jarvis-extension.XXXXXX")"
EXT_ZIP="${EXT_TMP_DIR}/jarvis-extension.zip" EXT_ZIP="${EXT_TMP_DIR}/jarvis-extension.zip"
mkdir -p "${EXT_DIR}" mkdir -p "${EXT_DIR}"
( cd "${ROOT_DIR}/apps/gnome-extension/[email protected]" && zip -q -r "${EXT_ZIP}" . ) ( cd "${ROOT_DIR}/apps/gnome-extension/[email protected]" && zip -q -r "${EXT_ZIP}" . )
if command -v gnome-extensions >/dev/null; then if command -v gnome-extensions >/dev/null; then
if ! gnome-extensions install --force "${EXT_ZIP}"; then if gnome-extensions install --force "${EXT_ZIP}"; then
log "registered GNOME extension from ${EXT_ZIP}"
else
log "warning: GNOME extension registration failed; copying files to ${EXT_DIR}"
echo "GNOME extension registration failed; installing the files directly." >&2 echo "GNOME extension registration failed; installing the files directly." >&2
cp -a "${ROOT_DIR}/apps/gnome-extension/[email protected]/." "${EXT_DIR}/" cp -a "${ROOT_DIR}/apps/gnome-extension/[email protected]/." "${EXT_DIR}/"
log "copied GNOME extension files to ${EXT_DIR}"
fi fi
else else
cp -a "${ROOT_DIR}/apps/gnome-extension/[email protected]/." "${EXT_DIR}/" cp -a "${ROOT_DIR}/apps/gnome-extension/[email protected]/." "${EXT_DIR}/"
log "copied GNOME extension files to ${EXT_DIR}"
fi fi
if command -v glib-compile-schemas >/dev/null && [[ -d "${EXT_DIR}/schemas" ]]; then if command -v glib-compile-schemas >/dev/null && [[ -d "${EXT_DIR}/schemas" ]]; then
glib-compile-schemas "${EXT_DIR}/schemas" >/dev/null glib-compile-schemas "${EXT_DIR}/schemas" >/dev/null
log "compiled GSettings schemas in ${EXT_DIR}/schemas"
fi fi
sed "s#__JARVIS_BARE__#${BARE_BIN}#" "${ROOT_DIR}/packaging/jarvisd.service" > "${HOME}/.config/systemd/user/jarvisd.service" sed "s#__JARVIS_BARE__#${BARE_BIN}#" "${ROOT_DIR}/packaging/jarvisd.service" > "${HOME}/.config/systemd/user/jarvisd.service"
log "wrote ${HOME}/.config/systemd/user/jarvisd.service"
if [[ -f "${CONFIG_DIR}/config.json" ]]; then
log "kept existing ${CONFIG_DIR}/config.json"
fi
if [[ ! -f "${CONFIG_DIR}/qvac.config.json" ]]; then if [[ ! -f "${CONFIG_DIR}/qvac.config.json" ]]; then
sed "s#__JARVIS_CACHE__#${CACHE_DIR}#g" "${ROOT_DIR}/packaging/qvac.config.template.json" > "${CONFIG_DIR}/qvac.config.json" sed "s#__JARVIS_CACHE__#${CACHE_DIR}#g" "${ROOT_DIR}/packaging/qvac.config.template.json" > "${CONFIG_DIR}/qvac.config.json"
log "created ${CONFIG_DIR}/qvac.config.json"
else
log "kept existing ${CONFIG_DIR}/qvac.config.json"
fi fi
restart_user_service() { restart_user_service() {
systemctl --user daemon-reload systemctl --user daemon-reload
log "reloaded user systemd units"
if [[ "${1:-}" == "enable" ]]; then if [[ "${1:-}" == "enable" ]]; then
systemctl --user enable jarvisd.service systemctl --user enable jarvisd.service
log "enabled jarvisd.service"
fi fi
systemctl --user restart jarvisd.service systemctl --user restart jarvisd.service
log "restarted jarvisd.service"
} }
if [[ "${1:-}" == "--enable" ]]; then if [[ "${1:-}" == "--enable" ]]; then
restart_user_service enable restart_user_service enable
if command -v gnome-extensions >/dev/null && gnome-extensions enable [email protected] >/dev/null 2>&1; then if command -v gnome-extensions >/dev/null && gnome-extensions enable [email protected] >/dev/null 2>&1; then
echo "GNOME extension enabled." log "enabled GNOME extension [email protected]"
elif command -v gsettings >/dev/null && gsettings writable org.gnome.shell enabled-extensions >/dev/null 2>&1; then elif command -v gsettings >/dev/null && gsettings writable org.gnome.shell enabled-extensions >/dev/null 2>&1; then
# A running GNOME Shell keeps its extension catalogue until the next # A running GNOME Shell keeps its extension catalogue until the next
# session. Persist the enabled state so the extension starts on login. # session. Persist the enabled state so the extension starts on login.
@@ -110,14 +186,16 @@ if [[ "${1:-}" == "--enable" ]]; then
ENABLED_EXTENSIONS="${ENABLED_EXTENSIONS%]}, '[email protected]']" ENABLED_EXTENSIONS="${ENABLED_EXTENSIONS%]}, '[email protected]']"
fi fi
gsettings set org.gnome.shell enabled-extensions "${ENABLED_EXTENSIONS}" gsettings set org.gnome.shell enabled-extensions "${ENABLED_EXTENSIONS}"
log "persisted [email protected] in org.gnome.shell enabled-extensions"
fi fi
echo "GNOME Shell will enable Jarvis after the next login (the current Shell session has not rescanned extensions)." log "GNOME Shell will enable Jarvis after the next login (the current Shell session has not rescanned extensions)"
else else
echo "GNOME Shell has not rescanned extensions; log out and back in, then run: gnome-extensions enable [email protected]" log "GNOME Shell has not rescanned extensions; log out and back in, then run: gnome-extensions enable [email protected]"
fi fi
elif [[ "${PREVIOUSLY_ACTIVE}" == true ]]; then elif [[ "${PREVIOUSLY_ACTIVE}" == true ]]; then
restart_user_service restart_user_service
echo "Restarted jarvisd.service with the upgraded files." log "restarted jarvisd.service with the upgraded files"
fi fi
log "install complete; log file ${LOG_FILE}"
echo "Installed JARVIS-QVAC to ${APP_DIR}" echo "Installed JARVIS-QVAC to ${APP_DIR}"
echo "Run: ${APP_DIR}/packaging/first-run.sh" echo "Run: ${APP_DIR}/packaging/first-run.sh"
+14 -1
View File
@@ -66,16 +66,22 @@ exit 0
echo "gnome-extensions $*" >> '${log}' echo "gnome-extensions $*" >> '${log}'
if [ "$1" = install ]; then exit 1; fi if [ "$1" = install ]; then exit 1; fi
exit 0 exit 0
`);
await writeFile(path.join(bin, 'logger'), `#!/bin/sh
echo "logger $*" >> '${log}'
exit 0
`); `);
await chmod(path.join(bin, 'systemctl'), 0o755); await chmod(path.join(bin, 'systemctl'), 0o755);
await chmod(path.join(bin, 'gnome-extensions'), 0o755); await chmod(path.join(bin, 'gnome-extensions'), 0o755);
await chmod(path.join(bin, 'logger'), 0o755);
await run('bash', [path.join(root, 'packaging/install.sh'), '--enable'], { const result = await run('bash', [path.join(root, 'packaging/install.sh'), '--enable'], {
...process.env, ...process.env,
HOME: home, HOME: home,
PATH: `${bin}:${process.env.PATH}`, PATH: `${bin}:${process.env.PATH}`,
XDG_DATA_HOME: path.join(home, '.local/share'), XDG_DATA_HOME: path.join(home, '.local/share'),
XDG_CACHE_HOME: path.join(home, '.cache'), XDG_CACHE_HOME: path.join(home, '.cache'),
XDG_STATE_HOME: path.join(home, '.local/state'),
}); });
assert.equal(existsSync(path.join(appDir, 'stale-old-version.js')), false); assert.equal(existsSync(path.join(appDir, 'stale-old-version.js')), false);
@@ -92,6 +98,13 @@ exit 0
assert.match(commands, /systemctl --user stop jarvisd\.service/); assert.match(commands, /systemctl --user stop jarvisd\.service/);
assert.match(commands, /gnome-extensions uninstall jarvis@qvac\.local/); assert.match(commands, /gnome-extensions uninstall jarvis@qvac\.local/);
assert.match(commands, /systemctl --user restart jarvisd\.service/); assert.match(commands, /systemctl --user restart jarvisd\.service/);
const installLog = await readFile(path.join(home, '.local/state/jarvis/install.log'), 'utf8');
assert.match(installLog, /stopping running jarvisd\.service/);
assert.match(installLog, /removing leftover staging directory/);
assert.match(installLog, /removing previous application tree/);
assert.match(installLog, /kept existing .*config\.json/);
assert.match(installLog, /install complete; log file/);
assert.match(result.stdout, /jarvis-install: stopping running jarvisd\.service/);
} finally { } finally {
await rm(work, { recursive: true, force: true }); await rm(work, { recursive: true, force: true });
} }