@sous-io/sous 0.2.15 → 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 +40 -9
- 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/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/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
|
|
@@ -265,13 +292,16 @@ Removes a subscription and everything only it brought in, then rebuilds so those
|
|
|
265
292
|
|
|
266
293
|
### `sous subscription list`
|
|
267
294
|
Lists the subscriptions this project declares, switched-off ones included, with the range each resolves within,
|
|
268
|
-
the versions the lockfile pins,
|
|
269
|
-
|
|
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`
|
|
270
299
|
|
|
271
300
|
## namespace
|
|
272
301
|
|
|
273
302
|
`namespace` reads the cached indexes and the lockfile, so it works offline. A trusted repository whose index has
|
|
274
|
-
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.
|
|
275
305
|
|
|
276
306
|
### `sous namespace list`
|
|
277
307
|
Lists every namespace the trusted repositories publish, how many recipes each holds, and how much of it this
|
|
@@ -284,11 +314,12 @@ Example: `sous namespace show sous-recipes:core`
|
|
|
284
314
|
|
|
285
315
|
## recipe
|
|
286
316
|
|
|
287
|
-
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).
|
|
288
319
|
|
|
289
320
|
### `sous recipe list`
|
|
290
321
|
Lists the recipes the trusted repositories publish, across every namespace, with the same per-recipe columns
|
|
291
|
-
`namespace show` prints. Example: `sous recipe list`
|
|
322
|
+
`namespace show` prints. Example: `sous recipe list --installed --latest`
|
|
292
323
|
|
|
293
324
|
### `sous recipe show REF`
|
|
294
325
|
Describes one recipe completely: its repository and location, every published version, its dependencies as
|
|
@@ -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
|
}
|
|
@@ -6,14 +6,17 @@
|
|
|
6
6
|
* and where its files land in this project. It reads only what sous already has
|
|
7
7
|
* on disk: the repository's cached index, the project's lockfile, and the
|
|
8
8
|
* recipe's own files when they are in the store or a linked working copy.
|
|
9
|
+
* `--latest` reads the repository's index from upstream instead, saving
|
|
10
|
+
* nothing, and `--installed` looks the ref up among installed recipes only.
|
|
9
11
|
*/
|
|
10
12
|
|
|
11
13
|
import { Args } from "@oclif/core";
|
|
12
14
|
import { BaseCommand } from "../../base-command.js";
|
|
13
15
|
import { resolveRootScope } from "../../lib/settings.js";
|
|
14
16
|
import { subscriptionServiceFor } from "../../lib/repos/subscription-service.js";
|
|
15
|
-
import {
|
|
17
|
+
import { loadCatalogContext } from "../../lib/repos/catalog-inputs.js";
|
|
16
18
|
import {
|
|
19
|
+
describeInstalled,
|
|
17
20
|
describeRecipe,
|
|
18
21
|
type RecipeContentListing,
|
|
19
22
|
type RecipeDependencyListing,
|
|
@@ -22,11 +25,14 @@ import {
|
|
|
22
25
|
} from "../../lib/repos/catalog.js";
|
|
23
26
|
import {
|
|
24
27
|
INDENT,
|
|
28
|
+
describeIndexSource,
|
|
25
29
|
describeVersionStatus,
|
|
26
30
|
factIf,
|
|
31
|
+
printBrowsingNotes,
|
|
27
32
|
printFacts,
|
|
28
33
|
} from "../../lib/repos/catalog-display.js";
|
|
29
34
|
import { renderTable, type TableColumn } from "../../utils/table.js";
|
|
35
|
+
import { browsingFlags } from "../../utils/flags.js";
|
|
30
36
|
import {
|
|
31
37
|
blankLine,
|
|
32
38
|
footer,
|
|
@@ -102,15 +108,17 @@ export default class RecipeShow extends BaseCommand {
|
|
|
102
108
|
}),
|
|
103
109
|
};
|
|
104
110
|
|
|
105
|
-
static flags = { ...BaseCommand.baseFlags };
|
|
111
|
+
static flags = { ...BaseCommand.baseFlags, ...browsingFlags() };
|
|
106
112
|
|
|
107
113
|
async run(): Promise<void> {
|
|
108
|
-
const { args } = await this.parse(RecipeShow);
|
|
114
|
+
const { args, flags } = await this.parse(RecipeShow);
|
|
109
115
|
|
|
110
116
|
showCommandVars({
|
|
111
117
|
Project: this.projectLabel,
|
|
112
118
|
Config: this.configContext.configPath,
|
|
113
119
|
Recipe: args.ref,
|
|
120
|
+
Reading: describeIndexSource(flags.latest),
|
|
121
|
+
...(flags.installed ? { Showing: "only what this project has installed" } : {}),
|
|
114
122
|
});
|
|
115
123
|
|
|
116
124
|
const service = subscriptionServiceFor({
|
|
@@ -119,14 +127,17 @@ export default class RecipeShow extends BaseCommand {
|
|
|
119
127
|
shellEnv: this.shellEnv,
|
|
120
128
|
});
|
|
121
129
|
|
|
122
|
-
const { inputs } =
|
|
130
|
+
const { inputs, notChecked } = await loadCatalogContext({
|
|
123
131
|
service,
|
|
124
132
|
sousDir: this.configContext.sousDir,
|
|
125
133
|
settings: this.settings,
|
|
126
134
|
scope: resolveRootScope(this.settings, this.configContext),
|
|
135
|
+
latest: flags.latest,
|
|
127
136
|
});
|
|
128
137
|
|
|
129
|
-
const detail =
|
|
138
|
+
const detail = flags.installed
|
|
139
|
+
? describeInstalled(inputs, args.ref, describeRecipe, "recipe")
|
|
140
|
+
: describeRecipe(inputs, args.ref);
|
|
130
141
|
|
|
131
142
|
heading(detail.key);
|
|
132
143
|
blankLine();
|
|
@@ -137,11 +148,22 @@ export default class RecipeShow extends BaseCommand {
|
|
|
137
148
|
...factIf("About", detail.description),
|
|
138
149
|
{ label: "Folder", lines: [detail.path] },
|
|
139
150
|
{ label: "Latest version", lines: [detail.latest ?? "none published"] },
|
|
140
|
-
{
|
|
151
|
+
{
|
|
152
|
+
label: flags.installed ? "Installed version" : "Pinned version",
|
|
153
|
+
lines: [detail.pinned ?? "this project pins none"],
|
|
154
|
+
},
|
|
155
|
+
...factIf(
|
|
156
|
+
"Linked",
|
|
157
|
+
detail.linkedPath === undefined
|
|
158
|
+
? undefined
|
|
159
|
+
: `builds currently read this recipe from the checkout at ${detail.linkedPath}`
|
|
160
|
+
),
|
|
141
161
|
{ label: "Subscribed", lines: [detail.subscribed ? "yes" : "no"] },
|
|
142
162
|
...factIf("Described below", detail.describing),
|
|
143
163
|
]);
|
|
144
164
|
|
|
165
|
+
printBrowsingNotes({ notChecked: notChecked.filter((name) => name === detail.repo) });
|
|
166
|
+
|
|
145
167
|
this.printVersions(detail.versions);
|
|
146
168
|
this.printDependencies(detail.dependencies, detail.manifestRead);
|
|
147
169
|
|