fleetfizz 0.5.2 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/fleetfizz.mjs +1925 -960
- package/package.json +2 -1
- package/schema.json +1340 -71
package/dist/fleetfizz.mjs
CHANGED
|
@@ -4299,6 +4299,18 @@ const findFirst$1 = /*#__PURE__*/ dual(2, (self, f) => {
|
|
|
4299
4299
|
//#endregion
|
|
4300
4300
|
//#region ../../node_modules/.pnpm/effect@4.0.2/node_modules/effect/dist/Array.js
|
|
4301
4301
|
/**
|
|
4302
|
+
* Works with JavaScript arrays, readonly arrays, and non-empty arrays.
|
|
4303
|
+
*
|
|
4304
|
+
* The helpers cover common collection work such as creating arrays, reading
|
|
4305
|
+
* elements, transforming values, sorting, grouping, splitting, combining, and
|
|
4306
|
+
* reducing many values to one result. Helpers that change contents return new
|
|
4307
|
+
* arrays and preserve non-empty array types when the result is guaranteed to
|
|
4308
|
+
* contain values.
|
|
4309
|
+
*
|
|
4310
|
+
* @stability stable
|
|
4311
|
+
* @since 2.0.0
|
|
4312
|
+
*/
|
|
4313
|
+
/**
|
|
4302
4314
|
* Exposes the global array constructor.
|
|
4303
4315
|
*
|
|
4304
4316
|
* **When to use**
|
|
@@ -4562,6 +4574,17 @@ const findLast = /*#__PURE__*/ dual(2, (self, f) => {
|
|
|
4562
4574
|
}
|
|
4563
4575
|
return none();
|
|
4564
4576
|
});
|
|
4577
|
+
const hashBucketsAdd = (buckets, value) => {
|
|
4578
|
+
const hash$1 = hash(value);
|
|
4579
|
+
const bucket = buckets.get(hash$1);
|
|
4580
|
+
if (bucket === void 0) {
|
|
4581
|
+
buckets.set(hash$1, [value]);
|
|
4582
|
+
return true;
|
|
4583
|
+
}
|
|
4584
|
+
for (const previous of bucket) if (equals$1(previous, value)) return false;
|
|
4585
|
+
bucket.push(value);
|
|
4586
|
+
return true;
|
|
4587
|
+
};
|
|
4565
4588
|
/**
|
|
4566
4589
|
* Creates an empty array.
|
|
4567
4590
|
*
|
|
@@ -4658,6 +4681,38 @@ const map$8 = /*#__PURE__*/ dual(2, (self, f) => self.map(f));
|
|
|
4658
4681
|
* @since 2.0.0
|
|
4659
4682
|
*/
|
|
4660
4683
|
const reduce = /*#__PURE__*/ dual(3, (self, b, f) => fromIterable$1(self).reduce((b, a, i) => f(b, a, i), b));
|
|
4684
|
+
/**
|
|
4685
|
+
* Removes duplicates using `Equal.equivalence()`, preserving the order of the
|
|
4686
|
+
* first occurrence.
|
|
4687
|
+
*
|
|
4688
|
+
* **When to use**
|
|
4689
|
+
*
|
|
4690
|
+
* Use to remove repeated values from an iterable when Effect's default equality
|
|
4691
|
+
* is the right comparison, preserving the first occurrence.
|
|
4692
|
+
*
|
|
4693
|
+
* **Example** (Removing duplicates)
|
|
4694
|
+
*
|
|
4695
|
+
* ```ts import.meta.vitest
|
|
4696
|
+
* import { Array } from "effect"
|
|
4697
|
+
*
|
|
4698
|
+
* Array.dedupe([1, 2, 1, 3, 2, 4]) // => [1, 2, 3, 4]
|
|
4699
|
+
* ```
|
|
4700
|
+
*
|
|
4701
|
+
* @see {@link dedupeWith} — use custom equality
|
|
4702
|
+
* @see {@link dedupeAdjacent} — only dedupes consecutive elements
|
|
4703
|
+
*
|
|
4704
|
+
* @stability stable
|
|
4705
|
+
* @category deduplication
|
|
4706
|
+
* @since 2.0.0
|
|
4707
|
+
*/
|
|
4708
|
+
const dedupe = (self) => {
|
|
4709
|
+
const input = fromIterable$1(self);
|
|
4710
|
+
if (input.length < 2) return [...input];
|
|
4711
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
4712
|
+
const out = [];
|
|
4713
|
+
for (const value of input) if (hashBucketsAdd(buckets, value)) out.push(value);
|
|
4714
|
+
return out;
|
|
4715
|
+
};
|
|
4661
4716
|
//#endregion
|
|
4662
4717
|
//#region ../../node_modules/.pnpm/effect@4.0.2/node_modules/effect/dist/Duration.js
|
|
4663
4718
|
const TypeId$31 = "~effect/Duration";
|
|
@@ -20340,13 +20395,13 @@ function canPreserveEncodingChecks(ast) {
|
|
|
20340
20395
|
* @category transforming
|
|
20341
20396
|
* @since 4.0.0
|
|
20342
20397
|
*/
|
|
20343
|
-
const toType = /*#__PURE__*/ memoizeIdempotent((ast) => {
|
|
20398
|
+
const toType$1 = /*#__PURE__*/ memoizeIdempotent((ast) => {
|
|
20344
20399
|
const owner = getContextOwner(ast);
|
|
20345
20400
|
if (owner !== ast) {
|
|
20346
|
-
const type = toType(owner);
|
|
20401
|
+
const type = toType$1(owner);
|
|
20347
20402
|
return type === owner && ast.encoding === void 0 ? ast : replaceContext(type, ast.context);
|
|
20348
20403
|
}
|
|
20349
|
-
const type = "recur" in ast ? ast.recur(toType) : ast;
|
|
20404
|
+
const type = "recur" in ast ? ast.recur(toType$1) : ast;
|
|
20350
20405
|
if ("encodingChecks" in type && type.encodingChecks) {
|
|
20351
20406
|
const checks = canPreserveEncodingChecks(ast) ? type.encodingChecks : isArrays(type) || isObjects(type) || isDeclaration(type) && type.typeParameters.length > 0 ? extractStructuralChecks(type.encodingChecks) : void 0;
|
|
20352
20407
|
return copy$1(type, {
|
|
@@ -20384,7 +20439,7 @@ const toType = /*#__PURE__*/ memoizeIdempotent((ast) => {
|
|
|
20384
20439
|
* @since 4.0.0
|
|
20385
20440
|
*/
|
|
20386
20441
|
const toEncoded = /*#__PURE__*/ memoizeIdempotent((ast) => {
|
|
20387
|
-
return toType(flip(ast));
|
|
20442
|
+
return toType$1(flip(ast));
|
|
20388
20443
|
});
|
|
20389
20444
|
function flipEncoding(ast, encoding) {
|
|
20390
20445
|
const links = encoding;
|
|
@@ -22738,7 +22793,7 @@ function makeEffect(schema) {
|
|
|
22738
22793
|
const ast = schema.ast;
|
|
22739
22794
|
let parser;
|
|
22740
22795
|
return (input, options) => {
|
|
22741
|
-
return (parser ??= runWithCompiler(constructorCompiler, toType(ast)))(input, options?.disableChecks ? options?.parseOptions ? {
|
|
22796
|
+
return (parser ??= runWithCompiler(constructorCompiler, toType$1(ast)))(input, options?.disableChecks ? options?.parseOptions ? {
|
|
22742
22797
|
...options.parseOptions,
|
|
22743
22798
|
disableChecks: true
|
|
22744
22799
|
} : { disableChecks: true } : options?.parseOptions);
|
|
@@ -22799,7 +22854,7 @@ function makeOption(schema) {
|
|
|
22799
22854
|
* @since 4.0.0
|
|
22800
22855
|
*/
|
|
22801
22856
|
function make$5(schema) {
|
|
22802
|
-
return makeConstructorSync(toType(schema.ast));
|
|
22857
|
+
return makeConstructorSync(toType$1(schema.ast));
|
|
22803
22858
|
}
|
|
22804
22859
|
/**
|
|
22805
22860
|
* Creates a type guard that checks whether an input satisfies the schema's decoded
|
|
@@ -22841,7 +22896,7 @@ function makeIs(ast) {
|
|
|
22841
22896
|
}
|
|
22842
22897
|
/** @internal */
|
|
22843
22898
|
function _is(ast) {
|
|
22844
|
-
const typeAST = toType(ast);
|
|
22899
|
+
const typeAST = toType$1(ast);
|
|
22845
22900
|
let guard = (input) => {
|
|
22846
22901
|
guard = makeIs(typeAST);
|
|
22847
22902
|
return guard(input);
|
|
@@ -22876,6 +22931,10 @@ function decodeUnknownEffect$1(schema, options) {
|
|
|
22876
22931
|
const parser = run$3(schema.ast);
|
|
22877
22932
|
return options === void 0 ? parser : (input, overrideOptions) => parser(input, mergeParseOptions(options, overrideOptions));
|
|
22878
22933
|
}
|
|
22934
|
+
/** @internal */
|
|
22935
|
+
function decodeUnknownOption$1(schema, options) {
|
|
22936
|
+
return asOption(decodeUnknownEffect$1(schema, options));
|
|
22937
|
+
}
|
|
22879
22938
|
/**
|
|
22880
22939
|
* Creates a decoder for `unknown` input that reports failure safely as a
|
|
22881
22940
|
* `Result`.
|
|
@@ -22961,6 +23020,16 @@ function runWithCompiler(compiler, ast) {
|
|
|
22961
23020
|
function asExit(parser) {
|
|
22962
23021
|
return (input, options) => runSyncExit(parser(input, options));
|
|
22963
23022
|
}
|
|
23023
|
+
/** @internal */
|
|
23024
|
+
function asOption(parser) {
|
|
23025
|
+
const parserExit = asExit(parser);
|
|
23026
|
+
return (input, options) => {
|
|
23027
|
+
const exit = parserExit(input, options);
|
|
23028
|
+
if (isSuccess(exit)) return some(exit.value);
|
|
23029
|
+
getSchemaIssueOrThrow(exit.cause, "Option adapter can only return none for schema issues");
|
|
23030
|
+
return none();
|
|
23031
|
+
};
|
|
23032
|
+
}
|
|
22964
23033
|
function asResult(parser) {
|
|
22965
23034
|
const parserExit = asExit(parser);
|
|
22966
23035
|
return (input, options) => {
|
|
@@ -24086,7 +24155,7 @@ function toRepresentations(asts, options) {
|
|
|
24086
24155
|
}
|
|
24087
24156
|
function visitChecks(checks) {
|
|
24088
24157
|
checks?.forEach((check) => {
|
|
24089
|
-
check.annotations?.representation?.schemas?.forEach((schema) => visit(toType(schema)));
|
|
24158
|
+
check.annotations?.representation?.schemas?.forEach((schema) => visit(toType$1(schema)));
|
|
24090
24159
|
if (check._tag === "FilterGroup") visitChecks(check.checks);
|
|
24091
24160
|
});
|
|
24092
24161
|
}
|
|
@@ -24226,7 +24295,7 @@ function toRepresentations(asts, options) {
|
|
|
24226
24295
|
const { representation, ...ordinary } = annotations;
|
|
24227
24296
|
const projected = representation === void 0 ? void 0 : representation.schemas === void 0 ? representation : {
|
|
24228
24297
|
...representation,
|
|
24229
|
-
schemas: representation.schemas.map((schema) => recur(toType(schema)))
|
|
24298
|
+
schemas: representation.schemas.map((schema) => recur(toType$1(schema)))
|
|
24230
24299
|
};
|
|
24231
24300
|
return {
|
|
24232
24301
|
...projected === void 0 ? void 0 : { representation: projected },
|
|
@@ -24282,6 +24351,20 @@ function isSchemaError$1(u) {
|
|
|
24282
24351
|
}
|
|
24283
24352
|
//#endregion
|
|
24284
24353
|
//#region ../../node_modules/.pnpm/effect@4.0.2/node_modules/effect/dist/Schema.js
|
|
24354
|
+
/**
|
|
24355
|
+
* Describes data shapes and how unknown input becomes trusted values.
|
|
24356
|
+
*
|
|
24357
|
+
* A schema can validate input, decode it into an application type, and encode
|
|
24358
|
+
* that value back to another representation. This module contains the main
|
|
24359
|
+
* schema, codec, decoder, and encoder APIs, together with schemas for common
|
|
24360
|
+
* JavaScript values and Effect data types. It also supports refinements,
|
|
24361
|
+
* transformations, defaults, classes, JSON Schema generation, test data
|
|
24362
|
+
* generation, formatting, equivalence, optics, and differs derived from schema
|
|
24363
|
+
* definitions.
|
|
24364
|
+
*
|
|
24365
|
+
* @stability stable
|
|
24366
|
+
* @since 4.0.0
|
|
24367
|
+
*/
|
|
24285
24368
|
const TypeId$5 = TypeId$6;
|
|
24286
24369
|
/**
|
|
24287
24370
|
* Error thrown or returned when schema decoding or encoding fails.
|
|
@@ -24468,6 +24551,34 @@ function decodeUnknownEffect(schema, options) {
|
|
|
24468
24551
|
*/
|
|
24469
24552
|
const decodeEffect = decodeUnknownEffect;
|
|
24470
24553
|
/**
|
|
24554
|
+
* Decodes an `unknown` input against a schema, returning an `Option` that is
|
|
24555
|
+
* `Some` with the decoded value on success or `None` for schema mismatches.
|
|
24556
|
+
*
|
|
24557
|
+
* **When to use**
|
|
24558
|
+
*
|
|
24559
|
+
* Use when you do not know the input type statically and only need to know
|
|
24560
|
+
* whether decoding succeeded.
|
|
24561
|
+
*
|
|
24562
|
+
* **Details**
|
|
24563
|
+
*
|
|
24564
|
+
* Prefer this over {@link decodeUnknownExit} or {@link decodeUnknownEffect}
|
|
24565
|
+
* when you don't need error details. For input already typed as the schema's
|
|
24566
|
+
* `Encoded` type use {@link decodeOption}.
|
|
24567
|
+
* Options may be provided either when creating the decoder or when applying it;
|
|
24568
|
+
* application options override creation options.
|
|
24569
|
+
*
|
|
24570
|
+
* **Gotchas**
|
|
24571
|
+
*
|
|
24572
|
+
* Only causes made entirely of schema issues are converted to `None`. Causes
|
|
24573
|
+
* that contain defects, interruptions, or other non-schema reasons throw
|
|
24574
|
+
* instead.
|
|
24575
|
+
*
|
|
24576
|
+
* @stability stable
|
|
24577
|
+
* @category decoding
|
|
24578
|
+
* @since 3.10.0
|
|
24579
|
+
*/
|
|
24580
|
+
const decodeUnknownOption = decodeUnknownOption$1;
|
|
24581
|
+
/**
|
|
24471
24582
|
* Decodes an `unknown` input against a schema, returning a `Result` that
|
|
24472
24583
|
* succeeds with the decoded value or fails with a {@link SchemaError} for schema
|
|
24473
24584
|
* mismatches.
|
|
@@ -24711,6 +24822,15 @@ const optional$2 = /*#__PURE__*/ lambda((self) => {
|
|
|
24711
24822
|
return make$3(optional$3(self.ast), { schema });
|
|
24712
24823
|
});
|
|
24713
24824
|
/**
|
|
24825
|
+
* Extracts the type-side schema: sets `Encoded` to equal the decoded `Type`,
|
|
24826
|
+
* discarding the encoding transformation path.
|
|
24827
|
+
*
|
|
24828
|
+
* @stability stable
|
|
24829
|
+
* @category transforming
|
|
24830
|
+
* @since 4.0.0
|
|
24831
|
+
*/
|
|
24832
|
+
const toType = /*#__PURE__*/ lambda((schema) => make$3(toType$1(schema.ast), { schema }));
|
|
24833
|
+
/**
|
|
24714
24834
|
* Creates a schema for a single literal value (string, number, bigint, boolean, or null).
|
|
24715
24835
|
*
|
|
24716
24836
|
* **Example** (Defining a string literal)
|
|
@@ -25244,6 +25364,45 @@ function isPattern(regExp, annotations) {
|
|
|
25244
25364
|
...annotations
|
|
25245
25365
|
});
|
|
25246
25366
|
}
|
|
25367
|
+
/**
|
|
25368
|
+
* Validates that a value has at least the specified length. Works with strings
|
|
25369
|
+
* and arrays.
|
|
25370
|
+
*
|
|
25371
|
+
* **Details**
|
|
25372
|
+
*
|
|
25373
|
+
* JSON Schema:
|
|
25374
|
+
*
|
|
25375
|
+
* The bound must be finite; it is rounded down and clamped to zero. For arrays,
|
|
25376
|
+
* this check corresponds to `minItems`. JavaScript counts UTF-16 code units
|
|
25377
|
+
* while JSON Schema counts Unicode code points, so strings use
|
|
25378
|
+
* `minLength: Math.ceil(minLength / 2)`, the tightest lower bound that cannot
|
|
25379
|
+
* reject a string accepted by this check.
|
|
25380
|
+
*
|
|
25381
|
+
* Arbitrary:
|
|
25382
|
+
*
|
|
25383
|
+
* During arbitrary generation, this applies a `minLength`
|
|
25384
|
+
* constraint to ensure generated strings or arrays have at least the required
|
|
25385
|
+
* length.
|
|
25386
|
+
*
|
|
25387
|
+
* **Example** (Checking minimum length)
|
|
25388
|
+
*
|
|
25389
|
+
* ```ts import.meta.vitest
|
|
25390
|
+
* import { Schema } from "effect"
|
|
25391
|
+
*
|
|
25392
|
+
* const NonEmptyStringSchema = Schema.String.check(Schema.isMinLength(1))
|
|
25393
|
+
* const NonEmptyArraySchema = Schema.Array(Schema.Number).check(Schema.isMinLength(1))
|
|
25394
|
+
* Schema.is(NonEmptyStringSchema)("a") // => true
|
|
25395
|
+
* Schema.is(NonEmptyArraySchema)([1]) // => true
|
|
25396
|
+
* ```
|
|
25397
|
+
*
|
|
25398
|
+
* @stability stable
|
|
25399
|
+
* @category validation
|
|
25400
|
+
* @since 4.0.0
|
|
25401
|
+
*/
|
|
25402
|
+
function isMinLength(minLength, annotations) {
|
|
25403
|
+
minLength = normalizeCardinality(minLength);
|
|
25404
|
+
return makeIsMinLength(minLength, Math.ceil(minLength / 2), annotations);
|
|
25405
|
+
}
|
|
25247
25406
|
function makeIsMinLength(minLength, minCodePoints, annotations) {
|
|
25248
25407
|
return makeFilter((input) => input.length >= minLength, {
|
|
25249
25408
|
expected: `a value with a length of at least ${minLength}`,
|
|
@@ -25284,6 +25443,39 @@ function makeIsMinLength(minLength, minCodePoints, annotations) {
|
|
|
25284
25443
|
function isNonEmpty(annotations) {
|
|
25285
25444
|
return makeIsMinLength(1, 1, annotations);
|
|
25286
25445
|
}
|
|
25446
|
+
function normalizeCardinality(value) {
|
|
25447
|
+
if (!globalThis.Number.isFinite(value)) throw new globalThis.RangeError(`Expected a finite number, got ${value}`);
|
|
25448
|
+
return Math.max(0, Math.floor(value));
|
|
25449
|
+
}
|
|
25450
|
+
/**
|
|
25451
|
+
* Validates that all items in an array are unique according to Effect equality.
|
|
25452
|
+
*
|
|
25453
|
+
* **Details**
|
|
25454
|
+
*
|
|
25455
|
+
* JSON Schema:
|
|
25456
|
+
* This check corresponds to the `uniqueItems: true` constraint in JSON Schema.
|
|
25457
|
+
*
|
|
25458
|
+
* Arbitrary:
|
|
25459
|
+
* During arbitrary generation, this applies a node-local identity selector
|
|
25460
|
+
* for constructive uniqueness using Effect equality.
|
|
25461
|
+
*
|
|
25462
|
+
* @stability stable
|
|
25463
|
+
* @category validation
|
|
25464
|
+
* @since 4.0.0
|
|
25465
|
+
*/
|
|
25466
|
+
function isUnique(annotations) {
|
|
25467
|
+
return makeFilter((input) => dedupe(input).length === input.length, {
|
|
25468
|
+
expected: "an array with unique items",
|
|
25469
|
+
representation: {
|
|
25470
|
+
id: "effect/schema/isUnique",
|
|
25471
|
+
payload: null
|
|
25472
|
+
},
|
|
25473
|
+
toJsonSchema: () => ({ uniqueItems: true }),
|
|
25474
|
+
toCode: () => ({ runtime: "Schema.isUnique()" }),
|
|
25475
|
+
arbitraryConstraint: { uniqueBy: identity },
|
|
25476
|
+
...annotations
|
|
25477
|
+
});
|
|
25478
|
+
}
|
|
25287
25479
|
/**
|
|
25288
25480
|
* Schema for non-empty strings. Validates that a string has at least one
|
|
25289
25481
|
* character.
|
|
@@ -25893,145 +26085,6 @@ function defaultShouldQuit(input) {
|
|
|
25893
26085
|
*/
|
|
25894
26086
|
const layer = /*#__PURE__*/ provideMerge(layer$11, /*#__PURE__*/ mergeAll(layer$7, layer$9, layer$5, layer$3, layer$2));
|
|
25895
26087
|
//#endregion
|
|
25896
|
-
//#region ../../node_modules/.pnpm/effect@4.0.2/node_modules/effect/dist/Console.js
|
|
25897
|
-
/**
|
|
25898
|
-
* Context reference for the current console service in the Effect system, allowing access to the active console implementation from within the Effect context.
|
|
25899
|
-
*
|
|
25900
|
-
* **When to use**
|
|
25901
|
-
*
|
|
25902
|
-
* Use when you need an effect to run against a provided console implementation,
|
|
25903
|
-
* such as tests or alternate runtimes, rather than the default console.
|
|
25904
|
-
*
|
|
25905
|
-
* **Details**
|
|
25906
|
-
*
|
|
25907
|
-
* When no override is provided, the reference resolves to `globalThis.console`.
|
|
25908
|
-
*
|
|
25909
|
-
* **Example** (Accessing the current console)
|
|
25910
|
-
*
|
|
25911
|
-
* ```ts import.meta.vitest
|
|
25912
|
-
* import { Console, Effect } from "effect"
|
|
25913
|
-
*
|
|
25914
|
-
* const messages: Array<unknown> = []
|
|
25915
|
-
* const testConsole: Console.Console = Object.assign(Object.create(console), {
|
|
25916
|
-
* log: (...args: ReadonlyArray<unknown>) => messages.push(...args)
|
|
25917
|
-
* })
|
|
25918
|
-
* const program = Console.consoleWith((console) =>
|
|
25919
|
-
* Effect.sync(() => {
|
|
25920
|
-
* console.log("Hello from current console!")
|
|
25921
|
-
* })
|
|
25922
|
-
* )
|
|
25923
|
-
*
|
|
25924
|
-
* Effect.runSync(Effect.provideService(program, Console.Console, testConsole))
|
|
25925
|
-
* messages // => ["Hello from current console!"]
|
|
25926
|
-
* ```
|
|
25927
|
-
*
|
|
25928
|
-
* @see {@link consoleWith} for using the current console service inside an effect
|
|
25929
|
-
*
|
|
25930
|
-
* @stability stable
|
|
25931
|
-
* @category services
|
|
25932
|
-
* @since 2.0.0
|
|
25933
|
-
*/
|
|
25934
|
-
const Console = ConsoleRef;
|
|
25935
|
-
/**
|
|
25936
|
-
* Creates an Effect that provides access to the current console service and lets you perform operations with it within an Effect context.
|
|
25937
|
-
*
|
|
25938
|
-
* **Example** (Accessing the current console service)
|
|
25939
|
-
*
|
|
25940
|
-
* ```ts import.meta.vitest
|
|
25941
|
-
* import { Console, Effect } from "effect"
|
|
25942
|
-
*
|
|
25943
|
-
* const messages: Array<unknown> = []
|
|
25944
|
-
* const testConsole: Console.Console = Object.assign(Object.create(console), {
|
|
25945
|
-
* log: (...args: ReadonlyArray<unknown>) => messages.push(...args),
|
|
25946
|
-
* error: (...args: ReadonlyArray<unknown>) => messages.push(...args)
|
|
25947
|
-
* })
|
|
25948
|
-
* const program = Console.consoleWith((console) =>
|
|
25949
|
-
* Effect.sync(() => {
|
|
25950
|
-
* console.log("Hello, world!")
|
|
25951
|
-
* console.error("This is an error message")
|
|
25952
|
-
* })
|
|
25953
|
-
* )
|
|
25954
|
-
*
|
|
25955
|
-
* Effect.runSync(Effect.provideService(program, Console.Console, testConsole))
|
|
25956
|
-
* messages // => ["Hello, world!", "This is an error message"]
|
|
25957
|
-
* ```
|
|
25958
|
-
*
|
|
25959
|
-
* @stability stable
|
|
25960
|
-
* @category constructors
|
|
25961
|
-
* @since 2.0.0
|
|
25962
|
-
*/
|
|
25963
|
-
const consoleWith = (f) => withFiber$1((fiber) => f(fiber.getRef(Console)));
|
|
25964
|
-
/**
|
|
25965
|
-
* Writes an error-level message to the console, typically displayed with error
|
|
25966
|
-
* styling by the active console implementation.
|
|
25967
|
-
*
|
|
25968
|
-
* **Example** (Writing error messages)
|
|
25969
|
-
*
|
|
25970
|
-
* ```ts import.meta.vitest
|
|
25971
|
-
* import { Console, Effect } from "effect"
|
|
25972
|
-
*
|
|
25973
|
-
* const messages: Array<ReadonlyArray<unknown>> = []
|
|
25974
|
-
* const testConsole: Console.Console = Object.assign(Object.create(console), {
|
|
25975
|
-
* error: (...args: ReadonlyArray<unknown>) => messages.push(args)
|
|
25976
|
-
* })
|
|
25977
|
-
* const program = Effect.gen(function*() {
|
|
25978
|
-
* yield* Console.error("Something went wrong!")
|
|
25979
|
-
* yield* Console.error("Error details:", {
|
|
25980
|
-
* code: 500,
|
|
25981
|
-
* message: "Internal Server Error"
|
|
25982
|
-
* })
|
|
25983
|
-
* })
|
|
25984
|
-
*
|
|
25985
|
-
* Effect.runSync(Effect.provideService(program, Console.Console, testConsole))
|
|
25986
|
-
* const expected = [
|
|
25987
|
-
* ["Something went wrong!"],
|
|
25988
|
-
* ["Error details:", { code: 500, message: "Internal Server Error" }]
|
|
25989
|
-
* ]
|
|
25990
|
-
* messages // => expected
|
|
25991
|
-
* ```
|
|
25992
|
-
*
|
|
25993
|
-
* @stability stable
|
|
25994
|
-
* @category accessors
|
|
25995
|
-
* @since 2.0.0
|
|
25996
|
-
*/
|
|
25997
|
-
const error = (...args) => consoleWith((console) => sync$1(() => {
|
|
25998
|
-
console.error(...args);
|
|
25999
|
-
}));
|
|
26000
|
-
/**
|
|
26001
|
-
* Logs a general-purpose message to the console.
|
|
26002
|
-
*
|
|
26003
|
-
* **Example** (Writing log messages)
|
|
26004
|
-
*
|
|
26005
|
-
* ```ts import.meta.vitest
|
|
26006
|
-
* import { Console, Effect } from "effect"
|
|
26007
|
-
*
|
|
26008
|
-
* const messages: Array<ReadonlyArray<unknown>> = []
|
|
26009
|
-
* const testConsole: Console.Console = Object.assign(Object.create(console), {
|
|
26010
|
-
* log: (...args: ReadonlyArray<unknown>) => messages.push(args)
|
|
26011
|
-
* })
|
|
26012
|
-
* const program = Effect.gen(function*() {
|
|
26013
|
-
* yield* Console.log("Hello, world!")
|
|
26014
|
-
* yield* Console.log("User data:", { name: "John", age: 30 })
|
|
26015
|
-
* yield* Console.log("Processing", 42, "items")
|
|
26016
|
-
* })
|
|
26017
|
-
*
|
|
26018
|
-
* Effect.runSync(Effect.provideService(program, Console.Console, testConsole))
|
|
26019
|
-
* const expected = [
|
|
26020
|
-
* ["Hello, world!"],
|
|
26021
|
-
* ["User data:", { name: "John", age: 30 }],
|
|
26022
|
-
* ["Processing", 42, "items"]
|
|
26023
|
-
* ]
|
|
26024
|
-
* messages // => expected
|
|
26025
|
-
* ```
|
|
26026
|
-
*
|
|
26027
|
-
* @stability stable
|
|
26028
|
-
* @category accessors
|
|
26029
|
-
* @since 2.0.0
|
|
26030
|
-
*/
|
|
26031
|
-
const log = (...args) => consoleWith((console) => sync$1(() => {
|
|
26032
|
-
console.log(...args);
|
|
26033
|
-
}));
|
|
26034
|
-
//#endregion
|
|
26035
26088
|
//#region ../../node_modules/.pnpm/effect@4.0.2/node_modules/effect/dist/cli/CliError.js
|
|
26036
26089
|
/**
|
|
26037
26090
|
* Defines structured errors for the unstable CLI parser and runner.
|
|
@@ -29124,6 +29177,145 @@ const getParamMetadata = (param) => {
|
|
|
29124
29177
|
});
|
|
29125
29178
|
};
|
|
29126
29179
|
//#endregion
|
|
29180
|
+
//#region ../../node_modules/.pnpm/effect@4.0.2/node_modules/effect/dist/Console.js
|
|
29181
|
+
/**
|
|
29182
|
+
* Context reference for the current console service in the Effect system, allowing access to the active console implementation from within the Effect context.
|
|
29183
|
+
*
|
|
29184
|
+
* **When to use**
|
|
29185
|
+
*
|
|
29186
|
+
* Use when you need an effect to run against a provided console implementation,
|
|
29187
|
+
* such as tests or alternate runtimes, rather than the default console.
|
|
29188
|
+
*
|
|
29189
|
+
* **Details**
|
|
29190
|
+
*
|
|
29191
|
+
* When no override is provided, the reference resolves to `globalThis.console`.
|
|
29192
|
+
*
|
|
29193
|
+
* **Example** (Accessing the current console)
|
|
29194
|
+
*
|
|
29195
|
+
* ```ts import.meta.vitest
|
|
29196
|
+
* import { Console, Effect } from "effect"
|
|
29197
|
+
*
|
|
29198
|
+
* const messages: Array<unknown> = []
|
|
29199
|
+
* const testConsole: Console.Console = Object.assign(Object.create(console), {
|
|
29200
|
+
* log: (...args: ReadonlyArray<unknown>) => messages.push(...args)
|
|
29201
|
+
* })
|
|
29202
|
+
* const program = Console.consoleWith((console) =>
|
|
29203
|
+
* Effect.sync(() => {
|
|
29204
|
+
* console.log("Hello from current console!")
|
|
29205
|
+
* })
|
|
29206
|
+
* )
|
|
29207
|
+
*
|
|
29208
|
+
* Effect.runSync(Effect.provideService(program, Console.Console, testConsole))
|
|
29209
|
+
* messages // => ["Hello from current console!"]
|
|
29210
|
+
* ```
|
|
29211
|
+
*
|
|
29212
|
+
* @see {@link consoleWith} for using the current console service inside an effect
|
|
29213
|
+
*
|
|
29214
|
+
* @stability stable
|
|
29215
|
+
* @category services
|
|
29216
|
+
* @since 2.0.0
|
|
29217
|
+
*/
|
|
29218
|
+
const Console = ConsoleRef;
|
|
29219
|
+
/**
|
|
29220
|
+
* Creates an Effect that provides access to the current console service and lets you perform operations with it within an Effect context.
|
|
29221
|
+
*
|
|
29222
|
+
* **Example** (Accessing the current console service)
|
|
29223
|
+
*
|
|
29224
|
+
* ```ts import.meta.vitest
|
|
29225
|
+
* import { Console, Effect } from "effect"
|
|
29226
|
+
*
|
|
29227
|
+
* const messages: Array<unknown> = []
|
|
29228
|
+
* const testConsole: Console.Console = Object.assign(Object.create(console), {
|
|
29229
|
+
* log: (...args: ReadonlyArray<unknown>) => messages.push(...args),
|
|
29230
|
+
* error: (...args: ReadonlyArray<unknown>) => messages.push(...args)
|
|
29231
|
+
* })
|
|
29232
|
+
* const program = Console.consoleWith((console) =>
|
|
29233
|
+
* Effect.sync(() => {
|
|
29234
|
+
* console.log("Hello, world!")
|
|
29235
|
+
* console.error("This is an error message")
|
|
29236
|
+
* })
|
|
29237
|
+
* )
|
|
29238
|
+
*
|
|
29239
|
+
* Effect.runSync(Effect.provideService(program, Console.Console, testConsole))
|
|
29240
|
+
* messages // => ["Hello, world!", "This is an error message"]
|
|
29241
|
+
* ```
|
|
29242
|
+
*
|
|
29243
|
+
* @stability stable
|
|
29244
|
+
* @category constructors
|
|
29245
|
+
* @since 2.0.0
|
|
29246
|
+
*/
|
|
29247
|
+
const consoleWith = (f) => withFiber$1((fiber) => f(fiber.getRef(Console)));
|
|
29248
|
+
/**
|
|
29249
|
+
* Writes an error-level message to the console, typically displayed with error
|
|
29250
|
+
* styling by the active console implementation.
|
|
29251
|
+
*
|
|
29252
|
+
* **Example** (Writing error messages)
|
|
29253
|
+
*
|
|
29254
|
+
* ```ts import.meta.vitest
|
|
29255
|
+
* import { Console, Effect } from "effect"
|
|
29256
|
+
*
|
|
29257
|
+
* const messages: Array<ReadonlyArray<unknown>> = []
|
|
29258
|
+
* const testConsole: Console.Console = Object.assign(Object.create(console), {
|
|
29259
|
+
* error: (...args: ReadonlyArray<unknown>) => messages.push(args)
|
|
29260
|
+
* })
|
|
29261
|
+
* const program = Effect.gen(function*() {
|
|
29262
|
+
* yield* Console.error("Something went wrong!")
|
|
29263
|
+
* yield* Console.error("Error details:", {
|
|
29264
|
+
* code: 500,
|
|
29265
|
+
* message: "Internal Server Error"
|
|
29266
|
+
* })
|
|
29267
|
+
* })
|
|
29268
|
+
*
|
|
29269
|
+
* Effect.runSync(Effect.provideService(program, Console.Console, testConsole))
|
|
29270
|
+
* const expected = [
|
|
29271
|
+
* ["Something went wrong!"],
|
|
29272
|
+
* ["Error details:", { code: 500, message: "Internal Server Error" }]
|
|
29273
|
+
* ]
|
|
29274
|
+
* messages // => expected
|
|
29275
|
+
* ```
|
|
29276
|
+
*
|
|
29277
|
+
* @stability stable
|
|
29278
|
+
* @category accessors
|
|
29279
|
+
* @since 2.0.0
|
|
29280
|
+
*/
|
|
29281
|
+
const error = (...args) => consoleWith((console) => sync$1(() => {
|
|
29282
|
+
console.error(...args);
|
|
29283
|
+
}));
|
|
29284
|
+
/**
|
|
29285
|
+
* Logs a general-purpose message to the console.
|
|
29286
|
+
*
|
|
29287
|
+
* **Example** (Writing log messages)
|
|
29288
|
+
*
|
|
29289
|
+
* ```ts import.meta.vitest
|
|
29290
|
+
* import { Console, Effect } from "effect"
|
|
29291
|
+
*
|
|
29292
|
+
* const messages: Array<ReadonlyArray<unknown>> = []
|
|
29293
|
+
* const testConsole: Console.Console = Object.assign(Object.create(console), {
|
|
29294
|
+
* log: (...args: ReadonlyArray<unknown>) => messages.push(args)
|
|
29295
|
+
* })
|
|
29296
|
+
* const program = Effect.gen(function*() {
|
|
29297
|
+
* yield* Console.log("Hello, world!")
|
|
29298
|
+
* yield* Console.log("User data:", { name: "John", age: 30 })
|
|
29299
|
+
* yield* Console.log("Processing", 42, "items")
|
|
29300
|
+
* })
|
|
29301
|
+
*
|
|
29302
|
+
* Effect.runSync(Effect.provideService(program, Console.Console, testConsole))
|
|
29303
|
+
* const expected = [
|
|
29304
|
+
* ["Hello, world!"],
|
|
29305
|
+
* ["User data:", { name: "John", age: 30 }],
|
|
29306
|
+
* ["Processing", 42, "items"]
|
|
29307
|
+
* ]
|
|
29308
|
+
* messages // => expected
|
|
29309
|
+
* ```
|
|
29310
|
+
*
|
|
29311
|
+
* @stability stable
|
|
29312
|
+
* @category accessors
|
|
29313
|
+
* @since 2.0.0
|
|
29314
|
+
*/
|
|
29315
|
+
const log = (...args) => consoleWith((console) => sync$1(() => {
|
|
29316
|
+
console.log(...args);
|
|
29317
|
+
}));
|
|
29318
|
+
//#endregion
|
|
29127
29319
|
//#region ../../node_modules/.pnpm/effect@4.0.2/node_modules/effect/dist/cli/CliOutput.js
|
|
29128
29320
|
/**
|
|
29129
29321
|
* Formats CLI help and errors as text.
|
|
@@ -32440,7 +32632,7 @@ const runWith = (command, config) => {
|
|
|
32440
32632
|
};
|
|
32441
32633
|
//#endregion
|
|
32442
32634
|
//#region package.json
|
|
32443
|
-
var version = "0.
|
|
32635
|
+
var version = "0.7.0";
|
|
32444
32636
|
//#endregion
|
|
32445
32637
|
//#region ../../node_modules/.pnpm/jsonc-parser@3.3.1/node_modules/jsonc-parser/lib/esm/impl/scanner.js
|
|
32446
32638
|
/**
|
|
@@ -35097,51 +35289,48 @@ var import_semver = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin(((exp
|
|
|
35097
35289
|
})))(), 1);
|
|
35098
35290
|
var BumpError = class extends TaggedError()("BumpError", {
|
|
35099
35291
|
path: String$5,
|
|
35100
|
-
|
|
35292
|
+
at: String$5,
|
|
35101
35293
|
reason: String$5
|
|
35102
35294
|
}) {
|
|
35103
35295
|
get message() {
|
|
35104
|
-
return `${this.path}: cannot bump ${this.
|
|
35296
|
+
return `${this.path}: cannot bump ${this.at}: ${this.reason}`;
|
|
35105
35297
|
}
|
|
35106
35298
|
};
|
|
35107
|
-
const rangePath = (pkg) => pkg === "vite-plus" ? ["vp", "version"] : pkg === "node" ? ["vp", "node"] : [
|
|
35108
|
-
"vp",
|
|
35109
|
-
"globals",
|
|
35110
|
-
pkg
|
|
35111
|
-
];
|
|
35112
35299
|
const bumpedRange = (current, installed) => import_semver.valid(current) !== null ? installed : `^${installed}`;
|
|
35113
|
-
const bumpText = (text,
|
|
35114
|
-
const
|
|
35115
|
-
const node = findNodeAtLocation(parseTree(text) ?? {
|
|
35300
|
+
const bumpText = (text, path, installed) => {
|
|
35301
|
+
const tree = parseTree(text) ?? {
|
|
35116
35302
|
type: "null",
|
|
35117
35303
|
offset: 0,
|
|
35118
35304
|
length: 0
|
|
35119
|
-
}
|
|
35305
|
+
};
|
|
35306
|
+
const shorthand = path.slice(0, -1);
|
|
35307
|
+
const at = findNodeAtLocation(tree, [...path]) === void 0 && findNodeAtLocation(tree, shorthand)?.type === "string" ? shorthand : path;
|
|
35308
|
+
const node = findNodeAtLocation(tree, [...at]);
|
|
35120
35309
|
if (node === void 0 || node.type !== "string" || typeof node.value !== "string") return { reason: `${path.join(".")} is not a string literal; change it by hand` };
|
|
35121
35310
|
const range = bumpedRange(node.value, installed);
|
|
35122
35311
|
return {
|
|
35123
|
-
text: applyEdits(text, modify(text,
|
|
35312
|
+
text: applyEdits(text, modify(text, [...at], range, { formattingOptions: {
|
|
35124
35313
|
insertSpaces: true,
|
|
35125
35314
|
tabSize: 2
|
|
35126
35315
|
} })),
|
|
35127
35316
|
range
|
|
35128
35317
|
};
|
|
35129
35318
|
};
|
|
35130
|
-
const bumpConfig = fn("bumpConfig")(function* (configPath,
|
|
35319
|
+
const bumpConfig = fn("bumpConfig")(function* (configPath, path, installed) {
|
|
35131
35320
|
const fs = yield* FileSystem;
|
|
35132
35321
|
const text = yield* fs.readFileString(configPath);
|
|
35133
|
-
const result = bumpText(text,
|
|
35322
|
+
const result = bumpText(text, path, installed);
|
|
35134
35323
|
if ("reason" in result) return yield* new BumpError({
|
|
35135
35324
|
path: configPath,
|
|
35136
|
-
|
|
35325
|
+
at: path.join("."),
|
|
35137
35326
|
reason: result.reason
|
|
35138
35327
|
});
|
|
35139
35328
|
yield* fs.writeFileString(configPath, result.text);
|
|
35140
35329
|
return result.range;
|
|
35141
35330
|
});
|
|
35142
35331
|
const Targeting = {
|
|
35143
|
-
platforms: optionalKey(NonEmptyArray(Literals$2(["darwin", "linux"]))),
|
|
35144
|
-
machines: optionalKey(NonEmptyArray(NonEmptyString))
|
|
35332
|
+
platforms: optionalKey(NonEmptyArray(Literals$2(["darwin", "linux"]))).annotateKey({ description: "`darwin`, `linux`, or both." }),
|
|
35333
|
+
machines: optionalKey(NonEmptyArray(NonEmptyString)).annotateKey({ description: "Machine names from `machines`." })
|
|
35145
35334
|
};
|
|
35146
35335
|
const Origin = String$5.check(isPattern(/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/, {
|
|
35147
35336
|
title: "GitHub origin",
|
|
@@ -35149,39 +35338,102 @@ const Origin = String$5.check(isPattern(/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/, {
|
|
|
35149
35338
|
}));
|
|
35150
35339
|
const Ref = NonEmptyString;
|
|
35151
35340
|
const isPin = (ref) => /^[0-9a-f]{40}$/.test(ref);
|
|
35341
|
+
const ProviderName = Literals$2([
|
|
35342
|
+
"vp",
|
|
35343
|
+
"brew",
|
|
35344
|
+
"cask",
|
|
35345
|
+
"repos"
|
|
35346
|
+
]);
|
|
35152
35347
|
const Range = NonEmptyString.check(makeFilter((range) => range === "latest" || import_semver.validRange(range) !== null, {
|
|
35153
35348
|
title: "Range",
|
|
35154
|
-
description: "a semver range, \"*\", or \"latest\""
|
|
35349
|
+
description: "a semver range (leave inside it, install below it, ask above it), \"*\" (install when missing, never upgrade), or \"latest\" (upgrade to the newest on every Ship)"
|
|
35155
35350
|
}));
|
|
35156
35351
|
const TrackedRepo = Struct({
|
|
35157
35352
|
...Targeting,
|
|
35158
|
-
origin: Origin,
|
|
35159
|
-
ref: Ref,
|
|
35160
|
-
install: NonEmptyString,
|
|
35161
|
-
|
|
35162
|
-
|
|
35163
|
-
|
|
35353
|
+
origin: Origin.annotateKey({ description: "The GitHub `owner/repo`." }),
|
|
35354
|
+
ref: Ref.annotateKey({ description: "A branch, or a full 40-character commit SHA to pin it." }),
|
|
35355
|
+
install: NonEmptyString.annotateKey({ description: "The Install Command, run in a login shell inside the Managed Clone." }),
|
|
35356
|
+
outputs: optionalKey(ArraySchema(NonEmptyString)).annotateKey({ description: "Paths outside the clone the Install Command produces. If one changes by hand, the repo reinstalls." }),
|
|
35357
|
+
files: optionalKey(Record(NonEmptyString, String$5)).annotateKey({ description: "Gitignored files (Clone Files) written into the clone before every install, keyed by path. Never secrets." })
|
|
35358
|
+
});
|
|
35359
|
+
const withShorthand = (entry, value, shorthand) => Union([entry, value.pipe(decodeTo(toType(entry), transform$1(shorthand)))]);
|
|
35360
|
+
const variants = (entry) => Union([entry, NonEmptyArray(entry)]);
|
|
35361
|
+
const dependsOn = optionalKey(ArraySchema(ProviderName)).annotateKey({ description: "Providers whose Items must succeed on a Machine before this one changes there." });
|
|
35362
|
+
const section = (settings, items, description) => Struct({
|
|
35363
|
+
...Targeting,
|
|
35364
|
+
dependsOn,
|
|
35365
|
+
...settings,
|
|
35366
|
+
items: optionalKey(items).annotateKey({ description })
|
|
35164
35367
|
});
|
|
35165
|
-
const
|
|
35368
|
+
const VARIANTS = "or a list of Variants, of which a Machine gets the first that targets it";
|
|
35369
|
+
const Global = withShorthand(Struct({
|
|
35166
35370
|
...Targeting,
|
|
35167
|
-
|
|
35168
|
-
|
|
35169
|
-
|
|
35371
|
+
range: Range
|
|
35372
|
+
}), Range, {
|
|
35373
|
+
decode: (range) => ({ range }),
|
|
35374
|
+
encode: (global) => global.range
|
|
35170
35375
|
});
|
|
35171
|
-
const
|
|
35376
|
+
const PACKAGE_MANAGERS = [
|
|
35377
|
+
"npm",
|
|
35378
|
+
"pnpm",
|
|
35379
|
+
"yarn",
|
|
35380
|
+
"bun"
|
|
35381
|
+
];
|
|
35382
|
+
const NOT_GLOBALS = {
|
|
35383
|
+
vp: "the vp Item is vp itself; set it with vp.version",
|
|
35384
|
+
mode: "the mode Item is vp's managed mode",
|
|
35385
|
+
node: "set Node with vp.node",
|
|
35386
|
+
...Object.fromEntries(PACKAGE_MANAGERS.map((pm) => [pm, `set ${pm} with vp.${pm}`])),
|
|
35387
|
+
"vite-plus": "set vp with vp.version",
|
|
35388
|
+
fleetfizz: "a Ship installs the fleetfizz that ships"
|
|
35389
|
+
};
|
|
35390
|
+
const VpSection = section({
|
|
35391
|
+
version: optionalKey(Range).annotateKey({ description: "The vp version. Pin it exactly." }),
|
|
35392
|
+
node: optionalKey(Range).annotateKey({ description: "The default Node version. Pin it exactly." }),
|
|
35393
|
+
npm: optionalKey(Range).annotateKey({ description: "The default npm version." }),
|
|
35394
|
+
pnpm: optionalKey(Range).annotateKey({ description: "The default pnpm version." }),
|
|
35395
|
+
yarn: optionalKey(Range).annotateKey({ description: "The default Yarn version." }),
|
|
35396
|
+
bun: optionalKey(Range).annotateKey({ description: "The default Bun version." })
|
|
35397
|
+
}, Record(NonEmptyString, variants(Global)).check(makeFilter((globals) => {
|
|
35398
|
+
const name = Object.keys(globals).find((n) => n in NOT_GLOBALS);
|
|
35399
|
+
return name === void 0 || `"${name}" is not a Global: ${NOT_GLOBALS[name]}`;
|
|
35400
|
+
}, {
|
|
35401
|
+
title: "Globals",
|
|
35402
|
+
description: "npm packages other than vp, node, a package manager, vite-plus, and fleetfizz"
|
|
35403
|
+
})), `Globals, keyed by package. Each is a Range, \`{ range, platforms?, machines? }\` to target it, ${VARIANTS}.`);
|
|
35404
|
+
const HomebrewRange = Literals$2(["*", "latest"]).annotate({ description: "\"*\" (install when missing, never upgrade) or \"latest\" (brew update, then upgrade on every Ship)" });
|
|
35405
|
+
const HomebrewItems = Record(NonEmptyString, variants(withShorthand(Struct({
|
|
35406
|
+
...Targeting,
|
|
35407
|
+
range: HomebrewRange
|
|
35408
|
+
}), HomebrewRange, {
|
|
35409
|
+
decode: (range) => ({ range }),
|
|
35410
|
+
encode: (entry) => entry.range
|
|
35411
|
+
})));
|
|
35412
|
+
const homebrewDescription = (noun) => `${noun}, keyed by name. Each is \`"*"\` or \`"latest"\`, \`{ range, platforms?, machines? }\` to target it, ${VARIANTS}. A tapped name (\`owner/tap/name\`) taps on install.`;
|
|
35413
|
+
const BrewSection = section({}, HomebrewItems.check(makeFilter((items) => !Object.hasOwn(items, "brew") || "\"brew\" is Homebrew itself", {
|
|
35414
|
+
title: "Formulae",
|
|
35415
|
+
description: "Formulae other than brew"
|
|
35416
|
+
})), homebrewDescription("Formulae"));
|
|
35417
|
+
const CaskSection = section({}, HomebrewItems, homebrewDescription("Casks"));
|
|
35418
|
+
const DEFAULT_CLONE_ROOT = "~/.local/share/fleetfizz/clones";
|
|
35419
|
+
const ReposSection = section({ cloneRoot: optionalKey(variants(withShorthand(Struct({
|
|
35420
|
+
...Targeting,
|
|
35421
|
+
path: NonEmptyString
|
|
35422
|
+
}), NonEmptyString, {
|
|
35423
|
+
decode: (path) => ({ path }),
|
|
35424
|
+
encode: (root) => root.path
|
|
35425
|
+
}))).annotateKey({ description: `Where a Machine keeps its Managed Clones: a path, or a list of \`{ path, platforms?, machines? }\` where a Machine gets the first that targets it. \`~\` expands on that Machine. Default: \`${DEFAULT_CLONE_ROOT}\`.` }) }, Record(NonEmptyString, variants(TrackedRepo)), `Tracked Repos, keyed by name, which names the Managed Clone and the \`repos:<name>\` Item. Each is \`{ origin, ref, install, ... }\`, ${VARIANTS}.`);
|
|
35172
35426
|
const FleetConfig = Struct({
|
|
35173
35427
|
$schema: optionalKey(String$5),
|
|
35174
35428
|
shippedAt: optionalKey(String$5),
|
|
35175
35429
|
shippedFrom: optionalKey(NonEmptyString),
|
|
35176
35430
|
shippedTo: optionalKey(Record(NonEmptyString, String$5)),
|
|
35177
|
-
machines:
|
|
35178
|
-
|
|
35179
|
-
|
|
35180
|
-
})
|
|
35181
|
-
|
|
35182
|
-
vp: optionalKey(VpSection)
|
|
35431
|
+
machines: ArraySchema(NonEmptyString).check(isMinLength(1, { message: "list at least one Machine" }), isUnique({ message: "list each Machine once" })).annotateKey({ description: "The Fleet: each Machine's tailnet name. A tailnet member that is not listed is not part of the Fleet." }),
|
|
35432
|
+
repos: optionalKey(ReposSection).annotateKey({ description: "Each Tracked Repo is cloned on every targeted Machine and installed from its origin ref." }),
|
|
35433
|
+
vp: optionalKey(VpSection).annotateKey({ description: "The vite-plus toolchain." }),
|
|
35434
|
+
brew: optionalKey(BrewSection).annotateKey({ description: "Homebrew Formulae. Needs Homebrew on the Machine; a Ship never installs it." }),
|
|
35435
|
+
cask: optionalKey(CaskSection).annotateKey({ description: "Homebrew Casks, macOS only. Needs Homebrew on the Machine." })
|
|
35183
35436
|
});
|
|
35184
|
-
const repoName = (repo) => repo.name ?? repo.origin.replace("/", "-");
|
|
35185
35437
|
const SELF_PACKAGE = "fleetfizz";
|
|
35186
35438
|
//#endregion
|
|
35187
35439
|
//#region ../../packages/config/src/jsonSchema.ts
|
|
@@ -35214,17 +35466,33 @@ var ConfigNotFound = class extends TaggedError()("ConfigNotFound", { path: Strin
|
|
|
35214
35466
|
}
|
|
35215
35467
|
};
|
|
35216
35468
|
const lineOf = (text, offset) => text.slice(0, offset).split("\n").length;
|
|
35217
|
-
const
|
|
35469
|
+
const repeatedKeys = (text) => {
|
|
35218
35470
|
const problems = [];
|
|
35219
|
-
const
|
|
35220
|
-
|
|
35221
|
-
|
|
35222
|
-
|
|
35223
|
-
|
|
35224
|
-
|
|
35225
|
-
|
|
35471
|
+
const visit = (node, path) => {
|
|
35472
|
+
if (node.type === "array") node.children?.forEach((child, i) => visit(child, [...path, i]));
|
|
35473
|
+
if (node.type !== "object") return;
|
|
35474
|
+
const seen = /* @__PURE__ */ new Set();
|
|
35475
|
+
for (const [key, value] of (node.children ?? []).map((property) => property.children ?? [])) {
|
|
35476
|
+
if (key === void 0) continue;
|
|
35477
|
+
const name = String(key.value);
|
|
35478
|
+
if (seen.has(name)) problems.push(`line ${lineOf(text, key.offset)}: "${name}" is repeated${path.length > 0 ? ` in ${path.join(".")}` : ""}`);
|
|
35479
|
+
seen.add(name);
|
|
35480
|
+
if (value !== void 0) visit(value, [...path, name]);
|
|
35481
|
+
}
|
|
35482
|
+
};
|
|
35483
|
+
const tree = parseTree(text, void 0, { allowTrailingComma: true });
|
|
35484
|
+
if (tree !== void 0) visit(tree, []);
|
|
35226
35485
|
return problems;
|
|
35227
35486
|
};
|
|
35487
|
+
const movedKeys = (parsed) => {
|
|
35488
|
+
if (typeof parsed !== "object" || parsed === null) return [];
|
|
35489
|
+
const config = parsed;
|
|
35490
|
+
return [
|
|
35491
|
+
...typeof config.machines === "object" && config.machines !== null && !Array.isArray(config.machines) ? ["machines is now a list of names, and machines.<name>.clones is repos.cloneRoot"] : [],
|
|
35492
|
+
...Array.isArray(config.repos) ? ["repos is now { items: { <name>: { origin, ref, install } } }, keyed by each repo's name"] : [],
|
|
35493
|
+
...typeof config.vp === "object" && config.vp !== null && "globals" in config.vp ? ["vp.globals is now vp.items"] : []
|
|
35494
|
+
];
|
|
35495
|
+
};
|
|
35228
35496
|
const parseConfig = fn("parseConfig")(function* (path, text) {
|
|
35229
35497
|
const parseErrors = [];
|
|
35230
35498
|
const parsed = parse(text, parseErrors, { allowTrailingComma: true });
|
|
@@ -35232,16 +35500,20 @@ const parseConfig = fn("parseConfig")(function* (path, text) {
|
|
|
35232
35500
|
path,
|
|
35233
35501
|
problems: parseErrors.map((e) => `line ${lineOf(text, e.offset)}: ${printParseErrorCode(e.error)}`)
|
|
35234
35502
|
});
|
|
35235
|
-
const
|
|
35503
|
+
const moved = movedKeys(parsed);
|
|
35504
|
+
if (moved.length > 0) return yield* new ConfigError({
|
|
35236
35505
|
path,
|
|
35237
|
-
problems:
|
|
35238
|
-
})
|
|
35239
|
-
const
|
|
35240
|
-
if (
|
|
35506
|
+
problems: moved
|
|
35507
|
+
});
|
|
35508
|
+
const repeated = repeatedKeys(text);
|
|
35509
|
+
if (repeated.length > 0) return yield* new ConfigError({
|
|
35241
35510
|
path,
|
|
35242
|
-
problems
|
|
35511
|
+
problems: repeated
|
|
35243
35512
|
});
|
|
35244
|
-
return
|
|
35513
|
+
return yield* decodeUnknownEffect(FleetConfig, { onExcessProperty: "error" })(parsed).pipe(mapError((error) => new ConfigError({
|
|
35514
|
+
path,
|
|
35515
|
+
problems: [formatIssue(error.issue)]
|
|
35516
|
+
})));
|
|
35245
35517
|
});
|
|
35246
35518
|
const formatIssue = makeFormatterDefault();
|
|
35247
35519
|
const loadConfig = fn("loadConfig")(function* (path) {
|
|
@@ -35283,7 +35555,7 @@ const stampText = (text, stamp) => {
|
|
|
35283
35555
|
const machinesOf = (config) => {
|
|
35284
35556
|
if (typeof config !== "object" || config === null || !("machines" in config)) return [];
|
|
35285
35557
|
const value = config.machines;
|
|
35286
|
-
return
|
|
35558
|
+
return Array.isArray(value) ? value.filter((name) => typeof name === "string") : [];
|
|
35287
35559
|
};
|
|
35288
35560
|
const shippedToOf = (config) => {
|
|
35289
35561
|
if (typeof config !== "object" || config === null || !("shippedTo" in config)) return {};
|
|
@@ -35308,8 +35580,10 @@ const vpEnv = [
|
|
|
35308
35580
|
].join("\n");
|
|
35309
35581
|
const prelude = [
|
|
35310
35582
|
vpEnv,
|
|
35583
|
+
`export PATH="$PATH:/opt/homebrew/bin:/home/linuxbrew/.linuxbrew/bin"`,
|
|
35311
35584
|
`ff_json() { printf '%s' "$1" | sed -e 's/\\\\/\\\\\\\\/g' -e 's/"/\\\\"/g' | tr -d '\\n'; }`,
|
|
35312
|
-
`ff_state() { printf 'ff-state %s\\n' "$1"; }
|
|
35585
|
+
`ff_state() { printf 'ff-state %s\\n' "$1"; }`,
|
|
35586
|
+
`ff_at() { ff_state "{\\"provider\\":\\"$(ff_json "$1")\\",\\"fact\\":\\"at\\",\\"item\\":\\"$(ff_json "$2")\\",\\"at\\":\\"$(ff_json "$3")\\"}"; }`
|
|
35313
35587
|
].join("\n");
|
|
35314
35588
|
const fingerprintFn = [
|
|
35315
35589
|
"ff_fp() {",
|
|
@@ -35324,470 +35598,52 @@ const fingerprintFn = [
|
|
|
35324
35598
|
const STATE_DIR = "~/.local/state/fleetfizz";
|
|
35325
35599
|
const RECORDS_DIR = `${STATE_DIR}/records`;
|
|
35326
35600
|
const CONFIG_DIR_SH = "\"${XDG_CONFIG_HOME:-$HOME/.config}/fleetfizz\"";
|
|
35601
|
+
const recordDir = (provider) => `${quotePath(RECORDS_DIR)}/${quote(provider)}`;
|
|
35602
|
+
const recordFile = (provider, item) => `${recordDir(provider)}/${quote(`${item}.json`)}`;
|
|
35603
|
+
const LEGACY_RECORD_PROVIDER = "repos";
|
|
35604
|
+
const recordFact = (provider, item) => [
|
|
35605
|
+
`ff_r=${recordFile(provider, item)}`,
|
|
35606
|
+
...provider === LEGACY_RECORD_PROVIDER ? [`[ -f "$ff_r" ] || ff_r=${quotePath(RECORDS_DIR)}/${quote(`${item}.json`)}`] : [],
|
|
35607
|
+
`if [ -f "$ff_r" ]; then ff_state "{\\"fact\\":\\"record\\",\\"provider\\":\\"${provider}\\",\\"item\\":\\"$(ff_json ${quote(item)})\\",\\"record\\":$(tr -d '\\n' < "$ff_r")}"; fi`
|
|
35608
|
+
];
|
|
35327
35609
|
const checkScript = (input) => {
|
|
35328
35610
|
const lines = [
|
|
35329
35611
|
prelude,
|
|
35330
35612
|
fingerprintFn,
|
|
35331
|
-
`ff_state "{\\"fact\\":\\"home\\",\\"path\\":\\"$(ff_json "$HOME")\\"}"
|
|
35332
|
-
"if command -v vp >/dev/null 2>&1; then",
|
|
35333
|
-
` ff_v=$(command vp --version 2>/dev/null | sed -n 's/^vp v\\{0,1\\}\\([^ ]*\\).*/\\1/p' | head -n 1)`,
|
|
35334
|
-
` ff_state "{\\"fact\\":\\"vp\\",\\"version\\":\\"$(ff_json "$ff_v")\\",\\"path\\":\\"$(ff_json "$(command -v vp)")\\"}"`,
|
|
35335
|
-
` ff_n=$(command vp env default 2>/dev/null | sed -n 's/^Default Node.js version: //p' | head -n 1)`,
|
|
35336
|
-
` if [ -n "$ff_n" ]; then ff_state "{\\"fact\\":\\"node\\",\\"version\\":\\"$(ff_json "$ff_n")\\"}"; else ff_state '{"fact":"node","version":null}'; fi`,
|
|
35337
|
-
` ff_g=$(command vp list --global --json 2>/dev/null | tr -d '\\n')`,
|
|
35338
|
-
` ff_state "{\\"fact\\":\\"globals\\",\\"list\\":\${ff_g:-[]}}"`,
|
|
35339
|
-
"else",
|
|
35340
|
-
` ff_state '{"fact":"vp","version":null}'`,
|
|
35341
|
-
"fi",
|
|
35342
|
-
`ff_root=${quotePath(input.cloneRoot)}`,
|
|
35343
|
-
`if [ -d "$ff_root" ]; then ff_present=true; else ff_present=false; fi`,
|
|
35344
|
-
`ff_state "{\\"fact\\":\\"cloneRoot\\",\\"path\\":\\"$(ff_json "$ff_root")\\",\\"present\\":$ff_present}"`
|
|
35613
|
+
`ff_state "{\\"fact\\":\\"home\\",\\"path\\":\\"$(ff_json "$HOME")\\"}"`
|
|
35345
35614
|
];
|
|
35346
|
-
for (const
|
|
35347
|
-
|
|
35348
|
-
|
|
35349
|
-
for (const output of repo.outputs) lines.push(`ff_p=${quotePath(output)}; ff_f=$(ff_fp "$ff_p")`, `if [ -n "$ff_f" ]; then ff_state "{\\"fact\\":\\"output\\",\\"repo\\":\\"$(ff_json ${name})\\",\\"path\\":\\"$(ff_json ${quote(output)})\\",\\"fingerprint\\":\\"$(ff_json "$ff_f")\\"}"; else ff_state "{\\"fact\\":\\"output\\",\\"repo\\":\\"$(ff_json ${name})\\",\\"path\\":\\"$(ff_json ${quote(output)})\\",\\"fingerprint\\":null}"; fi`);
|
|
35350
|
-
}
|
|
35351
|
-
for (const repo of input.repos) {
|
|
35352
|
-
const name = quote(repo.name);
|
|
35353
|
-
lines.push(`ff_r=${quotePath(RECORDS_DIR)}/${quote(`${repo.name}.json`)}`, `if [ -f "$ff_r" ]; then ff_state "{\\"fact\\":\\"record\\",\\"name\\":\\"$(ff_json ${name})\\",\\"record\\":$(tr -d '\\n' < "$ff_r")}"; fi`);
|
|
35615
|
+
for (const { provider, items } of input.providers) {
|
|
35616
|
+
lines.push(provider.observe(items, input.scope));
|
|
35617
|
+
if (provider.rule === "record") for (const item of items) lines.push(...recordFact(provider.name, item.name));
|
|
35354
35618
|
}
|
|
35355
35619
|
lines.push(`ff_c=${CONFIG_DIR_SH}/${quote(CONFIG_FILE)}`, `if [ -f "$ff_c" ]; then ff_state "{\\"fact\\":\\"config\\",\\"present\\":true,\\"base64\\":\\"$(base64 < "$ff_c" | tr -d '\\n')\\"}"; else ff_state '{"fact":"config","present":false}'; fi`);
|
|
35356
35620
|
lines.push(`ff_state '{"fact":"end"}'`);
|
|
35357
35621
|
return lines.join("\n");
|
|
35358
35622
|
};
|
|
35359
35623
|
//#endregion
|
|
35360
|
-
//#region ../../packages/core/src/range.ts
|
|
35361
|
-
const newest$1 = (available) => available.filter((v) => import_semver.prerelease(v) === null).sort(import_semver.rcompare)[0];
|
|
35362
|
-
const decideRange = (range, installed, available) => {
|
|
35363
|
-
if (range === "latest") {
|
|
35364
|
-
const version = newest$1(available);
|
|
35365
|
-
if (version === void 0) return { kind: "unavailable" };
|
|
35366
|
-
return installed === version ? { kind: "leave" } : {
|
|
35367
|
-
kind: "install",
|
|
35368
|
-
version
|
|
35369
|
-
};
|
|
35370
|
-
}
|
|
35371
|
-
if (range === "*") {
|
|
35372
|
-
if (installed !== void 0) return { kind: "leave" };
|
|
35373
|
-
const version = newest$1(available);
|
|
35374
|
-
return version === void 0 ? { kind: "unavailable" } : {
|
|
35375
|
-
kind: "install",
|
|
35376
|
-
version
|
|
35377
|
-
};
|
|
35378
|
-
}
|
|
35379
|
-
if (installed !== void 0 && import_semver.satisfies(installed, range)) return { kind: "leave" };
|
|
35380
|
-
if (installed !== void 0 && import_semver.gtr(installed, range)) return {
|
|
35381
|
-
kind: "ask",
|
|
35382
|
-
installed
|
|
35383
|
-
};
|
|
35384
|
-
const version = import_semver.maxSatisfying([...available], range);
|
|
35385
|
-
return version === null ? { kind: "unavailable" } : {
|
|
35386
|
-
kind: "install",
|
|
35387
|
-
version
|
|
35388
|
-
};
|
|
35389
|
-
};
|
|
35390
|
-
//#endregion
|
|
35391
|
-
//#region ../../packages/core/src/record.ts
|
|
35392
|
-
const sameRecord = (a, b) => Object.keys(a).length === Object.keys(b).length && Object.entries(a).every(([k, v]) => b[k] === v);
|
|
35393
|
-
const decideInstall = (record, now, rebuild) => {
|
|
35394
|
-
if (rebuild) return {
|
|
35395
|
-
run: true,
|
|
35396
|
-
reason: "--rebuild"
|
|
35397
|
-
};
|
|
35398
|
-
if (record === void 0) return {
|
|
35399
|
-
run: true,
|
|
35400
|
-
reason: "never installed"
|
|
35401
|
-
};
|
|
35402
|
-
if (record.commit !== now.commit) return {
|
|
35403
|
-
run: true,
|
|
35404
|
-
reason: `new commit ${now.commit.slice(0, 7)}`
|
|
35405
|
-
};
|
|
35406
|
-
if (record.path !== now.path) return {
|
|
35407
|
-
run: true,
|
|
35408
|
-
reason: "clone moved"
|
|
35409
|
-
};
|
|
35410
|
-
if (record.install !== now.install) return {
|
|
35411
|
-
run: true,
|
|
35412
|
-
reason: "install command changed"
|
|
35413
|
-
};
|
|
35414
|
-
if (!sameRecord(record.files, now.files)) return {
|
|
35415
|
-
run: true,
|
|
35416
|
-
reason: "files changed"
|
|
35417
|
-
};
|
|
35418
|
-
for (const [path, fingerprint] of Object.entries(now.outputs)) if (fingerprint === void 0 || record.outputs[path] !== fingerprint) return {
|
|
35419
|
-
run: true,
|
|
35420
|
-
reason: `drift: ${path}`
|
|
35421
|
-
};
|
|
35422
|
-
return { run: false };
|
|
35423
|
-
};
|
|
35424
|
-
//#endregion
|
|
35425
|
-
//#region ../../packages/core/src/targeting.ts
|
|
35426
|
-
const targets = (targeting, machine) => (targeting.platforms?.includes(machine.platform) ?? true) && (targeting.machines?.includes(machine.name) ?? true);
|
|
35427
|
-
//#endregion
|
|
35428
|
-
//#region ../../packages/core/src/plan.ts
|
|
35429
|
-
const VP_PACKAGE = "vite-plus";
|
|
35430
|
-
const NODE_PACKAGE = "node";
|
|
35431
|
-
const expandHome = (path, home) => path === "~" ? home : path.startsWith("~/") ? `${home}${path.slice(1)}` : path;
|
|
35432
|
-
const isHomebrew = (path) => path !== void 0 && (path.includes("/homebrew/") || path.includes("/Cellar/"));
|
|
35433
|
-
const planVp = (input) => {
|
|
35434
|
-
const out = {
|
|
35435
|
-
steps: [],
|
|
35436
|
-
questions: [],
|
|
35437
|
-
skipped: [],
|
|
35438
|
-
failures: []
|
|
35439
|
-
};
|
|
35440
|
-
const { state, machine } = input;
|
|
35441
|
-
const vp = input.config.vp;
|
|
35442
|
-
const targeted = vp !== void 0 && targets(vp, machine);
|
|
35443
|
-
const missing = state.vp === void 0 || state.vp.version === null;
|
|
35444
|
-
if (missing) out.steps.push({ kind: "bootstrap" });
|
|
35445
|
-
const installed = missing ? void 0 : state.vp?.version ?? void 0;
|
|
35446
|
-
const decide = (pkg, range, current, shown = pkg) => {
|
|
35447
|
-
if (range === void 0) return void 0;
|
|
35448
|
-
const decision = decideRange(range, current, input.versions[pkg] ?? []);
|
|
35449
|
-
switch (decision.kind) {
|
|
35450
|
-
case "leave": return;
|
|
35451
|
-
case "install": return decision.version;
|
|
35452
|
-
case "unavailable":
|
|
35453
|
-
out.failures.push({
|
|
35454
|
-
what: shown,
|
|
35455
|
-
reason: `no published version satisfies ${range}`
|
|
35456
|
-
});
|
|
35457
|
-
return;
|
|
35458
|
-
case "ask": {
|
|
35459
|
-
const answer = input.answers[pkg];
|
|
35460
|
-
if (answer === "downgrade") {
|
|
35461
|
-
const target = decideRange(range, void 0, input.versions[pkg] ?? []);
|
|
35462
|
-
if (target.kind === "install") return target.version;
|
|
35463
|
-
out.failures.push({
|
|
35464
|
-
what: shown,
|
|
35465
|
-
reason: `no published version satisfies ${range}`
|
|
35466
|
-
});
|
|
35467
|
-
return;
|
|
35468
|
-
}
|
|
35469
|
-
if (answer === "skip") {
|
|
35470
|
-
out.skipped.push({
|
|
35471
|
-
what: shown,
|
|
35472
|
-
reason: `${decision.installed} is above ${range}`
|
|
35473
|
-
});
|
|
35474
|
-
return;
|
|
35475
|
-
}
|
|
35476
|
-
out.questions.push({
|
|
35477
|
-
machine: machine.name,
|
|
35478
|
-
package: pkg,
|
|
35479
|
-
installed: decision.installed,
|
|
35480
|
-
range
|
|
35481
|
-
});
|
|
35482
|
-
return;
|
|
35483
|
-
}
|
|
35484
|
-
}
|
|
35485
|
-
};
|
|
35486
|
-
const nodeNow = missing ? void 0 : state.node ?? void 0;
|
|
35487
|
-
let nodeTarget;
|
|
35488
|
-
if (targeted) {
|
|
35489
|
-
const vpTarget = decide(VP_PACKAGE, vp.version, installed, "vp");
|
|
35490
|
-
if (vpTarget !== void 0) {
|
|
35491
|
-
if (isHomebrew(state.vp?.path)) out.failures.push({
|
|
35492
|
-
what: "vp",
|
|
35493
|
-
reason: `vp ${installed} was installed with Homebrew; run brew upgrade vite-plus to get ${vpTarget}`
|
|
35494
|
-
});
|
|
35495
|
-
else out.steps.push({
|
|
35496
|
-
kind: "vp",
|
|
35497
|
-
from: installed ?? null,
|
|
35498
|
-
version: vpTarget
|
|
35499
|
-
});
|
|
35500
|
-
}
|
|
35501
|
-
nodeTarget = decide(NODE_PACKAGE, vp.node, nodeNow, "node");
|
|
35502
|
-
if (nodeTarget !== void 0) out.steps.push({
|
|
35503
|
-
kind: "node",
|
|
35504
|
-
from: nodeNow ?? null,
|
|
35505
|
-
version: nodeTarget
|
|
35506
|
-
});
|
|
35507
|
-
}
|
|
35508
|
-
const nodeDefault = nodeTarget ?? nodeNow;
|
|
35509
|
-
const byName = new Map((missing ? [] : state.globals).map((g) => [g.name, g]));
|
|
35510
|
-
const installs = [];
|
|
35511
|
-
const wanted = Object.entries(targeted ? vp.globals ?? {} : {});
|
|
35512
|
-
for (const [name, range] of [...wanted, [SELF_PACKAGE, input.self]]) {
|
|
35513
|
-
const current = byName.get(name);
|
|
35514
|
-
const version = name === "fleetfizz" ? decideSelf(current?.version, input.self, out) : decide(name, range, current?.version);
|
|
35515
|
-
if (version !== void 0) installs.push(current === void 0 ? {
|
|
35516
|
-
name,
|
|
35517
|
-
version
|
|
35518
|
-
} : {
|
|
35519
|
-
name,
|
|
35520
|
-
from: current.version,
|
|
35521
|
-
version
|
|
35522
|
-
});
|
|
35523
|
-
else if (current !== void 0 && nodeDefault !== void 0 && current.platform?.node !== void 0 && current.platform.node !== nodeDefault) out.steps.push({
|
|
35524
|
-
kind: "reinstall",
|
|
35525
|
-
name,
|
|
35526
|
-
version: current.version
|
|
35527
|
-
});
|
|
35528
|
-
}
|
|
35529
|
-
if (installs.length > 0) out.steps.push({
|
|
35530
|
-
kind: "globals",
|
|
35531
|
-
packages: installs
|
|
35532
|
-
});
|
|
35533
|
-
return out;
|
|
35534
|
-
};
|
|
35535
|
-
const decideSelf = (installed, self, out) => {
|
|
35536
|
-
if (installed === void 0 || import_semver.lt(installed, self)) return self;
|
|
35537
|
-
if (import_semver.gt(installed, self)) out.failures.push({
|
|
35538
|
-
what: SELF_PACKAGE,
|
|
35539
|
-
reason: `runs ${SELF_PACKAGE} ${installed}, newer than this ${self}; upgrade here first`
|
|
35540
|
-
});
|
|
35541
|
-
};
|
|
35542
|
-
const planRepos = (input) => {
|
|
35543
|
-
const repos = [];
|
|
35544
|
-
const failures = [];
|
|
35545
|
-
const { config, machine, state } = input;
|
|
35546
|
-
const home = state.home ?? "~";
|
|
35547
|
-
const root = config.machines?.[machine.name]?.clones ?? "~/.local/share/fleetfizz/clones";
|
|
35548
|
-
for (const repo of config.repos ?? []) {
|
|
35549
|
-
if (!targets(repo, machine)) continue;
|
|
35550
|
-
const name = repoName(repo);
|
|
35551
|
-
if (state.cloneRoot !== void 0 && !state.cloneRoot.present && !root.startsWith("~")) {
|
|
35552
|
-
failures.push({
|
|
35553
|
-
what: name,
|
|
35554
|
-
reason: `clone root not mounted: ${state.cloneRoot.path}`
|
|
35555
|
-
});
|
|
35556
|
-
continue;
|
|
35557
|
-
}
|
|
35558
|
-
const current = state.repos[name];
|
|
35559
|
-
const expectedOrigin = `https://github.com/${repo.origin}.git`;
|
|
35560
|
-
if (current?.present && current.origin !== void 0 && current.origin !== expectedOrigin) {
|
|
35561
|
-
failures.push({
|
|
35562
|
-
what: name,
|
|
35563
|
-
reason: `managed clone has origin ${current.origin}, expected ${expectedOrigin}`
|
|
35564
|
-
});
|
|
35565
|
-
continue;
|
|
35566
|
-
}
|
|
35567
|
-
const path = `${root}/${name}`;
|
|
35568
|
-
const expanded = expandHome(path, home);
|
|
35569
|
-
const files = repo.files ?? {};
|
|
35570
|
-
const outputs = repo.outputs ?? [];
|
|
35571
|
-
const rebuild = input.rebuild === "all" || input.rebuild !== "none" && input.rebuild.includes(name);
|
|
35572
|
-
const decision = decideInstall(state.records[name], {
|
|
35573
|
-
commit: current?.head ?? "",
|
|
35574
|
-
path: expanded,
|
|
35575
|
-
install: repo.install,
|
|
35576
|
-
files,
|
|
35577
|
-
outputs: Object.fromEntries(outputs.map((o) => [o, state.outputs[name]?.[o] ?? void 0]))
|
|
35578
|
-
}, rebuild);
|
|
35579
|
-
repos.push({
|
|
35580
|
-
name,
|
|
35581
|
-
origin: repo.origin,
|
|
35582
|
-
ref: repo.ref,
|
|
35583
|
-
pin: isPin(repo.ref),
|
|
35584
|
-
path,
|
|
35585
|
-
expanded,
|
|
35586
|
-
...current?.head === void 0 ? {} : { head: current.head },
|
|
35587
|
-
install: repo.install,
|
|
35588
|
-
files,
|
|
35589
|
-
outputs,
|
|
35590
|
-
decision
|
|
35591
|
-
});
|
|
35592
|
-
}
|
|
35593
|
-
return {
|
|
35594
|
-
repos,
|
|
35595
|
-
failures
|
|
35596
|
-
};
|
|
35597
|
-
};
|
|
35598
|
-
const plan = (input) => {
|
|
35599
|
-
const vp = planVp(input);
|
|
35600
|
-
const repos = planRepos(input);
|
|
35601
|
-
return {
|
|
35602
|
-
machine: input.machine,
|
|
35603
|
-
vp: vp.steps,
|
|
35604
|
-
repos: repos.repos,
|
|
35605
|
-
questions: vp.questions,
|
|
35606
|
-
skipped: vp.skipped,
|
|
35607
|
-
failures: [...vp.failures.map((f) => ({
|
|
35608
|
-
...f,
|
|
35609
|
-
section: "vp"
|
|
35610
|
-
})), ...repos.failures.map((f) => ({
|
|
35611
|
-
...f,
|
|
35612
|
-
section: "repos"
|
|
35613
|
-
}))]
|
|
35614
|
-
};
|
|
35615
|
-
};
|
|
35616
|
-
//#endregion
|
|
35617
|
-
//#region ../../packages/core/src/state.ts
|
|
35618
|
-
const GlobalEntry = Struct({
|
|
35619
|
-
name: String$5,
|
|
35620
|
-
version: String$5,
|
|
35621
|
-
platform: optionalKey(Struct({ node: optionalKey(String$5) }))
|
|
35622
|
-
});
|
|
35623
|
-
const InstallRecordSchema = Struct({
|
|
35624
|
-
commit: String$5,
|
|
35625
|
-
path: String$5,
|
|
35626
|
-
install: String$5,
|
|
35627
|
-
files: Record(String$5, String$5),
|
|
35628
|
-
outputs: Record(String$5, String$5)
|
|
35629
|
-
});
|
|
35630
|
-
const Fact = Union([
|
|
35631
|
-
Struct({
|
|
35632
|
-
fact: Literal("home"),
|
|
35633
|
-
path: String$5
|
|
35634
|
-
}),
|
|
35635
|
-
Struct({ fact: Literal("end") }),
|
|
35636
|
-
Struct({
|
|
35637
|
-
fact: Literal("vp"),
|
|
35638
|
-
version: NullOr(String$5),
|
|
35639
|
-
path: optionalKey(String$5)
|
|
35640
|
-
}),
|
|
35641
|
-
Struct({
|
|
35642
|
-
fact: Literal("node"),
|
|
35643
|
-
version: NullOr(String$5)
|
|
35644
|
-
}),
|
|
35645
|
-
Struct({
|
|
35646
|
-
fact: Literal("globals"),
|
|
35647
|
-
list: ArraySchema(GlobalEntry)
|
|
35648
|
-
}),
|
|
35649
|
-
Struct({
|
|
35650
|
-
fact: Literal("cloneRoot"),
|
|
35651
|
-
path: String$5,
|
|
35652
|
-
present: Boolean$4
|
|
35653
|
-
}),
|
|
35654
|
-
Struct({
|
|
35655
|
-
fact: Literal("repo"),
|
|
35656
|
-
name: String$5,
|
|
35657
|
-
present: Boolean$4,
|
|
35658
|
-
head: optionalKey(String$5),
|
|
35659
|
-
origin: optionalKey(String$5)
|
|
35660
|
-
}),
|
|
35661
|
-
Struct({
|
|
35662
|
-
fact: Literal("record"),
|
|
35663
|
-
name: String$5,
|
|
35664
|
-
record: InstallRecordSchema
|
|
35665
|
-
}),
|
|
35666
|
-
Struct({
|
|
35667
|
-
fact: Literal("config"),
|
|
35668
|
-
present: Boolean$4,
|
|
35669
|
-
base64: optionalKey(String$5)
|
|
35670
|
-
}),
|
|
35671
|
-
Struct({
|
|
35672
|
-
fact: Literal("output"),
|
|
35673
|
-
repo: String$5,
|
|
35674
|
-
path: String$5,
|
|
35675
|
-
fingerprint: NullOr(String$5)
|
|
35676
|
-
})
|
|
35677
|
-
]);
|
|
35678
|
-
const emptyState = {
|
|
35679
|
-
complete: false,
|
|
35680
|
-
globals: [],
|
|
35681
|
-
repos: {},
|
|
35682
|
-
records: {},
|
|
35683
|
-
outputs: {}
|
|
35684
|
-
};
|
|
35685
|
-
const decodeBase64 = (base64) => new TextDecoder().decode(Uint8Array.from(atob(base64), (c) => c.charCodeAt(0)));
|
|
35686
|
-
const assembleState = (facts) => {
|
|
35687
|
-
let state = emptyState;
|
|
35688
|
-
for (const fact of facts) switch (fact.fact) {
|
|
35689
|
-
case "home":
|
|
35690
|
-
state = {
|
|
35691
|
-
...state,
|
|
35692
|
-
home: fact.path
|
|
35693
|
-
};
|
|
35694
|
-
break;
|
|
35695
|
-
case "end":
|
|
35696
|
-
state = {
|
|
35697
|
-
...state,
|
|
35698
|
-
complete: true
|
|
35699
|
-
};
|
|
35700
|
-
break;
|
|
35701
|
-
case "vp":
|
|
35702
|
-
state = {
|
|
35703
|
-
...state,
|
|
35704
|
-
vp: fact.path === void 0 ? { version: fact.version } : {
|
|
35705
|
-
version: fact.version,
|
|
35706
|
-
path: fact.path
|
|
35707
|
-
}
|
|
35708
|
-
};
|
|
35709
|
-
break;
|
|
35710
|
-
case "node":
|
|
35711
|
-
state = {
|
|
35712
|
-
...state,
|
|
35713
|
-
node: fact.version
|
|
35714
|
-
};
|
|
35715
|
-
break;
|
|
35716
|
-
case "globals":
|
|
35717
|
-
state = {
|
|
35718
|
-
...state,
|
|
35719
|
-
globals: fact.list
|
|
35720
|
-
};
|
|
35721
|
-
break;
|
|
35722
|
-
case "cloneRoot":
|
|
35723
|
-
state = {
|
|
35724
|
-
...state,
|
|
35725
|
-
cloneRoot: {
|
|
35726
|
-
path: fact.path,
|
|
35727
|
-
present: fact.present
|
|
35728
|
-
}
|
|
35729
|
-
};
|
|
35730
|
-
break;
|
|
35731
|
-
case "repo": {
|
|
35732
|
-
const repo = {
|
|
35733
|
-
present: fact.present,
|
|
35734
|
-
...fact.head === void 0 ? {} : { head: fact.head },
|
|
35735
|
-
...fact.origin === void 0 ? {} : { origin: fact.origin }
|
|
35736
|
-
};
|
|
35737
|
-
state = {
|
|
35738
|
-
...state,
|
|
35739
|
-
repos: {
|
|
35740
|
-
...state.repos,
|
|
35741
|
-
[fact.name]: repo
|
|
35742
|
-
}
|
|
35743
|
-
};
|
|
35744
|
-
break;
|
|
35745
|
-
}
|
|
35746
|
-
case "record":
|
|
35747
|
-
state = {
|
|
35748
|
-
...state,
|
|
35749
|
-
records: {
|
|
35750
|
-
...state.records,
|
|
35751
|
-
[fact.name]: fact.record
|
|
35752
|
-
}
|
|
35753
|
-
};
|
|
35754
|
-
break;
|
|
35755
|
-
case "config":
|
|
35756
|
-
if (fact.present && fact.base64 !== void 0) state = {
|
|
35757
|
-
...state,
|
|
35758
|
-
config: decodeBase64(fact.base64)
|
|
35759
|
-
};
|
|
35760
|
-
break;
|
|
35761
|
-
case "output": state = {
|
|
35762
|
-
...state,
|
|
35763
|
-
outputs: {
|
|
35764
|
-
...state.outputs,
|
|
35765
|
-
[fact.repo]: {
|
|
35766
|
-
...state.outputs[fact.repo],
|
|
35767
|
-
[fact.path]: fact.fingerprint
|
|
35768
|
-
}
|
|
35769
|
-
}
|
|
35770
|
-
};
|
|
35771
|
-
}
|
|
35772
|
-
return state;
|
|
35773
|
-
};
|
|
35774
|
-
//#endregion
|
|
35775
35624
|
//#region ../../packages/remote/src/protocol.ts
|
|
35625
|
+
const Fact = Record(String$5, Unknown);
|
|
35776
35626
|
const StepStart = Struct({ id: String$5 });
|
|
35777
35627
|
const StepDone = Struct({
|
|
35778
35628
|
id: String$5,
|
|
35779
35629
|
ok: Boolean$4,
|
|
35780
35630
|
code: optionalKey(Number$2)
|
|
35781
35631
|
});
|
|
35782
|
-
const
|
|
35632
|
+
const StepSkip = Struct({
|
|
35633
|
+
id: String$5,
|
|
35634
|
+
reason: String$5
|
|
35635
|
+
});
|
|
35636
|
+
const decodeFact$3 = decodeUnknownResult(fromJsonString(Fact));
|
|
35783
35637
|
const decodeStart = decodeUnknownResult(fromJsonString(StepStart));
|
|
35784
35638
|
const decodeDone = decodeUnknownResult(fromJsonString(StepDone));
|
|
35639
|
+
const decodeSkip = decodeUnknownResult(fromJsonString(StepSkip));
|
|
35785
35640
|
const STATE = "ff-state ";
|
|
35786
35641
|
const STEP = "ff-step ";
|
|
35787
35642
|
const DONE = "ff-done ";
|
|
35643
|
+
const SKIP = "ff-skip ";
|
|
35788
35644
|
const parseLine = (line) => {
|
|
35789
35645
|
if (line.startsWith(STATE)) {
|
|
35790
|
-
const result = decodeFact(line.slice(9));
|
|
35646
|
+
const result = decodeFact$3(line.slice(9));
|
|
35791
35647
|
if (result._tag === "Success") return {
|
|
35792
35648
|
kind: "state",
|
|
35793
35649
|
fact: result.success
|
|
@@ -35804,6 +35660,12 @@ const parseLine = (line) => {
|
|
|
35804
35660
|
kind: "done",
|
|
35805
35661
|
done: result.success
|
|
35806
35662
|
};
|
|
35663
|
+
} else if (line.startsWith(SKIP)) {
|
|
35664
|
+
const result = decodeSkip(line.slice(8));
|
|
35665
|
+
if (result._tag === "Success") return {
|
|
35666
|
+
kind: "skip",
|
|
35667
|
+
skip: result.success
|
|
35668
|
+
};
|
|
35807
35669
|
}
|
|
35808
35670
|
return {
|
|
35809
35671
|
kind: "text",
|
|
@@ -35812,95 +35674,48 @@ const parseLine = (line) => {
|
|
|
35812
35674
|
};
|
|
35813
35675
|
const stepLine = (id) => `printf 'ff-step {"id":"%s"}\\n' '${id}'`;
|
|
35814
35676
|
const doneLine = (id, ok, code) => code === void 0 ? `printf 'ff-done {"id":"%s","ok":${ok}}\\n' '${id}'` : `printf 'ff-done {"id":"%s","ok":${ok},"code":%s}\\n' '${id}' "${code}"`;
|
|
35677
|
+
const skipLine = (id, reason) => `printf 'ff-skip {"id":"%s","reason":"%s"}\\n' '${id}' ${reason}`;
|
|
35815
35678
|
//#endregion
|
|
35816
35679
|
//#region ../../packages/remote/src/apply.ts
|
|
35817
|
-
const jsonString = encodeSync(fromJsonString(String$5));
|
|
35818
|
-
const jsonRecord = encodeSync(fromJsonString(Record(String$5, String$5)));
|
|
35819
|
-
const stepId = (repo, step) => `repo:${repo}:${step}`;
|
|
35820
|
-
const isFetchStep = (id) => id.startsWith("repo:") && id.endsWith(":fetch");
|
|
35821
|
-
const vpStepId = (step) => step.kind === "reinstall" ? `vp:reinstall:${step.name}` : step.kind === "globals" ? "vp:globals" : `vp:${step.kind}`;
|
|
35822
35680
|
const CONFIG_STEP = "config";
|
|
35823
|
-
const
|
|
35824
|
-
"curl -fsSL https://vite.plus | bash",
|
|
35825
|
-
...vpEnv.split("\n"),
|
|
35826
|
-
"{ hash -r 2>/dev/null || true; }"
|
|
35827
|
-
].join(" && ");
|
|
35828
|
-
const marked = (id, run, then = []) => [
|
|
35681
|
+
const marked = (id, run, failed = []) => [
|
|
35829
35682
|
stepLine(id),
|
|
35830
35683
|
...run,
|
|
35831
35684
|
`ff_code=$?`,
|
|
35832
|
-
`if [ "$ff_code" -ne 0 ]; then
|
|
35685
|
+
`if [ "$ff_code" -ne 0 ]; then`,
|
|
35686
|
+
doneLine(id, false, "$ff_code"),
|
|
35687
|
+
...failed,
|
|
35688
|
+
"else",
|
|
35833
35689
|
doneLine(id, true),
|
|
35834
|
-
...then,
|
|
35835
35690
|
"fi"
|
|
35836
35691
|
];
|
|
35837
|
-
const vpStep = (step) => {
|
|
35838
|
-
const id = vpStepId(step);
|
|
35839
|
-
const command = (() => {
|
|
35840
|
-
switch (step.kind) {
|
|
35841
|
-
case "bootstrap": return VP_INSTALL;
|
|
35842
|
-
case "vp": return `command vp upgrade ${quote(step.version)}`;
|
|
35843
|
-
case "node": return `command vp env default ${quote(step.version)}`;
|
|
35844
|
-
case "reinstall": return `command vp install -g ${quote(`${step.name}@${step.version}`)}`;
|
|
35845
|
-
case "globals": return `command vp install -g ${step.packages.map((p) => quote(`${p.name}@${p.version}`)).join(" ")}`;
|
|
35846
|
-
}
|
|
35847
|
-
})();
|
|
35848
|
-
return marked(id, [step.kind === "bootstrap" ? command : `( ${command} )`]);
|
|
35849
|
-
};
|
|
35850
35692
|
const configStep = () => {
|
|
35851
35693
|
const dir = CONFIG_DIR_SH;
|
|
35852
35694
|
const write = (variable, file) => `printf '%s' "$${variable}" | base64 -d > ${dir}/${quote(`${file}.tmp`)} && mv -f ${dir}/${quote(`${file}.tmp`)} ${dir}/${quote(file)}`;
|
|
35853
35695
|
return marked(CONFIG_STEP, [`( mkdir -p ${dir} && ${write("ff_config", CONFIG_FILE)} && ${write("ff_schema", SCHEMA_FILE)} )`]);
|
|
35854
35696
|
};
|
|
35855
|
-
const
|
|
35856
|
-
return [
|
|
35857
|
-
|
|
35858
|
-
|
|
35859
|
-
|
|
35860
|
-
|
|
35861
|
-
`
|
|
35697
|
+
const providerSteps = (plan) => {
|
|
35698
|
+
if (plan.decisions.length === 0 && plan.steps.length === 0) return [];
|
|
35699
|
+
const held = `ff_held_${plan.name}`;
|
|
35700
|
+
const items = [...new Set(plan.steps.flatMap((step) => step.items))];
|
|
35701
|
+
const flag = (item) => `ff_f_${plan.name}_${items.indexOf(item)}`;
|
|
35702
|
+
const step = (s) => [
|
|
35703
|
+
`if [ -n "${s.items.map((item) => `\${${flag(item)}:-}`).join("")}" ]; then`,
|
|
35704
|
+
skipLine(s.id, "'an earlier step failed'"),
|
|
35705
|
+
"else",
|
|
35706
|
+
...marked(s.id, s.run, [...s.items.map((item) => `${flag(item)}=1`), `${held}=1`]),
|
|
35707
|
+
"fi"
|
|
35862
35708
|
];
|
|
35863
|
-
};
|
|
35864
|
-
|
|
35865
|
-
const repoSteps = (repo, input) => {
|
|
35866
|
-
const fetch = stepId(repo.name, "fetch");
|
|
35867
|
-
const install = stepId(repo.name, "install");
|
|
35868
|
-
const url = `https://github.com/${repo.origin}.git`;
|
|
35869
|
-
const sync = repo.pin ? [
|
|
35870
|
-
`if [ "$(git -C "$ff_d" rev-parse HEAD)" != ${quote(repo.ref)} ]; then ff_git -C "$ff_d" fetch --quiet origin ${quote(repo.ref)}; fi`,
|
|
35871
|
-
`git -C "$ff_d" checkout --quiet --detach ${quote(repo.ref)}`,
|
|
35872
|
-
`git -C "$ff_d" reset --quiet --hard ${quote(repo.ref)}`
|
|
35873
|
-
] : [`ff_git -C "$ff_d" fetch --quiet origin ${quote(repo.ref)}`, `git -C "$ff_d" reset --quiet --hard ${quote(`origin/${repo.ref}`)}`];
|
|
35874
|
-
const envPrefix = `FLEETFIZZ_MACHINE=${quote(input.env.machine)} FLEETFIZZ_PLATFORM=${quote(input.env.platform)} FLEETFIZZ_MACHINES=${quote(input.env.machines.join(","))}`;
|
|
35709
|
+
const why = [`ff_why=""`, ...plan.dependsOn.map((dep) => `if [ -z "$ff_why" ] && [ -n "\${ff_held_${dep}:-}" ]; then ff_why=${quote(dep)}; fi`)];
|
|
35710
|
+
if (plan.steps.length === 0) return [...why, `if [ -n "$ff_why" ]; then ${held}=1; fi`];
|
|
35875
35711
|
return [
|
|
35876
|
-
|
|
35877
|
-
`
|
|
35878
|
-
|
|
35879
|
-
|
|
35880
|
-
|
|
35881
|
-
|
|
35882
|
-
|
|
35883
|
-
...sync.map((l) => ` ${l}`),
|
|
35884
|
-
` git -C "$ff_d" clean --quiet -fd`,
|
|
35885
|
-
...writeFiles(repo).map((l) => ` ${l}`),
|
|
35886
|
-
")"
|
|
35887
|
-
], [
|
|
35888
|
-
`ff_after=$(git -C "$ff_d" rev-parse HEAD)`,
|
|
35889
|
-
`ff_state "{\\"fact\\":\\"repo\\",\\"name\\":\\"$(ff_json ${quote(repo.name)})\\",\\"present\\":true,\\"head\\":\\"$(ff_json "$ff_after")\\"}"`,
|
|
35890
|
-
`if [ ${repo.decision.run ? "true" : "false"} = true ] || [ "$ff_after" != "$ff_before" ]; then`,
|
|
35891
|
-
` ${stepLine(install)}`,
|
|
35892
|
-
` (cd "$ff_d" && ${envPrefix} "\${SHELL:-/bin/sh}" -lc ${quote(repo.install)})`,
|
|
35893
|
-
` ff_code=$?`,
|
|
35894
|
-
` if [ "$ff_code" -ne 0 ]; then ${doneLine(install, false, "$ff_code")}; else`,
|
|
35895
|
-
" (",
|
|
35896
|
-
" set -e",
|
|
35897
|
-
...writeRecord(repo).map((l) => ` ${l}`),
|
|
35898
|
-
" )",
|
|
35899
|
-
` ff_code=$?`,
|
|
35900
|
-
` if [ "$ff_code" -ne 0 ]; then echo "could not write the install record"; ${doneLine(install, false, "$ff_code")}; else ${doneLine(install, true)}; fi`,
|
|
35901
|
-
" fi",
|
|
35902
|
-
"fi"
|
|
35903
|
-
])
|
|
35712
|
+
...why,
|
|
35713
|
+
`if [ -n "$ff_why" ]; then`,
|
|
35714
|
+
`${held}=1`,
|
|
35715
|
+
...plan.steps.map((s) => skipLine(s.id, `"depends on $ff_why"`)),
|
|
35716
|
+
"else",
|
|
35717
|
+
...plan.steps.flatMap(step),
|
|
35718
|
+
"fi"
|
|
35904
35719
|
];
|
|
35905
35720
|
};
|
|
35906
35721
|
const applyStdin = (token, config, schema) => [
|
|
@@ -35914,24 +35729,18 @@ const encodeBase64 = (text) => {
|
|
|
35914
35729
|
for (const byte of bytes) binary += String.fromCharCode(byte);
|
|
35915
35730
|
return btoa(binary);
|
|
35916
35731
|
};
|
|
35917
|
-
const applyScript = (
|
|
35918
|
-
|
|
35919
|
-
|
|
35920
|
-
|
|
35921
|
-
|
|
35922
|
-
|
|
35923
|
-
|
|
35924
|
-
|
|
35925
|
-
|
|
35926
|
-
|
|
35927
|
-
|
|
35928
|
-
|
|
35929
|
-
lines.push(...configStep());
|
|
35930
|
-
for (const step of input.plan.vp) lines.push(...vpStep(step));
|
|
35931
|
-
for (const repo of input.plan.repos) lines.push(...repoSteps(repo, input));
|
|
35932
|
-
lines.push(doneLine("end", true));
|
|
35933
|
-
return lines.join("\n");
|
|
35934
|
-
};
|
|
35732
|
+
const applyScript = (plan) => [
|
|
35733
|
+
prelude,
|
|
35734
|
+
fingerprintFn,
|
|
35735
|
+
`ff_lit() { printf '%s' "$1"; }`,
|
|
35736
|
+
`IFS= read -r ff_token || ff_token=""`,
|
|
35737
|
+
`IFS= read -r ff_config || ff_config=""`,
|
|
35738
|
+
`IFS= read -r ff_schema || ff_schema=""`,
|
|
35739
|
+
`ff_git() { if [ -n "$ff_token" ]; then FF_TOKEN="$ff_token" git -c credential.helper= -c 'credential.helper=!f() { echo username=x-access-token; echo "password=$FF_TOKEN"; }; f' "$@"; else git "$@"; fi; }`,
|
|
35740
|
+
...configStep(),
|
|
35741
|
+
...plan.providers.flatMap(providerSteps),
|
|
35742
|
+
doneLine("end", true)
|
|
35743
|
+
].join("\n");
|
|
35935
35744
|
//#endregion
|
|
35936
35745
|
//#region ../../packages/remote/src/tailnet.ts
|
|
35937
35746
|
const StatusNode = Struct({
|
|
@@ -64199,6 +64008,355 @@ const useWindowSize = () => {
|
|
|
64199
64008
|
return size;
|
|
64200
64009
|
};
|
|
64201
64010
|
//#endregion
|
|
64011
|
+
//#region ../../packages/core/src/targeting.ts
|
|
64012
|
+
const targets = (targeting, machine) => (targeting.platforms?.includes(machine.platform) ?? true) && (targeting.machines?.includes(machine.name) ?? true);
|
|
64013
|
+
const isVariantList = (entry) => Array.isArray(entry);
|
|
64014
|
+
const variantFor = (entry, machine) => {
|
|
64015
|
+
if (!isVariantList(entry)) return targets(entry, machine) ? { variant: entry } : void 0;
|
|
64016
|
+
const index = entry.findIndex((variant) => targets(variant, machine));
|
|
64017
|
+
const variant = entry[index];
|
|
64018
|
+
return variant === void 0 ? void 0 : {
|
|
64019
|
+
variant,
|
|
64020
|
+
index
|
|
64021
|
+
};
|
|
64022
|
+
};
|
|
64023
|
+
//#endregion
|
|
64024
|
+
//#region ../../packages/core/src/engine.ts
|
|
64025
|
+
const dependenciesOf = (provider, config) => [.../* @__PURE__ */ new Set([...provider.dependsOn, ...config[provider.name]?.dependsOn ?? []])];
|
|
64026
|
+
const withoutTargeting = ({ platforms: _platforms, machines: _machines, ...def }) => def;
|
|
64027
|
+
const targetedItems = (provider, config, machine) => {
|
|
64028
|
+
const section = config[provider.name];
|
|
64029
|
+
if (section === void 0 || !targets(section, machine)) return provider.items(void 0, []);
|
|
64030
|
+
const listed = Object.entries(section.items ?? {}).flatMap(([name, entry]) => {
|
|
64031
|
+
const chosen = variantFor(entry, machine);
|
|
64032
|
+
if (chosen === void 0) return [];
|
|
64033
|
+
const at = chosen.index === void 0 ? [] : [chosen.index];
|
|
64034
|
+
return [{
|
|
64035
|
+
name,
|
|
64036
|
+
def: withoutTargeting(chosen.variant),
|
|
64037
|
+
path: [
|
|
64038
|
+
provider.name,
|
|
64039
|
+
"items",
|
|
64040
|
+
name,
|
|
64041
|
+
...at
|
|
64042
|
+
]
|
|
64043
|
+
}];
|
|
64044
|
+
});
|
|
64045
|
+
return provider.items(section, listed);
|
|
64046
|
+
};
|
|
64047
|
+
const machineNames = (value) => {
|
|
64048
|
+
if (Array.isArray(value)) return value.flatMap(machineNames);
|
|
64049
|
+
if (typeof value !== "object" || value === null) return [];
|
|
64050
|
+
return Object.entries(value).flatMap(([key, v]) => key === "machines" && Array.isArray(v) && v.every((name) => typeof name === "string") ? v : machineNames(v));
|
|
64051
|
+
};
|
|
64052
|
+
const machinesNamed = (provider, config) => machineNames(config[provider.name]);
|
|
64053
|
+
const hold = (decisions, by) => decisions.map((d) => d.kind === "change" || d.kind === "ask" ? {
|
|
64054
|
+
kind: "skip",
|
|
64055
|
+
item: d.item,
|
|
64056
|
+
...d.kind === "change" && d.from !== void 0 ? { at: d.from } : {},
|
|
64057
|
+
...d.kind === "ask" && d.at !== void 0 ? { at: d.at } : {},
|
|
64058
|
+
reason: `depends on ${by}`
|
|
64059
|
+
} : d);
|
|
64060
|
+
const planMachine = (input) => {
|
|
64061
|
+
const ctx = {
|
|
64062
|
+
...input.ctx,
|
|
64063
|
+
home: input.state.home ?? "~"
|
|
64064
|
+
};
|
|
64065
|
+
const plans = /* @__PURE__ */ new Map();
|
|
64066
|
+
const held = /* @__PURE__ */ new Set();
|
|
64067
|
+
for (const provider of input.providers) {
|
|
64068
|
+
const dependsOn = dependenciesOf(provider, ctx.config);
|
|
64069
|
+
const items = targetedItems(provider, ctx.config, ctx.machine);
|
|
64070
|
+
const decisions = provider.decide({
|
|
64071
|
+
items,
|
|
64072
|
+
observed: provider.parse(input.state.facts[provider.name] ?? [], input.state.records[provider.name] ?? {}),
|
|
64073
|
+
resolved: input.resolved[provider.name],
|
|
64074
|
+
ctx
|
|
64075
|
+
});
|
|
64076
|
+
const by = dependsOn.find((name) => {
|
|
64077
|
+
const dep = plans.get(name);
|
|
64078
|
+
return dep !== void 0 && dep.decisions.length > 0 && (held.has(name) || dep.decisions.some((d) => d.kind === "fail"));
|
|
64079
|
+
});
|
|
64080
|
+
if (by !== void 0) held.add(provider.name);
|
|
64081
|
+
plans.set(provider.name, {
|
|
64082
|
+
name: provider.name,
|
|
64083
|
+
rule: provider.rule,
|
|
64084
|
+
dependsOn,
|
|
64085
|
+
decisions: by === void 0 ? decisions : hold(decisions, by),
|
|
64086
|
+
steps: by === void 0 ? provider.act(decisions, ctx) : []
|
|
64087
|
+
});
|
|
64088
|
+
}
|
|
64089
|
+
return {
|
|
64090
|
+
machine: ctx.machine,
|
|
64091
|
+
providers: [...plans.values()]
|
|
64092
|
+
};
|
|
64093
|
+
};
|
|
64094
|
+
//#endregion
|
|
64095
|
+
//#region ../../packages/core/src/range.ts
|
|
64096
|
+
const newest = (available) => available.filter((v) => import_semver.prerelease(v) === null).sort(import_semver.rcompare)[0];
|
|
64097
|
+
const decideRange = (range, installed, available) => {
|
|
64098
|
+
if (range === "latest") {
|
|
64099
|
+
const version = newest(available);
|
|
64100
|
+
if (version === void 0) return { kind: "unavailable" };
|
|
64101
|
+
return installed === version ? { kind: "leave" } : {
|
|
64102
|
+
kind: "install",
|
|
64103
|
+
version
|
|
64104
|
+
};
|
|
64105
|
+
}
|
|
64106
|
+
if (range === "*") {
|
|
64107
|
+
if (installed !== void 0) return { kind: "leave" };
|
|
64108
|
+
const version = newest(available);
|
|
64109
|
+
return version === void 0 ? { kind: "unavailable" } : {
|
|
64110
|
+
kind: "install",
|
|
64111
|
+
version
|
|
64112
|
+
};
|
|
64113
|
+
}
|
|
64114
|
+
if (installed !== void 0 && import_semver.satisfies(installed, range)) return { kind: "leave" };
|
|
64115
|
+
if (installed !== void 0 && import_semver.gtr(installed, range)) return {
|
|
64116
|
+
kind: "ask",
|
|
64117
|
+
installed
|
|
64118
|
+
};
|
|
64119
|
+
const version = import_semver.maxSatisfying([...available], range);
|
|
64120
|
+
return version === null ? { kind: "unavailable" } : {
|
|
64121
|
+
kind: "install",
|
|
64122
|
+
version
|
|
64123
|
+
};
|
|
64124
|
+
};
|
|
64125
|
+
//#endregion
|
|
64126
|
+
//#region ../../packages/core/src/provider.ts
|
|
64127
|
+
const address = (provider, item) => `${provider}:${item}`;
|
|
64128
|
+
const parseAddress = (text) => {
|
|
64129
|
+
const at = text.indexOf(":");
|
|
64130
|
+
return at <= 0 || at === text.length - 1 ? void 0 : {
|
|
64131
|
+
provider: text.slice(0, at),
|
|
64132
|
+
item: text.slice(at + 1)
|
|
64133
|
+
};
|
|
64134
|
+
};
|
|
64135
|
+
const QUESTION_CHOICES = {
|
|
64136
|
+
range: [
|
|
64137
|
+
"bump",
|
|
64138
|
+
"skip",
|
|
64139
|
+
"downgrade"
|
|
64140
|
+
],
|
|
64141
|
+
config: ["overwrite", "stop"],
|
|
64142
|
+
mode: ["managed", "skip"]
|
|
64143
|
+
};
|
|
64144
|
+
const isQuestionKind = (kind) => kind in QUESTION_CHOICES;
|
|
64145
|
+
const rangeQuestion = (subject, installed, range, bumpPath) => ({
|
|
64146
|
+
kind: "range",
|
|
64147
|
+
subject,
|
|
64148
|
+
found: installed,
|
|
64149
|
+
problem: `is above ${range}`,
|
|
64150
|
+
choices: [
|
|
64151
|
+
{
|
|
64152
|
+
value: "bump",
|
|
64153
|
+
title: "bump the config"
|
|
64154
|
+
},
|
|
64155
|
+
{
|
|
64156
|
+
value: "skip",
|
|
64157
|
+
title: "skip on these Machines (leave as is, shown as skipped)"
|
|
64158
|
+
},
|
|
64159
|
+
{
|
|
64160
|
+
value: "downgrade",
|
|
64161
|
+
title: "downgrade into the range"
|
|
64162
|
+
}
|
|
64163
|
+
],
|
|
64164
|
+
default: "skip",
|
|
64165
|
+
bump: {
|
|
64166
|
+
path: bumpPath,
|
|
64167
|
+
range
|
|
64168
|
+
}
|
|
64169
|
+
});
|
|
64170
|
+
const decideRangeItem = (input) => {
|
|
64171
|
+
const { item, range, installed, available } = input;
|
|
64172
|
+
const at = installed === void 0 ? {} : { at: installed };
|
|
64173
|
+
const unavailable = {
|
|
64174
|
+
kind: "fail",
|
|
64175
|
+
item,
|
|
64176
|
+
...at,
|
|
64177
|
+
reason: `no published version satisfies ${range}`
|
|
64178
|
+
};
|
|
64179
|
+
const install = (version) => ({
|
|
64180
|
+
kind: "change",
|
|
64181
|
+
item,
|
|
64182
|
+
...installed === void 0 ? {} : { from: installed },
|
|
64183
|
+
to: version,
|
|
64184
|
+
change: version
|
|
64185
|
+
});
|
|
64186
|
+
const decision = decideRange(range, installed, available);
|
|
64187
|
+
switch (decision.kind) {
|
|
64188
|
+
case "leave": return {
|
|
64189
|
+
kind: "leave",
|
|
64190
|
+
item,
|
|
64191
|
+
...at
|
|
64192
|
+
};
|
|
64193
|
+
case "install": return install(decision.version);
|
|
64194
|
+
case "unavailable": return unavailable;
|
|
64195
|
+
case "ask": {
|
|
64196
|
+
const subject = address(input.provider, item);
|
|
64197
|
+
const answer = input.ctx.answer("range", subject);
|
|
64198
|
+
if (answer === "skip") return {
|
|
64199
|
+
kind: "skip",
|
|
64200
|
+
item,
|
|
64201
|
+
...at,
|
|
64202
|
+
reason: `is above ${range}`
|
|
64203
|
+
};
|
|
64204
|
+
if (answer === "downgrade") {
|
|
64205
|
+
const target = decideRange(range, void 0, available);
|
|
64206
|
+
return target.kind === "install" ? install(target.version) : unavailable;
|
|
64207
|
+
}
|
|
64208
|
+
return {
|
|
64209
|
+
kind: "ask",
|
|
64210
|
+
item,
|
|
64211
|
+
...at,
|
|
64212
|
+
question: rangeQuestion(subject, decision.installed, range, input.bumpPath)
|
|
64213
|
+
};
|
|
64214
|
+
}
|
|
64215
|
+
}
|
|
64216
|
+
};
|
|
64217
|
+
const orderProviders = (all, dependsOn) => {
|
|
64218
|
+
const byName = new Map(all.map((p) => [p.name, p]));
|
|
64219
|
+
const order = [];
|
|
64220
|
+
const done = /* @__PURE__ */ new Set();
|
|
64221
|
+
const visit = (p, path) => {
|
|
64222
|
+
if (done.has(p.name)) return void 0;
|
|
64223
|
+
if (path.includes(p.name)) return [...path.slice(path.indexOf(p.name)), p.name];
|
|
64224
|
+
for (const name of dependsOn(p)) {
|
|
64225
|
+
const dep = byName.get(name);
|
|
64226
|
+
const cycle = dep === void 0 ? void 0 : visit(dep, [...path, p.name]);
|
|
64227
|
+
if (cycle !== void 0) return cycle;
|
|
64228
|
+
}
|
|
64229
|
+
done.add(p.name);
|
|
64230
|
+
order.push(p);
|
|
64231
|
+
};
|
|
64232
|
+
for (const p of all) {
|
|
64233
|
+
const cycle = visit(p, []);
|
|
64234
|
+
if (cycle !== void 0) return { cycle };
|
|
64235
|
+
}
|
|
64236
|
+
return { order };
|
|
64237
|
+
};
|
|
64238
|
+
//#endregion
|
|
64239
|
+
//#region ../../packages/core/src/record.ts
|
|
64240
|
+
const sameRecord = (a, b) => Object.keys(a).length === Object.keys(b).length && Object.entries(a).every(([k, v]) => b[k] === v);
|
|
64241
|
+
const decideInstall = (record, now, rebuild) => {
|
|
64242
|
+
if (rebuild) return {
|
|
64243
|
+
run: true,
|
|
64244
|
+
reason: "--rebuild"
|
|
64245
|
+
};
|
|
64246
|
+
if (record === void 0) return {
|
|
64247
|
+
run: true,
|
|
64248
|
+
reason: "never installed"
|
|
64249
|
+
};
|
|
64250
|
+
if (record.commit !== now.commit) return {
|
|
64251
|
+
run: true,
|
|
64252
|
+
reason: `new commit ${now.commit.slice(0, 7)}`
|
|
64253
|
+
};
|
|
64254
|
+
if (record.path !== now.path) return {
|
|
64255
|
+
run: true,
|
|
64256
|
+
reason: "clone moved"
|
|
64257
|
+
};
|
|
64258
|
+
if (record.install !== now.install) return {
|
|
64259
|
+
run: true,
|
|
64260
|
+
reason: "install command changed"
|
|
64261
|
+
};
|
|
64262
|
+
if (!sameRecord(record.files, now.files)) return {
|
|
64263
|
+
run: true,
|
|
64264
|
+
reason: "files changed"
|
|
64265
|
+
};
|
|
64266
|
+
for (const [path, fingerprint] of Object.entries(now.outputs)) if (fingerprint === void 0 || record.outputs[path] !== fingerprint) return {
|
|
64267
|
+
run: true,
|
|
64268
|
+
reason: `drift: ${path}`
|
|
64269
|
+
};
|
|
64270
|
+
return { run: false };
|
|
64271
|
+
};
|
|
64272
|
+
//#endregion
|
|
64273
|
+
//#region ../../packages/core/src/state.ts
|
|
64274
|
+
const EngineFact = Union([
|
|
64275
|
+
Struct({
|
|
64276
|
+
fact: Literal("home"),
|
|
64277
|
+
path: String$5
|
|
64278
|
+
}),
|
|
64279
|
+
Struct({ fact: Literal("end") }),
|
|
64280
|
+
Struct({
|
|
64281
|
+
fact: Literal("config"),
|
|
64282
|
+
present: Boolean$4,
|
|
64283
|
+
base64: optionalKey(String$5)
|
|
64284
|
+
}),
|
|
64285
|
+
Struct({
|
|
64286
|
+
fact: Literal("record"),
|
|
64287
|
+
provider: String$5,
|
|
64288
|
+
item: String$5,
|
|
64289
|
+
record: Unknown
|
|
64290
|
+
})
|
|
64291
|
+
]);
|
|
64292
|
+
const ProviderFact = Struct({ provider: String$5 });
|
|
64293
|
+
const AtFact = Struct({
|
|
64294
|
+
provider: String$5,
|
|
64295
|
+
fact: Literal("at"),
|
|
64296
|
+
item: String$5,
|
|
64297
|
+
at: String$5
|
|
64298
|
+
});
|
|
64299
|
+
const decodeEngineFact = decodeUnknownOption(EngineFact);
|
|
64300
|
+
const decodeProviderFact = decodeUnknownOption(ProviderFact);
|
|
64301
|
+
const emptyState = {
|
|
64302
|
+
complete: false,
|
|
64303
|
+
records: {},
|
|
64304
|
+
facts: {}
|
|
64305
|
+
};
|
|
64306
|
+
const decodeBase64 = (base64) => new TextDecoder().decode(Uint8Array.from(atob(base64), (c) => c.charCodeAt(0)));
|
|
64307
|
+
const assembleState = (facts) => {
|
|
64308
|
+
let state = emptyState;
|
|
64309
|
+
for (const raw of facts) {
|
|
64310
|
+
const fact = decodeEngineFact(raw);
|
|
64311
|
+
if (fact._tag === "Some") {
|
|
64312
|
+
const f = fact.value;
|
|
64313
|
+
switch (f.fact) {
|
|
64314
|
+
case "home":
|
|
64315
|
+
state = {
|
|
64316
|
+
...state,
|
|
64317
|
+
home: f.path
|
|
64318
|
+
};
|
|
64319
|
+
break;
|
|
64320
|
+
case "end":
|
|
64321
|
+
state = {
|
|
64322
|
+
...state,
|
|
64323
|
+
complete: true
|
|
64324
|
+
};
|
|
64325
|
+
break;
|
|
64326
|
+
case "config":
|
|
64327
|
+
if (f.present && f.base64 !== void 0) state = {
|
|
64328
|
+
...state,
|
|
64329
|
+
config: decodeBase64(f.base64)
|
|
64330
|
+
};
|
|
64331
|
+
break;
|
|
64332
|
+
case "record": state = {
|
|
64333
|
+
...state,
|
|
64334
|
+
records: {
|
|
64335
|
+
...state.records,
|
|
64336
|
+
[f.provider]: {
|
|
64337
|
+
...state.records[f.provider],
|
|
64338
|
+
[f.item]: f.record
|
|
64339
|
+
}
|
|
64340
|
+
}
|
|
64341
|
+
};
|
|
64342
|
+
}
|
|
64343
|
+
continue;
|
|
64344
|
+
}
|
|
64345
|
+
const owned = decodeProviderFact(raw);
|
|
64346
|
+
if (owned._tag === "Some") {
|
|
64347
|
+
const { provider } = owned.value;
|
|
64348
|
+
state = {
|
|
64349
|
+
...state,
|
|
64350
|
+
facts: {
|
|
64351
|
+
...state.facts,
|
|
64352
|
+
[provider]: [...state.facts[provider] ?? [], raw]
|
|
64353
|
+
}
|
|
64354
|
+
};
|
|
64355
|
+
}
|
|
64356
|
+
}
|
|
64357
|
+
return state;
|
|
64358
|
+
};
|
|
64359
|
+
//#endregion
|
|
64202
64360
|
//#region src/ledger.ts
|
|
64203
64361
|
const Note = Struct({
|
|
64204
64362
|
kind: Literals$2([
|
|
@@ -64211,8 +64369,8 @@ const Note = Struct({
|
|
|
64211
64369
|
const Item = Struct({
|
|
64212
64370
|
name: String$5,
|
|
64213
64371
|
kind: Literals$2([
|
|
64214
|
-
"
|
|
64215
|
-
"
|
|
64372
|
+
"range",
|
|
64373
|
+
"record",
|
|
64216
64374
|
"config"
|
|
64217
64375
|
]),
|
|
64218
64376
|
from: optionalKey(String$5),
|
|
@@ -64229,7 +64387,10 @@ const Item = Struct({
|
|
|
64229
64387
|
doing: optionalKey(String$5),
|
|
64230
64388
|
detail: optionalKey(String$5),
|
|
64231
64389
|
output: optionalKey(ArraySchema(String$5)),
|
|
64232
|
-
steps: ArraySchema(
|
|
64390
|
+
steps: ArraySchema(Struct({
|
|
64391
|
+
id: String$5,
|
|
64392
|
+
doing: String$5
|
|
64393
|
+
})),
|
|
64233
64394
|
started: optionalKey(Number$2),
|
|
64234
64395
|
ended: optionalKey(Number$2)
|
|
64235
64396
|
});
|
|
@@ -64258,88 +64419,56 @@ const LedgerState = Struct({
|
|
|
64258
64419
|
started: Number$2,
|
|
64259
64420
|
ended: optionalKey(Number$2)
|
|
64260
64421
|
});
|
|
64261
|
-
const
|
|
64262
|
-
const
|
|
64263
|
-
|
|
64264
|
-
|
|
64265
|
-
|
|
64266
|
-
|
|
64267
|
-
|
|
64268
|
-
|
|
64269
|
-
|
|
64270
|
-
|
|
64271
|
-
|
|
64272
|
-
|
|
64273
|
-
|
|
64274
|
-
|
|
64275
|
-
|
|
64276
|
-
const now = from === void 0 ? checked : from ?? void 0;
|
|
64277
|
-
return {
|
|
64278
|
-
...item,
|
|
64279
|
-
...now === void 0 ? {} : { from: now },
|
|
64280
|
-
to,
|
|
64281
|
-
...reason === void 0 ? {} : { reason },
|
|
64422
|
+
const itemsOf = (p) => [...p.providers.flatMap((pp) => pp.decisions.map((d) => {
|
|
64423
|
+
const base = {
|
|
64424
|
+
name: address(pp.name, d.item),
|
|
64425
|
+
kind: pp.rule,
|
|
64426
|
+
steps: pp.steps.filter((step) => step.items.includes(d.item)).map(({ id, doing }) => ({
|
|
64427
|
+
id,
|
|
64428
|
+
doing
|
|
64429
|
+
}))
|
|
64430
|
+
};
|
|
64431
|
+
switch (d.kind) {
|
|
64432
|
+
case "change": return {
|
|
64433
|
+
...base,
|
|
64434
|
+
...d.from === void 0 ? {} : { from: d.from },
|
|
64435
|
+
to: d.to,
|
|
64436
|
+
...d.reason === void 0 ? {} : { reason: d.reason },
|
|
64282
64437
|
changes: true,
|
|
64283
|
-
|
|
64438
|
+
status: "idle"
|
|
64439
|
+
};
|
|
64440
|
+
case "leave": return {
|
|
64441
|
+
...base,
|
|
64442
|
+
...d.at === void 0 ? {} : { from: d.at },
|
|
64443
|
+
changes: false,
|
|
64444
|
+
status: "idle"
|
|
64445
|
+
};
|
|
64446
|
+
case "skip":
|
|
64447
|
+
case "fail": return {
|
|
64448
|
+
...base,
|
|
64449
|
+
...d.at === void 0 ? {} : { from: d.at },
|
|
64450
|
+
changes: d.kind === "fail",
|
|
64451
|
+
status: d.kind === "fail" ? "failed" : "skipped",
|
|
64452
|
+
detail: d.reason
|
|
64453
|
+
};
|
|
64454
|
+
case "ask": return {
|
|
64455
|
+
...base,
|
|
64456
|
+
...d.at === void 0 ? {} : { from: d.at },
|
|
64457
|
+
changes: false,
|
|
64458
|
+
status: "skipped",
|
|
64459
|
+
detail: d.question.problem
|
|
64284
64460
|
};
|
|
64285
|
-
};
|
|
64286
|
-
const vp = state.vp?.version ?? void 0;
|
|
64287
|
-
items.set(key("version", "vp"), base("vp", vp));
|
|
64288
|
-
if (state.node != null) items.set(key("version", "node"), base("node", state.node));
|
|
64289
|
-
for (const g of state.globals) items.set(key("version", g.name), base(g.name, g.version));
|
|
64290
|
-
for (const step of p.vp) {
|
|
64291
|
-
const id = vpStepId(step);
|
|
64292
|
-
switch (step.kind) {
|
|
64293
|
-
case "bootstrap":
|
|
64294
|
-
set("vp", plans(id, "latest", null));
|
|
64295
|
-
break;
|
|
64296
|
-
case "vp":
|
|
64297
|
-
case "node":
|
|
64298
|
-
set(step.kind, plans(id, step.version, step.from));
|
|
64299
|
-
break;
|
|
64300
|
-
case "reinstall":
|
|
64301
|
-
set(step.name, plans(id, step.version, step.version, "reinstall"));
|
|
64302
|
-
break;
|
|
64303
|
-
case "globals": for (const pkg of step.packages) set(pkg.name, plans(id, pkg.version, pkg.from ?? null));
|
|
64304
|
-
}
|
|
64305
|
-
}
|
|
64306
|
-
for (const repo of p.repos) {
|
|
64307
|
-
const from = short(state.records[repo.name]?.commit);
|
|
64308
|
-
const to = short(repo.head);
|
|
64309
|
-
items.set(key("repo", repo.name), {
|
|
64310
|
-
name: repo.name,
|
|
64311
|
-
kind: "repo",
|
|
64312
|
-
...from === void 0 ? {} : { from },
|
|
64313
|
-
...to === void 0 ? {} : { to },
|
|
64314
|
-
...repo.decision.run ? { reason: repo.decision.reason } : {},
|
|
64315
|
-
changes: repo.decision.run,
|
|
64316
|
-
status: "idle",
|
|
64317
|
-
steps: [stepId(repo.name, "fetch"), stepId(repo.name, "install")]
|
|
64318
|
-
});
|
|
64319
64461
|
}
|
|
64320
|
-
|
|
64321
|
-
|
|
64322
|
-
|
|
64323
|
-
|
|
64324
|
-
|
|
64325
|
-
|
|
64326
|
-
|
|
64327
|
-
|
|
64328
|
-
|
|
64329
|
-
|
|
64330
|
-
status: "failed",
|
|
64331
|
-
detail: f.reason
|
|
64332
|
-
}), kind);
|
|
64333
|
-
}
|
|
64334
|
-
items.set(key("config", CONFIG_STEP), {
|
|
64335
|
-
name: CONFIG_STEP,
|
|
64336
|
-
kind: "config",
|
|
64337
|
-
changes: false,
|
|
64338
|
-
status: "idle",
|
|
64339
|
-
steps: [CONFIG_STEP]
|
|
64340
|
-
});
|
|
64341
|
-
return [...items.values()];
|
|
64342
|
-
};
|
|
64462
|
+
})), {
|
|
64463
|
+
name: CONFIG_STEP,
|
|
64464
|
+
kind: "config",
|
|
64465
|
+
changes: false,
|
|
64466
|
+
status: "idle",
|
|
64467
|
+
steps: [{
|
|
64468
|
+
id: CONFIG_STEP,
|
|
64469
|
+
doing: "copying"
|
|
64470
|
+
}]
|
|
64471
|
+
}];
|
|
64343
64472
|
const outcomeOf = (m, dryRun) => m.status === "skipped" ? "skipped" : m.status === "failed" || m.items.some((i) => i.status === "failed") ? "failed" : m.status === "ok" || m.status === "planned" && dryRun ? "ok" : void 0;
|
|
64344
64473
|
const anyFailed = (state) => state.machines.some((m) => outcomeOf(m, state.dryRun) === "failed");
|
|
64345
64474
|
const makeLedger = fn("makeLedger")(function* (input) {
|
|
@@ -64373,7 +64502,7 @@ const makeLedger = fn("makeLedger")(function* (input) {
|
|
|
64373
64502
|
}));
|
|
64374
64503
|
const items = (name, id, change) => machine(name, (m, now) => ({
|
|
64375
64504
|
...m,
|
|
64376
|
-
items: m.items.map((i) => i.steps.
|
|
64505
|
+
items: m.items.map((i) => i.steps.some((step) => step.id === id) ? change(i, now) : i)
|
|
64377
64506
|
}));
|
|
64378
64507
|
const store = {
|
|
64379
64508
|
get: () => snapshot,
|
|
@@ -64414,25 +64543,24 @@ const makeLedger = fn("makeLedger")(function* (input) {
|
|
|
64414
64543
|
...output.length === 0 ? {} : { output },
|
|
64415
64544
|
ended: now
|
|
64416
64545
|
})),
|
|
64417
|
-
plan: (name, p
|
|
64546
|
+
plan: (name, p) => machine(name, (m) => ({
|
|
64418
64547
|
...m,
|
|
64419
64548
|
status: "planned",
|
|
64420
|
-
items: itemsOf(p
|
|
64549
|
+
items: itemsOf(p)
|
|
64421
64550
|
})),
|
|
64422
64551
|
start: (name) => machine(name, (m, now) => ({
|
|
64423
64552
|
...m,
|
|
64424
64553
|
status: "running",
|
|
64425
64554
|
started: now
|
|
64426
64555
|
})),
|
|
64427
|
-
stepStarted: (name, id) => items(name, id, (item, now) => item.status === "failed" ? item : {
|
|
64556
|
+
stepStarted: (name, id) => items(name, id, (item, now) => item.status === "failed" || item.status === "skipped" ? item : {
|
|
64428
64557
|
...item,
|
|
64429
|
-
changes: item.changes || !(id === "config" || isFetchStep(id)),
|
|
64430
64558
|
status: "running",
|
|
64431
|
-
doing:
|
|
64559
|
+
doing: item.steps.find((step) => step.id === id)?.doing ?? "running",
|
|
64432
64560
|
started: item.started ?? now
|
|
64433
64561
|
}),
|
|
64434
64562
|
stepDone: (name, id, result) => items(name, id, (item, now) => {
|
|
64435
|
-
if (item.status === "failed") return item;
|
|
64563
|
+
if (item.status === "failed" || item.status === "skipped") return item;
|
|
64436
64564
|
if (!result.ok) return {
|
|
64437
64565
|
...item,
|
|
64438
64566
|
changes: true,
|
|
@@ -64441,25 +64569,31 @@ const makeLedger = fn("makeLedger")(function* (input) {
|
|
|
64441
64569
|
...result.output.length === 0 ? {} : { output: result.output },
|
|
64442
64570
|
ended: now
|
|
64443
64571
|
};
|
|
64572
|
+
if (item.steps.at(-1)?.id !== id) return item;
|
|
64444
64573
|
const { doing: _, ...rest } = item;
|
|
64445
|
-
|
|
64574
|
+
return {
|
|
64446
64575
|
...rest,
|
|
64447
|
-
status: "
|
|
64576
|
+
status: "ok",
|
|
64448
64577
|
ended: now
|
|
64449
64578
|
};
|
|
64579
|
+
}),
|
|
64580
|
+
stepSkipped: (name, id, reason) => items(name, id, (item, now) => {
|
|
64581
|
+
if (item.status === "failed") return item;
|
|
64582
|
+
const { doing: _, ...rest } = item;
|
|
64450
64583
|
return {
|
|
64451
64584
|
...rest,
|
|
64452
|
-
status: "
|
|
64585
|
+
status: "skipped",
|
|
64586
|
+
detail: reason,
|
|
64453
64587
|
ended: now
|
|
64454
64588
|
};
|
|
64455
64589
|
}),
|
|
64456
|
-
|
|
64590
|
+
reached: (name, item, at) => machine(name, (m) => ({
|
|
64457
64591
|
...m,
|
|
64458
|
-
items: m.items.map((i) => i.
|
|
64592
|
+
items: m.items.map((i) => i.name !== item ? i : {
|
|
64459
64593
|
...i,
|
|
64460
|
-
to:
|
|
64461
|
-
changes: i.
|
|
64462
|
-
}
|
|
64594
|
+
to: at,
|
|
64595
|
+
changes: i.status === "failed" || i.from !== at
|
|
64596
|
+
})
|
|
64463
64597
|
})),
|
|
64464
64598
|
finish: (name, outcome) => machine(name, (m, now) => ({
|
|
64465
64599
|
...m,
|
|
@@ -64801,6 +64935,10 @@ const Cell = (props) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box, {
|
|
|
64801
64935
|
})
|
|
64802
64936
|
});
|
|
64803
64937
|
const value = (i) => i.to === void 0 ? i.from ?? "" : i.from === void 0 ? `+ ${i.to}` : i.from === i.to ? i.to : `${i.from} → ${i.to}`;
|
|
64938
|
+
const unchanged = (i) => ({
|
|
64939
|
+
text: "",
|
|
64940
|
+
detail: i.kind === "record" ? "up to date" : void 0
|
|
64941
|
+
});
|
|
64804
64942
|
const statusOf = (i, dryRun) => {
|
|
64805
64943
|
switch (i.status) {
|
|
64806
64944
|
case "running": return {
|
|
@@ -64822,7 +64960,8 @@ const statusOf = (i, dryRun) => {
|
|
|
64822
64960
|
text: "✓ copied",
|
|
64823
64961
|
tone: "dim"
|
|
64824
64962
|
};
|
|
64825
|
-
if (i.
|
|
64963
|
+
if (!i.changes) return unchanged(i);
|
|
64964
|
+
if (i.kind === "record") return i.from !== void 0 && i.from === i.to ? {
|
|
64826
64965
|
text: "✓ rebuilt",
|
|
64827
64966
|
tone: "ok",
|
|
64828
64967
|
detail: i.reason
|
|
@@ -64841,10 +64980,7 @@ const statusOf = (i, dryRun) => {
|
|
|
64841
64980
|
tone: "dim",
|
|
64842
64981
|
detail: i.reason
|
|
64843
64982
|
};
|
|
64844
|
-
return
|
|
64845
|
-
text: "",
|
|
64846
|
-
detail: i.kind === "repo" ? "up to date" : void 0
|
|
64847
|
-
};
|
|
64983
|
+
return unchanged(i);
|
|
64848
64984
|
}
|
|
64849
64985
|
};
|
|
64850
64986
|
const countsOf = (m) => {
|
|
@@ -65187,6 +65323,743 @@ const report = fn("report")(function* () {
|
|
|
65187
65323
|
]
|
|
65188
65324
|
})));
|
|
65189
65325
|
});
|
|
65326
|
+
const decodeFact$2 = decodeUnknownOption(Union([Struct({
|
|
65327
|
+
fact: Literal("brew"),
|
|
65328
|
+
version: NullOr(String$5)
|
|
65329
|
+
}), AtFact]));
|
|
65330
|
+
const NO_BREW = "Homebrew is not installed; install it first";
|
|
65331
|
+
function homebrew(name) {
|
|
65332
|
+
const flag = name === "brew" ? "--formula" : "--cask";
|
|
65333
|
+
const lookup = name === "brew" ? "\"$ff_i\"" : "\"${ff_i##*/}\"";
|
|
65334
|
+
const report = (names) => `for ff_i in ${names.map(quote).join(" ")}; do ff_v=$(brew list --versions ${flag} ${lookup} 2>/dev/null | awk '{print $NF}'); [ -z "$ff_v" ] || ff_at ${name} "$ff_i" "$ff_v"; done`;
|
|
65335
|
+
const step = (what, batch) => {
|
|
65336
|
+
const names = batch.map((c) => c.name);
|
|
65337
|
+
const update = batch.some((c) => c.range === "latest") ? "brew update && " : "";
|
|
65338
|
+
return {
|
|
65339
|
+
id: `${name}:${name === "brew" ? "formulae" : "casks"}:${what}`,
|
|
65340
|
+
items: names,
|
|
65341
|
+
doing: what === "install" ? "installing" : "upgrading",
|
|
65342
|
+
run: [[
|
|
65343
|
+
`( ${update}NONINTERACTIVE=1 brew ${what} ${flag} ${names.map(quote).join(" ")}`,
|
|
65344
|
+
"ff_rc=$?",
|
|
65345
|
+
report(names),
|
|
65346
|
+
"exit $ff_rc )"
|
|
65347
|
+
].join("; ")]
|
|
65348
|
+
};
|
|
65349
|
+
};
|
|
65350
|
+
return {
|
|
65351
|
+
name,
|
|
65352
|
+
rule: "range",
|
|
65353
|
+
dependsOn: name === "cask" ? ["brew"] : [],
|
|
65354
|
+
items(section, listed) {
|
|
65355
|
+
if (section === void 0) return [];
|
|
65356
|
+
const packages = listed.map(({ name: item, def }) => ({
|
|
65357
|
+
name: item,
|
|
65358
|
+
kind: "package",
|
|
65359
|
+
range: def.range
|
|
65360
|
+
}));
|
|
65361
|
+
return name === "brew" ? [{
|
|
65362
|
+
name: "brew",
|
|
65363
|
+
kind: "homebrew"
|
|
65364
|
+
}, ...packages] : packages;
|
|
65365
|
+
},
|
|
65366
|
+
observe: (items) => [
|
|
65367
|
+
"if command -v brew >/dev/null 2>&1; then",
|
|
65368
|
+
` ff_state "{\\"provider\\":\\"${name}\\",\\"fact\\":\\"brew\\",\\"version\\":\\"$(ff_json "$(brew --version 2>/dev/null | head -n 1 | sed 's/^Homebrew //')")\\"}"`,
|
|
65369
|
+
` ${report(items.flatMap((i) => i.kind === "package" ? [i.name] : []))}`,
|
|
65370
|
+
"else",
|
|
65371
|
+
` ff_state '{"provider":"${name}","fact":"brew","version":null}'`,
|
|
65372
|
+
"fi"
|
|
65373
|
+
].join("\n"),
|
|
65374
|
+
parse(facts) {
|
|
65375
|
+
let brew;
|
|
65376
|
+
const at = /* @__PURE__ */ new Map();
|
|
65377
|
+
for (const raw of facts) {
|
|
65378
|
+
const fact = decodeFact$2(raw);
|
|
65379
|
+
if (fact._tag === "None") continue;
|
|
65380
|
+
const f = fact.value;
|
|
65381
|
+
if (f.fact === "brew") brew = f.version ?? void 0;
|
|
65382
|
+
else at.set(f.item, f.at);
|
|
65383
|
+
}
|
|
65384
|
+
return {
|
|
65385
|
+
...brew === void 0 ? {} : { brew },
|
|
65386
|
+
at
|
|
65387
|
+
};
|
|
65388
|
+
},
|
|
65389
|
+
resolve: () => void_,
|
|
65390
|
+
decide({ items, observed, ctx }) {
|
|
65391
|
+
return items.map((item) => {
|
|
65392
|
+
const installed = observed.at.get(item.name);
|
|
65393
|
+
if (item.kind === "homebrew") return observed.brew === void 0 ? {
|
|
65394
|
+
kind: "fail",
|
|
65395
|
+
item: item.name,
|
|
65396
|
+
reason: NO_BREW
|
|
65397
|
+
} : {
|
|
65398
|
+
kind: "leave",
|
|
65399
|
+
item: item.name,
|
|
65400
|
+
at: observed.brew
|
|
65401
|
+
};
|
|
65402
|
+
if (name === "cask" && ctx.machine.platform !== "darwin") return {
|
|
65403
|
+
kind: "fail",
|
|
65404
|
+
item: item.name,
|
|
65405
|
+
reason: "Casks need macOS"
|
|
65406
|
+
};
|
|
65407
|
+
if (observed.brew === void 0) return name === "brew" ? {
|
|
65408
|
+
kind: "skip",
|
|
65409
|
+
item: item.name,
|
|
65410
|
+
reason: "needs Homebrew"
|
|
65411
|
+
} : {
|
|
65412
|
+
kind: "fail",
|
|
65413
|
+
item: item.name,
|
|
65414
|
+
reason: NO_BREW
|
|
65415
|
+
};
|
|
65416
|
+
if (installed === void 0) return {
|
|
65417
|
+
kind: "change",
|
|
65418
|
+
item: item.name,
|
|
65419
|
+
to: "latest",
|
|
65420
|
+
change: {
|
|
65421
|
+
kind: "install",
|
|
65422
|
+
name: item.name,
|
|
65423
|
+
range: item.range
|
|
65424
|
+
}
|
|
65425
|
+
};
|
|
65426
|
+
if (item.range === "latest") return {
|
|
65427
|
+
kind: "change",
|
|
65428
|
+
item: item.name,
|
|
65429
|
+
from: installed,
|
|
65430
|
+
to: "latest",
|
|
65431
|
+
change: {
|
|
65432
|
+
kind: "upgrade",
|
|
65433
|
+
name: item.name,
|
|
65434
|
+
range: item.range
|
|
65435
|
+
}
|
|
65436
|
+
};
|
|
65437
|
+
return {
|
|
65438
|
+
kind: "leave",
|
|
65439
|
+
item: item.name,
|
|
65440
|
+
at: installed
|
|
65441
|
+
};
|
|
65442
|
+
});
|
|
65443
|
+
},
|
|
65444
|
+
act(decisions) {
|
|
65445
|
+
const changes = decisions.flatMap((d) => d.kind === "change" ? [d.change] : []);
|
|
65446
|
+
return ["install", "upgrade"].flatMap((what) => {
|
|
65447
|
+
const batch = changes.filter((c) => c.kind === what);
|
|
65448
|
+
return batch.length === 0 ? [] : [step(what, batch)];
|
|
65449
|
+
});
|
|
65450
|
+
}
|
|
65451
|
+
};
|
|
65452
|
+
}
|
|
65453
|
+
const brew = homebrew("brew");
|
|
65454
|
+
const cask = homebrew("cask");
|
|
65455
|
+
const decodeFact$1 = decodeUnknownOption(Union([
|
|
65456
|
+
Struct({
|
|
65457
|
+
fact: Literal("cloneRoot"),
|
|
65458
|
+
path: String$5,
|
|
65459
|
+
present: Boolean$4
|
|
65460
|
+
}),
|
|
65461
|
+
Struct({
|
|
65462
|
+
fact: Literal("repo"),
|
|
65463
|
+
name: String$5,
|
|
65464
|
+
present: Boolean$4,
|
|
65465
|
+
head: optionalKey(String$5),
|
|
65466
|
+
origin: optionalKey(String$5)
|
|
65467
|
+
}),
|
|
65468
|
+
Struct({
|
|
65469
|
+
fact: Literal("output"),
|
|
65470
|
+
repo: String$5,
|
|
65471
|
+
path: String$5,
|
|
65472
|
+
fingerprint: NullOr(String$5)
|
|
65473
|
+
})
|
|
65474
|
+
]));
|
|
65475
|
+
const decodeRecord = decodeUnknownOption(Struct({
|
|
65476
|
+
commit: String$5,
|
|
65477
|
+
path: String$5,
|
|
65478
|
+
install: String$5,
|
|
65479
|
+
files: Record(String$5, String$5),
|
|
65480
|
+
outputs: Record(String$5, String$5)
|
|
65481
|
+
}));
|
|
65482
|
+
const branchKey = (repo) => `${repo.origin}#${repo.ref}`;
|
|
65483
|
+
const cloneRoot = (config, machine) => {
|
|
65484
|
+
const root = config.repos?.cloneRoot;
|
|
65485
|
+
return (root === void 0 ? void 0 : variantFor(root, machine))?.variant.path ?? "~/.local/share/fleetfizz/clones";
|
|
65486
|
+
};
|
|
65487
|
+
const originUrl = (origin) => `https://github.com/${origin}.git`;
|
|
65488
|
+
const short = (commit) => commit.slice(0, 7);
|
|
65489
|
+
const expandHome = (path, home) => path === "~" ? home : path.startsWith("~/") ? `${home}${path.slice(1)}` : path;
|
|
65490
|
+
const jsonString = encodeSync(fromJsonString(String$5));
|
|
65491
|
+
const jsonRecord = encodeSync(fromJsonString(Record(String$5, String$5)));
|
|
65492
|
+
const lsRemote = fn("lsRemote")(function* (repo, token) {
|
|
65493
|
+
const spawner = yield* ChildProcessSpawner;
|
|
65494
|
+
const auth = token === void 0 ? [] : [
|
|
65495
|
+
"-c",
|
|
65496
|
+
"credential.helper=",
|
|
65497
|
+
"-c",
|
|
65498
|
+
"credential.helper=!f() { echo username=x-access-token; echo \"password=$FF_TOKEN\"; }; f"
|
|
65499
|
+
];
|
|
65500
|
+
return yield* scoped(gen(function* () {
|
|
65501
|
+
const handle = yield* spawner.spawn(make$12("git", [
|
|
65502
|
+
...auth,
|
|
65503
|
+
"ls-remote",
|
|
65504
|
+
originUrl(repo.origin),
|
|
65505
|
+
`refs/heads/${repo.ref}`
|
|
65506
|
+
], {
|
|
65507
|
+
stdout: "pipe",
|
|
65508
|
+
stderr: "pipe",
|
|
65509
|
+
env: {
|
|
65510
|
+
GIT_TERMINAL_PROMPT: "0",
|
|
65511
|
+
...token === void 0 ? {} : { FF_TOKEN: token }
|
|
65512
|
+
},
|
|
65513
|
+
extendEnv: true
|
|
65514
|
+
}));
|
|
65515
|
+
const [stdout, stderr, code] = yield* all([
|
|
65516
|
+
runCollect(decodeText(handle.stdout)),
|
|
65517
|
+
runCollect(decodeText(handle.stderr)),
|
|
65518
|
+
handle.exitCode
|
|
65519
|
+
], { concurrency: "unbounded" });
|
|
65520
|
+
if (code !== 0) {
|
|
65521
|
+
const lines = stderr.join("").trim().split("\n");
|
|
65522
|
+
return { error: lines[lines.length - 1] || `git ls-remote exited ${code}` };
|
|
65523
|
+
}
|
|
65524
|
+
const commit = stdout.join("").split(/\s/)[0];
|
|
65525
|
+
return commit === void 0 || commit === "" ? { error: `no branch ${repo.ref} on origin` } : { commit };
|
|
65526
|
+
})).pipe(orElseSucceed(() => ({ error: "could not run git ls-remote" })));
|
|
65527
|
+
});
|
|
65528
|
+
const observe = (items, root) => {
|
|
65529
|
+
if (items.length === 0) return "";
|
|
65530
|
+
const lines = [
|
|
65531
|
+
`ff_root=${quotePath(root)}`,
|
|
65532
|
+
`if [ -d "$ff_root" ]; then ff_present=true; else ff_present=false; fi`,
|
|
65533
|
+
`ff_state "{\\"provider\\":\\"repos\\",\\"fact\\":\\"cloneRoot\\",\\"path\\":\\"$(ff_json "$ff_root")\\",\\"present\\":$ff_present}"`
|
|
65534
|
+
];
|
|
65535
|
+
for (const repo of items) {
|
|
65536
|
+
const name = quote(repo.name);
|
|
65537
|
+
lines.push(`ff_d="$ff_root"/${name}`, `if [ -d "$ff_d/.git" ]; then`, ` ff_state "{\\"provider\\":\\"repos\\",\\"fact\\":\\"repo\\",\\"name\\":\\"$(ff_json ${name})\\",\\"present\\":true,\\"head\\":\\"$(ff_json "$(git -C "$ff_d" rev-parse HEAD 2>/dev/null)")\\",\\"origin\\":\\"$(ff_json "$(git -C "$ff_d" remote get-url origin 2>/dev/null)")\\"}"`, "else", ` ff_state "{\\"provider\\":\\"repos\\",\\"fact\\":\\"repo\\",\\"name\\":\\"$(ff_json ${name})\\",\\"present\\":false}"`, "fi");
|
|
65538
|
+
for (const output of repo.outputs ?? []) lines.push(`ff_p=${quotePath(output)}; ff_f=$(ff_fp "$ff_p")`, `if [ -n "$ff_f" ]; then ff_fv="\\"$(ff_json "$ff_f")\\""; else ff_fv=null; fi`, `ff_state "{\\"provider\\":\\"repos\\",\\"fact\\":\\"output\\",\\"repo\\":\\"$(ff_json ${name})\\",\\"path\\":\\"$(ff_json ${quote(output)})\\",\\"fingerprint\\":$ff_fv}"`);
|
|
65539
|
+
}
|
|
65540
|
+
return lines.join("\n");
|
|
65541
|
+
};
|
|
65542
|
+
const decideRepo = (repo, root, observed, resolved, ctx) => {
|
|
65543
|
+
const clone = observed.clones.get(repo.name);
|
|
65544
|
+
const record = observed.records.get(repo.name);
|
|
65545
|
+
const at = clone?.head === void 0 ? {} : { at: short(clone.head) };
|
|
65546
|
+
const fail = (reason) => ({
|
|
65547
|
+
kind: "fail",
|
|
65548
|
+
item: repo.name,
|
|
65549
|
+
...at,
|
|
65550
|
+
reason
|
|
65551
|
+
});
|
|
65552
|
+
if (observed.cloneRoot?.present === false && !root.startsWith("~")) return fail(`clone root not mounted: ${observed.cloneRoot.path}`);
|
|
65553
|
+
const url = originUrl(repo.origin);
|
|
65554
|
+
if (clone?.present && clone.origin !== void 0 && clone.origin !== url) return fail(`managed clone has origin ${clone.origin}, expected ${url}`);
|
|
65555
|
+
const target = isPin(repo.ref) ? { commit: repo.ref } : resolved[branchKey(repo)];
|
|
65556
|
+
if (target === void 0) return fail(`could not resolve ${repo.ref}`);
|
|
65557
|
+
if ("error" in target) return fail(target.error);
|
|
65558
|
+
const { commit } = target;
|
|
65559
|
+
const outputs = observed.outputs.get(repo.name);
|
|
65560
|
+
const install = decideInstall(record, {
|
|
65561
|
+
commit,
|
|
65562
|
+
path: expandHome(`${root}/${repo.name}`, ctx.home),
|
|
65563
|
+
install: repo.install,
|
|
65564
|
+
files: repo.files ?? {},
|
|
65565
|
+
outputs: Object.fromEntries((repo.outputs ?? []).map((o) => [o, outputs?.get(o)]))
|
|
65566
|
+
}, ctx.rebuild(address("repos", repo.name)));
|
|
65567
|
+
const reason = install.run ? install.reason : !clone?.present ? "not cloned" : clone.head !== commit ? `checked out at ${short(clone.head ?? "")}` : void 0;
|
|
65568
|
+
const change = {
|
|
65569
|
+
item: repo,
|
|
65570
|
+
root,
|
|
65571
|
+
commit
|
|
65572
|
+
};
|
|
65573
|
+
if (reason === void 0) return {
|
|
65574
|
+
kind: "leave",
|
|
65575
|
+
item: repo.name,
|
|
65576
|
+
at: short(commit),
|
|
65577
|
+
upkeep: change
|
|
65578
|
+
};
|
|
65579
|
+
const from = record?.commit ?? clone?.head;
|
|
65580
|
+
return {
|
|
65581
|
+
kind: "change",
|
|
65582
|
+
item: repo.name,
|
|
65583
|
+
...from === void 0 ? {} : { from: short(from) },
|
|
65584
|
+
to: short(commit),
|
|
65585
|
+
reason,
|
|
65586
|
+
change
|
|
65587
|
+
};
|
|
65588
|
+
};
|
|
65589
|
+
const fetchStep = ({ item, root, commit }) => {
|
|
65590
|
+
const url = originUrl(item.origin);
|
|
65591
|
+
const sync = isPin(item.ref) ? [
|
|
65592
|
+
`if [ "$(git -C "$ff_d" rev-parse HEAD)" != ${quote(commit)} ]; then ff_git -C "$ff_d" fetch --quiet origin ${quote(commit)}; fi`,
|
|
65593
|
+
`git -C "$ff_d" checkout --quiet --detach ${quote(commit)}`,
|
|
65594
|
+
`git -C "$ff_d" reset --quiet --hard ${quote(commit)}`
|
|
65595
|
+
] : [`ff_git -C "$ff_d" fetch --quiet origin ${quote(item.ref)}`, `git -C "$ff_d" reset --quiet --hard ${quote(commit)}`];
|
|
65596
|
+
const files = Object.entries(item.files ?? {}).flatMap(([path, content]) => [`mkdir -p "$(dirname "$ff_d"/${quote(path)})"`, `printf '%s' ${quote(content)} > "$ff_d"/${quote(path)}`]);
|
|
65597
|
+
return {
|
|
65598
|
+
id: `repos:${item.name}:fetch`,
|
|
65599
|
+
items: [item.name],
|
|
65600
|
+
doing: "fetching",
|
|
65601
|
+
run: [
|
|
65602
|
+
`ff_root=${quotePath(root)}`,
|
|
65603
|
+
...root.startsWith("~") ? [`mkdir -p "$ff_root"`] : [],
|
|
65604
|
+
`ff_d="$ff_root"/${quote(item.name)}`,
|
|
65605
|
+
"(",
|
|
65606
|
+
" set -e",
|
|
65607
|
+
` if [ ! -d "$ff_d/.git" ]; then ff_git clone --quiet ${quote(url)} "$ff_d"; fi`,
|
|
65608
|
+
` if [ "$(git -C "$ff_d" remote get-url origin)" != ${quote(url)} ]; then echo "origin is $(git -C "$ff_d" remote get-url origin), expected ${url}"; exit 1; fi`,
|
|
65609
|
+
...[
|
|
65610
|
+
...sync,
|
|
65611
|
+
`git -C "$ff_d" clean --quiet -fd`,
|
|
65612
|
+
...files
|
|
65613
|
+
].map((l) => ` ${l}`),
|
|
65614
|
+
")"
|
|
65615
|
+
]
|
|
65616
|
+
};
|
|
65617
|
+
};
|
|
65618
|
+
const installStep = ({ item, root }, ctx) => {
|
|
65619
|
+
const env = [
|
|
65620
|
+
`FLEETFIZZ_MACHINE=${quote(ctx.machine.name)}`,
|
|
65621
|
+
`FLEETFIZZ_PLATFORM=${quote(ctx.machine.platform)}`,
|
|
65622
|
+
`FLEETFIZZ_MACHINES=${quote(ctx.config.machines.join(","))}`
|
|
65623
|
+
].join(" ");
|
|
65624
|
+
const tmp = `${recordDir("repos")}/${quote(`${item.name}.json.tmp`)}`;
|
|
65625
|
+
const record = [
|
|
65626
|
+
`ff_after=$(git -C "$ff_d" rev-parse HEAD)`,
|
|
65627
|
+
`ff_outs=""`,
|
|
65628
|
+
...(item.outputs ?? []).map((o) => `ff_fpv=$(ff_fp ${quotePath(o)}); if [ -n "$ff_fpv" ]; then ff_outs="$ff_outs,\\"$(ff_json ${quote(o)})\\":\\"$(ff_json "$ff_fpv")\\""; fi`),
|
|
65629
|
+
`mkdir -p ${recordDir("repos")}`,
|
|
65630
|
+
`printf '%s\\n' "{\\"commit\\":\\"$ff_after\\",\\"path\\":\\"$(ff_json "$ff_d")\\",\\"install\\":$(ff_lit ${quote(jsonString(item.install))}),\\"files\\":$(ff_lit ${quote(jsonRecord(item.files ?? {}))}),\\"outputs\\":{\${ff_outs#,}}}" > ${tmp}`,
|
|
65631
|
+
`mv -f ${tmp} ${recordFile("repos", item.name)}`,
|
|
65632
|
+
`rm -f ${quotePath(RECORDS_DIR)}/${quote(`${item.name}.json`)}`
|
|
65633
|
+
];
|
|
65634
|
+
return {
|
|
65635
|
+
id: `repos:${item.name}:install`,
|
|
65636
|
+
items: [item.name],
|
|
65637
|
+
doing: "installing",
|
|
65638
|
+
run: [
|
|
65639
|
+
`ff_root=${quotePath(root)}`,
|
|
65640
|
+
`ff_d="$ff_root"/${quote(item.name)}`,
|
|
65641
|
+
`(cd "$ff_d" && ${env} "\${SHELL:-/bin/sh}" -lc ${quote(item.install)})`,
|
|
65642
|
+
`ff_rc=$?`,
|
|
65643
|
+
`if [ "$ff_rc" -eq 0 ]; then`,
|
|
65644
|
+
" (",
|
|
65645
|
+
" set -e",
|
|
65646
|
+
...record.map((l) => ` ${l}`),
|
|
65647
|
+
" )",
|
|
65648
|
+
` ff_rc=$?`,
|
|
65649
|
+
` if [ "$ff_rc" -ne 0 ]; then echo "could not write the install record"; fi`,
|
|
65650
|
+
"fi",
|
|
65651
|
+
`(exit "$ff_rc")`
|
|
65652
|
+
]
|
|
65653
|
+
};
|
|
65654
|
+
};
|
|
65655
|
+
const repos = {
|
|
65656
|
+
name: "repos",
|
|
65657
|
+
rule: "record",
|
|
65658
|
+
dependsOn: ["vp"],
|
|
65659
|
+
items: (_section, listed) => listed.map(({ name, def }) => ({
|
|
65660
|
+
...def,
|
|
65661
|
+
name
|
|
65662
|
+
})),
|
|
65663
|
+
observe: (items, scope) => observe(items, cloneRoot(scope.config, scope.machine)),
|
|
65664
|
+
parse(facts, records) {
|
|
65665
|
+
let root;
|
|
65666
|
+
const clones = /* @__PURE__ */ new Map();
|
|
65667
|
+
const outputs = /* @__PURE__ */ new Map();
|
|
65668
|
+
for (const raw of facts) {
|
|
65669
|
+
const fact = decodeFact$1(raw);
|
|
65670
|
+
if (fact._tag === "None") continue;
|
|
65671
|
+
const f = fact.value;
|
|
65672
|
+
switch (f.fact) {
|
|
65673
|
+
case "cloneRoot":
|
|
65674
|
+
root = {
|
|
65675
|
+
path: f.path,
|
|
65676
|
+
present: f.present
|
|
65677
|
+
};
|
|
65678
|
+
break;
|
|
65679
|
+
case "repo":
|
|
65680
|
+
clones.set(f.name, {
|
|
65681
|
+
present: f.present,
|
|
65682
|
+
...f.head === void 0 || f.head === "" ? {} : { head: f.head },
|
|
65683
|
+
...f.origin === void 0 || f.origin === "" ? {} : { origin: f.origin }
|
|
65684
|
+
});
|
|
65685
|
+
break;
|
|
65686
|
+
case "output": {
|
|
65687
|
+
const paths = outputs.get(f.repo) ?? /* @__PURE__ */ new Map();
|
|
65688
|
+
paths.set(f.path, f.fingerprint ?? void 0);
|
|
65689
|
+
outputs.set(f.repo, paths);
|
|
65690
|
+
break;
|
|
65691
|
+
}
|
|
65692
|
+
}
|
|
65693
|
+
}
|
|
65694
|
+
const decoded = /* @__PURE__ */ new Map();
|
|
65695
|
+
for (const [name, raw] of Object.entries(records)) {
|
|
65696
|
+
const record = decodeRecord(raw);
|
|
65697
|
+
if (record._tag === "Some") decoded.set(name, record.value);
|
|
65698
|
+
}
|
|
65699
|
+
return {
|
|
65700
|
+
...root === void 0 ? {} : { cloneRoot: root },
|
|
65701
|
+
clones,
|
|
65702
|
+
outputs,
|
|
65703
|
+
records: decoded
|
|
65704
|
+
};
|
|
65705
|
+
},
|
|
65706
|
+
resolve: (items, { token }) => forEach$1([...new Map(items.filter((r) => !isPin(r.ref)).map((r) => [branchKey(r), r])).entries()], ([key, repo]) => lsRemote(repo, token).pipe(map$5((result) => [key, result])), { concurrency: 8 }).pipe(map$5((entries) => Object.fromEntries(entries))),
|
|
65707
|
+
decide: ({ items, observed, resolved, ctx }) => {
|
|
65708
|
+
const root = cloneRoot(ctx.config, ctx.machine);
|
|
65709
|
+
return items.map((repo) => decideRepo(repo, root, observed, resolved, ctx));
|
|
65710
|
+
},
|
|
65711
|
+
act: (decisions, ctx) => decisions.flatMap((d) => d.kind === "change" ? [fetchStep(d.change), installStep(d.change, ctx)] : d.kind === "leave" && d.upkeep !== void 0 ? [fetchStep(d.upkeep)] : [])
|
|
65712
|
+
};
|
|
65713
|
+
//#endregion
|
|
65714
|
+
//#region ../../packages/providers/src/vp/index.ts
|
|
65715
|
+
const VP_PACKAGE = "vite-plus";
|
|
65716
|
+
const TOOL_PACKAGES = {
|
|
65717
|
+
node: ["node"],
|
|
65718
|
+
npm: ["npm"],
|
|
65719
|
+
pnpm: ["pnpm"],
|
|
65720
|
+
yarn: ["yarn", "@yarnpkg/cli-dist"],
|
|
65721
|
+
bun: ["bun"]
|
|
65722
|
+
};
|
|
65723
|
+
const GlobalEntry = Struct({
|
|
65724
|
+
name: String$5,
|
|
65725
|
+
version: String$5,
|
|
65726
|
+
platform: optionalKey(Struct({ node: optionalKey(String$5) }))
|
|
65727
|
+
});
|
|
65728
|
+
const decodeFact = decodeUnknownOption(Union([
|
|
65729
|
+
Struct({
|
|
65730
|
+
fact: Literal("vp"),
|
|
65731
|
+
version: NullOr(String$5),
|
|
65732
|
+
path: optionalKey(String$5)
|
|
65733
|
+
}),
|
|
65734
|
+
Struct({
|
|
65735
|
+
fact: Literal("default"),
|
|
65736
|
+
tool: String$5,
|
|
65737
|
+
version: String$5
|
|
65738
|
+
}),
|
|
65739
|
+
Struct({
|
|
65740
|
+
fact: Literal("mode"),
|
|
65741
|
+
mode: Literals$2(["managed", "system-first"])
|
|
65742
|
+
}),
|
|
65743
|
+
Struct({
|
|
65744
|
+
fact: Literal("globals"),
|
|
65745
|
+
list: ArraySchema(GlobalEntry)
|
|
65746
|
+
})
|
|
65747
|
+
]));
|
|
65748
|
+
const VP_INSTALL = [
|
|
65749
|
+
"curl -fsSL https://vite.plus | bash",
|
|
65750
|
+
...vpEnv.split("\n"),
|
|
65751
|
+
"{ hash -r 2>/dev/null || true; }"
|
|
65752
|
+
].join(" && ");
|
|
65753
|
+
const isHomebrew = (path) => path !== void 0 && (path.includes("/homebrew/") || path.includes("/Cellar/"));
|
|
65754
|
+
const OBSERVE = [
|
|
65755
|
+
"if command -v vp >/dev/null 2>&1; then",
|
|
65756
|
+
` ff_v=$(command vp --version 2>/dev/null | sed -n 's/^vp v\\{0,1\\}\\([^ ]*\\).*/\\1/p' | head -n 1)`,
|
|
65757
|
+
` ff_state "{\\"provider\\":\\"vp\\",\\"fact\\":\\"vp\\",\\"version\\":\\"$(ff_json "$ff_v")\\",\\"path\\":\\"$(ff_json "$(command -v vp)")\\"}"`,
|
|
65758
|
+
" if command vp env doctor 2>/dev/null | grep -q 'system-first mode'; then ff_m=system-first; else ff_m=managed; fi",
|
|
65759
|
+
` ff_state "{\\"provider\\":\\"vp\\",\\"fact\\":\\"mode\\",\\"mode\\":\\"$ff_m\\"}"`,
|
|
65760
|
+
` command vp env default 2>/dev/null | sed -n -e 's/^Default Node.js version: /node /p' -e 's/^Default \\([a-z]*\\) version: /\\1 /p' | while read -r ff_t ff_n; do`,
|
|
65761
|
+
` ff_state "{\\"provider\\":\\"vp\\",\\"fact\\":\\"default\\",\\"tool\\":\\"$(ff_json "$ff_t")\\",\\"version\\":\\"$(ff_json "$ff_n")\\"}"`,
|
|
65762
|
+
" done",
|
|
65763
|
+
` ff_g=$(command vp list --global --json 2>/dev/null | tr -d '\\n')`,
|
|
65764
|
+
` ff_state "{\\"provider\\":\\"vp\\",\\"fact\\":\\"globals\\",\\"list\\":\${ff_g:-[]}}"`,
|
|
65765
|
+
"else",
|
|
65766
|
+
` ff_state '{"provider":"vp","fact":"vp","version":null}'`,
|
|
65767
|
+
"fi"
|
|
65768
|
+
].join("\n");
|
|
65769
|
+
const decideSelf = (item, installed, self) => {
|
|
65770
|
+
const at = installed === void 0 ? {} : { at: installed };
|
|
65771
|
+
if (installed === void 0 || import_semver.lt(installed, self)) return {
|
|
65772
|
+
kind: "change",
|
|
65773
|
+
item,
|
|
65774
|
+
...installed === void 0 ? {} : { from: installed },
|
|
65775
|
+
to: self,
|
|
65776
|
+
change: {
|
|
65777
|
+
kind: "global",
|
|
65778
|
+
name: item,
|
|
65779
|
+
version: self
|
|
65780
|
+
}
|
|
65781
|
+
};
|
|
65782
|
+
if (import_semver.gt(installed, self)) return {
|
|
65783
|
+
kind: "fail",
|
|
65784
|
+
item,
|
|
65785
|
+
...at,
|
|
65786
|
+
reason: `runs ${SELF_PACKAGE} ${installed}, newer than this ${self}; upgrade here first`
|
|
65787
|
+
};
|
|
65788
|
+
return {
|
|
65789
|
+
kind: "leave",
|
|
65790
|
+
item,
|
|
65791
|
+
...at
|
|
65792
|
+
};
|
|
65793
|
+
};
|
|
65794
|
+
const MODE_SUBJECT = address("vp", "mode");
|
|
65795
|
+
const NOT_MANAGED = "needs managed mode";
|
|
65796
|
+
const decideMode = (observed, ctx) => {
|
|
65797
|
+
if (observed.vp !== void 0 && observed.mode !== "system-first") return {
|
|
65798
|
+
kind: "leave",
|
|
65799
|
+
item: "mode",
|
|
65800
|
+
at: "managed"
|
|
65801
|
+
};
|
|
65802
|
+
const from = observed.mode === void 0 ? {} : { from: observed.mode };
|
|
65803
|
+
const answer = observed.vp === void 0 ? "managed" : ctx.answer("mode", MODE_SUBJECT);
|
|
65804
|
+
if (answer === "managed") return {
|
|
65805
|
+
kind: "change",
|
|
65806
|
+
item: "mode",
|
|
65807
|
+
...from,
|
|
65808
|
+
to: "managed",
|
|
65809
|
+
change: { kind: "mode" }
|
|
65810
|
+
};
|
|
65811
|
+
if (answer === "skip") return {
|
|
65812
|
+
kind: "skip",
|
|
65813
|
+
item: "mode",
|
|
65814
|
+
at: "system-first",
|
|
65815
|
+
reason: NOT_MANAGED
|
|
65816
|
+
};
|
|
65817
|
+
return {
|
|
65818
|
+
kind: "ask",
|
|
65819
|
+
item: "mode",
|
|
65820
|
+
at: "system-first",
|
|
65821
|
+
question: {
|
|
65822
|
+
kind: "mode",
|
|
65823
|
+
subject: MODE_SUBJECT,
|
|
65824
|
+
found: "system-first",
|
|
65825
|
+
problem: NOT_MANAGED,
|
|
65826
|
+
choices: [{
|
|
65827
|
+
value: "managed",
|
|
65828
|
+
title: "switch to managed mode"
|
|
65829
|
+
}, {
|
|
65830
|
+
value: "skip",
|
|
65831
|
+
title: "skip Node and package managers on these Machines"
|
|
65832
|
+
}],
|
|
65833
|
+
default: "skip"
|
|
65834
|
+
}
|
|
65835
|
+
};
|
|
65836
|
+
};
|
|
65837
|
+
const decideRanged = (item, observed, resolved, ctx) => {
|
|
65838
|
+
const installed = item.kind === "vp" ? observed.vp?.version : item.kind === "default" ? observed.defaults.get(item.name) : observed.globals.get(item.name)?.version;
|
|
65839
|
+
const decision = decideRangeItem({
|
|
65840
|
+
provider: "vp",
|
|
65841
|
+
item: item.name,
|
|
65842
|
+
range: item.range,
|
|
65843
|
+
installed,
|
|
65844
|
+
available: item.packages.flatMap((p) => resolved[p] ?? []),
|
|
65845
|
+
bumpPath: item.bumpPath,
|
|
65846
|
+
ctx
|
|
65847
|
+
});
|
|
65848
|
+
if (item.kind === "vp" && observed.vp === void 0) {
|
|
65849
|
+
if (decision.kind === "change") return {
|
|
65850
|
+
...decision,
|
|
65851
|
+
change: {
|
|
65852
|
+
kind: "bootstrap",
|
|
65853
|
+
version: decision.change
|
|
65854
|
+
}
|
|
65855
|
+
};
|
|
65856
|
+
if (decision.kind === "fail" && (item.range === "*" || item.range === "latest")) return {
|
|
65857
|
+
kind: "change",
|
|
65858
|
+
item: item.name,
|
|
65859
|
+
to: "latest",
|
|
65860
|
+
change: { kind: "bootstrap" }
|
|
65861
|
+
};
|
|
65862
|
+
return decision;
|
|
65863
|
+
}
|
|
65864
|
+
if (decision.kind !== "change") return decision;
|
|
65865
|
+
const version = decision.change;
|
|
65866
|
+
if (item.kind === "vp" && isHomebrew(observed.vp?.path)) return {
|
|
65867
|
+
kind: "fail",
|
|
65868
|
+
item: item.name,
|
|
65869
|
+
...installed === void 0 ? {} : { at: installed },
|
|
65870
|
+
reason: `vp ${installed} was installed with Homebrew; run brew upgrade vite-plus to get ${version}`
|
|
65871
|
+
};
|
|
65872
|
+
const change = item.kind === "vp" ? {
|
|
65873
|
+
kind: "upgrade",
|
|
65874
|
+
version
|
|
65875
|
+
} : item.kind === "default" ? {
|
|
65876
|
+
kind: "default",
|
|
65877
|
+
tool: item.name,
|
|
65878
|
+
version
|
|
65879
|
+
} : {
|
|
65880
|
+
kind: "global",
|
|
65881
|
+
name: item.name,
|
|
65882
|
+
version
|
|
65883
|
+
};
|
|
65884
|
+
return {
|
|
65885
|
+
...decision,
|
|
65886
|
+
change
|
|
65887
|
+
};
|
|
65888
|
+
};
|
|
65889
|
+
//#endregion
|
|
65890
|
+
//#region ../../packages/providers/src/index.ts
|
|
65891
|
+
const PROVIDERS = [
|
|
65892
|
+
{
|
|
65893
|
+
name: "vp",
|
|
65894
|
+
rule: "range",
|
|
65895
|
+
dependsOn: [],
|
|
65896
|
+
items(section, listed) {
|
|
65897
|
+
const globals = listed.map(({ name, def, path }) => ({
|
|
65898
|
+
name,
|
|
65899
|
+
kind: "global",
|
|
65900
|
+
packages: [name],
|
|
65901
|
+
range: def.range,
|
|
65902
|
+
bumpPath: [...path, "range"]
|
|
65903
|
+
}));
|
|
65904
|
+
const defaults = ["node", ...PACKAGE_MANAGERS].flatMap((tool) => {
|
|
65905
|
+
const range = section?.[tool];
|
|
65906
|
+
return range === void 0 ? [] : [{
|
|
65907
|
+
name: tool,
|
|
65908
|
+
kind: "default",
|
|
65909
|
+
packages: TOOL_PACKAGES[tool],
|
|
65910
|
+
range,
|
|
65911
|
+
bumpPath: ["vp", tool]
|
|
65912
|
+
}];
|
|
65913
|
+
});
|
|
65914
|
+
return [
|
|
65915
|
+
{
|
|
65916
|
+
name: "vp",
|
|
65917
|
+
kind: "vp",
|
|
65918
|
+
packages: [VP_PACKAGE],
|
|
65919
|
+
range: section?.version ?? "*",
|
|
65920
|
+
bumpPath: ["vp", "version"]
|
|
65921
|
+
},
|
|
65922
|
+
{
|
|
65923
|
+
name: "mode",
|
|
65924
|
+
kind: "mode"
|
|
65925
|
+
},
|
|
65926
|
+
...defaults,
|
|
65927
|
+
...globals,
|
|
65928
|
+
{
|
|
65929
|
+
name: SELF_PACKAGE,
|
|
65930
|
+
kind: "self"
|
|
65931
|
+
}
|
|
65932
|
+
];
|
|
65933
|
+
},
|
|
65934
|
+
observe: () => OBSERVE,
|
|
65935
|
+
parse(facts) {
|
|
65936
|
+
let vpFact;
|
|
65937
|
+
let mode;
|
|
65938
|
+
const defaults = /* @__PURE__ */ new Map();
|
|
65939
|
+
let globals = [];
|
|
65940
|
+
for (const raw of facts) {
|
|
65941
|
+
const fact = decodeFact(raw);
|
|
65942
|
+
if (fact._tag === "None") continue;
|
|
65943
|
+
const f = fact.value;
|
|
65944
|
+
if (f.fact === "vp" && f.version !== null) vpFact = {
|
|
65945
|
+
version: f.version,
|
|
65946
|
+
...f.path === void 0 ? {} : { path: f.path }
|
|
65947
|
+
};
|
|
65948
|
+
else if (f.fact === "mode") mode = f.mode;
|
|
65949
|
+
else if (f.fact === "default") defaults.set(f.tool, f.version);
|
|
65950
|
+
else if (f.fact === "globals") globals = f.list;
|
|
65951
|
+
}
|
|
65952
|
+
if (vpFact === void 0) return {
|
|
65953
|
+
defaults: /* @__PURE__ */ new Map(),
|
|
65954
|
+
globals: /* @__PURE__ */ new Map()
|
|
65955
|
+
};
|
|
65956
|
+
return {
|
|
65957
|
+
vp: vpFact,
|
|
65958
|
+
...mode === void 0 ? {} : { mode },
|
|
65959
|
+
defaults,
|
|
65960
|
+
globals: new Map(globals.map((g) => [g.name, g]))
|
|
65961
|
+
};
|
|
65962
|
+
},
|
|
65963
|
+
resolve: (items) => resolveVersions(items.flatMap((item) => "packages" in item ? item.packages : [])),
|
|
65964
|
+
decide({ items, observed, resolved, ctx }) {
|
|
65965
|
+
const mode = decideMode(observed, ctx);
|
|
65966
|
+
const managed = mode.kind === "leave" || mode.kind === "change";
|
|
65967
|
+
const decisions = items.map((item) => {
|
|
65968
|
+
switch (item.kind) {
|
|
65969
|
+
case "mode": return mode;
|
|
65970
|
+
case "self": return decideSelf(item.name, observed.globals.get(item.name)?.version, ctx.self);
|
|
65971
|
+
case "default":
|
|
65972
|
+
if (!managed) {
|
|
65973
|
+
const at = observed.defaults.get(item.name);
|
|
65974
|
+
return {
|
|
65975
|
+
kind: "skip",
|
|
65976
|
+
item: item.name,
|
|
65977
|
+
...at === void 0 ? {} : { at },
|
|
65978
|
+
reason: NOT_MANAGED
|
|
65979
|
+
};
|
|
65980
|
+
}
|
|
65981
|
+
return decideRanged(item, observed, resolved, ctx);
|
|
65982
|
+
default: return decideRanged(item, observed, resolved, ctx);
|
|
65983
|
+
}
|
|
65984
|
+
});
|
|
65985
|
+
const nodeChange = decisions.find((d) => d.kind === "change" && d.change.kind === "default" && d.change.tool === "node");
|
|
65986
|
+
const nodeDefault = nodeChange?.kind === "change" ? nodeChange.to : observed.defaults.get("node");
|
|
65987
|
+
return decisions.map((d, i) => {
|
|
65988
|
+
const item = items[i];
|
|
65989
|
+
const current = observed.globals.get(d.item);
|
|
65990
|
+
const node = current?.platform?.node;
|
|
65991
|
+
if (d.kind !== "leave" || item === void 0 || item.kind !== "global" && item.kind !== "self" || current === void 0 || node === void 0 || nodeDefault === void 0 || node === nodeDefault) return d;
|
|
65992
|
+
return {
|
|
65993
|
+
kind: "change",
|
|
65994
|
+
item: d.item,
|
|
65995
|
+
from: current.version,
|
|
65996
|
+
to: current.version,
|
|
65997
|
+
reason: `Node ${node} → ${nodeDefault}`,
|
|
65998
|
+
change: {
|
|
65999
|
+
kind: "reinstall",
|
|
66000
|
+
name: d.item,
|
|
66001
|
+
version: current.version
|
|
66002
|
+
}
|
|
66003
|
+
};
|
|
66004
|
+
});
|
|
66005
|
+
},
|
|
66006
|
+
act(decisions) {
|
|
66007
|
+
const changes = decisions.flatMap((d) => d.kind === "change" ? [d.change] : []);
|
|
66008
|
+
const steps = [];
|
|
66009
|
+
for (const change of changes) switch (change.kind) {
|
|
66010
|
+
case "bootstrap":
|
|
66011
|
+
steps.push({
|
|
66012
|
+
id: "vp:vp:install",
|
|
66013
|
+
items: ["vp"],
|
|
66014
|
+
doing: "installing",
|
|
66015
|
+
run: [change.version === void 0 ? VP_INSTALL : `${VP_INSTALL} && command vp upgrade ${quote(change.version)}`]
|
|
66016
|
+
});
|
|
66017
|
+
break;
|
|
66018
|
+
case "upgrade":
|
|
66019
|
+
steps.push({
|
|
66020
|
+
id: "vp:vp:upgrade",
|
|
66021
|
+
items: ["vp"],
|
|
66022
|
+
doing: "upgrading",
|
|
66023
|
+
run: [`( command vp upgrade ${quote(change.version)} )`]
|
|
66024
|
+
});
|
|
66025
|
+
break;
|
|
66026
|
+
case "mode":
|
|
66027
|
+
steps.push({
|
|
66028
|
+
id: "vp:mode:on",
|
|
66029
|
+
items: ["mode"],
|
|
66030
|
+
doing: "switching",
|
|
66031
|
+
run: ["( command vp env on )"]
|
|
66032
|
+
});
|
|
66033
|
+
break;
|
|
66034
|
+
case "default":
|
|
66035
|
+
steps.push({
|
|
66036
|
+
id: `vp:${change.tool}:default`,
|
|
66037
|
+
items: [change.tool],
|
|
66038
|
+
doing: "installing",
|
|
66039
|
+
run: [`( command vp env default ${quote(change.tool === "node" ? change.version : `${change.tool}@${change.version}`)} )`]
|
|
66040
|
+
});
|
|
66041
|
+
break;
|
|
66042
|
+
case "reinstall": steps.push({
|
|
66043
|
+
id: `vp:${change.name}:reinstall`,
|
|
66044
|
+
items: [change.name],
|
|
66045
|
+
doing: "reinstalling",
|
|
66046
|
+
run: [`( command vp install -g ${quote(`${change.name}@${change.version}`)} )`]
|
|
66047
|
+
});
|
|
66048
|
+
}
|
|
66049
|
+
const installs = changes.flatMap((c) => c.kind === "global" ? [c] : []);
|
|
66050
|
+
if (installs.length > 0) steps.push({
|
|
66051
|
+
id: "vp:globals:install",
|
|
66052
|
+
items: installs.map((c) => c.name),
|
|
66053
|
+
doing: "installing",
|
|
66054
|
+
run: [`( command vp install -g ${installs.map((c) => quote(`${c.name}@${c.version}`)).join(" ")} )`]
|
|
66055
|
+
});
|
|
66056
|
+
return steps;
|
|
66057
|
+
}
|
|
66058
|
+
},
|
|
66059
|
+
brew,
|
|
66060
|
+
cask,
|
|
66061
|
+
repos
|
|
66062
|
+
];
|
|
65190
66063
|
//#endregion
|
|
65191
66064
|
//#region src/live.tsx
|
|
65192
66065
|
const cell = (initial) => {
|
|
@@ -65272,6 +66145,7 @@ const noLive = { ask: void 0 };
|
|
|
65272
66145
|
const canRedraw = () => Boolean(process.stdout.isTTY) && process.env.TERM !== "dumb";
|
|
65273
66146
|
//#endregion
|
|
65274
66147
|
//#region src/machine.ts
|
|
66148
|
+
const decodeAt = decodeUnknownOption(AtFact);
|
|
65275
66149
|
const runOn = fn("runOn")(function* (target, script, secrets, onLine, ledger) {
|
|
65276
66150
|
let first;
|
|
65277
66151
|
const run = yield* runScript(target, script, secrets, (line) => {
|
|
@@ -65341,10 +66215,17 @@ const apply = fn("apply")(function* (target, p, script, secrets, ledger) {
|
|
|
65341
66215
|
});
|
|
65342
66216
|
break;
|
|
65343
66217
|
}
|
|
66218
|
+
case "skip":
|
|
66219
|
+
yield* ledger.stepSkipped(target.name, line.skip.id, line.skip.reason);
|
|
66220
|
+
break;
|
|
65344
66221
|
case "text":
|
|
65345
66222
|
if (line.text.trim() !== "") (current?.output ?? head).push(line.text.trimEnd());
|
|
65346
66223
|
break;
|
|
65347
|
-
case "state":
|
|
66224
|
+
case "state": {
|
|
66225
|
+
const at = decodeAt(line.fact);
|
|
66226
|
+
if (at._tag === "Some") yield* ledger.reached(target.name, address(at.value.provider, at.value.item), at.value.at);
|
|
66227
|
+
break;
|
|
66228
|
+
}
|
|
65348
66229
|
}
|
|
65349
66230
|
}), ledger);
|
|
65350
66231
|
const finish = fn("finish")(function* (outcome) {
|
|
@@ -65365,43 +66246,63 @@ const apply = fn("apply")(function* (target, p, script, secrets, ledger) {
|
|
|
65365
66246
|
yield* ledger.fail(target.name, ["apply did not finish", ...head]);
|
|
65366
66247
|
return yield* finish("failed");
|
|
65367
66248
|
}
|
|
65368
|
-
|
|
66249
|
+
const planFailed = p.providers.some((pp) => pp.decisions.some((d) => d.kind === "fail"));
|
|
66250
|
+
return yield* finish(failed.length > 0 || planFailed ? "failed" : "ok");
|
|
65369
66251
|
});
|
|
65370
66252
|
//#endregion
|
|
65371
66253
|
//#region src/questions.ts
|
|
65372
|
-
const
|
|
65373
|
-
const
|
|
65374
|
-
const
|
|
65375
|
-
|
|
65376
|
-
|
|
65377
|
-
|
|
65378
|
-
const
|
|
65379
|
-
|
|
65380
|
-
const
|
|
65381
|
-
|
|
65382
|
-
|
|
65383
|
-
|
|
65384
|
-
|
|
65385
|
-
|
|
65386
|
-
|
|
65387
|
-
|
|
65388
|
-
|
|
65389
|
-
|
|
65390
|
-
|
|
65391
|
-
|
|
65392
|
-
|
|
65393
|
-
|
|
65394
|
-
|
|
65395
|
-
|
|
65396
|
-
|
|
65397
|
-
|
|
65398
|
-
|
|
65399
|
-
|
|
65400
|
-
|
|
65401
|
-
|
|
65402
|
-
|
|
66254
|
+
const parseAnswers = (raw) => {
|
|
66255
|
+
const given = /* @__PURE__ */ new Map();
|
|
66256
|
+
for (const entry of raw) {
|
|
66257
|
+
const at = entry.lastIndexOf("=");
|
|
66258
|
+
const key = entry.slice(0, at);
|
|
66259
|
+
const choice = entry.slice(at + 1);
|
|
66260
|
+
const kind = key.split(":")[0] ?? "";
|
|
66261
|
+
if (at <= 0 || !isQuestionKind(kind)) return { invalid: `--answer ${entry}: expected kind=choice or kind:subject=choice, kind one of ${Object.keys(QUESTION_CHOICES).join(", ")}` };
|
|
66262
|
+
const choices = QUESTION_CHOICES[kind];
|
|
66263
|
+
if (!choices.includes(choice)) return { invalid: `--answer ${entry}: ${kind} takes ${choices.join(", ")}` };
|
|
66264
|
+
given.set(key, choice);
|
|
66265
|
+
}
|
|
66266
|
+
return { answer: (kind, subject) => given.get(`${kind}:${subject}`) ?? given.get(kind) };
|
|
66267
|
+
};
|
|
66268
|
+
const newestOf = (found) => found.toSorted((a, b) => b.localeCompare(a, void 0, { numeric: true }))[0] ?? "";
|
|
66269
|
+
const askQuestions = fn("askQuestions")(function* (input) {
|
|
66270
|
+
const groups = Map.groupBy(input.asked, (a) => `${a.question.kind}:${a.question.subject}`);
|
|
66271
|
+
const answered = [];
|
|
66272
|
+
for (const group of groups.values()) {
|
|
66273
|
+
const question = group[0]?.question;
|
|
66274
|
+
if (question === void 0) continue;
|
|
66275
|
+
const bumps = [...Map.groupBy(group.flatMap(({ question: q }) => q.bump === void 0 ? [] : [{
|
|
66276
|
+
...q.bump,
|
|
66277
|
+
found: q.found
|
|
66278
|
+
}]), (bump) => JSON.stringify(bump.path)).values()].flatMap((list) => {
|
|
66279
|
+
const first = list[0];
|
|
66280
|
+
return first === void 0 ? [] : [{
|
|
66281
|
+
path: first.path,
|
|
66282
|
+
range: first.range,
|
|
66283
|
+
newest: newestOf(list.map((b) => b.found))
|
|
66284
|
+
}];
|
|
66285
|
+
});
|
|
66286
|
+
const where = [...Map.groupBy(group, (a) => a.question.problem)].map(([problem, list]) => `${list.map((a) => `${a.question.found} on ${a.machine}`).join(", ")} ${problem}`).join("; ");
|
|
66287
|
+
yield* input.ledger.note("ask", `${question.subject} ${where}`);
|
|
66288
|
+
if (input.dryRun) {
|
|
66289
|
+
yield* input.ledger.note("answer", "not asked (dry run)");
|
|
66290
|
+
continue;
|
|
66291
|
+
}
|
|
66292
|
+
const choices = question.choices.map((c) => ({
|
|
66293
|
+
value: c.value,
|
|
66294
|
+
title: c.value === "bump" && bumps.length > 0 ? `bump the config to ${bumps.map((b) => bumpedRange(b.range, b.newest)).join(" and ")}` : c.title
|
|
66295
|
+
}));
|
|
66296
|
+
const answer = input.answer(question.kind, question.subject) ?? (input.ask === void 0 ? question.default : yield* input.ask(choices));
|
|
66297
|
+
yield* input.ledger.note("answer", choices.find((c) => c.value === answer)?.title ?? answer);
|
|
66298
|
+
answered.push({
|
|
66299
|
+
question,
|
|
66300
|
+
machines: group.map((a) => a.machine),
|
|
66301
|
+
bumps,
|
|
66302
|
+
answer
|
|
66303
|
+
});
|
|
65403
66304
|
}
|
|
65404
|
-
return
|
|
66305
|
+
return answered;
|
|
65405
66306
|
});
|
|
65406
66307
|
//#endregion
|
|
65407
66308
|
//#region src/ship.ts
|
|
@@ -65411,23 +66312,20 @@ var ShipError = class extends Error {
|
|
|
65411
66312
|
const unknownMachines = (config, tailnet, only) => {
|
|
65412
66313
|
const known = new Set(tailnet.fleet.map((m) => m.name));
|
|
65413
66314
|
const referenced = [
|
|
65414
|
-
...
|
|
65415
|
-
...
|
|
65416
|
-
...config.vp?.machines ?? [],
|
|
66315
|
+
...config.machines,
|
|
66316
|
+
...PROVIDERS.flatMap((p) => machinesNamed(p, config)),
|
|
65417
66317
|
...only
|
|
65418
66318
|
];
|
|
65419
66319
|
return [...new Set(referenced.filter((name) => !known.has(name)))];
|
|
65420
66320
|
};
|
|
65421
|
-
const
|
|
65422
|
-
const
|
|
65423
|
-
if (
|
|
65424
|
-
|
|
65425
|
-
|
|
65426
|
-
|
|
65427
|
-
|
|
65428
|
-
];
|
|
66321
|
+
const unshippable = (config, tailnet, only, source) => {
|
|
66322
|
+
const unknown = unknownMachines(config, tailnet, only);
|
|
66323
|
+
if (unknown.length > 0) return `unknown Machine: ${unknown.join(", ")} (the tailnet has: ${tailnet.fleet.map((m) => m.name).join(", ")})`;
|
|
66324
|
+
const fleet = new Set(config.machines);
|
|
66325
|
+
if (!fleet.has(tailnet.self.name)) return `this Machine (${tailnet.self.name}) is not in machines in ${source}`;
|
|
66326
|
+
const outsideFleet = only.filter((name) => !fleet.has(name));
|
|
66327
|
+
if (outsideFleet.length > 0) return `not in machines in ${source}: ${outsideFleet.join(", ")}`;
|
|
65429
66328
|
};
|
|
65430
|
-
const rebuildOf = (flags) => flags.rebuild.length === 0 ? "none" : flags.rebuild.includes("all") ? "all" : flags.rebuild;
|
|
65431
66329
|
const staleConfigs = fn("staleConfigs")(function* (config, own, checked, ledger) {
|
|
65432
66330
|
const copies = [];
|
|
65433
66331
|
for (const { machine, state } of checked) {
|
|
@@ -65436,25 +66334,44 @@ const staleConfigs = fn("staleConfigs")(function* (config, own, checked, ledger)
|
|
|
65436
66334
|
if (parsed._tag === "Failure") yield* ledger.note("info", `the config on ${machine.name} does not parse; it will be overwritten`);
|
|
65437
66335
|
else copies.push({
|
|
65438
66336
|
machine: machine.name,
|
|
65439
|
-
config: parsed.success
|
|
66337
|
+
config: parsed.success,
|
|
66338
|
+
text: state.config
|
|
65440
66339
|
});
|
|
65441
66340
|
}
|
|
65442
|
-
return staleCopies(config, copies, own)
|
|
66341
|
+
return [...Map.groupBy(staleCopies(config, copies, own), (c) => c.text)].flatMap(([text, [first, ...rest]]) => {
|
|
66342
|
+
if (first === void 0) return [];
|
|
66343
|
+
const { config, machine } = first;
|
|
66344
|
+
const machines = [machine, ...rest.map((c) => c.machine)];
|
|
66345
|
+
return [{
|
|
66346
|
+
text,
|
|
66347
|
+
config,
|
|
66348
|
+
machines,
|
|
66349
|
+
description: `${machines.join(", ")} (shipped ${config.shippedAt} from ${config.shippedFrom ?? "unknown"})`
|
|
66350
|
+
}];
|
|
66351
|
+
});
|
|
65443
66352
|
});
|
|
65444
66353
|
const schemaJson = encodeSync(fromJsonString(Unknown, { space: 2 }));
|
|
65445
66354
|
const ship = fn("ship")(function* (flags) {
|
|
66355
|
+
while ((yield* shipPass(flags)) === "adopted");
|
|
66356
|
+
});
|
|
66357
|
+
const shipPass = fn("shipPass")(function* (flags) {
|
|
65446
66358
|
const fs = yield* FileSystem;
|
|
66359
|
+
const parsed = parseAnswers(flags.answers);
|
|
66360
|
+
if ("invalid" in parsed) return yield* fail$1(new ShipError(parsed.invalid));
|
|
66361
|
+
const given = parsed.answer;
|
|
66362
|
+
const notAddress = flags.rebuild.find((r) => r !== "all" && !PROVIDERS.some((p) => p.rule === "record" && p.name === parseAddress(r)?.provider));
|
|
66363
|
+
if (notAddress !== void 0) return yield* fail$1(new ShipError(`--rebuild ${notAddress}: expected a record Item (repos:<name>) or all`));
|
|
65447
66364
|
const path = flags.config ?? configPath(process.env);
|
|
65448
66365
|
const config = yield* loadConfig(path);
|
|
66366
|
+
const ordered = orderProviders(PROVIDERS, (p) => dependenciesOf(p, config));
|
|
66367
|
+
if ("cycle" in ordered) return yield* fail$1(new ShipError(`dependsOn cycle: ${ordered.cycle.join(" → ")}`));
|
|
66368
|
+
const providers = ordered.order;
|
|
65449
66369
|
const tailnet = yield* readTailnet();
|
|
65450
|
-
const
|
|
65451
|
-
if (
|
|
65452
|
-
const fleet = new Set(
|
|
66370
|
+
const problem = unshippable(config, tailnet, flags.only, path);
|
|
66371
|
+
if (problem !== void 0) return yield* fail$1(new ShipError(problem));
|
|
66372
|
+
const fleet = new Set(config.machines);
|
|
65453
66373
|
const own = flags.config === void 0 ? tailnet.self.name : void 0;
|
|
65454
|
-
|
|
65455
|
-
const outsideFleet = flags.only.filter((name) => !fleet.has(name));
|
|
65456
|
-
if (outsideFleet.length > 0) return yield* fail$1(new ShipError(`not in machines in ${path}: ${outsideFleet.join(", ")}`));
|
|
65457
|
-
const order = Object.keys(config.machines);
|
|
66374
|
+
const order = config.machines;
|
|
65458
66375
|
const targetsList = tailnet.fleet.filter((m) => fleet.has(m.name) && (flags.only.length === 0 || flags.only.includes(m.name))).toSorted((a, b) => order.indexOf(a.name) - order.indexOf(b.name));
|
|
65459
66376
|
const count = `${targetsList.length} machine${targetsList.length === 1 ? "" : "s"}`;
|
|
65460
66377
|
yield* log(`${flags.dryRun ? "dry run, " : ""}${count} from ${tailnet.self.name}`);
|
|
@@ -65467,8 +66384,10 @@ const ship = fn("ship")(function* (flags) {
|
|
|
65467
66384
|
});
|
|
65468
66385
|
const redraw = canRedraw();
|
|
65469
66386
|
let changing = false;
|
|
66387
|
+
let adopted = false;
|
|
65470
66388
|
const finish = fn("finish")(function* () {
|
|
65471
66389
|
const state = yield* ledger.end;
|
|
66390
|
+
if (adopted) return;
|
|
65472
66391
|
const saved = changing && (yield* saveReport(state).pipe(as(true), catch_((e) => error(`could not save the report for fizz report: ${e.message}`).pipe(as(false)))));
|
|
65473
66392
|
yield* log(ledgerText(state, redraw ? {
|
|
65474
66393
|
full: false,
|
|
@@ -65482,11 +66401,6 @@ const ship = fn("ship")(function* (flags) {
|
|
|
65482
66401
|
});
|
|
65483
66402
|
yield* addFinalizer(() => finish());
|
|
65484
66403
|
const live = redraw ? yield* startLive(store, color) : noLive;
|
|
65485
|
-
const cloneRootOf = (machine) => config.machines[machine.name]?.clones ?? "~/.local/share/fleetfizz/clones";
|
|
65486
|
-
const checkRepos = (config.repos ?? []).map((r) => ({
|
|
65487
|
-
name: repoName(r),
|
|
65488
|
-
outputs: r.outputs ?? []
|
|
65489
|
-
}));
|
|
65490
66404
|
const checked = yield* forEach$1(targetsList, fn("checkOne")(function* (machine) {
|
|
65491
66405
|
const local = machine.name === tailnet.self.name;
|
|
65492
66406
|
if (!machine.online) {
|
|
@@ -65497,9 +66411,19 @@ const ship = fn("ship")(function* (flags) {
|
|
|
65497
66411
|
yield* ledger.skip(machine.name, "no Tailscale SSH server");
|
|
65498
66412
|
return;
|
|
65499
66413
|
}
|
|
66414
|
+
const identity = {
|
|
66415
|
+
name: machine.name,
|
|
66416
|
+
platform: machine.platform
|
|
66417
|
+
};
|
|
65500
66418
|
const script = checkScript({
|
|
65501
|
-
|
|
65502
|
-
|
|
66419
|
+
scope: {
|
|
66420
|
+
machine: identity,
|
|
66421
|
+
config
|
|
66422
|
+
},
|
|
66423
|
+
providers: providers.map((provider) => ({
|
|
66424
|
+
provider,
|
|
66425
|
+
items: targetedItems(provider, config, identity)
|
|
66426
|
+
}))
|
|
65503
66427
|
});
|
|
65504
66428
|
const result = yield* check({
|
|
65505
66429
|
name: machine.name,
|
|
@@ -65515,58 +66439,105 @@ const ship = fn("ship")(function* (flags) {
|
|
|
65515
66439
|
}), { concurrency: "unbounded" }).pipe(map$5((list) => list.filter((g) => g !== void 0)));
|
|
65516
66440
|
const stale = yield* staleConfigs(config, own, checked, ledger);
|
|
65517
66441
|
if (stale.length > 0) {
|
|
65518
|
-
const what = `newer config on ${stale.join(", ")}`;
|
|
66442
|
+
const what = `newer config on ${stale.map((s) => s.description).join(", ")}`;
|
|
66443
|
+
const answers = stale.flatMap((s) => s.machines).map((m) => given("config", m));
|
|
65519
66444
|
if (flags.dryRun) yield* ledger.note("info", `${what}; a Ship would ask before overwriting it`);
|
|
65520
|
-
else if (
|
|
66445
|
+
else if (answers.every((a) => a === "overwrite")) yield* ledger.note("info", `${what}; overwriting it, as answered`);
|
|
66446
|
+
else if (answers.includes("stop")) return yield* fail$1(new ShipError("aborted: the config here is older"));
|
|
65521
66447
|
else if (live.ask === void 0) return yield* fail$1(new ShipError(`${what}; copy it here first, or pass --overwrite-config`));
|
|
65522
66448
|
else {
|
|
66449
|
+
const usable = [];
|
|
66450
|
+
for (const s of stale) {
|
|
66451
|
+
const why = unshippable(s.config, tailnet, flags.only, `the config on ${s.machines[0]}`);
|
|
66452
|
+
if (why === void 0) usable.push(s);
|
|
66453
|
+
else yield* ledger.note("info", `cannot ship from here: ${why}`);
|
|
66454
|
+
}
|
|
65523
66455
|
yield* ledger.note("ask", what);
|
|
65524
|
-
const
|
|
65525
|
-
|
|
65526
|
-
|
|
65527
|
-
|
|
65528
|
-
|
|
65529
|
-
|
|
65530
|
-
|
|
65531
|
-
|
|
65532
|
-
|
|
66456
|
+
const choice = yield* live.ask([
|
|
66457
|
+
...usable.map((s) => ({
|
|
66458
|
+
title: `use the config on ${s.machines[0]} (replaces this one)`,
|
|
66459
|
+
value: s
|
|
66460
|
+
})),
|
|
66461
|
+
{
|
|
66462
|
+
title: "overwrite it with this Machine's config",
|
|
66463
|
+
value: "overwrite"
|
|
66464
|
+
},
|
|
66465
|
+
{
|
|
66466
|
+
title: "stop",
|
|
66467
|
+
value: "stop"
|
|
66468
|
+
}
|
|
66469
|
+
]);
|
|
66470
|
+
if (choice === "stop") {
|
|
66471
|
+
yield* ledger.note("answer", "stop");
|
|
66472
|
+
return yield* fail$1(new ShipError("aborted: the config here is older"));
|
|
66473
|
+
}
|
|
66474
|
+
if (choice === "overwrite") yield* ledger.note("answer", "overwrite it");
|
|
66475
|
+
else {
|
|
66476
|
+
yield* ledger.note("answer", `use the config on ${choice.machines[0]}`);
|
|
66477
|
+
yield* fs.writeFileString(path, choice.text);
|
|
66478
|
+
adopted = true;
|
|
66479
|
+
return "adopted";
|
|
66480
|
+
}
|
|
65533
66481
|
}
|
|
65534
66482
|
}
|
|
65535
|
-
const
|
|
65536
|
-
|
|
66483
|
+
const targeted = providers.map((provider) => ({
|
|
66484
|
+
provider,
|
|
66485
|
+
items: checked.flatMap(({ machine }) => targetedItems(provider, config, machine))
|
|
66486
|
+
}));
|
|
66487
|
+
const lent = targeted.some(({ provider, items }) => provider.name === "repos" && items.length > 0) ? yield* readLentToken() : { token: void 0 };
|
|
66488
|
+
if (lent.token === void 0 && lent.reason !== void 0) yield* ledger.note("info", `no gh token (${lent.reason}); private repos will fail`);
|
|
66489
|
+
const resolved = Object.fromEntries(yield* forEach$1(targeted, ({ provider, items }) => provider.resolve(items, lent.token === void 0 ? {} : { token: lent.token }).pipe(map$5((r) => [provider.name, r])), { concurrency: "unbounded" }));
|
|
66490
|
+
const planAll = (cfg, answer) => checked.map((g) => ({
|
|
65537
66491
|
...g,
|
|
65538
|
-
plan:
|
|
65539
|
-
|
|
65540
|
-
machine: {
|
|
65541
|
-
name: g.machine.name,
|
|
65542
|
-
platform: g.machine.platform
|
|
65543
|
-
},
|
|
66492
|
+
plan: planMachine({
|
|
66493
|
+
providers,
|
|
65544
66494
|
state: g.state,
|
|
65545
|
-
|
|
65546
|
-
|
|
65547
|
-
|
|
65548
|
-
|
|
66495
|
+
resolved,
|
|
66496
|
+
ctx: {
|
|
66497
|
+
machine: {
|
|
66498
|
+
name: g.machine.name,
|
|
66499
|
+
platform: g.machine.platform
|
|
66500
|
+
},
|
|
66501
|
+
config: cfg,
|
|
66502
|
+
self: flags.version,
|
|
66503
|
+
rebuild: (address) => flags.rebuild.includes("all") || flags.rebuild.includes(address),
|
|
66504
|
+
answer
|
|
66505
|
+
}
|
|
65549
66506
|
})
|
|
65550
66507
|
}));
|
|
65551
66508
|
let cfg = config;
|
|
65552
|
-
|
|
65553
|
-
const
|
|
65554
|
-
|
|
65555
|
-
|
|
65556
|
-
|
|
65557
|
-
|
|
65558
|
-
|
|
65559
|
-
|
|
65560
|
-
|
|
65561
|
-
|
|
65562
|
-
|
|
65563
|
-
|
|
65564
|
-
|
|
65565
|
-
|
|
65566
|
-
|
|
65567
|
-
|
|
65568
|
-
|
|
65569
|
-
|
|
66509
|
+
const decided = /* @__PURE__ */ new Map();
|
|
66510
|
+
const answer = (kind, subject) => decided.get(`${kind}:${subject}`) ?? given(kind, subject);
|
|
66511
|
+
let planned = planAll(cfg, answer);
|
|
66512
|
+
for (;;) {
|
|
66513
|
+
const asked = planned.flatMap((g) => g.plan.providers.flatMap((pp) => pp.decisions.flatMap((d) => d.kind === "ask" ? [{
|
|
66514
|
+
machine: g.machine.name,
|
|
66515
|
+
question: d.question
|
|
66516
|
+
}] : [])));
|
|
66517
|
+
const answered = yield* askQuestions({
|
|
66518
|
+
asked,
|
|
66519
|
+
answer,
|
|
66520
|
+
ledger,
|
|
66521
|
+
ask: live.ask,
|
|
66522
|
+
dryRun: flags.dryRun
|
|
66523
|
+
});
|
|
66524
|
+
let progressed = false;
|
|
66525
|
+
for (const { question, bumps, answer: choice } of answered) {
|
|
66526
|
+
const key = `${question.kind}:${question.subject}`;
|
|
66527
|
+
progressed ||= !decided.has(key);
|
|
66528
|
+
decided.set(key, choice);
|
|
66529
|
+
if (choice !== "bump") continue;
|
|
66530
|
+
for (const bump of bumps) {
|
|
66531
|
+
changing = true;
|
|
66532
|
+
const range = yield* bumpConfig(path, bump.path, bump.newest);
|
|
66533
|
+
progressed ||= range !== bump.range;
|
|
66534
|
+
}
|
|
66535
|
+
if (bumps.length > 0) cfg = yield* loadConfig(path);
|
|
66536
|
+
}
|
|
66537
|
+
if (!progressed) break;
|
|
66538
|
+
planned = planAll(cfg, answer);
|
|
66539
|
+
}
|
|
66540
|
+
for (const { machine, plan: p } of planned) yield* ledger.plan(machine.name, p);
|
|
65570
66541
|
if (flags.dryRun) return;
|
|
65571
66542
|
const shippedAt = formatIso(yield* now);
|
|
65572
66543
|
changing = true;
|
|
@@ -65580,44 +66551,36 @@ const ship = fn("ship")(function* (flags) {
|
|
|
65580
66551
|
const stamped = stampWith(planned.map((g) => g.machine.name));
|
|
65581
66552
|
yield* fs.writeFileString(path, stamped);
|
|
65582
66553
|
const schema = `${schemaJson(fleetConfigJsonSchema())}\n`;
|
|
65583
|
-
const lent = planned.some((g) => g.plan.repos.length > 0) ? yield* readLentToken() : { token: void 0 };
|
|
65584
|
-
if (lent.token === void 0 && lent.reason !== void 0) yield* ledger.note("info", `no gh token (${lent.reason}); private repos will fail`);
|
|
65585
|
-
const machineNames = [...fleet];
|
|
65586
66554
|
const stdin = applyStdin(lent.token, stamped, schema);
|
|
65587
66555
|
const delivered = yield* forEach$1(planned, fn("applyOne")(function* ({ machine, local, plan: p }) {
|
|
65588
|
-
const script = applyScript({
|
|
65589
|
-
plan: p,
|
|
65590
|
-
cloneRoot: cloneRootOf(machine),
|
|
65591
|
-
env: {
|
|
65592
|
-
machine: machine.name,
|
|
65593
|
-
platform: machine.platform,
|
|
65594
|
-
machines: machineNames
|
|
65595
|
-
}
|
|
65596
|
-
});
|
|
65597
66556
|
return (yield* apply({
|
|
65598
66557
|
name: machine.name,
|
|
65599
66558
|
local
|
|
65600
|
-
}, p,
|
|
66559
|
+
}, p, applyScript(p), stdin, ledger)).done.includes("config") ? machine.name : void 0;
|
|
65601
66560
|
}), { concurrency: "unbounded" }).pipe(map$5((list) => list.filter((name) => name !== void 0)));
|
|
65602
66561
|
yield* fs.writeFileString(path, stampWith(delivered));
|
|
65603
66562
|
}, scoped);
|
|
65604
66563
|
//#endregion
|
|
65605
|
-
//#region src/
|
|
66564
|
+
//#region src/command.ts
|
|
65606
66565
|
const shipCommand = make("ship", {
|
|
65607
66566
|
dryRun: Boolean$1("dry-run").pipe(withDefault(false), withDescription$1("Check and plan only. Print every Machine's plan and change nothing.")),
|
|
65608
|
-
only: String$1("only").pipe(atLeast(0), withDescription$1("Ship only to
|
|
65609
|
-
rebuild: String$1("rebuild").pipe(atLeast(0), withDescription$1("
|
|
65610
|
-
|
|
65611
|
-
|
|
65612
|
-
|
|
65613
|
-
|
|
66567
|
+
only: String$1("only").pipe(atLeast(0), withMetavar("machine"), withDescription$1("Ship only to this Machine. Repeat the flag for more.")),
|
|
66568
|
+
rebuild: String$1("rebuild").pipe(atLeast(0), withMetavar("item"), withDescription$1("Rebuild a record Item (`repos:<name>`) even when it is up to date. `all` for every one.")),
|
|
66569
|
+
answer: String$1("answer").pipe(atLeast(0), withMetavar("answer"), withDescription$1("Answer a Question in advance: `kind=choice` or `kind:subject=choice`. Repeat the flag for more.")),
|
|
66570
|
+
bump: Boolean$1("bump").pipe(withDefault(false), withDescription$1("Answer every above-range Question by bumping the config (`--answer range=bump`).")),
|
|
66571
|
+
enforce: Boolean$1("enforce").pipe(withDefault(false), withDescription$1("Answer every above-range Question by downgrading into the Range (`--answer range=downgrade`).")),
|
|
66572
|
+
overwriteConfig: Boolean$1("overwrite-config").pipe(withDefault(false), withDescription$1("Ship even when another Machine holds a newer config, overwriting it (`--answer config=overwrite`).")),
|
|
66573
|
+
config: String$1("config").pipe(optional, withMetavar("path"), withDescription$1("The config file. Default: `$XDG_CONFIG_HOME/fleetfizz/config.jsonc`."))
|
|
65614
66574
|
}).pipe(withDescription("Ship the config to every reachable Machine."), withHandler((flags) => ship({
|
|
65615
66575
|
dryRun: flags.dryRun,
|
|
65616
66576
|
only: flags.only,
|
|
65617
66577
|
rebuild: flags.rebuild,
|
|
65618
|
-
|
|
65619
|
-
|
|
65620
|
-
|
|
66578
|
+
answers: [
|
|
66579
|
+
...flags.answer,
|
|
66580
|
+
...flags.bump ? ["range=bump"] : [],
|
|
66581
|
+
...flags.enforce ? ["range=downgrade"] : [],
|
|
66582
|
+
...flags.overwriteConfig ? ["config=overwrite"] : []
|
|
66583
|
+
],
|
|
65621
66584
|
config: flags.config._tag === "Some" ? flags.config.value : void 0,
|
|
65622
66585
|
version
|
|
65623
66586
|
}).pipe(catch_((e) => gen(function* () {
|
|
@@ -65625,6 +66588,8 @@ const shipCommand = make("ship", {
|
|
|
65625
66588
|
process.exitCode = 1;
|
|
65626
66589
|
})))));
|
|
65627
66590
|
const reportCommand = make("report", {}).pipe(withDescription("Print the full Ledger of the last Ship from this Machine."), withHandler(() => report()));
|
|
66591
|
+
//#endregion
|
|
66592
|
+
//#region src/bin.ts
|
|
65628
66593
|
run(make("fizz").pipe(withDescription("Keep every Machine on your tailnet in line with one config."), withSubcommands([shipCommand, reportCommand])), { version }).pipe(provide(layer), runMain);
|
|
65629
66594
|
//#endregion
|
|
65630
66595
|
export {};
|