From 569f3d6538bc564b22ac2af6d1755b029e4bc9c6 Mon Sep 17 00:00:00 2001 From: krol Date: Fri, 6 Feb 2026 21:17:58 +0300 Subject: [PATCH] feat: managed zsh config + optional installers + version bump action --- .github/workflows/bump-version.yml | 67 +++++++ .zshrc | 275 ++++++++++++++--------------- README.md | 25 +++ install.sh | 78 +++++++- termux_zsh.sh | 90 +++++++++- version.txt | 2 +- zshrc.managed | 76 ++++++++ 7 files changed, 462 insertions(+), 151 deletions(-) create mode 100644 .github/workflows/bump-version.yml create mode 100644 zshrc.managed diff --git a/.github/workflows/bump-version.yml b/.github/workflows/bump-version.yml new file mode 100644 index 0000000..00e5e1f --- /dev/null +++ b/.github/workflows/bump-version.yml @@ -0,0 +1,67 @@ +name: Bump version.txt + +on: + push: + branches: [ "main" ] + # Avoid infinite loop when this workflow commits version.txt. + paths-ignore: + - "version.txt" + +concurrency: + group: bump-version-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: write + +jobs: + bump: + if: github.actor != 'github-actions[bot]' + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Bump patch version in version.txt + shell: bash + run: | + set -euo pipefail + + file="version.txt" + if [[ ! -f "$file" ]]; then + echo "0.0.1" > "$file" + else + v="$(tr -d '[:space:]' < "$file")" + if [[ "$v" =~ ^([0-9]+)\.([0-9]+)\.([0-9]+)$ ]]; then + major="${BASH_REMATCH[1]}" + minor="${BASH_REMATCH[2]}" + patch="${BASH_REMATCH[3]}" + patch="$((patch + 1))" + echo "${major}.${minor}.${patch}" > "$file" + else + echo "version.txt has invalid format: '$v' (expected x.y.z)" >&2 + exit 1 + fi + fi + + echo "New version: $(cat "$file")" + + - name: Commit and push + shell: bash + run: | + set -euo pipefail + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + + # If version didn't change for any reason, do nothing. + git add version.txt + if git diff --cached --quiet; then + echo "No changes to commit." + exit 0 + fi + + git commit -m "chore: bump version [skip ci]" + git push + diff --git a/.zshrc b/.zshrc index aee7a01..085329c 100644 --- a/.zshrc +++ b/.zshrc @@ -1,50 +1,75 @@ -# --- zshrc auto-updater (github.com/ushst/my-zsh) --- -typeset -gA UpdaterCfg -UpdaterCfg[repoRawBase]="https://raw.githubusercontent.com/ushst/my-zsh/main" -UpdaterCfg[remoteZshrcPath]=".zshrc" -UpdaterCfg[remoteVersionPath]="version.txt" -UpdaterCfg[checkIntervalSeconds]=21600 # 6 часов -UpdaterCfg[offlineRetrySeconds]=300 # повторная попытка через 5 минут, если сети нет -UpdaterCfg[networkCheckRetries]=3 -UpdaterCfg[networkRetryDelaySeconds]=1 -UpdaterCfg[networkCheckTimeoutSeconds]=2 +# --- my-zsh loader + auto-updater (github.com/ushst/my-zsh) --- +# This file is intended to stay small and stable. +# Your personal config should go to ~/.zshrc.local or ~/.zshrc.d/*.zsh -localZshrc="${HOME}/.zshrc" -localStateDir="${XDG_STATE_HOME:-${HOME}/.local/state}/zsh-updater" -mkdir -p "${localStateDir}" +typeset -gA MyZshUpdaterCfg +MyZshUpdaterCfg[repoRawBase]="https://raw.githubusercontent.com/ushst/my-zsh/main" +MyZshUpdaterCfg[remoteVersionPath]="version.txt" +MyZshUpdaterCfg[remoteManagedPath]="zshrc.managed" +MyZshUpdaterCfg[checkIntervalSeconds]=21600 # 6 hours +MyZshUpdaterCfg[offlineRetrySeconds]=300 # retry in 5 minutes if offline +MyZshUpdaterCfg[networkCheckRetries]=3 +MyZshUpdaterCfg[networkRetryDelaySeconds]=1 +MyZshUpdaterCfg[networkCheckTimeoutSeconds]=2 -lastCheckFile="${localStateDir}/last_check" -localVersionFile="${localStateDir}/local_version" -lockFile="${localStateDir}/lock" -deferredFlag="${localStateDir}/deferred_check_scheduled" +my_zsh_state_dir="${XDG_STATE_HOME:-${HOME}/.local/state}/my-zsh" +my_zsh_config_dir="${XDG_CONFIG_HOME:-${HOME}/.config}/my-zsh" +mkdir -p "${my_zsh_state_dir}" "${my_zsh_config_dir}" 2>/dev/null || true -get_local_version() { - [[ -f "${localVersionFile}" ]] && cat "${localVersionFile}" && return +my_zsh_last_check_file="${my_zsh_state_dir}/last_check" +my_zsh_local_version_file="${my_zsh_state_dir}/local_version" +my_zsh_lock_dir="${my_zsh_state_dir}/lockdir" +my_zsh_deferred_flag="${my_zsh_state_dir}/deferred_check_scheduled" + +my_zsh_managed_file="${my_zsh_config_dir}/zshrc.managed" +my_zsh_local_file="${HOME}/.zshrc.local" +my_zsh_local_dir="${HOME}/.zshrc.d" + +my_zsh_get_local_version() { + [[ -f "${my_zsh_local_version_file}" ]] && cat "${my_zsh_local_version_file}" && return echo "0.0.0" } -version_lt() { [[ "$(printf '%s\n%s\n' "$1" "$2" | sort -V | head -n1)" == "$1" && "$1" != "$2" ]]; } - -should_check_now() { - now=$(date +%s) - [[ ! -f "${lastCheckFile}" ]] && return 0 - last=$(<"${lastCheckFile}") - (( now - last >= UpdaterCfg[checkIntervalSeconds] )) +my_zsh_version_lt() { + [[ "$(printf '%s\n%s\n' "$1" "$2" | sort -V | head -n1)" == "$1" && "$1" != "$2" ]] } -with_lock() { exec 9>"${lockFile}"; flock -n 9 || return 1; "$@"; } +my_zsh_should_check_now() { + local now last + now=$(date +%s) + [[ ! -f "${my_zsh_last_check_file}" ]] && return 0 + last=$(<"${my_zsh_last_check_file}") + (( now - last >= MyZshUpdaterCfg[checkIntervalSeconds] )) +} -update_local_version_cache() { echo "$1" > "${localVersionFile}"; } +my_zsh_with_lock() { + # Portable lock (no flock dependency): mkdir is atomic on POSIX filesystems. + if mkdir "${my_zsh_lock_dir}" 2>/dev/null; then + "$@" + rmdir "${my_zsh_lock_dir}" 2>/dev/null || true + return 0 + fi + return 1 +} -network_available() { - local testUrl="${UpdaterCfg[repoRawBase]}/${UpdaterCfg[remoteVersionPath]}" - local retries=${UpdaterCfg[networkCheckRetries]} - local delay=${UpdaterCfg[networkRetryDelaySeconds]} - local timeout=${UpdaterCfg[networkCheckTimeoutSeconds]} +my_zsh_network_available() { + local testUrl retries delay timeout attempt + testUrl="${MyZshUpdaterCfg[repoRawBase]}/${MyZshUpdaterCfg[remoteVersionPath]}" + retries=${MyZshUpdaterCfg[networkCheckRetries]} + delay=${MyZshUpdaterCfg[networkRetryDelaySeconds]} + timeout=${MyZshUpdaterCfg[networkCheckTimeoutSeconds]} for (( attempt = 1; attempt <= retries; attempt++ )); do - if curl -fsI --max-time "${timeout}" "${testUrl}" >/dev/null 2>&1; then - return 0 + if command -v curl >/dev/null 2>&1; then + if curl -fsI --max-time "${timeout}" "${testUrl}" >/dev/null 2>&1; then + return 0 + fi + elif command -v wget >/dev/null 2>&1; then + if wget -q --spider --timeout="${timeout}" "${testUrl}" >/dev/null 2>&1; then + return 0 + fi + else + return 1 fi sleep "${delay}" done @@ -52,139 +77,109 @@ network_available() { return 1 } -schedule_offline_retry() { - local delay="${UpdaterCfg[offlineRetrySeconds]}" - [[ -f "${deferredFlag}" ]] && return 0 +my_zsh_update_local_version_cache() { echo "$1" > "${my_zsh_local_version_file}"; } - echo "${delay}" > "${deferredFlag}" +my_zsh_schedule_offline_retry() { + local delay="${MyZshUpdaterCfg[offlineRetrySeconds]}" + [[ -f "${my_zsh_deferred_flag}" ]] && return 0 + + echo "${delay}" > "${my_zsh_deferred_flag}" ( sleep "${delay}" - rm -f "${deferredFlag}" - zshrc_update_check 1 + rm -f "${my_zsh_deferred_flag}" + my_zsh_update_check 1 ) >/dev/null 2>&1 & } -zshrc_update_check() { - local force="${1:-0}" - - (( force )) || should_check_now || return 0 - - if ! network_available; then - echo "$(date +%s)" > "${lastCheckFile}" - [[ -t 1 ]] && echo "[zsh-updater] Сети нет. Повторим проверку позже." - schedule_offline_retry - return 0 +my_zsh_fetch_to() { + local url out + url="$1" + out="$2" + if command -v curl >/dev/null 2>&1; then + curl -fsSL "${url}" -o "${out}" + return $? fi - - with_lock _do_update_check - echo "$(date +%s)" > "${lastCheckFile}" + if command -v wget >/dev/null 2>&1; then + wget -q -O "${out}" "${url}" + return $? + fi + return 1 } -_do_update_check() { - local repo="${UpdaterCfg[repoRawBase]}" - local rverPath="${UpdaterCfg[remoteVersionPath]}" - local rcfgPath="${UpdaterCfg[remoteZshrcPath]}" +my_zsh_do_update_check() { + local repo remoteVersion localVersion tmpNew backup - remoteVersion="$(curl -fsSL "${repo}/${rverPath}" 2>/dev/null || true)" + repo="${MyZshUpdaterCfg[repoRawBase]}" + remoteVersion="$( (command -v curl >/dev/null 2>&1 && curl -fsSL "${repo}/${MyZshUpdaterCfg[remoteVersionPath]}" 2>/dev/null) || (command -v wget >/dev/null 2>&1 && wget -q -O - "${repo}/${MyZshUpdaterCfg[remoteVersionPath]}" 2>/dev/null) || true )" [[ -n "${remoteVersion}" ]] || return 0 - localVersion="$(get_local_version)" + localVersion="$(my_zsh_get_local_version)" - if version_lt "${localVersion}" "${remoteVersion}"; then - tmpNew="${localStateDir}/.zshrc.new" - backup="${localStateDir}/zshrc.backup.$(date +%Y%m%d-%H%M%S)" + # If managed file doesn't exist yet, treat it like version 0.0.0. + if [[ ! -f "${my_zsh_managed_file}" ]]; then + localVersion="0.0.0" + fi + + if my_zsh_version_lt "${localVersion}" "${remoteVersion}"; then + tmpNew="${my_zsh_state_dir}/zshrc.managed.new" + backup="${my_zsh_state_dir}/managed.backup.$(date +%Y%m%d-%H%M%S)" - # простая «полоса проверки» if [[ -t 1 ]]; then - echo -n "[zsh-updater] Проверка" + echo -n "[my-zsh] Checking updates" for i in 1 2 3; do sleep 0.2; echo -n "."; done echo fi - if curl -fsSL "${repo}/${rcfgPath}" -o "${tmpNew}"; then - cp -f "${localZshrc}" "${backup}" 2>/dev/null || true - mv -f "${tmpNew}" "${localZshrc}" - update_local_version_cache "${remoteVersion}" - [[ -t 1 ]] && echo "[zsh-updater] Обновлено до ${remoteVersion}. Бэкап: ${backup}. Перезапусти shell." + if my_zsh_fetch_to "${repo}/${MyZshUpdaterCfg[remoteManagedPath]}" "${tmpNew}"; then + cp -f "${my_zsh_managed_file}" "${backup}" 2>/dev/null || true + mv -f "${tmpNew}" "${my_zsh_managed_file}" + my_zsh_update_local_version_cache "${remoteVersion}" + [[ -t 1 ]] && echo "[my-zsh] Updated managed config to ${remoteVersion}. Backup: ${backup}. Restart shell." fi fi } -trigger_zshrc_update_check() { - # Проверяем в фоне, чтобы запуск shell не блокировался при отсутствии сети - ( zshrc_update_check "$@" ) &! -} +my_zsh_update_check() { + local force="${1:-0}" -trigger_zshrc_update_check -# --- end zshrc auto-updater --- + # Allow disabling auto-update. + [[ "${MY_ZSH_AUTOUPDATE:-1}" == "0" ]] && return 0 -# If you come from bash you might have to change your $PATH. -# export PATH=$HOME/bin:/usr/local/bin:$PATH + (( force )) || my_zsh_should_check_now || return 0 -# Path to your oh-my-zsh installation. -export ZSH="$HOME/.oh-my-zsh" - -# Theme -ZSH_THEME="avit" - -# Plugins -plugins=( - git - zsh-autosuggestions - zsh-syntax-highlighting -) -source $ZSH/oh-my-zsh.sh - -# User configuration -prompt_context() { - if [[ "$USER" != "$DEFAULT_USER" || -n "$SSH_CLIENT" ]]; then - prompt_segment black default "%(!.%{%F{yellow}%}.)" + if ! my_zsh_network_available; then + echo "$(date +%s)" > "${my_zsh_last_check_file}" + [[ -t 1 ]] && echo "[my-zsh] Offline. Will retry later." + my_zsh_schedule_offline_retry + return 0 fi + + my_zsh_with_lock my_zsh_do_update_check || true + echo "$(date +%s)" > "${my_zsh_last_check_file}" } -export NVM_DIR="$HOME/.nvm" -[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" -[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" - -# Custom aliases and functions -alias untargz='tar -xvzf' - -function a() { - case "$1" in - i) - shift - sudo apt install "$@" - ;; - u) - sudo apt update - ;; - up) - sudo apt upgrade -y - ;; - all) - sudo apt update && sudo apt upgrade -y - ;; - *) - echo "Неизвестная команда: a $1" - ;; - esac +my_zsh_trigger_update_check() { + # Run in background to avoid slowing shell startup. + ( my_zsh_update_check "$@" ) &! } -extract() { - if [ -f "$1" ]; then - case "$1" in - *.tar.bz2) tar xvjf "$1" ;; - *.tar.gz) tar xvzf "$1" ;; - *.tar.xz) tar xvJf "$1" ;; - *.tar) tar xvf "$1" ;; - *.gz) gunzip "$1" ;; - *.zip) unzip "$1" ;; - *.rar) unrar x "$1" ;; - *.7z) 7z x "$1" ;; - *) echo "Неизвестный формат: $1" ;; - esac - else - echo "Файл не найден: $1" - fi -} -alias x='extract' +# --- load managed config (auto-updated) --- +if [[ -f "${my_zsh_managed_file}" ]]; then + source "${my_zsh_managed_file}" +fi + +# --- load user overrides --- +if [[ -f "${my_zsh_local_file}" ]]; then + source "${my_zsh_local_file}" +fi + +if [[ -d "${my_zsh_local_dir}" ]]; then + for f in "${my_zsh_local_dir}"/*.zsh(N); do + source "$f" + done +fi + +# Update last: takes effect next shell. +my_zsh_trigger_update_check +# --- end my-zsh loader + auto-updater --- + diff --git a/README.md b/README.md index a00ba53..e4aff3a 100644 --- a/README.md +++ b/README.md @@ -3,9 +3,34 @@ `bash -c "$(curl -fsSL https://raw.githubusercontent.com/ushst/my-zsh/main/termux_zsh.sh)"` +## Как теперь хранить свои изменения +- `~/.zshrc` это загрузчик + автообновление managed-конфига. +- Основная конфигурация обновляется в `~/.config/my-zsh/zshrc.managed`. +- Твои личные настройки добавляй в `~/.zshrc.local` или в файлы `~/.zshrc.d/*.zsh` (они не будут перезаписываться). +- Установщик ставит `~/.zshrc` один раз. Повторный запуск `install.sh`/`termux_zsh.sh` не перезапишет его, если там уже my-zsh loader. + +## Отключить автообновление +Добавь в `~/.zshrc.local`: +`export MY_ZSH_AUTOUPDATE=0` + +# MICRO +Конфиг micro лежит в репо: `.microrc` и `.config/micro/syntax/shell.yaml`. + +Установить вручную: +`wget -O ~/.microrc https://raw.githubusercontent.com/ushst/my-zsh/main/.microrc` +`mkdir -p ~/.config/micro/syntax && wget -O ~/.config/micro/syntax/shell.yaml https://raw.githubusercontent.com/ushst/my-zsh/main/.config/micro/syntax/shell.yaml` + +Или через установщик: он спросит, ставить ли micro-конфиг. +Можно без вопросов: +`MY_ZSH_INSTALL_MICRO=1 bash -c "$(curl -fsSL https://raw.githubusercontent.com/ushst/my-zsh/main/install.sh)"` + # NANO `sudo wget -O ~/.nanorc https://raw.githubusercontent.com/ushst/my-zsh/main/.nanorc` # MSFCONSOLE `mkdir -p ~/.msf4 && wget -O ~/.msf4/msfconsole.rc https://raw.githubusercontent.com/ushst/my-zsh/main/msfconsole.rc` + +Или через установщик: он спросит, ставить ли msfconsole-конфиг. +Можно без вопросов: +`MY_ZSH_INSTALL_MSFCONSOLE=1 bash -c "$(curl -fsSL https://raw.githubusercontent.com/ushst/my-zsh/main/install.sh)"` diff --git a/install.sh b/install.sh index 0fb3207..b0b99cf 100644 --- a/install.sh +++ b/install.sh @@ -5,6 +5,7 @@ set -e ZSH_DIR="${HOME}/.oh-my-zsh" ZDOTDIR="${HOME}" ZSHRC_URL="https://raw.githubusercontent.com/ushst/my-zsh/main/.zshrc" +ZSHRC_MANAGED_URL="https://raw.githubusercontent.com/ushst/my-zsh/main/zshrc.managed" PLUGINS_REPO1="https://github.com/zsh-users/zsh-autosuggestions" PLUGINS_REPO2="https://github.com/zsh-users/zsh-syntax-highlighting.git" # ============================= @@ -23,8 +24,81 @@ echo "[*] Установка плагинов..." git clone "$PLUGINS_REPO1" ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions || true git clone "$PLUGINS_REPO2" ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting || true -echo "[*] Загрузка конфигурации .zshrc..." -wget -O "${ZDOTDIR}/.zshrc" "$ZSHRC_URL" +echo "[*] Установка загрузчика .zshrc (my-zsh)..." +# Ставим loader один раз: если он уже установлен, не перезаписываем ~/.zshrc. +if [ -f "${ZDOTDIR}/.zshrc" ] && grep -q "my-zsh loader + auto-updater" "${ZDOTDIR}/.zshrc" 2>/dev/null; then + echo "[*] ~/.zshrc уже установлен как my-zsh loader — пропускаю." +else + # Не теряем существующий ~/.zshrc: делаем бэкап, если он есть. + if [ -f "${ZDOTDIR}/.zshrc" ]; then + cp -f "${ZDOTDIR}/.zshrc" "${ZDOTDIR}/.zshrc.backup.$(date +%Y%m%d-%H%M%S)" || true + fi + wget -O "${ZDOTDIR}/.zshrc" "$ZSHRC_URL" +fi + +echo "[*] Загрузка managed-конфига (auto-updated)..." +mkdir -p "${HOME}/.config/my-zsh" || true +wget -O "${HOME}/.config/my-zsh/zshrc.managed" "$ZSHRC_MANAGED_URL" + +echo "[*] Создаю файл для пользовательских правок: ~/.zshrc.local (если его нет)..." +if [ ! -f "${HOME}/.zshrc.local" ]; then + cat > "${HOME}/.zshrc.local" <<'EOF' +# Your custom zsh config goes here. +# This file will NOT be overwritten by my-zsh updates. +EOF +fi + +# ========= Optional configs ========= +ask_yes_no() { + # Usage: ask_yes_no "Question" "N|Y" + local question default reply + question="$1" + default="${2:-N}" + + # Non-interactive shell: honor default. + if [ ! -t 0 ]; then + [ "${default}" = "Y" ] && return 0 || return 1 + fi + + read -r -p "${question} [y/N]: " reply + reply="${reply:-$default}" + case "$reply" in + y|Y|yes|YES) return 0 ;; + *) return 1 ;; + esac +} + +backup_if_exists() { + local p ts + p="$1" + ts="$(date +%Y%m%d-%H%M%S)" + if [ -f "$p" ]; then + cp -f "$p" "$p.backup.$ts" 2>/dev/null || true + fi +} + +# Micro +MICRORC_URL="https://raw.githubusercontent.com/ushst/my-zsh/main/.microrc" +MICRO_SHELL_SYNTAX_URL="https://raw.githubusercontent.com/ushst/my-zsh/main/.config/micro/syntax/shell.yaml" + +if [ "${MY_ZSH_INSTALL_MICRO:-}" = "1" ] || ( [ "${MY_ZSH_INSTALL_MICRO:-}" != "0" ] && ask_yes_no "[?] Установить конфиг для micro ( .microrc + syntax )?" "N" ); then + echo "[*] Установка конфига micro..." + backup_if_exists "${HOME}/.microrc" + wget -O "${HOME}/.microrc" "$MICRORC_URL" + mkdir -p "${HOME}/.config/micro/syntax" || true + backup_if_exists "${HOME}/.config/micro/syntax/shell.yaml" + wget -O "${HOME}/.config/micro/syntax/shell.yaml" "$MICRO_SHELL_SYNTAX_URL" +fi + +# msfconsole +MSFCONSOLE_RC_URL="https://raw.githubusercontent.com/ushst/my-zsh/main/msfconsole.rc" + +if [ "${MY_ZSH_INSTALL_MSFCONSOLE:-}" = "1" ] || ( [ "${MY_ZSH_INSTALL_MSFCONSOLE:-}" != "0" ] && ask_yes_no "[?] Установить конфиг для msfconsole ( alias s -> search )?" "N" ); then + echo "[*] Установка конфига msfconsole..." + mkdir -p "${HOME}/.msf4" || true + backup_if_exists "${HOME}/.msf4/msfconsole.rc" + wget -O "${HOME}/.msf4/msfconsole.rc" "$MSFCONSOLE_RC_URL" +fi echo "[*] Смена стандартной оболочки на zsh..." chsh -s "$(which zsh)" "$USER" diff --git a/termux_zsh.sh b/termux_zsh.sh index 9670b1c..8644c20 100644 --- a/termux_zsh.sh +++ b/termux_zsh.sh @@ -5,6 +5,7 @@ set -e ZSH_DIR="${HOME}/.oh-my-zsh" ZDOTDIR="${HOME}" ZSHRC_URL="https://raw.githubusercontent.com/ushst/my-zsh/main/.zshrc" +ZSHRC_MANAGED_URL="https://raw.githubusercontent.com/ushst/my-zsh/main/zshrc.managed" PLUGINS_REPO1="https://github.com/zsh-users/zsh-autosuggestions" PLUGINS_REPO2="https://github.com/zsh-users/zsh-syntax-highlighting.git" # ============================= @@ -23,22 +24,95 @@ echo "[*] Установка плагинов..." git clone "$PLUGINS_REPO1" ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions || true git clone "$PLUGINS_REPO2" ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting || true -echo "[*] Загрузка конфигурации .zshrc..." -wget -O "${ZDOTDIR}/.zshrc" "$ZSHRC_URL" +echo "[*] Установка загрузчика .zshrc (my-zsh)..." +# Ставим loader один раз: если он уже установлен, не перезаписываем ~/.zshrc. +if [ -f "${ZDOTDIR}/.zshrc" ] && grep -q "my-zsh loader + auto-updater" "${ZDOTDIR}/.zshrc" 2>/dev/null; then + echo "[*] ~/.zshrc уже установлен как my-zsh loader — пропускаю." +else + # Не теряем существующий ~/.zshrc: делаем бэкап, если он есть. + if [ -f "${ZDOTDIR}/.zshrc" ]; then + cp -f "${ZDOTDIR}/.zshrc" "${ZDOTDIR}/.zshrc.backup.$(date +%Y%m%d-%H%M%S)" || true + fi + wget -O "${ZDOTDIR}/.zshrc" "$ZSHRC_URL" +fi -# Если установка проходит в Termux — заменим "sudo apt install" на "apt install" в .zshrc +echo "[*] Загрузка managed-конфига (auto-updated)..." +mkdir -p "${HOME}/.config/my-zsh" || true +wget -O "${HOME}/.config/my-zsh/zshrc.managed" "$ZSHRC_MANAGED_URL" + +# Если установка проходит в Termux — заменим "sudo apt install" на "apt install" в managed-конфиге if [ -n "$TERMUX_VERSION" ] || ( [ -n "$PREFIX" ] && [[ "$PREFIX" == *"com.termux"* ]] ); then - echo "[*] Обнаружен Termux — адаптирую .zshrc (замена 'sudo apt install' -> 'apt install')..." - if grep -q "sudo apt install" "${ZDOTDIR}/.zshrc" 2>/dev/null; then + echo "[*] Обнаружен Termux — адаптирую managed-конфиг (замена 'sudo apt install' -> 'apt install')..." + if grep -q "sudo apt install" "${HOME}/.config/my-zsh/zshrc.managed" 2>/dev/null; then # делаем inplace замену и удаляем бэкап, если он создастся - sed -i.bak 's/sudo apt install/apt install/g' "${ZDOTDIR}/.zshrc" || true - rm -f "${ZDOTDIR}/.zshrc.bak" || true + sed -i.bak 's/sudo apt install/apt install/g' "${HOME}/.config/my-zsh/zshrc.managed" || true + rm -f "${HOME}/.config/my-zsh/zshrc.managed.bak" || true echo "[*] Замена выполнена." else - echo "[*] В .zshrc не найдено 'sudo apt install' — ничего менять не нужно." + echo "[*] В managed-конфиге не найдено 'sudo apt install' — ничего менять не нужно." fi fi +echo "[*] Создаю файл для пользовательских правок: ~/.zshrc.local (если его нет)..." +if [ ! -f "${HOME}/.zshrc.local" ]; then + cat > "${HOME}/.zshrc.local" <<'EOF' +# Your custom zsh config goes here. +# This file will NOT be overwritten by my-zsh updates. +EOF +fi + +# ========= Optional configs ========= +ask_yes_no() { + # Usage: ask_yes_no "Question" "N|Y" + local question default reply + question="$1" + default="${2:-N}" + + # Non-interactive shell: honor default. + if [ ! -t 0 ]; then + [ "${default}" = "Y" ] && return 0 || return 1 + fi + + read -r -p "${question} [y/N]: " reply + reply="${reply:-$default}" + case "$reply" in + y|Y|yes|YES) return 0 ;; + *) return 1 ;; + esac +} + +backup_if_exists() { + local p ts + p="$1" + ts="$(date +%Y%m%d-%H%M%S)" + if [ -f "$p" ]; then + cp -f "$p" "$p.backup.$ts" 2>/dev/null || true + fi +} + +# Micro +MICRORC_URL="https://raw.githubusercontent.com/ushst/my-zsh/main/.microrc" +MICRO_SHELL_SYNTAX_URL="https://raw.githubusercontent.com/ushst/my-zsh/main/.config/micro/syntax/shell.yaml" + +if [ "${MY_ZSH_INSTALL_MICRO:-}" = "1" ] || ( [ "${MY_ZSH_INSTALL_MICRO:-}" != "0" ] && ask_yes_no "[?] Установить конфиг для micro ( .microrc + syntax )?" "N" ); then + echo "[*] Установка конфига micro..." + backup_if_exists "${HOME}/.microrc" + wget -O "${HOME}/.microrc" "$MICRORC_URL" + mkdir -p "${HOME}/.config/micro/syntax" || true + backup_if_exists "${HOME}/.config/micro/syntax/shell.yaml" + wget -O "${HOME}/.config/micro/syntax/shell.yaml" "$MICRO_SHELL_SYNTAX_URL" +fi + +# msfconsole +MSFCONSOLE_RC_URL="https://raw.githubusercontent.com/ushst/my-zsh/main/msfconsole.rc" + +if [ "${MY_ZSH_INSTALL_MSFCONSOLE:-}" = "1" ] || ( [ "${MY_ZSH_INSTALL_MSFCONSOLE:-}" != "0" ] && ask_yes_no "[?] Установить конфиг для msfconsole ( alias s -> search )?" "N" ); then + echo "[*] Установка конфига msfconsole..." + mkdir -p "${HOME}/.msf4" || true + backup_if_exists "${HOME}/.msf4/msfconsole.rc" + wget -O "${HOME}/.msf4/msfconsole.rc" "$MSFCONSOLE_RC_URL" +fi + echo "[*] Смена стандартной оболочки на zsh..." chsh -s "$(which zsh)" "$USER" diff --git a/version.txt b/version.txt index 26aaba0..f0bb29e 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.2.0 +1.3.0 diff --git a/zshrc.managed b/zshrc.managed new file mode 100644 index 0000000..35eddfb --- /dev/null +++ b/zshrc.managed @@ -0,0 +1,76 @@ +# Managed by github.com/ushst/my-zsh (do not edit; it may be overwritten). +# Put your changes into ~/.zshrc.local or ~/.zshrc.d/*.zsh + +# If you come from bash you might have to change your $PATH. +# export PATH=$HOME/bin:/usr/local/bin:$PATH + +# Path to your oh-my-zsh installation. +export ZSH="$HOME/.oh-my-zsh" + +# Theme +ZSH_THEME="avit" + +# Plugins +plugins=( + git + zsh-autosuggestions + zsh-syntax-highlighting +) + +source "$ZSH/oh-my-zsh.sh" + +# User configuration +prompt_context() { + if [[ "$USER" != "$DEFAULT_USER" || -n "$SSH_CLIENT" ]]; then + prompt_segment black default "%(!.%{%F{yellow}%}.)" + fi +} + +export NVM_DIR="$HOME/.nvm" +[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" +[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" + +# Custom aliases and functions +alias untargz='tar -xvzf' + +function a() { + case "$1" in + i) + shift + sudo apt install "$@" + ;; + u) + sudo apt update + ;; + up) + sudo apt upgrade -y + ;; + all) + sudo apt update && sudo apt upgrade -y + ;; + *) + echo "Неизвестная команда: a $1" + ;; + esac +} + +extract() { + if [ -f "$1" ]; then + case "$1" in + *.tar.bz2) tar xvjf "$1" ;; + *.tar.gz) tar xvzf "$1" ;; + *.tar.xz) tar xvJf "$1" ;; + *.tar) tar xvf "$1" ;; + *.gz) gunzip "$1" ;; + *.zip) unzip "$1" ;; + *.rar) unrar x "$1" ;; + *.7z) 7z x "$1" ;; + *) echo "Неизвестный формат: $1" ;; + esac + else + echo "Файл не найден: $1" + fi +} + +alias x='extract' +