From 1b9e8b39998e99ead0987ba2682f53ec94c574e5 Mon Sep 17 00:00:00 2001 From: m1ngsama Date: Mon, 4 May 2026 11:49:20 +0800 Subject: [PATCH] Add bootstrap dry-run safety checks --- .github/workflows/test.yml | 23 +++++++++++++++ CHANGELOG.md | 3 ++ QUICKSTART.md | 1 + README.md | 3 ++ get.sh | 57 +++++++++++++++++++++++++++++++++----- 5 files changed, 80 insertions(+), 7 deletions(-) mode change 100644 => 100755 get.sh diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 00d0903..2ed562a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -180,6 +180,29 @@ jobs: XDG_CONFIG_HOME=/tmp/chopsticks-default ./install.sh --configure-only --yes grep -q "let g:chopsticks_profile = 'engineer'" /tmp/chopsticks-default/chopsticks.vim + - name: Verify bootstrap dry-run safety + run: | + CHOPSTICKS_DEST=/tmp/chopsticks-bootstrap ./get.sh --dry-run --profile=minimal \ + | tee /tmp/chopsticks-get-dry-run.txt + grep -q 'Would clone' /tmp/chopsticks-get-dry-run.txt + test ! -e /tmp/chopsticks-bootstrap + + mkdir -p /tmp/not-chopsticks + git init /tmp/not-chopsticks + git -C /tmp/not-chopsticks remote add origin https://github.com/example/not-chopsticks.git + if CHOPSTICKS_DEST=/tmp/not-chopsticks ./get.sh --dry-run; then + echo "Expected get.sh to reject non-chopsticks repo" + exit 1 + fi + + mkdir -p /tmp/chopsticks-existing + git init /tmp/chopsticks-existing + git -C /tmp/chopsticks-existing remote add origin https://github.com/m1ngsama/chopsticks.git + touch /tmp/chopsticks-existing/install.sh /tmp/chopsticks-existing/.vimrc + CHOPSTICKS_DEST=/tmp/chopsticks-existing ./get.sh --dry-run --yes \ + | tee /tmp/chopsticks-get-existing.txt + grep -q 'Would update existing chopsticks repo' /tmp/chopsticks-get-existing.txt + docs: runs-on: ubuntu-latest steps: diff --git a/CHANGELOG.md b/CHANGELOG.md index f182a60..b2996df 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,8 @@ - `install.sh --profile=minimal|engineer|full` for scripted profile selection - `install.sh --dry-run` to show the resolved profile/config path without writes - `install.sh --configure-only` to update local profile config without reinstalling +- `get.sh --dry-run` for safe bootstrap previews before clone/update/install +- `CHOPSTICKS_DEST=/absolute/path` to test or install the bootstrap target elsewhere ### Fixed @@ -53,6 +55,7 @@ - tmux integration is written as a managed block so future installer runs can update it without appending duplicate bindings - Installer cleanup now restores the cursor after interrupted checkbox menus +- Bootstrap dry-run now refuses unrelated existing git repos before any writes - Skip 2 more built-in plugins: openPlugin, manpager (10 → 12 total) - Remove deprecated `set ttyfast` (no-op since Vim 8) - Add `grepprg=rg --vimgrep` — `:grep` now uses ripgrep + quickfix diff --git a/QUICKSTART.md b/QUICKSTART.md index c1bef2c..5028fa9 100644 --- a/QUICKSTART.md +++ b/QUICKSTART.md @@ -7,6 +7,7 @@ Five minutes from zero to a working Vim setup. ```bash curl -fsSL https://raw.githubusercontent.com/m1ngsama/chopsticks/main/get.sh | bash curl -fsSL https://raw.githubusercontent.com/m1ngsama/chopsticks/main/get.sh | bash -s -- --profile=minimal +curl -fsSL https://raw.githubusercontent.com/m1ngsama/chopsticks/main/get.sh | bash -s -- --dry-run --profile=full ``` Open vim. First launch auto-installs plugins — **wait 30-60s, don't close vim**. Restart when done. diff --git a/README.md b/README.md index 08b10c6..656cdc9 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,7 @@ chopsticks gives you a production-ready Vim config in one command. Pure VimScrip ```bash curl -fsSL https://raw.githubusercontent.com/m1ngsama/chopsticks/main/get.sh | bash curl -fsSL https://raw.githubusercontent.com/m1ngsama/chopsticks/main/get.sh | bash -s -- --profile=minimal +curl -fsSL https://raw.githubusercontent.com/m1ngsama/chopsticks/main/get.sh | bash -s -- --dry-run --profile=full ``` Or manually: @@ -60,6 +61,8 @@ cd ~/.vim && ./install.sh --profile=engineer ``` Supports macOS (brew), Debian/Ubuntu (apt), Arch (pacman), Fedora (dnf). +Set `CHOPSTICKS_DEST=/absolute/path` before running `get.sh` to install +somewhere other than `~/.vim`. First launch installs plugins automatically (30-60s). Restart vim when done. Use `./install.sh --dry-run --profile=full` to inspect the resolved profile and diff --git a/get.sh b/get.sh old mode 100644 new mode 100755 index 7e0d8d2..b1ca910 --- a/get.sh +++ b/get.sh @@ -4,11 +4,37 @@ # Usage: # curl -fsSL https://raw.githubusercontent.com/m1ngsama/chopsticks/main/get.sh | bash # curl -fsSL https://raw.githubusercontent.com/m1ngsama/chopsticks/main/get.sh | bash -s -- --yes +# CHOPSTICKS_DEST=/absolute/path bash get.sh --dry-run set -eo pipefail REPO="https://github.com/m1ngsama/chopsticks.git" -DEST="$HOME/.vim" +DEST="${CHOPSTICKS_DEST:-$HOME/.vim}" +DRY_RUN=0 +INSTALLER_ARGS=() + +usage() { + cat <<'EOF' +Usage: get.sh [OPTIONS] [INSTALLER_OPTIONS] + +Options: + --dry-run Show what would happen without cloning, pulling, or installing + --help, -h Show this help and exit + +Environment: + CHOPSTICKS_DEST Absolute install path (default: ~/.vim) + +All other options are passed to install.sh after clone/update. +EOF +} + +for arg in "$@"; do + case "$arg" in + --dry-run) DRY_RUN=1 ;; + --help|-h) usage; exit 0 ;; + *) INSTALLER_ARGS+=("$arg") ;; + esac +done if [[ -t 1 ]] && [[ -z "${NO_COLOR:-}" ]]; then GREEN='\033[0;32m'; YELLOW='\033[1;33m'; RED='\033[0;31m'; BOLD='\033[1m'; NC='\033[0m' @@ -19,6 +45,12 @@ ok() { echo -e "${GREEN}[OK]${NC} $1"; } warn() { echo -e "${YELLOW}[!]${NC} $1"; } die() { echo -e "${RED}[FATAL]${NC} $1" >&2; exit 1; } step() { echo -e "\n${BOLD}==> $1${NC}"; } +info() { echo " $1"; } + +case "$DEST" in + /*) ;; + *) die "CHOPSTICKS_DEST must be an absolute path: $DEST" ;; +esac repo_origin() { git -C "$DEST" config --get remote.origin.url 2>/dev/null || true @@ -42,6 +74,7 @@ echo -e "${BOLD}chopsticks — One-command installer${NC}" echo "----------------------------------" echo " Repo: $REPO" echo " Dest: $DEST" +[[ $DRY_RUN -eq 1 ]] && echo " Mode: dry-run" # ── git ─────────────────────────────────────────────────────────────────────── step "Checking for git" @@ -65,22 +98,32 @@ if [[ -d "$DEST/.git" ]]; then if ! is_chopsticks_repo "$ORIGIN"; then die "$DEST is a git repo, but it does not look like chopsticks. origin: ${ORIGIN:-none} - Back it up first: mv ~/.vim ~/.vim.bak + Back it up first: mv \"$DEST\" \"$DEST.bak\" Then re-run: curl -fsSL https://raw.githubusercontent.com/m1ngsama/chopsticks/main/get.sh | bash" fi [[ -f "$DEST/install.sh" && -f "$DEST/.vimrc" ]] || \ die "$DEST looks incomplete. Expected install.sh and .vimrc. - Back it up first: mv ~/.vim ~/.vim.bak + Back it up first: mv \"$DEST\" \"$DEST.bak\" Then re-run: curl -fsSL https://raw.githubusercontent.com/m1ngsama/chopsticks/main/get.sh | bash" + if [[ $DRY_RUN -eq 1 ]]; then + info "Would update existing chopsticks repo at $DEST" + info "Would run: bash install.sh ${INSTALLER_ARGS[*]:-(no installer options)}" + exit 0 + fi warn "$DEST already exists — pulling latest changes" git -C "$DEST" pull --ff-only origin main 2>/dev/null || \ warn "Could not pull latest — using existing version (run: git -C ~/.vim pull)" ok "Repository updated ($(git -C "$DEST" describe --tags 2>/dev/null || git -C "$DEST" rev-parse --short HEAD))" elif [[ -d "$DEST" ]]; then - die "$HOME/.vim exists but is not a chopsticks git repo. - Back it up first: mv ~/.vim ~/.vim.bak + die "$DEST exists but is not a chopsticks git repo. + Back it up first: mv \"$DEST\" \"$DEST.bak\" Then re-run: curl -fsSL https://raw.githubusercontent.com/m1ngsama/chopsticks/main/get.sh | bash" else + if [[ $DRY_RUN -eq 1 ]]; then + info "Would clone $REPO to $DEST" + info "Would run: bash install.sh ${INSTALLER_ARGS[*]:-(no installer options)}" + exit 0 + fi git clone --depth=1 "$REPO" "$DEST" || \ die "Clone failed — check your network connection" ok "Cloned to $DEST ($(git -C "$DEST" describe --tags 2>/dev/null || git -C "$DEST" rev-parse --short HEAD))" @@ -96,7 +139,7 @@ cd "$DEST" # Use a test-open to check /dev/tty is actually accessible (it may exist but be # unusable in non-interactive SSH sessions or container environments). if { true /dev/null; then - exec bash install.sh "$@"