From d8eabf77a1c2188bb788ea2bf0bec6f4042e96b5 Mon Sep 17 00:00:00 2001 From: Salvydas Lukosius Date: Fri, 15 May 2026 23:58:54 +0100 Subject: [PATCH 01/12] chore: remove deprecated files and configs Remove obsolete cspell word lists, editorconfig, vscode settings, and retired workflows (rebase, stale, sync-labels, wrangler). Drop legacy installer scripts i.sh and install_alpha.sh. --- .cspell/project-words.txt | 45 --- .editorconfig | 60 --- .github/.cspell/project-ignored.txt | 2 - .github/.cspell/project-usernames.txt | 1 - .github/.cspell/project-words.txt | 34 -- .github/workflows/rebase-action.yml | 29 -- .github/workflows/stale-action.yml | 35 -- .github/workflows/sync-labels.yml | 10 - .github/workflows/wrangler.yml | 40 -- .gitignore | 4 + .vscode/settings.json | 17 - lib/sh/i.sh | 547 -------------------------- lib/sh/install_alpha.sh | 512 ------------------------ 13 files changed, 4 insertions(+), 1332 deletions(-) delete mode 100644 .cspell/project-words.txt delete mode 100644 .editorconfig delete mode 100644 .github/.cspell/project-ignored.txt delete mode 100644 .github/.cspell/project-usernames.txt delete mode 100644 .github/.cspell/project-words.txt delete mode 100644 .github/workflows/rebase-action.yml delete mode 100644 .github/workflows/stale-action.yml delete mode 100644 .github/workflows/sync-labels.yml delete mode 100644 .github/workflows/wrangler.yml delete mode 100644 .vscode/settings.json delete mode 100755 lib/sh/i.sh delete mode 100755 lib/sh/install_alpha.sh diff --git a/.cspell/project-words.txt b/.cspell/project-words.txt deleted file mode 100644 index bb883fb..0000000 --- a/.cspell/project-words.txt +++ /dev/null @@ -1,45 +0,0 @@ -AOPT -atinit -atload -atpull -autoload -blockf -BOPT -CFLAGS -Cgreen -Checkig -COLORTERM -COMPINIT -CPPFLAGS -creinstall -Creset -distclean -gdbm -LDFLAGS -mgit -mhas -mktemp -mload -nearcolor -OMZL -OMZP -OMZT -pname -robbyrussell -SAVEHIST -setopt -srand -tcsetpgrp -truecolor -WORKDIR -ZDOTDIR -zicdreplay -zicompinit -zinit -zmodload -zmodules -ZOPT -ZPMOD -zstyle -zunit -zzinit diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index c25c645..0000000 --- a/.editorconfig +++ /dev/null @@ -1,60 +0,0 @@ -# Space or Tabs? -# https://stackoverflow.com/questions/35649847/objective-reasons-for-using-spaces-instead-of-tabs-for-indentation -# https://stackoverflow.com/questions/12093748/how-to-use-tabs-instead-of-spaces-in-a-shell-script -# https://github.com/editorconfig/editorconfig-defaults/blob/master/editorconfig-defaults.json -# -# 1. What happens when I press the Tab key in my text editor? -# 2. What happens when I request my editor to indent one or more lines? -# 3. What happens when I view a file containing U+0009 HORIZONTAL TAB characters? -# -# Answers: -# -# 1. Pressing the Tab key should indent the current line (or selected lines) one additional level. -# 2. As a secondary alternative, I can also tolerate an editor that, -# like Emacs, uses this key for a context-sensitive fix-my-indentation command. -# 3. Indenting one or more lines should follow the reigning convention, if consensus is sufficiently strong; otherwise, -# I greatly prefer 2-space indentation at each level. U+0009 characters should shift subsequent characters to the next tab stop. -# -# Note: VIM users should use alternate marks [[[ and ]]] as the original ones can confuse nested substitutions, e.g.: ${${${VAR}}} -# -# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*- -# vim: ft=zsh sw=2 ts=2 et - -root = true - -[*] -charset = utf-8 -indent_style = space -indent_size = 2 -insert_final_newline = true -trim_trailing_whitespace = true - -[*.sln] -indent_style = tab - -[*.{md,mdx,rst}] -trim_trailing_whitespace = false - -[*.{cmd,bat}] -end_of_line = crlf - -[*za-*] -end_of_line = lf - -[*.{sh,bash,zsh,fish}] -end_of_line = lf - -[Makefile] -indent_style = tab -indent_size = 4 - -[*.{py,rb}] -indent_size = 4 - -[*.{go,java,scala,groovy,kotlin}] -indent_style = tab -indent_size = 4 - -[*.{cs,csx,cake,vb,vbx}] -# Default Severity for all .NET Code Style rules below -dotnet_analyzer_diagnostic.severity = warning diff --git a/.github/.cspell/project-ignored.txt b/.github/.cspell/project-ignored.txt deleted file mode 100644 index 01e9305..0000000 --- a/.github/.cspell/project-ignored.txt +++ /dev/null @@ -1,2 +0,0 @@ -mhas -mload diff --git a/.github/.cspell/project-usernames.txt b/.github/.cspell/project-usernames.txt deleted file mode 100644 index 43ee3d2..0000000 --- a/.github/.cspell/project-usernames.txt +++ /dev/null @@ -1 +0,0 @@ -robbyrussell diff --git a/.github/.cspell/project-words.txt b/.github/.cspell/project-words.txt deleted file mode 100644 index e09d106..0000000 --- a/.github/.cspell/project-words.txt +++ /dev/null @@ -1,34 +0,0 @@ -AOPT -atinit'COMPLETION -atinit'setopt -atinit'typeset -atinit'ZI -atinit'zstyle -atload -atpull -autoload -blockf -BOPT -CFLAGS -COMPINIT -CPPFLAGS -creinstall -distclean -gdbm -LDFLAGS -mktemp -OMZL -OMZP -OMZT -SAVEHIST -tcsetpgrp -WORKDIR -ZDOTDIR -zicdreplay -zicompinit -zinit -zmodload -zmodules -ZOPT -zpmod -zzinit diff --git a/.github/workflows/rebase-action.yml b/.github/workflows/rebase-action.yml deleted file mode 100644 index 83e6615..0000000 --- a/.github/workflows/rebase-action.yml +++ /dev/null @@ -1,29 +0,0 @@ ---- -name: "๐Ÿ” Rebase" -on: - issue_comment: - types: [created] - -jobs: - rebase: - runs-on: ubuntu-latest - name: ๐Ÿ” Rebase - # Automate with comments: /autosquash, /rebase - if: >- - github.event.issue.pull_request != '' && - ( - contains(github.event.comment.body, '/rebase') || - contains(github.event.comment.body, '/autosquash') - ) - steps: - - name: โคต๏ธ Check out code from GitHub - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - with: - token: ${{ secrets.ORG_TOKEN }} - fetch-depth: 0 # otherwise, you will fail to push refs to dest repo - - name: ๐Ÿ” Rebase - uses: z-shell/.github/actions/rebase@91068ee88e8788deff439d6ee36b77329edeb98a # v1.0.8 - with: - autosquash: ${{ contains(github.event.comment.body, '/autosquash') || contains(github.event.comment.body, '/rebase-autosquash') }} - env: - GITHUB_TOKEN: ${{ secrets.ORG_TOKEN }} diff --git a/.github/workflows/stale-action.yml b/.github/workflows/stale-action.yml deleted file mode 100644 index d6fd984..0000000 --- a/.github/workflows/stale-action.yml +++ /dev/null @@ -1,35 +0,0 @@ ---- -name: "๐Ÿ‘ป Stale" - -on: - schedule: - - cron: "0 8 * * *" - workflow_dispatch: - -jobs: - stale: - name: "๐Ÿงน Clean up stale issues and PRs" - runs-on: ubuntu-latest - steps: - - name: "๐Ÿš€ Run stale" - uses: actions/stale@5bef64f19d7facfb25b37b414482c7164d639639 # v9 - with: - # ๐Ÿ“‹ https://github.com/actions/stale#all-options - days-before-stale: 30 - days-before-close: 7 - exempt-all-pr-assignees: true - exempt-all-pr-milestones: true - remove-stale-when-updated: true - stale-issue-label: "stale ๐Ÿ‘ป" - exempt-issue-labels: "no-stale ๐Ÿ”’,help-wanted ๐Ÿ‘ฅ" - stale-issue-message: > - There hasn't been any activity on this issue recently, and in order to prioritize active issues, it will be - marked as stale. Please make sure to update to the latest version and check if that solves the issue. Let us - know if that works for you by leaving a ๐Ÿ‘ Because this issue is marked as stale, it will be closed and - locked in 7 days if no further activity occurs. Thank you for your contributions! - stale-pr-label: "stale ๐Ÿ‘ป" - exempt-pr-labels: "no-stale ๐Ÿ”’" - stale-pr-message: > - There hasn't been any activity on this pull request recently, and in order to prioritize active work, it has - been marked as stale. This PR will be closed and locked in 7 days if no further activity occurs. Thank you - for your contributions! diff --git a/.github/workflows/sync-labels.yml b/.github/workflows/sync-labels.yml deleted file mode 100644 index f5f02c3..0000000 --- a/.github/workflows/sync-labels.yml +++ /dev/null @@ -1,10 +0,0 @@ ---- -name: "โ™ป๏ธ Sync Labels" -on: - schedule: - - cron: "22 2 * * 2" - workflow_dispatch: -jobs: - labels: - name: "โ™ป๏ธ Sync labels" - uses: z-shell/.github/.github/workflows/sync-labels.yml@91068ee88e8788deff439d6ee36b77329edeb98a # v1.0.8 diff --git a/.github/workflows/wrangler.yml b/.github/workflows/wrangler.yml deleted file mode 100644 index 57f590a..0000000 --- a/.github/workflows/wrangler.yml +++ /dev/null @@ -1,40 +0,0 @@ ---- -name: "๐Ÿค  Wrangler" - -on: - # schedule: - # - cron: "0 03 * * 1/3" - # push: - # branches: [main] - # paths: - # - "lib/**" - # - "workers/**" - workflow_dispatch: - inputs: - environment: - description: "Choose an environment to deploy to: " - required: true - default: "dev" - -jobs: - deploy: - runs-on: ubuntu-latest - concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - timeout-minutes: 15 - environment: wrangler - steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - - name: "๐Ÿค  Deploy > cdn" - uses: cloudflare/wrangler-action@da0e0dfe58b7a431659754fdf3f186c529afbe65 # v3.14.1 - with: - apiToken: ${{ secrets.CF_API_TOKEN }} - workingDirectory: "workers/cdn" - command: "publish" - - name: "๐Ÿค  Deploy > r2-store" - uses: cloudflare/wrangler-action@da0e0dfe58b7a431659754fdf3f186c529afbe65 # v3.14.1 - with: - apiToken: ${{ secrets.CF_API_TOKEN }} - workingDirectory: "workers/r2-store" - command: "publish" diff --git a/.gitignore b/.gitignore index c8968ab..030f2a7 100644 --- a/.gitignore +++ b/.gitignore @@ -150,3 +150,7 @@ worker/ node_modules/ .pnpm-store/ .cargo-ok +AGENTS.md +CLAUDE.md +GEMINI.md +.github/copilot-instructions.md diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index c17dc3e..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "[markdown]": { - "editor.formatOnSave": true, - "editor.formatOnPaste": true - }, - "editor.codeActionsOnSave": { - "source.fixAll.markdownlint": true - }, - "conventionalCommits.scopes": [ - "maintenance", - "workspace", - "community", - "general", - "misc" - ], - "shellformat.useEditorConfig": true -} diff --git a/lib/sh/i.sh b/lib/sh/i.sh deleted file mode 100755 index 285a610..0000000 --- a/lib/sh/i.sh +++ /dev/null @@ -1,547 +0,0 @@ -#!/usr/bin/env sh -# -*- mode: sh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*- -# vim: ft=sh sw=2 ts=2 et -trap 'rm -rf "$WORKDIR"' EXIT INT -WORKDIR="$(mktemp -d)" - -col_pname="" -col_error="" -col_info="" -col_rst="" -zsh_current=$(zsh --version &2 <&2 - exit 1 -} - -_os_type() { - OS="$(command -v uname)" - case $("${OS}" | tr '[:upper:]' '[:lower:]') in - android*) - OS='android' - ;; - darwin*) - OS='darwin' - ;; - linux*) - OS='linux' - ;; - freebsd*) - OS='freebsd' - ;; - netbsd*) - OS='netbsd' - ;; - openbsd*) - OS='openbsd' - ;; - sunos*) - OS='solaris' - ;; - msys* | cygwin* | mingw*) - OS='windows' - ;; - nt | win*) - OS='windows' - ;; - *) - echo 'OS not supported' - ;; - esac -} - -_cpu_type() { - case "$(uname -m)" in - x86_64 | x86-64 | x64 | amd64) - ARCH='amd64' - ;; - i?86 | x86) - ARCH='386' - ;; - armv8* | aarch64 | arm64) - ARCH='arm64' - ;; - armv7*) - ARCH='armv7' - ;; - armv6*) - ARCH='armv6' - ;; - arm*) - ARCH='arm' - ;; - mips64le*) - ARCH='mips64le' - ;; - mips64*) - ARCH='mips64' - ;; - mipsle*) - ARCH='mipsle' - ;; - mips*) - ARCH='mips' - ;; - ppc64le*) - ARCH='ppc64le' - ;; - ppc64*) - ARCH='ppc64' - ;; - ppcle*) - ARCH='ppcle' - ;; - ppc*) - ARCH='ppc' - ;; - s390*) - ARCH='s390x' - ;; - *) - echo 'OS architecture not supported' - ;; - esac -} - -# Synopsis: -# -# annex: (available: recommended) -# -a recommended -# branch: (available: main or any other existing branch) -# -b main -# configuration directory: (default: ~/.config/zi, can be overridden to prefered location) -# -c ${HOME}/.config/zi -# ZI home directory (default: ~/.zi, can be overriden prefered location) -# -d ${HOME}/.zi -# zshrc header: (available loader, installer) -# -e loader -# clone options: (default: --progress, can be overridden to prefered git clone options) -# -o --progress -# make/build options: (build, make additonal. Available: zpmod) -# -m zpmod -# host to use: (default: host to use. Available: github.com, gitlab.com) -# -h github.com -# install profile: (profile to run: install, uninstall) -# -p install -# snippets: (group of snippets to install: not-available yet) -# -s not-available yet -# plugins: group of plugins to install: not-available yet) -# -s not-available yet -# -# Example: ./install.sh -p install -c ~/.config/zi -d ~/.zi -e loader -o --progress -m zpmod -h github.com - -while getopts ":a:b:c:d:e:o:m:h:p:z:s:" opt; do - case ${opt} in - a) - ANNEX="${ANNEX}${OPTARG}" - ;; - b) - BRANCH="${BRANCH}${OPTARG}" - ;; - c) - CONFIG_DIR="${CONFIG_DIR}${OPTARG}" - ;; - d) - ZI_HOME="${ZI_HOME}${OPTARG}" - ;; - e) - ZHEADER="${ZHEADER}${OPTARG}" - ;; - o) - CLONE_OPTS="${CLONE_OPTS}${OPTARG}" - ;; - m) - MAKE="${MAKE}${OPTARG}" - ;; - h) - HOST="${HOST}${OPTARG}" - ;; - p) - PROFILE="${PROFILE}${OPTARG}" - ;; - z) - OMZ="${OMZ}${OPTARG}" - ;; - s) - STD="${STD}${OPTARG}" - ;; - \?) - err "Invalid option: ${OPTARG}" 1>&2 - ;; - :) - err "Invalid option: ${OPTARG} requires an argument" 1>&2 - ;; - *) - err "Invalid option: ${OPTARG}" 1>&2 - - ;; - esac -done -shift $((OPTIND - 1)) - -if [ -z "${PROFILE}" ]; then - # Available profiles: install, uninstall, main. - PROFILE="main" -fi -if [ -z "${HOST}" ]; then - # Default host - HOST="github.com" -fi -if [ -z "${BRANCH}" ]; then - # Default branch - BRANCH="main" -fi -if [ -z "${CLONE_OPTS}" ]; then - # Default git clone options - CLONE_OPTS="--progress" -fi -if [ -z "${ZI_HOME}" ]; then - # Installiation time ZI home directory - ZI_HOME="${ZDOTDIR:-${HOME}}/.zi" -fi -if [ -z "${ZI_BIN_DIR_NAME}" ]; then - # ZI bin directory - ZI_BIN_DIR_NAME="bin" -fi -if [ -z "${CONFIG_DIR}" ]; then - # Default configuration directory - CONFIG_DIR="${XDG_CONFIG_HOME:-${HOME}/.config}/zi" -fi -if [ -z "${ZHEADER}" ]; then - # Default header script - ZHEADER="loader" -fi - -_set_externals() { - if ! command -v git >/dev/null 2>&1; then - err "โ–“โ–’โ–‘ Something went wrong: git not available, cannot proceed." - fi - if [ "${HOST}" = github.com ]; then - if curl -fsL https://raw.githubusercontent.com/z-shell/zi-src/main/lib/zsh/init.zsh >/dev/null; then - RAW_LOADER_URL="https://raw.githubusercontent.com/z-shell/zi-src/main/lib/zsh/init.zsh" - if curl -fsL https://raw.githubusercontent.com/z-shell/zi/main/lib/zsh/git-process-output.zsh >/dev/null; then - RAW_GIT_OUPUT="https://raw.githubusercontent.com/z-shell/zi/main/lib/zsh/git-process-output.zsh" - else - err "Git process script at GitHub is not reachable" - fi - else - err "GitLab and GitHub repositories are unreachable" - fi - elif [ "${HOST}" = gitlab.com ]; then - if curl -fsL https://gitlab.com/ss-o/zi-src/-/raw/main/lib/zsh/init.zsh >/dev/null; then - RAW_LOADER_URL="https://gitlab.com/ss-o/zi-src/-/raw/main/lib/zsh/init.zsh" - if curl -fsL https://gitlab.com/ss-o/zi/-/raw/main/lib/zsh/git-process-output.zsh >/dev/null; then - RAW_GIT_OUPUT="https://gitlab.com/ss-o/zi/-/raw/main/lib/zsh/git-process-output.zsh" - else - err "Git process script at GitLab is not reachable" - fi - fi - fi - # Get the download-progress bar tool - if command -v curl >/dev/null 2>&1; then - command mkdir -p "${WORKDIR}" - cd "${WORKDIR}" || return - command curl -fsSLO "${RAW_GIT_OUPUT}" && command chmod a+x "${WORKDIR}"/git-process-output.zsh - elif command -v wget >/dev/null 2>&1; then - command mkdir -p "${WORKDIR}" - cd "${WORKDIR}" || return - command wget -q "${RAW_GIT_OUPUT}" && command chmod a+x "${WORKDIR}"/git-process-output.zsh - else - say "โ–“โ–’โ–‘ Something went wrong:" - err "curl or wget not available or failed to create temp directory, cannot proceed." - fi -} - -_check_zshrc() { - THE_ZDOTDIR="${ZDOTDIR:-${HOME}}" - say "โ–“โ–’โ–‘ Updating ${THE_ZDOTDIR}/.zshrc" - if grep -E '(zi|init|zinit)\.zsh' "${THE_ZDOTDIR}/.zshrc" >/dev/null 2>&1; then - say "โ–“โ–’โ–‘ File .zshrc have conflicting commands, backuping..." - say "โ–“โ–’โ–‘ creating backup at ${CONFIG_DIR}/zshrc..." - date=$(date +%H%M%S) && command mv -f "${THE_ZDOTDIR}/.zshrc" "${CONFIG_DIR}/zshrc.${date}" - fi -} - -_set_zshrc_header() { - # current zshrc headers: (loader, installer) - _check_zshrc - if [ "${ZHEADER}" = loader ]; then - if command -v curl >/dev/null 2>&1; then - command curl -fsSL "${RAW_LOADER_URL}" -o "${CONFIG_DIR}/init.zsh" - elif command -v wget >/dev/null 2>&1; then - command wget -qO "${CONFIG_DIR}/init.zsh" "${RAW_LOADER_URL}" - else - err "โ–“โ–’โ–‘ Something went wrong: curl and wget not available, cannot proceed." - fi - command chmod a+x "${CONFIG_DIR}/init.zsh" - command sed -i "s/branch=\"main\"/branch=\"${BRANCH}\"/g" "${CONFIG_DIR}/init.zsh" - command cat <<-EOF >>"${THE_ZDOTDIR}/.zshrc" -if [[ -r "${XDG_CONFIG_HOME:-${HOME}/.config}/zi/init.zsh" ]]; then - source "${XDG_CONFIG_HOME:-${HOME}/.config}/zi/init.zsh" && zzinit -fi -EOF - say "โ–“โ–’โ–‘ Loader added successfully." - elif [ "${ZHEADER}" = installer ]; then - command cat <<-EOF >>"${THE_ZDOTDIR}/.zshrc" -if [[ ! -f ${ZI_HOME}/${ZI_BIN_DIR_NAME}/zi.zsh ]]; then - print -P "%F{33}โ–“โ–’โ–‘ %F{160}Installing (%F{33}z-shell/zi%F{160})โ€ฆ%f" - command mkdir -p "${ZI_HOME}" && command chmod g-rwX "${ZI_HOME}" - command git clone ${CLONE_OPTS} --branch "${BRANCH}" https://${HOST}/z-shell/zi "${ZI_HOME}/${ZI_BIN_DIR_NAME}" && \\ - print -P "%F{33}โ–“โ–’โ–‘ %F{34}Installation successful.%f%b" || \\ - print -P "%F{160}โ–“โ–’โ–‘ The clone has failed.%f%b" -fi -source "${ZI_HOME}/${ZI_BIN_DIR_NAME}/zi.zsh" -autoload -Uz _zi -(( \${+_comps} )) && _comps[zi]=_zi -EOF - else - true - fi -} - -_setup_directories() { - _set_externals "$@" - if ! test -d "${ZI_HOME}"; then - command mkdir "${ZI_HOME}" - command chmod g-w "${ZI_HOME}" - command chmod o-w "${ZI_HOME}" - fi - if ! test -d "${ZI_HOME}/${ZI_BIN_DIR_NAME}"; then - command mkdir "${ZI_HOME}/${ZI_BIN_DIR_NAME}" - command chmod g-w "${ZI_HOME}/${ZI_BIN_DIR_NAME}" - command chmod o-w "${ZI_HOME}/${ZI_BIN_DIR_NAME}" - fi - if ! test -d "${CONFIG_DIR}"; then - command mkdir "${CONFIG_DIR}" - command chmod g-w "${CONFIG_DIR}" - command chmod o-w "${CONFIG_DIR}" - fi - _set_zshrc_header "$@" -} - -_setup_profile() { - _setup_directories "$@" - if [ "${PROFILE}" = install ]; then - if test -d "${ZI_HOME}/${ZI_BIN_DIR_NAME}/.git"; then - cd "${ZI_HOME}/${ZI_BIN_DIR_NAME}" || return - say "โ–“โ–’โ–‘ Updating (z-shell/zi) plugin manager at ${ZI_HOME}/${ZI_BIN_DIR_NAME}" - command git clean -d -f -f - command git reset --hard HEAD - command git pull -q origin HEAD - command git submodule update --init --recursive - command git submodule update --recursive --remote - say "โ–“โ–’โ–‘ Successfully installed (z-shell/zi) at ${ZI_HOME}/${ZI_BIN_DIR_NAME}" - else - cd "${ZI_HOME}" || return - say "โ–“โ–’โ–‘ Installing (z-shell/zi) plugin manager at ${ZI_HOME}/${ZI_BIN_DIR_NAME}" - { git clone "${CLONE_OPTS}" --branch "${BRANCH}" https://"${HOST}"/z-shell/zi.git "${ZI_BIN_DIR_NAME}" \ - 2>&1 | { "${WORKDIR}/out/git-process-output.zsh" || cat; }; } 2>/dev/null - if [ -d "${ZI_BIN_DIR_NAME}" ]; then - say "โ–“โ–’โ–‘ Successfully installed at ${ZI_HOME}/${ZI_BIN_DIR_NAME}". - else - err "โ–“โ–’โ–‘ Something went wrong, couldn't install ZI at ${ZI_HOME}/${ZI_BIN_DIR_NAME}" - fi - fi - elif [ "${PROFILE}" = uninstall ]; then - clear - say "โ–“โ–’โ–‘ Remove โฎ ZI โฏ? [y/N]" - read -r confirmation - if [ "${confirmation}" != y ] && [ "${confirmation}" != Y ]; then - echo "Uninstall process cancelled" - exit 0 - fi - clear - say "Removing โฎ ZI โฏ home directory" - sleep 2 - if [ -d "${HOME}/.zi" ]; then - rm -rvf "${HOME}/.zi" - elif [ -d "${ZDOTDIR}/.zi" ]; then - rm -rvf "${ZDOTDIR}/.zi" - elif [ -d "${XDG_DATA_HOME}/.zi" ]; then - rm -rvf "${XDG_DATA_HOME}/.zi" - fi - clear - echo "โ–“โ–’โ–‘ Clean โฎ ZI โฏ cache? [y/N]" - read -r confirmation - if [ "${confirmation}" != y ] && [ "${confirmation}" != Y ]; then - echo "Cleaning โฎ ZI โฏ cache" - sleep 2 - if [ -d "${HOME}/.cache/zi" ]; then - rm -rvf "${HOME}/.cache/zi" - elif [ -d "${ZDOTDIR}/.cache/zi" ]; then - rm -rvf "${ZDOTDIR}/.cache/zi" - elif [ -d "${XDG_DATA_HOME}/.cache/zi" ]; then - rm -rvf "${XDG_DATA_HOME}/.cache/zi" - fi - fi - clear - echo "โ–“โ–’โ–‘ Remove โฎ ZI โฏ config directory? [y/N]" - read -r confirmation - if [ "${confirmation}" != y ] && [ "${confirmation}" != Y ]; then - echo "Removing โฎ ZI โฏ config directory" - sleep 2 - if [ -d "${XDG_CONFIG_HOME}/zi" ]; then - rm -rvf "${XDG_CONFIG_HOME}/zi" - else - if [ -d "${HOME}/.config/zi" ]; then - rm -rvf "${HOME}/.config/zi" - elif [ -d "${XDG_DATA_HOME}/zi" ]; then - rm -rvf "${XDG_DATA_HOME}/zi" - fi - fi - fi - clear - echo "โ–“โ–’โ–‘ Reload shell? [y/N]" - read -r confirmation - if [ "${confirmation}" != y ] && [ "${confirmation}" != Y ]; then - say "โ–“โ–’โ–‘ Uninstall successful" - command cat <<-EOF -โ–“โ–’โ–‘ โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ–  โฎ ZI โฏ -โ–“โ–’โ–‘ Wiki: https://wiki.zshell.dev -โ–“โ–’โ–‘ Issues: https://github.com/z-shell/zi/issues -โ–“โ–’โ–‘ Discussions: https://discussions.zshell.dev" -EOF - rm -rf "${WORKDIR}" - exit 0 - else - rm -rf "${WORKDIR}" - exec "${SHELL}" -l - fi - elif [ "${PROFILE}" = main ]; then - true - else - err "Invalid profile: ${PROFILE}" 1>&2 - fi -} - -_make_build() { - if [ "${MAKE}" = zpmod ]; then - ZI_HOME="${ZI_HOME:-${ZDOTDIR:-${HOME}}/.zi}" - MOD_HOME="${MOD_HOME:-zmodules}/zpmod" - if ! test -d "${ZI_HOME}/${MOD_HOME}"; then - mkdir -p "${ZI_HOME}/${MOD_HOME}" - chmod g-rwX "${ZI_HOME}/${MOD_HOME}" - fi - say "${col_pname}== Downloading ZPMOD module to ${ZI_HOME}/${MOD_HOME}" - if test -d "${ZI_HOME}/${MOD_HOME}/.git"; then - cd "${ZI_HOME}/${MOD_HOME}" || return - git pull -q origin main - else - cd "${ZI_HOME}" || return - git clone "${CLONE_OPTS}" https://"${HOST}"/z-shell/zpmod.git "${MOD_HOME}" - fi - say "${col_pname}== Done" - if command -v zsh >/dev/null; then - say "${col_info}-- Checkig version --${col_rst}" - if expr "${zsh_current}" \< "${zsh_required}" >/dev/null; then - say "${col_error}-- Zsh version 5.8.1 and above required --${col_rst}" - - else - say "${col_info}-- Zsh version ${zsh_current} --${col_rst}" - cd "${ZI_HOME}/${MOD_HOME}" || return - say "${col_pname}== Building module ZPMOD, running: a make clean, then ./configure and then make ==${col_rst}" - say "${col_pname}== The module sources are located at: ${ZI_HOME}/${MOD_HOME} ==${col_rst}" - if test -f Makefile; then - if [ "$1" = "--clean" ]; then - say "${col_info}-- make distclean --${col_rst}" - make -s distclean - true - else - say "${col_info}-- make clean (pass --clean to invoke \`make distclean') --${col_rst}" - make -s clean - fi - fi - say "${col_info}-- Configuring --${col_rst}" - if CPPFLAGS=-I/usr/local/include CFLAGS="-g -Wall -O3" LDFLAGS=-L/usr/local/lib ./configure --disable-gdbm --without-tcsetpgrp; then - say "${col_info}-- Running make --${col_rst}" - if make -s; then - command cat <<-EOF -โ–“โ–’โ–‘ Module has been built correctly. -โ–“โ–’โ–‘ See 'zpmod -h' for more information. -โ–“โ–’โ–‘ Run 'zpmod source-study' to see profile data, -โ–“โ–’โ–‘ Guaranteed, automatic compilation of any sourced script. -EOF - zpmod_file="${WORKDIR}/zpmod" - command cat <<-EOF >>"${zpmod_file}" -module_path+=( "${ZI_HOME}/${MOD_HOME}/Src" ) -zmodload zi/zpmod -EOF - say "โ–“โ–’โ–‘ Enabling zpmod" - command cat "${zpmod_file}" >>"${THE_ZDOTDIR}/.zshrc" - zsh -ic "@zi-scheduler burst" - else - say "${col_error}Module did not build.${col_rst}. You can copy the error messages and submit" - err "error-report at: https://${HOST}/z-shell/zpmod/issues" - fi - fi - fi - else - err "${col_error} Zsh is not installed. Please install zsh and try again.${col_rst}" - fi - else - true - fi -} - -_set_annexes() { - if [ "${ANNEX}" = recommended ]; then - file="${WORKDIR}/annex_recommended" - command cat <<-EOF >>"${file}" -zi light-mode for \\ - z-shell/z-a-meta-plugins \\ - @annexes # <- https://wiki.zshell.dev/ecosystem/category/-annexes -# examples here -> https://wiki.zshell.dev/community/gallery/collection -zicompinit # <- https://wiki.zshell.dev/docs/guides/commands -EOF - say "โ–“โ–’โ–‘ Installing annexes" - command cat "${file}" >>"${THE_ZDOTDIR}/.zshrc" - zsh -ic "@zi-scheduler burst" - else - true - fi -} - -_finish_install() { - git_refs="$( - command cd "${ZI_HOME}/${ZI_BIN_DIR_NAME}" || true - command git log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit | head -3 - )" - say "โ–“โ–’โ–‘ Latest changes:" - say "${git_refs}" -} - -_system() { - _os_type - _cpu_type - _setup_profile "$@" - _make_build "$@" - _set_annexes "$@" - _finish_install "$@" -} - -MAIN() { - _system "$@" - say "โ–“โ–’โ–‘ System: ${OS} - ${ARCH}" - command cat <<-EOF -โ–“โ–’โ–‘ โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ–  Successfully installed โฎ ZI โฏ โ– โ– โ– โ– โ– โ– โ– โ– โ–  -โ–“โ–’โ–‘ Wiki: https://wiki.zshell.dev -โ–“โ–’โ–‘ Issues: https://github.com/z-shell/zi/issues -โ–“โ–’โ–‘ Discussions: https://discussions.zshell.dev -โ–“โ–’โ–‘ โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ–  -EOF - exit 0 -} - -while true; do - MAIN "${@}" -done diff --git a/lib/sh/install_alpha.sh b/lib/sh/install_alpha.sh deleted file mode 100755 index a62d423..0000000 --- a/lib/sh/install_alpha.sh +++ /dev/null @@ -1,512 +0,0 @@ -#!/usr/bin/env sh -# -*- mode: sh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*- -# vim: ft=sh sw=2 ts=2 et - -# shellcheck disable=all - -# Temporary work directory -trap 'rm -rf "$WORKDIR"' EXIT INT - -# Variables -WORKDIR="$(mktemp -d)" -ZI_REPO="https://github.com/z-shell/zi" -MOD_REPO="https://github.com/z-shell/zpmod" -GIT_BAR="${WORKDIR}/git-progress-bar.zsh" -GIT_BAR_URL="https://raw.githubusercontent.com/z-shell/zi/main/lib/zsh/git-process-output.zsh" -LOADER_URL="https://raw.githubusercontent.com/z-shell/zi-src/main/lib/zsh/init.zsh" - -# Messages -say() { - while [ -n "$1" ]; do - case "$1" in - -normal) col="\033[00m" ;; - -black) col="\033[30;01m" ;; - -red) col="\033[31;01m" ;; - -green) col="\033[32;01m" ;; - -yellow) col="\033[33;01m" ;; - -blue) col="\033[34;01m" ;; - -magenta) col="\033[35;01m" ;; - -cyan) col="\033[36;01m" ;; - -white) col="\033[37;01m" ;; - -n) - one_line=1 - shift - continue - ;; - *) - printf '%s' "$1" - shift - continue - ;; - esac - shift - printf "%s${col}" - printf '%s' "$1" - printf "\033[00m" - shift - done - [ -z "${one_line}" ] && printf "\n" -} - -ask() { - question="$1" - printf "\033[34;1mโ–“โ–’โ–‘ \033[00mยป " - say -yellow "$question" -n - printf " \033[00m[y/N]: " - read -r answer - case $answer in - [yY]*) - true - ;; - *) - false - ;; - esac -} - -err() { - say -red "$1" >&2 - exit 1 -} - -say_ok() { - printf "\033[34;1mโ–“โ–’โ–‘\033[32;01m โœ” \033[00mยป " - say -green "$1" - printf "\033[00m" -} - -say_err() { - printf "\033[34;01mโ–“โ–’โ–‘\033[31;01m โœ˜ \033[00mยป " - say -red "$*" >&2 - printf "\033[00m" - exit 1 -} - -say_info() { - printf "\033[34;1mโ–“โ–’โ–‘\033[36;01m โšก\033[00mยป " - say -cyan "$1" - printf "\033[00m" -} - -while getopts ":i:a:b:" opt; do - case ${opt} in - i) - ZOPT="${ZOPT}${OPTARG}" - ;; - a) - AOPT="${AOPT}${OPTARG}" - ;; - b) - BOPT="${OPTARG}" - ;; - \?) - say_err "Invalid option: ${OPTARG}" - ;; - :) - say_err "Invalid option: ${OPTARG} requires an argument" - ;; - *) - say_err "Invalid option: ${OPTARG}" - ;; - esac -done -shift $((OPTIND - 1)) - -# Default options -[ -z "$BOPT" ] && BOPT="main" - -# Functions -is_cmd() { command -v "$1" >/dev/null 2>&1; } - -check_cmd() { - if ! is_cmd "$1"; then - say_err "$1 not found. Please install it and try again." - fi -} - -download() { - # Set download command - if is_cmd curl; then - command curl -fsSL "$1" -o "$2" && command chmod a+x "$2" - elif is_cmd wget; then - command wget -qO "$2" "$1" && command chmod a+x "$2" - else - say_err "curl or wget is required. Please install it and try again." - fi -} - -git_clone() { - command git clone --progress --depth 1 --branch "$BOPT" "$1" "$2" 2>&1 | { "$GIT_BAR" || cat; } 2>/dev/null -} - -prepare_installer() { - # Check for required commands - check_cmd git - check_cmd zsh - - # Establish Zi home directory - if [ -z "$ZI_HOME" ]; then - if [ -d "${HOME}" ]; then - ZSH_HOME_DIR="$HOME" - ZI_HOME="${HOME}/.zi" - elif [ -d "${ZDOTDIR}" ]; then - ZSH_HOME_DIR="$ZDOTDIR" - ZI_HOME="${ZDOTDIR}/.zi" - elif [ -d "${XDG_DATA_HOME}" ]; then - ZSH_HOME_DIR="$XDG_DATA_HOME" - ZI_HOME="${XDG_DATA_HOME}/.zi" - fi - fi - - if [ ! -d "$ZI_HOME" ]; then - command mkdir -p "$ZI_HOME" - fi - - if [ ! -w "$ZI_HOME" ]; then - command chown -R "$(whoami)" - command chmod -R go-w "$ZI_HOME" - fi - - # Establish Zi bin directory - if [ -z "$ZI_BIN_DIR" ]; then - ZI_BIN_DIR="${ZI_HOME}/bin" - fi - - if [ ! -d "$ZI_BIN_DIR" ]; then - command mkdir -p "$ZI_BIN_DIR" - fi - - if [ ! -w "$ZI_BIN_DIR" ]; then - command chown -R "$(whoami)" - command chmod -R go-w "$ZI_BIN_DIR" - fi - - if [ -z "$ZSH_CACHE_DIR" ]; then - ZSH_CACHE_DIR="${ZSH_HOME_DIR}/.cache/zi" - fi - - if [ ! -d "$ZSH_CACHE_DIR" ]; then - command mkdir -p "$ZSH_CACHE_DIR" - fi - - if [ ! -w "$ZSH_CACHE_DIR" ]; then - command chown -R "$(whoami)" - command chmod -R go-w "$ZSH_CACHE_DIR" - fi - - if [ -z "$ZSH_LOG_DIR" ]; then - ZSH_LOG_DIR="${ZSH_HOME_DIR}/.cache/zi/logs" - fi - - if [ -z "$ZSH_LOG_FILE" ]; then - ZSH_LOG_FILE="${ZSH_LOG_DIR}/$(date +%Y-%m-%d).log" - fi - - if [ ! -f "$GIT_BAR" ]; then - download "$GIT_BAR_URL" "$GIT_BAR" - fi -} - -check_zshrc() { - # Check if Zi is already installed - if grep -E '(zi|init|zinit)\.zsh' "${ZSH_HOME_DIR}/.zshrc" >/dev/null 2>&1; then - say_info "Zi already set in .zshrc, backing up to .zshrc.bak" - command mv "${ZSH_HOME_DIR}/.zshrc" "${ZSH_HOME_DIR}/.zshrc.bak" - elif [ -f "${ZSH_HOME_DIR}/.zshrc" ]; then - say_info "Backing up to current .zshrc to .zshrc.bak" - command mv "${ZSH_HOME_DIR}/.zshrc" "${ZSH_HOME_DIR}/.zshrc.bak" - fi -} - -set_repository() { - prepare_installer "$@" - - if [ -d "${ZI_BIN_DIR}/.git" ]; then - builtin cd "${ZI_BIN_DIR}" && say_info "Found Zi at $ZI_BIN_DIR, updating..." - command git clean --quiet -d -f -f - command git reset --quiet --hard HEAD - command git pull --quiet origin HEAD - say_ok "Update Successful!" - return 0 - elif [ -d "$ZI_BIN_DIR" ]; then - git_clone "$ZI_REPO" "$ZI_BIN_DIR" - if [ -f "${ZI_BIN_DIR}/zi.zsh" ]; then - command cat <<-EOF -โ–“โ–’โ–‘ โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ–  Successfully installed Zi โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ–  -EOF - return 0 - else - say_err "Something went wrong, couldn't proceed with installation." - fi - fi -} - -set_loader() { - check_zshrc - # Establish Zi config directory - if [ -z "$ZI_CONFIG_DIR" ]; then - ZI_CONFIG_DIR="${XDG_CONFIG_HOME:-${HOME}/.config}/zi" - fi - - if [ ! -d "$ZI_CONFIG_DIR" ]; then - command mkdir -p "$ZI_CONFIG_DIR" - fi - - if [ ! -w "$ZI_CONFIG_DIR" ]; then - command chmod go-w "$ZI_CONFIG_DIR" - fi - - download "$LOADER_URL" "${ZI_CONFIG_DIR}/init.zsh" - command sed -i "s/branch=\"main\"/branch=\"${BOPT}\"/g" "${ZI_CONFIG_DIR}/init.zsh" - command cat <<-EOF >>"$ZSH_HOME_DIR/.zshrc" -# Zi Loader ========================================================================================================= # -# https://wiki.zshell.dev/docs/getting_started/installation -if [[ -r "${XDG_CONFIG_HOME:-${HOME}/.config}/zi/init.zsh" ]]; then - source "${XDG_CONFIG_HOME:-${HOME}/.config}/zi/init.zsh" && zzinit -fi - -EOF - return 0 -} - -set_installer() { - check_zshrc - command cat <<-EOF >>"$ZSH_HOME_DIR/.zshrc" -# Zi source directory =============================================================================================== # -# https://wiki.zshell.dev/docs/guides/customization#customizing-paths -typeset -A ZI -ZI[BIN_DIR]="$ZI_BIN_DIR" - -# Auto install Zi =================================================================================================== # -if [[ ! -f \${ZI[BIN_DIR]}/zi.zsh ]]; then - print -P "%F{33}โ–“โ–’โ–‘ %F{160}Installing (%F{33}z-shell/zi%F{160})โ€ฆ%f" - command mkdir -p "\$ZI[BIN_DIR]" && \\ - command git clone -q --branch "${BOPT}" $ZI_REPO "\${ZI[BIN_DIR]}" && \\ - print -P "%F{33}โ–“โ–’โ–‘ %F{34}Installation successfulโ€ฆ%f%b" || print -P "%F{160}โ–“โ–’โ–‘ The clone has failed.%f%b" -fi - -# Enable Zi ========================================================================================================= # -# https://wiki.zshell.dev/docs/getting_started/installation#manual-setup -source "\${ZI[BIN_DIR]}/zi.zsh" -autoload -Uz _zi -(( \${+_comps} )) && _comps[zi]=_zi - -EOF - return 0 -} - -set_omz_lib() { - command cat <<-EOF >>"$ZSH_HOME_DIR/.zshrc" -# Oh-My-Zsh lib ===================================================================================================== # -# https://wiki.zshell.dev/docs/getting_started/migration#omz-library -zi is-snippet wait lucid for \\ - OMZL::{git,theme-and-appearance,prompt_info_functions,vcs_info}.zsh \\ - atinit'COMPLETION_WAITING_DOTS=true' \\ - OMZL::completion.zsh \\ - atinit'typeset -gx HISTSIZE=290000 SAVEHIST=290000 HISTFILE=${ZSH_CACHE_DIR}/.history' \\ - OMZL::history.zsh - -EOF -} - -set_omz_plugins() { - command cat <<-EOF >>"$ZSH_HOME_DIR/.zshrc" -# Oh-My-Zsh plugins ================================================================================================= # -# https://wiki.zshell.dev/docs/getting_started/migration#omz-plugins -zi is-snippet wait lucid for \\ - atload"unalias grv" \\ - OMZP::git \\ - if'[[ -d ~/.ssh ]]' \\ - OMZP::ssh-agent \\ - if'[[ -d ~/.gnupg ]]' \\ - OMZP::gpg-agent - -EOF -} - -set_omz_themes() { - command cat <<-EOF >>"$ZSH_HOME_DIR/.zshrc" -# Oh-My-Zsh theme =================================================================================================== # -# https://wiki.zshell.dev/community/gallery/collection/themes -# https://wiki.zshell.dev/docs/getting_started/migration#omz-themes -zi wait'!' lucid for \\ - atinit'setopt prompt_subst' \\ - OMZT::robbyrussell - -EOF -} - -set_plugins() { - command cat <<-EOF >>"$ZSH_HOME_DIR/.zshrc" -# Popular plugins =================================================================================================== # -# https://wiki.zshell.dev/ecosystem -# https://wiki.zshell.dev/community/gallery/collection/plugins -zi wait lucid for \\ - atinit'ZI[COMPINIT_OPTS]=-C; zicompinit; zicdreplay' \\ - z-shell/F-Sy-H \\ - atload'!_zsh_autosuggest_start' \\ - zsh-users/zsh-autosuggestions \\ - blockf atpull' zi creinstall -q .' \\ - zsh-users/zsh-completions \\ - atinit'zstyle ":history-search-multi-word" page-size "7"' \\ - z-shell/H-S-MW -EOF -} - -set_themes() { - command cat <<-EOF >>"$ZSH_HOME_DIR/.zshrc" -# Popular themes ==================================================================================================== # -# https://wiki.zshell.dev/community/gallery/collection/themes - -EOF -} - -set_annexes() { - command cat <<-EOF >>"$ZSH_HOME_DIR/.zshrc" -# Meta-plugins & annexes =========================================================================================== # -# https://wiki.zshell.dev/ecosystem/category/-annexes -zi for \\ - z-shell/z-a-meta-plugins \\ - @annexes - -EOF -} - -set_zpmod() { - check_cmd make - - # Establish zpmod directory - if [ -z "$MOD_HOME" ]; then - MOD_HOME="${ZI_HOME}/zmodules/zpmod" - fi - - if [ ! -d "$MOD_HOME" ]; then - command mkdir -p "$MOD_HOME" - fi - - if [ ! -w "$MOD_HOME" ]; then - command chmod go-w "$MOD_HOME" - fi - - if [ -d "${MOD_HOME}/.git" ]; then - say_info "Updating ZPMOD at $MOD_HOME" - builtin cd "$MOD_HOME" && command git pull -q --ff-only origin main - else - say_info "Downloading ZPMOD to $MOD_HOME" - command git clone -q "$MOD_REPO" "$MOD_HOME" - fi - - say_info "Checkig version for zsh..." - ZSH_CURRENT=$(zsh --version /dev/null; then - say_err "Zsh version 5.8.1 and above required." - else - say_info "Zsh version ${ZSH_CURRENT} is compatible." - builtin cd "$MOD_HOME" || err "Failed to change directory to $MOD_HOME." - say_info "Building module ZPMOD, running: a make clean, then ./configure and then make." - say_info "The module source are located at: $MOD_HOME" - if test -f Makefile; then - if [ "$1" = "--clean" ]; then - say_info "Running: make distclean..." - make distclean - true - else - say_info "Running: make clean (pass --clean to invoke \`make distclean')..." - make clean - fi - fi - say_info "Configuring..." - if CPPFLAGS=-I/usr/local/include CFLAGS="-g -Wall -O3" LDFLAGS=-L/usr/local/lib ./configure --disable-gdbm --without-tcsetpgrp; then - say_info "Building..." - if make -s; then - command cat <<-EOF -โ–“โ–’โ–‘ Module has been built correctly. -โ–“โ–’โ–‘ To load the module, add following 2 lines to .zshrc, at top: -  module_path+=( "${MOD_HOME}/Src" ) -  zmodload zi/zpmod -โ–“โ–’โ–‘ See 'zpmod -h' for more information. -โ–“โ–’โ–‘ Run 'zpmod source-study' to see profile data, -โ–“โ–’โ–‘ Guaranteed, automatic compilation of any sourced script. -EOF - else - say_err "Module failed build. Please report error at: ${MOD_REPO}/issues" - fi - fi - fi -} - -interactive_zshrc() { - if [ "$ZOPT" != skip ] && [ "$AOPT" = interactive ]; then - say_info "Creating .zshrc interactively..." - if ask "Install Zi Loader?"; then - set_loader - else - set_installer - fi - - if ask "Install annexes?"; then - set_annexes - fi - - if ask "Add recommended Oh-My-Zsh library?"; then - set_omz_lib - fi - - if ask "Add recommended Oh-My-Zsh plugins?"; then - set_omz_plugins - fi - - if ask "Add recommended Oh-My-Zsh theme?"; then - set_omz_themes - fi - - if ask "Add recommended plugins?"; then - set_plugins - fi - - zsh -ilc "@zi-scheduler burst" - command cat <<-EOF -โ–“โ–’โ–‘ โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ–  Successfully created .zshrc โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ–  -EOF - return 0 - fi -} - -default_zshrc() { - if [ "$ZOPT" != skip ] && [ "$AOPT" = default ]; then - say_info "Creating .zshrc file..." - set_loader - set_annexes - set_omz_lib - set_omz_plugins - set_omz_themes - set_plugins - - zsh -ilc "@zi-scheduler burst" - command cat <<-EOF -โ–“โ–’โ–‘ โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ–  Successfully created .zshrc โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ–  -EOF - return 0 - fi -} - -MAIN() { - set_repository "$@" - default_zshrc - - command cat <<-EOF - -โ–“โ–’โ–‘ Wiki: https://wiki.zshell.dev -โ–“โ–’โ–‘ Issues: https://github.com/z-shell/zi/issues -โ–“โ–’โ–‘ Discussions: https://discussions.zshell.dev - -โ–“โ–’โ–‘ โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ–  - -EOF - exit $? -} - -while true; do - MAIN "${@}" -done From b003a258fb101f683bcb7131766676a4d336d6ac Mon Sep 17 00:00:00 2001 From: Salvydas Lukosius Date: Fri, 15 May 2026 23:59:14 +0100 Subject: [PATCH 02/12] ci: update workflows and trunk configuration - Bump actions/checkout to v6.0.2 and shellcheck to 2.0.0 - Add lib/zsh/** and tests/** to push/PR path triggers - Add permissions: contents: read and timeout-minutes: 10 - Use github.ref in concurrency group - Replace ~/.zi hard-coded paths with XDG_DATA_HOME equivalents - Add unit-fixture step calling tests/installers.sh - Remove wrangler deploy job; update trunk linter config --- .github/workflows/check-linux.yml | 36 ++++++++++++++++--------- .github/workflows/check-macos.yml | 38 ++++++++++++++++++--------- .github/workflows/checksum.yml | 16 ++++++++--- .github/workflows/deploy-gh-pages.yml | 22 ++++++++++++++-- .github/workflows/rclone-action.yml | 9 +++++-- .github/workflows/win-install.yml | 25 ++++++++++++------ .trunk/trunk.yaml | 31 +++++++++++++++------- 7 files changed, 127 insertions(+), 50 deletions(-) diff --git a/.github/workflows/check-linux.yml b/.github/workflows/check-linux.yml index 3af9a27..705dfd7 100644 --- a/.github/workflows/check-linux.yml +++ b/.github/workflows/check-linux.yml @@ -5,24 +5,34 @@ on: branches: [main] paths: - "lib/sh/**" + - "lib/zsh/**" + - "tests/**" + - ".github/workflows/check-linux.yml" pull_request: branches: [main] paths: - "lib/sh/**" + - "lib/zsh/**" + - "tests/**" + - ".github/workflows/check-linux.yml" workflow_dispatch: +permissions: + contents: read + concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: shellcheck: runs-on: ubuntu-latest + timeout-minutes: 10 steps: - name: โคต๏ธ Check out code from GitHub - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: โ˜‘๏ธ ShellCheck - uses: ludeeus/action-shellcheck@00b27aa7cb85167568cb48a3838b75f4265f2bca + uses: ludeeus/action-shellcheck@00cae500b08a931fb5698e11e79bfbd38e612a38 # 2.0.0 with: scandir: "./lib/sh" @@ -32,24 +42,26 @@ jobs: needs: [shellcheck] steps: - name: โคต๏ธ Check out code from GitHub - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: โš™๏ธ Prepare dependencies run: | sudo apt-get update sudo apt-get install -y zsh + - name: "โš™๏ธ Check: unit fixtures" + run: sh ./tests/installers.sh - name: "โš™๏ธ Check: install.sh -- -i skip" - run: sh -x ./lib/sh/install.sh -- -i skip; command rm -rf ~/.zi - - name: "โš™๏ธ Check: install.sh -- -i annex" - run: sh -x ./lib/sh/install.sh -- -a annex; command rm -rf ~/.zi - - name: "โš™๏ธ Check: install.sh -- -i loader" - run: sh -x ./lib/sh/install.sh -- -a loader; command rm -rf ~/.zi - - name: "โš™๏ธ Check: install.sh -- -i zunit" - run: sh -x ./lib/sh/install.sh -- -a zunit; command rm -rf ~/.zi + run: sh -x ./lib/sh/install.sh -- -i skip; command rm -rf "${XDG_DATA_HOME:-$HOME/.local/share}/zi" ~/.zi + - name: "โš™๏ธ Check: install.sh -- -a annex" + run: sh -x ./lib/sh/install.sh -- -a annex; command rm -rf "${XDG_DATA_HOME:-$HOME/.local/share}/zi" ~/.zi + - name: "โš™๏ธ Check: install.sh -- -a loader" + run: sh -x ./lib/sh/install.sh -- -a loader; command rm -rf "${XDG_DATA_HOME:-$HOME/.local/share}/zi" ~/.zi + - name: "โš™๏ธ Check: install.sh -- -a zunit" + run: sh -x ./lib/sh/install.sh -- -a zunit; command rm -rf "${XDG_DATA_HOME:-$HOME/.local/share}/zi" ~/.zi - name: "โš™๏ธ Check: install_zpmod.sh" run: sh -x ./lib/sh/install_zpmod.sh - name: โš™๏ธ Load zpmod module run: | - module_path+=( "$HOME/.zi/zmodules/zpmod/Src" ) + module_path+=( "${XDG_DATA_HOME:-$HOME/.local/share}/zi/zmodules/zpmod/Src" ) zmodload zi/zpmod zpmod source-study -l shell: zsh {0} diff --git a/.github/workflows/check-macos.yml b/.github/workflows/check-macos.yml index 0acf6d1..1d1d8e0 100644 --- a/.github/workflows/check-macos.yml +++ b/.github/workflows/check-macos.yml @@ -6,50 +6,62 @@ on: branches: [main] paths: - "lib/sh/**" + - "lib/zsh/**" + - "tests/**" + - ".github/workflows/check-macos.yml" pull_request: branches: [main] paths: - "lib/sh/**" + - "lib/zsh/**" + - "tests/**" + - ".github/workflows/check-macos.yml" workflow_dispatch: +permissions: + contents: read + concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: shellcheck: runs-on: ubuntu-latest + timeout-minutes: 10 steps: - name: โคต๏ธ Check out code from GitHub - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: โ˜‘๏ธ ShellCheck - uses: ludeeus/action-shellcheck@00b27aa7cb85167568cb48a3838b75f4265f2bca + uses: ludeeus/action-shellcheck@00cae500b08a931fb5698e11e79bfbd38e612a38 # 2.0.0 with: scandir: "./lib/sh" build: - runs-on: ubuntu-latest + runs-on: macos-latest timeout-minutes: 30 needs: [shellcheck] steps: - name: โคต๏ธ Check out code from GitHub - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: โš™๏ธ Prepare dependencies run: | brew install zsh + - name: "โš™๏ธ Check: unit fixtures" + run: sh ./tests/installers.sh - name: "โš™๏ธ Check: install.sh -- -i skip" - run: sh -x ./lib/sh/install.sh -- -i skip; command rm -rf ~/.zi - - name: "โš™๏ธ Check: install.sh -- -i annex" - run: sh -x ./lib/sh/install.sh -- -a annex; command rm -rf ~/.zi - - name: "โš™๏ธ Check: install.sh -- -i loader" - run: sh -x ./lib/sh/install.sh -- -a loader; command rm -rf ~/.zi - - name: "โš™๏ธ Check: install.sh -- -i zunit" - run: sh -x ./lib/sh/install.sh -- -a zunit; command rm -rf ~/.zi + run: sh -x ./lib/sh/install.sh -- -i skip; command rm -rf "${XDG_DATA_HOME:-$HOME/.local/share}/zi" ~/.zi + - name: "โš™๏ธ Check: install.sh -- -a annex" + run: sh -x ./lib/sh/install.sh -- -a annex; command rm -rf "${XDG_DATA_HOME:-$HOME/.local/share}/zi" ~/.zi + - name: "โš™๏ธ Check: install.sh -- -a loader" + run: sh -x ./lib/sh/install.sh -- -a loader; command rm -rf "${XDG_DATA_HOME:-$HOME/.local/share}/zi" ~/.zi + - name: "โš™๏ธ Check: install.sh -- -a zunit" + run: sh -x ./lib/sh/install.sh -- -a zunit; command rm -rf "${XDG_DATA_HOME:-$HOME/.local/share}/zi" ~/.zi - name: "โš™๏ธ Check: install_zpmod.sh" run: sh -x ./lib/sh/install_zpmod.sh - name: โš™๏ธ Load zpmod module run: | - module_path+=( "$HOME/.zi/zmodules/zpmod/Src" ) + module_path+=( "${XDG_DATA_HOME:-$HOME/.local/share}/zi/zmodules/zpmod/Src" ) zmodload zi/zpmod zpmod source-study -l shell: zsh {0} diff --git a/.github/workflows/checksum.yml b/.github/workflows/checksum.yml index 66080e7..2a84471 100644 --- a/.github/workflows/checksum.yml +++ b/.github/workflows/checksum.yml @@ -3,20 +3,30 @@ name: "๐Ÿ†— Checksum" on: push: paths: - - "lib/**" + - "lib/sh/install_zpmod.sh" + - "lib/sh/install.sh" + - "lib/sh/sync-init.sh" + - "lib/zsh/init.zsh" + - ".github/workflows/checksum.yml" workflow_dispatch: {} +permissions: + contents: write + jobs: checksum: + if: github.repository == 'z-shell/zi-src' runs-on: ubuntu-latest + timeout-minutes: 10 steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: "๐Ÿ†— Generate checksum" - uses: jmgilman/actions-generate-checksum@521a903edf511407d8bd5535d257402fd9bb5db0 + uses: jmgilman/actions-generate-checksum@3ea6dc9bf8eecf28e2ecc982fab683484a1a8561 # v1.0.1 with: patterns: | lib/sh/install_zpmod.sh lib/sh/install.sh + lib/sh/sync-init.sh lib/zsh/init.zsh - run: mv checksum.txt lib/ - name: "๐Ÿ†— Commit" diff --git a/.github/workflows/deploy-gh-pages.yml b/.github/workflows/deploy-gh-pages.yml index 688a65f..83b21fd 100644 --- a/.github/workflows/deploy-gh-pages.yml +++ b/.github/workflows/deploy-gh-pages.yml @@ -8,17 +8,35 @@ on: tags: ["v*.*.*"] paths: - "lib/**" + - ".github/workflows/deploy-gh-pages.yml" + +permissions: + contents: write jobs: deploy: + if: github.repository == 'z-shell/zi-src' environment: name: github-pages runs-on: ubuntu-latest + timeout-minutes: 15 concurrency: group: ${{ github.workflow }}-${{ github.ref }} steps: - name: โคต๏ธ Check out code from GitHub - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - name: "๐Ÿท Prepare deployment metadata" + id: prepare_deploy + run: | + commit_message="$(jq -r '.head_commit.message // empty' "$GITHUB_EVENT_PATH")" + if [ -z "$commit_message" ]; then + commit_message="Deploy ${GITHUB_REF_NAME}" + fi + { + echo "commit_message<> "$GITHUB_OUTPUT" - name: "๐Ÿท Prepare tag" id: prepare_tag if: startsWith(github.ref, 'refs/tags/') @@ -34,6 +52,6 @@ jobs: publish_dir: ./lib user_name: ${{ secrets.ACTIONS_USER }} user_email: ${{ secrets.ACTIONS_MAIL }} - commit_message: ${{ github.event.head_commit.message }} + commit_message: ${{ steps.prepare_deploy.outputs.commit_message }} tag_name: ${{ steps.prepare_tag.outputs.deploy_tag_name }} tag_message: "Deployment ${{ steps.prepare_tag.outputs.tag_name }}" diff --git a/.github/workflows/rclone-action.yml b/.github/workflows/rclone-action.yml index e4f62b6..719d600 100644 --- a/.github/workflows/rclone-action.yml +++ b/.github/workflows/rclone-action.yml @@ -5,8 +5,12 @@ on: branches: [main] paths: - "lib/**" + - ".github/workflows/rclone-action.yml" workflow_dispatch: {} +permissions: + contents: read + concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true @@ -15,14 +19,15 @@ jobs: sync: if: github.repository == 'z-shell/zi-src' runs-on: ubuntu-latest + timeout-minutes: 15 env: local_path: "lib" remote_path: "r2:r2-store/src" steps: - name: "โคต๏ธ Check out code from GitHub" - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: "โซ Run rclone/r2-store" - uses: z-shell/.github/actions/rclone@v1 + uses: z-shell/.github/actions/rclone@91068ee88e8788deff439d6ee36b77329edeb98a # v1.0.8 with: config: ${{ secrets.R2_STORE }} args: "copy --check-first ${{ env.local_path }} ${{ env.remote_path }}" diff --git a/.github/workflows/win-install.yml b/.github/workflows/win-install.yml index c9c32f1..c1b5cc5 100644 --- a/.github/workflows/win-install.yml +++ b/.github/workflows/win-install.yml @@ -5,20 +5,28 @@ on: pull_request: paths: - "lib/sh/**" + - "lib/zsh/**" + - "tests/**" - ".github/workflows/win-install.yml" push: paths: - "lib/sh/**" + - "lib/zsh/**" + - "tests/**" - ".github/workflows/win-install.yml" workflow_dispatch: {} +permissions: + contents: read + jobs: shellcheck: runs-on: ubuntu-latest + timeout-minutes: 10 steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: โ˜‘๏ธ ShellCheck - uses: ludeeus/action-shellcheck@00b27aa7cb85167568cb48a3838b75f4265f2bca + uses: ludeeus/action-shellcheck@00cae500b08a931fb5698e11e79bfbd38e612a38 # 2.0.0 with: scandir: "./lib/sh" run-install: @@ -33,21 +41,22 @@ jobs: run: | git config --global core.autocrlf input git config --global --add safe.directory /cygdrive/d/a/zi-src/zi-src - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: ๐ŸชŸ Dependencies (Windows) - uses: egor-tensin/setup-cygwin@d2c752bab416d4b0662591bd366fc2686297c82d # v4 + uses: egor-tensin/setup-cygwin@d2c752bab416d4b0662591bd366fc2686297c82d # v4.0.1 with: platform: x64 packages: curl git zsh - name: ๐ŸชŸ Run Install run: | + sh ./tests/installers.sh sh -x ./lib/sh/install.sh -- -i skip - command rm -rf /home/runneradmin/.zi + command rm -rf "${XDG_DATA_HOME:-$HOME/.local/share}/zi" /home/runneradmin/.zi sh -x ./lib/sh/install.sh -- -a annex - command rm -rf /home/runneradmin/.zi + command rm -rf "${XDG_DATA_HOME:-$HOME/.local/share}/zi" /home/runneradmin/.zi sh -x ./lib/sh/install.sh -- -a loader - command rm -rf /home/runneradmin/.zi + command rm -rf "${XDG_DATA_HOME:-$HOME/.local/share}/zi" /home/runneradmin/.zi sh -x ./lib/sh/install.sh -- -a zunit - command rm -rf /home/runneradmin/.zi + command rm -rf "${XDG_DATA_HOME:-$HOME/.local/share}/zi" /home/runneradmin/.zi sh -x ./lib/sh/install.sh -- -a zpmod shell: C:\tools\cygwin\bin\bash.exe --login -o igncr '{0}' diff --git a/.trunk/trunk.yaml b/.trunk/trunk.yaml index edc1935..6bb320d 100644 --- a/.trunk/trunk.yaml +++ b/.trunk/trunk.yaml @@ -1,10 +1,10 @@ version: 0.1 cli: - version: 1.22.11 + version: 1.25.0 plugins: sources: - id: trunk - ref: v1.6.7 + ref: v1.10.0 uri: https://github.com/trunk-io/plugins repo: repo: @@ -12,6 +12,17 @@ repo: owner: z-shell name: zi-src lint: + definitions: + - name: shfmt + commands: + - name: format + output: shfmt + run: shfmt -w -s -ln=bash -i 2 ${target} + success_codes: [0, 1] + cache_results: true + formatter: true + batch: true + in_place: true disabled: - yamllint - trufflehog @@ -20,13 +31,13 @@ lint: - trivy enabled: - git-diff-check@SYSTEM - - actionlint@1.7.7 - - gitleaks@8.24.0 - - markdownlint@0.44.0 - - prettier@3.5.3 - - shellcheck@0.10.0 + - actionlint@1.7.12 + - gitleaks@8.30.1 + - markdownlint@0.48.0 + - prettier@3.8.3 + - shellcheck@0.11.0 - shfmt@3.6.0 - - taplo@0.9.3 + - taplo@0.10.0 actions: enabled: - trunk-announce @@ -36,6 +47,6 @@ actions: - trunk-cache-prune runtimes: enabled: - - python@3.10.8 + - python@3.14.4 - go@1.21.0 - - node@18.20.5 + - node@22.16.0 From a810dc8ff74c0543f4f3c8b097bec2a476f74306 Mon Sep 17 00:00:00 2001 From: Salvydas Lukosius Date: Fri, 15 May 2026 23:59:26 +0100 Subject: [PATCH 03/12] feat: add sync-init.sh and tests/installers.sh sync-init.sh verifies (and optionally replaces) the local lib/zsh/init.zsh against the canonical GitHub raw main copy. Supports --write, --local, --remote, --checksum-url and --no-checksum flags. tests/installers.sh provides a POSIX sh test suite covering: - script syntax validation (sh -n / zsh -n) - checksum integrity checks - loader install with XDG path and branch-override assertions - standalone zpmod delegation test - sync-init fixture round-trip test --- lib/sh/sync-init.sh | 252 ++++++++++++++++++++++++++++++++++++++++++++ tests/installers.sh | 251 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 503 insertions(+) create mode 100755 lib/sh/sync-init.sh create mode 100755 tests/installers.sh diff --git a/lib/sh/sync-init.sh b/lib/sh/sync-init.sh new file mode 100755 index 0000000..5cc30ac --- /dev/null +++ b/lib/sh/sync-init.sh @@ -0,0 +1,252 @@ +#!/usr/bin/env sh +# -*- mode: sh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*- +# vim: ft=sh sw=2 ts=2 et +# +# sync-init.sh โ€” verify and optionally sync local lib/zsh/init.zsh with remote. +# +# Usage: +# sh lib/sh/sync-init.sh [OPTIONS] +# +# Options: +# --write Replace local file with remote copy (requires valid checksum) +# --local PATH Local file to compare (default: lib/zsh/init.zsh) +# --remote URL|PATH Remote URL or local path (default: GitHub raw main) +# --checksum-url URL|PATH Checksum.txt URL or path (default: GitHub raw main) +# --no-checksum Skip checksum validation of remote content +# --help Print this help and exit +# +# Exit codes: +# 0 Files match (or --write sync succeeded) +# 1 Files differ, fetch error, or checksum mismatch +# 2 Usage error + +set -eu + +WORKDIR="$(mktemp -d)" || exit 1 +trap 'rm -rf "${WORKDIR:?}"' EXIT INT TERM + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +REPO_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)" + +DEFAULT_LOCAL="${REPO_ROOT}/lib/zsh/init.zsh" +DEFAULT_REMOTE="https://raw.githubusercontent.com/z-shell/zi-src/main/lib/zsh/init.zsh" +DEFAULT_CHECKSUM_URL="https://raw.githubusercontent.com/z-shell/zi-src/main/lib/checksum.txt" +CHECKSUM_KEY="lib/zsh/init.zsh" + +OPT_LOCAL="${DEFAULT_LOCAL}" +OPT_REMOTE="${DEFAULT_REMOTE}" +OPT_CHECKSUM_URL="${DEFAULT_CHECKSUM_URL}" +OPT_WRITE=0 +OPT_NO_CHECKSUM=0 + +# โ”€โ”€ Helpers โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + +print_help() { + cat </dev/null 2>&1; then + command curl -fsSL "${_src}" + elif command -v wget >/dev/null 2>&1; then + command wget -qO- "${_src}" + else + printf '%s\n' "[1;31mโ–“โ–’โ–‘[0m No curl or wget available." >&2 + return 1 + fi + ;; + *) + if [ -r "${_src}" ]; then + command cat "${_src}" + else + printf '%s\n' "[1;31mโ–“โ–’โ–‘[0m Cannot read local path: ${_src}" >&2 + return 1 + fi + ;; + esac +} + +# Compute SHA-256 hex digest of a file. +_sha256() { + _file="$1" + if command -v sha256sum >/dev/null 2>&1; then + sha256sum "${_file}" | command awk '{print $1}' + elif command -v shasum >/dev/null 2>&1; then + shasum -a 256 "${_file}" | command awk '{print $1}' + else + printf '%s\n' "[1;31mโ–“โ–’โ–‘[0m No sha256sum or shasum available." >&2 + return 1 + fi +} + +# โ”€โ”€ Argument Parsing โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + +while [ "$#" -gt 0 ]; do + case "$1" in + --write) + OPT_WRITE=1 + shift + ;; + --local) + [ "$#" -ge 2 ] || { + printf '%s\n' "Error: --local requires an argument." >&2 + exit 2 + } + OPT_LOCAL="$2" + shift 2 + ;; + --remote) + [ "$#" -ge 2 ] || { + printf '%s\n' "Error: --remote requires an argument." >&2 + exit 2 + } + OPT_REMOTE="$2" + shift 2 + ;; + --checksum-url) + [ "$#" -ge 2 ] || { + printf '%s\n' "Error: --checksum-url requires an argument." >&2 + exit 2 + } + OPT_CHECKSUM_URL="$2" + shift 2 + ;; + --no-checksum) + OPT_NO_CHECKSUM=1 + shift + ;; + --help | -h) + print_help + exit 0 + ;; + *) + printf '%s\n' "Error: unknown option: $1" >&2 + exit 2 + ;; + esac +done + +# โ”€โ”€ Validate Inputs โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + +if [ ! -f "${OPT_LOCAL}" ] && [ "${OPT_WRITE}" -eq 0 ]; then + printf '%s\n' "[1;31mโ–“โ–’โ–‘[0m Local file not found: ${OPT_LOCAL}" >&2 + printf '%s\n' "[1;33mโ–“โ–’โ–‘[0m Use --write to create it from remote." >&2 + exit 1 +fi + +# โ”€โ”€ Fetch Remote โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + +REMOTE_FILE="${WORKDIR}/remote-init.zsh" +printf '%s\n' "โ–“โ–’โ–‘ Fetching remote: ${OPT_REMOTE}" +# shellcheck disable=SC2310 +if ! _fetch "${OPT_REMOTE}" >"${REMOTE_FILE}"; then + printf '%s\n' "[1;31mโ–“โ–’โ–‘[0m Failed to fetch remote file." >&2 + exit 1 +fi + +# โ”€โ”€ Verify Remote Against Checksum โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + +if [ "${OPT_NO_CHECKSUM}" -eq 0 ]; then + CHECKSUM_FILE="${WORKDIR}/checksum.txt" + printf '%s\n' "โ–“โ–’โ–‘ Fetching checksum: ${OPT_CHECKSUM_URL}" + # shellcheck disable=SC2310 + if ! _fetch "${OPT_CHECKSUM_URL}" >"${CHECKSUM_FILE}"; then + printf '%s\n' "[1;31mโ–“โ–’โ–‘[0m Failed to fetch checksum file." >&2 + exit 1 + fi + + EXPECTED_HASH="$(grep "${CHECKSUM_KEY}" "${CHECKSUM_FILE}" | command awk '{print $1}')" + if [ -z "${EXPECTED_HASH}" ]; then + printf '%s\n' "[1;31mโ–“โ–’โ–‘[0m No checksum entry for '${CHECKSUM_KEY}' in checksum.txt." >&2 + exit 1 + fi + + REMOTE_HASH="$(_sha256 "${REMOTE_FILE}")" + if [ "${REMOTE_HASH}" != "${EXPECTED_HASH}" ]; then + printf '%s\n' "[1;31mโ–“โ–’โ–‘[0m Remote checksum mismatch!" >&2 + printf '%s\n' " expected : ${EXPECTED_HASH}" >&2 + printf '%s\n' " got : ${REMOTE_HASH}" >&2 + exit 1 + fi + printf '%s\n' "โ–“โ–’โ–‘ Remote checksum verified: ${REMOTE_HASH}" +else + REMOTE_HASH="$(_sha256 "${REMOTE_FILE}")" + printf '%s\n' "โ–“โ–’โ–‘ Remote hash (checksum validation skipped): ${REMOTE_HASH}" +fi + +# โ”€โ”€ Compare โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + +if [ -f "${OPT_LOCAL}" ]; then + LOCAL_HASH="$(_sha256 "${OPT_LOCAL}")" +else + LOCAL_HASH="(file not present)" +fi + +if [ "${LOCAL_HASH}" = "${REMOTE_HASH}" ]; then + printf '%s\n' "[1;32mโ–“โ–’โ–‘[0m Local file matches remote. No sync needed." + printf '%s\n' " hash : ${LOCAL_HASH}" + printf '%s\n' " path : ${OPT_LOCAL}" + exit 0 +fi + +printf '%s\n' "[1;33mโ–“โ–’โ–‘[0m Local and remote differ." +printf '%s\n' " local : ${LOCAL_HASH}" +printf '%s\n' " remote : ${REMOTE_HASH}" +printf '%s\n' " source : ${OPT_REMOTE}" + +if command -v diff >/dev/null 2>&1 && [ -f "${OPT_LOCAL}" ]; then + printf '\n%s\n' "--- diff (local vs remote) ---" + diff -u "${OPT_LOCAL}" "${REMOTE_FILE}" || true + printf '%s\n' "--- end diff ---" +fi + +# โ”€โ”€ Sync โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + +if [ "${OPT_WRITE}" -eq 0 ]; then + printf '\n%s\n' "โ–“โ–’โ–‘ Run with --write to replace the local file." + exit 1 +fi + +LOCAL_DIR="$(dirname "${OPT_LOCAL}")" +TMP_TARGET="${LOCAL_DIR}/.sync-init.zsh.tmp.$$" + +command cp "${REMOTE_FILE}" "${TMP_TARGET}" + +if [ -f "${OPT_LOCAL}" ]; then + ORIG_MODE="$(command stat -c '%a' "${OPT_LOCAL}" 2>/dev/null || + command stat -f '%A' "${OPT_LOCAL}" 2>/dev/null || + printf '755')" + command chmod "${ORIG_MODE}" "${TMP_TARGET}" +else + command chmod 755 "${TMP_TARGET}" +fi + +command mv "${TMP_TARGET}" "${OPT_LOCAL}" + +NEW_HASH="$(_sha256 "${OPT_LOCAL}")" +printf '%s\n' "[1;32mโ–“โ–’โ–‘[0m Sync complete." +printf '%s\n' " before : ${LOCAL_HASH}" +printf '%s\n' " after : ${NEW_HASH}" +printf '%s\n' " path : ${OPT_LOCAL}" diff --git a/tests/installers.sh b/tests/installers.sh new file mode 100755 index 0000000..5e58b13 --- /dev/null +++ b/tests/installers.sh @@ -0,0 +1,251 @@ +#!/usr/bin/env sh +# -*- mode: sh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*- +# vim: ft=sh sw=2 ts=2 et + +set -eu + +ROOT="$( + unset CDPATH + cd -- "$(dirname "$0")/.." && pwd +)" +TMP_ROOT="$(mktemp -d)" || exit 1 +trap 'rm -rf "${TMP_ROOT:?}"' EXIT INT TERM + +fail() { + printf '%s\n' "not ok - $*" >&2 + exit 1 +} + +pass() { + printf '%s\n' "ok - $*" +} + +contains() { + file="$1" + pattern="$2" + if ! grep -F "${pattern}" "${file}" >/dev/null 2>&1; then + printf '%s\n' "--- ${file} ---" >&2 + if [ -f "${file}" ]; then + sed -n '1,120p' "${file}" >&2 + else + printf '%s\n' "(missing)" >&2 + fi + printf '%s\n' "--- end ${file} ---" >&2 + fail "${file} does not contain: ${pattern}" + fi +} + +sha256_file() { + file="$1" + if command -v sha256sum >/dev/null 2>&1; then + sha256sum "${file}" | awk '{print $1}' + elif command -v shasum >/dev/null 2>&1; then + shasum -a 256 "${file}" | awk '{print $1}' + else + fail "sha256sum or shasum is required" + fi +} + +check_syntax() { + sh -n "${ROOT}/lib/sh/install.sh" + sh -n "${ROOT}/lib/sh/install_zpmod.sh" + sh -n "${ROOT}/lib/sh/sync-init.sh" + command -v zsh >/dev/null 2>&1 || fail "zsh is required for init.zsh syntax checks" + zsh -n "${ROOT}/lib/zsh/init.zsh" + pass "script syntax" +} + +check_checksums() { + while read -r expected path; do + [ -n "${expected}" ] || continue + actual="$(sha256_file "${ROOT}/${path}")" + [ "${actual}" = "${expected}" ] || fail "checksum mismatch for ${path}" + done <"${ROOT}/lib/checksum.txt" + pass "checksums" +} + +write_fake_tools() { + FAKE_BIN="${TMP_ROOT}/bin" + command mkdir -p "${FAKE_BIN}" + + cat >"${FAKE_BIN}/curl" <<'EOF' +#!/usr/bin/env sh +set -eu + +out="" +remote_name=0 +url="" + +while [ "$#" -gt 0 ]; do + case "$1" in + -o) + shift + out="${1:-}" + [ -n "${out}" ] || exit 64 + shift + ;; + -*O*) + remote_name=1 + shift + ;; + -*) + shift + ;; + *) + url="$1" + shift + ;; + esac +done + +[ -n "${url}" ] || { printf '%s\n' "curl test double: missing URL" >&2; exit 64; } +if [ -z "${out}" ] && [ "${remote_name}" -eq 1 ]; then + out="${url##*/}" +fi + +case "${url}" in + */lib/zsh/init.zsh) + if [ -n "${out}" ]; then + cp "${ZI_SRC_TEST_ROOT}/lib/zsh/init.zsh" "${out}" + else + cat "${ZI_SRC_TEST_ROOT}/lib/zsh/init.zsh" + fi + ;; + */git-process-output.zsh) + [ -n "${out}" ] || out="git-process-output.zsh" + cat > "${out}" <<'SCRIPT' +#!/usr/bin/env sh +cat +SCRIPT + chmod a+x "${out}" + ;; + */lib/sh/install_zpmod.sh) + [ -n "${out}" ] || { printf '%s\n' "curl test double: missing output path" >&2; exit 64; } + cat > "${out}" <<'SCRIPT' +#!/usr/bin/env sh +set -eu +printf '%s\n' "zpmod fallback executed" > "${ZI_SRC_TEST_MARKER:?}" +SCRIPT + chmod a+x "${out}" + ;; + *) + printf '%s\n' "curl test double: unexpected URL ${url}" >&2 + exit 65 + ;; +esac +EOF + + cat >"${FAKE_BIN}/git" <<'EOF' +#!/usr/bin/env sh +set -eu + +cmd="${1:-}" +[ "$#" -gt 0 ] && shift + +case "${cmd}" in + clone) + dest="" + for arg do + dest="${arg}" + done + [ -n "${dest}" ] || { printf '%s\n' "git test double: missing clone destination" >&2; exit 64; } + mkdir -p "${dest}/.git" "${dest}/lib" + printf '%s\n' '# fake zi.zsh' > "${dest}/zi.zsh" + printf '%s\n' '# fake _zi completion' > "${dest}/lib/_zi" + ;; + clean | reset | pull) + ;; + log) + printf '%s\n' 'abcdef0 - fake zi commit (now) ' + ;; + *) + printf '%s\n' "git test double: unexpected command ${cmd}" >&2 + exit 65 + ;; +esac +EOF + + command chmod a+x "${FAKE_BIN}/curl" "${FAKE_BIN}/git" +} + +test_loader_install() { + home="${TMP_ROOT}/loader-home" + config="${TMP_ROOT}/loader-config" + data="${TMP_ROOT}/loader-data" + command mkdir -p "${home}" "${config}" "${data}" + + HOME="${home}" \ + ZDOTDIR="${home}" \ + XDG_CONFIG_HOME="${config}" \ + XDG_DATA_HOME="${data}" \ + ZI_SRC_TEST_ROOT="${ROOT}" \ + PATH="${FAKE_BIN}:${PATH}" \ + sh "${ROOT}/lib/sh/install.sh" -a loader -b feature/test >/dev/null + + # shellcheck disable=SC2016 + contains "${config}/zi/init.zsh" ': ${ZI[STREAM]:="feature/test"}' + # shellcheck disable=SC2016 + contains "${home}/.zshrc" 'source "${XDG_CONFIG_HOME:-${HOME}/.config}/zi/init.zsh" && zzinit' + [ -f "${data}/zi/bin/zi.zsh" ] || fail "loader install did not clone Zi into XDG data home" + pass "loader install uses XDG paths and branch override" +} + +test_standalone_zpmod_delegation() { + standalone_dir="${TMP_ROOT}/standalone" + home="${TMP_ROOT}/zpmod-home" + data="${TMP_ROOT}/zpmod-data" + marker="${TMP_ROOT}/zpmod-marker" + command mkdir -p "${standalone_dir}" "${home}" "${data}" + command cp "${ROOT}/lib/sh/install.sh" "${standalone_dir}/install.sh" + + HOME="${home}" \ + ZDOTDIR="${home}" \ + XDG_DATA_HOME="${data}" \ + ZI_SRC_TEST_ROOT="${ROOT}" \ + ZI_SRC_TEST_MARKER="${marker}" \ + PATH="${FAKE_BIN}:${PATH}" \ + sh "${standalone_dir}/install.sh" -a zpmod -i skip >/dev/null + + contains "${marker}" 'zpmod fallback executed' + pass "standalone install.sh fetches zpmod helper" +} + +test_sync_init() { + local_file="${TMP_ROOT}/local-init.zsh" + remote_file="${TMP_ROOT}/remote-init.zsh" + checksum_file="${TMP_ROOT}/checksum.txt" + + printf '%s\n' '# remote init fixture' >"${remote_file}" + command cp "${remote_file}" "${local_file}" + remote_hash="$(sha256_file "${remote_file}")" + printf '%s %s\n' "${remote_hash}" 'lib/zsh/init.zsh' >"${checksum_file}" + + sh "${ROOT}/lib/sh/sync-init.sh" \ + --local "${local_file}" \ + --remote "${remote_file}" \ + --checksum-url "${checksum_file}" >/dev/null + + printf '%s\n' '# stale init fixture' >"${local_file}" + if sh "${ROOT}/lib/sh/sync-init.sh" \ + --local "${local_file}" \ + --remote "${remote_file}" \ + --checksum-url "${checksum_file}" >/dev/null 2>&1; then + fail "sync-init mismatch check unexpectedly succeeded" + fi + + sh "${ROOT}/lib/sh/sync-init.sh" \ + --write \ + --local "${local_file}" \ + --remote "${remote_file}" \ + --checksum-url "${checksum_file}" >/dev/null + + cmp -s "${local_file}" "${remote_file}" || fail "sync-init --write did not replace local file" + pass "sync-init fixtures" +} + +check_syntax +check_checksums +write_fake_tools +test_loader_install +test_standalone_zpmod_delegation +test_sync_init From bf6a68a0c7e06fadc0e7f259113ca28a3ac8c370 Mon Sep 17 00:00:00 2001 From: Salvydas Lukosius Date: Fri, 15 May 2026 23:59:39 +0100 Subject: [PATCH 04/12] refactor: migrate installer scripts to XDG paths and harden POSIX install.sh: - Add set -eu; use WORKDIR=$(mktemp -d) with safe trap cleanup - Replace ~/.zi with XDG_DATA_HOME-aware path - Fix sed command for ZI[STREAM] substitution - Correct cd fallback from return to exit 1 - Guard branch pull with BOPT; add exit 1 on failed clone - Fix .zshrc loader snippet variable quoting install_zpmod.sh: - Add set -eu, file header and WORKDIR trap - Add pure-POSIX _zi_ver_ge() replacing expr string comparison - Honour XDG_DATA_HOME for ZI_HOME default - Replace exit 255 with exit 1 throughout lib/zsh/init.zsh: - Update default branch to use ZI[STREAM] parameter - Align loader paths with XDG layout --- lib/sh/install.sh | 140 +++++++++++-------------------- lib/sh/install_zpmod.sh | 68 +++++++++------ lib/zsh/init.zsh | 178 +++++++++++++++++++++++++--------------- 3 files changed, 204 insertions(+), 182 deletions(-) diff --git a/lib/sh/install.sh b/lib/sh/install.sh index 0f7bbbc..57959c7 100755 --- a/lib/sh/install.sh +++ b/lib/sh/install.sh @@ -2,8 +2,10 @@ # -*- mode: sh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*- # vim: ft=sh sw=2 ts=2 et -trap 'rm -rf "$WORKDIR"' EXIT INT -WORKDIR="$(mktemp -d)" +set -eu + +WORKDIR="$(mktemp -d)" || exit 1 +trap 'rm -rf "${WORKDIR:?}"' EXIT INT TERM ZOPT="" AOPT="" BOPT="main" @@ -43,21 +45,21 @@ if [ "${AOPT}" = loader ]; then command wget -qO "${ZI_CONFIG_DIR}/init.zsh" https://raw.githubusercontent.com/z-shell/zi-src/main/lib/zsh/init.zsh fi command chmod go-w "${ZI_CONFIG_DIR}" && command chmod a+x "${ZI_CONFIG_DIR}/init.zsh" - command sed -i "s/branch=\"main\"/branch=\"${BOPT}\"/g" "${ZI_CONFIG_DIR}/init.zsh" + # shellcheck disable=SC2016 + command sed -i 's|: ${ZI\[STREAM\]:="main"}|: ${ZI[STREAM]:="'"${BOPT}"'"}|' "${ZI_CONFIG_DIR}/init.zsh" fi -if [ -z "${ZI_HOME}" ]; then - ZI_HOME="${ZDOTDIR:-${HOME}}/.zi" +if [ -z "${ZI_HOME-}" ]; then + ZI_HOME="${XDG_DATA_HOME:-${HOME}/.local/share}/zi" fi -if [ -z "${ZI_BIN_DIR_NAME}" ]; then +if [ -z "${ZI_BIN_DIR_NAME-}" ]; then ZI_BIN_DIR_NAME="bin" fi if ! test -d "${ZI_HOME}"; then command mkdir "${ZI_HOME}" command chmod go-w "${ZI_HOME}" - command chmod go-w "${ZI_HOME}/${ZI_BIN_DIR_NAME}" fi if ! command -v git >/dev/null 2>&1; then @@ -68,31 +70,32 @@ fi # Get the download-progress bar tool if command -v curl >/dev/null 2>&1; then command mkdir -p /tmp/zi - cd /tmp/zi || return + cd /tmp/zi || exit 1 command curl -fsSLO https://raw.githubusercontent.com/z-shell/zi/main/lib/zsh/git-process-output.zsh && command chmod a+x /tmp/zi/git-process-output.zsh elif command -v wget >/dev/null 2>&1; then command mkdir -p /tmp/zi - cd /tmp/zi || return + cd /tmp/zi || exit 1 command wget -q https://raw.githubusercontent.com/z-shell/zi/main/lib/zsh/git-process-output.zsh && command chmod a+x /tmp/zi/git-process-output.zsh fi if test -d "${ZI_HOME}/${ZI_BIN_DIR_NAME}/.git"; then - cd "${ZI_HOME}/${ZI_BIN_DIR_NAME}" || return + cd "${ZI_HOME}/${ZI_BIN_DIR_NAME}" || exit 1 printf '%s\n' "โ–“โ–’โ–‘ Updating (z-shell/zi) plugin manager at ${ZI_HOME}/${ZI_BIN_DIR_NAME}" command git clean -d -f -f command git reset --hard HEAD - command git pull -q origin HEAD + command git pull -q origin "${BOPT}" else - cd "${ZI_HOME}" || return + cd "${ZI_HOME}" || exit 1 printf '%s\n' "โ–“โ–’โ–‘ Installing (z-shell/zi) plugin manager at ${ZI_HOME}/${ZI_BIN_DIR_NAME}" { git clone --progress --depth=1 --branch "${BOPT}" https://github.com/z-shell/zi.git "${ZI_BIN_DIR_NAME}" \ 2>&1 | { /tmp/zi/git-process-output.zsh || cat; }; } 2>/dev/null - if [ -d "${ZI_BIN_DIR_NAME}" ]; then + if [ -d "${ZI_HOME}/${ZI_BIN_DIR_NAME}" ]; then printf '%s\n' "โ–“โ–’โ–‘ Successfully installed at ${ZI_HOME}/${ZI_BIN_DIR_NAME}". else printf '%s\n' "โ–“โ–’โ–‘ Something went wrong, couldn't install ZI at ${ZI_HOME}/${ZI_BIN_DIR_NAME}" + exit 1 fi fi @@ -106,7 +109,7 @@ MAIN_PROFILE() { printf '%s\n' "โ–“โ–’โ–‘ Seems that .zshrc already has content or setup skipped - no changes will be made." ZOPT='skip' fi - if [ "${ZOPT}" != skip ]; then + if [ "${ZOPT}" != skip ] && [ "${AOPT}" != loader ]; then printf '%s\n' "โ–“โ–’โ–‘ Updating ${THE_ZDOTDIR}/.zshrc" ZI_HOME="$(echo "${ZI_HOME}" | sed "s|${HOME}|\$HOME|")" command cat <<-EOF >>"${THE_ZDOTDIR}/.zshrc" @@ -126,10 +129,9 @@ EOF printf '%s\n' "โ–“โ–’โ–‘ Minimal configuration" fi if [ "${AOPT}" = loader ] && [ "${ZOPT}" != skip ]; then - command rm -rf "${THE_ZDOTDIR}/.zshrc" command cat <<-EOF >>"${THE_ZDOTDIR}/.zshrc" -if [[ -r "${XDG_CONFIG_HOME:-${HOME}/.config}/zi/init.zsh" ]]; then - source "${XDG_CONFIG_HOME:-${HOME}/.config}/zi/init.zsh" && zzinit +if [[ -r "\${XDG_CONFIG_HOME:-\${HOME}/.config}/zi/init.zsh" ]]; then + source "\${XDG_CONFIG_HOME:-\${HOME}/.config}/zi/init.zsh" && zzinit fi EOF printf '%s\n' "โ–“โ–’โ–‘ Loader added" @@ -164,86 +166,38 @@ EOF fi } -SETUP_ZPMOD() { - if ! test -d "${ZI_HOME}/${MOD_HOME}"; then - command mkdir -p "${ZI_HOME}/${MOD_HOME}" - command chmod go-w "${ZI_HOME}/${MOD_HOME}" - fi +ZPMOD_PROFILE() { + _zpmod_sh="" + case "$0" in + */*) + _script_dir="$(cd "$(dirname "$0")" 2>/dev/null && pwd)" || _script_dir="" + ;; + *) + _script_dir="" + ;; + esac - printf '%s\n' "${col_pname}== Downloading ZPMOD module to ${ZI_HOME}/${MOD_HOME}" - if test -d "${ZI_HOME}/${MOD_HOME}/.git"; then - cd "${ZI_HOME}/${MOD_HOME}" || return - git pull -q origin main + if [ -n "${_script_dir}" ] && [ -f "${_script_dir}/install_zpmod.sh" ]; then + _zpmod_sh="${_script_dir}/install_zpmod.sh" else - cd "${ZI_HOME}" || return - git clone -q https://github.com/z-shell/zpmod.git "${MOD_HOME}" - fi - printf '%s\n' "${col_pname}== Done" -} - -BUILD_ZPMOD() { - if command -v zsh >/dev/null; then - printf '%s\n' "${col_info2}-- Checkig version --${col_rst}" - ZSH_CURRENT=$(zsh --version /dev/null; then - printf '%s\n' "${col_error}-- Zsh version 5.8.1 and above required --${col_rst}" - exit 1 + _zpmod_sh="${WORKDIR}/install_zpmod.sh" + _zpmod_url="https://raw.githubusercontent.com/z-shell/zi-src/main/lib/sh/install_zpmod.sh" + if command -v curl >/dev/null 2>&1; then + command curl -fsSL "${_zpmod_url}" -o "${_zpmod_sh}" + elif command -v wget >/dev/null 2>&1; then + command wget -qO "${_zpmod_sh}" "${_zpmod_url}" else - printf '%s\n' "${col_info2}-- Zsh version ${ZSH_CURRENT} --${col_rst}" - cd "${ZI_HOME}/${MOD_HOME}" || return - printf '%s\n' "${col_pname}== Building module ZPMOD, running: a make clean, then ./configure and then make ==${col_rst}" - printf '%s\n' "${col_pname}== The module sources are located at: ${ZI_HOME}/${MOD_HOME} ==${col_rst}" - if test -f Makefile; then - if [ "$1" = "--clean" ]; then - printf '%s\n' "${col_info2}-- make distclean --${col_rst}" - make -s distclean - true - else - printf '%s\n' "${col_info2}-- make clean (pass --clean to invoke \`make distclean') --${col_rst}" - make -s clean - fi - fi - printf '%s\n' "${col_info2}-- Configuring --${col_rst}" - if CPPFLAGS=-I/usr/local/include CFLAGS="-g -Wall -O3" LDFLAGS=-L/usr/local/lib ./configure --disable-gdbm --without-tcsetpgrp; then - printf '%s\n' "${col_info2}-- Running make --${col_rst}" - if make -s; then - command cat <<-EOF -โ–“โ–’โ–‘ Module has been built correctly. -โ–“โ–’โ–‘ To load the module, add following 2 lines to .zshrc, at top: -  module_path+=( "${ZI_HOME}/${MOD_HOME}/Src" ) -  zmodload zi/zpmod -โ–“โ–’โ–‘ See 'zpmod -h' for more information. -โ–“โ–’โ–‘ Run 'zpmod source-study' to see profile data, -โ–“โ–’โ–‘ Guaranteed, automatic compilation of any sourced script. -EOF - else - printf '%s\n' "${col_error}Module didn't build.${col_rst}. You can copy the error messages and submit" - printf '%s\n' "error-report at: https://github.com/z-shell/zpmod/issues" - fi - fi + printf '%s\n' "-- ERROR -- curl or wget is required to download install_zpmod.sh" >&2 + exit 1 fi - else - printf '%s\n' "${col_error} Zsh is not installed. Please install zsh and try again.${col_rst}" + if [ ! -s "${_zpmod_sh}" ]; then + printf '%s\n' "-- ERROR -- failed to download install_zpmod.sh" >&2 + exit 1 + fi + command chmod a+x "${_zpmod_sh}" fi -} -ZPMOD_PROFILE() { - col_pname="" - col_error="" - col_info="" - col_info2="" - col_rst="" - - ZI_HOME="${ZI_HOME:-${ZDOTDIR:-${HOME}}/.zi}" - MOD_HOME="${MOD_HOME:-zmodules}/zpmod" - - printf '%s\n' "${col_info}Re-run this script to update (from Github) and rebuild the module.${col_rst}" - printf '%s\n' "${col_info2}Press any key to continue, or Ctrl-C to exit.${col_rst}" - read -r - - SETUP_ZPMOD - BUILD_ZPMOD "$@" + exec sh "${_zpmod_sh}" "$@" } CLOSE_PROFILE() { @@ -273,6 +227,4 @@ EOF exit 0 } -while true; do - MAIN "${@}" -done +MAIN "${@}" diff --git a/lib/sh/install_zpmod.sh b/lib/sh/install_zpmod.sh index d694f88..c49b99c 100755 --- a/lib/sh/install_zpmod.sh +++ b/lib/sh/install_zpmod.sh @@ -1,34 +1,56 @@ #!/usr/bin/env sh +# -*- mode: sh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*- +# vim: ft=sh sw=2 ts=2 et + +set -eu + +WORKDIR="$(mktemp -d)" || exit 1 +trap 'rm -rf "${WORKDIR:?}"' EXIT INT TERM + +# Returns 0 if version $1 >= version $2 (dot-separated integers) +_zi_ver_ge() { + _vga="$1" _vgb="$2" + while [ -n "${_vga}${_vgb}" ]; do + _af="${_vga%%.*}" _bf="${_vgb%%.*}" + case "${_vga}" in *.*) _vga="${_vga#*.}" ;; *) _vga="" ;; esac + case "${_vgb}" in *.*) _vgb="${_vgb#*.}" ;; *) _vgb="" ;; esac + _af="${_af:-0}" _bf="${_bf:-0}" + if [ "${_af}" -gt "${_bf}" ]; then return 0; fi + if [ "${_af}" -lt "${_bf}" ]; then return 1; fi + done + return 0 +} setup_environment() { - if [ -z "${ZI_HOME}" ]; then - if [ -d "${HOME}"/.zi ]; then + if [ -z "${ZI_HOME-}" ]; then + _xdg_zi="${XDG_DATA_HOME:-${HOME}/.local/share}/zi" + if [ -d "${_xdg_zi}" ]; then + ZI_HOME="${_xdg_zi}" + elif [ -d "${HOME}/.zi" ]; then ZI_HOME="${HOME}/.zi" - elif [ -d "${ZDOTDIR}"/.zi ]; then + elif [ -n "${ZDOTDIR-}" ] && [ -d "${ZDOTDIR}/.zi" ]; then ZI_HOME="${ZDOTDIR}/.zi" - elif [ -d "${XDG_DATA_HOME}"/.zi ]; then - ZI_HOME="${XDG_DATA_HOME}/.zi" else - ZI_HOME="${HOME}/.zi" + ZI_HOME="${_xdg_zi}" fi fi - if [ -z "${MOD_HOME}" ]; then + if [ -z "${MOD_HOME-}" ]; then MOD_HOME="${ZI_HOME}/zmodules/zpmod" fi if ! test -d "${MOD_HOME}"; then mkdir -p "${MOD_HOME}" - chmod g-rwX "${MOD_HOME}" + chmod go-w "${MOD_HOME}" fi if [ ! -d "${MOD_HOME}" ]; then printf '%s\n' "${col_error}== Error: Failed to setup module directory ==${col_rst}" - exit 255 + exit 1 fi } setup_zpmod_repository() { printf '%s\n' "${col_pname}== Downloading ZPMOD module to ${MOD_HOME}" if test -d "${MOD_HOME}/.git"; then - cd "${MOD_HOME}" || exit 255 + cd "${MOD_HOME}" || exit 1 git pull -q origin main else git clone --depth 10 -q https://github.com/z-shell/zpmod.git "${MOD_HOME}" @@ -39,18 +61,19 @@ build_zpmod_module() { if command -v zsh >/dev/null; then printf '%s\n' "${col_info2}-- Checking version --${col_rst}" ZSH_CURRENT=$(zsh --version /dev/null; then - printf '%s\n' "${col_error}-- Zsh version 5.8.1 and above required --${col_rst}" + ZSH_REQUIRED="5.8.1" + # shellcheck disable=SC2310 + if ! _zi_ver_ge "${ZSH_CURRENT}" "${ZSH_REQUIRED}"; then + printf '%s\n' "${col_error}-- Zsh version ${ZSH_REQUIRED} and above required --${col_rst}" exit 1 else ( printf '%s\n' "${col_info2}-- Zsh version ${ZSH_CURRENT} --${col_rst}" - cd "${MOD_HOME}" || exit 255 + cd "${MOD_HOME}" || exit 1 printf '%s\n' "${col_pname}== Building module ZPMOD, running: a make clean, then ./configure and then make ==${col_rst}" printf '%s\n' "${col_pname}== The module sources are located at: ${MOD_HOME} ==${col_rst}" if test -f Makefile; then - if [ "$1" = "--clean" ]; then + if [ "${1-}" = "--clean" ]; then printf '%s\n' "${col_info2}-- make distclean --${col_rst}" make distclean true @@ -62,9 +85,10 @@ build_zpmod_module() { INSTALL_PATH="/usr/local" export PATH="${INSTALL_PATH}"/bin:"${PATH}" - export LD_LIBRARY_PATH="${INSTALL_PATH}"/lib:"${LD_LIBRARY_PATH}" - export CFLAGS=-I"${INSTALL_PATH}"/include - export CPPFLAGS="-I${INSTALL_PATH}/include" LDFLAGS="-L${INSTALL_PATH}/lib" + export LD_LIBRARY_PATH="${INSTALL_PATH}/lib:${LD_LIBRARY_PATH-}" + export CFLAGS="-I${INSTALL_PATH}/include" + export CPPFLAGS="-I${INSTALL_PATH}/include" + export LDFLAGS="-L${INSTALL_PATH}/lib" CFLAGS="-g -Wall -O3" ./configure --disable-gdbm --without-tcsetpgrp --quiet printf '%s\n' "${col_info2}-- Running make --${col_rst}" @@ -84,13 +108,13 @@ EOF else printf '%s\n' "${col_error}Module didn't build.${col_rst}. You can copy the error messages and submit" printf '%s\n' "error-report at: https://github.com/z-shell/zpmod/issues" - exit 255 + exit 1 fi ) fi else printf '%s\n' "${col_error} Zsh is not installed. Please install zsh and try again.${col_rst}" - exit 255 + exit 1 fi } @@ -106,6 +130,4 @@ MAIN() { exit 0 } -while true; do - MAIN "${@}" -done +MAIN "${@}" diff --git a/lib/zsh/init.zsh b/lib/zsh/init.zsh index 49b86a6..01add00 100755 --- a/lib/zsh/init.zsh +++ b/lib/zsh/init.zsh @@ -1,88 +1,136 @@ #!/usr/bin/env zsh -# ZI Loader (Values set: default) +# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*- +# vim: ft=zsh sw=2 ts=2 et # -# https://z.digitalclouds.dev/community/zsh_plugin_standard -0="${ZERO:-${${0:#$ZSH_ARGZERO}:-${(%):-%N}}}" -0="${${(M)0:#/*}:-$PWD/$0}" - -# https://z.digitalclouds.dev/docs/guides/customization -local repo="https://github.com/z-shell/zi.git" -local branch="main" -local verbose_mode="${verbose_mode:-false}" -typeset -A ZI -# Where ZI should create all working directories, e.g.: "~/.zi" -ZI[HOME_DIR]="${ZI[HOME_DIR]:-${HOME}/.zi}" -# Where ZI code resides, e.g.: "~/.zi/bin" -ZI[BIN_DIR]="$ZI[HOME_DIR]/bin" -# Zsh modules directory -ZI[ZMODULES_DIR]="$ZI[HOME_DIR]/zmodules" -# Where ZI cache is, e.g.: "~/.cache/zi" -ZI[CACHE_DIR]="${ZI[CACHE_DIR]:-$HOME/.cache/zi}" -# Path to .zcompdump file, with the file included (i.e. its name can be different) -ZI[ZCOMPDUMP_PATH]="$ZI[CACHE_DIR]/.zcompdump" -# If set to 1, then mutes some of the ZI warnings, specifically the plugin already registered warning -ZI[MUTE_WARNINGS]="${ZI[MUTE_WARNINGS]:-0}" - -# Clone ZI repository if it doesn't exist -zzsetup() { - [[ $verbose_mode == true ]] && builtin print "(ZI): Checking if ZI (zi.zsh) is available." +# Zi Loader โ€” bootstrap and source the Zi plugin manager. +# +# Sourced early in .zshrc. Defines zzinit() which clones Zi on first run, +# sources zi.zsh, registers completions, and loads zpmod if built. +# All helper functions are cleaned up after zzinit() returns. + +# โ”€โ”€ Zi Configuration โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + +typeset -ghA ZI + +# https://wiki.zshell.dev/docs/guides/customization +: ${ZI[REPOSITORY]:="https://github.com/z-shell/zi.git"} +: ${ZI[STREAM]:="main"} +: ${ZI[HOME_DIR]:="${XDG_DATA_HOME:-$HOME/.local/share}/zi"} +: ${ZI[BIN_DIR]:="${ZI[HOME_DIR]}/bin"} +: ${ZI[CACHE_DIR]:="${XDG_CACHE_HOME:-$HOME/.cache}/zi"} +: ${ZI[CONFIG_DIR]:="${XDG_CONFIG_HOME:-$HOME/.config}/zi"} + +# https://wiki.zshell.dev/community/zsh_plugin_standard#global-parameter-with-prefix +: ${ZPFX:=${ZI[HOME_DIR]}/polaris} +: ${ZI[ZMODULES_DIR]:=${ZI[HOME_DIR]}/zmodules} +: ${ZI[ZCOMPDUMP_PATH]:=${ZI[CACHE_DIR]}/.zcompdump} +: ${ZI[MUTE_WARNINGS]:=0} + +# History defaults +: ${HISTFILE:=${XDG_STATE_HOME:-$HOME/.local/state}/zsh/history} +[[ -e "$HISTFILE" ]] || { command mkdir -p "${HISTFILE:h}"; command touch "$HISTFILE"; } +[[ -w "$HISTFILE" ]] && typeset -gx SAVEHIST=440000 HISTSIZE=441000 + +# โ”€โ”€ Bootstrap Helpers โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + +# Fetch content from a URL to stdout. +_zi_fetch() { + builtin emulate -L zsh + if (( $+commands[curl] )); then + command curl -fsSL "$1" + elif (( $+commands[wget] )); then + command wget -qO- "$1" + else + return 255 + fi +} + +# Clone Zi repository if it doesn't exist. +_zi_setup() { + builtin emulate -L zsh + builtin autoload colors; colors + local -a git_refs + local tmp_dir show_process process_url + if [[ ! -f "${ZI[BIN_DIR]}/zi.zsh" ]]; then - [[ $verbose_mode == true ]] && builtin print "(ZI): ZI (zi.zsh) is not found. Installing..." - builtin print -P "%F{33}โ–“โ–’โ–‘ %F{160}Installing interactive feature-rich plugin manager (%F{33}z-shell/zi%F{160})%f%b" - command mkdir -p "${ZI[BIN_DIR]}" && command chmod -R go-w "${ZI[HOME_DIR]}" - command git clone -q --progress --branch "$branch" "$repo" "${ZI[BIN_DIR]}" + tmp_dir="${TMPDIR:-/tmp}/zi" + [[ -d "$tmp_dir" ]] || command mkdir -p "$tmp_dir" + + show_process="${tmp_dir}/git-process.zsh" + process_url="https://raw.githubusercontent.com/z-shell/zi/main/lib/zsh/git-process-output.zsh" + + if [[ ! -f "$show_process" ]]; then + if _zi_fetch "$process_url" > "${tmp_dir}/git-process.zsh"; then + command chmod a+x "${tmp_dir}/git-process.zsh" + else + return 1 + fi + fi + + (( $+commands[clear] )) && command clear + builtin print -P "%F{33}โ–“โ–’โ–‘ %F{160}Installing interactive & feature-rich plugin manager (%F{33}z-shell/zi%F{160})%f%bโ€ฆ\n" + command mkdir -p "${ZI[BIN_DIR]}" && \ + command git clone --verbose --progress --branch \ + "${ZI[STREAM]}" "${ZI[REPOSITORY]}" "${ZI[BIN_DIR]}" \ + |& { command "$show_process" || command cat; } + if [[ -f "${ZI[BIN_DIR]}/zi.zsh" ]]; then - [[ $verbose_mode == true ]] && builtin print "(ZI): Installed and ZI (zi.zsh) is found" - local git_refs=("$(cd "${ZI[BIN_DIR]}"; command git log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit | head -10)") - print -P "%F{33}โ–“โ–’โ–‘ %F{34}Successfully installed %F{160}(%F{33}z-shell/zi%F{160})%f%b" - print -P "%F{33}โ–“โ–’โ–‘ %F{226}Last changes:%f%b" - print -P "%F{33}โ–“โ–’โ–‘ %F{160}%F{33}\n${git_refs}%F{160}%f%b" + command chmod -R go-w "${ZI[HOME_DIR]}" + git_refs=("${(f@)$(builtin cd -q "${ZI[BIN_DIR]}" && command git log --color --graph --abbrev-commit \ + --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' | command head -5)}") + builtin print + builtin print -P "%F{33}โ–“โ–’โ–‘ %F{34}Successfully installed %F{160}(%F{33}z-shell/zi%F{160})%f%b\n" + builtin print -rl -- "${git_refs[@]}" else - print -P "%F{160}โ–“โ–’โ–‘ The clone has failedโ€ฆ%f%b" - print -P "%F{160}โ–“โ–’โ–‘ %F{33} Please report the issue:%f%b" - print -P "%F{160}โ–“โ–’โ–‘ %F{33} https://github.com/z-shell/zi/issues/new%f%b" + builtin print -P "%F{160}โ–“โ–’โ–‘ The clone has failedโ€ฆ%f%b" + builtin print -P "%F{160}โ–“โ–’โ–‘ %F{33} Please report the issue: %F{226}https://github.com/z-shell/zi/issues/new%f%b" return 1 fi - return 0 fi + return 0 } -# If setup is successful or ZI is already installed, then load ZI. Otherwise, not continue and exit. -zzsource() { - [[ $verbose_mode == true ]] && builtin print "(ZI): If (zzsetup) function status code 0, then load ZI." - if zzsetup; then - [[ $verbose_mode == true ]] && builtin print "(ZI): Loading (zi.zsh)" - source "${ZI[BIN_DIR]}/zi.zsh" +# Source zi.zsh, bootstrapping first if needed. +_zi_source() { + builtin emulate -L zsh + if [[ -f "${ZI[BIN_DIR]}/zi.zsh" ]]; then + builtin source "${ZI[BIN_DIR]}/zi.zsh" else - [[ $verbose_mode == true ]] && builtin print "(ZI): (zzsetup) function status code 1, not continue and exit." - exit 1 + _zi_setup || return 1 + # Guard: if setup succeeded but zi.zsh is still missing, don't recurse + if [[ -f "${ZI[BIN_DIR]}/zi.zsh" ]]; then + builtin source "${ZI[BIN_DIR]}/zi.zsh" + else + return 1 + fi fi } -# Load zi module if built -zzpmod() { - [[ $verbose_mode == true ]] && builtin print "(ZI): Checking for ZI module." +# Load zpmod module if built. +_zi_pmod() { + builtin emulate -L zsh if [[ -f "${ZI[ZMODULES_DIR]}/zpmod/Src/zi/zpmod.so" ]]; then - [[ $verbose_mode == true ]] && builtin print "(ZI): Loading ZI module." module_path+=( "${ZI[ZMODULES_DIR]}/zpmod/Src" ) - zmodload zi/zpmod &>/dev/null - ZI[ZPMOD_ENABLED]=1 + zmodload zi/zpmod 2>/dev/null fi + return 0 } -# Enable completion (completions should be loaded after zzsource) -zzcomps() { - [[ $verbose_mode == true ]] && builtin print "(ZI): Loading completionโ€ฆ (_zi)" - autoload -Uz _zi - (( ${+_comps} )) && _comps[zi]=_zi - ZI[COMPS_ENABLED]=1 +# Register Zi completion if the completion system is active. +_zi_comps() { + builtin emulate -L zsh + if (( ${+_comps} )) && [[ -f "${ZI[BIN_DIR]}/lib/_zi" ]]; then + (( ${+_comps[zi]} )) || _comps[zi]="${ZI[BIN_DIR]}/lib/_zi" + fi + return 0 } -# If ZI is installed, load ZI, enable completion and load zpmod. +# โ”€โ”€ Entry Point โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + zzinit() { - (( ZI[SOURCED] )) && return - [[ $verbose_mode == true ]] && builtin print "(ZI): Loading ZI (zi.zsh)" - zzsource - zzcomps - zzpmod + { + _zi_source && _zi_comps && _zi_pmod + } always { + unset -f _zi_fetch _zi_setup _zi_source _zi_comps _zi_pmod zzinit 2>/dev/null + } } From e470ca3516f9180c8e3bdf0d85e6b4eea1e1e26d Mon Sep 17 00:00:00 2001 From: Salvydas Lukosius Date: Fri, 15 May 2026 23:59:48 +0100 Subject: [PATCH 05/12] chore: update gitignore, checksums, and docs - Exclude AI agent instruction files from git tracking (AGENTS.md, CLAUDE.md, GEMINI.md, .github/copilot-instructions.md) - Add .geminiignore - Regenerate lib/checksum.txt to reflect updated scripts - Document sync-init.sh usage in docs/README.md - Remove deprecated git.io short URLs from README --- .geminiignore | 0 docs/README.md | 31 +++++++++++++++++++++++++++++-- lib/checksum.txt | 7 ++++--- 3 files changed, 33 insertions(+), 5 deletions(-) create mode 100644 .geminiignore diff --git a/.geminiignore b/.geminiignore new file mode 100644 index 0000000..e69de29 diff --git a/docs/README.md b/docs/README.md index cd6b128..c45d77d 100644 --- a/docs/README.md +++ b/docs/README.md @@ -31,13 +31,40 @@ - https://wiki.zshell.dev - Loader: - https://init.zshell.dev - - https://git.io/zi-loader - Installer: - https://get.zshell.dev - - https://git.io/get-zi - R2: - https://r2.zshell.dev - IPFS: - https://ipfs.zshell.dev - jsDeliver: - https://cdn.jsdelivr.net/gh/z-shell/zi-src@main/ + +### Maintainer โ€” Verify and Sync Loader + +Check whether the local `lib/zsh/init.zsh` matches the canonical GitHub raw `main` copy: + +```sh +sh lib/sh/sync-init.sh +``` + +Replace the local file if it drifts: + +```sh +sh lib/sh/sync-init.sh --write +``` + +Run against local fixtures (no network required, useful in tests): + +```sh +sh lib/sh/sync-init.sh \ + --local /tmp/my-init.zsh \ + --remote /tmp/remote-init.zsh \ + --checksum-url /tmp/checksum.txt +``` + +Skip checksum validation: + +```sh +sh lib/sh/sync-init.sh --no-checksum +``` diff --git a/lib/checksum.txt b/lib/checksum.txt index 7335fdd..de6d2fc 100644 --- a/lib/checksum.txt +++ b/lib/checksum.txt @@ -1,3 +1,4 @@ -13668e0d6edce92994b0434932873d8a8a2c2579a2cb53964de19212f02a2954 lib/sh/install_zpmod.sh -6214cad3026f4150dfe1070592f6b24256cae5c60c596bdfebda07ffeaaf39fc lib/sh/install.sh -23a563e80249a866c7cba3ac44eaedb1ca38f20c35690fb764a7cb75e95d38be lib/zsh/init.zsh +5d8fdd881b84548f38c1d5ffc6d5f46a18919d8dd6c1398d69abe055dd76ef98 lib/sh/install_zpmod.sh +9d643c40be25f71d93dd295dacc58944defe7218f961f3f3ecb4ee9c0a56d486 lib/sh/install.sh +83d9f0dc013376b5aa03b7a11f3908058da176df3407ac6e2872857d7c9658fd lib/sh/sync-init.sh +66dc5bb0575d44e4e1192e229204abe1ac47979a05ee3c3bb23afc2b9b493637 lib/zsh/init.zsh From b91e7e202f5b09c26d9f0bd271648cf69fe89061 Mon Sep 17 00:00:00 2001 From: Salvydas Lukosius Date: Sat, 16 May 2026 06:34:16 +0100 Subject: [PATCH 06/12] ci(check-linux): add init.zsh sync-drift detection step --- .github/workflows/check-linux.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/check-linux.yml b/.github/workflows/check-linux.yml index 705dfd7..1e9a62a 100644 --- a/.github/workflows/check-linux.yml +++ b/.github/workflows/check-linux.yml @@ -65,3 +65,5 @@ jobs: zmodload zi/zpmod zpmod source-study -l shell: zsh {0} + - name: "โš™๏ธ Check: init.zsh sync drift" + run: sh lib/sh/sync-init.sh From ae8f88898eec0671a8723364ab68bcac54c675c3 Mon Sep 17 00:00:00 2001 From: Salvydas Lukosius Date: Sat, 16 May 2026 06:36:36 +0100 Subject: [PATCH 07/12] fix(install.sh): verify zi.zsh exists after clone, not just directory --- lib/sh/install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/sh/install.sh b/lib/sh/install.sh index 57959c7..03522ac 100755 --- a/lib/sh/install.sh +++ b/lib/sh/install.sh @@ -91,7 +91,7 @@ else printf '%s\n' "โ–“โ–’โ–‘ Installing (z-shell/zi) plugin manager at ${ZI_HOME}/${ZI_BIN_DIR_NAME}" { git clone --progress --depth=1 --branch "${BOPT}" https://github.com/z-shell/zi.git "${ZI_BIN_DIR_NAME}" \ 2>&1 | { /tmp/zi/git-process-output.zsh || cat; }; } 2>/dev/null - if [ -d "${ZI_HOME}/${ZI_BIN_DIR_NAME}" ]; then + if [ -d "${ZI_HOME}/${ZI_BIN_DIR_NAME}" ] && [ -f "${ZI_HOME}/${ZI_BIN_DIR_NAME}/zi.zsh" ]; then printf '%s\n' "โ–“โ–’โ–‘ Successfully installed at ${ZI_HOME}/${ZI_BIN_DIR_NAME}". else printf '%s\n' "โ–“โ–’โ–‘ Something went wrong, couldn't install ZI at ${ZI_HOME}/${ZI_BIN_DIR_NAME}" From 138aaa911c2a59e1027f632e39a169536e6143a7 Mon Sep 17 00:00:00 2001 From: Salvydas Lukosius Date: Sat, 16 May 2026 06:39:40 +0100 Subject: [PATCH 08/12] ci: add concurrency to checksum.yml; add smoke-test to win-install.yml Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/checksum.yml | 4 ++++ .github/workflows/win-install.yml | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/.github/workflows/checksum.yml b/.github/workflows/checksum.yml index 2a84471..4e4278c 100644 --- a/.github/workflows/checksum.yml +++ b/.github/workflows/checksum.yml @@ -13,6 +13,10 @@ on: permissions: contents: write +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: false + jobs: checksum: if: github.repository == 'z-shell/zi-src' diff --git a/.github/workflows/win-install.yml b/.github/workflows/win-install.yml index c1b5cc5..dcf9fc3 100644 --- a/.github/workflows/win-install.yml +++ b/.github/workflows/win-install.yml @@ -60,3 +60,13 @@ jobs: command rm -rf "${XDG_DATA_HOME:-$HOME/.local/share}/zi" /home/runneradmin/.zi sh -x ./lib/sh/install.sh -- -a zpmod shell: C:\tools\cygwin\bin\bash.exe --login -o igncr '{0}' + - name: ๐ŸชŸ Smoke-test โ€” verify zi.zsh present + run: | + ZI_BIN="${XDG_DATA_HOME:-${HOME}/.local/share}/zi/bin" + if [ ! -f "${ZI_BIN}/zi.zsh" ]; then + printf '%s\n' "FAIL: zi.zsh not found at ${ZI_BIN}/zi.zsh" + exit 1 + fi + printf '%s\n' "OK: zi.zsh found at ${ZI_BIN}/zi.zsh" + command rm -rf "${XDG_DATA_HOME:-${HOME}/.local/share}/zi" /home/runneradmin/.zi + shell: C:\tools\cygwin\bin\bash.exe --login -o igncr '{0}' From fde8a2cc60b043f7de1d554a3c2ce9d19d2e77b1 Mon Sep 17 00:00:00 2001 From: Salvydas Lukosius Date: Sat, 16 May 2026 08:12:14 +0100 Subject: [PATCH 09/12] chore: rename repo references from zi-src to src Update all internal references to reflect the repository rename: - .trunk/trunk.yaml repo name - workflow repository guards (checksum, rclone-action, deploy-gh-pages) - win-install safe.directory path - docs/README.md VSCode and jsDelivr URLs --- .github/workflows/checksum.yml | 2 +- .github/workflows/deploy-gh-pages.yml | 2 +- .github/workflows/rclone-action.yml | 2 +- .github/workflows/win-install.yml | 2 +- .trunk/trunk.yaml | 2 +- docs/README.md | 4 ++-- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/checksum.yml b/.github/workflows/checksum.yml index 4e4278c..29fdb4e 100644 --- a/.github/workflows/checksum.yml +++ b/.github/workflows/checksum.yml @@ -19,7 +19,7 @@ concurrency: jobs: checksum: - if: github.repository == 'z-shell/zi-src' + if: github.repository == 'z-shell/src' runs-on: ubuntu-latest timeout-minutes: 10 steps: diff --git a/.github/workflows/deploy-gh-pages.yml b/.github/workflows/deploy-gh-pages.yml index 83b21fd..351dbeb 100644 --- a/.github/workflows/deploy-gh-pages.yml +++ b/.github/workflows/deploy-gh-pages.yml @@ -15,7 +15,7 @@ permissions: jobs: deploy: - if: github.repository == 'z-shell/zi-src' + if: github.repository == 'z-shell/src' environment: name: github-pages runs-on: ubuntu-latest diff --git a/.github/workflows/rclone-action.yml b/.github/workflows/rclone-action.yml index 719d600..5b0f0e0 100644 --- a/.github/workflows/rclone-action.yml +++ b/.github/workflows/rclone-action.yml @@ -17,7 +17,7 @@ concurrency: jobs: sync: - if: github.repository == 'z-shell/zi-src' + if: github.repository == 'z-shell/src' runs-on: ubuntu-latest timeout-minutes: 15 env: diff --git a/.github/workflows/win-install.yml b/.github/workflows/win-install.yml index dcf9fc3..365e6bc 100644 --- a/.github/workflows/win-install.yml +++ b/.github/workflows/win-install.yml @@ -40,7 +40,7 @@ jobs: - name: ๐ŸชŸ Set CRLF (Windows) run: | git config --global core.autocrlf input - git config --global --add safe.directory /cygdrive/d/a/zi-src/zi-src + git config --global --add safe.directory /cygdrive/d/a/src/src - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: ๐ŸชŸ Dependencies (Windows) uses: egor-tensin/setup-cygwin@d2c752bab416d4b0662591bd366fc2686297c82d # v4.0.1 diff --git a/.trunk/trunk.yaml b/.trunk/trunk.yaml index 6bb320d..7cdfae6 100644 --- a/.trunk/trunk.yaml +++ b/.trunk/trunk.yaml @@ -10,7 +10,7 @@ repo: repo: host: github.com owner: z-shell - name: zi-src + name: src lint: definitions: - name: shfmt diff --git a/docs/README.md b/docs/README.md index c45d77d..7b2fa8c 100644 --- a/docs/README.md +++ b/docs/README.md @@ -21,7 +21,7 @@ VIM - + Visual Studio Code


@@ -38,7 +38,7 @@ - IPFS: - https://ipfs.zshell.dev - jsDeliver: - - https://cdn.jsdelivr.net/gh/z-shell/zi-src@main/ + - https://cdn.jsdelivr.net/gh/z-shell/src@main/ ### Maintainer โ€” Verify and Sync Loader From 8d6cecb48f2a9f5381ae5dde664c85fbd18cc1fa Mon Sep 17 00:00:00 2001 From: ss-o Date: Sat, 16 May 2026 08:46:27 +0100 Subject: [PATCH 10/12] ci: add org project tracker scripts (label sync + workflow rollout) --- scripts/add-project-workflow.sh | 126 ++++++++++++++++++++++++++++++++ scripts/repos.txt | 94 ++++++++++++++++++++++++ scripts/sync-labels.sh | 94 ++++++++++++++++++++++++ 3 files changed, 314 insertions(+) create mode 100755 scripts/add-project-workflow.sh create mode 100644 scripts/repos.txt create mode 100755 scripts/sync-labels.sh diff --git a/scripts/add-project-workflow.sh b/scripts/add-project-workflow.sh new file mode 100755 index 0000000..3436536 --- /dev/null +++ b/scripts/add-project-workflow.sh @@ -0,0 +1,126 @@ +#!/usr/bin/env sh +# add-project-workflow.sh โ€” Add project-tracker workflow to all org repos. +# +# Usage: +# ./add-project-workflow.sh [owner] [repos-file] +# +# Defaults: +# owner = z-shell +# repos-file = scripts/repos.txt +# +# Requirements: +# - gh CLI authenticated with repo scope +# - SSH key configured for git push +# - z-shell/.github already has add-to-project.yml deployed + +set -e + +OWNER="${1:-z-shell}" +REPOS="${2:-$(dirname "$0")/repos.txt}" +WORKFLOW_FILE=".github/workflows/project-tracker.yml" +BRANCH="ci/add-project-tracker" + +if [ ! -f "$REPOS" ]; then + printf 'Error: repos file not found: %s\n' "$REPOS" >&2 + exit 1 +fi + +# Skip repos that already have the workflow or are the .github meta-repo +SKIP_REPOS=".github" + +WORKFLOW_CONTENT='# Add issues and PRs to the Z-Shell Tracker project automatically. +name: Track in Z-Shell Tracker + +on: + issues: + types: [opened, reopened, transferred] + pull_request: + types: [opened, reopened] + +jobs: + track: + uses: z-shell/.github/.github/workflows/add-to-project.yml@main + secrets: inherit +' + +total=0 +ok=0 +skipped=0 +failed=0 + +add_workflow() { + repo="$1" + printf '=== %s/%s ===\n' "$OWNER" "$repo" + + # Skip the .github meta-repo itself + for skip in $SKIP_REPOS; do + if [ "$repo" = "$skip" ]; then + printf 'Skipping meta-repo\n' + skipped=$((skipped + 1)) + return 0 + fi + done + + tmpdir=$(mktemp -d) + trap 'rm -rf "$tmpdir"' EXIT INT TERM + + # Clone (shallow) โ€” skip archived/empty repos gracefully + if ! git clone --depth=1 "git@github.com:$OWNER/$repo.git" "$tmpdir/$repo" 2>/dev/null; then + printf 'SKIP: cannot clone (archived or empty?)\n' + skipped=$((skipped + 1)) + trap - EXIT INT TERM + rm -rf "$tmpdir" + return 0 + fi + + cd "$tmpdir/$repo" + + # Skip if workflow already exists + if [ -f "$WORKFLOW_FILE" ]; then + printf 'SKIP: workflow already present\n' + skipped=$((skipped + 1)) + cd - >/dev/null + trap - EXIT INT TERM + rm -rf "$tmpdir" + return 0 + fi + + # Get default branch + default_branch=$(git symbolic-ref --short HEAD 2>/dev/null || echo "main") + + git checkout -b "$BRANCH" 2>/dev/null || git checkout "$BRANCH" + mkdir -p "$(dirname "$WORKFLOW_FILE")" + printf '%s' "$WORKFLOW_CONTENT" >"$WORKFLOW_FILE" + + git add "$WORKFLOW_FILE" + git commit -m "ci: add project tracker workflow" + git push origin "$BRANCH" + + # Open a PR + gh pr create \ + --repo "$OWNER/$repo" \ + --base "$default_branch" \ + --head "$BRANCH" \ + --title "ci: add project tracker workflow" \ + --body 'Adds the `.github/workflows/project-tracker.yml` workflow so new issues and PRs are automatically added to the [Z-Shell Tracker](https://github.com/orgs/z-shell/projects/28) project. + +Uses the shared reusable workflow from `z-shell/.github` โ€” no per-repo secrets needed.' \ + 2>/dev/null && printf 'PR opened\n' || printf 'PR already open or failed\n' + + ok=$((ok + 1)) + cd - >/dev/null + trap - EXIT INT TERM + rm -rf "$tmpdir" +} + +while IFS= read -r repo || [ -n "$repo" ]; do + [ -z "$repo" ] && continue + total=$((total + 1)) + add_workflow "$repo" || { + failed=$((failed + 1)) + printf 'FAILED: %s/%s\n' "$OWNER" "$repo" >&2 + } +done <"$REPOS" + +printf '\nDone โ€” %d total, %d ok, %d skipped, %d failed\n' \ + "$total" "$ok" "$skipped" "$failed" diff --git a/scripts/repos.txt b/scripts/repos.txt new file mode 100644 index 0000000..2aacb30 --- /dev/null +++ b/scripts/repos.txt @@ -0,0 +1,94 @@ +F-Sy-H +z-a-bin-gem-node +z-a-patch-dl +z-a-readurl +z-a-rust +z-a-submods +z-a-meta-plugins +zsh-navigation-tools +declare-zsh +zsh-unique-id +zsh-diff-so-fancy +zflai +null +zconvey +zui +z-a-man +zsh +z-a-unscope +z-a-default-ice +zi-crasis +zi-vim-syntax +zsh-lint +zsh-github-issues +zzcomplete +zbrowse +firefox-dev +any-node +any-gem +apr +doctoc +asciidoctor +ecs-cli +fzf +fzy +github-issues-srv +github-issues +ls_colors +pyenv +z-a-test +z-a-linkbin +z-a-eval +dircolors-material +zi-rbenv +ztrace +zsnapshot +zsh-select +zsh-morpho +zsh-log-lines +zservice-py3http +zsh-editing-workbench +pm-perf-test +system-completions +subversion +remark +community +zsh-tig-plugin +zsh-string-lib +zsh-util-lib +zsh-cmd-architect +zredis-cmd +zredis +zprompts +zi-console +playground +zgdbm +redis +VATS +zi +H-S-MW +src +zsh-bin +docs +zsdoc +vramsteg-zsh +zd +status +.github +z-shell.github.io +zpmod +zsh-eza +brew-completions +0 +wiki +zsh-zoxide +zsh-fancy-completions +web +zsh-web-artwork +merch +nb +.github-private +z-a-linkman +zsh-lsd +.trunk +zunit diff --git a/scripts/sync-labels.sh b/scripts/sync-labels.sh new file mode 100755 index 0000000..328ded5 --- /dev/null +++ b/scripts/sync-labels.sh @@ -0,0 +1,94 @@ +#!/usr/bin/env sh +# sync-labels.sh โ€” Apply canonical Z-Shell label set to org repos. +# +# Usage: +# ./sync-labels.sh [owner] [repos-file] +# +# Defaults: +# owner = z-shell +# repos-file = scripts/repos.txt (one repo name per line) +# +# Requirements: +# - gh CLI authenticated with repo scope +# - gh label create supports --force (gh >= 2.14) + +set -e + +OWNER="${1:-z-shell}" +REPOS="${2:-$(dirname "$0")/repos.txt}" + +if [ ! -f "$REPOS" ]; then + printf 'Error: repos file not found: %s\n' "$REPOS" >&2 + exit 1 +fi + +apply_labels() { + repo="$1" + printf '=== %s/%s ===\n' "$OWNER" "$repo" + + # โ”€โ”€ Type labels โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + gh label create "bug ๐Ÿ›" --repo "$OWNER/$repo" --color d73a4a \ + --description "Something isn't working" --force + gh label create "feature-request ๐Ÿ’ก" --repo "$OWNER/$repo" --color 0075ca \ + --description "New feature or request" --force + gh label create "enhancement โœจ" --repo "$OWNER/$repo" --color a2eeef \ + --description "Improvement to existing functionality" --force + gh label create "documentation ๐Ÿ“" --repo "$OWNER/$repo" --color 0052cc \ + --description "Documentation-only changes" --force + gh label create "performance ๐Ÿš€" --repo "$OWNER/$repo" --color 006b75 \ + --description "Performance improvements" --force + gh label create "security ๐Ÿ›ก๏ธ" --repo "$OWNER/$repo" --color ee0701 \ + --description "Security vulnerability or hardening" --force + gh label create "breaking-change ๐Ÿ’ฅ" --repo "$OWNER/$repo" --color d93f0b \ + --description "Breaks backward compatibility" --force + gh label create "dependencies ๐Ÿ“ฆ" --repo "$OWNER/$repo" --color 0366d6 \ + --description "Dependency updates" --force + gh label create "chore ๐Ÿ”ง" --repo "$OWNER/$repo" --color c5def5 \ + --description "Routine maintenance, no behavior change" --force + gh label create "refactor โ™ป๏ธ" --repo "$OWNER/$repo" --color 5319e7 \ + --description "Code refactor, no behavior change" --force + gh label create "ci โš™๏ธ" --repo "$OWNER/$repo" --color 1d76db \ + --description "CI/CD pipeline changes" --force + + # โ”€โ”€ Status / workflow labels โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + gh label create "triage ๐Ÿ”" --repo "$OWNER/$repo" --color fbca04 \ + --description "Needs investigation before action" --force + gh label create "in-progress ๐Ÿšง" --repo "$OWNER/$repo" --color f9d0c4 \ + --description "Currently being worked on" --force + gh label create "blocked โ›”" --repo "$OWNER/$repo" --color e4e669 \ + --description "Blocked on external dependency/decision" --force + gh label create "stale ๐Ÿ’ค" --repo "$OWNER/$repo" --color f2f2f2 \ + --description "No activity for an extended period" --force + gh label create "invalid โš ๏ธ" --repo "$OWNER/$repo" --color e4e669 \ + --description "Off-topic, cannot reproduce, or incorrect" --force + gh label create "wontfix ๐Ÿšซ" --repo "$OWNER/$repo" --color ffffff \ + --description "Will not be fixed" --force + gh label create "no-stale ๐Ÿ”’" --repo "$OWNER/$repo" --color 0e8a16 \ + --description "Exempt from stale-bot closing" --force + + # โ”€โ”€ Community labels โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + gh label create "help-wanted ๐Ÿ™‹" --repo "$OWNER/$repo" --color 008672 \ + --description "Extra attention or expertise needed" --force + gh label create "good-first-issue ๐ŸŒฑ" --repo "$OWNER/$repo" --color 7057ff \ + --description "Good for newcomers" --force + gh label create "Q&A โœ๏ธ" --repo "$OWNER/$repo" --color d4c5f9 \ + --description "Questions and answers" --force +} + +# โ”€โ”€ Main loop โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +total=0 +ok=0 +failed=0 + +while IFS= read -r repo || [ -n "$repo" ]; do + [ -z "$repo" ] && continue + total=$((total + 1)) + if apply_labels "$repo"; then + ok=$((ok + 1)) + else + failed=$((failed + 1)) + printf 'FAILED: %s/%s\n' "$OWNER" "$repo" >&2 + fi +done <"$REPOS" + +printf '\nDone โ€” %d total, %d ok, %d failed\n' "$total" "$ok" "$failed" From 3aa0f71466cd096c2a5908ead668aad1eb7a36e0 Mon Sep 17 00:00:00 2001 From: ss-o Date: Sat, 16 May 2026 12:35:29 +0100 Subject: [PATCH 11/12] fix(ci): continue label sync after repo failures --- scripts/sync-labels.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/scripts/sync-labels.sh b/scripts/sync-labels.sh index 328ded5..3ccf349 100755 --- a/scripts/sync-labels.sh +++ b/scripts/sync-labels.sh @@ -12,8 +12,6 @@ # - gh CLI authenticated with repo scope # - gh label create supports --force (gh >= 2.14) -set -e - OWNER="${1:-z-shell}" REPOS="${2:-$(dirname "$0")/repos.txt}" From 4152bc048713f4438d691181acc75fa2dd2f2279 Mon Sep 17 00:00:00 2001 From: ss-o Date: Sat, 16 May 2026 14:43:52 +0100 Subject: [PATCH 12/12] chore: fix lint issues and syntax errors reported by trunk --- lib/index.html | 335 ++++++++++++++++++++++++++++++++ scripts/add-project-workflow.sh | 52 ++--- scripts/sync-labels.sh | 60 +++--- 3 files changed, 392 insertions(+), 55 deletions(-) create mode 100644 lib/index.html diff --git a/lib/index.html b/lib/index.html new file mode 100644 index 0000000..be05ff4 --- /dev/null +++ b/lib/index.html @@ -0,0 +1,335 @@ + + + + + + Z-Shell / src โ€” CDN Assets + + + +
+
+ Z-Shell Logo +

Z-Shell / src

+

High-performance CDN for Z-Shell ecosystem assets.

+
+ +
+
+
+
+
+
+
+
z-shell@src:~
+
+
+
+ โฏ + ls -1 assets/ +
+
    +
  • +
    + Zi Loader + src.zshell.dev/zsh/init.zsh +
    + +
  • +
  • +
    + Zi Installer + get.zshell.dev +
    + +
  • +
  • +
    + Zi Wiki + wiki.zshell.dev +
    + +
  • +
+
+ โฏ _ +
+
+
+ + +
+ + + + + + diff --git a/scripts/add-project-workflow.sh b/scripts/add-project-workflow.sh index 3436536..b5573ba 100755 --- a/scripts/add-project-workflow.sh +++ b/scripts/add-project-workflow.sh @@ -20,8 +20,8 @@ REPOS="${2:-$(dirname "$0")/repos.txt}" WORKFLOW_FILE=".github/workflows/project-tracker.yml" BRANCH="ci/add-project-tracker" -if [ ! -f "$REPOS" ]; then - printf 'Error: repos file not found: %s\n' "$REPOS" >&2 +if [ ! -f "${REPOS}" ]; then + printf 'Error: repos file not found: %s\n' "${REPOS}" >&2 exit 1 fi @@ -50,11 +50,11 @@ failed=0 add_workflow() { repo="$1" - printf '=== %s/%s ===\n' "$OWNER" "$repo" + printf '=== %s/%s ===\n' "${OWNER}" "${repo}" # Skip the .github meta-repo itself - for skip in $SKIP_REPOS; do - if [ "$repo" = "$skip" ]; then + for skip in ${SKIP_REPOS}; do + if [ "${repo}" = "${skip}" ]; then printf 'Skipping meta-repo\n' skipped=$((skipped + 1)) return 0 @@ -65,42 +65,43 @@ add_workflow() { trap 'rm -rf "$tmpdir"' EXIT INT TERM # Clone (shallow) โ€” skip archived/empty repos gracefully - if ! git clone --depth=1 "git@github.com:$OWNER/$repo.git" "$tmpdir/$repo" 2>/dev/null; then + if ! git clone --depth=1 "git@github.com:${OWNER}/${repo}.git" "${tmpdir}/${repo}" 2>/dev/null; then printf 'SKIP: cannot clone (archived or empty?)\n' skipped=$((skipped + 1)) trap - EXIT INT TERM - rm -rf "$tmpdir" + rm -rf "${tmpdir}" return 0 fi - cd "$tmpdir/$repo" + cd "${tmpdir}/${repo}" # Skip if workflow already exists - if [ -f "$WORKFLOW_FILE" ]; then + if [ -f "${WORKFLOW_FILE}" ]; then printf 'SKIP: workflow already present\n' skipped=$((skipped + 1)) cd - >/dev/null trap - EXIT INT TERM - rm -rf "$tmpdir" + rm -rf "${tmpdir}" return 0 fi # Get default branch default_branch=$(git symbolic-ref --short HEAD 2>/dev/null || echo "main") - git checkout -b "$BRANCH" 2>/dev/null || git checkout "$BRANCH" - mkdir -p "$(dirname "$WORKFLOW_FILE")" - printf '%s' "$WORKFLOW_CONTENT" >"$WORKFLOW_FILE" + git checkout -b "${BRANCH}" 2>/dev/null || git checkout "${BRANCH}" + mkdir -p "$(dirname "${WORKFLOW_FILE}")" + printf '%s' "${WORKFLOW_CONTENT}" >"${WORKFLOW_FILE}" - git add "$WORKFLOW_FILE" + git add "${WORKFLOW_FILE}" git commit -m "ci: add project tracker workflow" - git push origin "$BRANCH" + git push origin "${BRANCH}" # Open a PR + # shellcheck disable=SC2016 gh pr create \ - --repo "$OWNER/$repo" \ - --base "$default_branch" \ - --head "$BRANCH" \ + --repo "${OWNER}/${repo}" \ + --base "${default_branch}" \ + --head "${BRANCH}" \ --title "ci: add project tracker workflow" \ --body 'Adds the `.github/workflows/project-tracker.yml` workflow so new issues and PRs are automatically added to the [Z-Shell Tracker](https://github.com/orgs/z-shell/projects/28) project. @@ -110,17 +111,18 @@ Uses the shared reusable workflow from `z-shell/.github` โ€” no per-repo secrets ok=$((ok + 1)) cd - >/dev/null trap - EXIT INT TERM - rm -rf "$tmpdir" + rm -rf "${tmpdir}" } -while IFS= read -r repo || [ -n "$repo" ]; do - [ -z "$repo" ] && continue +while IFS= read -r repo || [ -n "${repo}" ]; do + [ -z "${repo}" ] && continue total=$((total + 1)) - add_workflow "$repo" || { + # shellcheck disable=SC2310 + add_workflow "${repo}" || { failed=$((failed + 1)) - printf 'FAILED: %s/%s\n' "$OWNER" "$repo" >&2 + printf 'FAILED: %s/%s\n' "${OWNER}" "${repo}" >&2 } -done <"$REPOS" +done <"${REPOS}" printf '\nDone โ€” %d total, %d ok, %d skipped, %d failed\n' \ - "$total" "$ok" "$skipped" "$failed" + "${total}" "${ok}" "${skipped}" "${failed}" diff --git a/scripts/sync-labels.sh b/scripts/sync-labels.sh index 3ccf349..95089c7 100755 --- a/scripts/sync-labels.sh +++ b/scripts/sync-labels.sh @@ -15,61 +15,61 @@ OWNER="${1:-z-shell}" REPOS="${2:-$(dirname "$0")/repos.txt}" -if [ ! -f "$REPOS" ]; then - printf 'Error: repos file not found: %s\n' "$REPOS" >&2 +if [ ! -f "${REPOS}" ]; then + printf 'Error: repos file not found: %s\n' "${REPOS}" >&2 exit 1 fi apply_labels() { repo="$1" - printf '=== %s/%s ===\n' "$OWNER" "$repo" + printf '=== %s/%s ===\n' "${OWNER}" "${repo}" # โ”€โ”€ Type labels โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - gh label create "bug ๐Ÿ›" --repo "$OWNER/$repo" --color d73a4a \ + gh label create "bug ๐Ÿ›" --repo "${OWNER}/${repo}" --color d73a4a \ --description "Something isn't working" --force - gh label create "feature-request ๐Ÿ’ก" --repo "$OWNER/$repo" --color 0075ca \ + gh label create "feature-request ๐Ÿ’ก" --repo "${OWNER}/${repo}" --color 0075ca \ --description "New feature or request" --force - gh label create "enhancement โœจ" --repo "$OWNER/$repo" --color a2eeef \ + gh label create "enhancement โœจ" --repo "${OWNER}/${repo}" --color a2eeef \ --description "Improvement to existing functionality" --force - gh label create "documentation ๐Ÿ“" --repo "$OWNER/$repo" --color 0052cc \ + gh label create "documentation ๐Ÿ“" --repo "${OWNER}/${repo}" --color 0052cc \ --description "Documentation-only changes" --force - gh label create "performance ๐Ÿš€" --repo "$OWNER/$repo" --color 006b75 \ + gh label create "performance ๐Ÿš€" --repo "${OWNER}/${repo}" --color 006b75 \ --description "Performance improvements" --force - gh label create "security ๐Ÿ›ก๏ธ" --repo "$OWNER/$repo" --color ee0701 \ + gh label create "security ๐Ÿ›ก๏ธ" --repo "${OWNER}/${repo}" --color ee0701 \ --description "Security vulnerability or hardening" --force - gh label create "breaking-change ๐Ÿ’ฅ" --repo "$OWNER/$repo" --color d93f0b \ + gh label create "breaking-change ๐Ÿ’ฅ" --repo "${OWNER}/${repo}" --color d93f0b \ --description "Breaks backward compatibility" --force - gh label create "dependencies ๐Ÿ“ฆ" --repo "$OWNER/$repo" --color 0366d6 \ + gh label create "dependencies ๐Ÿ“ฆ" --repo "${OWNER}/${repo}" --color 0366d6 \ --description "Dependency updates" --force - gh label create "chore ๐Ÿ”ง" --repo "$OWNER/$repo" --color c5def5 \ + gh label create "chore ๐Ÿ”ง" --repo "${OWNER}/${repo}" --color c5def5 \ --description "Routine maintenance, no behavior change" --force - gh label create "refactor โ™ป๏ธ" --repo "$OWNER/$repo" --color 5319e7 \ + gh label create "refactor โ™ป๏ธ" --repo "${OWNER}/${repo}" --color 5319e7 \ --description "Code refactor, no behavior change" --force - gh label create "ci โš™๏ธ" --repo "$OWNER/$repo" --color 1d76db \ + gh label create "ci โš™๏ธ" --repo "${OWNER}/${repo}" --color 1d76db \ --description "CI/CD pipeline changes" --force # โ”€โ”€ Status / workflow labels โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - gh label create "triage ๐Ÿ”" --repo "$OWNER/$repo" --color fbca04 \ + gh label create "triage ๐Ÿ”" --repo "${OWNER}/${repo}" --color fbca04 \ --description "Needs investigation before action" --force - gh label create "in-progress ๐Ÿšง" --repo "$OWNER/$repo" --color f9d0c4 \ + gh label create "in-progress ๐Ÿšง" --repo "${OWNER}/${repo}" --color f9d0c4 \ --description "Currently being worked on" --force - gh label create "blocked โ›”" --repo "$OWNER/$repo" --color e4e669 \ + gh label create "blocked โ›”" --repo "${OWNER}/${repo}" --color e4e669 \ --description "Blocked on external dependency/decision" --force - gh label create "stale ๐Ÿ’ค" --repo "$OWNER/$repo" --color f2f2f2 \ + gh label create "stale ๐Ÿ’ค" --repo "${OWNER}/${repo}" --color f2f2f2 \ --description "No activity for an extended period" --force - gh label create "invalid โš ๏ธ" --repo "$OWNER/$repo" --color e4e669 \ + gh label create "invalid โš ๏ธ" --repo "${OWNER}/${repo}" --color e4e669 \ --description "Off-topic, cannot reproduce, or incorrect" --force - gh label create "wontfix ๐Ÿšซ" --repo "$OWNER/$repo" --color ffffff \ + gh label create "wontfix ๐Ÿšซ" --repo "${OWNER}/${repo}" --color ffffff \ --description "Will not be fixed" --force - gh label create "no-stale ๐Ÿ”’" --repo "$OWNER/$repo" --color 0e8a16 \ + gh label create "no-stale ๐Ÿ”’" --repo "${OWNER}/${repo}" --color 0e8a16 \ --description "Exempt from stale-bot closing" --force # โ”€โ”€ Community labels โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - gh label create "help-wanted ๐Ÿ™‹" --repo "$OWNER/$repo" --color 008672 \ + gh label create "help-wanted ๐Ÿ™‹" --repo "${OWNER}/${repo}" --color 008672 \ --description "Extra attention or expertise needed" --force - gh label create "good-first-issue ๐ŸŒฑ" --repo "$OWNER/$repo" --color 7057ff \ + gh label create "good-first-issue ๐ŸŒฑ" --repo "${OWNER}/${repo}" --color 7057ff \ --description "Good for newcomers" --force - gh label create "Q&A โœ๏ธ" --repo "$OWNER/$repo" --color d4c5f9 \ + gh label create "Q&A โœ๏ธ" --repo "${OWNER}/${repo}" --color d4c5f9 \ --description "Questions and answers" --force } @@ -78,15 +78,15 @@ total=0 ok=0 failed=0 -while IFS= read -r repo || [ -n "$repo" ]; do - [ -z "$repo" ] && continue +while IFS= read -r repo || [ -n "${repo}" ]; do + [ -z "${repo}" ] && continue total=$((total + 1)) - if apply_labels "$repo"; then + if apply_labels "${repo}"; then ok=$((ok + 1)) else failed=$((failed + 1)) - printf 'FAILED: %s/%s\n' "$OWNER" "$repo" >&2 + printf 'FAILED: %s/%s\n' "${OWNER}" "${repo}" >&2 fi -done <"$REPOS" +done <"${REPOS}" -printf '\nDone โ€” %d total, %d ok, %d failed\n' "$total" "$ok" "$failed" +printf '\nDone โ€” %d total, %d ok, %d failed\n' "${total}" "${ok}" "${failed}"