Repository navigation
Expand file tree
/
Copy pathactivate
More file actions
executable file
·181 lines (168 loc) · 7.06 KB
/
Copy pathactivate
File metadata and controls
executable file
·181 lines (168 loc) · 7.06 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
#!/usr/bin/env bash
# ============================================================================
# venv-style activation of the Hermes dev environment for an interactive shell.
#
# source ./activate (bash / zsh, repo root)
# source ./activate.fish (fish)
# .\activate.ps1 (PowerShell)
#
# Applies the composed pm env (PATH + tool vars) to the CURRENT shell, with
# save/restore: `deactivate` undoes exactly what activation changed.
#
# `hermes` becomes a shell function for this checkout. It runs only while the
# shell is inside this worktree and refuses outside it, so a sibling worktree
# keeps its own command. A prompt prefix names the worktree.
#
# Scripts and other processes do not source this: they run under
# `scripts/run-in-hermes-env`. Both build on scripts/_activation.sh.
#
# Sync through setup before selecting the environment. PM owns freshness;
# activation does not maintain a second dependency stamp. It trusts the
# recorded tool digest instead of re-hashing every entry. `hermes pm
# install` and `hermes update` keep that check.
# ============================================================================
_HERMES_REPO="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# Options: `--test-extras a,b` selects the test environment's runtime extras
# (default: [all]); `--` ends options.
# A bare `source ./activate` inherits the caller's positional parameters.
# Ignore unrelated words so scripts with their own arguments can source it.
_hermes_test_env="--test-environment"
_hermes_expect_extras=""
for _hermes_arg in "$@"; do
if [ -n "$_hermes_expect_extras" ]; then
_hermes_test_env="--test-environment=$_hermes_arg"
_hermes_expect_extras=""
continue
fi
case "$_hermes_arg" in
--) break ;;
--test-extras) _hermes_expect_extras=1 ;;
--test-extras=*) _hermes_test_env="--test-environment=${_hermes_arg#--test-extras=}" ;;
*) : ;;
esac
done
if [ -n "$_hermes_expect_extras" ]; then
printf '%s\n' 'activate: --test-extras needs a comma-separated list' >&2
unset _hermes_arg _hermes_test_env _hermes_expect_extras
return 2 2>/dev/null || exit 2
fi
unset _hermes_arg _hermes_expect_extras
# shellcheck source=scripts/_activation.sh
. "$_HERMES_REPO/scripts/_activation.sh"
if ! hermes_sync "$_HERMES_REPO" "$_hermes_test_env"; then
printf '%s\n' 'activate: setup failed; shell environment unchanged' >&2
unset _hermes_test_env
return 1 2>/dev/null || exit 1
fi
unset _hermes_test_env
# Guard against double-sourcing: venv activate precedent (re-activating is a
# no-op re-save; we keep it idempotent by deactivating first). Key on the
# function, not the sentinel: child shells inherit __HERMES_ACTIVATED from an
# activated parent but never the function, and there is nothing to undo there.
if [ "$(type -t deactivate 2>/dev/null)" = "function" ]; then
deactivate
fi
_hermes_script="$(hermes_compose_env "$_HERMES_REPO" sh)" || {
echo "activate: could not compose the environment (see above)" >&2
unset _hermes_script
return 1 2>/dev/null || exit 1
}
_hermes_keys="$(printf '%s\n' "$_hermes_script" | sed -n 's/^export \([A-Za-z_][A-Za-z0-9_]*\)=.*/\1/p' | tr '\n' ' ')"
# --- snapshot what we are about to change (deactivate restores this) ---
# __HERMES_ACTIVATED is part of the composed env below (it carries the
# installed-state path this environment was built from), so it is snapshotted
# and exported with every other key — no separate assignment here.
__HERMES_SAVED_PATH="$PATH"
for _hermes_k in $_hermes_keys; do
eval "__HERMES_SAVED_$_hermes_k=\"\${$_hermes_k+set}\""
eval "__HERMES_PRIOR_$_hermes_k=\${$_hermes_k-__HERMES_UNSET__}"
done
hermes_apply_env "$_hermes_script"
# This checkout, not whichever `hermes` PATH finds. A function beats PATH, an
# alias, and a hashed command, including the MSIX execution alias.
__HERMES_WORKTREE="$_HERMES_REPO"
# The branch names the worktree. A checkout cannot share a branch with another.
__HERMES_WORKTREE_NAME="$(git -C "$_HERMES_REPO" rev-parse --abbrev-ref HEAD 2>/dev/null || :)"
if [ -z "$__HERMES_WORKTREE_NAME" ] || [ "$__HERMES_WORKTREE_NAME" = HEAD ]; then
__HERMES_WORKTREE_NAME="$(basename "$_HERMES_REPO")"
fi
__HERMES_SAVED_PS1="${PS1-__HERMES_UNSET__}"
__HERMES_SAVED_PROMPT_COMMAND="${PROMPT_COMMAND-__HERMES_UNSET__}"
_hermes_worktree_here() {
_hermes_top="$(git rev-parse --show-toplevel 2>/dev/null)" || return 1
[ "$(cd "$_hermes_top" && pwd -P)" = "$(cd "$__HERMES_WORKTREE" && pwd -P)" ]
}
hermes() {
_hermes_worktree_here || {
printf '%s\n' "hermes: $(pwd) is outside $__HERMES_WORKTREE; refusing (the installed command is hidden while this checkout is active)" >&2
return 1
}
(
cd "$__HERMES_WORKTREE" || exit 1
if [ -n "${PYTHON-}" ]; then
exec "$PYTHON" hermes "$@"
elif [ -x .venv/Scripts/python.exe ]; then
exec .venv/Scripts/python.exe hermes "$@"
elif [ -x .venv/bin/python ]; then
exec .venv/bin/python hermes "$@"
elif [ -x venv/Scripts/python.exe ]; then
exec venv/Scripts/python.exe hermes "$@"
elif [ -x venv/bin/python ]; then
exec venv/bin/python hermes "$@"
else
exec python hermes "$@"
fi
)
}
_hermes_prompt() {
if [ "$__HERMES_SAVED_PS1" = "__HERMES_UNSET__" ]; then
_hermes_base_ps1=""
else
_hermes_base_ps1="$__HERMES_SAVED_PS1"
fi
if _hermes_worktree_here; then
PS1="($__HERMES_WORKTREE_NAME) $_hermes_base_ps1"
else
PS1="$_hermes_base_ps1"
fi
}
if [ -n "${PROMPT_COMMAND-}" ]; then
PROMPT_COMMAND="_hermes_prompt; ${PROMPT_COMMAND}"
else
PROMPT_COMMAND=_hermes_prompt
fi
_hermes_prompt
deactivate() {
export PATH="$__HERMES_SAVED_PATH"
for _hermes_k in $__HERMES_KEY_LIST; do
eval "_hermes_was=\"\$__HERMES_SAVED_$_hermes_k\""
eval "_hermes_old=\"\$__HERMES_PRIOR_$_hermes_k\""
if [ "$_hermes_was" != "set" ]; then
unset "$_hermes_k"
else
export "$_hermes_k=$_hermes_old"
fi
unset "__HERMES_SAVED_$_hermes_k" "__HERMES_PRIOR_$_hermes_k"
done
if [ "$__HERMES_SAVED_PS1" = "__HERMES_UNSET__" ]; then
unset PS1
else
PS1="$__HERMES_SAVED_PS1"
fi
if [ "$__HERMES_SAVED_PROMPT_COMMAND" = "__HERMES_UNSET__" ]; then
unset PROMPT_COMMAND
else
PROMPT_COMMAND="$__HERMES_SAVED_PROMPT_COMMAND"
fi
unset __HERMES_SAVED_PATH __HERMES_KEY_LIST __HERMES_ACTIVATED \
__HERMES_WORKTREE __HERMES_WORKTREE_NAME \
__HERMES_SAVED_PS1 __HERMES_SAVED_PROMPT_COMMAND
unset -f deactivate hermes _hermes_worktree_here _hermes_prompt
unset _hermes_k _hermes_was _hermes_old _hermes_top
}
# remember the key list for deactivate (kept out of the loop vars above)
__HERMES_KEY_LIST="$_hermes_keys"
# The composition library is not part of the user's shell.
unset -f hermes_sync hermes_bootstrap_python hermes_compose_env hermes_apply_env \
hermes_activation_current hermes_ensure_env
unset _HERMES_REPO _hermes_script _hermes_keys _hermes_k _hermes_top