@sous-io/sous 0.2.37 → 1.0.2
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/README.md +14 -256
- package/dist/bin.js +11 -0
- package/dist/sous.js +1094 -0
- package/docs/markdown/README.md +5 -4
- package/docs/markdown/_sidebar.md +21 -1
- package/docs/markdown/commands.md +294 -431
- package/docs/markdown/config-discovery.md +25 -14
- package/docs/markdown/config-inspection.md +53 -31
- package/docs/markdown/config-layers.md +168 -66
- package/docs/markdown/config-variables.md +44 -11
- package/docs/markdown/configuration.md +104 -17
- package/docs/markdown/design-principles.md +4 -1
- package/docs/markdown/repositories-authoring.md +30 -0
- package/docs/markdown/repositories-consuming.md +72 -14
- package/docs/markdown/repositories-file-formats.md +31 -13
- package/docs/markdown/repositories-providers.md +48 -57
- package/docs/markdown/repositories-quickstart.md +3 -2
- package/docs/markdown/repositories-troubleshooting.md +27 -1
- package/docs/markdown/repositories-variables.md +6 -1
- package/docs/markdown/repositories.md +18 -8
- package/package.json +48 -107
- package/recipes/core/sous-skills/skills/about-liquid-templates/SKILL.tpl.md +4 -6
- package/recipes/core/sous-skills/skills/about-liquid-templates/references/liquid-filters.tpl.md +2 -0
- package/recipes/core/sous-skills/skills/about-sous/SKILL.tpl.md +10 -9
- package/recipes/core/sous-skills/skills/about-sous-configuration/SKILL.tpl.md +35 -14
- package/recipes/core/sous-skills/skills/about-sous-recipes/SKILL.tpl.md +51 -20
- package/recipes/core/sous-skills/sous.recipe.yaml +1 -1
- package/sous.config.schema.json +351 -132
- package/bin/run.js +0 -51
- package/src/base-command.ts +0 -457
- package/src/commands/build.ts +0 -181
- package/src/commands/clear.ts +0 -79
- package/src/commands/compile.ts +0 -155
- package/src/commands/config/get.ts +0 -110
- package/src/commands/config/show.ts +0 -32
- package/src/commands/config/validate.ts +0 -53
- package/src/commands/help.ts +0 -46
- package/src/commands/init.ts +0 -289
- package/src/commands/launch.ts +0 -139
- package/src/commands/lock/rebuild.ts +0 -239
- package/src/commands/lock/show.ts +0 -115
- package/src/commands/namespace/list.ts +0 -138
- package/src/commands/namespace/show.ts +0 -130
- package/src/commands/prune.ts +0 -43
- package/src/commands/recipe/list.ts +0 -112
- package/src/commands/recipe/show.ts +0 -439
- package/src/commands/repo/add.ts +0 -145
- package/src/commands/repo/contribute.ts +0 -604
- package/src/commands/repo/gc.ts +0 -173
- package/src/commands/repo/init.ts +0 -136
- package/src/commands/repo/link.ts +0 -899
- package/src/commands/repo/list.ts +0 -236
- package/src/commands/repo/release.ts +0 -685
- package/src/commands/repo/remove.ts +0 -194
- package/src/commands/repo/search.ts +0 -243
- package/src/commands/repo/submit.ts +0 -341
- package/src/commands/repo/unlink.ts +0 -461
- package/src/commands/subscription/add.ts +0 -286
- package/src/commands/subscription/list.ts +0 -208
- package/src/commands/subscription/remove.ts +0 -182
- package/src/commands/subscription/update.ts +0 -216
- package/src/commands/update.ts +0 -178
- package/src/commands/vars/ask.ts +0 -417
- package/src/commands/vars/index.ts +0 -79
- package/src/commands/vars/list.ts +0 -67
- package/src/commands/vars/show.ts +0 -77
- package/src/config-command.ts +0 -30
- package/src/lib/build-preparation.ts +0 -128
- package/src/lib/build-service.ts +0 -580
- package/src/lib/config-discovery.ts +0 -378
- package/src/lib/config-inspect.ts +0 -145
- package/src/lib/config-kernel.mjs +0 -379
- package/src/lib/config-schema.ts +0 -401
- package/src/lib/env-file.ts +0 -328
- package/src/lib/env-local.ts +0 -212
- package/src/lib/errors.ts +0 -32
- package/src/lib/glob-pattern.ts +0 -24
- package/src/lib/include-resolver.ts +0 -523
- package/src/lib/interactive.ts +0 -165
- package/src/lib/markdown-compiler.ts +0 -947
- package/src/lib/package-info.ts +0 -25
- package/src/lib/pid-service.ts +0 -99
- package/src/lib/project-install.d.mts +0 -44
- package/src/lib/project-install.mjs +0 -234
- package/src/lib/project-scaffold/index.ts +0 -332
- package/src/lib/project-scaffold/templates.ts +0 -240
- package/src/lib/repos/catalog-display.ts +0 -215
- package/src/lib/repos/catalog-inputs.ts +0 -288
- package/src/lib/repos/catalog.ts +0 -842
- package/src/lib/repos/contribute.ts +0 -452
- package/src/lib/repos/core-recipe.ts +0 -105
- package/src/lib/repos/declarations.ts +0 -187
- package/src/lib/repos/defaults.ts +0 -175
- package/src/lib/repos/formats/common.ts +0 -440
- package/src/lib/repos/formats/index-file.ts +0 -253
- package/src/lib/repos/formats/links-map.ts +0 -98
- package/src/lib/repos/formats/lockfile.ts +0 -169
- package/src/lib/repos/formats/patterns.ts +0 -57
- package/src/lib/repos/formats/recipe-manifest.ts +0 -205
- package/src/lib/repos/formats/repo-manifest.ts +0 -97
- package/src/lib/repos/formats/store-entry.ts +0 -84
- package/src/lib/repos/formats/variable-definition.ts +0 -268
- package/src/lib/repos/freshness.ts +0 -264
- package/src/lib/repos/git-clone.ts +0 -850
- package/src/lib/repos/identity.ts +0 -89
- package/src/lib/repos/index.ts +0 -57
- package/src/lib/repos/links.ts +0 -356
- package/src/lib/repos/load-manifest.ts +0 -237
- package/src/lib/repos/lock-service.ts +0 -454
- package/src/lib/repos/locked-namespace-resolver.ts +0 -232
- package/src/lib/repos/locked-recipe-lookup.ts +0 -123
- package/src/lib/repos/locked-recipes.ts +0 -254
- package/src/lib/repos/managed-layer.ts +0 -422
- package/src/lib/repos/memories-hash-name.ts +0 -33
- package/src/lib/repos/namespace-resolver.ts +0 -527
- package/src/lib/repos/providers/base.ts +0 -268
- package/src/lib/repos/providers/git.ts +0 -245
- package/src/lib/repos/providers/github.ts +0 -589
- package/src/lib/repos/providers/gitlab.ts +0 -332
- package/src/lib/repos/providers/http.ts +0 -128
- package/src/lib/repos/providers/index-cache.ts +0 -421
- package/src/lib/repos/providers/index.ts +0 -106
- package/src/lib/repos/providers/local.ts +0 -410
- package/src/lib/repos/providers/provider.ts +0 -615
- package/src/lib/repos/recipe-config-layers.ts +0 -316
- package/src/lib/repos/recipe-key-matcher.ts +0 -62
- package/src/lib/repos/recipe-memories.ts +0 -178
- package/src/lib/repos/recipe-targets.ts +0 -236
- package/src/lib/repos/ref-search.ts +0 -46
- package/src/lib/repos/release/bump.ts +0 -161
- package/src/lib/repos/release/changelog.ts +0 -461
- package/src/lib/repos/release/git-state.ts +0 -460
- package/src/lib/repos/release/index-builder.ts +0 -1108
- package/src/lib/repos/release/index.ts +0 -19
- package/src/lib/repos/release/plan.ts +0 -521
- package/src/lib/repos/release/settle.ts +0 -154
- package/src/lib/repos/release/submissions.ts +0 -214
- package/src/lib/repos/release/submit-checkout.ts +0 -290
- package/src/lib/repos/release/submit-questions.ts +0 -153
- package/src/lib/repos/release/submit-service.ts +0 -898
- package/src/lib/repos/release/tags.ts +0 -239
- package/src/lib/repos/release/validate.ts +0 -463
- package/src/lib/repos/resolver.ts +0 -1028
- package/src/lib/repos/scaffold/index.ts +0 -245
- package/src/lib/repos/scaffold/templates.ts +0 -517
- package/src/lib/repos/seed.ts +0 -473
- package/src/lib/repos/store/contract.ts +0 -64
- package/src/lib/repos/store/hash.ts +0 -191
- package/src/lib/repos/store/recipe-store.ts +0 -599
- package/src/lib/repos/store/settings.ts +0 -58
- package/src/lib/repos/subscription-service.ts +0 -3859
- package/src/lib/repos/trust.ts +0 -447
- package/src/lib/repos/update-plan.ts +0 -235
- package/src/lib/self-update/index.ts +0 -14
- package/src/lib/self-update/installs.ts +0 -413
- package/src/lib/self-update/managers.ts +0 -126
- package/src/lib/self-update/plan.ts +0 -315
- package/src/lib/self-update/registry.ts +0 -99
- package/src/lib/self-update/run.ts +0 -506
- package/src/lib/self-update/versions.ts +0 -243
- package/src/lib/settings.ts +0 -1107
- package/src/lib/sous-home.ts +0 -104
- package/src/lib/state.ts +0 -167
- package/src/lib/vars/answers.ts +0 -192
- package/src/lib/vars/ask.ts +0 -1152
- package/src/lib/vars/definition-source.ts +0 -261
- package/src/lib/vars/display.ts +0 -231
- package/src/lib/vars/index.ts +0 -20
- package/src/lib/vars/ladder.ts +0 -282
- package/src/lib/vars/mappings.ts +0 -260
- package/src/lib/vars/names.ts +0 -94
- package/src/lib/vars/preanswers.ts +0 -395
- package/src/lib/vars/question-plan.ts +0 -241
- package/src/lib/vars/report.ts +0 -228
- package/src/lib/vars/safe-regex.ts +0 -235
- package/src/lib/vars/secrets.ts +0 -131
- package/src/lib/vars/validate.ts +0 -312
- package/src/lib/version-report.ts +0 -90
- package/src/lib/watch-loop.ts +0 -148
- package/src/lib/watch-service.ts +0 -116
- package/src/services/ref-resolver/container.ts +0 -107
- package/src/services/ref-resolver/dependency.ts +0 -60
- package/src/services/ref-resolver/format.ts +0 -197
- package/src/services/ref-resolver/glob.ts +0 -115
- package/src/services/ref-resolver/hash-names.ts +0 -155
- package/src/services/ref-resolver/index.ts +0 -55
- package/src/services/ref-resolver/injectable.ts +0 -36
- package/src/services/ref-resolver/location.ts +0 -62
- package/src/services/ref-resolver/lookups/cached-index-lookup.ts +0 -53
- package/src/services/ref-resolver/lookups/catalog-lookup.ts +0 -23
- package/src/services/ref-resolver/lookups/catalog-matcher.ts +0 -261
- package/src/services/ref-resolver/lookups/chained-lookup.ts +0 -27
- package/src/services/ref-resolver/lookups/env-var-lookup.ts +0 -65
- package/src/services/ref-resolver/lookups/fetched-index-lookup.ts +0 -150
- package/src/services/ref-resolver/lookups/recorded-dependency-lookup.ts +0 -62
- package/src/services/ref-resolver/lookups/ref-lookup.ts +0 -54
- package/src/services/ref-resolver/lookups/variable-lookup.ts +0 -123
- package/src/services/ref-resolver/named-refs.ts +0 -144
- package/src/services/ref-resolver/parser/env-var-splitter.ts +0 -27
- package/src/services/ref-resolver/parser/location-splitter.ts +0 -239
- package/src/services/ref-resolver/parser/name-path-splitter.ts +0 -200
- package/src/services/ref-resolver/parser/partial-ref.ts +0 -84
- package/src/services/ref-resolver/parser/query-splitter.ts +0 -61
- package/src/services/ref-resolver/parser/range-splitter.ts +0 -52
- package/src/services/ref-resolver/parser/ref-parser.ts +0 -115
- package/src/services/ref-resolver/parser/repo-qualifier-splitter.ts +0 -51
- package/src/services/ref-resolver/parts.ts +0 -115
- package/src/services/ref-resolver/pruners/command-line-pruner.ts +0 -47
- package/src/services/ref-resolver/pruners/include-pruner.ts +0 -66
- package/src/services/ref-resolver/pruners/manifest-pruner.ts +0 -130
- package/src/services/ref-resolver/pruners/ref-pruner.ts +0 -135
- package/src/services/ref-resolver/pruners/rule-helpers.ts +0 -44
- package/src/services/ref-resolver/pruners/stored-key-pruner.ts +0 -136
- package/src/services/ref-resolver/ref-helpers.ts +0 -62
- package/src/services/ref-resolver/ref-picker-service.ts +0 -204
- package/src/services/ref-resolver/ref-report.ts +0 -84
- package/src/services/ref-resolver/ref-resolve-arguments.ts +0 -47
- package/src/services/ref-resolver/ref-resolve-result.ts +0 -36
- package/src/services/ref-resolver/ref-resolver-service.ts +0 -323
- package/src/services/ref-resolver/source.ts +0 -48
- package/src/services/ref-resolver/tokens.ts +0 -25
- package/src/services/ref-resolver/types.ts +0 -155
- package/src/templating/filters/bullet-list.ts +0 -9
- package/src/templating/filters/index.ts +0 -8
- package/src/templating/init-liquid-engine.ts +0 -139
- package/src/templating/lib/glob-files.ts +0 -74
- package/src/templating/lib/import-export.ts +0 -32
- package/src/templating/lib/secret-scope.ts +0 -41
- package/src/templating/lib/tag-args.ts +0 -19
- package/src/templating/tags/exportScalarVarsJs.ts +0 -46
- package/src/templating/tags/getFiles.ts +0 -89
- package/src/templating/tags/index.ts +0 -14
- package/src/templating/tags/listFiles.ts +0 -54
- package/src/templating/tags/showVars.ts +0 -28
- package/src/utils/choice-prompt.ts +0 -143
- package/src/utils/command-errors.ts +0 -186
- package/src/utils/command-help.ts +0 -45
- package/src/utils/confirm-prompt.ts +0 -110
- package/src/utils/flags.ts +0 -177
- package/src/utils/formatting.ts +0 -849
- package/src/utils/prompts.ts +0 -53
- package/src/utils/sous-directory.ts +0 -245
- package/src/utils/table.ts +0 -603
- package/src/utils/value-prompt.ts +0 -119
package/src/lib/repos/trust.ts
DELETED
|
@@ -1,447 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The trust layer.
|
|
3
|
-
*
|
|
4
|
-
* Added equals trusted. There is no separate trust command and no trusted-but-
|
|
5
|
-
* not-added state: a repository sous will read from is one written into the
|
|
6
|
-
* project's `repos:` map, and removing the entry withdraws the trust. Until a
|
|
7
|
-
* repository is added, sous downloads nothing from it, not even its index;
|
|
8
|
-
* there is no peeking before trusting, because the decision rests on the URL
|
|
9
|
-
* and the publisher's reputation, which are inspected outside sous.
|
|
10
|
-
*
|
|
11
|
-
* Resolution can turn up repositories a dependency needs but the project has
|
|
12
|
-
* not added. Those come back from the resolver as `MissingRepo` entries with
|
|
13
|
-
* their provenance, and this is where the user is asked about them: one
|
|
14
|
-
* consolidated question per round, listing every new repository with its URL
|
|
15
|
-
* and the recipe that requires it. A refusal aborts. A non-interactive run
|
|
16
|
-
* fails hard, naming the repositories and the command that grants trust, and
|
|
17
|
-
* `--trust` acknowledges without asking.
|
|
18
|
-
*/
|
|
19
|
-
|
|
20
|
-
import { color } from "@oclif/color";
|
|
21
|
-
import { ConfigError } from "../errors.js";
|
|
22
|
-
import type { Settings } from "../settings.js";
|
|
23
|
-
import {
|
|
24
|
-
blankLine,
|
|
25
|
-
formatVariable,
|
|
26
|
-
log as writeLine,
|
|
27
|
-
palette,
|
|
28
|
-
wrapColumns,
|
|
29
|
-
wrapText,
|
|
30
|
-
type VariableEntry,
|
|
31
|
-
} from "../../utils/formatting.js";
|
|
32
|
-
import { askYesNo } from "../../utils/prompts.js";
|
|
33
|
-
import {
|
|
34
|
-
isInteractive,
|
|
35
|
-
nonInteractiveReason,
|
|
36
|
-
NonInteractiveError,
|
|
37
|
-
} from "../interactive.js";
|
|
38
|
-
import {
|
|
39
|
-
REPOS_LAYER_FILENAME,
|
|
40
|
-
readManagedLayer,
|
|
41
|
-
updateManagedLayer,
|
|
42
|
-
type ManagedLayerOptions,
|
|
43
|
-
} from "./managed-layer.js";
|
|
44
|
-
import type { MissingRepo } from "./resolver.js";
|
|
45
|
-
import type { ProviderId } from "./providers/provider.js";
|
|
46
|
-
import { enabledRepos } from "./defaults.js";
|
|
47
|
-
|
|
48
|
-
/** The `addedBy` value meaning a person deliberately added the repository. */
|
|
49
|
-
export const USER_ADDED_BY = "user";
|
|
50
|
-
|
|
51
|
-
/** One repository entry, as it is written into the managed layer. */
|
|
52
|
-
export type TrustedRepo = {
|
|
53
|
-
/** Where the repository lives. */
|
|
54
|
-
url: string;
|
|
55
|
-
/** The provider that handles it, when the URL does not give it away. */
|
|
56
|
-
provider?: ProviderId;
|
|
57
|
-
/** Whether a newer in-range version is preferred over the locked one. */
|
|
58
|
-
alwaysPull?: boolean;
|
|
59
|
-
/** When it was added. */
|
|
60
|
-
addedAt?: string;
|
|
61
|
-
/** Who required it: "user", or the ref of the recipe whose dependency pulled it in. */
|
|
62
|
-
addedBy?: string;
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
/** What `addRepo` is told. */
|
|
66
|
-
export type AddRepoRequest = {
|
|
67
|
-
/** The repository's short name, which refs use as the `repo:` qualifier. */
|
|
68
|
-
name: string;
|
|
69
|
-
/** Where the repository lives. */
|
|
70
|
-
url: string;
|
|
71
|
-
/** The provider that handles it, when the URL does not give it away. */
|
|
72
|
-
provider?: ProviderId;
|
|
73
|
-
/** Whether a newer in-range version is preferred over the locked one. */
|
|
74
|
-
alwaysPull?: boolean;
|
|
75
|
-
/** Who required it. Defaults to "user". */
|
|
76
|
-
addedBy?: string;
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
/** How trust is confirmed for a round of missing repositories. */
|
|
80
|
-
export type ConfirmTrustOptions = {
|
|
81
|
-
/** Whether sous may ask. Defaults to whether both streams are a terminal. */
|
|
82
|
-
interactive?: boolean;
|
|
83
|
-
/**
|
|
84
|
-
* The confirmation flag, spelled `--trust` on the commands that perform this
|
|
85
|
-
* ceremony (and `--yes`, `-y`, `-f` or `--force`): acknowledge every
|
|
86
|
-
* repository this command adds, without asking.
|
|
87
|
-
*/
|
|
88
|
-
trustFlag?: boolean;
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
/** What a confirmation round produced. */
|
|
92
|
-
export type ConfirmTrustResult = {
|
|
93
|
-
/** The repositories the user accepted. */
|
|
94
|
-
accepted: MissingRepo[];
|
|
95
|
-
/** The ones whose URL sous knew, and has now written into the managed layer. */
|
|
96
|
-
added: string[];
|
|
97
|
-
/**
|
|
98
|
-
* The ones sous still cannot add on its own, because nothing told it their
|
|
99
|
-
* URL. A recipe names a repository by its short name, so the URL has to come
|
|
100
|
-
* from the person adding it.
|
|
101
|
-
*/
|
|
102
|
-
needUrl: string[];
|
|
103
|
-
};
|
|
104
|
-
|
|
105
|
-
/** How the trust service is built. */
|
|
106
|
-
export type TrustServiceOptions = ManagedLayerOptions & {
|
|
107
|
-
/** The project's `.sous/` directory; the managed layer lives under it. */
|
|
108
|
-
sousDir: string;
|
|
109
|
-
/** The merged settings, which is where hand-written `repos:` entries come from. */
|
|
110
|
-
settings?: Settings;
|
|
111
|
-
/** Whether sous may ask questions. Defaults to whether both streams are a terminal. */
|
|
112
|
-
interactive?: boolean;
|
|
113
|
-
/** How a yes or no question is asked. Injected in tests. */
|
|
114
|
-
ask?: (message: string) => Promise<boolean>;
|
|
115
|
-
/** Where the consolidated trust notice is written. Defaults to the console. */
|
|
116
|
-
write?: (message: string) => void;
|
|
117
|
-
/** The clock, so a recorded `addedAt` is predictable in tests. */
|
|
118
|
-
now?: () => Date;
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
/** Reads and changes the list of repositories a project trusts. */
|
|
122
|
-
export class TrustService {
|
|
123
|
-
private readonly sousDir: string;
|
|
124
|
-
|
|
125
|
-
private readonly layerOptions: ManagedLayerOptions;
|
|
126
|
-
|
|
127
|
-
private readonly settings: Settings | undefined;
|
|
128
|
-
|
|
129
|
-
private readonly interactive: boolean;
|
|
130
|
-
|
|
131
|
-
private readonly ask: (message: string) => Promise<boolean>;
|
|
132
|
-
|
|
133
|
-
private readonly write: (message: string) => void;
|
|
134
|
-
|
|
135
|
-
private readonly now: () => Date;
|
|
136
|
-
|
|
137
|
-
constructor(options: TrustServiceOptions) {
|
|
138
|
-
this.sousDir = options.sousDir;
|
|
139
|
-
this.layerOptions = options.confDir === undefined ? {} : { confDir: options.confDir };
|
|
140
|
-
this.settings = options.settings;
|
|
141
|
-
this.interactive = options.interactive ?? isInteractive();
|
|
142
|
-
this.ask = options.ask ?? ((message: string) => askYesNo(message));
|
|
143
|
-
this.write = options.write ?? writeLine;
|
|
144
|
-
this.now = options.now ?? (() => new Date());
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
/**
|
|
148
|
-
* Every repository the project trusts, keyed by short name. This is the
|
|
149
|
-
* merged view: entries hand-written in the primary config and entries sous
|
|
150
|
-
* wrote into the managed layer both appear, because by the time settings are
|
|
151
|
-
* loaded they are one map.
|
|
152
|
-
*
|
|
153
|
-
* @param settings - The merged settings. Defaults to the ones given at construction.
|
|
154
|
-
*/
|
|
155
|
-
listTrusted(settings: Settings | undefined = this.settings): Record<string, TrustedRepo> {
|
|
156
|
-
return { ...enabledRepos(settings) } as Record<string, TrustedRepo>;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
/**
|
|
160
|
-
* True when the project trusts a repository by that name.
|
|
161
|
-
*
|
|
162
|
-
* @param repoName - The repository's short name.
|
|
163
|
-
* @param settings - The merged settings. Defaults to the ones given at construction.
|
|
164
|
-
*/
|
|
165
|
-
isTrusted(repoName: string, settings: Settings | undefined = this.settings): boolean {
|
|
166
|
-
return Object.hasOwn(this.listTrusted(settings), repoName);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
/** Every repository written in the managed layer, keyed by short name. */
|
|
170
|
-
listManaged(): Record<string, TrustedRepo> {
|
|
171
|
-
const layer = readManagedLayer(this.sousDir, REPOS_LAYER_FILENAME, this.layerOptions);
|
|
172
|
-
const repos = layer["repos"];
|
|
173
|
-
if (typeof repos !== "object" || repos === null || Array.isArray(repos)) return {};
|
|
174
|
-
return repos as Record<string, TrustedRepo>;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
/**
|
|
178
|
-
* Adds a repository to the managed layer, which is what trusting one means.
|
|
179
|
-
* Adding a name that is already there replaces its entry, so this is also how
|
|
180
|
-
* a URL or a provider is corrected.
|
|
181
|
-
*
|
|
182
|
-
* @param request - The repository's name, URL and provenance.
|
|
183
|
-
*/
|
|
184
|
-
addRepo(request: AddRepoRequest): TrustedRepo {
|
|
185
|
-
const entry: TrustedRepo = {
|
|
186
|
-
url: request.url,
|
|
187
|
-
...(request.provider === undefined ? {} : { provider: request.provider }),
|
|
188
|
-
...(request.alwaysPull === undefined ? {} : { alwaysPull: request.alwaysPull }),
|
|
189
|
-
addedAt: this.now().toISOString(),
|
|
190
|
-
addedBy: request.addedBy ?? USER_ADDED_BY,
|
|
191
|
-
};
|
|
192
|
-
|
|
193
|
-
updateManagedLayer(
|
|
194
|
-
this.sousDir,
|
|
195
|
-
REPOS_LAYER_FILENAME,
|
|
196
|
-
[{ path: ["repos", request.name], value: entry }],
|
|
197
|
-
this.layerOptions
|
|
198
|
-
);
|
|
199
|
-
return entry;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
/**
|
|
203
|
-
* Removes a repository from the managed layer, withdrawing the trust. A
|
|
204
|
-
* repository written by hand in the primary config is not sous's to remove:
|
|
205
|
-
* that is an error saying so, since silently doing nothing would look like it
|
|
206
|
-
* worked.
|
|
207
|
-
*
|
|
208
|
-
* @param name - The repository's short name.
|
|
209
|
-
*/
|
|
210
|
-
removeRepo(name: string): void {
|
|
211
|
-
const existing = this.listManaged();
|
|
212
|
-
if (!Object.hasOwn(existing, name)) {
|
|
213
|
-
if (this.isTrusted(name)) {
|
|
214
|
-
throw new ConfigError(
|
|
215
|
-
`The repository '${name}' is written in this project's own config, not in the ` +
|
|
216
|
-
`layer sous manages.\n` +
|
|
217
|
-
` Remove its entry from the 'repos' block of your config file; sous never ` +
|
|
218
|
-
`edits a config file you wrote.`
|
|
219
|
-
);
|
|
220
|
-
}
|
|
221
|
-
throw new ConfigError(
|
|
222
|
-
`This project has no repository called '${name}'.\n` +
|
|
223
|
-
` Run 'sous repo list' to see the repositories it trusts.`
|
|
224
|
-
);
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
updateManagedLayer(
|
|
228
|
-
this.sousDir,
|
|
229
|
-
REPOS_LAYER_FILENAME,
|
|
230
|
-
[{ path: ["repos", name], value: undefined }],
|
|
231
|
-
this.layerOptions
|
|
232
|
-
);
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
/**
|
|
236
|
-
* Switches a repository off without deleting an entry, which is how trust is
|
|
237
|
-
* withdrawn from the repository sous provides itself. That entry is recreated
|
|
238
|
-
* from the installed package on every run, so only a recorded `enabled: false`
|
|
239
|
-
* outlives it; the shape is the same one a person writes by hand to opt out.
|
|
240
|
-
*
|
|
241
|
-
* @param name - The repository's short name.
|
|
242
|
-
*/
|
|
243
|
-
disableRepo(name: string): void {
|
|
244
|
-
updateManagedLayer(
|
|
245
|
-
this.sousDir,
|
|
246
|
-
REPOS_LAYER_FILENAME,
|
|
247
|
-
[{ path: ["repos", name], value: { enabled: false } }],
|
|
248
|
-
this.layerOptions
|
|
249
|
-
);
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
/**
|
|
253
|
-
* Asks about every repository a round of resolution turned up that the
|
|
254
|
-
* project has not added, in ONE consolidated question. Any refusal aborts,
|
|
255
|
-
* because a half-trusted install is not something sous will produce.
|
|
256
|
-
*
|
|
257
|
-
* @param missing - The repositories resolution says are needed.
|
|
258
|
-
* @param options - Whether sous may ask, and whether `--trust` was passed.
|
|
259
|
-
*/
|
|
260
|
-
async confirmTrust(
|
|
261
|
-
missing: MissingRepo[],
|
|
262
|
-
options: ConfirmTrustOptions = {}
|
|
263
|
-
): Promise<ConfirmTrustResult> {
|
|
264
|
-
if (missing.length === 0) return { accepted: [], added: [], needUrl: [] };
|
|
265
|
-
|
|
266
|
-
const interactive = options.interactive ?? this.interactive;
|
|
267
|
-
const trustFlag = options.trustFlag ?? false;
|
|
268
|
-
|
|
269
|
-
if (!trustFlag && !interactive) {
|
|
270
|
-
throw new NonInteractiveError(this.nonInteractiveMessage(missing));
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
if (!trustFlag) {
|
|
274
|
-
// The notice opens with a blank line of its own, so it never lands
|
|
275
|
-
// pressed up against whatever the command printed before it, wherever the
|
|
276
|
-
// ceremony runs from.
|
|
277
|
-
this.write(" ");
|
|
278
|
-
this.write(this.trustNotice(missing));
|
|
279
|
-
const plural = missing.length === 1 ? "this repository" : "these repositories";
|
|
280
|
-
const accepted = await this.ask(`Do you trust ${plural}?`);
|
|
281
|
-
if (!accepted) {
|
|
282
|
-
throw new ConfigError(
|
|
283
|
-
`Nothing was installed: trust was declined for ` +
|
|
284
|
-
`${missing.map((repo) => `'${repo.name}'`).join(", ")}.\n` +
|
|
285
|
-
` Sous installs a dependency closure whole or not at all, so declining any ` +
|
|
286
|
-
`repository in it stops the whole install.`
|
|
287
|
-
);
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
const added: string[] = [];
|
|
292
|
-
const needUrl: string[] = [];
|
|
293
|
-
for (const repo of missing) {
|
|
294
|
-
if (repo.url === undefined) {
|
|
295
|
-
needUrl.push(repo.name);
|
|
296
|
-
continue;
|
|
297
|
-
}
|
|
298
|
-
// Every requester is recorded, not just the first. Removal hygiene reads
|
|
299
|
-
// this to say why a repository is there, and a repository three recipes
|
|
300
|
-
// need looks removable when the entry names only one of them.
|
|
301
|
-
const requesters = [
|
|
302
|
-
...new Set(repo.requiredBy.map((entry) => entry.requestedBy)),
|
|
303
|
-
].sort();
|
|
304
|
-
this.addRepo({
|
|
305
|
-
name: repo.name,
|
|
306
|
-
url: repo.url,
|
|
307
|
-
// A dependency's locator names the provider in its scheme, which is the
|
|
308
|
-
// one thing a URL alone cannot say for a self-hosted host.
|
|
309
|
-
...(repo.provider === undefined ? {} : { provider: repo.provider as ProviderId }),
|
|
310
|
-
addedBy: requesters.length > 0 ? requesters.join(", ") : USER_ADDED_BY,
|
|
311
|
-
});
|
|
312
|
-
added.push(repo.name);
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
return { accepted: missing, added, needUrl };
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
/**
|
|
319
|
-
* The consolidated notice shown before the question: every new repository,
|
|
320
|
-
* its URL, the recipe that requires it, and what trusting it actually means.
|
|
321
|
-
*
|
|
322
|
-
* @param missing - The repositories being asked about.
|
|
323
|
-
*/
|
|
324
|
-
trustNotice(missing: MissingRepo[]): string {
|
|
325
|
-
const width = wrapColumns() - 2;
|
|
326
|
-
const lines: string[] = [];
|
|
327
|
-
lines.push(
|
|
328
|
-
palette.warning(
|
|
329
|
-
missing.length === 1
|
|
330
|
-
? "One repository has to be trusted before this can continue."
|
|
331
|
-
: `${missing.length} repositories have to be trusted before this can continue.`
|
|
332
|
-
)
|
|
333
|
-
);
|
|
334
|
-
lines.push(" ");
|
|
335
|
-
|
|
336
|
-
// Every repository is written as the same key and value block the rest of
|
|
337
|
-
// the CLI uses, so the facts under a repository name are read the same way
|
|
338
|
-
// as the facts anywhere else.
|
|
339
|
-
for (const repo of missing) {
|
|
340
|
-
lines.push(` ${color.bold(repo.name)}`);
|
|
341
|
-
|
|
342
|
-
const entries: VariableEntry[] = [
|
|
343
|
-
{
|
|
344
|
-
label: "Location",
|
|
345
|
-
value:
|
|
346
|
-
repo.url === undefined
|
|
347
|
-
? "not known to sous; a ref named it by its short name only"
|
|
348
|
-
: repo.url,
|
|
349
|
-
},
|
|
350
|
-
...(repo.identity === undefined
|
|
351
|
-
? []
|
|
352
|
-
: [{ label: "Identity", value: repo.identity }]),
|
|
353
|
-
...repo.requiredBy.map((entry) => ({
|
|
354
|
-
label: "Required",
|
|
355
|
-
value: entry.ref,
|
|
356
|
-
detail: `required by ${
|
|
357
|
-
entry.requestedBy === "project" ? "this project" : `'${entry.requestedBy}'`
|
|
358
|
-
}`,
|
|
359
|
-
})),
|
|
360
|
-
];
|
|
361
|
-
const labelWidth = Math.max(...entries.map((entry) => entry.label.length));
|
|
362
|
-
for (const entry of entries) {
|
|
363
|
-
lines.push(...formatVariable(entry, { labelWidth, width }));
|
|
364
|
-
}
|
|
365
|
-
lines.push(" ");
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
// The two phrases that carry the actual risk are highlighted in orange
|
|
369
|
-
// inside the yellow, so a reader skimming the block still takes in the part
|
|
370
|
-
// that matters.
|
|
371
|
-
const body = [
|
|
372
|
-
`Trusting a repository trusts ${palette.highlight(
|
|
373
|
-
"every namespace and every recipe"
|
|
374
|
-
)} in it, including ones published later. Trusting on its own executes ` +
|
|
375
|
-
`nothing; subscribing to something inside it ${palette.highlight(
|
|
376
|
-
"can, and probably will,"
|
|
377
|
-
)} run scripts on this machine. This question is the last gate before ` +
|
|
378
|
-
`that happens.`,
|
|
379
|
-
"",
|
|
380
|
-
"Sous cannot tell you whether a repository deserves trust. Look at the " +
|
|
381
|
-
"location above, and at who publishes it, before answering.",
|
|
382
|
-
].join("\n");
|
|
383
|
-
|
|
384
|
-
for (const line of wrapText(body, width - 2)) {
|
|
385
|
-
lines.push(line === "" ? " " : ` ${palette.warning(line)}`);
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
// The block closes on a blank line, so the question that follows it stands
|
|
389
|
-
// on its own rather than reading as the last line of the notice.
|
|
390
|
-
lines.push(" ");
|
|
391
|
-
return lines.join("\n");
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
/**
|
|
395
|
-
* The error a non-interactive run gets: it names every repository needing
|
|
396
|
-
* trust and the exact command that grants it, because a script cannot answer
|
|
397
|
-
* a question.
|
|
398
|
-
*
|
|
399
|
-
* @param missing - The repositories being asked about.
|
|
400
|
-
*/
|
|
401
|
-
private nonInteractiveMessage(missing: MissingRepo[]): string {
|
|
402
|
-
const lines: string[] = [
|
|
403
|
-
missing.length === 1
|
|
404
|
-
? "One repository has to be trusted before this can continue, and sous is not " +
|
|
405
|
-
"running where it can ask."
|
|
406
|
-
: `${missing.length} repositories have to be trusted before this can continue, ` +
|
|
407
|
-
`and sous is not running where it can ask.`,
|
|
408
|
-
` Why: ${nonInteractiveReason() ?? "there is no terminal to ask on"}.`,
|
|
409
|
-
"",
|
|
410
|
-
];
|
|
411
|
-
|
|
412
|
-
for (const repo of missing) {
|
|
413
|
-
const provenance = repo.requiredBy
|
|
414
|
-
.map((entry) => `${entry.ref} (required by ${entry.requestedBy})`)
|
|
415
|
-
.join(", ");
|
|
416
|
-
lines.push(` ${repo.name}: ${repo.url ?? "URL not known to sous"}`);
|
|
417
|
-
lines.push(` ${provenance}`);
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
lines.push("");
|
|
421
|
-
lines.push(" Trusting a repository trusts every namespace and recipe in it, and");
|
|
422
|
-
lines.push(" subscribing to something inside it can run scripts on this machine.");
|
|
423
|
-
lines.push(" Add each repository deliberately, with its URL:");
|
|
424
|
-
lines.push("");
|
|
425
|
-
for (const repo of missing) {
|
|
426
|
-
lines.push(` sous repo add ${repo.url ?? "<url>"} --name ${repo.name} --trust`);
|
|
427
|
-
}
|
|
428
|
-
lines.push("");
|
|
429
|
-
lines.push(
|
|
430
|
-
" '--trust' is one spelling of the confirmation flag; '--yes', '-y' and"
|
|
431
|
-
);
|
|
432
|
-
lines.push(" '--force' mean exactly the same thing.");
|
|
433
|
-
|
|
434
|
-
return lines.join("\n");
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
/**
|
|
439
|
-
* Writes a blank line and then a block of text, which is how the trust notice
|
|
440
|
-
* reaches the console when nothing overrides it.
|
|
441
|
-
*
|
|
442
|
-
* @param message - The block to write.
|
|
443
|
-
*/
|
|
444
|
-
export function writeTrustNotice(message: string): void {
|
|
445
|
-
blankLine();
|
|
446
|
-
writeLine(message);
|
|
447
|
-
}
|
|
@@ -1,235 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* What an update is about to do, written out before it asks.
|
|
3
|
-
*
|
|
4
|
-
* `sous subscription update` (and `sous repo unlink --update`, which runs the
|
|
5
|
-
* same code) works out the whole change first: which pins move, which
|
|
6
|
-
* dependencies arrive or leave, which repositories a newer version needs that
|
|
7
|
-
* the project does not trust yet, and which questions the new versions ask.
|
|
8
|
-
* This module turns those facts into the lines printed above the one question.
|
|
9
|
-
* It is pure: it formats what it is handed and decides nothing.
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import type { LockDiff } from "./lock-service.js";
|
|
13
|
-
import type { MissingRepo } from "./resolver.js";
|
|
14
|
-
import { formatQuestionPlan, type PlannedVariable } from "../vars/index.js";
|
|
15
|
-
import { BULLET, palette, wrapColumns, wrapText } from "../../utils/formatting.js";
|
|
16
|
-
|
|
17
|
-
/** What an update narrowed itself to. */
|
|
18
|
-
export type UpdateScope =
|
|
19
|
-
| { kind: "all" }
|
|
20
|
-
| { kind: "repository"; repo: string }
|
|
21
|
-
| { kind: "namespace"; repo: string; namespace: string }
|
|
22
|
-
| { kind: "recipe"; repo: string; key: string };
|
|
23
|
-
|
|
24
|
-
/** Everything the plan says, gathered by the subscription service. */
|
|
25
|
-
export type UpdatePlanFacts = {
|
|
26
|
-
/** What the update covers. */
|
|
27
|
-
scope: UpdateScope;
|
|
28
|
-
/** What would change in the lockfile. */
|
|
29
|
-
diff: LockDiff;
|
|
30
|
-
/** Repositories a newer version needs that the project does not trust yet. */
|
|
31
|
-
missingRepos: MissingRepo[];
|
|
32
|
-
/** The questions the new versions ask that nothing answers yet. */
|
|
33
|
-
questions: PlannedVariable[];
|
|
34
|
-
/** Recipes whose files are not on this machine and whose index does not record their questions. */
|
|
35
|
-
unreadable: string[];
|
|
36
|
-
/** Repositories whose index could not be fetched, so their pins stay where they are. */
|
|
37
|
-
unreachable: Array<{ repo: string; reason: string }>;
|
|
38
|
-
/** Linked repositories whose pins move, which builds keep bypassing. */
|
|
39
|
-
linked: string[];
|
|
40
|
-
/** Subscriptions sous provides itself, held at the version this sous ships. */
|
|
41
|
-
builtIn: Array<{ key: string; version?: string }>;
|
|
42
|
-
/** Switched-off subscriptions the update left alone. */
|
|
43
|
-
switchedOff: string[];
|
|
44
|
-
/** Subscriptions that could not be resolved, each with the reason. */
|
|
45
|
-
failed: Array<{ key: string; reason: string }>;
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* The scope in words, for a sentence that has to say what was updated.
|
|
50
|
-
*
|
|
51
|
-
* describeUpdateScope({ kind: "repository", repo: "sous-recipes" })
|
|
52
|
-
* // -> "the recipes this project takes from the repository 'sous-recipes'"
|
|
53
|
-
*
|
|
54
|
-
* @param scope - What the update covers.
|
|
55
|
-
*/
|
|
56
|
-
export function describeUpdateScope(scope: UpdateScope): string {
|
|
57
|
-
switch (scope.kind) {
|
|
58
|
-
case "all":
|
|
59
|
-
return "every subscription in this project";
|
|
60
|
-
case "repository":
|
|
61
|
-
return `the recipes this project takes from the repository '${scope.repo}'`;
|
|
62
|
-
case "namespace":
|
|
63
|
-
return `the recipes in the namespace '${scope.repo}:${scope.namespace}'`;
|
|
64
|
-
case "recipe":
|
|
65
|
-
return `the recipe '${scope.repo}:${scope.key}'`;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* True when the plan has nothing to do: no pin moves, nothing arrives or
|
|
71
|
-
* leaves, and no new repository is needed.
|
|
72
|
-
*
|
|
73
|
-
* @param facts - What the service worked out.
|
|
74
|
-
*/
|
|
75
|
-
export function isEmptyUpdate(facts: Pick<UpdatePlanFacts, "diff" | "missingRepos">): boolean {
|
|
76
|
-
return facts.diff.unchanged && facts.missingRepos.length === 0;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* The plan, as lines ready to be indented and printed. Pin changes come first,
|
|
81
|
-
* then the repositories that need trusting, then the questions, then the notes
|
|
82
|
-
* about what the update deliberately left alone.
|
|
83
|
-
*
|
|
84
|
-
* @param facts - What the service worked out.
|
|
85
|
-
* @param options - The width to wrap to, for tests.
|
|
86
|
-
*/
|
|
87
|
-
export function formatUpdatePlan(
|
|
88
|
-
facts: UpdatePlanFacts,
|
|
89
|
-
options: { width?: number } = {}
|
|
90
|
-
): string[] {
|
|
91
|
-
const width = (options.width ?? wrapColumns()) - 4;
|
|
92
|
-
const lines: string[] = [""];
|
|
93
|
-
|
|
94
|
-
/** One sentence, wrapped. */
|
|
95
|
-
const sentence = (text: string, paint = (line: string): string => line): string[] =>
|
|
96
|
-
wrapText(text, width).map(paint);
|
|
97
|
-
|
|
98
|
-
/** One bullet, wrapped so its continuation hangs under the text. */
|
|
99
|
-
const bullet = (text: string): string[] =>
|
|
100
|
-
wrapText(` ${BULLET} ${text}`, width, { hangingIndent: 2 });
|
|
101
|
-
|
|
102
|
-
if (isEmptyUpdate(facts)) {
|
|
103
|
-
lines.push(
|
|
104
|
-
...sentence(
|
|
105
|
-
`Nothing to update: every pin in ${describeUpdateScope(facts.scope)} is ` +
|
|
106
|
-
`already the newest published version its range allows.`
|
|
107
|
-
)
|
|
108
|
-
);
|
|
109
|
-
} else {
|
|
110
|
-
lines.push(...sentence(`Updating ${describeUpdateScope(facts.scope)} changes the lockfile:`));
|
|
111
|
-
lines.push("");
|
|
112
|
-
if (facts.diff.unchanged) {
|
|
113
|
-
lines.push(
|
|
114
|
-
...bullet("No pin moves until the repositories below are trusted and read.")
|
|
115
|
-
);
|
|
116
|
-
} else {
|
|
117
|
-
for (const change of facts.diff.lines) lines.push(...bullet(change));
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
if (facts.missingRepos.length > 0) {
|
|
122
|
-
lines.push("");
|
|
123
|
-
lines.push(
|
|
124
|
-
...sentence(
|
|
125
|
-
`A newer version needs ${
|
|
126
|
-
facts.missingRepos.length === 1 ? "a repository" : "repositories"
|
|
127
|
-
} this project ${palette.highlight("does not trust yet")}. You are asked about ` +
|
|
128
|
-
`each one by name before anything is fetched from it:`,
|
|
129
|
-
palette.warning
|
|
130
|
-
)
|
|
131
|
-
);
|
|
132
|
-
lines.push("");
|
|
133
|
-
for (const missing of facts.missingRepos) {
|
|
134
|
-
const where = missing.url === undefined ? "" : ` at ${missing.url}`;
|
|
135
|
-
const needers = missing.requiredBy.map((entry) => entry.requestedBy).join(", ");
|
|
136
|
-
lines.push(...bullet(`${missing.name}${where}, needed by ${needers}`));
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
if (facts.questions.length > 0 || facts.unreadable.length > 0) {
|
|
141
|
-
lines.push("");
|
|
142
|
-
lines.push(...sentence("Questions the new versions ask that nothing answers yet:"));
|
|
143
|
-
lines.push("");
|
|
144
|
-
for (const line of formatQuestionPlan(facts.questions, {
|
|
145
|
-
unreadable: facts.unreadable,
|
|
146
|
-
width,
|
|
147
|
-
})) {
|
|
148
|
-
lines.push(line === "" ? "" : ` ${line}`);
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
const notes: string[] = [];
|
|
153
|
-
if (facts.unreadable.length > 0) {
|
|
154
|
-
notes.push(
|
|
155
|
-
`A dry run downloads no recipe, so the dependencies of the versions not on this ` +
|
|
156
|
-
`machine yet, and not described by their index, are not shown: ` +
|
|
157
|
-
`${facts.unreadable.join(", ")}.`
|
|
158
|
-
);
|
|
159
|
-
}
|
|
160
|
-
for (const entry of facts.unreachable) {
|
|
161
|
-
notes.push(
|
|
162
|
-
`The index of '${entry.repo}' could not be fetched, so its pins stay where ` +
|
|
163
|
-
`they are. ${firstLine(entry.reason)}`
|
|
164
|
-
);
|
|
165
|
-
}
|
|
166
|
-
for (const entry of facts.failed) {
|
|
167
|
-
notes.push(
|
|
168
|
-
`The subscription to '${entry.key}' could not be resolved, so its pins stay ` +
|
|
169
|
-
`where they are. ${firstLine(entry.reason)}`
|
|
170
|
-
);
|
|
171
|
-
}
|
|
172
|
-
for (const repo of facts.linked) {
|
|
173
|
-
notes.push(
|
|
174
|
-
`The repository '${repo}' is linked to a working copy, so builds keep ` +
|
|
175
|
-
`reading that checkout until it is unlinked; the pins above take effect then.`
|
|
176
|
-
);
|
|
177
|
-
}
|
|
178
|
-
for (const entry of facts.builtIn) {
|
|
179
|
-
notes.push(
|
|
180
|
-
`The subscription to '${entry.key}' is one sous provides itself, and it stays ` +
|
|
181
|
-
`at ${
|
|
182
|
-
entry.version === undefined ? "the version" : `version ${entry.version}, the version`
|
|
183
|
-
} this installation of sous ships.`
|
|
184
|
-
);
|
|
185
|
-
}
|
|
186
|
-
if (facts.switchedOff.length > 0) {
|
|
187
|
-
notes.push(
|
|
188
|
-
`Switched off, so left alone: ${facts.switchedOff.join(", ")}.`
|
|
189
|
-
);
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
if (notes.length > 0) {
|
|
193
|
-
lines.push("");
|
|
194
|
-
for (const text of notes) {
|
|
195
|
-
lines.push(...wrapText(`${BULLET} ${text}`, width, { hangingIndent: 2 }).map(palette.note));
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
lines.push("");
|
|
200
|
-
return lines;
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
/**
|
|
204
|
-
* The first line of a possibly multi-line reason, which is what fits in a note.
|
|
205
|
-
*
|
|
206
|
-
* @param text - The reason.
|
|
207
|
-
*/
|
|
208
|
-
function firstLine(text: string): string {
|
|
209
|
-
return text.split("\n")[0]!.trim();
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
/**
|
|
213
|
-
* True when an update of this scope may move a recipe, judged by the recipe's
|
|
214
|
-
* key and the repository it comes from.
|
|
215
|
-
*
|
|
216
|
-
* recipeInScope({ kind: "namespace", repo: "r", namespace: "workflow" }, "workflow/x", "r")
|
|
217
|
-
* // -> true
|
|
218
|
-
*
|
|
219
|
-
* @param scope - What the update covers.
|
|
220
|
-
* @param key - The recipe key, `namespace/recipe`.
|
|
221
|
-
* @param repo - The short name of the repository it comes from.
|
|
222
|
-
*/
|
|
223
|
-
export function recipeInScope(scope: UpdateScope, key: string, repo: string): boolean {
|
|
224
|
-
switch (scope.kind) {
|
|
225
|
-
case "all":
|
|
226
|
-
return true;
|
|
227
|
-
case "repository":
|
|
228
|
-
return repo === scope.repo;
|
|
229
|
-
case "namespace":
|
|
230
|
-
return repo === scope.repo && key.startsWith(`${scope.namespace}/`);
|
|
231
|
-
case "recipe":
|
|
232
|
-
return repo === scope.repo && key === scope.key;
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The self-update layer: which copies of sous are installed, which version
|
|
3
|
-
* each should move to, and the package manager command that moves it.
|
|
4
|
-
*
|
|
5
|
-
* Import from here rather than from the individual modules. Nothing exported
|
|
6
|
-
* here installs anything; `run.ts`, imported on its own by `sous update`, is
|
|
7
|
-
* the flow that runs the commands the plans name.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
export * from "./versions.js";
|
|
11
|
-
export * from "./registry.js";
|
|
12
|
-
export * from "./managers.js";
|
|
13
|
-
export * from "./installs.js";
|
|
14
|
-
export * from "./plan.js";
|