Coexist with a desktop that already manages its tools (Omarchy)
On an Omarchy laptop bootstrap left two of almost everything: VS Code from both pacman and the tarball (two menu entries, one shared ~/.config/Code profile), and kubectl/helm/k9s/kubectx/yq/jq/node/ansible in ~/.local/bin behind mise and pacman copies that always won on PATH. The zsh helpers (op*, grmb, secrets.env) also never reached the bash login shell. - lib/fetch.sh: add `shadowed`, true when another copy of a tool comes earlier on PATH than ~/.local/bin. Always false where zshrc puts ~/.local/bin first, so VM installs are unchanged. - bin/, node/, ansible/: skip tools that are shadowed. - vscode/: defer to any system `code`, and remove a tarball copy this module installed earlier. - bash/: new module; bash port of the zshrc helpers, sourced from ~/.bashrc via a marked block. No-ops without ~/.bashrc. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -29,6 +29,11 @@ Already have a clone? Just run it directly:
|
|||||||
(robbyrussell theme, git plugin), and sets zsh as the login shell. The
|
(robbyrussell theme, git plugin), and sets zsh as the login shell. The
|
||||||
managed rc sources `~/.zshrc.local` last for per-machine customizations
|
managed rc sources `~/.zshrc.local` last for per-machine customizations
|
||||||
(see below).
|
(see below).
|
||||||
|
- `bash/` — for hosts that keep bash as the login shell (Omarchy), copies a
|
||||||
|
bash port of the `zsh/zshrc` helpers (`opr`/`opc`/`opd`/`opl`/`ops`,
|
||||||
|
`grmb`, and `secrets.env` loading) to `~/.config/dotfiles/dotfiles.bash` and
|
||||||
|
adds one marked source line to `~/.bashrc`. Never owns `~/.bashrc`; no-ops
|
||||||
|
when there is none. No sudo.
|
||||||
- `git/` — sets git `user.name`/`user.email` and configures
|
- `git/` — sets git `user.name`/`user.email` and configures
|
||||||
`credential.helper store` (plaintext `~/.git-credentials`, 0600) for
|
`credential.helper store` (plaintext `~/.git-credentials`, 0600) for
|
||||||
HTTPS auth.
|
HTTPS auth.
|
||||||
@@ -48,6 +53,10 @@ Already have a clone? Just run it directly:
|
|||||||
redeploys with no reinstall. Idempotent: each tool records its version
|
redeploys with no reinstall. Idempotent: each tool records its version
|
||||||
under `~/.local/bin/.versions` and is skipped when the pinned version
|
under `~/.local/bin/.versions` and is skipped when the pinned version
|
||||||
is already present. `zsh/zshrc` puts `~/.local/bin` on `PATH`.
|
is already present. `zsh/zshrc` puts `~/.local/bin` on `PATH`.
|
||||||
|
A tool is also skipped when another copy comes *earlier* on `PATH` than
|
||||||
|
`~/.local/bin` (e.g. mise or pacman on Omarchy, where `~/.local/bin` is last),
|
||||||
|
since a copy there would never run. `node/` and `ansible/` follow the same
|
||||||
|
rule. On boxes where zshrc puts `~/.local/bin` first, nothing changes.
|
||||||
- `secrets/` — reads your 1Password vault once and writes every field to
|
- `secrets/` — reads your 1Password vault once and writes every field to
|
||||||
`~/.config/dotfiles/secrets.env` (0600), which the managed `~/.zshrc`
|
`~/.config/dotfiles/secrets.env` (0600), which the managed `~/.zshrc`
|
||||||
sources, so opening a shell never calls `op`. One vault per user and one
|
sources, so opening a shell never calls `op`. One vault per user and one
|
||||||
@@ -86,6 +95,10 @@ Already have a clone? Just run it directly:
|
|||||||
Also sets `password-store: basic` in `~/.vscode/argv.json` so KDE's kwallet
|
Also sets `password-store: basic` in `~/.vscode/argv.json` so KDE's kwallet
|
||||||
does not prompt for an unlock on every launch (see below). **No-ops on
|
does not prompt for an unlock on every launch (see below). **No-ops on
|
||||||
headless hosts** — it's a ~400MB GUI app — override with `DOTFILES_VSCODE`.
|
headless hosts** — it's a ~400MB GUI app — override with `DOTFILES_VSCODE`.
|
||||||
|
**Defers to a system VS Code** (any `code` on `PATH` outside `~/.local/bin`,
|
||||||
|
e.g. Arch's `visual-studio-code-bin`): it skips the install and removes a
|
||||||
|
tarball copy it put there earlier, since two builds would show two menu
|
||||||
|
entries and share one `~/.config/Code` profile.
|
||||||
- `docker-rootless-cgroup/` — on systemd-less hosts (e.g. Kasm), hand-delegates
|
- `docker-rootless-cgroup/` — on systemd-less hosts (e.g. Kasm), hand-delegates
|
||||||
cgroup v2 controllers to the rootless Docker daemon so per-container cgroups
|
cgroup v2 controllers to the rootless Docker daemon so per-container cgroups
|
||||||
work (rootless Docker otherwise comes up with
|
work (rootless Docker otherwise comes up with
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ REPO_ROOT="$(dirname -- "$SCRIPT_DIR")"
|
|||||||
|
|
||||||
# shellcheck source=../lib/os-detect.sh
|
# shellcheck source=../lib/os-detect.sh
|
||||||
. "$REPO_ROOT/lib/os-detect.sh"
|
. "$REPO_ROOT/lib/os-detect.sh"
|
||||||
|
# shellcheck source=../lib/fetch.sh
|
||||||
|
. "$REPO_ROOT/lib/fetch.sh"
|
||||||
|
|
||||||
say() { printf '%s\n' "$*" >&2; }
|
say() { printf '%s\n' "$*" >&2; }
|
||||||
|
|
||||||
@@ -22,6 +24,13 @@ VENV="$HOME/.local/opt/ansible"
|
|||||||
BIN_DIR="$HOME/.local/bin"
|
BIN_DIR="$HOME/.local/bin"
|
||||||
ANSIBLE_CLIS="ansible ansible-playbook ansible-galaxy ansible-vault ansible-config ansible-doc ansible-inventory ansible-console ansible-pull"
|
ANSIBLE_CLIS="ansible ansible-playbook ansible-galaxy ansible-vault ansible-config ansible-doc ansible-inventory ansible-console ansible-pull"
|
||||||
|
|
||||||
|
# Another ansible (mise, pipx, a distro package) already wins on PATH, so this
|
||||||
|
# venv would never run -- see `shadowed` in lib/fetch.sh.
|
||||||
|
if _winner="$(shadowed ansible)"; then
|
||||||
|
say "ansible: $_winner comes first on PATH; skipping (a copy in $BIN_DIR would never run)."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
# Verify it actually runs, not just that the file exists: a Kasm redeploy can
|
# Verify it actually runs, not just that the file exists: a Kasm redeploy can
|
||||||
# wipe the system python3 the venv links to, leaving a present-but-broken
|
# wipe the system python3 the venv links to, leaving a present-but-broken
|
||||||
# venv that must be rebuilt.
|
# venv that must be rebuilt.
|
||||||
|
|||||||
@@ -0,0 +1,110 @@
|
|||||||
|
# Managed by dotfiles/bash/install.sh — copied to ~/.config/dotfiles/dotfiles.bash
|
||||||
|
# and overwritten on the next bootstrap run. Edit bash/dotfiles.bash in the
|
||||||
|
# dotfiles repo instead.
|
||||||
|
#
|
||||||
|
# The bash port of the helpers in zsh/zshrc, for hosts that keep bash as the
|
||||||
|
# login shell (Omarchy ships its own bash config and the zsh module cannot
|
||||||
|
# install zsh there). Only the helpers: PATH, prompt and history stay with the
|
||||||
|
# host's own rc. Keep the two in sync — see zsh/zshrc for the full rationale
|
||||||
|
# behind each function.
|
||||||
|
|
||||||
|
# grmb <branch>... — delete remote branches; takes `origin/foo` or `foo`.
|
||||||
|
grmb() {
|
||||||
|
local remote=origin b rc=0
|
||||||
|
if [ "$#" -eq 0 ]; then
|
||||||
|
echo "grmb: usage: grmb <branch>... (origin/ prefix optional)" >&2
|
||||||
|
return 2
|
||||||
|
fi
|
||||||
|
git fetch --prune --quiet "$remote" || return 1
|
||||||
|
for b in "$@"; do
|
||||||
|
b=${b#"${remote}"/}
|
||||||
|
if git push "$remote" --delete "$b"; then
|
||||||
|
echo "deleted ${remote}/${b}"
|
||||||
|
else
|
||||||
|
echo "grmb: could not delete ${b} (already gone? check: git ls-remote --heads ${remote})" >&2
|
||||||
|
rc=1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
return $rc
|
||||||
|
}
|
||||||
|
|
||||||
|
# Secrets from this user's 1Password vault, written by dotfiles/secrets/install.sh.
|
||||||
|
# Reading a local 0600 file keeps shell startup off the network.
|
||||||
|
_DOTFILES_CONF="$HOME/.config/dotfiles"
|
||||||
|
[ -f "$_DOTFILES_CONF/secrets.env" ] && source "$_DOTFILES_CONF/secrets.env"
|
||||||
|
|
||||||
|
# opr NAME | opc NAME[=VALUE] | opc NAME VALUE | opd NAME | opl [VAULT [ITEM]] | ops
|
||||||
|
# Same behaviour as zsh/zshrc. The service-account token is loaded only inside
|
||||||
|
# the subshells, never into this shell's environment.
|
||||||
|
_dotfiles_op() {
|
||||||
|
[ -f "$_DOTFILES_CONF/op.env" ] || { echo "no $_DOTFILES_CONF/op.env; run: ops" >&2; return 1; }
|
||||||
|
( set -a; source "$_DOTFILES_CONF/op.env"; set +a; "$@" )
|
||||||
|
}
|
||||||
|
_dotfiles_env_name() {
|
||||||
|
[[ $1 =~ ^[A-Za-z_][A-Za-z0-9_]*$ ]] && return 0
|
||||||
|
echo "$2: '$1' is not a valid variable name" >&2; return 2
|
||||||
|
}
|
||||||
|
opr() {
|
||||||
|
_dotfiles_env_name "$1" opr || return
|
||||||
|
_dotfiles_op sh -c 'op read "op://$OP_VAULT/$OP_ITEM/$1"' opr "$1"
|
||||||
|
}
|
||||||
|
opc() {
|
||||||
|
local name=$1 value=
|
||||||
|
if [[ $1 == *=* ]]; then
|
||||||
|
# NAME=VALUE: split on the first '=' so values may contain '='
|
||||||
|
name=${1%%=*} value=${1#*=}
|
||||||
|
elif (( $# >= 2 )); then
|
||||||
|
value=$2
|
||||||
|
fi
|
||||||
|
_dotfiles_env_name "$name" opc || return
|
||||||
|
if [[ -z $value ]]; then
|
||||||
|
read -rsp "$name: " value && echo
|
||||||
|
[[ -n $value ]] || { echo "opc: empty value for $name; nothing changed" >&2; return 1; }
|
||||||
|
fi
|
||||||
|
# op's exit code is unreliable after an edit it did save; read the field back.
|
||||||
|
_dotfiles_op sh -c '
|
||||||
|
clean() { printf "%s" "${1:-(no output)}" | sed "s/^\[ERROR\] [0-9/]* [0-9:]* //"; }
|
||||||
|
ref="op://$OP_VAULT/$OP_ITEM/$1"
|
||||||
|
err=$(op item edit "$OP_ITEM" --vault "$OP_VAULT" "$1[concealed]=$2" 2>&1 >/dev/null)
|
||||||
|
if [ "$(op read "$ref" 2>/dev/null)" = "$2" ]; then
|
||||||
|
printf "opc: saved %s\n" "$ref" >&2
|
||||||
|
else
|
||||||
|
printf "opc: could not save %s\n op said: %s\n check vault, item and service-account write access with: opl\n" \
|
||||||
|
"$ref" "$(clean "$err")" >&2
|
||||||
|
exit 1
|
||||||
|
fi' opc "$name" "$value" && ops
|
||||||
|
}
|
||||||
|
opd() {
|
||||||
|
_dotfiles_env_name "$1" opd || return
|
||||||
|
_dotfiles_op sh -c '
|
||||||
|
clean() { printf "%s" "${1:-(no output)}" | sed "s/^\[ERROR\] [0-9/]* [0-9:]* //"; }
|
||||||
|
ref="op://$OP_VAULT/$OP_ITEM/$1"
|
||||||
|
err=$(op item edit "$OP_ITEM" --vault "$OP_VAULT" "$1[delete]" 2>&1 >/dev/null)
|
||||||
|
if ! item=$(op item get "$OP_ITEM" --vault "$OP_VAULT" --format json 2>&1); then
|
||||||
|
printf "opd: could not re-read %s to confirm the delete\n op said: %s\n" "$ref" "$(clean "$item")" >&2
|
||||||
|
exit 1
|
||||||
|
elif printf "%s" "$item" | jq -r ".fields[].label" | grep -qxF "$1"; then
|
||||||
|
printf "opd: could not delete %s\n op said: %s\n" "$ref" "$(clean "$err")" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
printf "opd: deleted %s\n" "$ref" >&2' opd "$1" \
|
||||||
|
&& unset "$1" && ops
|
||||||
|
}
|
||||||
|
opl() {
|
||||||
|
_dotfiles_op sh -c '
|
||||||
|
vault=${1:-$OP_VAULT} item=${2:-$OP_ITEM}
|
||||||
|
printf "op://%s/%s\n" "$vault" "$item" >&2
|
||||||
|
op item get "$item" --vault "$vault" --reveal --format json' opl "$@" \
|
||||||
|
| jq -r '
|
||||||
|
[.fields[] | select(.purpose != "NOTES")] as $f
|
||||||
|
| ([$f[] | .label // "" | length] | max // 0) as $w
|
||||||
|
| $f[]
|
||||||
|
| ((.label // "") + " " * ($w - ((.label // "") | length))) as $name
|
||||||
|
| ((.value // "") | split("\n")) as $lines
|
||||||
|
| "\($name) \($lines[0] // "")",
|
||||||
|
($lines[1:][] | (" " * ($w + 2)) + .)'
|
||||||
|
}
|
||||||
|
ops() {
|
||||||
|
"${DOTFILES_DIR:-$HOME/.dotfiles}/secrets/install.sh" \
|
||||||
|
&& source "$_DOTFILES_CONF/secrets.env"
|
||||||
|
}
|
||||||
Executable
+47
@@ -0,0 +1,47 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
# bash/install.sh — give bash the dotfiles shell helpers (opr/opc/opd/opl/ops,
|
||||||
|
# grmb, and secrets.env loading).
|
||||||
|
#
|
||||||
|
# WHY: those helpers lived only in the managed ~/.zshrc, so on a host that
|
||||||
|
# keeps bash as its login shell they silently did not exist. Omarchy is that
|
||||||
|
# host: it ships its own ~/.bashrc and default rc, and zsh/ cannot install zsh
|
||||||
|
# there (no dnf/apt). secrets/ still wrote secrets.env, but nothing loaded it,
|
||||||
|
# so every vault-backed variable was simply unset in new shells.
|
||||||
|
#
|
||||||
|
# Unlike zsh/, this never owns ~/.bashrc -- the host's rc stays in charge. It
|
||||||
|
# copies bash/dotfiles.bash to ~/.config/dotfiles/ and adds one marked source
|
||||||
|
# line, the same pattern mcp-config/ uses. Skipped when there is no ~/.bashrc
|
||||||
|
# (a zsh-only box has no use for it). No sudo. Idempotent.
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
|
||||||
|
|
||||||
|
say() { printf '%s\n' "$*" >&2; }
|
||||||
|
|
||||||
|
BASHRC="$HOME/.bashrc"
|
||||||
|
CONF_DIR="$HOME/.config/dotfiles"
|
||||||
|
DEST="$CONF_DIR/dotfiles.bash"
|
||||||
|
MARK_BEGIN="# >>> dotfiles helpers >>>"
|
||||||
|
MARK_END="# <<< dotfiles helpers <<<"
|
||||||
|
|
||||||
|
if [ ! -f "$BASHRC" ]; then
|
||||||
|
say "bash: no $BASHRC; skipping."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "$CONF_DIR"
|
||||||
|
chmod 700 "$CONF_DIR"
|
||||||
|
install -m 0644 "$SCRIPT_DIR/dotfiles.bash" "$DEST"
|
||||||
|
say "bash: wrote $DEST"
|
||||||
|
|
||||||
|
if grep -qxF "$MARK_BEGIN" "$BASHRC"; then
|
||||||
|
say "bash: $BASHRC already sources it."
|
||||||
|
else
|
||||||
|
cat >>"$BASHRC" <<EOF
|
||||||
|
|
||||||
|
$MARK_BEGIN
|
||||||
|
[ -f "\$HOME/.config/dotfiles/dotfiles.bash" ] && . "\$HOME/.config/dotfiles/dotfiles.bash"
|
||||||
|
$MARK_END
|
||||||
|
EOF
|
||||||
|
say "bash: added a source line to $BASHRC (open a new shell to pick it up)."
|
||||||
|
fi
|
||||||
+25
-18
@@ -238,35 +238,42 @@ install_coder() {
|
|||||||
# The subshell re-enables `set -e` inside itself (it is disabled for a command
|
# The subshell re-enables `set -e` inside itself (it is disabled for a command
|
||||||
# being tested by `if`), so a failed download still aborts that tool's function
|
# being tested by `if`), so a failed download still aborts that tool's function
|
||||||
# before mark_version stamps a version that was never installed.
|
# before mark_version stamps a version that was never installed.
|
||||||
|
#
|
||||||
|
# try <install_fn> <binary> also skips the tool when another <binary> already
|
||||||
|
# wins on PATH (see `shadowed` in lib/fetch.sh): a copy here would never run.
|
||||||
FAILED=""
|
FAILED=""
|
||||||
try() {
|
try() {
|
||||||
|
if _winner="$(shadowed "$2")"; then
|
||||||
|
fsay "$2: $_winner comes first on PATH; skipping (a copy in $BIN_DIR would never run)."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
if ( set -e; "$1" ); then return 0; fi
|
if ( set -e; "$1" ); then return 0; fi
|
||||||
FAILED="$FAILED ${1#install_}"
|
FAILED="$FAILED ${1#install_}"
|
||||||
fsay "WARNING: ${1#install_} failed to install; continuing."
|
fsay "WARNING: ${1#install_} failed to install; continuing."
|
||||||
}
|
}
|
||||||
|
|
||||||
try install_jq
|
try install_jq jq
|
||||||
try install_kubectl
|
try install_kubectl kubectl
|
||||||
try install_oidc_login
|
try install_oidc_login kubectl-oidc_login
|
||||||
try install_helm
|
try install_helm helm
|
||||||
try install_k9s
|
try install_k9s k9s
|
||||||
if docker_full_available; then
|
if docker_full_available; then
|
||||||
try install_kind
|
try install_kind kind
|
||||||
else
|
else
|
||||||
fsay "Skipping kind: full (non-rootless) Docker not available."
|
fsay "Skipping kind: full (non-rootless) Docker not available."
|
||||||
fi
|
fi
|
||||||
try install_kubectx
|
try install_kubectx kubectx
|
||||||
try install_kubens
|
try install_kubens kubens
|
||||||
try install_stern
|
try install_stern stern
|
||||||
try install_yq
|
try install_yq yq
|
||||||
try install_tofu
|
try install_tofu tofu
|
||||||
try install_task
|
try install_task task
|
||||||
try install_terragrunt
|
try install_terragrunt terragrunt
|
||||||
try install_1p
|
try install_1p op
|
||||||
try install_opencode
|
try install_opencode opencode
|
||||||
try install_zarf
|
try install_zarf zarf
|
||||||
try install_packer
|
try install_packer packer
|
||||||
try install_coder
|
try install_coder coder
|
||||||
|
|
||||||
if [ -n "$FAILED" ]; then
|
if [ -n "$FAILED" ]; then
|
||||||
fsay ""
|
fsay ""
|
||||||
|
|||||||
@@ -78,6 +78,8 @@ run_module() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
run_module zsh
|
run_module zsh
|
||||||
|
# bash/ is zsh/'s helpers for hosts that keep bash (Omarchy); no-ops without ~/.bashrc.
|
||||||
|
run_module bash
|
||||||
run_module git
|
run_module git
|
||||||
run_module bin
|
run_module bin
|
||||||
# Needs op and jq from bin/. Runs before everything that consumes a secret, and
|
# Needs op and jq from bin/. Runs before everything that consumes a secret, and
|
||||||
|
|||||||
@@ -55,6 +55,38 @@ have_version() {
|
|||||||
[ "$(cat "$VERSION_DIR/$1")" = "$2" ]
|
[ "$(cat "$VERSION_DIR/$1")" = "$2" ]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# shadowed <name> — true (printing the winner's path) when another <name> sits
|
||||||
|
# EARLIER on PATH than $BIN_DIR, so a copy installed there would never run.
|
||||||
|
#
|
||||||
|
# WHY: on a desktop that already manages these tools (Omarchy: pacman for VS
|
||||||
|
# Code and jq, mise for kubectl/helm/node/...), ~/.local/bin is at the END of
|
||||||
|
# PATH. Installing there anyway left a second, older copy of every tool that
|
||||||
|
# nothing ran but `type -a` and the version stamps still reported. On the VMs
|
||||||
|
# this repo targets, zshrc puts ~/.local/bin FIRST, so nothing shadows it and
|
||||||
|
# this is always false -- installs there behave exactly as before. If $BIN_DIR
|
||||||
|
# is not on PATH at all (a fresh box, before zshrc), it is false too.
|
||||||
|
#
|
||||||
|
# A mise shim with no version configured is not a real provider (it errors when
|
||||||
|
# run), so shims only count when `mise which` resolves them.
|
||||||
|
shadowed() {
|
||||||
|
_sh_name="$1"
|
||||||
|
_sh_ifs="$IFS"; IFS=:
|
||||||
|
# shellcheck disable=SC2086 # split PATH on ':' deliberately
|
||||||
|
set -- $PATH
|
||||||
|
IFS="$_sh_ifs"
|
||||||
|
case ":$PATH:" in *":$BIN_DIR:"*) ;; *) return 1 ;; esac
|
||||||
|
for _sh_dir; do
|
||||||
|
[ "$_sh_dir" = "$BIN_DIR" ] && return 1
|
||||||
|
[ -n "$_sh_dir" ] && [ -x "$_sh_dir/$_sh_name" ] && [ ! -d "$_sh_dir/$_sh_name" ] || continue
|
||||||
|
case "$_sh_dir" in
|
||||||
|
*/mise/shims) mise which "$_sh_name" >/dev/null 2>&1 || continue ;;
|
||||||
|
esac
|
||||||
|
printf '%s\n' "$_sh_dir/$_sh_name"
|
||||||
|
return 0
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
# mark_version <name> <version> — record the installed version.
|
# mark_version <name> <version> — record the installed version.
|
||||||
mark_version() {
|
mark_version() {
|
||||||
mkdir -p "$VERSION_DIR"
|
mkdir -p "$VERSION_DIR"
|
||||||
|
|||||||
@@ -29,6 +29,13 @@ PREFIX="$HOME/.local/opt/node"
|
|||||||
BIN_DIR="$HOME/.local/bin"
|
BIN_DIR="$HOME/.local/bin"
|
||||||
NODE_CLIS="node npm npx"
|
NODE_CLIS="node npm npx"
|
||||||
|
|
||||||
|
# Another node (mise, nvm, a distro package) already wins on PATH, so ours
|
||||||
|
# would never run -- see `shadowed` in lib/fetch.sh. npx comes with it.
|
||||||
|
if _winner="$(shadowed node)"; then
|
||||||
|
say "node: $_winner comes first on PATH; skipping (a copy in $BIN_DIR would never run)."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
case "$(fetch_arch)" in
|
case "$(fetch_arch)" in
|
||||||
x86_64) NODE_ARCH=x64 ;;
|
x86_64) NODE_ARCH=x64 ;;
|
||||||
aarch64) NODE_ARCH=arm64 ;;
|
aarch64) NODE_ARCH=arm64 ;;
|
||||||
|
|||||||
+31
-11
@@ -69,6 +69,37 @@ case "${DOTFILES_VSCODE:-auto}" in
|
|||||||
fi ;;
|
fi ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
# --- defer to a system-wide VS Code -------------------------------------------
|
||||||
|
# WHY: a distro package (Arch's visual-studio-code-bin on Omarchy, Microsoft's
|
||||||
|
# rpm/deb elsewhere) and this tarball both add a "Visual Studio Code" menu entry
|
||||||
|
# and both open the same ~/.config/Code profile. Two builds on one profile is
|
||||||
|
# the real hazard: the older one opens state the newer one already migrated,
|
||||||
|
# and extensions break in ways that look like extension bugs. The system copy
|
||||||
|
# also gets updates this pinned one does not, so it wins.
|
||||||
|
#
|
||||||
|
# PATH order is irrelevant here (unlike `shadowed` in bin/): the menu entries
|
||||||
|
# collide wherever the binaries sit. Anything we installed earlier is removed --
|
||||||
|
# only ours, recognised by the .desktop Exec pointing into $PREFIX.
|
||||||
|
_sys_code=""
|
||||||
|
_sh_ifs="$IFS"; IFS=:
|
||||||
|
for _d in $PATH; do
|
||||||
|
[ "$_d" != "$BIN_DIR" ] && [ -x "$_d/code" ] && { _sys_code="$_d/code"; break; }
|
||||||
|
done
|
||||||
|
IFS="$_sh_ifs"
|
||||||
|
if [ -n "$_sys_code" ]; then
|
||||||
|
say "vscode: system VS Code at $_sys_code; skipping the tarball install."
|
||||||
|
if grep -qs "^Exec=$PREFIX/" "$DESKTOP_DIR/code.desktop"; then
|
||||||
|
rm -f "$DESKTOP_DIR/code.desktop"
|
||||||
|
[ "$(readlink "$BIN_DIR/code" 2>/dev/null)" = "$PREFIX/bin/code" ] && rm -f "$BIN_DIR/code"
|
||||||
|
rm -f "$VERSION_DIR/code"
|
||||||
|
rm -rf "$PREFIX"
|
||||||
|
command -v update-desktop-database >/dev/null 2>&1 &&
|
||||||
|
update-desktop-database "$DESKTOP_DIR" 2>/dev/null || true
|
||||||
|
say "vscode: removed the earlier tarball copy ($PREFIX, its menu entry and $BIN_DIR/code)."
|
||||||
|
fi
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
# Upstream keys its download URLs on x64/arm64 rather than amd64/arm64.
|
# Upstream keys its download URLs on x64/arm64 rather than amd64/arm64.
|
||||||
case "$(fetch_arch)" in
|
case "$(fetch_arch)" in
|
||||||
x86_64) VSCODE_ARCH=x64 ;;
|
x86_64) VSCODE_ARCH=x64 ;;
|
||||||
@@ -202,15 +233,4 @@ else
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# A system-wide VS Code (from Microsoft's rpm/deb repo) shadows this one in the
|
|
||||||
# menu and shows a duplicate entry. Flag it rather than touching it -- removing
|
|
||||||
# it needs the root this module deliberately avoids.
|
|
||||||
if [ -e /usr/share/applications/com.microsoft.VSCode.desktop ]; then
|
|
||||||
say ""
|
|
||||||
say "vscode: NOTE: a system-wide VS Code package is also installed."
|
|
||||||
say " You will see two menu entries until it is removed:"
|
|
||||||
say " sudo dnf remove code # or: sudo apt remove code"
|
|
||||||
say ""
|
|
||||||
fi
|
|
||||||
|
|
||||||
say "vscode: ready."
|
say "vscode: ready."
|
||||||
|
|||||||
@@ -21,6 +21,9 @@ SAVEHIST=10000
|
|||||||
setopt SHARE_HISTORY
|
setopt SHARE_HISTORY
|
||||||
setopt HIST_IGNORE_DUPS
|
setopt HIST_IGNORE_DUPS
|
||||||
|
|
||||||
|
# grmb and the op* helpers below have a bash port in bash/dotfiles.bash for
|
||||||
|
# hosts that keep bash; change both together.
|
||||||
|
|
||||||
# Delete remote branches without fighting tab-completion.
|
# Delete remote branches without fighting tab-completion.
|
||||||
#
|
#
|
||||||
# `git push origin --delete <TAB>` completes to `origin/foo`, but `origin/foo`
|
# `git push origin --delete <TAB>` completes to `origin/foo`, but `origin/foo`
|
||||||
|
|||||||
Reference in New Issue
Block a user