@sous-io/sous 0.2.14 → 0.2.16
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/docs/markdown/commands.md +64 -13
- package/docs/markdown/repositories-authoring.md +53 -0
- package/docs/markdown/repositories-consuming.md +32 -1
- package/package.json +1 -1
- package/recipes/core/sous-skills/sous.recipe.yaml +1 -1
- package/src/commands/namespace/list.ts +42 -21
- package/src/commands/namespace/show.ts +32 -12
- package/src/commands/recipe/list.ts +40 -23
- package/src/commands/recipe/show.ts +28 -6
- package/src/commands/repo/link.ts +400 -1
- package/src/commands/repo/list.ts +67 -10
- package/src/commands/repo/search.ts +68 -15
- package/src/commands/subscription/list.ts +98 -19
- package/src/lib/build-preparation.ts +44 -1
- package/src/lib/repos/catalog-display.ts +101 -2
- package/src/lib/repos/catalog-inputs.ts +145 -17
- package/src/lib/repos/catalog.ts +92 -5
- package/src/lib/repos/freshness.ts +56 -0
- package/src/lib/repos/git-clone.ts +468 -7
- package/src/lib/repos/providers/github.ts +1 -0
- package/src/lib/repos/providers/gitlab.ts +1 -0
- package/src/lib/repos/providers/http.ts +7 -2
- package/src/lib/repos/providers/index-cache.ts +56 -17
- package/src/lib/repos/providers/provider.ts +2 -0
- package/src/lib/repos/subscription-service.ts +138 -9
- package/src/utils/flags.ts +24 -0
|
@@ -41,6 +41,22 @@ Help has four spellings. `sous --help` prints the root screen; `sous repo add --
|
|
|
41
41
|
`sous --version` prints the version alone, as `v1.2.3`; `sous --version --verbose` adds the package name, where
|
|
42
42
|
it is installed, the platform and the Node build under it.
|
|
43
43
|
|
|
44
|
+
## Flags that browse
|
|
45
|
+
|
|
46
|
+
Every command that shows published versions takes the same two flags: `sous recipe list`, `sous recipe show`,
|
|
47
|
+
`sous namespace list`, `sous namespace show`, `sous repo list`, `sous repo search` (and `sous search`) and
|
|
48
|
+
`sous subscription list`. The flags combine.
|
|
49
|
+
|
|
50
|
+
| Flag | What it does |
|
|
51
|
+
|------|--------------|
|
|
52
|
+
| `--latest` | Read each repository's index from upstream instead of the cache. `--remote` is the same flag. What it fetches is never written to the cache; a repository that cannot be reached is shown from the cache and named as not checked |
|
|
53
|
+
| `--installed` | Show only what this project has installed, at the version its lockfile pins. A recipe whose repository is linked is marked `linked`, because builds read it from the checkout rather than the pinned version |
|
|
54
|
+
|
|
55
|
+
Without either flag a browsing command reads only the cached indexes, so it works offline and fast.
|
|
56
|
+
`sous recipe list --installed --latest` is the out-of-date view: each installed recipe with upstream's newest
|
|
57
|
+
version beside the installed one. With `--installed`, `recipe show` and `namespace show` look the reference up
|
|
58
|
+
among installed recipes only, and a reference to something published but not installed is an error saying so.
|
|
59
|
+
|
|
44
60
|
Every topic answers to both spellings of its name: `repo` and `repos`, `subscription` and `subscriptions`,
|
|
45
61
|
`namespace` and `namespaces`, `recipe` and `recipes`, `lock` and `locks`, `vars` and `var`, `config` and
|
|
46
62
|
`configs`. Three commands also answer to one word: `sous search`, `sous subscribe` and `sous unsubscribe`.
|
|
@@ -79,6 +95,12 @@ and the command you want almost always. Takes `--dry-run`.
|
|
|
79
95
|
- `--strict`: fail on any compilation error rather than reporting it and continuing.
|
|
80
96
|
- `-w, --watch`: rebuild on every change to a source file, a config layer or a linked checkout.
|
|
81
97
|
|
|
98
|
+
Before it compiles, a build lists each recipe this project uses that has a newer version within the range
|
|
99
|
+
declared for it, beside the version pinned. It moves no pin; only always-pull moves one. The build reads upstream
|
|
100
|
+
for this at most once per freshness window (`store.freshnessSeconds`, five minutes by default), gives a
|
|
101
|
+
repository three seconds to answer, and otherwise answers from the cached index without a word about the
|
|
102
|
+
failed check.
|
|
103
|
+
|
|
82
104
|
Example: `sous build --rebuild`
|
|
83
105
|
|
|
84
106
|
### `sous compile`
|
|
@@ -103,8 +125,10 @@ Example: `sous launch claude --continuous`
|
|
|
103
125
|
|
|
104
126
|
### `sous search TEXT`
|
|
105
127
|
Searches the recipes every trusted repository publishes, by name or description; reads the cached indexes only,
|
|
106
|
-
so it works offline. `--limit <n>` sets how many matches to show, defaulting to 25.
|
|
107
|
-
`
|
|
128
|
+
so it works offline. `--limit <n>` sets how many matches to show, defaulting to 25. Takes the
|
|
129
|
+
[browsing flags](#flags-that-browse): `--latest` searches the indexes upstream serves, and `--installed` searches
|
|
130
|
+
only installed recipes and adds an Installed column. Also spelled `sous repo search`.
|
|
131
|
+
Example: `sous search task --limit 50`
|
|
108
132
|
|
|
109
133
|
### `sous help [COMMAND]`
|
|
110
134
|
Prints the help for sous, or for one command or topic. Works from any directory, including one with no config
|
|
@@ -155,7 +179,9 @@ held, the files the next build prunes, and the linked checkout if one points at
|
|
|
155
179
|
### `sous repo list`
|
|
156
180
|
Lists the repositories this project trusts, with the provider, where the entry came from, whether it is linked,
|
|
157
181
|
how many recipes it publishes (`not fetched` until its index has been downloaded) and its URL. `--verbose` adds
|
|
158
|
-
the namespaces each one publishes, on a line under its row.
|
|
182
|
+
the namespaces each one publishes, on a line under its row. Takes the [browsing flags](#flags-that-browse):
|
|
183
|
+
`--installed` keeps only the repositories something is installed from and names each installed recipe and
|
|
184
|
+
version on a line under its row.
|
|
159
185
|
|
|
160
186
|
```term
|
|
161
187
|
$ sous repo list
|
|
@@ -165,7 +191,8 @@ $ sous repo list
|
|
|
165
191
|
```
|
|
166
192
|
|
|
167
193
|
### `sous repo search TEXT`
|
|
168
|
-
Same command as `sous search`, under its own topic; takes `--limit <n
|
|
194
|
+
Same command as `sous search`, under its own topic; takes `--limit <n>` and the
|
|
195
|
+
[browsing flags](#flags-that-browse). Example: `sous repo search browser --installed`
|
|
169
196
|
|
|
170
197
|
### `sous repo gc`
|
|
171
198
|
Collects the machine-wide recipe store down to its size cap. `--max-bytes <n>` collects to that cap instead of
|
|
@@ -177,10 +204,30 @@ Points a repository at a working copy on this machine instead of a published ver
|
|
|
177
204
|
clones it into `.sous/repos` and links the clone; a name or URL with a `PATH` links the checkout at that path; a
|
|
178
205
|
path alone links that checkout where it is, adding the repository first if needed. Takes `--dry-run`.
|
|
179
206
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
207
|
+
A checkout that was already on disk is fetched (a fetch changes none of its files or branches) and compared with
|
|
208
|
+
upstream: its branch, whether that branch is merged into the default branch, and how many commits it is behind.
|
|
209
|
+
When upstream cannot be reached within a few seconds, a warning gives git's reason and says since when the
|
|
210
|
+
checkout may have diverged, and the link is still recorded. Nothing else changes the checkout unless a flag
|
|
211
|
+
asks for it; git carries out each step, and a step git refuses stops the command with git's own message.
|
|
212
|
+
|
|
213
|
+
- `--global`: link for every project on this machine, sharing one checkout. Changing that checkout's branch
|
|
214
|
+
says it affects every project that links it.
|
|
215
|
+
- `--branch <name>`: switch to an existing branch, fetching it from upstream first when it is not local.
|
|
216
|
+
- `--create-branch <name>`: create a new branch and switch to it; git refuses a name that already exists.
|
|
217
|
+
- `--generate-branch`: the same, with the generated name `sous/edit-<YYYYMMDD>-<HHMM>`, which is printed.
|
|
218
|
+
- `--from <branch>`: the base of the new branch, fetched first. Defaults to the repository's default branch,
|
|
219
|
+
not whatever is checked out, and needs `--create-branch` or `--generate-branch`.
|
|
220
|
+
- `--latest`: make the branch being worked from (the `--branch` target, the `--from` base, or else the default
|
|
221
|
+
branch) match upstream's, leaving every other branch alone. What that would discard (uncommitted changes and
|
|
222
|
+
local commits upstream lacks) is listed first, with one question; it fails when the fetch fails.
|
|
223
|
+
- `-y, --yes`: answer the trust question a not-yet-added repository raises and the question `--latest` asks
|
|
224
|
+
(also `-f`, `--force`, `--trust`).
|
|
225
|
+
|
|
226
|
+
`--branch`, `--create-branch` and `--generate-branch` exclude each other; each flag works on a checkout linked
|
|
227
|
+
by path, too.
|
|
228
|
+
|
|
229
|
+
Example: `sous repo link sous-recipes ~/Projects/sous-recipes`, or `sous repo link sous-recipes
|
|
230
|
+
--generate-branch --latest --yes`
|
|
184
231
|
|
|
185
232
|
### `sous repo unlink REPO`
|
|
186
233
|
Stops reading a repository from a working copy and goes back to published versions; `REPO` is the short name as
|
|
@@ -245,13 +292,16 @@ Removes a subscription and everything only it brought in, then rebuilds so those
|
|
|
245
292
|
|
|
246
293
|
### `sous subscription list`
|
|
247
294
|
Lists the subscriptions this project declares, switched-off ones included, with the range each resolves within,
|
|
248
|
-
the versions the lockfile pins,
|
|
249
|
-
|
|
295
|
+
the versions the lockfile pins, the latest version each of those recipes has published, where it came from and
|
|
296
|
+
whether it is on. Reads the config, the lockfile and the cached indexes only. Takes the
|
|
297
|
+
[browsing flags](#flags-that-browse): `--latest` reads the latest versions from upstream, and `--installed` keeps
|
|
298
|
+
only the subscriptions that have pinned something. Example: `sous subscription list --latest`
|
|
250
299
|
|
|
251
300
|
## namespace
|
|
252
301
|
|
|
253
302
|
`namespace` reads the cached indexes and the lockfile, so it works offline. A trusted repository whose index has
|
|
254
|
-
never been fetched is named at the end of a listing, not left out.
|
|
303
|
+
never been fetched is named at the end of a listing, not left out. Both commands take the
|
|
304
|
+
[browsing flags](#flags-that-browse); with `--installed` the recipe count is the number installed.
|
|
255
305
|
|
|
256
306
|
### `sous namespace list`
|
|
257
307
|
Lists every namespace the trusted repositories publish, how many recipes each holds, and how much of it this
|
|
@@ -264,11 +314,12 @@ Example: `sous namespace show sous-recipes:core`
|
|
|
264
314
|
|
|
265
315
|
## recipe
|
|
266
316
|
|
|
267
|
-
Browses the recipes the trusted repositories publish; like `namespace`, it works offline
|
|
317
|
+
Browses the recipes the trusted repositories publish; like `namespace`, it works offline, and both commands take
|
|
318
|
+
the [browsing flags](#flags-that-browse).
|
|
268
319
|
|
|
269
320
|
### `sous recipe list`
|
|
270
321
|
Lists the recipes the trusted repositories publish, across every namespace, with the same per-recipe columns
|
|
271
|
-
`namespace show` prints. Example: `sous recipe list`
|
|
322
|
+
`namespace show` prints. Example: `sous recipe list --installed --latest`
|
|
272
323
|
|
|
273
324
|
### `sous recipe show REF`
|
|
274
325
|
Describes one recipe completely: its repository and location, every published version, its dependencies as
|
|
@@ -289,6 +289,59 @@ Run 'sous repo unlink my-recipes' to go back to published versions.
|
|
|
289
289
|
`sous repo unlink` removes the map entry and nothing else: the checkout stays where it is, and its path is
|
|
290
290
|
printed so you can delete it. Unlinking a name linked in the other scope says which scope holds it.
|
|
291
291
|
|
|
292
|
+
### How a checkout compares with upstream
|
|
293
|
+
|
|
294
|
+
A link says which checkout to read, not why, so `sous repo link` never changes a checkout on its own. When the
|
|
295
|
+
checkout was already on disk (a clone reused from an earlier link, or one you named by path), it runs a short
|
|
296
|
+
`git fetch`, which updates only the remote-tracking refs, and reports what it found. The part of the output that
|
|
297
|
+
reports it looks like this:
|
|
298
|
+
|
|
299
|
+
```term
|
|
300
|
+
$ sous repo link my-recipes
|
|
301
|
+
Branch : lc/my-change
|
|
302
|
+
Compared with : origin/main
|
|
303
|
+
Merged into origin/main: yes
|
|
304
|
+
Behind origin/main : 12 commits
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
A branch that is merged and behind has usually been released already, and the checkout is building from an older
|
|
308
|
+
state than upstream's. When the fetch fails or takes longer than a few seconds, the link is still recorded, and
|
|
309
|
+
a warning gives git's reason and says since when the checkout may have diverged (the last time it was fetched).
|
|
310
|
+
The fetch is skipped for a checkout sous has just cloned, and a checkout with no `origin` remote says it has no
|
|
311
|
+
upstream to compare with.
|
|
312
|
+
|
|
313
|
+
### Choosing the branch
|
|
314
|
+
|
|
315
|
+
Every change to the checkout is a flag, and git carries each one out. When git refuses a step (a conflict with
|
|
316
|
+
uncommitted changes, a branch that already exists, one that does not), the command stops and shows git's message
|
|
317
|
+
under a line naming the step. Each flag works on a checkout linked by path, too.
|
|
318
|
+
|
|
319
|
+
```bash
|
|
320
|
+
sous repo link my-recipes --branch lc/their-change # read from an existing branch
|
|
321
|
+
sous repo link my-recipes --create-branch my-change # start a new branch
|
|
322
|
+
sous repo link my-recipes --generate-branch # start one named sous/edit-<YYYYMMDD>-<HHMM>
|
|
323
|
+
sous repo link my-recipes --generate-branch --from next # start it from another branch
|
|
324
|
+
sous repo link my-recipes --latest # bring the default branch up to upstream's
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
- `--branch <name>` switches with `git switch`, which also checks out a branch that exists only upstream. A clone
|
|
328
|
+
sous makes holds only the default branch, so a branch that is not local is fetched first and added to the
|
|
329
|
+
branches `origin` is fetched for.
|
|
330
|
+
- `--create-branch <name>` and `--generate-branch` create a new branch and switch to it; the generated name is
|
|
331
|
+
printed. The new branch starts from upstream's copy of `--from`, which defaults to the repository's default
|
|
332
|
+
branch rather than whatever is checked out, so a new branch never silently stacks on an old, already-merged
|
|
333
|
+
one. `--from` is an error without one of the two.
|
|
334
|
+
- `--branch`, `--create-branch` and `--generate-branch` exclude each other.
|
|
335
|
+
- `--latest` means upstream's latest version of what you are working from: the `--branch` target, the `--from`
|
|
336
|
+
base, or otherwise the default branch. It fetches that branch, switches to it and makes it match upstream's,
|
|
337
|
+
and leaves every other branch alone. Making a branch match upstream discards local work without git warning
|
|
338
|
+
about it, so this is the one place sous checks for itself: uncommitted changes to tracked files and local
|
|
339
|
+
commits upstream lacks are listed first, with one question. `--yes` answers it, and a run with no terminal
|
|
340
|
+
fails naming that flag. When the fetch fails, `--latest` fails, with git's reason.
|
|
341
|
+
|
|
342
|
+
A `--global` link's checkout is shared by every project on the machine that links the repository globally, so
|
|
343
|
+
changing its branch says it affects all of them.
|
|
344
|
+
|
|
292
345
|
## Contribute to someone else's repository
|
|
293
346
|
|
|
294
347
|
`sous repo submit` proposes your committed changes to a repository's maintainers; it never publishes and never
|
|
@@ -52,6 +52,19 @@ sous namespace show workflow # one namespace and the recipes in it
|
|
|
52
52
|
sous recipe list # every recipe, latest version, pinned version, subscribed
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
+
The cache can be behind what a repository has published since. Every one of these commands, plus
|
|
56
|
+
`sous recipe show`, `sous repo list` and `sous subscription list`, takes two flags that combine:
|
|
57
|
+
|
|
58
|
+
- `--latest` (also `--remote`) reads each index from upstream instead. Nothing it fetches is
|
|
59
|
+
written to the cache; only a command that resolves versions changes what the cache holds. A
|
|
60
|
+
repository that cannot be reached is shown from the cache and named as not checked.
|
|
61
|
+
- `--installed` narrows the listing to what this project has installed, at the version the
|
|
62
|
+
lockfile pins. A recipe from a linked repository is marked `linked`, because builds read it from
|
|
63
|
+
the checkout instead of that version.
|
|
64
|
+
|
|
65
|
+
`sous recipe list --installed --latest` is the out-of-date view: every installed recipe, with
|
|
66
|
+
upstream's newest version beside the installed one.
|
|
67
|
+
|
|
55
68
|
Read `sous recipe show` before subscribing: every published version, what it depends on (as
|
|
56
69
|
declared, beside the version the index resolved it to), and its questions and files once it has
|
|
57
70
|
them here.
|
|
@@ -201,7 +214,8 @@ $ sous subscription list
|
|
|
201
214
|
|
|
202
215
|
A namespace subscription names every recipe it holds, each with the version the lockfile pins. A
|
|
203
216
|
subscription that has never been built has nothing pinned yet, and its cell reads `pinned on first
|
|
204
|
-
build` instead.
|
|
217
|
+
build` instead. The `Latest version` column beside it is read from the cache, or from upstream with
|
|
218
|
+
`--latest`.
|
|
205
219
|
|
|
206
220
|
`sous repo list` shows each trusted repository with its provider, origin, whether it is linked, its
|
|
207
221
|
recipe count and its URL; `--verbose` adds a `Namespaces:` line under each row. `sous lock show`
|
|
@@ -278,6 +292,23 @@ happens after that check, not how often it happens: a repository or subscription
|
|
|
278
292
|
`alwaysPull` takes a newer in-range version rather than the locked one; set it with
|
|
279
293
|
`--always-pull`, or on either entry in the config.
|
|
280
294
|
|
|
295
|
+
Every other repository the lockfile pins from is checked on the same window, only to tell you what
|
|
296
|
+
is newer. A build lists each recipe with a newer version inside the range declared for it, beside
|
|
297
|
+
the version it pins, and moves nothing:
|
|
298
|
+
|
|
299
|
+
```term
|
|
300
|
+
$ sous build
|
|
301
|
+
▶ Newer versions published:
|
|
302
|
+
|
|
303
|
+
workflow/qa-variables: 0.2.0 this project pins 0.1.0
|
|
304
|
+
|
|
305
|
+
This version is within the range declared for the recipe. No pin was changed, so this build
|
|
306
|
+
uses the pinned version.
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
That check waits at most three seconds for a repository, and a check that fails or runs out of
|
|
310
|
+
time is not mentioned: the cached index answers instead, and the build carries on.
|
|
311
|
+
|
|
281
312
|
The store is machine-wide and disposable, because everything in it is re-fetchable from a
|
|
282
313
|
lockfile's pins. `sous repo gc` collects it back to its size cap, evicting least recently used
|
|
283
314
|
entries first, and protects everything this project's lockfile pins whatever that does to the
|
package/package.json
CHANGED
|
@@ -3,17 +3,25 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Shows every namespace published by the repositories this project trusts, how
|
|
5
5
|
* many recipes each one holds, and how much of it the project subscribes to. It
|
|
6
|
-
* reads only the indexes sous already has on disk, so it works
|
|
7
|
-
* repository whose index has never been fetched is named at the end
|
|
8
|
-
* being silently left out.
|
|
6
|
+
* reads only the indexes sous already has on disk by default, so it works
|
|
7
|
+
* offline; a repository whose index has never been fetched is named at the end
|
|
8
|
+
* rather than being silently left out. `--latest` reads the indexes from
|
|
9
|
+
* upstream instead, without saving them, and `--installed` narrows the listing
|
|
10
|
+
* to the namespaces the lockfile pins a recipe from.
|
|
9
11
|
*/
|
|
10
12
|
|
|
11
13
|
import { BaseCommand } from "../../base-command.js";
|
|
12
14
|
import { subscriptionServiceFor } from "../../lib/repos/subscription-service.js";
|
|
13
|
-
import {
|
|
14
|
-
import { listNamespaces } from "../../lib/repos/catalog.js";
|
|
15
|
-
import {
|
|
15
|
+
import { loadCatalogContext } from "../../lib/repos/catalog-inputs.js";
|
|
16
|
+
import { listNamespaces, narrowToInstalled } from "../../lib/repos/catalog.js";
|
|
17
|
+
import {
|
|
18
|
+
INDENT,
|
|
19
|
+
describeCoverage,
|
|
20
|
+
describeIndexSource,
|
|
21
|
+
printBrowsingNotes,
|
|
22
|
+
} from "../../lib/repos/catalog-display.js";
|
|
16
23
|
import { renderTable, type TableColumn } from "../../utils/table.js";
|
|
24
|
+
import { browsingFlags } from "../../utils/flags.js";
|
|
17
25
|
import {
|
|
18
26
|
blankLine,
|
|
19
27
|
footer,
|
|
@@ -53,19 +61,28 @@ export default class NamespaceList extends BaseCommand {
|
|
|
53
61
|
*/
|
|
54
62
|
static aliases = ["namespaces:list"];
|
|
55
63
|
|
|
56
|
-
static examples = [
|
|
64
|
+
static examples = [
|
|
65
|
+
"<%= config.bin %> namespace list",
|
|
66
|
+
"<%= config.bin %> namespace list --installed",
|
|
67
|
+
];
|
|
57
68
|
|
|
58
|
-
static flags = { ...BaseCommand.baseFlags };
|
|
69
|
+
static flags = { ...BaseCommand.baseFlags, ...browsingFlags() };
|
|
59
70
|
|
|
60
71
|
async run(): Promise<void> {
|
|
61
|
-
await this.parse(NamespaceList);
|
|
72
|
+
const { flags } = await this.parse(NamespaceList);
|
|
62
73
|
|
|
63
74
|
showCommandVars({
|
|
64
75
|
Project: this.projectLabel,
|
|
65
76
|
Config: this.configContext.configPath,
|
|
77
|
+
Reading: describeIndexSource(flags.latest),
|
|
78
|
+
...(flags.installed ? { Showing: "only what this project has installed" } : {}),
|
|
66
79
|
});
|
|
67
80
|
|
|
68
|
-
heading(
|
|
81
|
+
heading(
|
|
82
|
+
flags.installed
|
|
83
|
+
? "Namespaces this project has installed recipes from"
|
|
84
|
+
: "Namespaces in the repositories this project trusts"
|
|
85
|
+
);
|
|
69
86
|
|
|
70
87
|
const service = subscriptionServiceFor({
|
|
71
88
|
configContext: this.configContext,
|
|
@@ -73,13 +90,21 @@ export default class NamespaceList extends BaseCommand {
|
|
|
73
90
|
shellEnv: this.shellEnv,
|
|
74
91
|
});
|
|
75
92
|
|
|
76
|
-
const { inputs, notFetched } =
|
|
93
|
+
const { inputs, notFetched, notChecked } = await loadCatalogContext({
|
|
77
94
|
service,
|
|
78
95
|
sousDir: this.configContext.sousDir,
|
|
79
96
|
settings: this.settings,
|
|
97
|
+
latest: flags.latest,
|
|
80
98
|
});
|
|
81
99
|
|
|
82
|
-
|
|
100
|
+
// Narrowed to what is installed, a namespace's recipe count is the number
|
|
101
|
+
// of its recipes the project has installed, and the column says so.
|
|
102
|
+
const listings = listNamespaces(flags.installed ? narrowToInstalled(inputs) : inputs);
|
|
103
|
+
const columns = flags.installed
|
|
104
|
+
? COLUMNS.map((column) =>
|
|
105
|
+
column.key === "recipes" ? { ...column, header: "Installed" } : column
|
|
106
|
+
)
|
|
107
|
+
: COLUMNS;
|
|
83
108
|
|
|
84
109
|
blankLine();
|
|
85
110
|
|
|
@@ -88,7 +113,9 @@ export default class NamespaceList extends BaseCommand {
|
|
|
88
113
|
inputs.repos.length === 0
|
|
89
114
|
? "Sous has read no repository index for this project, so there are no " +
|
|
90
115
|
"namespaces to show."
|
|
91
|
-
:
|
|
116
|
+
: flags.installed
|
|
117
|
+
? "This project has installed no recipe from the repositories it trusts."
|
|
118
|
+
: "The repositories this project trusts publish no namespaces."
|
|
92
119
|
);
|
|
93
120
|
} else {
|
|
94
121
|
const rows = listings.map((entry) => ({
|
|
@@ -99,18 +126,12 @@ export default class NamespaceList extends BaseCommand {
|
|
|
99
126
|
description: entry.description ?? "no description published",
|
|
100
127
|
}));
|
|
101
128
|
|
|
102
|
-
for (const line of renderTable(
|
|
129
|
+
for (const line of renderTable(columns, rows, { indent: INDENT })) {
|
|
103
130
|
log(indent(line, INDENT));
|
|
104
131
|
}
|
|
105
132
|
}
|
|
106
133
|
|
|
107
|
-
|
|
108
|
-
blankLine();
|
|
109
|
-
paragraph(
|
|
110
|
-
`These repositories are trusted and their index has not been fetched yet, so ` +
|
|
111
|
-
`nothing in them is listed: ${notFetched.join(", ")}.`
|
|
112
|
-
);
|
|
113
|
-
}
|
|
134
|
+
printBrowsingNotes({ notFetched, notChecked });
|
|
114
135
|
|
|
115
136
|
footer();
|
|
116
137
|
}
|
|
@@ -4,23 +4,28 @@
|
|
|
4
4
|
* Shows one namespace in full: the repository publishing it, what that
|
|
5
5
|
* repository says it is for, how much of it this project subscribes to, and
|
|
6
6
|
* every recipe in it with its latest version, its pinned version and its own
|
|
7
|
-
* subscription state. It reads only the indexes sous already has on disk
|
|
7
|
+
* subscription state. It reads only the indexes sous already has on disk,
|
|
8
|
+
* unless `--latest` asks it to read upstream (which saves nothing); `--installed`
|
|
9
|
+
* narrows the recipes to the ones the lockfile pins.
|
|
8
10
|
*/
|
|
9
11
|
|
|
10
12
|
import { Args } from "@oclif/core";
|
|
11
13
|
import { BaseCommand } from "../../base-command.js";
|
|
12
14
|
import { subscriptionServiceFor } from "../../lib/repos/subscription-service.js";
|
|
13
|
-
import {
|
|
14
|
-
import { describeNamespace } from "../../lib/repos/catalog.js";
|
|
15
|
+
import { loadCatalogContext } from "../../lib/repos/catalog-inputs.js";
|
|
16
|
+
import { describeInstalled, describeNamespace } from "../../lib/repos/catalog.js";
|
|
15
17
|
import {
|
|
16
18
|
INDENT,
|
|
17
|
-
RECIPE_COLUMNS,
|
|
18
19
|
describeCoverage,
|
|
20
|
+
describeIndexSource,
|
|
19
21
|
factIf,
|
|
22
|
+
printBrowsingNotes,
|
|
20
23
|
printFacts,
|
|
24
|
+
recipeColumns,
|
|
21
25
|
recipeRows,
|
|
22
26
|
} from "../../lib/repos/catalog-display.js";
|
|
23
27
|
import { renderTable } from "../../utils/table.js";
|
|
28
|
+
import { browsingFlags } from "../../utils/flags.js";
|
|
24
29
|
import {
|
|
25
30
|
blankLine,
|
|
26
31
|
footer,
|
|
@@ -53,15 +58,17 @@ export default class NamespaceShow extends BaseCommand {
|
|
|
53
58
|
}),
|
|
54
59
|
};
|
|
55
60
|
|
|
56
|
-
static flags = { ...BaseCommand.baseFlags };
|
|
61
|
+
static flags = { ...BaseCommand.baseFlags, ...browsingFlags() };
|
|
57
62
|
|
|
58
63
|
async run(): Promise<void> {
|
|
59
|
-
const { args } = await this.parse(NamespaceShow);
|
|
64
|
+
const { args, flags } = await this.parse(NamespaceShow);
|
|
60
65
|
|
|
61
66
|
showCommandVars({
|
|
62
67
|
Project: this.projectLabel,
|
|
63
68
|
Config: this.configContext.configPath,
|
|
64
69
|
Namespace: args.ref,
|
|
70
|
+
Reading: describeIndexSource(flags.latest),
|
|
71
|
+
...(flags.installed ? { Showing: "only what this project has installed" } : {}),
|
|
65
72
|
});
|
|
66
73
|
|
|
67
74
|
const service = subscriptionServiceFor({
|
|
@@ -70,13 +77,16 @@ export default class NamespaceShow extends BaseCommand {
|
|
|
70
77
|
shellEnv: this.shellEnv,
|
|
71
78
|
});
|
|
72
79
|
|
|
73
|
-
const { inputs } =
|
|
80
|
+
const { inputs, notChecked } = await loadCatalogContext({
|
|
74
81
|
service,
|
|
75
82
|
sousDir: this.configContext.sousDir,
|
|
76
83
|
settings: this.settings,
|
|
84
|
+
latest: flags.latest,
|
|
77
85
|
});
|
|
78
86
|
|
|
79
|
-
const detail =
|
|
87
|
+
const detail = flags.installed
|
|
88
|
+
? describeInstalled(inputs, args.ref, describeNamespace, "namespace")
|
|
89
|
+
: describeNamespace(inputs, args.ref);
|
|
80
90
|
|
|
81
91
|
heading(`The namespace ${detail.namespace}`);
|
|
82
92
|
blankLine();
|
|
@@ -85,7 +95,10 @@ export default class NamespaceShow extends BaseCommand {
|
|
|
85
95
|
{ label: "Repository", lines: [detail.repo] },
|
|
86
96
|
...factIf("Location", detail.repoUrl),
|
|
87
97
|
...factIf("About", detail.description),
|
|
88
|
-
{
|
|
98
|
+
{
|
|
99
|
+
label: flags.installed ? "Installed recipes" : "Recipes",
|
|
100
|
+
lines: [String(detail.recipes.length)],
|
|
101
|
+
},
|
|
89
102
|
{ label: "Subscribed", lines: [describeCoverage(detail.subscribed)] },
|
|
90
103
|
]);
|
|
91
104
|
|
|
@@ -99,12 +112,19 @@ export default class NamespaceShow extends BaseCommand {
|
|
|
99
112
|
return;
|
|
100
113
|
}
|
|
101
114
|
|
|
102
|
-
for (const line of renderTable(
|
|
103
|
-
|
|
104
|
-
|
|
115
|
+
for (const line of renderTable(
|
|
116
|
+
recipeColumns({ installed: flags.installed }),
|
|
117
|
+
recipeRows(detail.recipes),
|
|
118
|
+
{ indent: INDENT }
|
|
119
|
+
)) {
|
|
105
120
|
log(indent(line, INDENT));
|
|
106
121
|
}
|
|
107
122
|
|
|
123
|
+
printBrowsingNotes({
|
|
124
|
+
notChecked: notChecked.filter((name) => name === detail.repo),
|
|
125
|
+
anyLinked: detail.recipes.some((entry) => entry.linkedPath !== undefined),
|
|
126
|
+
});
|
|
127
|
+
|
|
108
128
|
footer();
|
|
109
129
|
}
|
|
110
130
|
}
|
|
@@ -3,21 +3,26 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Shows every recipe the repositories this project trusts publish, with the
|
|
5
5
|
* latest published version, the version this project pins, and whether it is
|
|
6
|
-
* subscribed.
|
|
7
|
-
* offline; a repository whose index has never been fetched is named at
|
|
8
|
-
* rather than being silently left out.
|
|
6
|
+
* subscribed. By default it reads only the indexes sous already has on disk, so
|
|
7
|
+
* it works offline; a repository whose index has never been fetched is named at
|
|
8
|
+
* the end rather than being silently left out. `--latest` reads the indexes
|
|
9
|
+
* from upstream instead, without saving them, and `--installed` narrows the
|
|
10
|
+
* listing to what the lockfile pins.
|
|
9
11
|
*/
|
|
10
12
|
|
|
11
13
|
import { BaseCommand } from "../../base-command.js";
|
|
12
14
|
import { subscriptionServiceFor } from "../../lib/repos/subscription-service.js";
|
|
13
|
-
import {
|
|
14
|
-
import { listRecipes } from "../../lib/repos/catalog.js";
|
|
15
|
+
import { loadCatalogContext } from "../../lib/repos/catalog-inputs.js";
|
|
16
|
+
import { listRecipes, narrowToInstalled } from "../../lib/repos/catalog.js";
|
|
15
17
|
import {
|
|
16
18
|
INDENT,
|
|
17
|
-
|
|
19
|
+
describeIndexSource,
|
|
20
|
+
printBrowsingNotes,
|
|
21
|
+
recipeColumns,
|
|
18
22
|
recipeRows,
|
|
19
23
|
} from "../../lib/repos/catalog-display.js";
|
|
20
24
|
import { renderTable } from "../../utils/table.js";
|
|
25
|
+
import { browsingFlags } from "../../utils/flags.js";
|
|
21
26
|
import {
|
|
22
27
|
blankLine,
|
|
23
28
|
footer,
|
|
@@ -37,19 +42,28 @@ export default class RecipeList extends BaseCommand {
|
|
|
37
42
|
*/
|
|
38
43
|
static aliases = ["recipes:list"];
|
|
39
44
|
|
|
40
|
-
static examples = [
|
|
45
|
+
static examples = [
|
|
46
|
+
"<%= config.bin %> recipe list",
|
|
47
|
+
"<%= config.bin %> recipe list --installed --latest",
|
|
48
|
+
];
|
|
41
49
|
|
|
42
|
-
static flags = { ...BaseCommand.baseFlags };
|
|
50
|
+
static flags = { ...BaseCommand.baseFlags, ...browsingFlags() };
|
|
43
51
|
|
|
44
52
|
async run(): Promise<void> {
|
|
45
|
-
await this.parse(RecipeList);
|
|
53
|
+
const { flags } = await this.parse(RecipeList);
|
|
46
54
|
|
|
47
55
|
showCommandVars({
|
|
48
56
|
Project: this.projectLabel,
|
|
49
57
|
Config: this.configContext.configPath,
|
|
58
|
+
Reading: describeIndexSource(flags.latest),
|
|
59
|
+
...(flags.installed ? { Showing: "only what this project has installed" } : {}),
|
|
50
60
|
});
|
|
51
61
|
|
|
52
|
-
heading(
|
|
62
|
+
heading(
|
|
63
|
+
flags.installed
|
|
64
|
+
? "Recipes this project has installed"
|
|
65
|
+
: "Recipes in the repositories this project trusts"
|
|
66
|
+
);
|
|
53
67
|
|
|
54
68
|
const service = subscriptionServiceFor({
|
|
55
69
|
configContext: this.configContext,
|
|
@@ -57,13 +71,14 @@ export default class RecipeList extends BaseCommand {
|
|
|
57
71
|
shellEnv: this.shellEnv,
|
|
58
72
|
});
|
|
59
73
|
|
|
60
|
-
const { inputs, notFetched } =
|
|
74
|
+
const { inputs, notFetched, notChecked } = await loadCatalogContext({
|
|
61
75
|
service,
|
|
62
76
|
sousDir: this.configContext.sousDir,
|
|
63
77
|
settings: this.settings,
|
|
78
|
+
latest: flags.latest,
|
|
64
79
|
});
|
|
65
80
|
|
|
66
|
-
const listings = listRecipes(inputs);
|
|
81
|
+
const listings = listRecipes(flags.installed ? narrowToInstalled(inputs) : inputs);
|
|
67
82
|
|
|
68
83
|
blankLine();
|
|
69
84
|
|
|
@@ -72,23 +87,25 @@ export default class RecipeList extends BaseCommand {
|
|
|
72
87
|
inputs.repos.length === 0
|
|
73
88
|
? "Sous has read no repository index for this project, so there are no " +
|
|
74
89
|
"recipes to show."
|
|
75
|
-
:
|
|
90
|
+
: flags.installed
|
|
91
|
+
? "This project has installed no recipe from the repositories it trusts."
|
|
92
|
+
: "The repositories this project trusts publish no recipes."
|
|
76
93
|
);
|
|
77
94
|
} else {
|
|
78
|
-
for (const line of renderTable(
|
|
79
|
-
|
|
80
|
-
|
|
95
|
+
for (const line of renderTable(
|
|
96
|
+
recipeColumns({ installed: flags.installed }),
|
|
97
|
+
recipeRows(listings),
|
|
98
|
+
{ indent: INDENT }
|
|
99
|
+
)) {
|
|
81
100
|
log(indent(line, INDENT));
|
|
82
101
|
}
|
|
83
102
|
}
|
|
84
103
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
);
|
|
91
|
-
}
|
|
104
|
+
printBrowsingNotes({
|
|
105
|
+
notFetched,
|
|
106
|
+
notChecked,
|
|
107
|
+
anyLinked: listings.some((entry) => entry.linkedPath !== undefined),
|
|
108
|
+
});
|
|
92
109
|
|
|
93
110
|
footer();
|
|
94
111
|
}
|