visidata: make installer idempotent and use v3.3 VD_DIR

This commit is contained in:
tobias
2026-02-14 11:23:09 +01:00
parent 273b47f08e
commit 1c9cdc5c19

View File

@@ -3,20 +3,22 @@ set -euo pipefail
mode="link" # link|copy mode="link" # link|copy
do_deps=0 do_deps=0
verbose=0
usage() { usage() {
cat <<'USAGE' cat <<'USAGE'
Usage: ./install.sh [--link|--copy] [--deps] Usage: ./install.sh [--link|--copy] [--deps] [-v|--verbose]
Installs this repo's VisiData config and plugins into standard per-user locations: Installs this repo's VisiData config and plugins into standard per-user locations:
- config.py in the user config dir (VisiData 3.3+ default) - config.py in the user config dir (VisiData 3.3+ default)
- ~/.visidatarc (legacy fallback) - ~/.visidatarc (legacy fallback)
- plugins into $VD_DIR/plugins (default ~/.visidata/plugins) - plugins into $VD_DIR/plugins (VisiData 3.3 default on macOS is ~/Library/Preferences/visidata/plugins)
Options: Options:
--link Symlink files into place (default) --link Symlink files into place (default)
--copy Copy files into place --copy Copy files into place
--deps Install requirements.txt into $VD_DIR/plugins-deps using pip --target --deps Install requirements.txt into $VD_DIR/plugins-deps using pip --target
-v,--verbose Print actions taken
-h,--help Show this help -h,--help Show this help
USAGE USAGE
} }
@@ -26,6 +28,7 @@ while [[ $# -gt 0 ]]; do
--link) mode="link"; shift ;; --link) mode="link"; shift ;;
--copy) mode="copy"; shift ;; --copy) mode="copy"; shift ;;
--deps) do_deps=1; shift ;; --deps) do_deps=1; shift ;;
-v|--verbose) verbose=1; shift ;;
-h|--help) usage; exit 0 ;; -h|--help) usage; exit 0 ;;
*) echo "Unknown arg: $1" >&2; usage; exit 2 ;; *) echo "Unknown arg: $1" >&2; usage; exit 2 ;;
esac esac
@@ -45,24 +48,30 @@ timestamp() { date +"%Y%m%d-%H%M%S"; }
backup_if_needed() { backup_if_needed() {
local dst="$1" local dst="$1"
local src="$2"
if [[ -L "$dst" ]]; then if [[ -L "$dst" ]]; then
# If it's already a symlink to our source (absolute), keep it. # If it's already a symlink to our source (absolute), no-op.
local cur local cur
cur="$(readlink "$dst" || true)" cur="$(readlink "$dst" || true)"
if [[ "$cur" == "$2" ]]; then if [[ "$cur" == "$src" ]]; then
return 0 return 1
fi fi
fi fi
if [[ -e "$dst" || -L "$dst" ]]; then if [[ -e "$dst" || -L "$dst" ]]; then
mv "$dst" "${dst}.bak.$(timestamp)" mv "$dst" "${dst}.bak.$(timestamp)"
fi fi
return 0
} }
install_one() { install_one() {
local src="$1" local src="$1"
local dst="$2" local dst="$2"
mkdir -p "$(dirname "$dst")" mkdir -p "$(dirname "$dst")"
backup_if_needed "$dst" "$src" if ! backup_if_needed "$dst" "$src"; then
[[ "$verbose" -eq 1 ]] && echo "skip (already installed): $dst"
return 0
fi
[[ "$verbose" -eq 1 ]] && echo "install: $src -> $dst ($mode)"
if [[ "$mode" == "copy" ]]; then if [[ "$mode" == "copy" ]]; then
cp -f "$src" "$dst" cp -f "$src" "$dst"
else else
@@ -70,16 +79,30 @@ install_one() {
fi fi
} }
os="$(uname -s)"
if [[ "$os" == "Darwin" ]]; then
config_dir="${HOME}/Library/Preferences/visidata"
else
config_dir="${XDG_CONFIG_HOME:-${HOME}/.config}/visidata"
fi
dst_config_py="${config_dir}/config.py"
dst_visidatarc="${HOME}/.visidatarc" dst_visidatarc="${HOME}/.visidatarc"
vd_dir="${VD_DIR:-${HOME}/.visidata}" # Prefer the python used by the `vd` entrypoint (if available).
pip_py=""
if command -v vd >/dev/null 2>&1; then
vd_bin="$(command -v vd)"
pip_py="$(sed -n '1{s/^#!//p;}' "$vd_bin" || true)"
fi
if [[ -z "$pip_py" ]]; then
pip_py="$(command -v python3 || true)"
fi
if [[ -z "$pip_py" ]]; then
echo "No python found to run pip." >&2
exit 1
fi
# Use VisiData's own idea of the user config/VD dir (VisiData 3.3 on macOS
# defaults this to ~/Library/Preferences/visidata). Allow override via $VD_DIR.
vd_dir="${VD_DIR:-$("$pip_py" -c 'from visidata import vd; print(vd.options.visidata_dir)' 2>/dev/null || true)}"
if [[ -z "$vd_dir" ]]; then
vd_dir="${HOME}/.visidata"
fi
dst_config_py="${vd_dir}/config.py"
dst_plugins_dir="${vd_dir}/plugins" dst_plugins_dir="${vd_dir}/plugins"
dst_deps_dir="${vd_dir}/plugins-deps" dst_deps_dir="${vd_dir}/plugins-deps"
@@ -103,20 +126,6 @@ if [[ "$do_deps" -eq 1 ]]; then
fi fi
mkdir -p "$dst_deps_dir" mkdir -p "$dst_deps_dir"
# Prefer the python used by the `vd` entrypoint (if available).
pip_py=""
if command -v vd >/dev/null 2>&1; then
vd_bin="$(command -v vd)"
pip_py="$(sed -n '1{s/^#!//p;}' "$vd_bin" || true)"
fi
if [[ -z "$pip_py" ]]; then
pip_py="$(command -v python3 || true)"
fi
if [[ -z "$pip_py" ]]; then
echo "No python found to run pip." >&2
exit 1
fi
"$pip_py" -m pip install --upgrade --target "$dst_deps_dir" -r "$src_reqs" "$pip_py" -m pip install --upgrade --target "$dst_deps_dir" -r "$src_reqs"
fi fi