oh-my-devpod 0.14.5 → 0.15.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oh-my-devpod",
3
- "version": "0.14.5",
3
+ "version": "0.15.1",
4
4
  "description": "Ubuntu productivity tool manager with the omd terminal interface",
5
5
  "license": "MIT",
6
6
  "author": "zhangdw156",
package/runtime/VERSION CHANGED
@@ -1 +1 @@
1
- 0.14.5
1
+ 0.15.1
package/runtime/bin/omd CHANGED
Binary file
@@ -0,0 +1,326 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ production_libexec="/usr/local/libexec/oh-my-devpod"
5
+ production_gateway="${production_libexec}/brew-gateway"
6
+ resolved_self="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)/$(basename "${BASH_SOURCE[0]}")"
7
+ if command -v readlink >/dev/null 2>&1; then
8
+ resolved_self="$(readlink -f "${BASH_SOURCE[0]}" 2>/dev/null || printf '%s' "${resolved_self}")"
9
+ fi
10
+
11
+ if [[ "${resolved_self}" == "${production_gateway}" ||
12
+ "${resolved_self}" == "${production_libexec}/bin/brew" ||
13
+ "${resolved_self}" == "/usr/local/bin/brew" ]]; then
14
+ test_mode=0
15
+ prefix="/home/linuxbrew/.linuxbrew"
16
+ state_dir="/var/lib/oh-my-devpod/linuxbrew"
17
+ libexec_dir="${production_libexec}"
18
+ else
19
+ test_mode="${OHMYDEVPOD_SHARED_BREW_TEST_MODE:-0}"
20
+ prefix="${OHMYDEVPOD_SHARED_BREW_PREFIX:-/home/linuxbrew/.linuxbrew}"
21
+ state_dir="${OHMYDEVPOD_SHARED_BREW_STATE_DIR:-/var/lib/oh-my-devpod/linuxbrew}"
22
+ libexec_dir="${OHMYDEVPOD_SHARED_BREW_LIBEXEC_DIR:-${production_libexec}}"
23
+ fi
24
+
25
+ manifest="${state_dir}/manifest"
26
+ inventory_dir="${state_dir}/inventory"
27
+ real_brew="${prefix}/bin/brew"
28
+ stable_gateway="${libexec_dir}/brew-gateway"
29
+ lock_file="${state_dir}/locks/mutation.lock"
30
+ brew_noninteractive=0
31
+ declare -a forwarded_env=()
32
+
33
+ fail() {
34
+ printf 'brew: shared Linuxbrew gateway: %s\n' "$*" >&2
35
+ exit 1
36
+ }
37
+
38
+ manifest_value() {
39
+ local key="$1"
40
+ sed -n "s/^${key}=//p" "${manifest}" | head -n 1
41
+ }
42
+
43
+ group_gid() {
44
+ local group="$1"
45
+ if command -v getent >/dev/null 2>&1; then
46
+ getent group "${group}" | awk -F: '{print $3}'
47
+ else
48
+ id -g "${group}"
49
+ fi
50
+ }
51
+
52
+ stat_uid() {
53
+ if stat -c '%u' "$1" >/dev/null 2>&1; then stat -c '%u' "$1"; else stat -f '%u' "$1"; fi
54
+ }
55
+
56
+ stat_gid() {
57
+ if stat -c '%g' "$1" >/dev/null 2>&1; then stat -c '%g' "$1"; else stat -f '%g' "$1"; fi
58
+ }
59
+
60
+ stat_mode() {
61
+ if stat -c '%a' "$1" >/dev/null 2>&1; then stat -c '%a' "$1"; else stat -f '%Lp' "$1"; fi
62
+ }
63
+
64
+ validate_manifest() {
65
+ local service_user manager_group expected_uid expected_gid actual_uid actual_gid installation_id
66
+ [[ -f "${manifest}" && ! -L "${manifest}" ]] || fail "missing or unsafe shared manifest"
67
+ [[ "$(manifest_value schema_version || true)" == "1" ]] || fail "unsupported shared manifest schema"
68
+ [[ "$(manifest_value managed_by || true)" == "oh-my-devpod" ]] || fail "shared manifest ownership mismatch"
69
+ [[ "$(manifest_value mode || true)" == "shared-service-account" ]] || fail "shared manifest mode mismatch"
70
+ [[ "$(manifest_value prefix || true)" == "${prefix}" ]] || fail "shared prefix mismatch"
71
+ [[ -d "${prefix}" && ! -L "${prefix}" && -x "${real_brew}" ]] || fail "real Brew backend is unavailable"
72
+ [[ "$(cd "${prefix}" 2>/dev/null && pwd -P)" == "${prefix}" ]] || fail "shared prefix resolves outside its fixed path"
73
+ [[ "$(cd "${state_dir}" 2>/dev/null && pwd -P)" == "${state_dir}" ]] || fail "shared state resolves outside its fixed path"
74
+ [[ -d "${inventory_dir}" && ! -L "${inventory_dir}" ]] || fail "shared inventory is unavailable"
75
+ [[ -f "${lock_file}" && ! -L "${lock_file}" ]] || fail "shared mutation lock is unavailable"
76
+
77
+ service_user="$(manifest_value service_user || true)"
78
+ manager_group="$(manifest_value manager_group || true)"
79
+ expected_uid="$(manifest_value service_uid || true)"
80
+ expected_gid="$(manifest_value service_gid || true)"
81
+ installation_id="$(manifest_value installation_id || true)"
82
+ [[ "${service_user}" =~ ^[a-z_][a-z0-9_-]*[$]?$ ]] || fail "shared service user is invalid"
83
+ [[ "${manager_group}" =~ ^[a-z_][a-z0-9_-]*[$]?$ ]] || fail "shared manager group is invalid"
84
+ [[ "${expected_uid}" =~ ^[0-9]+$ && "${expected_gid}" =~ ^[0-9]+$ ]] || fail "shared service identity is invalid"
85
+ [[ "${installation_id}" =~ ^[[:xdigit:]]{8}-[[:xdigit:]]{4}-[[:xdigit:]]{4}-[[:xdigit:]]{4}-[[:xdigit:]]{12}$ ]] || fail "shared installation ID is invalid"
86
+ actual_uid="$(id -u "${service_user}" 2>/dev/null || true)"
87
+ if [[ "${test_mode}" == "1" && -n "${OHMYDEVPOD_SHARED_BREW_TEST_SERVICE_GID:-}" ]]; then
88
+ actual_gid="${OHMYDEVPOD_SHARED_BREW_TEST_SERVICE_GID}"
89
+ else
90
+ actual_gid="$(group_gid "${manager_group}" 2>/dev/null || true)"
91
+ fi
92
+ [[ "${actual_uid}" == "${expected_uid}" && "${actual_gid}" == "${expected_gid}" ]] || fail "shared service identity changed"
93
+ [[ "$(stat_uid "${prefix}")" == "${expected_uid}" && "$(stat_gid "${prefix}")" == "${expected_gid}" ]] || fail "shared prefix ownership changed"
94
+ if [[ "${test_mode}" != "1" ]]; then
95
+ [[ "$(stat_uid "${manifest}")" == "0" && "$(stat_gid "${manifest}")" == "0" ]] || fail "shared manifest is not root-owned"
96
+ (( (8#$(stat_mode "${manifest}") & 8#022) == 0 )) || fail "shared manifest is writable by non-root users"
97
+ [[ "$(stat_uid "${state_dir}")" == "0" && "$(stat_uid "$(dirname "${lock_file}")")" == "0" ]] || fail "shared state parents are not root-owned"
98
+ [[ "$(stat_uid "${stable_gateway}")" == "0" && "$(stat_gid "${stable_gateway}")" == "0" ]] || fail "Brew gateway is not root-owned"
99
+ fi
100
+ }
101
+
102
+ service_user() {
103
+ manifest_value service_user
104
+ }
105
+
106
+ service_home() {
107
+ local user="$1" home=""
108
+ if command -v getent >/dev/null 2>&1; then
109
+ home="$(getent passwd "${user}" 2>/dev/null | awk -F: '{print $6}')"
110
+ fi
111
+ printf '%s\n' "${home:-${state_dir}/service-home}"
112
+ }
113
+
114
+ valid_formula_name() {
115
+ [[ "$1" =~ ^[a-z0-9][a-z0-9@+_.-]*$ ]]
116
+ }
117
+
118
+ record_value() {
119
+ local record="$1" key="$2"
120
+ sed -n "s/^${key}=//p" "${record}" | head -n 1
121
+ }
122
+
123
+ validate_inventory_records() {
124
+ local record formula installation_id state
125
+ installation_id="$(manifest_value installation_id)"
126
+ for record in "${inventory_dir}"/*; do
127
+ [[ -e "${record}" || -L "${record}" ]] || continue
128
+ [[ -f "${record}" && ! -L "${record}" ]] || fail "unsafe shared inventory record"
129
+ formula="$(basename "${record}")"
130
+ valid_formula_name "${formula}" || fail "invalid formula inventory name"
131
+ [[ "$(record_value "${record}" managed_by || true)" == "oh-my-devpod" ]] || fail "invalid formula inventory owner"
132
+ [[ "$(record_value "${record}" component || true)" == "${formula}" ]] || fail "invalid formula inventory component"
133
+ [[ "$(record_value "${record}" kind || true)" == "brew-formula" ]] || fail "invalid formula inventory kind"
134
+ [[ "$(record_value "${record}" artifact || true)" == "${formula}" ]] || fail "invalid formula inventory artifact"
135
+ [[ "$(record_value "${record}" brew_prefix || true)" == "${prefix}" ]] || fail "invalid formula inventory prefix"
136
+ [[ "$(record_value "${record}" installation_id || true)" == "${installation_id}" ]] || fail "invalid formula inventory installation ID"
137
+ state="$(record_value "${record}" state || true)"
138
+ [[ "${state}" == "managed" || "${state}" == "external" ]] || fail "invalid formula inventory state"
139
+ done
140
+ }
141
+
142
+ is_inventory_mutation() {
143
+ case "${1:-}" in
144
+ ""|--cellar|--config|--env|--prefix|--repository|--version|-v|analytics|autoremove|command|commands|config|deps|desc|doctor|formulae|help|home|info|leaves|list|log|outdated|readall|search|shellenv|tap-info|tap-pin|tap-unpin|uses)
145
+ return 1
146
+ ;;
147
+ *)
148
+ return 0
149
+ ;;
150
+ esac
151
+ }
152
+
153
+ snapshot_formulae() {
154
+ local destination="$1"
155
+ : > "${destination}"
156
+ [[ -d "${prefix}/Cellar" ]] || return 0
157
+ find "${prefix}/Cellar" -mindepth 1 -maxdepth 1 -type d -exec basename {} \; | LC_ALL=C sort -u > "${destination}"
158
+ }
159
+
160
+ write_formula_record() {
161
+ local formula="$1" installation_id="$2" state="$3" provenance="$4" record temporary
162
+ valid_formula_name "${formula}" || return 0
163
+ record="${inventory_dir}/${formula}"
164
+ [[ ! -L "${record}" ]] || fail "unsafe formula inventory record"
165
+ temporary="${inventory_dir}/.${formula}.tmp.$$"
166
+ {
167
+ printf 'managed_by=oh-my-devpod\n'
168
+ printf 'component=%s\n' "${formula}"
169
+ printf 'kind=brew-formula\n'
170
+ printf 'artifact=%s\n' "${formula}"
171
+ printf 'brew_prefix=%s\n' "${prefix}"
172
+ printf 'installation_id=%s\n' "${installation_id}"
173
+ printf 'state=%s\n' "${state}"
174
+ printf 'provenance=%s\n' "${provenance}"
175
+ printf 'observed_at=%s\n' "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
176
+ } > "${temporary}"
177
+ chmod 0644 "${temporary}"
178
+ mv -f "${temporary}" "${record}"
179
+ }
180
+
181
+ reconcile_inventory() {
182
+ local before="$1" installation_id formula record
183
+ installation_id="$(manifest_value installation_id)"
184
+ if [[ -d "${prefix}/Cellar" ]]; then
185
+ while IFS= read -r formula; do
186
+ [[ -n "${formula}" ]] || continue
187
+ record="${inventory_dir}/${formula}"
188
+ if [[ -f "${record}" && ! -L "${record}" ]]; then
189
+ continue
190
+ fi
191
+ if grep -Fqx "${formula}" "${before}" 2>/dev/null; then
192
+ write_formula_record "${formula}" "${installation_id}" external preexisting
193
+ else
194
+ write_formula_record "${formula}" "${installation_id}" managed brew-gateway
195
+ fi
196
+ done < <(find "${prefix}/Cellar" -mindepth 1 -maxdepth 1 -type d -exec basename {} \; | LC_ALL=C sort -u)
197
+ fi
198
+
199
+ for record in "${inventory_dir}"/*; do
200
+ [[ -f "${record}" && ! -L "${record}" ]] || continue
201
+ formula="$(basename "${record}")"
202
+ valid_formula_name "${formula}" || continue
203
+ [[ -d "${prefix}/Cellar/${formula}" ]] || rm -f "${record}"
204
+ done
205
+ }
206
+
207
+ append_gateway_shellenv() {
208
+ local shell_name="${2:-}"
209
+ case "${shell_name}" in
210
+ fish)
211
+ printf 'set -gx PATH %q $PATH;\n' "${libexec_dir}/bin"
212
+ ;;
213
+ csh|tcsh)
214
+ printf 'setenv PATH %q:$PATH;\n' "${libexec_dir}/bin"
215
+ ;;
216
+ *)
217
+ printf 'export PATH=%q:"$PATH"\n' "${libexec_dir}/bin"
218
+ ;;
219
+ esac
220
+ }
221
+
222
+ run_real_brew() {
223
+ local home="$1"
224
+ shift
225
+ local -a clean_env
226
+ clean_env=(HOME="${home}" USER="$(service_user)" LOGNAME="$(service_user)" PATH="/usr/local/bin:/usr/bin:/bin:${prefix}/bin")
227
+ if [[ "${test_mode}" == "1" ]]; then
228
+ clean_env+=(OHMYDEVPOD_SHARED_BREW_PREFIX="${prefix}" OMD_TEST_BREW_LOG="${OMD_TEST_BREW_LOG:-/dev/null}")
229
+ fi
230
+ if [[ "${brew_noninteractive}" == "1" ]]; then
231
+ clean_env+=(NONINTERACTIVE=1 HOMEBREW_NO_ASK=1 HOMEBREW_NO_AUTO_UPDATE=1 HOMEBREW_NO_ENV_HINTS=1 HOMEBREW_NO_INSTALL_CLEANUP=1)
232
+ fi
233
+ if [[ "${#forwarded_env[@]}" -gt 0 ]]; then
234
+ clean_env+=("${forwarded_env[@]}")
235
+ fi
236
+ [[ -z "${HOMEBREW_NO_AUTO_UPDATE:-}" ]] || clean_env+=(HOMEBREW_NO_AUTO_UPDATE="${HOMEBREW_NO_AUTO_UPDATE}")
237
+ [[ -z "${HOMEBREW_NO_ANALYTICS:-}" ]] || clean_env+=(HOMEBREW_NO_ANALYTICS="${HOMEBREW_NO_ANALYTICS}")
238
+ [[ -z "${HOMEBREW_NO_ENV_HINTS:-}" ]] || clean_env+=(HOMEBREW_NO_ENV_HINTS="${HOMEBREW_NO_ENV_HINTS}")
239
+ env -i "${clean_env[@]}" "${real_brew}" "$@"
240
+ }
241
+
242
+ run_backend() {
243
+ local home status mutates=0 before name value
244
+ if [[ "${1:-}" == "--omd-forwarded" ]]; then
245
+ shift
246
+ while [[ "${1:-}" != "--" ]]; do
247
+ case "${1:-}" in
248
+ --omd-noninteractive)
249
+ brew_noninteractive=1
250
+ shift
251
+ ;;
252
+ --omd-env)
253
+ [[ "$#" -ge 3 ]] || fail "invalid forwarded Brew environment"
254
+ name="$2"
255
+ value="$3"
256
+ case "${name}" in
257
+ HOMEBREW_NO_AUTO_UPDATE|HOMEBREW_NO_ANALYTICS|HOMEBREW_NO_ENV_HINTS|HTTP_PROXY|HTTPS_PROXY|NO_PROXY|http_proxy|https_proxy|no_proxy) ;;
258
+ *) fail "unsupported forwarded Brew environment" ;;
259
+ esac
260
+ [[ "${#value}" -le 4096 ]] || fail "forwarded Brew environment is too large"
261
+ forwarded_env+=("${name}=${value}")
262
+ shift 3
263
+ ;;
264
+ *)
265
+ fail "invalid internal gateway arguments"
266
+ ;;
267
+ esac
268
+ done
269
+ [[ "${1:-}" == "--" ]] || fail "invalid internal gateway arguments"
270
+ shift
271
+ fi
272
+ validate_manifest
273
+ [[ "$(id -u)" == "$(manifest_value service_uid)" ]] || fail "backend must run as $(service_user)"
274
+ validate_inventory_records
275
+ home="$(service_home "$(service_user)")"
276
+ before="${state_dir}/.inventory-before.$$"
277
+ if is_inventory_mutation "${1:-}"; then
278
+ mutates=1
279
+ snapshot_formulae "${before}"
280
+ fi
281
+
282
+ set +e
283
+ run_real_brew "${home}" "$@"
284
+ status=$?
285
+ set -e
286
+ if [[ "${status}" -eq 0 && "${1:-}" == "shellenv" ]]; then
287
+ append_gateway_shellenv "$@"
288
+ fi
289
+ if [[ "${mutates}" == "1" ]]; then
290
+ reconcile_inventory "${before}"
291
+ rm -f "${before}"
292
+ fi
293
+ return "${status}"
294
+ }
295
+
296
+ run_locked_backend() {
297
+ command -v flock >/dev/null 2>&1 || fail "flock is required"
298
+ exec 9<> "${lock_file}"
299
+ flock -x 9
300
+ run_backend "$@"
301
+ }
302
+
303
+ validate_manifest
304
+ if [[ "${1:-}" == "--service" ]]; then
305
+ shift
306
+ run_locked_backend "$@"
307
+ exit $?
308
+ fi
309
+
310
+ expected_user="$(service_user)"
311
+ if [[ "$(id -u)" == "$(manifest_value service_uid)" ]]; then
312
+ run_locked_backend "$@"
313
+ exit $?
314
+ fi
315
+ declare -a forwarded_args
316
+ forwarded_args=(--omd-forwarded)
317
+ if [[ "${OHMYDEVPOD_BREW_NONINTERACTIVE:-0}" == "1" ]]; then
318
+ forwarded_args+=(--omd-noninteractive)
319
+ fi
320
+ for name in HOMEBREW_NO_AUTO_UPDATE HOMEBREW_NO_ANALYTICS HOMEBREW_NO_ENV_HINTS HTTP_PROXY HTTPS_PROXY NO_PROXY http_proxy https_proxy no_proxy; do
321
+ if [[ -n "${!name:-}" ]]; then
322
+ forwarded_args+=(--omd-env "${name}" "${!name}")
323
+ fi
324
+ done
325
+ forwarded_args+=(--)
326
+ exec sudo -n -H -u "${expected_user}" -- "${stable_gateway}" --service "${forwarded_args[@]}" "$@"