mirror of
https://github.com/ohmyzsh/ohmyzsh.git
synced 2026-03-27 03:14:56 +01:00
Merge 2138e2662b into 11c1718983
This commit is contained in:
commit
d6c20c01c2
3 changed files with 555 additions and 0 deletions
517
tools/UPDATE_PROCESS.md
Normal file
517
tools/UPDATE_PROCESS.md
Normal file
|
|
@ -0,0 +1,517 @@
|
|||
# check_for_upgrade.sh: Update Process
|
||||
|
||||
## Visual State Diagram
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> Bootstrap
|
||||
|
||||
state Bootstrap {
|
||||
[*] --> CheckLegacyUpdateFile
|
||||
CheckLegacyUpdateFile: check [[ -f ~/.zsh-update && ! -f $ZSH_CACHE_DIR/.zsh-update ]]
|
||||
CheckLegacyUpdateFile --> MigrateLegacyFile: TRUE
|
||||
CheckLegacyUpdateFile --> LoadMode: FALSE
|
||||
MigrateLegacyFile: mv ~/.zsh-update $ZSH_CACHE_DIR/.zsh-update
|
||||
MigrateLegacyFile --> LoadMode
|
||||
|
||||
LoadMode: read update mode from zstyle
|
||||
LoadMode --> LegacyModeFallback: fail
|
||||
LegacyModeFallback: set update_mode=prompt
|
||||
LegacyModeFallback --> LegacyPromptFlag
|
||||
LegacyPromptFlag: evaluate DISABLE_UPDATE_PROMPT
|
||||
LegacyPromptFlag --> LegacyAutoFlag
|
||||
LegacyAutoFlag: evaluate DISABLE_AUTO_UPDATE
|
||||
LegacyAutoFlag --> PreFlightGate
|
||||
LoadMode --> PreFlightGate: success
|
||||
}
|
||||
|
||||
PreFlightGate: aggregated early-return gate
|
||||
PreFlightGate --> ExitNoUpdate: mode=disabled
|
||||
PreFlightGate --> ExitNoUpdate: write permission or owner check failed
|
||||
PreFlightGate --> ExitNoUpdate: tty gate failed
|
||||
PreFlightGate --> ExitNoUpdate: git command unavailable
|
||||
PreFlightGate --> ExitNoUpdate: repository check failed
|
||||
PreFlightGate --> ModeDispatch: all checks pass
|
||||
ExitNoUpdate: unset update_mode; return
|
||||
|
||||
state ModeDispatch {
|
||||
[*] --> SetupBackgroundHooks: mode=background-alpha
|
||||
[*] --> RunHandleUpdate: otherwise
|
||||
}
|
||||
|
||||
SetupBackgroundHooks: autoload -Uz add-zsh-hook
|
||||
SetupBackgroundHooks --> RegisterBgPrecmd
|
||||
RegisterBgPrecmd: add-zsh-hook precmd _omz_bg_update
|
||||
RegisterBgPrecmd --> BackgroundStatusHook
|
||||
|
||||
RunHandleUpdate --> HandleUpdateCore
|
||||
|
||||
state HandleUpdateCore {
|
||||
[*] --> LockCleanupCheck
|
||||
LockCleanupCheck: load datetime and read lock mtime
|
||||
LockCleanupCheck --> CheckStaleAge: lock exists
|
||||
LockCleanupCheck --> AcquireLock: no lock
|
||||
|
||||
CheckStaleAge: stale if lock older than 24h
|
||||
CheckStaleAge --> RemoveStaleLock: TRUE
|
||||
CheckStaleAge --> AcquireLock: FALSE
|
||||
|
||||
RemoveStaleLock: rm -rf $ZSH/log/update.lock
|
||||
RemoveStaleLock --> AcquireLock
|
||||
|
||||
AcquireLock: mkdir $ZSH/log/update.lock
|
||||
AcquireLock --> ExitHandle: fail (lock exists)
|
||||
AcquireLock --> InstallTrap: success
|
||||
|
||||
InstallTrap: install trap to cleanup lock and functions
|
||||
InstallTrap --> LoadStatusFile
|
||||
|
||||
LoadStatusFile: source status file and validate last epoch
|
||||
LoadStatusFile --> InitStatusFile: fail or empty LAST_EPOCH
|
||||
LoadStatusFile --> FrequencyCheck: success
|
||||
|
||||
InitStatusFile: update_last_updated_file
|
||||
InitStatusFile --> ExitHandle
|
||||
|
||||
FrequencyCheck: resolve frequency from zstyle or default
|
||||
FrequencyCheck --> PeriodElapsed
|
||||
|
||||
PeriodElapsed: enough days elapsed since last check
|
||||
PeriodElapsed --> RepoCheck: TRUE
|
||||
PeriodElapsed --> ExitHandle: FALSE
|
||||
|
||||
RepoCheck: verify ZSH path is a git repository
|
||||
RepoCheck --> CheckUpdateAvailable: success
|
||||
RepoCheck --> ExitHandle: fail
|
||||
|
||||
CheckUpdateAvailable --> ReminderOrTypedInput: update available (return 0)
|
||||
CheckUpdateAvailable --> ExitHandleWithTimestamp: no update (return 1)
|
||||
|
||||
ExitHandleWithTimestamp: update_last_updated_file
|
||||
ExitHandleWithTimestamp --> ExitHandle
|
||||
|
||||
ReminderOrTypedInput --> ReminderExit: mode=reminder
|
||||
ReminderOrTypedInput --> TypedInputCheck: mode!=background-alpha
|
||||
ReminderOrTypedInput --> ModeAutoGate: mode=background-alpha
|
||||
|
||||
TypedInputCheck: detect pending typed input from terminal
|
||||
TypedInputCheck --> ReminderExit: input detected
|
||||
TypedInputCheck --> ModeAutoGate: no input
|
||||
|
||||
ReminderExit: echo reminder message
|
||||
ReminderExit --> ExitHandle
|
||||
|
||||
ModeAutoGate --> RunUpgrade: mode is auto or background alpha
|
||||
ModeAutoGate --> PromptUser: mode=prompt
|
||||
|
||||
PromptUser: read -r -k 1 option
|
||||
PromptUser --> RunUpgrade: yes or enter
|
||||
PromptUser --> WriteTimestampOnly: [nN]
|
||||
PromptUser --> ManualMsg: other
|
||||
|
||||
WriteTimestampOnly: update_last_updated_file
|
||||
WriteTimestampOnly --> ManualMsg
|
||||
|
||||
ManualMsg: echo manual update hint
|
||||
ManualMsg --> ExitHandle
|
||||
|
||||
RunUpgrade --> ExitHandle
|
||||
ExitHandle --> [*]
|
||||
}
|
||||
|
||||
state CheckUpdateAvailable {
|
||||
[*] --> ReadBranch
|
||||
ReadBranch: read configured branch default master
|
||||
ReadBranch --> ReadRemote
|
||||
ReadRemote: read configured remote default origin
|
||||
ReadRemote --> ReadRemoteUrl
|
||||
ReadRemoteUrl: read remote URL from git config
|
||||
ReadRemoteUrl --> ParseRemoteStyle
|
||||
|
||||
ParseRemoteStyle --> AssumeUpdateYes: non-GitHub remote
|
||||
ParseRemoteStyle --> ValidateOfficialRepo: GitHub URL
|
||||
|
||||
ValidateOfficialRepo --> AssumeUpdateYes: repo != ohmyzsh/ohmyzsh
|
||||
ValidateOfficialRepo --> LocalHeadCheck: repo == ohmyzsh/ohmyzsh
|
||||
|
||||
LocalHeadCheck: resolve local branch HEAD hash
|
||||
LocalHeadCheck --> AssumeUpdateYes: fail
|
||||
LocalHeadCheck --> RemoteHeadFetch: success
|
||||
|
||||
RemoteHeadFetch --> UseCurl: curl available
|
||||
RemoteHeadFetch --> UseWget: wget available
|
||||
RemoteHeadFetch --> UseFetch: fetch available
|
||||
RemoteHeadFetch --> AssumeUpdateNo: none available
|
||||
|
||||
UseCurl: fetch remote head using curl
|
||||
UseWget: fetch remote head using wget
|
||||
UseFetch: fetch remote head using fetch utility
|
||||
|
||||
UseCurl --> CompareHeads: success
|
||||
UseCurl --> AssumeUpdateNo: fail
|
||||
UseWget --> CompareHeads: success
|
||||
UseWget --> AssumeUpdateNo: fail
|
||||
UseFetch --> CompareHeads: success
|
||||
UseFetch --> AssumeUpdateNo: fail
|
||||
|
||||
CompareHeads: compare local and remote head hashes
|
||||
CompareHeads --> MergeBaseCheck: TRUE
|
||||
CompareHeads --> AssumeUpdateNo: FALSE
|
||||
|
||||
MergeBaseCheck: compute merge base from both hashes
|
||||
MergeBaseCheck --> AssumeUpdateYes: fail
|
||||
MergeBaseCheck --> EvaluateAncestry: success
|
||||
|
||||
EvaluateAncestry: decide if local is behind remote
|
||||
EvaluateAncestry --> AssumeUpdateYes: TRUE
|
||||
EvaluateAncestry --> AssumeUpdateNo: FALSE
|
||||
|
||||
AssumeUpdateYes --> [*]
|
||||
AssumeUpdateNo --> [*]
|
||||
}
|
||||
|
||||
state RunUpgrade {
|
||||
[*] --> ResolveVerbose
|
||||
ResolveVerbose: resolve verbose mode from zstyle
|
||||
ResolveVerbose --> CheckP10kPrompt
|
||||
|
||||
CheckP10kPrompt: check instant prompt setting
|
||||
CheckP10kPrompt --> ForceSilent: TRUE
|
||||
CheckP10kPrompt --> UpgradePath: FALSE
|
||||
|
||||
ForceSilent: verbose_mode=silent
|
||||
ForceSilent --> UpgradePath
|
||||
|
||||
UpgradePath --> InteractiveUpgrade: mode != background-alpha
|
||||
UpgradePath --> SilentCaptureUpgrade: mode=background-alpha
|
||||
|
||||
InteractiveUpgrade: run upgrade script with interactive verbosity
|
||||
InteractiveUpgrade --> UpdateTimestampOnly: success
|
||||
InteractiveUpgrade --> SilentCaptureUpgrade: fail
|
||||
|
||||
SilentCaptureUpgrade: run upgrade script and capture output
|
||||
SilentCaptureUpgrade --> UpdateSuccessStatus: success
|
||||
SilentCaptureUpgrade --> UpdateErrorStatus: fail
|
||||
|
||||
UpdateTimestampOnly: update_last_updated_file
|
||||
UpdateSuccessStatus: write status file with success
|
||||
UpdateErrorStatus: write status file with captured error
|
||||
|
||||
UpdateTimestampOnly --> [*]
|
||||
UpdateSuccessStatus --> [*]
|
||||
UpdateErrorStatus --> [*]
|
||||
}
|
||||
|
||||
state BackgroundStatusHook {
|
||||
[*] --> RegisterStatusHook
|
||||
RegisterStatusHook: register precmd status hook
|
||||
RegisterStatusHook --> PollStatus
|
||||
|
||||
PollStatus: poll status file on each precmd
|
||||
PollStatus --> WaitMore: status file not ready
|
||||
PollStatus --> PrintSuccess: EXIT_STATUS==0
|
||||
PollStatus --> PrintFailure: EXIT_STATUS!=0
|
||||
|
||||
WaitMore: return 1 (continue polling)
|
||||
WaitMore --> [*]
|
||||
|
||||
PrintSuccess: print success message
|
||||
PrintSuccess --> CleanupStatusHook
|
||||
|
||||
PrintFailure: print error message with details
|
||||
PrintFailure --> CleanupStatusHook
|
||||
|
||||
CleanupStatusHook: reset status file and deregister status hook
|
||||
CleanupStatusHook --> [*]
|
||||
}
|
||||
|
||||
SetupBackgroundHooks --> BackgroundStatusHook
|
||||
ExitNoUpdate --> [*]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## State Transition Table
|
||||
|
||||
### BOOTSTRAP Phase
|
||||
|
||||
| State | Condition | Command/Check | Next State |
|
||||
|-------|-----------|---|---|
|
||||
| START | — | — | CheckLegacyUpdateFile |
|
||||
| CheckLegacyUpdateFile | `[[ -f ~/.zsh-update && ! -f $ZSH_CACHE_DIR/.zsh-update ]]` | TRUE | MigrateLegacyFile |
|
||||
| CheckLegacyUpdateFile | — | FALSE (no legacy file) | LoadMode |
|
||||
| MigrateLegacyFile | — | `mv ~/.zsh-update $ZSH_CACHE_DIR/.zsh-update` | LoadMode |
|
||||
| LoadMode | `zstyle -s ':omz:update' mode update_mode` | SUCCESS | PreFlightGate |
|
||||
| LoadMode | — | FAIL (zstyle missing) | LegacyModeFallback |
|
||||
| LegacyModeFallback | — | `set update_mode=prompt` (default) | LegacyPromptFlag |
|
||||
| LegacyPromptFlag | `[[ $DISABLE_UPDATE_PROMPT != true ]]` | TRUE | LegacyAutoFlag |
|
||||
| LegacyPromptFlag | — | FALSE | SetAutoMode |
|
||||
| SetAutoMode | — | `update_mode=auto` | LegacyAutoFlag |
|
||||
| LegacyAutoFlag | `[[ $DISABLE_AUTO_UPDATE != true ]]` | TRUE | PreFlightGate |
|
||||
| LegacyAutoFlag | — | FALSE | SetDisabledMode |
|
||||
| SetDisabledMode | — | `update_mode=disabled` | PreFlightGate |
|
||||
|
||||
---
|
||||
|
||||
### PRE-FLIGHT GATE (Early Exit Checks)
|
||||
|
||||
| State | Condition | Command/Check | Next State |
|
||||
|-------|-----------|---|---|
|
||||
| PreFlightGate | `[[ $update_mode = disabled ]]` | TRUE | ExitNoUpdate |
|
||||
| PreFlightGate | `[[ ! -w $ZSH \|\| ! -O $ZSH ]]` | TRUE | ExitNoUpdate |
|
||||
| PreFlightGate | `[[ ! -t 1 && ${POWERLEVEL9K_INSTANT_PROMPT:-off} == off ]]` | TRUE | ExitNoUpdate |
|
||||
| PreFlightGate | `! command git --version 2>&1 >/dev/null` | TRUE | ExitNoUpdate |
|
||||
| PreFlightGate | `(cd $ZSH; ! git rev-parse --is-inside-work-tree &>/dev/null)` | TRUE | ExitNoUpdate |
|
||||
| PreFlightGate | — | ALL FALSE | ModeDispatch |
|
||||
| ExitNoUpdate | — | `unset update_mode; return` | [*] |
|
||||
|
||||
---
|
||||
|
||||
### MODE DISPATCH & BACKGROUND SETUP
|
||||
|
||||
| State | Condition | Command/Check | Next State |
|
||||
|-------|-----------|---|---|
|
||||
| ModeDispatch | `[[ $update_mode = background-alpha ]]` | TRUE | SetupBackgroundHooks |
|
||||
| ModeDispatch | — | FALSE | RunHandleUpdate |
|
||||
| SetupBackgroundHooks | — | `autoload -Uz add-zsh-hook` | RegisterBgPrecmd |
|
||||
| RegisterBgPrecmd | — | `add-zsh-hook precmd _omz_bg_update` | BackgroundStatusHook |
|
||||
| RunHandleUpdate | — | enter HandleUpdateCore | HandleUpdateCore |
|
||||
|
||||
---
|
||||
|
||||
### HANDLE UPDATE CORE (Main Logic)
|
||||
|
||||
#### Lock Management
|
||||
| State | Condition | Command/Check | Next State |
|
||||
|-------|-----------|---|---|
|
||||
| HandleUpdateCore | — | `zmodload zsh/datetime` | LockCleanupCheck |
|
||||
| LockCleanupCheck | `zstat +mtime $ZSH/log/update.lock 2>/dev/null` | SUCCESS (mtime exists) | CheckStaleAge |
|
||||
| LockCleanupCheck | — | FAIL (no lock file) | AcquireLock |
|
||||
| CheckStaleAge | `(mtime + 86400) < EPOCHSECONDS` | TRUE (older than 24h) | RemoveStaleLock |
|
||||
| CheckStaleAge | — | FALSE | AcquireLock |
|
||||
| RemoveStaleLock | — | `rm -rf $ZSH/log/update.lock` | AcquireLock |
|
||||
| AcquireLock | `mkdir $ZSH/log/update.lock 2>/dev/null` | SUCCESS | InstallTrap |
|
||||
| AcquireLock | — | FAIL (lock exists) | ExitHandle |
|
||||
| InstallTrap | — | `trap "...cleanup..." EXIT INT QUIT` | LoadStatusFile |
|
||||
|
||||
#### Status File Validation
|
||||
| State | Condition | Command/Check | Next State |
|
||||
|-------|-----------|---|---|
|
||||
| LoadStatusFile | `source $ZSH_CACHE_DIR/.zsh-update 2>/dev/null && [[ -n $LAST_EPOCH ]]` | SUCCESS | FrequencyCheck |
|
||||
| LoadStatusFile | — | FAIL or missing LAST_EPOCH | InitStatusFile |
|
||||
| InitStatusFile | — | `update_last_updated_file` (writes LAST_EPOCH) | ExitHandle |
|
||||
|
||||
#### Frequency Check
|
||||
| State | Condition | Command/Check | Next State |
|
||||
|-------|-----------|---|---|
|
||||
| FrequencyCheck | `zstyle -s ':omz:update' frequency epoch_target` | SUCCESS | PeriodElapsed |
|
||||
| FrequencyCheck | — | FAIL | SetDefaultFrequency |
|
||||
| SetDefaultFrequency | — | `epoch_target=${UPDATE_ZSH_DAYS:-13}` | PeriodElapsed |
|
||||
| PeriodElapsed | `(current_epoch - LAST_EPOCH) >= epoch_target` | TRUE | RepoCheck |
|
||||
| PeriodElapsed | — | FALSE | ExitHandle |
|
||||
|
||||
#### Git Repository Check
|
||||
| State | Condition | Command/Check | Next State |
|
||||
|-------|-----------|---|---|
|
||||
| RepoCheck | `(cd $ZSH && LANG= git rev-parse)` | SUCCESS | CheckUpdateAvailable |
|
||||
| RepoCheck | — | FAIL | ExitHandle |
|
||||
|
||||
#### Post-Update Decision
|
||||
| State | Condition | Command/Check | Next State |
|
||||
|-------|-----------|---|---|
|
||||
| CheckUpdateAvailable | — | function returns TRUE | ReminderOrTypedInput |
|
||||
| CheckUpdateAvailable | — | function returns FALSE | ExitHandleWithTimestamp |
|
||||
| ExitHandleWithTimestamp | — | `update_last_updated_file` | ExitHandle |
|
||||
|
||||
---
|
||||
|
||||
### REMINDER OR INPUT CHECK
|
||||
|
||||
| State | Condition | Command/Check | Next State |
|
||||
|-------|-----------|---|---|
|
||||
| ReminderOrTypedInput | `[[ $update_mode = reminder ]]` | TRUE | ReminderExit |
|
||||
| ReminderOrTypedInput | `[[ $update_mode != background-alpha ]]` | TRUE | TypedInputCheck |
|
||||
| ReminderOrTypedInput | — | FALSE (background-alpha) | ModeAutoGate |
|
||||
| TypedInputCheck | `has_typed_input` | TRUE | ReminderExit |
|
||||
| TypedInputCheck | — | FALSE | ModeAutoGate |
|
||||
| ReminderExit | — | `echo "[oh-my-zsh] It's time to update!..."` | ExitHandle |
|
||||
|
||||
**has_typed_input internals:**
|
||||
- `stty --save`
|
||||
- `stty -icanon`
|
||||
- `zselect -t 0 -r 0` (poll stdin fd 0)
|
||||
- `stty $termios` (restore)
|
||||
|
||||
---
|
||||
|
||||
### UPDATE MODE GATE
|
||||
|
||||
| State | Condition | Command/Check | Next State |
|
||||
|-------|-----------|---|---|
|
||||
| ModeAutoGate | `[[ $update_mode = (auto\|background-alpha) ]]` | TRUE | RunUpgrade |
|
||||
| ModeAutoGate | — | FALSE (prompt) | PromptUser |
|
||||
|
||||
#### Prompt Mode
|
||||
| State | Condition | Command/Check | Next State |
|
||||
|-------|-----------|---|---|
|
||||
| PromptUser | — | `read -r -k 1 option` | ProcessResponse |
|
||||
| ProcessResponse | `[[ $option = [yY$'\n'] ]]` | TRUE | RunUpgrade |
|
||||
| ProcessResponse | `[[ $option = [nN] ]]` | TRUE | WriteTimestampOnly |
|
||||
| ProcessResponse | — | OTHER | ManualMsg |
|
||||
| WriteTimestampOnly | — | `update_last_updated_file` | ManualMsg |
|
||||
| ManualMsg | — | `echo "[oh-my-zsh] You can update manually..."` | ExitHandle |
|
||||
|
||||
---
|
||||
|
||||
### RUN UPGRADE SUBPROCESS
|
||||
|
||||
| State | Condition | Command/Check | Next State |
|
||||
|-------|-----------|---|---|
|
||||
| RunUpgrade | — | `zstyle -s ':omz:update' verbose verbose_mode` | ResolveVerbose |
|
||||
| ResolveVerbose | — | SET to `default` if missing | CheckP10kPrompt |
|
||||
| CheckP10kPrompt | `[[ ${POWERLEVEL9K_INSTANT_PROMPT:-off} != off ]]` | TRUE | ForceSilent |
|
||||
| CheckP10kPrompt | — | FALSE | UpgradePath |
|
||||
| ForceSilent | — | `verbose_mode=silent` | UpgradePath |
|
||||
| UpgradePath | `[[ $update_mode != background-alpha ]]` | TRUE | InteractiveUpgrade |
|
||||
| UpgradePath | — | FALSE | SilentCaptureUpgrade |
|
||||
|
||||
#### Interactive Mode (TTY + user interaction)
|
||||
| State | Condition | Command/Check | Next State |
|
||||
|-------|-----------|---|---|
|
||||
| InteractiveUpgrade | `LANG= ZSH=$ZSH zsh -f $ZSH/tools/upgrade.sh -i -v $verbose_mode` | SUCCESS (exit 0) | UpdateTimestampOnly |
|
||||
| InteractiveUpgrade | — | FAIL (exit >0) | SilentCaptureUpgrade |
|
||||
| UpdateTimestampOnly | — | `update_last_updated_file` | ExitHandle |
|
||||
|
||||
#### Silent Mode (Background/Capture)
|
||||
| State | Condition | Command/Check | Next State |
|
||||
|-------|-----------|---|---|
|
||||
| SilentCaptureUpgrade | `error=$(LANG= ZSH=$ZSH zsh -f $ZSH/tools/upgrade.sh -i -v silent 2>&1)` | SUCCESS | UpdateSuccessStatus |
|
||||
| SilentCaptureUpgrade | — | FAIL (nonzero exit) | UpdateErrorStatus |
|
||||
| UpdateSuccessStatus | — | `update_last_updated_file 0 "Update successful"` | ExitHandle |
|
||||
| UpdateErrorStatus | — | `update_last_updated_file $exit_status "$error"` | ExitHandle |
|
||||
|
||||
---
|
||||
|
||||
### CHECK UPDATE AVAILABLE (Nested Function)
|
||||
|
||||
#### Configuration Retrieval
|
||||
| State | Condition | Command/Check | Next State |
|
||||
|-------|-----------|---|---|
|
||||
| CheckUpdateAvailable | — | `cd $ZSH; git config --local oh-my-zsh.branch` | ReadRemote |
|
||||
| ReadRemote | — | `cd $ZSH; git config --local oh-my-zsh.remote` | ReadRemoteUrl |
|
||||
| ReadRemoteUrl | — | `cd $ZSH; git config remote.$remote.url` | ParseRemoteStyle |
|
||||
|
||||
#### Remote Validation
|
||||
| State | Condition | Command/Check | Next State |
|
||||
|-------|-----------|---|---|
|
||||
| ParseRemoteStyle | URL matches `https://github.com/*` or `git@github.com:*` | TRUE | ValidateOfficialRepo |
|
||||
| ParseRemoteStyle | — | FALSE (non-GitHub) | AssumeUpdateYes |
|
||||
| ValidateOfficialRepo | `[[ $repo = ohmyzsh/ohmyzsh ]]` | TRUE | LocalHeadCheck |
|
||||
| ValidateOfficialRepo | — | FALSE | AssumeUpdateYes |
|
||||
|
||||
#### Local HEAD Retrieval
|
||||
| State | Condition | Command/Check | Next State |
|
||||
|-------|-----------|---|---|
|
||||
| LocalHeadCheck | `cd $ZSH; git rev-parse $branch 2>/dev/null` | SUCCESS | RemoteHeadFetch |
|
||||
| LocalHeadCheck | — | FAIL | AssumeUpdateYes |
|
||||
|
||||
#### Remote HEAD Fetch (Prefer curl > wget > fetch)
|
||||
| State | Condition | Command/Check | Next State |
|
||||
|-------|-----------|---|---|
|
||||
| RemoteHeadFetch | `(( ${+commands[curl]} ))` | TRUE | UseCurl |
|
||||
| RemoteHeadFetch | `(( ${+commands[wget]} ))` | TRUE | UseWget |
|
||||
| RemoteHeadFetch | `(( ${+commands[fetch]} ))` | TRUE | UseFetch |
|
||||
| RemoteHeadFetch | — | NONE (no http tool) | AssumeUpdateNo |
|
||||
| UseCurl | `curl --connect-timeout 2 -fsSL -H 'Accept: application/vnd.github.v3.sha' $api_url 2>/dev/null` | SUCCESS | CompareHeads |
|
||||
| UseCurl | — | FAIL | AssumeUpdateNo |
|
||||
| UseWget | `wget -T 2 -O- --header='Accept: application/vnd.github.v3.sha' $api_url 2>/dev/null` | SUCCESS | CompareHeads |
|
||||
| UseWget | — | FAIL | AssumeUpdateNo |
|
||||
| UseFetch | `HTTP_ACCEPT='...' fetch -T 2 -o - $api_url 2>/dev/null` | SUCCESS | CompareHeads |
|
||||
| UseFetch | — | FAIL | AssumeUpdateNo |
|
||||
|
||||
#### Head Comparison
|
||||
| State | Condition | Command/Check | Next State |
|
||||
|-------|-----------|---|---|
|
||||
| CompareHeads | `[[ $local_head != $remote_head ]]` | TRUE | MergeBaseCheck |
|
||||
| CompareHeads | — | FALSE (equal) | AssumeUpdateNo |
|
||||
|
||||
#### Ancestry Check
|
||||
| State | Condition | Command/Check | Next State |
|
||||
|-------|-----------|---|---|
|
||||
| MergeBaseCheck | `cd $ZSH; git merge-base $local_head $remote_head 2>/dev/null` | SUCCESS | EvaluateAncestry |
|
||||
| MergeBaseCheck | — | FAIL | AssumeUpdateYes |
|
||||
| EvaluateAncestry | `[[ $base != $remote_head ]]` | TRUE | AssumeUpdateYes |
|
||||
| EvaluateAncestry | — | FALSE | AssumeUpdateNo |
|
||||
|
||||
#### Results
|
||||
| State | Condition | Command/Check | Next State |
|
||||
|-------|-----------|---|---|
|
||||
| AssumeUpdateYes | — | `return 0` (update available) | return from function |
|
||||
| AssumeUpdateNo | — | `return 1` (no update) | return from function |
|
||||
|
||||
---
|
||||
|
||||
### BACKGROUND UPDATE STATUS HOOK
|
||||
|
||||
| State | Condition | Command/Check | Next State |
|
||||
|-------|-----------|---|---|
|
||||
| BackgroundStatusHook | — | register precmd → `_omz_bg_update_status` | PollStatus |
|
||||
| PollStatus | `[[ ! -f $ZSH_CACHE_DIR/.zsh-update ]]` | TRUE | WaitMore |
|
||||
| PollStatus | `source $ZSH_CACHE_DIR/.zsh-update` | SUCCESS + `[[ -z $EXIT_STATUS \|\| -z $ERROR ]]` | WaitMore |
|
||||
| PollStatus | `[[ $EXIT_STATUS -eq 0 ]]` | TRUE | PrintSuccess |
|
||||
| PollStatus | `[[ $EXIT_STATUS -ne 0 ]]` | TRUE | PrintFailure |
|
||||
| WaitMore | — | `return 1` (continue polling on next precmd) | PollStatus (next precmd) |
|
||||
| PrintSuccess | — | `print -P "\n%F{green}[oh-my-zsh] Update successful.%f"` | CleanupStatusHook |
|
||||
| PrintFailure | — | `print -P "\n%F{red}[oh-my-zsh] There was an error updating:%f"; printf "${ERROR}"` | CleanupStatusHook |
|
||||
| CleanupStatusHook | `(( TRY_BLOCK_ERROR == 0 ))` | TRUE | DeregisterHook |
|
||||
| DeregisterHook | — | `update_last_updated_file` (reset status file) | DeregisterStatusFunc |
|
||||
| DeregisterStatusFunc | — | `add-zsh-hook -d precmd _omz_bg_update_status` | [*] |
|
||||
|
||||
---
|
||||
|
||||
### EXIT & CLEANUP
|
||||
|
||||
| State | Condition | Command/Check | Next State |
|
||||
|-------|-----------|---|---|
|
||||
| ExitHandle | — | trap fires (EXIT/INT/QUIT) → `rm -rf $ZSH/log/update.lock` | TrapExit |
|
||||
| TrapExit | — | `unset update_mode` | TrapExit2 |
|
||||
| TrapExit | — | `unset -f current_epoch is_update_available ...` | TrapExit2 |
|
||||
| TrapExit2 | — | `return $ret` | [*] |
|
||||
|
||||
---
|
||||
|
||||
## Key Functions (Always Available)
|
||||
|
||||
### current_epoch()
|
||||
```zsh
|
||||
zmodload zsh/datetime
|
||||
echo $(( EPOCHSECONDS / 60 / 60 / 24 ))
|
||||
```
|
||||
Returns the current day count since epoch.
|
||||
|
||||
### is_update_available()
|
||||
Returns 0 (update available) or 1 (no update).
|
||||
See "CHECK UPDATE AVAILABLE" section above.
|
||||
|
||||
### update_last_updated_file()
|
||||
- Called with no args → writes `LAST_EPOCH=$(current_epoch)`
|
||||
- Called with `exit_status` and `error` → writes status + error msg
|
||||
|
||||
### update_ohmyzsh()
|
||||
Calls `upgrade.sh` subprocesses (interactive or silent capture).
|
||||
Returns exit code of upgrade operation.
|
||||
|
||||
### has_typed_input()
|
||||
Polls stdin with stty/zselect. Returns 0 if input detected, 1 if not.
|
||||
|
||||
---
|
||||
|
||||
## Summary Statistics
|
||||
|
||||
- **Total States (conceptual):** 60+
|
||||
- **Total Transitions:** 80+
|
||||
- **Early Exit Points (PreFlightGate):** 5 conditions
|
||||
- **Update Decision Points:** 3 (mode, frequency, availability)
|
||||
- **User Prompt Paths:** 2 (prompt mode vs. auto)
|
||||
- **Background Poller States:** 4
|
||||
- **Nested Function Depth:** 2 (handle_update → is_update_available)
|
||||
|
|
@ -39,6 +39,7 @@ function current_epoch() {
|
|||
echo $(( EPOCHSECONDS / 60 / 60 / 24 ))
|
||||
}
|
||||
|
||||
# TODO: change this to support stable releases
|
||||
function is_update_available() {
|
||||
local branch
|
||||
branch=${"$(builtin cd -q "$ZSH"; git config --local oh-my-zsh.branch)":-master}
|
||||
|
|
@ -211,6 +212,8 @@ function handle_update() {
|
|||
return
|
||||
fi
|
||||
|
||||
# TODO: somewhere like here we should support fast-tracking of security patches
|
||||
|
||||
# Check if there are updates available before proceeding
|
||||
if ! is_update_available; then
|
||||
update_last_updated_file
|
||||
|
|
|
|||
|
|
@ -191,6 +191,8 @@ if is_tty; then
|
|||
RESET=$(printf '\033[0m')
|
||||
fi
|
||||
|
||||
## START Migrations
|
||||
|
||||
# Update upstream remote to ohmyzsh org
|
||||
git remote -v | while read remote url extra; do
|
||||
case "$url" in
|
||||
|
|
@ -213,6 +215,14 @@ git remote -v | while read remote url extra; do
|
|||
break
|
||||
done
|
||||
|
||||
# Set default release mode
|
||||
# We should really move away from `.branch`, and keep it only for forks
|
||||
# then we can set `.release` and `.remote` as the right ones for us
|
||||
# Release options: master, release/YY0M, vYY0M.x.y
|
||||
if [[ -z "$(git config --local oh-my-zsh.release)" ]]; then
|
||||
git config --local oh-my-zsh.release "master"
|
||||
fi
|
||||
|
||||
# Set git-config values known to fix git errors
|
||||
# Line endings (#4069)
|
||||
git config core.eol lf
|
||||
|
|
@ -225,11 +235,14 @@ git config receive.fsck.zeroPaddedFilemode ignore
|
|||
resetAutoStash=$(git config --bool rebase.autoStash 2>/dev/null)
|
||||
git config rebase.autoStash true
|
||||
|
||||
## END migrations
|
||||
|
||||
local ret=0
|
||||
|
||||
# repository settings
|
||||
remote=${"$(git config --local oh-my-zsh.remote)":-origin}
|
||||
branch=${"$(git config --local oh-my-zsh.branch)":-master}
|
||||
release=${"$(git config --local oh-my-zsh.release)":-master}
|
||||
|
||||
# repository state
|
||||
last_head=$(git symbolic-ref --quiet --short HEAD || git rev-parse HEAD)
|
||||
|
|
@ -242,6 +255,28 @@ last_commit=$(git rev-parse "$branch")
|
|||
if [[ $verbose_mode != silent ]]; then
|
||||
printf "${BLUE}%s${RESET}\n" "Updating Oh My Zsh"
|
||||
fi
|
||||
|
||||
# master -> git pull
|
||||
# release/YY0M -> git pull origin release/YY0M
|
||||
# vYY0M.x.y -> only update if release/ branch of the tag has a security update
|
||||
case "$release" in
|
||||
master|release/*) git pull --quiet --rebase "$remote" "$release" ;;
|
||||
v*) ;; # do nothing, but we should really make sure that security patches are fast-tracked: if the "$release" tag is in branch release/YY0M, we should pull that branch and then check out the latest tag, and inform the user that we upgraded their release
|
||||
*) echo "error: unknown release '$release'" && exit 1 ;; # here we should show how to fix the issue
|
||||
esac
|
||||
|
||||
# test: are we updating on the main remote or from a fork?
|
||||
# if main remote then
|
||||
# case "$release" in
|
||||
# master|release/*) git pull --quiet --rebase "$remote" "$release" ;;
|
||||
# release/*) git pull --quiet --rebase "$remote" "$release" ;;
|
||||
# v*) ;; # nothing
|
||||
# *) echo "error: unknown release '$release'" && exit 1 ;;
|
||||
# esac
|
||||
# fi
|
||||
|
||||
# if master or release/* do just git pull $remote $branch
|
||||
|
||||
if LANG= git pull --quiet --rebase $remote $branch; then
|
||||
# Check if it was really updated or not
|
||||
if [[ "$(git rev-parse HEAD)" = "$last_commit" ]]; then
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue