Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion public/checksum.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
6de66efba021ebcf462e7672577d9f6876f13db55691f04e7009ff7e78d658b8 public/sh/install_zpmod.sh
6e753a0314ba9f2e4f0a2c429798ca3767af4fb94c669e6923d161d6af7aa745 public/sh/install.sh
eff43da44827d4774eed21d31d841df04b9cd8fe089c1b59d38bef3608920754 public/sh/install.sh
08cc893ceb982fc99d17db1966c6c30790cc571e16e4f5392352d995f5252952 public/sh/sync-init.sh
c979e39748d1d86ace17a61ff2b1bf6e1224a43291c25bf7fad985d1e9e11af1 public/zsh/init.zsh
116 changes: 82 additions & 34 deletions public/sh/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,11 @@ shift $((OPTIND - 1))
# | is the sed delimiter used in the substitution; \ and & are special in
# sed replacement expressions. The *[\\]* pattern matches a single backslash.
case "${BOPT}" in
# [\\] is a bracket expression for a literal backslash.
*'|'* | *[\\]* | *'&'* )
printf '%s\n' "-- ERROR -- Invalid -b value: branch name must not contain '|', '\\', or '&'." >&2
exit 1
;;
# [\\] is a bracket expression for a literal backslash.
*'|'* | *[\\]* | *'&'*)
printf '%s\n' "-- ERROR -- Invalid -b value: branch name must not contain '|', '\\', or '&'." >&2
exit 1
;;
Comment thread
ss-o marked this conversation as resolved.
esac

SCRIPT_DIR=""
Expand Down Expand Up @@ -104,8 +104,8 @@ fetch_to_file() {

is_absolute_path() {
case "${1-}" in
/*) return 0 ;;
*) return 1 ;;
/*) return 0 ;;
*) return 1 ;;
esac
}

Expand Down Expand Up @@ -183,6 +183,13 @@ if ! command -v git >/dev/null 2>&1; then
exit 1
fi

# -b is used as a fetch refspec and inside generated Zsh: accept only a
# well-formed branch name (no ':', no leading '-', no '..').
if ! command git check-ref-format --branch "${BOPT}" >/dev/null 2>&1; then
printf '%s\n' "-- ERROR -- Invalid -b value: '${BOPT}' is not a valid branch name." >&2
exit 1
fi

# Get the download-progress bar tool
command mkdir -p /tmp/zi
cd /tmp/zi || exit 1
Expand All @@ -204,9 +211,10 @@ if test -d "${ZI_HOME}/${ZI_BIN_DIR_NAME}/.git"; then
if test -f "${ZI_HOME}/${ZI_BIN_DIR_NAME}/zi.zsh"; then
# Canonical zi remote URLs (HTTPS and SSH, with and without .git suffix)
case "$(command git -C "${ZI_HOME}/${ZI_BIN_DIR_NAME}" remote get-url origin 2>/dev/null || true)" in
https://github.com/z-shell/zi | https://github.com/z-shell/zi.git \
| git@github.com:z-shell/zi | git@github.com:z-shell/zi.git)
_zi_valid=1 ;;
https://github.com/z-shell/zi | https://github.com/z-shell/zi.git | \
git@github.com:z-shell/zi | git@github.com:z-shell/zi.git)
_zi_valid=1
;;
esac
fi
if [ "${_zi_valid}" -ne 1 ]; then
Expand All @@ -216,9 +224,18 @@ if test -d "${ZI_HOME}/${ZI_BIN_DIR_NAME}/.git"; then
fi
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 "${BOPT}"
# Match `zi self-update`: fetch the requested branch and fast-forward only.
# Local state is never discarded; refuse loudly when it cannot be advanced.
if ! command git fetch -q origin "refs/heads/${BOPT}"; then
printf '%s\n' "-- ERROR -- failed to fetch origin ${BOPT} into ${ZI_HOME}/${ZI_BIN_DIR_NAME}" >&2
exit 1
fi
if ! command git merge -q --ff-only FETCH_HEAD; then
printf '%s\n' "-- ERROR -- ${ZI_HOME}/${ZI_BIN_DIR_NAME} cannot be fast-forwarded to origin/${BOPT}; local state was left untouched:" >&2
command git status --short --branch 2>/dev/null | head -20 >&2
printf '%s\n' "-- ERROR -- resolve the checkout state shown above so HEAD can fast-forward to origin/${BOPT} (move local commits to another branch, or drop changes you do not need), then rerun the installer." >&2
exit 1
fi
else
cd "${ZI_HOME}" || exit 1
printf '%s\n' "▓▒░ Installing (z-shell/zi) plugin manager at ${ZI_HOME}/${ZI_BIN_DIR_NAME}"
Expand All @@ -238,30 +255,40 @@ fi

MAIN_PROFILE() {
THE_ZDOTDIR="${ZDOTDIR:-${HOME}}"
if grep -E '(zi|init|zinit)\.zsh' "${THE_ZDOTDIR}/.zshrc" >/dev/null 2>&1; then
printf '%s\n' "▓▒░ Seems that .zshrc already has content or setup skipped - no changes will be made."
ZOPT='skip'
ZSHRC_INTEGRATED=0
# Detect an existing Zi integration by a real source line. A comment that
# merely mentions the file name must not suppress the integration.
if grep -E '^[[:space:]]*(source|\.)[[:space:]]+[^#]*(zi|init|zinit)\.zsh(["'"'"'[:space:]]|$)' "${THE_ZDOTDIR}/.zshrc" >/dev/null 2>&1; then
printf '%s\n' "▓▒░ Seems that .zshrc already sources Zi - the integration block will not be added."
ZSHRC_INTEGRATED=1
fi
if [ "${ZOPT}" != skip ] && [ "${AOPT}" != loader ]; then
# The .zshrc text refers to the home through $HOME; the installer itself
# keeps using the real path.
# shellcheck disable=SC2016
case "${ZI_HOME}" in
"${HOME}") ZI_HOME_TEXT='$HOME' ;;
"${HOME}"/*) ZI_HOME_TEXT="\$HOME${ZI_HOME#"${HOME}"}" ;;
*) ZI_HOME_TEXT="${ZI_HOME}" ;;
esac
if [ "${ZOPT}" != skip ] && [ "${ZSHRC_INTEGRATED}" -eq 0 ] && [ "${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"
if [[ ! -f ${ZI_HOME}/${ZI_BIN_DIR_NAME}/zi.zsh ]]; then
if [[ ! -f ${ZI_HOME_TEXT}/${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 go-rwX "${ZI_HOME}"
command git clone -q --filter=blob:none --single-branch --branch "${BOPT}" https://github.com/z-shell/zi "${ZI_HOME}/${ZI_BIN_DIR_NAME}" && \\
command mkdir -p "${ZI_HOME_TEXT}" && command chmod go-rwX "${ZI_HOME_TEXT}"
command git clone -q --filter=blob:none --single-branch --branch "${BOPT}" https://github.com/z-shell/zi "${ZI_HOME_TEXT}/${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"
source "${ZI_HOME_TEXT}/${ZI_BIN_DIR_NAME}/zi.zsh"
autoload -Uz _zi
(( \${+_comps} )) && _comps[zi]=_zi
# examples here -> https://wiki.zshell.dev/ecosystem/category/-annexes
zicompinit # <- https://wiki.zshell.dev/docs/guides/commands
EOF
printf '%s\n' "▓▒░ Minimal configuration"
fi
if [ "${AOPT}" = loader ] && [ "${ZOPT}" != skip ]; then
if [ "${AOPT}" = loader ] && [ "${ZOPT}" != skip ] && [ "${ZSHRC_INTEGRATED}" -eq 0 ]; then
command cat <<-EOF >>"${THE_ZDOTDIR}/.zshrc"
if [[ -n \${XDG_CONFIG_HOME:-} && \${XDG_CONFIG_HOME} == /* ]]; then
ZI_LOADER_CONFIG_HOME="\${XDG_CONFIG_HOME}/zi"
Expand All @@ -278,31 +305,52 @@ EOF
}

ANNEX_PROFILE() {
if [ "${AOPT}" != annex ] && [ "${AOPT}" != zunit ]; then
printf '%s\n' "▓▒░ Skipped all annexes"
return 0
fi
if [ "${ZOPT}" = skip ]; then
printf '%s\n' "▓▒░ .zshrc changes were skipped (-i skip); annexes were not configured"
return 0
fi
# Rerunning the installer must not append the block a second time.
if grep -E '^[^#]*z-shell/z-a-meta-plugins([[:space:]]|$)' "${THE_ZDOTDIR}/.zshrc" >/dev/null 2>&1; then
printf '%s\n' "▓▒░ .zshrc already loads z-shell/z-a-meta-plugins - annex block not added again"
return 0
fi
file="${WORKDIR}/temp-zsh-config"
if [ "${AOPT}" = annex ]; then
file="${WORKDIR}/temp-zsh-config"
command cat <<-EOF >>"${file}"
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
printf '%s\n' "▓▒░ Installing annexes"
command cat "${file}" >>"${THE_ZDOTDIR}/.zshrc"
zsh -ic "@zi-scheduler burst"
elif [ "${AOPT}" = zunit ]; then
file2="${WORKDIR}/temp-zunit-config"
command cat <<-EOF >>"${file2}"
else
command cat <<-EOF >"${file}"
zi light-mode for \\
z-shell/z-a-meta-plugins \\
@annexes @zunit
EOF
printf '%s\n' "▓▒░ Installing annexes + zunit"
command cat "${file2}" >>"${THE_ZDOTDIR}/.zshrc"
zsh -ic "@zi-scheduler burst"
else
printf '%s\n' "▓▒░ Skipped all annexes"
fi
command cat "${file}" >>"${THE_ZDOTDIR}/.zshrc"
ANNEX_BURST "${file}"
}

ANNEX_BURST() {
# Install the annexes now without an interactive shell and with -f, so no
# user startup file (not even .zshenv) runs: source only zi.zsh and the
# fragment just written. A failure here must not abort an install whose
# .zshrc changes are already in place.
if zsh -f -c 'builtin source "$1" && builtin source "$2" && @zi-scheduler burst' zsh \
"${ZI_HOME}/${ZI_BIN_DIR_NAME}/zi.zsh" "$1"; then
return 0
fi
printf '%s\n' "▓▒░ Annexes could not be installed now; they will be installed on the next shell start." >&2
return 0
}

ZPMOD_PROFILE() {
Expand Down
Loading
Loading