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/docs/module-abi.md
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Module ABI
|
|
2
2
|
|
|
3
|
-
This document defines
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
This document defines module metadata and the rules the compiled plans and
|
|
4
|
+
the loaders apply to it. Metadata is data: valise never executes a module to
|
|
5
|
+
learn its name, dependencies, or supported shells.
|
|
6
6
|
|
|
7
7
|
## Metadata file format
|
|
8
8
|
|
|
9
9
|
Module metadata lives in `module.d/*.meta` as UTF-8 text with one `key=value`
|
|
10
10
|
field per line. Blank lines and `#` comments are ignored. Values are plain text;
|
|
11
11
|
there is no shell quoting, interpolation, command substitution, glob expansion,
|
|
12
|
-
or `eval` phase.
|
|
12
|
+
or `eval` phase. Each field may appear once: a repeated key is rejected rather
|
|
13
|
+
than letting the last value win. An unknown field is rejected, and so is
|
|
14
|
+
`updates`, which was removed in 0.3.0.
|
|
13
15
|
|
|
14
16
|
Required fields:
|
|
15
17
|
|
|
@@ -19,8 +21,8 @@ Required fields:
|
|
|
19
21
|
| `shells` | Space-separated supported shell identifiers. |
|
|
20
22
|
| `platforms` | Space-separated supported platform identifiers. |
|
|
21
23
|
| `side_effect` | Startup/install/update side-effect class. |
|
|
22
|
-
| `load` |
|
|
23
|
-
| `requires` | Required
|
|
24
|
+
| `load` | Path to the module body, relative to the module's source directory. Absent for a **meta module** (see below). |
|
|
25
|
+
| `requires` | Required for a meta module. |
|
|
24
26
|
|
|
25
27
|
Optional fields:
|
|
26
28
|
|
|
@@ -29,7 +31,9 @@ Optional fields:
|
|
|
29
31
|
| `requires` | Space-separated required dependency module identifiers. |
|
|
30
32
|
| `optional` | Space-separated optional dependency module identifiers. |
|
|
31
33
|
| `exports` | Space-separated exported command/function identifiers. |
|
|
32
|
-
| `
|
|
34
|
+
| `commands` | Space-separated exports a built release publishes as commands on PATH. |
|
|
35
|
+
| `executables` | Space-separated module-relative paths of scripts published as commands. |
|
|
36
|
+
| `tests` | Space-separated module-relative test scripts that `valise test` runs. |
|
|
33
37
|
| `version` | Optional module version used to reject version skew across roots. |
|
|
34
38
|
|
|
35
39
|
## Meta modules
|
|
@@ -49,12 +53,11 @@ an export on a meta module is rejected.
|
|
|
49
53
|
name=profile_main
|
|
50
54
|
version=1.0.0
|
|
51
55
|
side_effect=read-only
|
|
52
|
-
requires=
|
|
56
|
+
requires=valise_path valise_editor
|
|
53
57
|
optional=
|
|
54
|
-
shells=
|
|
58
|
+
shells=posix
|
|
55
59
|
platforms=any
|
|
56
60
|
exports=
|
|
57
|
-
updates=
|
|
58
61
|
```
|
|
59
62
|
|
|
60
63
|
At least one of `load` or `requires` is required: a module with neither a
|
|
@@ -75,67 +78,74 @@ whitespace inside one identifier, path separators, quotes, shell metacharacters,
|
|
|
75
78
|
glob characters, and control characters are invalid. Invalid identifiers are
|
|
76
79
|
rejected before the loader can build function names or source a body.
|
|
77
80
|
|
|
78
|
-
Accepted `shells` values are `sh`, `bash`, `zsh`, `ksh`, and
|
|
79
|
-
`
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
`
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
the
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
is
|
|
101
|
-
|
|
81
|
+
Accepted `shells` values are `posix`, `sh`, `bash`, `zsh`, `ksh`, and
|
|
82
|
+
`fish`. Each running POSIX shell belongs to one class: `bash`, `zsh`, or
|
|
83
|
+
`ksh` when the shell can be proven to be that shell, and `sh` for every
|
|
84
|
+
other POSIX shell (dash, BusyBox ash, and so on). The values match classes
|
|
85
|
+
as follows:
|
|
86
|
+
|
|
87
|
+
- `posix` matches every POSIX class: `sh`, `bash`, `zsh`, and `ksh`. Use it
|
|
88
|
+
for a body written in portable shell.
|
|
89
|
+
- `sh` matches only the `sh` class. Combine it with the shells the body also
|
|
90
|
+
supports: `shells=sh bash ksh` loads in dash, bash, and ksh, and is skipped
|
|
91
|
+
in zsh, for a body that needs word splitting zsh does not do.
|
|
92
|
+
- `bash`, `zsh`, and `ksh` match only that class.
|
|
93
|
+
- `fish` selects the native Fish runtime. Fish never sources a POSIX body,
|
|
94
|
+
and no POSIX value matches Fish.
|
|
95
|
+
|
|
96
|
+
A module whose shells do not include the running class is skipped; a bundle
|
|
97
|
+
root, or a module a root requires, that does not support its shell is an
|
|
98
|
+
error.
|
|
99
|
+
|
|
100
|
+
In a built release, the native Fish loader resolves the release's Fish roots
|
|
101
|
+
(`roots_fish=` in `valise-release.conf`) against the release's `module.d/`,
|
|
102
|
+
each `layers/<provider>/module.d/`, and `valise/module.d/`, in that order.
|
|
103
|
+
`runtime/fish/profile.fish` is the adapter the Fish hook sources: it sets
|
|
104
|
+
`_sp_fish_loader_bootstrap_mode` and `_sp_fish_loader_bootstrap_seeds`,
|
|
105
|
+
sources `runtime/fish/loader.fish`, and requires the
|
|
106
|
+
`_sp_fish_loader_bootstrap_status` marker the loader publishes, failing
|
|
107
|
+
closed when it is absent. Duplicate providers of one name are valid only when
|
|
108
|
+
their metadata and Fish bodies are byte-identical.
|
|
102
109
|
|
|
103
110
|
Supported `platforms` values are `any`, `darwin`, `linux`, `bsd`, `freebsd`,
|
|
104
111
|
`openbsd`, and `netbsd`. `platforms=any` matches every supported platform.
|
|
105
112
|
Specific platform values are ORed: `platforms=darwin linux` matches macOS or
|
|
106
113
|
Linux, not BSD.
|
|
107
114
|
|
|
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
|
-
|
|
115
|
+
## Layers
|
|
116
|
+
|
|
117
|
+
A project composes provider modules by vendoring the provider's tree as
|
|
118
|
+
`layers/<provider>/` (its `module.d/` and bodies). Every module in a layer
|
|
119
|
+
uses the `contrib_` prefix, and the `valise_` prefix belongs to the engine.
|
|
120
|
+
Dependencies resolve by name: the same source first, then the only module
|
|
121
|
+
with that name; a name defined in several sources must be written as
|
|
122
|
+
`name@source` where it is used as a root or an exclusion. A built release
|
|
123
|
+
copies the layer modules it loads to `layers/<provider>/`, and one manifest
|
|
124
|
+
covers the project, layer, and engine files together.
|
|
125
|
+
|
|
126
|
+
To update a provider, copy a reviewed revision into `layers/<provider>/`,
|
|
127
|
+
review the diff, and rebuild; record the provider revision beside it if you
|
|
128
|
+
need to know later which one you have. The manifest proves that the
|
|
129
|
+
installed files match the release, not who wrote them.
|
|
130
|
+
|
|
131
|
+
### The development loader's search path
|
|
132
|
+
|
|
133
|
+
The POSIX loader in `lib/loader.sh`, used by `entrypoints/profile.sh` from an
|
|
134
|
+
engine checkout, resolves modules across a priority-ordered root list
|
|
135
|
+
instead: the primary root first, then the colon-separated
|
|
136
|
+
`VALISE_MODULE_PATH`. Its rules, enforced by
|
|
137
|
+
`tests/loader/multi-root.test.sh`:
|
|
138
|
+
|
|
139
|
+
- Every element must be a non-empty, readable, searchable directory. An
|
|
140
|
+
empty element, a missing directory, a newline, or any of the glob
|
|
141
|
+
characters `[`, `?`, and `*` is rejected. Duplicate elements are
|
|
142
|
+
deduplicated; the first occurrence keeps its priority.
|
|
143
|
+
- A module present in several roots must have identical metadata and body
|
|
144
|
+
bytes. Identical copies resolve to the highest-priority root; any
|
|
145
|
+
difference is an error naming both paths.
|
|
146
|
+
- A module provided only by a layer root must carry the `contrib_` prefix.
|
|
147
|
+
- Bodies load from the root that provided the metadata. Dependencies resolve
|
|
148
|
+
across roots in both directions, and the duplicate-export check is global.
|
|
139
149
|
|
|
140
150
|
## Versioning
|
|
141
151
|
|
|
@@ -143,10 +153,11 @@ Shared modules carry an optional `version` field so independent releases
|
|
|
143
153
|
of the same name can be told apart. The value must start with a digit
|
|
144
154
|
and contain only digits, letters, `.`, `_`, `-`; an empty value means
|
|
145
155
|
unversioned. Providers should bump the version for a breaking change.
|
|
146
|
-
Consumers vendor a specific provider snapshot;
|
|
147
|
-
|
|
156
|
+
Consumers vendor a specific provider snapshot; nothing resolves version
|
|
157
|
+
ranges. See [Layers](#layers).
|
|
148
158
|
|
|
149
|
-
Enforcement,
|
|
159
|
+
Enforcement, where one name has several providers (the development loader's
|
|
160
|
+
roots, or the Fish loader's providers):
|
|
150
161
|
|
|
151
162
|
- The same name with different valid versions across roots fails closed
|
|
152
163
|
with a version-skew diagnostic naming both versions and both paths,
|
|
@@ -160,32 +171,6 @@ A versioned record that disagrees with itself is not a version at all:
|
|
|
160
171
|
malformed versions are rejected by `sp_metadata_read` before any body
|
|
161
172
|
is sourced.
|
|
162
173
|
|
|
163
|
-
## Cross-repo composition
|
|
164
|
-
|
|
165
|
-
The supported composition is a primary consumer root plus one
|
|
166
|
-
version-pinned layer root per provider.
|
|
167
|
-
The provider tree is vendored under `layer/<name>/` of the release
|
|
168
|
-
(preserving its internal `module.d/` + `modules/` layout), and a single
|
|
169
|
-
manifest covers the whole closure, so `release verify` checks consumer
|
|
170
|
-
and provider bytes together before anything is sourced.
|
|
171
|
-
|
|
172
|
-
- Pinning: record the provider source and revision beside the vendored
|
|
173
|
-
bytes (the e2e example writes `layer/shared/layer-pin.txt` from
|
|
174
|
-
`git rev-parse HEAD` at vendor time). Re-pinning means copying the
|
|
175
|
-
provider at a new revision, reviewing the diff, and rebuilding the
|
|
176
|
-
manifest. Pin by git SHA and review the diff; the seal proves the
|
|
177
|
-
release matches its manifest, not who authored it.
|
|
178
|
-
- Loading: the consumer sets `VALISE_MODULE_ROOT` to the release and
|
|
179
|
-
`VALISE_MODULE_PATH` to the layer directory inside it. Deployed login
|
|
180
|
-
snippets carry only the primary root; the layer path is a consumer
|
|
181
|
-
setting applied when sourcing the entrypoint.
|
|
182
|
-
- Naming: layer-only modules must carry the `contrib_` prefix, and
|
|
183
|
-
same-name modules across roots must be byte-identical or the load
|
|
184
|
-
fails closed naming both paths. Dependencies resolve across the
|
|
185
|
-
boundary in both directions: layer modules may require primary
|
|
186
|
-
modules, and primary modules may follow optional dependencies into
|
|
187
|
-
the layer.
|
|
188
|
-
|
|
189
174
|
## Runtime detection contract
|
|
190
175
|
|
|
191
176
|
The loader classifies the running shell and platform before matching module
|
|
@@ -270,30 +255,42 @@ Only the module for the running platform loads. The other is skipped without a
|
|
|
270
255
|
message, because its absence is expected. The POSIX loader and compiled plans
|
|
271
256
|
follow the same rules.
|
|
272
257
|
|
|
273
|
-
`exports` lists public
|
|
274
|
-
|
|
275
|
-
|
|
258
|
+
`exports` lists the public functions the module defines. Plans and loaders use
|
|
259
|
+
it for the pre-load conflict check, the post-load check, and failure cleanup.
|
|
260
|
+
An exported name
|
|
276
261
|
must be defined by the module body before the module is considered
|
|
277
262
|
successfully loaded. An export must name a function, so shell reserved words
|
|
278
263
|
(`case`, `do`, `done`, `elif`, `else`, `esac`, `fi`, `for`, `if`, `in`,
|
|
279
264
|
`then`, `until`, `while`, and `time`) are rejected.
|
|
280
265
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
266
|
+
### Published commands
|
|
267
|
+
|
|
268
|
+
`commands` names exports that should also run as ordinary commands, from any
|
|
269
|
+
program and not only from an interactive shell. Every entry must also appear in
|
|
270
|
+
`exports`. `executables` names standalone scripts in the module's directory;
|
|
271
|
+
each is published under its file name, which must start with a letter, digit,
|
|
272
|
+
or underscore and contain only letters, digits, `.`, `_`, and `-`. The
|
|
273
|
+
metadata field `updates` was removed in 0.3.0; a metadata file that still sets
|
|
274
|
+
it is rejected.
|
|
275
|
+
|
|
276
|
+
`valise build` turns both into entries under the release's `bin/`:
|
|
277
|
+
|
|
278
|
+
- For a module with `commands`, it compiles `plans/commands/<module>.sh`, a
|
|
279
|
+
plan whose only root is that module, for the module's command shell: `sh`
|
|
280
|
+
when the module supports `posix` or `sh`, otherwise the first of `bash`,
|
|
281
|
+
`zsh`, and `ksh` it lists. Each command gets a launcher `bin/<command>` that
|
|
282
|
+
runs under that shell, loads the plan in strict mode from the release that
|
|
283
|
+
contains it, restores the caller's `VALISE_MODE`, and calls the function
|
|
284
|
+
with the command's arguments. The function's exit status is the command's.
|
|
285
|
+
- Each `executables` path is copied to `bin/<file name>` and keeps its own
|
|
286
|
+
interpreter line.
|
|
287
|
+
|
|
288
|
+
The plan's closure ships in the release even when no shell bundle loads it.
|
|
289
|
+
A Fish-only module cannot declare `commands`; it may declare `executables`.
|
|
290
|
+
Two modules that publish the same command name, from either field, fail the
|
|
291
|
+
build. `valise-release.conf` lists the published names in `commands=`.
|
|
292
|
+
Installation puts a stub for each name on PATH; see
|
|
293
|
+
[installation.md](installation.md#published-commands).
|
|
297
294
|
|
|
298
295
|
## Side-effect phases
|
|
299
296
|
|
|
@@ -315,12 +312,13 @@ before ordinary source invokes a load path.
|
|
|
315
312
|
|
|
316
313
|
## Capability layer available to modules
|
|
317
314
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
315
|
+
Every plan sources the capability prelude (`runtime/capabilities.sh` in a
|
|
316
|
+
release, `lib/capabilities.sh` in the engine) before any module, and the
|
|
317
|
+
development entrypoint does the same before the loader. Module bodies may
|
|
318
|
+
therefore call the `sp_cap_*` helpers without sourcing platform files
|
|
319
|
+
themselves: CPU count, file mtime, temporary directories and files, command
|
|
320
|
+
lookup, OS detection, canonical path containment, symlink-component
|
|
321
|
+
rejection, Homebrew discovery, secure local-bin checks, and background
|
|
324
322
|
process launch.
|
|
325
323
|
|
|
326
324
|
**The helpers stay available after the profile loads.** A compiled plan
|
|
@@ -344,15 +342,15 @@ Read-only/status paths may degrade only by quietly skipping unsupported details
|
|
|
344
342
|
or by returning a clear nonzero status with a diagnostic from the caller.
|
|
345
343
|
|
|
346
344
|
Platform modules under `modules/platform/` are thin wrappers around the library.
|
|
347
|
-
They expose stable module dependencies (`
|
|
348
|
-
`
|
|
345
|
+
They expose stable module dependencies (`valise_platform_posix`, `valise_platform_macos`,
|
|
346
|
+
`valise_platform_linux`, and `valise_platform_bsd`) while keeping compatibility logic in one
|
|
349
347
|
library.
|
|
350
348
|
|
|
351
349
|
## Load target and loader mode
|
|
352
350
|
|
|
353
|
-
For file-backed modules, `load` is the
|
|
354
|
-
|
|
355
|
-
|
|
351
|
+
For file-backed modules, `load` is the shell file sourced after metadata
|
|
352
|
+
validation, dependency ordering, shell and platform matching, and the
|
|
353
|
+
side-effect checks have passed. The ABI has no unload hook: the loader
|
|
356
354
|
does not implement module rollback or unload semantics.
|
|
357
355
|
|
|
358
356
|
A meta module has no `load`; it has `requires` and no body. Nothing is
|
|
@@ -388,7 +386,8 @@ Permissive mode reports the affected module and continues with unrelated modules
|
|
|
388
386
|
|
|
389
387
|
## Path fields
|
|
390
388
|
|
|
391
|
-
`load` paths are
|
|
389
|
+
`load`, `executables`, and `tests` paths are relative to the module's source
|
|
390
|
+
directory (the project root, `layers/<provider>/`, or the engine). Absolute
|
|
392
391
|
paths, `..` path segments, spaces, quotes, shell metacharacters, and glob
|
|
393
392
|
characters are invalid. Reading metadata must not source these paths.
|
|
394
393
|
|
package/docs/projects.md
ADDED
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
# Projects, bundles, variants, and builds
|
|
2
|
+
|
|
3
|
+
This document describes a valise project: the files it contains, how
|
|
4
|
+
`valise compile` and `valise build` turn them into plans and a release, and
|
|
5
|
+
how those commands fail. [module-abi.md](module-abi.md) covers the metadata
|
|
6
|
+
format; [installation.md](installation.md) covers what happens to a release
|
|
7
|
+
once it is built.
|
|
8
|
+
|
|
9
|
+
## The project layout
|
|
10
|
+
|
|
11
|
+
A project is a directory that holds `valise.conf`:
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
valise.conf project settings
|
|
15
|
+
module.d/ primary modules: <name>.meta
|
|
16
|
+
modules/ primary module bodies (any layout below modules/)
|
|
17
|
+
layers/<provider>/ vendored provider layers (optional)
|
|
18
|
+
module.d/ layer modules: contrib_<name>.meta
|
|
19
|
+
modules/ layer module bodies
|
|
20
|
+
bundles.tsv the root modules of each bundle, per shell
|
|
21
|
+
variants.tsv build variants and what each leaves out (optional)
|
|
22
|
+
build/ build output; keep it out of version control
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
`valise new [dir]` writes this layout with a POSIX seed module
|
|
26
|
+
`profile_main`, a Fish seed module `profile_main_fish`, a `bundles.tsv` with
|
|
27
|
+
`sh`, `bash`, `zsh`, `ksh`, and `fish` rows, `variants.tsv`, and a
|
|
28
|
+
`.gitignore` for `build/`.
|
|
29
|
+
|
|
30
|
+
Project commands find the project by walking up from the working directory to
|
|
31
|
+
the first directory that holds `valise.conf`. `valise -C <dir> <command>` runs
|
|
32
|
+
a command as if it had been started in `dir`.
|
|
33
|
+
|
|
34
|
+
`valise.conf` has one `key=value` per line. Blank lines and `#` comments are
|
|
35
|
+
ignored; an unknown or repeated key is an error.
|
|
36
|
+
|
|
37
|
+
| Key | Meaning |
|
|
38
|
+
|---|---|
|
|
39
|
+
| `bundle` | Default bundle for build, apply, compile, and run (default `default`). |
|
|
40
|
+
| `variant` | Default variant (default `default`). |
|
|
41
|
+
| `requires_valise` | Oldest valise version that may build the project, such as `0.3.0`. An older valise refuses with `this project requires valise >= ...`. |
|
|
42
|
+
| `lint_layer_forbid` | Extended regular expression that must not match anything under `layers/` (case-insensitive). `valise lint` enforces it; use it to keep personal or employer material out of a layer you share. |
|
|
43
|
+
|
|
44
|
+
A layer's directory name is made of letters, digits, `_`, `-`, and `.`, and
|
|
45
|
+
may not start with `.` or contain `..`. Metadata and bodies must be regular
|
|
46
|
+
files reached without a symlink.
|
|
47
|
+
|
|
48
|
+
## Modules and the registry
|
|
49
|
+
|
|
50
|
+
The `.meta` files are the only source of truth. valise reads them as data,
|
|
51
|
+
never by sourcing them. Each build collects three groups of modules:
|
|
52
|
+
|
|
53
|
+
1. the project's `module.d/`, with source `module.d`;
|
|
54
|
+
2. each `layers/<provider>/module.d/`, with source
|
|
55
|
+
`layers/<provider>/module.d`;
|
|
56
|
+
3. the engine's own modules, with source `valise`.
|
|
57
|
+
|
|
58
|
+
The engine modules (`valise_path`, `valise_editor`, `valise_history`,
|
|
59
|
+
`valise_pager`, `valise_xdg`, and the `valise_platform_*` modules) are always
|
|
60
|
+
available. They ship in a release only when the release loads them. The
|
|
61
|
+
`valise_` prefix is reserved for them, and every layer module must use the
|
|
62
|
+
`contrib_` prefix.
|
|
63
|
+
|
|
64
|
+
`valise registry [path]` prints the table valise builds from these files, for
|
|
65
|
+
inspection. It is internal: nothing reads a saved copy, so do not commit one.
|
|
66
|
+
The table is tab-separated, with one header row and one row per module, in
|
|
67
|
+
a fixed order: primary modules, then each layer, then the engine, each in
|
|
68
|
+
C-locale name order.
|
|
69
|
+
|
|
70
|
+
| # | Column | Meaning |
|
|
71
|
+
|---|---|---|
|
|
72
|
+
| 1 | `name` | Module identifier. |
|
|
73
|
+
| 2 | `version` | Version string; empty means unversioned. |
|
|
74
|
+
| 3 | `side_effect` | Side-effect class. |
|
|
75
|
+
| 4 | `requires` | Required dependencies. |
|
|
76
|
+
| 5 | `optional` | Optional dependencies. |
|
|
77
|
+
| 6 | `shells` | Shell classes. |
|
|
78
|
+
| 7 | `platforms` | Platforms. |
|
|
79
|
+
| 8 | `exports` | Exported functions. |
|
|
80
|
+
| 9 | `load` | Body path relative to the module's source directory; empty for a meta module. |
|
|
81
|
+
| 10 | `commands` | Exports published as commands. |
|
|
82
|
+
| 11 | `executables` | Scripts published as commands. |
|
|
83
|
+
| 12 | `tests` | Test scripts for `valise test`. |
|
|
84
|
+
| 13 | `source` | `module.d`, `layers/<provider>/module.d`, or `valise`. |
|
|
85
|
+
|
|
86
|
+
Building the table also validates it. A `name` that differs from its file
|
|
87
|
+
name, a missing body, executable or test, a symlink, a misplaced prefix, or
|
|
88
|
+
invalid metadata stops the command and names the file.
|
|
89
|
+
|
|
90
|
+
A module reference is a bare name or a qualified `name@source`. A bare
|
|
91
|
+
dependency resolves to the module with that name in the same source when
|
|
92
|
+
there is one, otherwise to the only module with that name. A bare bundle root
|
|
93
|
+
or exclusion resolves to the primary module when there is one, otherwise to
|
|
94
|
+
the only module with that name; when several sources define the name, qualify
|
|
95
|
+
it.
|
|
96
|
+
|
|
97
|
+
## Bundles: the root modules for each shell
|
|
98
|
+
|
|
99
|
+
`bundles.tsv` is tab-separated: bundle, shell, and a space-separated list of
|
|
100
|
+
root modules. The first row may be a header.
|
|
101
|
+
|
|
102
|
+
```
|
|
103
|
+
bundle shell roots
|
|
104
|
+
default sh profile_main
|
|
105
|
+
default bash profile_main profile_bash
|
|
106
|
+
default zsh profile_main
|
|
107
|
+
default ksh profile_main
|
|
108
|
+
default fish profile_main_fish
|
|
109
|
+
work bash profile_main profile_work
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
The shell column is one of `sh`, `bash`, `zsh`, `ksh`, and `fish`. `sh` is the
|
|
113
|
+
plan for any POSIX shell that is not bash, zsh, or ksh, such as dash or
|
|
114
|
+
BusyBox ash. A bundle without a row for a shell loads nothing there.
|
|
115
|
+
|
|
116
|
+
Roots are starting points. The plan loads each root's whole closure of
|
|
117
|
+
`requires` and available `optional` dependencies, in dependency order.
|
|
118
|
+
`valise explain-bundles [--bundle=<name>] [--variant=<name>]` prints each
|
|
119
|
+
bundle's roots and ordered closure per shell, with each module's source.
|
|
120
|
+
|
|
121
|
+
A root, and every module it requires, must support the shell and the
|
|
122
|
+
platform it runs on: in strict mode an unsupported platform is a failure. A
|
|
123
|
+
module that exists only for some platforms belongs behind an optional edge.
|
|
124
|
+
Write an aggregator whose `optional=` lists the per-platform modules and use
|
|
125
|
+
the aggregator as the root; the module for the running platform loads, and
|
|
126
|
+
the others are skipped without a message.
|
|
127
|
+
|
|
128
|
+
## Variants: what to leave out
|
|
129
|
+
|
|
130
|
+
`variants.tsv` is tab-separated: variant name, description, and a
|
|
131
|
+
space-separated list of excluded modules. Without the file, the only variant
|
|
132
|
+
is `default`, which excludes nothing.
|
|
133
|
+
|
|
134
|
+
```
|
|
135
|
+
variant description excluded
|
|
136
|
+
default All project modules
|
|
137
|
+
lean No editor defaults valise_editor
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Each exclusion must resolve to exactly one module; an unknown or ambiguous
|
|
141
|
+
exclusion is an error. An excluded module is removed from every closure, and
|
|
142
|
+
its optional edges are dropped. **If a remaining module requires an excluded
|
|
143
|
+
module, the build fails**, naming both; exclude the dependents too. Nothing is
|
|
144
|
+
removed silently.
|
|
145
|
+
|
|
146
|
+
`valise explain-variant [--bundle=<name>] [name]` shows a variant's
|
|
147
|
+
description, its exclusions, and how many of the bundle's roots it removes
|
|
148
|
+
per shell. The bundle chooses the roots, and the variant then removes
|
|
149
|
+
modules from what they reach.
|
|
150
|
+
|
|
151
|
+
## `valise compile`
|
|
152
|
+
|
|
153
|
+
```sh
|
|
154
|
+
valise compile [--bundle=<name>] [--variant=<name>] <output-dir>
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Compile writes `<output-dir>/<shell>.sh` for each POSIX shell the bundle has
|
|
158
|
+
roots for, and nothing else. The output directory must be empty or absent;
|
|
159
|
+
compile stages beside it and publishes only after every plan compiled.
|
|
160
|
+
|
|
161
|
+
A plan is a POSIX shell file:
|
|
162
|
+
|
|
163
|
+
```
|
|
164
|
+
# valise-plan-v2
|
|
165
|
+
# Generated by valise compile; DO NOT EDIT.
|
|
166
|
+
# plan=bash
|
|
167
|
+
# roots=profile_main
|
|
168
|
+
# order=valise_path profile_main
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
The header names the format, the shell, the roots, and the resolved load
|
|
172
|
+
order. Sourced with `VALISE_MODULE_ROOT` naming a release, the plan:
|
|
173
|
+
|
|
174
|
+
- reads `VALISE_MODE` (`strict` or `permissive`; default `strict`);
|
|
175
|
+
- probes the platform once and gates each module by `platforms=`;
|
|
176
|
+
- sources `runtime/capabilities.sh`, so the `sp_cap_*` helpers stay available
|
|
177
|
+
to module functions afterwards;
|
|
178
|
+
- refuses to load a module whose declared export already exists as an alias,
|
|
179
|
+
function, or builtin (an export may shadow a command on PATH), and checks
|
|
180
|
+
after loading that each export is defined;
|
|
181
|
+
- skips a module whose required dependency failed or was skipped, and says
|
|
182
|
+
which;
|
|
183
|
+
- in strict mode, returns nonzero at the first failure among the roots and
|
|
184
|
+
everything they require;
|
|
185
|
+
- in permissive mode, reports each failure, continues with unrelated
|
|
186
|
+
modules, and returns zero;
|
|
187
|
+
- loads an optional dependency first when it can; its absence never affects
|
|
188
|
+
the module that declared it;
|
|
189
|
+
- with `VALISE_RELOAD=1`, removes the plan's declared exports first, so the
|
|
190
|
+
plan can be sourced again.
|
|
191
|
+
|
|
192
|
+
Compile fails before writing anything when the variant or bundle is unknown,
|
|
193
|
+
an exclusion or root does not resolve, a variant exclusion breaks a required
|
|
194
|
+
dependency, a module in a closure has a side-effect class that is not safe at
|
|
195
|
+
startup (`generated-file`, `update-network`, or `install-time`), or a module
|
|
196
|
+
is not representable as plan source.
|
|
197
|
+
|
|
198
|
+
## `valise build`
|
|
199
|
+
|
|
200
|
+
```sh
|
|
201
|
+
valise build [--bundle=<name>] [--variant=<name>] [out]
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
Build produces an installable release tree at `build/release`, or at `out`,
|
|
205
|
+
which must then be empty or absent. The tree contains:
|
|
206
|
+
|
|
207
|
+
```
|
|
208
|
+
valise-release.conf format=2, valise_version, bundle, variant,
|
|
209
|
+
roots_<shell>=, modules=, commands=
|
|
210
|
+
manifest.tsv the release manifest
|
|
211
|
+
plans/<shell>.sh one plan per POSIX shell with roots
|
|
212
|
+
plans/commands/<module>.sh a plan per module that publishes commands
|
|
213
|
+
bin/<command> command launchers and executables
|
|
214
|
+
runtime/capabilities.sh the capability prelude
|
|
215
|
+
runtime/fish/{metadata,loader,profile}.fish when the bundle has fish roots
|
|
216
|
+
module.d/, modules/... primary modules some shell loads
|
|
217
|
+
layers/<provider>/module.d, ... layer modules some shell loads
|
|
218
|
+
valise/module.d, valise/modules/... engine modules some shell loads
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
Only modules in some shell's closure are copied, with their metadata. A
|
|
222
|
+
module that a variant excludes, or that no root reaches, is absent from the
|
|
223
|
+
release, together with its body. The Fish runtime resolves the Fish roots
|
|
224
|
+
recorded in `valise-release.conf` against the copied metadata when Fish
|
|
225
|
+
starts. See [module-abi.md](module-abi.md#published-commands) for `bin/`.
|
|
226
|
+
|
|
227
|
+
Directories are `0755`, files `0644`, and `bin/` entries `0755`. Build
|
|
228
|
+
stages beside the destination and publishes only after the tree and its
|
|
229
|
+
manifest are complete. A previous `build/release` is moved aside first and
|
|
230
|
+
put back if publication fails, so a failed build leaves the previous output
|
|
231
|
+
in place. Building the same project twice produces byte-identical output.
|
|
232
|
+
|
|
233
|
+
## `valise apply` and `valise status`
|
|
234
|
+
|
|
235
|
+
`valise apply [--bundle=<name>] [--variant=<name>] [--no-integration]
|
|
236
|
+
[--dry-run]` builds to `build/release`, installs it, writes the shell
|
|
237
|
+
integration and command stubs, and verifies the active release. Running it
|
|
238
|
+
again changes nothing. `--dry-run` stops after the build and prints what
|
|
239
|
+
install would change; see [installation.md](installation.md).
|
|
240
|
+
|
|
241
|
+
`valise status` reports the project defaults, the integration in each startup
|
|
242
|
+
file, the bundle, variant, and valise version the active release was built
|
|
243
|
+
with, and whether the active release matches `build/release`.
|
|
244
|
+
|
|
245
|
+
## Checking a project
|
|
246
|
+
|
|
247
|
+
`valise lint` and `valise test` check a project without installing it, and
|
|
248
|
+
`valise run` loads modules into a throwaway shell; see
|
|
249
|
+
[contrib-modules.md](contrib-modules.md#checking-and-testing-modules).
|