valise-sh 0.2.0 → 0.3.0
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/CHANGELOG.md +152 -2
- package/README.md +99 -146
- package/bin/valise +57 -5376
- package/docs/architecture.md +77 -121
- package/docs/contrib-modules.md +172 -218
- package/docs/installation.md +137 -83
- package/docs/module-abi.md +125 -126
- package/docs/projects.md +249 -0
- package/docs/release-policy.md +68 -93
- package/docs/shared-modules.md +40 -39
- package/examples/README.md +12 -11
- package/examples/e2e/README.md +59 -66
- package/examples/e2e/bundles.tsv +6 -0
- package/examples/e2e/module.d/e2e_aliases.meta +1 -2
- package/examples/e2e/module.d/e2e_completions_bash.meta +0 -1
- package/examples/e2e/module.d/e2e_completions_zsh.meta +0 -1
- package/examples/e2e/module.d/e2e_env_setup.meta +2 -3
- package/examples/e2e/module.d/e2e_fish_features.meta +0 -1
- package/examples/e2e/module.d/e2e_generated_config.meta +1 -2
- package/examples/e2e/module.d/e2e_ksh_features.meta +0 -1
- package/examples/e2e/module.d/e2e_layer_probe.meta +1 -2
- package/examples/e2e/module.d/e2e_optional_network.meta +1 -2
- package/examples/e2e/module.d/e2e_platform_tools.meta +8 -0
- package/examples/e2e/module.d/e2e_platform_tools_bsd.meta +2 -3
- package/examples/e2e/module.d/e2e_platform_tools_darwin.meta +2 -3
- package/examples/e2e/module.d/e2e_platform_tools_linux.meta +2 -3
- package/examples/e2e/valise.conf +4 -0
- package/examples/e2e/variants.tsv +3 -0
- package/examples/local/module.d/hello_valise.meta +1 -2
- package/examples/profile-project/README.md +78 -108
- package/examples/profile-project/bundles.tsv +8 -0
- package/examples/profile-project/{shell/layers → layers}/demo/module.d/contrib_demo_greeting.meta +1 -2
- package/examples/profile-project/{shell/module.d → module.d}/greeting.meta +1 -2
- package/examples/profile-project/{shell/module.d → module.d}/profile_main.meta +0 -1
- package/examples/profile-project/{shell/modules → modules}/greeting.sh +1 -1
- package/examples/profile-project/valise.conf +4 -0
- package/examples/profile-project/variants.tsv +3 -0
- package/examples/shared/README.md +13 -34
- package/examples/shared/module.d/contrib_shared_paths.meta +2 -3
- package/examples/shared/module.d/contrib_shared_umask.meta +1 -2
- package/examples/shared/modules/shared/contrib_shared_paths.sh +2 -2
- package/lib/capabilities.sh +40 -13
- package/lib/cli/commands.sh +278 -0
- package/lib/cli/common.sh +326 -0
- package/lib/cli/devtools.sh +539 -0
- package/lib/cli/fish-hook.sh +986 -0
- package/lib/cli/integration.sh +337 -0
- package/lib/cli/lifecycle.sh +578 -0
- package/lib/cli/project.sh +1807 -0
- package/lib/cli/store.sh +1023 -0
- package/lib/cli/usage.sh +308 -0
- package/lib/compiler.awk +11 -4
- package/lib/fish/loader.fish +69 -9
- package/lib/fish/metadata.fish +49 -5
- package/lib/fish/profile.fish +170 -0
- package/lib/loader.sh +6 -8
- package/lib/metadata.sh +111 -5
- package/manifests/parser-support.tsv +2 -2
- package/module.d/valise_editor.meta +9 -0
- package/module.d/valise_history.meta +9 -0
- package/module.d/valise_pager.meta +9 -0
- package/module.d/valise_path.meta +9 -0
- package/module.d/{platform_bsd.meta → valise_platform_bsd.meta} +3 -4
- package/module.d/{platform_linux.meta → valise_platform_linux.meta} +3 -4
- package/module.d/{platform_macos.meta → valise_platform_macos.meta} +3 -4
- package/module.d/{platform_posix.meta → valise_platform_posix.meta} +2 -3
- package/module.d/valise_xdg.meta +9 -0
- package/modules/system/{contrib_editor.sh → valise_editor.sh} +2 -2
- package/modules/system/{contrib_history.sh → valise_history.sh} +2 -2
- package/modules/system/{contrib_pager.sh → valise_pager.sh} +2 -2
- package/modules/system/{contrib_path.sh → valise_path.sh} +3 -3
- package/modules/system/{contrib_xdg.sh → valise_xdg.sh} +2 -2
- package/package.json +91 -10
- package/docs/variants.md +0 -327
- package/entrypoints/.gitkeep +0 -0
- package/entrypoints/fish/profile.fish +0 -99
- package/examples/e2e/build-manifest.sh +0 -138
- package/examples/local/.gitkeep +0 -0
- package/examples/profile-project/shell/release/bundle-roots +0 -9
- package/examples/profile-project/shell/release/install-variants +0 -3
- package/examples/profile-project/shell/release/module-registry.tsv +0 -4
- package/examples/profile-project/shell/release/project.conf +0 -3
- package/lib/.gitkeep +0 -0
- package/manifests/.gitkeep +0 -0
- package/module.d/.gitkeep +0 -0
- package/module.d/contrib_editor.meta +0 -10
- package/module.d/contrib_history.meta +0 -10
- package/module.d/contrib_pager.meta +0 -10
- package/module.d/contrib_path.meta +0 -10
- package/module.d/contrib_xdg.meta +0 -10
- package/modules/.gitkeep +0 -0
- /package/examples/profile-project/{shell/layers → layers}/demo/modules/shared/contrib_demo_greeting.sh +0 -0
package/lib/cli/usage.sh
ADDED
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
# Copyright (c) 2026 Joseph Cumines
|
|
2
|
+
# SPDX-License-Identifier: MIT
|
|
3
|
+
# valise CLI: per-command usage text.
|
|
4
|
+
# Sourced by bin/valise; not executable on its own.
|
|
5
|
+
|
|
6
|
+
usage() {
|
|
7
|
+
printf '%s\n' \
|
|
8
|
+
"Usage: valise <command> [options]" \
|
|
9
|
+
"" \
|
|
10
|
+
"Global option:" \
|
|
11
|
+
" -C <dir> Run as if valise was started in dir" \
|
|
12
|
+
"" \
|
|
13
|
+
"Project commands (run anywhere inside a directory holding valise.conf):" \
|
|
14
|
+
" new [dir] Scaffold a new valise project" \
|
|
15
|
+
" module <new|list|remove> Create, list, or remove project modules" \
|
|
16
|
+
" build [--variant=<name>] [--bundle=<name>] [out]" \
|
|
17
|
+
" Build a release tree (default: build/release)" \
|
|
18
|
+
" apply [--variant=<name>] [--bundle=<name>] [--no-integration] [--dry-run]" \
|
|
19
|
+
" Build the project, install it, and integrate it" \
|
|
20
|
+
" status Show project, active release, integration, and drift" \
|
|
21
|
+
" lint [--require-parsers] [module...] Check metadata, layers, bundles, and syntax" \
|
|
22
|
+
" test [--shell=<class>] [--require-shells] [module...] Run module tests" \
|
|
23
|
+
" run [--shell=<class>] [--module=<m>]... -- <script> Run a script with modules loaded" \
|
|
24
|
+
" env Print the engine, project, and storage paths" \
|
|
25
|
+
"" \
|
|
26
|
+
"Release commands:" \
|
|
27
|
+
" install [--no-integration] Install the release tree in the current directory" \
|
|
28
|
+
" release <list|use|rollback|prune|verify> Manage installed releases" \
|
|
29
|
+
" uninstall [--keep-releases] Remove the integration, commands, and releases" \
|
|
30
|
+
" init [posix|fish] Print the shell integration snippet" \
|
|
31
|
+
" doctor [--pre-install] [--no-integration] Run environment diagnostics" \
|
|
32
|
+
"" \
|
|
33
|
+
"Plumbing:" \
|
|
34
|
+
" compile [--bundle=<name>] [--variant=<name>] <output-dir> Compile plans only" \
|
|
35
|
+
" registry [path] Print the module table generated from metadata" \
|
|
36
|
+
" make-manifest <tree> [--output <file>] Write a release manifest for a tree" \
|
|
37
|
+
" explain-variant [--bundle=<name>] [name] Show a variant and its per-shell impact" \
|
|
38
|
+
" explain-bundles [--bundle=<name>] [--variant=<name>] Show each bundle's closure" \
|
|
39
|
+
" layer-lint <name> Validate a contribution layer structure" \
|
|
40
|
+
" version Print version" \
|
|
41
|
+
"" \
|
|
42
|
+
"Environment:" \
|
|
43
|
+
" XDG_DATA_HOME Release storage root (default: ~/.local/share)" \
|
|
44
|
+
" XDG_CONFIG_HOME Active pointer symlink (default: ~/.config)" \
|
|
45
|
+
" XDG_STATE_HOME Lock and journal state (default: ~/.local/state)" \
|
|
46
|
+
"" \
|
|
47
|
+
"Run 'valise <command> --help' for command-specific usage."
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
# Per-command usage. Each command prints its own contract instead of the
|
|
51
|
+
# global list, so `valise compile --help` names the arguments that command
|
|
52
|
+
# actually accepts.
|
|
53
|
+
|
|
54
|
+
usage_init() {
|
|
55
|
+
printf '%s\n' \
|
|
56
|
+
"usage: valise init [posix|fish] [--source-tree]" \
|
|
57
|
+
"" \
|
|
58
|
+
"Print the shell integration snippet for the active release. valise install" \
|
|
59
|
+
"and valise apply write it for you; use this to wire a startup file by hand." \
|
|
60
|
+
"" \
|
|
61
|
+
" posix A managed block for any POSIX shell. It loads the plan for" \
|
|
62
|
+
" the running shell class: ksh, zsh, bash, or sh for any other." \
|
|
63
|
+
" fish The Fish conf.d hook." \
|
|
64
|
+
" --source-tree Skip release verification in the Fish hook (development only)." \
|
|
65
|
+
"" \
|
|
66
|
+
"With no argument, fish when \$SHELL names fish, otherwise posix."
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
usage_install() {
|
|
70
|
+
printf '%s\n' \
|
|
71
|
+
"usage: valise install [--no-integration]" \
|
|
72
|
+
"" \
|
|
73
|
+
"Install the release tree in the current directory and make it active, then" \
|
|
74
|
+
"write the shell integration." \
|
|
75
|
+
"" \
|
|
76
|
+
"A managed block is written to ~/.profile; to the first of ~/.bash_profile and" \
|
|
77
|
+
"~/.bash_login that exists, because it shadows ~/.profile for bash; to ~/.bashrc" \
|
|
78
|
+
"and ~/.zshrc when that shell is \$SHELL or the file exists; and to ~/.zprofile" \
|
|
79
|
+
"when zsh is installed or the file exists. Symlinked files are left alone. A" \
|
|
80
|
+
"Fish conf.d hook is written when Fish is installed. Each install replaces the" \
|
|
81
|
+
"block in place. Each command the release publishes gets a stub in the command" \
|
|
82
|
+
"directory (see valise doctor)." \
|
|
83
|
+
"" \
|
|
84
|
+
"Every startup file is checked before the active release changes. If a later" \
|
|
85
|
+
"step fails, the previous active release is restored." \
|
|
86
|
+
"" \
|
|
87
|
+
" --no-integration Write no startup file, Fish hook, or command stubs."
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
usage_doctor() {
|
|
91
|
+
printf '%s\n' \
|
|
92
|
+
"usage: valise doctor [--pre-install] [--no-integration]" \
|
|
93
|
+
"" \
|
|
94
|
+
"Report the environment, the active release, and the shell integration." \
|
|
95
|
+
"" \
|
|
96
|
+
" --pre-install Skip the active-release and integration checks, for use" \
|
|
97
|
+
" before the first install." \
|
|
98
|
+
" --no-integration Check the environment and active release only."
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
usage_lint() {
|
|
102
|
+
printf '%s\n' \
|
|
103
|
+
"usage: valise lint [--require-parsers] [module...]" \
|
|
104
|
+
"" \
|
|
105
|
+
"Check the project: every metadata record and the files it names, each layer" \
|
|
106
|
+
"(contrib_ names, version=, dependencies inside the layer or the engine), the" \
|
|
107
|
+
"lint_layer_forbid pattern from valise.conf, every bundle compiled for every" \
|
|
108
|
+
"variant and shell, and the syntax of each body and test with the parser of" \
|
|
109
|
+
"every shell it declares. Listing modules limits the syntax checks to them." \
|
|
110
|
+
"" \
|
|
111
|
+
" --require-parsers Fail instead of skipping when a shell's parser is missing."
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
usage_test() {
|
|
115
|
+
printf '%s\n' \
|
|
116
|
+
"usage: valise test [--shell=<class>[,<class>...]] [--require-shells] [module...]" \
|
|
117
|
+
"" \
|
|
118
|
+
"Run the tests= scripts of each module (default: every module that has them)" \
|
|
119
|
+
"in every shell class it declares whose interpreter is installed: dash (or a" \
|
|
120
|
+
"plain sh) for sh, bash, zsh, ksh, and fish. Each run builds a release with" \
|
|
121
|
+
"the module as its only root, starts the shell with env -i, a fresh HOME," \
|
|
122
|
+
"TMPDIR and XDG directories, and PATH=\${VALISE_TEST_PATH:-/usr/bin:/bin:/usr/sbin:/sbin}" \
|
|
123
|
+
"plus the interpreter's directory, loads the module in strict mode, then runs" \
|
|
124
|
+
"the test. A test passes when it exits 0. Fish tests (*.fish) run only in" \
|
|
125
|
+
"Fish, other tests only in POSIX shells. A test can write fixtures and call" \
|
|
126
|
+
"valise_test_reload to load the module again. VALISE_TEST_ROOT, VALISE_TEST_MODULE," \
|
|
127
|
+
"VALISE_TEST_MODULE_DIR, VALISE_TEST_SHELL and VALISE_PROJECT_ROOT are set." \
|
|
128
|
+
"" \
|
|
129
|
+
" --shell=<class> Run only these shell classes." \
|
|
130
|
+
" --require-shells Fail instead of skipping when an interpreter is missing."
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
usage_run() {
|
|
134
|
+
printf '%s\n' \
|
|
135
|
+
"usage: valise run [--shell=<class>] [--module=<m>]... [--bundle=<b>] [--variant=<v>] [--keep-env] -- <script> [args...]" \
|
|
136
|
+
"" \
|
|
137
|
+
"Load modules into a shell and run a script there; the exit status is the" \
|
|
138
|
+
"script's. With --module the named modules are the only roots; otherwise the" \
|
|
139
|
+
"bundle and variant (default: valise.conf) select them. The shell class" \
|
|
140
|
+
"defaults to the one \$SHELL names, else sh. The environment is quarantined as" \
|
|
141
|
+
"for valise test unless --keep-env is given."
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
usage_env() {
|
|
145
|
+
printf '%s\n' \
|
|
146
|
+
"usage: valise env" \
|
|
147
|
+
"" \
|
|
148
|
+
"Print KEY=value lines, shell-quoted, for VALISE_VERSION, VALISE_ENGINE_ROOT," \
|
|
149
|
+
"VALISE_PROJECT_ROOT (empty outside a project), VALISE_DATA_DIR," \
|
|
150
|
+
"VALISE_CONFIG_DIR, VALISE_STATE_DIR, VALISE_RELEASES_DIR, VALISE_ACTIVE_LINK," \
|
|
151
|
+
"and VALISE_BIN_DIR."
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
usage_uninstall() {
|
|
155
|
+
printf '%s\n' \
|
|
156
|
+
"usage: valise uninstall [--keep-releases]" \
|
|
157
|
+
"" \
|
|
158
|
+
"Remove what valise install wrote: the managed block from each startup file" \
|
|
159
|
+
"(every other line is kept, and a file install created is deleted when it is" \
|
|
160
|
+
"left empty), the Fish hook, the command stubs valise owns, the active link," \
|
|
161
|
+
"and the installed releases. Files valise does not own are left alone." \
|
|
162
|
+
"" \
|
|
163
|
+
" --keep-releases Keep the installed releases." \
|
|
164
|
+
"" \
|
|
165
|
+
"The valise CLI itself is not removed."
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
usage_release() {
|
|
169
|
+
printf '%s\n' \
|
|
170
|
+
"usage: valise release <list|use|rollback|prune|verify> [options]" \
|
|
171
|
+
"" \
|
|
172
|
+
" list List installed releases and mark the active one." \
|
|
173
|
+
" use <sha256> Verify a release and make it active." \
|
|
174
|
+
" rollback Verify the release that was active before the last" \
|
|
175
|
+
" switch and make it active again." \
|
|
176
|
+
" prune [--keep=N] Remove older releases, keeping the active one and the" \
|
|
177
|
+
" N newest by modification time. A release that fails" \
|
|
178
|
+
" verification is kept, not removed." \
|
|
179
|
+
" verify [--print-root] Verify the sealed active release and optionally" \
|
|
180
|
+
" print its root." \
|
|
181
|
+
"" \
|
|
182
|
+
"prune --keep=0 keeps only the active release."
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
usage_new() {
|
|
186
|
+
printf '%s\n' \
|
|
187
|
+
"usage: valise new [dir]" \
|
|
188
|
+
"" \
|
|
189
|
+
"Scaffold a new valise project in dir (default: the current directory)." \
|
|
190
|
+
"" \
|
|
191
|
+
"The directory must be empty or absent. The scaffold contains valise.conf," \
|
|
192
|
+
"bundles.tsv with sh, bash, zsh, ksh and fish rows, variants.tsv, the POSIX" \
|
|
193
|
+
"seed module profile_main and the Fish seed module profile_main_fish."
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
usage_module() {
|
|
197
|
+
printf '%s\n' \
|
|
198
|
+
"usage: valise module <new|list|remove> [options]" \
|
|
199
|
+
"" \
|
|
200
|
+
" new <name> [--exports=<list>] [--into=<module>[,...] | --no-wire]" \
|
|
201
|
+
" Create a POSIX module in module.d/ and add it" \
|
|
202
|
+
" to the requires= of the bundle's single POSIX" \
|
|
203
|
+
" root, of the named modules, or of none." \
|
|
204
|
+
" list List the project's and its layers' modules." \
|
|
205
|
+
" remove <name> Remove a module and its references in metadata," \
|
|
206
|
+
" bundle roots, and variant exclusions. Refuses" \
|
|
207
|
+
" if that would leave a bundle or module empty."
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
usage_build() {
|
|
211
|
+
printf '%s\n' \
|
|
212
|
+
"usage: valise build [--variant=<name>] [--bundle=<name>] [out]" \
|
|
213
|
+
"" \
|
|
214
|
+
"Build a release tree from the project in the current directory." \
|
|
215
|
+
"" \
|
|
216
|
+
" --variant=<name> Build variant whose exclusion list applies (default:" \
|
|
217
|
+
" valise.conf variant=)." \
|
|
218
|
+
" --bundle=<name> Bundle whose roots seed each plan (default: valise.conf" \
|
|
219
|
+
" bundle=)." \
|
|
220
|
+
" out Output directory (default: build/release). An existing" \
|
|
221
|
+
" default output is replaced after a successful build." \
|
|
222
|
+
" An explicit output must be empty or absent." \
|
|
223
|
+
"" \
|
|
224
|
+
"The tree holds plans/<shell>.sh for each POSIX shell the bundle names," \
|
|
225
|
+
"runtime/capabilities.sh, valise-release.conf, manifest.tsv, and the metadata" \
|
|
226
|
+
"and bodies of exactly the modules some plan loads. Engine modules are copied" \
|
|
227
|
+
"under valise/, layer modules under layers/<provider>/. A module that" \
|
|
228
|
+
"publishes commands adds plans/commands/<module>.sh and bin/<command>; Fish" \
|
|
229
|
+
"roots add runtime/fish/."
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
usage_apply() {
|
|
233
|
+
printf '%s\n' \
|
|
234
|
+
"usage: valise apply [--variant=<name>] [--bundle=<name>] [--no-integration] [--dry-run]" \
|
|
235
|
+
"" \
|
|
236
|
+
"Build the project, install the result, write the shell integration, and verify" \
|
|
237
|
+
"the active release. See 'valise install --help' for the files it writes." \
|
|
238
|
+
"" \
|
|
239
|
+
" --no-integration Write no startup file, Fish hook, or command stubs." \
|
|
240
|
+
" --dry-run Build, then print what install would change: the release," \
|
|
241
|
+
" each startup file, the Fish hook, and the command stubs." \
|
|
242
|
+
" Nothing outside build/ is written."
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
usage_status() {
|
|
246
|
+
printf '%s\n' \
|
|
247
|
+
"usage: valise status" \
|
|
248
|
+
"" \
|
|
249
|
+
"Report the project defaults, the integration in each startup file, the bundle," \
|
|
250
|
+
"variant and valise version the active release was built with, and whether the" \
|
|
251
|
+
"active release matches build/release."
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
usage_compile() {
|
|
255
|
+
printf '%s\n' \
|
|
256
|
+
"usage: valise compile [--bundle=<name>] [--variant=<name>] <output-dir>" \
|
|
257
|
+
"" \
|
|
258
|
+
"Compile the project's modules into <output-dir>/<shell>.sh plans for the" \
|
|
259
|
+
"POSIX shells the bundle names. Use build for an installable release." \
|
|
260
|
+
"" \
|
|
261
|
+
" --bundle=<name> Bundle whose roots seed each plan (default: valise.conf)." \
|
|
262
|
+
" --variant=<name> Variant whose exclusion list applies (default: valise.conf)." \
|
|
263
|
+
" output-dir Destination directory. It must be empty or absent."
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
usage_registry() {
|
|
267
|
+
printf '%s\n' \
|
|
268
|
+
"usage: valise registry [path]" \
|
|
269
|
+
"" \
|
|
270
|
+
"Print the module table valise builds from metadata: the project's module.d/," \
|
|
271
|
+
"each layers/<provider>/module.d/, then the engine's own modules under the" \
|
|
272
|
+
"source valise. The table is internal; nothing needs to commit it." \
|
|
273
|
+
"" \
|
|
274
|
+
" path Write the table to this file instead of standard output."
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
usage_explain_bundles() {
|
|
278
|
+
printf '%s\n' \
|
|
279
|
+
"usage: valise explain-bundles [--bundle=<name>] [--variant=<name>]" \
|
|
280
|
+
"" \
|
|
281
|
+
"Show the roots and the ordered module closure each bundle resolves to, per" \
|
|
282
|
+
"shell, with each module's source." \
|
|
283
|
+
"" \
|
|
284
|
+
" --bundle=<name> Report one bundle instead of all of them." \
|
|
285
|
+
" --variant=<name> Apply this variant's exclusions (default: valise.conf)."
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
usage_layer_lint() {
|
|
289
|
+
printf '%s\n' \
|
|
290
|
+
"usage: valise layer-lint <layer-name>" \
|
|
291
|
+
"" \
|
|
292
|
+
"Validate a contribution layer's structure, namespace, metadata, load paths," \
|
|
293
|
+
"file modes, and dependency closure." \
|
|
294
|
+
"" \
|
|
295
|
+
" layer-name Provider directory under layers/, or a path to a layer" \
|
|
296
|
+
" tree containing module.d/."
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
usage_explain_variant() {
|
|
300
|
+
printf '%s\n' \
|
|
301
|
+
"usage: valise explain-variant [--bundle=<name>] [variant-name]" \
|
|
302
|
+
"" \
|
|
303
|
+
"Show a variant's description, excluded modules, and how many of the bundle's" \
|
|
304
|
+
"roots it removes per shell." \
|
|
305
|
+
"" \
|
|
306
|
+
" --bundle=<name> Bundle to measure against (default: valise.conf)." \
|
|
307
|
+
" variant-name Variant from variants.tsv (default: valise.conf)."
|
|
308
|
+
}
|
package/lib/compiler.awk
CHANGED
|
@@ -7,11 +7,13 @@
|
|
|
7
7
|
# Lines starting with MOD: identity<TAB>requires<TAB>load_path<TAB>platforms<TAB>side_effect<TAB>exports<TAB>optional
|
|
8
8
|
# identity is module@meta_source when registry sources are qualified.
|
|
9
9
|
# Lines starting with PRELUDE: sp_cap function names (space-separated)
|
|
10
|
-
# Output: complete installed plan on stdout.
|
|
10
|
+
# Output: complete installed plan on stdout. With -v mode=closure the
|
|
11
|
+
# compiler validates and orders the closure, then prints one module identity
|
|
12
|
+
# per line in load order instead of rendering a plan.
|
|
11
13
|
|
|
12
14
|
BEGIN {
|
|
13
|
-
prefix = "
|
|
14
|
-
prelude_dest = "
|
|
15
|
+
prefix = "_valise_plan_"
|
|
16
|
+
prelude_dest = "runtime/capabilities.sh"
|
|
15
17
|
seed_count = 0
|
|
16
18
|
mod_count = 0
|
|
17
19
|
prelude_fn_count = 0
|
|
@@ -306,8 +308,13 @@ END {
|
|
|
306
308
|
}
|
|
307
309
|
}
|
|
308
310
|
|
|
311
|
+
if (mode == "closure") {
|
|
312
|
+
for (oi = 1; oi <= ordered_count; oi++) print ordered[oi]
|
|
313
|
+
exit 0
|
|
314
|
+
}
|
|
315
|
+
|
|
309
316
|
# --- Render plan ---
|
|
310
|
-
printf "#
|
|
317
|
+
printf "# valise-plan-v2\n"
|
|
311
318
|
printf "# Generated by valise compile; DO NOT EDIT.\n"
|
|
312
319
|
printf "# plan=%s\n", plan_name
|
|
313
320
|
printf "# roots="
|
package/lib/fish/loader.fish
CHANGED
|
@@ -157,6 +157,12 @@ function _sp_fish_loader_function_copy_matches --no-scope-shadowing --descriptio
|
|
|
157
157
|
end
|
|
158
158
|
set -l original_declaration (string replace -r '^function [^[:space:]]+' 'function __source_backed_copy__' -- "$original_lines[2]")
|
|
159
159
|
set -l copy_declaration (string replace -r '^function [^[:space:]]+' 'function __source_backed_copy__' -- "$copy_lines[2]")
|
|
160
|
+
# `functions --copy` drops --wraps, which every `alias` sets. The option
|
|
161
|
+
# only links completions; the body and every other option must still
|
|
162
|
+
# agree. A restore re-checks full provenance and fails closed.
|
|
163
|
+
set -l wraps_option ' --wraps=(\'[^\']*\'|"[^"]*"|[^[:space:]]+)'
|
|
164
|
+
set original_declaration (string replace -r -a -- $wraps_option '' "$original_declaration")
|
|
165
|
+
set copy_declaration (string replace -r -a -- $wraps_option '' "$copy_declaration")
|
|
160
166
|
test "$original_declaration" = "$copy_declaration"; or return 1
|
|
161
167
|
set -l copy_index 3
|
|
162
168
|
while test $copy_index -le (builtin count $copy_lines)
|
|
@@ -1582,6 +1588,21 @@ function _sp_fish_loader_load_ordered_impl --description 'Load modules from seed
|
|
|
1582
1588
|
set -a reserved_function_before (builtin functions --details "$reserved_name")
|
|
1583
1589
|
end
|
|
1584
1590
|
|
|
1591
|
+
# Introspecting a name materializes Fish 3's autoloadable-but-undefined
|
|
1592
|
+
# functions into `functions --all --names`, so the pre-loop snapshot is
|
|
1593
|
+
# stale by the time the body runs. Re-capture the diff baseline after the
|
|
1594
|
+
# snapshot loop and before sourcing; otherwise Fish's own system functions
|
|
1595
|
+
# would be attributed to the body and published in the ownership ledger
|
|
1596
|
+
# with an unauthenticatable `/usr/share/fish` source. The snapshot copies
|
|
1597
|
+
# above are already defined, but are re-added defensively so a baseline
|
|
1598
|
+
# that failed to enumerate them can never classify them as body output.
|
|
1599
|
+
set -l function_names_before (builtin functions --all --names)
|
|
1600
|
+
for caller_function_snapshot in $caller_function_snapshot_copies
|
|
1601
|
+
if not builtin contains -- "$caller_function_snapshot" $function_names_before
|
|
1602
|
+
set -a function_names_before "$caller_function_snapshot"
|
|
1603
|
+
end
|
|
1604
|
+
end
|
|
1605
|
+
|
|
1585
1606
|
# Snapshot private loader globals before sourcing. Module bodies are
|
|
1586
1607
|
# allowed to publish their declared functions, not to rewrite the
|
|
1587
1608
|
# loader's discovery roots, provider cache, or loaded set.
|
|
@@ -1975,14 +1996,22 @@ function _sp_fish_loader_load_ordered_impl --description 'Load modules from seed
|
|
|
1975
1996
|
builtin set loader_state_changed 1
|
|
1976
1997
|
end
|
|
1977
1998
|
# Classify all protected-state and function mutations before rollback.
|
|
1978
|
-
# A combined handshake mutation plus
|
|
1979
|
-
#
|
|
1999
|
+
# A combined handshake mutation plus `cd` mutation must never enter a
|
|
2000
|
+
# return path that leaves a replacement critical function installed.
|
|
2001
|
+
# Fish 4 embeds `cd`; Fish 3 loads it from the installation function
|
|
2002
|
+
# path. Both are Fish-provided definitions the loader cannot restore
|
|
2003
|
+
# with provenance after a body replaces them, so both fail closed.
|
|
1980
2004
|
set -l preflight_embedded_mutation ''
|
|
1981
2005
|
set -l preflight_embedded_index 1
|
|
1982
2006
|
for preflight_reserved_name in $reserved_function_names
|
|
1983
2007
|
set -l preflight_before_source "$reserved_function_before[$preflight_embedded_index]"
|
|
1984
2008
|
set -l preflight_after_source (builtin functions --details "$preflight_reserved_name")
|
|
1985
|
-
|
|
2009
|
+
set -l preflight_before_dir (builtin path dirname -- "$preflight_before_source")
|
|
2010
|
+
set -l preflight_fish_provided 0
|
|
2011
|
+
if builtin string match -q 'embedded:*' -- "$preflight_before_source"; or builtin test "$preflight_before_source" = builtin; or builtin contains -- "$preflight_before_dir" /usr/share/fish/functions /usr/local/share/fish/functions /opt/local/share/fish/functions /opt/homebrew/share/fish/functions
|
|
2012
|
+
set preflight_fish_provided 1
|
|
2013
|
+
end
|
|
2014
|
+
if builtin test $preflight_fish_provided -eq 1; and not builtin test "$preflight_after_source" = "$preflight_before_source"
|
|
1986
2015
|
set preflight_embedded_mutation "$preflight_reserved_name"
|
|
1987
2016
|
break
|
|
1988
2017
|
end
|
|
@@ -2175,8 +2204,24 @@ function _sp_fish_loader_load_ordered_impl --description 'Load modules from seed
|
|
|
2175
2204
|
set -g _sp_fish_loaded_modules $_sp_fish_loaded_modules $mod
|
|
2176
2205
|
for owned_function in $new_function_names $mod_exports
|
|
2177
2206
|
if test -n "$owned_function"; and not builtin contains -- $owned_function $_sp_fish_loader_owned_exports
|
|
2207
|
+
set -l owned_source (builtin functions --details "$owned_function")
|
|
2208
|
+
# Fish's own system functions are not module state. A body can
|
|
2209
|
+
# materialize them by sourcing a completion or function file or
|
|
2210
|
+
# by running completions, but the ledger must not claim them:
|
|
2211
|
+
# their source is not an authenticated release path, so the next
|
|
2212
|
+
# activation would fail closed, and its cleanup would erase real
|
|
2213
|
+
# Fish functions. Fish 3 reports a file under the installation
|
|
2214
|
+
# prefix; Fish 4 reports an embedded: path. A module's own
|
|
2215
|
+
# functions report their body file (or "-" for an alias), so they
|
|
2216
|
+
# are unaffected. Rollback still removes these from
|
|
2217
|
+
# new_function_names because, for a failed body, they are this
|
|
2218
|
+
# activation's residue.
|
|
2219
|
+
switch "$owned_source"
|
|
2220
|
+
case '/usr/share/fish/*' '/usr/local/share/fish/*' '/opt/local/share/fish/*' '/opt/homebrew/share/fish/*' 'embedded:completions/*' 'embedded:functions/*' 'autoloaded:*'
|
|
2221
|
+
continue
|
|
2222
|
+
end
|
|
2178
2223
|
set -a _sp_fish_loader_owned_exports $owned_function
|
|
2179
|
-
set -a _sp_fish_loader_owned_sources
|
|
2224
|
+
set -a _sp_fish_loader_owned_sources $owned_source
|
|
2180
2225
|
end
|
|
2181
2226
|
end
|
|
2182
2227
|
end
|
|
@@ -2235,13 +2280,28 @@ function _sp_fish_loader_init --description 'Initialize the Fish loader with sta
|
|
|
2235
2280
|
# providers, followed by engine generic metadata and project generic
|
|
2236
2281
|
# metadata. Duplicate names are accepted only when metadata and native
|
|
2237
2282
|
# Fish bodies are byte-identical; conflicting providers fail closed.
|
|
2283
|
+
# A built release (valise-release.conf beside runtime/) ships its loader at
|
|
2284
|
+
# runtime/fish/loader.fish, so ../.. is the release root. Its providers are
|
|
2285
|
+
# the primary modules, each layers/<provider>, then the engine modules
|
|
2286
|
+
# under valise/, in the order valise build resolves them.
|
|
2287
|
+
if test -n "$engine_root"; and test -f "$engine_root/valise-release.conf"
|
|
2288
|
+
if test -d "$engine_root/module.d"
|
|
2289
|
+
sp_fish_loader_add_root "$engine_root"; or return 1
|
|
2290
|
+
end
|
|
2291
|
+
for layer_root in "$engine_root"/layers/*
|
|
2292
|
+
if test -d "$layer_root/module.d"
|
|
2293
|
+
sp_fish_loader_add_root "$layer_root"; or return 1
|
|
2294
|
+
end
|
|
2295
|
+
end
|
|
2296
|
+
if test -d "$engine_root/valise/module.d"
|
|
2297
|
+
sp_fish_loader_add_root "$engine_root/valise"; or return 1
|
|
2298
|
+
end
|
|
2299
|
+
return 0
|
|
2300
|
+
end
|
|
2301
|
+
|
|
2238
2302
|
set -l project_root ''
|
|
2239
2303
|
if set -q SHELL_PROJECT_ROOT
|
|
2240
|
-
|
|
2241
|
-
set project_root "$SHELL_PROJECT_ROOT/shell"
|
|
2242
|
-
else
|
|
2243
|
-
set project_root "$SHELL_PROJECT_ROOT"
|
|
2244
|
-
end
|
|
2304
|
+
set project_root "$SHELL_PROJECT_ROOT"
|
|
2245
2305
|
end
|
|
2246
2306
|
if test -n "$project_root"; and test -d "$project_root/modules/fish"
|
|
2247
2307
|
sp_fish_loader_add_root "$project_root/modules/fish"; or return 1
|
package/lib/fish/metadata.fish
CHANGED
|
@@ -76,7 +76,7 @@ function sp_fish_metadata_validate_shell_list --description 'Validate shell list
|
|
|
76
76
|
end
|
|
77
77
|
set seen 1
|
|
78
78
|
switch "$sh"
|
|
79
|
-
case sh bash zsh ksh fish
|
|
79
|
+
case posix sh bash zsh ksh fish
|
|
80
80
|
# valid
|
|
81
81
|
case '*'
|
|
82
82
|
sp_fish_metadata_error "invalid shell: $sh"
|
|
@@ -190,7 +190,10 @@ function sp_fish_metadata_read --description 'Read and validate a .meta file, ou
|
|
|
190
190
|
set -l m_platforms ''
|
|
191
191
|
set -l m_side_effect ''
|
|
192
192
|
set -l m_exports ''
|
|
193
|
-
set -l
|
|
193
|
+
set -l m_commands ''
|
|
194
|
+
set -l m_executables ''
|
|
195
|
+
set -l m_tests ''
|
|
196
|
+
set -l m_seen
|
|
194
197
|
set -l m_version ''
|
|
195
198
|
set -l m_load ''
|
|
196
199
|
|
|
@@ -206,6 +209,11 @@ function sp_fish_metadata_read --description 'Read and validate a .meta file, ou
|
|
|
206
209
|
end
|
|
207
210
|
set -l key (string split -m1 '=' -- "$line")[1]
|
|
208
211
|
set -l val (string split -m1 '=' -- "$line")[2]
|
|
212
|
+
if contains -- "$key" $m_seen
|
|
213
|
+
sp_fish_metadata_error "duplicate metadata field: $key"
|
|
214
|
+
return 1
|
|
215
|
+
end
|
|
216
|
+
set -a m_seen "$key"
|
|
209
217
|
switch "$key"
|
|
210
218
|
case name; set m_name $val
|
|
211
219
|
case requires; set m_requires $val
|
|
@@ -214,7 +222,12 @@ function sp_fish_metadata_read --description 'Read and validate a .meta file, ou
|
|
|
214
222
|
case platforms; set m_platforms $val
|
|
215
223
|
case side_effect; set m_side_effect $val
|
|
216
224
|
case exports; set m_exports $val
|
|
217
|
-
case
|
|
225
|
+
case commands; set m_commands $val
|
|
226
|
+
case executables; set m_executables $val
|
|
227
|
+
case tests; set m_tests $val
|
|
228
|
+
case updates
|
|
229
|
+
sp_fish_metadata_error 'metadata field updates is not supported since valise 0.3.0; publish commands with commands= or executables='
|
|
230
|
+
return 1
|
|
218
231
|
case version; set m_version $val
|
|
219
232
|
case load; set m_load $val
|
|
220
233
|
case load_hook
|
|
@@ -275,9 +288,38 @@ function sp_fish_metadata_read --description 'Read and validate a .meta file, ou
|
|
|
275
288
|
if not sp_fish_metadata_validate_identifier_list "$m_exports" export
|
|
276
289
|
return 1
|
|
277
290
|
end
|
|
278
|
-
if not sp_fish_metadata_validate_identifier_list "$
|
|
291
|
+
if not sp_fish_metadata_validate_identifier_list "$m_commands" command
|
|
279
292
|
return 1
|
|
280
293
|
end
|
|
294
|
+
for cmd in (string split ' ' -- $m_commands)
|
|
295
|
+
test -n "$cmd"; or continue
|
|
296
|
+
if not contains -- "$cmd" (string split ' ' -- $m_exports)
|
|
297
|
+
sp_fish_metadata_error "command is not a declared export: $cmd"
|
|
298
|
+
return 1
|
|
299
|
+
end
|
|
300
|
+
end
|
|
301
|
+
for kind in executable test
|
|
302
|
+
set -l paths $m_executables
|
|
303
|
+
test "$kind" = test; and set paths $m_tests
|
|
304
|
+
if string match -qr '[*?\[\]\\\\]' -- "$paths"
|
|
305
|
+
sp_fish_metadata_error "invalid $kind: contains glob metacharacter"
|
|
306
|
+
return 1
|
|
307
|
+
end
|
|
308
|
+
for p in (string split ' ' -- $paths)
|
|
309
|
+
test -n "$p"; or continue
|
|
310
|
+
if string match -qr '(^|/)\.(/|$)|//|/$' -- "$p"
|
|
311
|
+
sp_fish_metadata_error "invalid $kind path: $p"
|
|
312
|
+
return 1
|
|
313
|
+
end
|
|
314
|
+
if not sp_fish_metadata_validate_relative_path "$p"
|
|
315
|
+
return 1
|
|
316
|
+
end
|
|
317
|
+
if test "$kind" = executable; and not string match -qr '^[A-Za-z0-9_]' -- (string split -r -m1 / -- "$p")[-1]
|
|
318
|
+
sp_fish_metadata_error "invalid executable name: "(string split -r -m1 / -- "$p")[-1]
|
|
319
|
+
return 1
|
|
320
|
+
end
|
|
321
|
+
end
|
|
322
|
+
end
|
|
281
323
|
if not sp_fish_metadata_validate_version "$m_version"
|
|
282
324
|
return 1
|
|
283
325
|
end
|
|
@@ -292,7 +334,9 @@ function sp_fish_metadata_read --description 'Read and validate a .meta file, ou
|
|
|
292
334
|
echo "platforms=$m_platforms"
|
|
293
335
|
echo "side_effect=$m_side_effect"
|
|
294
336
|
echo "exports=$m_exports"
|
|
295
|
-
echo "
|
|
337
|
+
echo "commands=$m_commands"
|
|
338
|
+
echo "executables=$m_executables"
|
|
339
|
+
echo "tests=$m_tests"
|
|
296
340
|
echo "version=$m_version"
|
|
297
341
|
echo "load=$m_load"
|
|
298
342
|
return 0
|