From a943771501506de56f1d481ccc2e119259fc9e98 Mon Sep 17 00:00:00 2001 From: Luc Perkins Date: Fri, 26 Apr 2024 11:37:43 -0300 Subject: [PATCH] Revamp logic into central class --- .eslintrc.json | 2 +- action.yml | 34 +- dist/index.js | 895 ++++++++++++++++++++++++---------------------- dist/index.js.map | 2 +- package.json | 2 +- pnpm-lock.yaml | 246 ++++++------- src/helpers.ts | 53 +++ src/index.ts | 536 +++++++++++++-------------- 8 files changed, 916 insertions(+), 854 deletions(-) create mode 100644 src/helpers.ts diff --git a/.eslintrc.json b/.eslintrc.json index 3e73697..6499d3b 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -33,7 +33,7 @@ "@typescript-eslint/array-type": "error", "@typescript-eslint/await-thenable": "error", "@typescript-eslint/ban-ts-comment": "error", - "camelcase": "off", + "camelcase": "error", "@typescript-eslint/consistent-type-assertions": "error", "@typescript-eslint/explicit-function-return-type": [ "error", diff --git a/action.yml b/action.yml index 527eb67..dc8006a 100644 --- a/action.yml +++ b/action.yml @@ -14,23 +14,6 @@ inputs: upstream-cache: description: Your preferred upstream cache. Store paths in this store will not be cached in GitHub Actions' cache. default: https://cache.nixos.org - source-binary: - description: Run a version of the cache binary from somewhere already on disk. Conflicts with all other `source-*` options. - source-branch: - description: The branch of `magic-nix-cache` to use. Conflicts with all other `source-*` options. - required: false - source-pr: - description: The PR of `magic-nix-cache` to use. Conflicts with all other `source-*` options. - required: false - source-revision: - description: The revision of `nix-magic-nix-cache` to use. Conflicts with all other `source-*` options. - required: false - source-tag: - description: The tag of `magic-nix-cache` to use. Conflicts with all other `source-*` options. - required: false - source-url: - description: A URL pointing to a `magic-nix-cache` binary. Overrides all other `source-*` options. - required: false diagnostic-endpoint: description: "Diagnostic endpoint url where diagnostics and performance data is sent. To disable set this to an empty string." default: "https://install.determinate.systems/magic-nix-cache/perf" @@ -51,6 +34,23 @@ inputs: startup-notification-port: description: "The port magic-nix-cache uses for daemon startup notification." default: 41239 + source-binary: + description: Run a version of the cache binary from somewhere already on disk. Conflicts with all other `source-*` options. + source-branch: + description: The branch of `magic-nix-cache` to use. Conflicts with all other `source-*` options. + required: false + source-pr: + description: The PR of `magic-nix-cache` to use. Conflicts with all other `source-*` options. + required: false + source-revision: + description: The revision of `nix-magic-nix-cache` to use. Conflicts with all other `source-*` options. + required: false + source-tag: + description: The tag of `magic-nix-cache` to use. Conflicts with all other `source-*` options. + required: false + source-url: + description: A URL pointing to a `magic-nix-cache` binary. Overrides all other `source-*` options. + required: false runs: using: "node20" diff --git a/dist/index.js b/dist/index.js index 6e010c4..734e062 100644 --- a/dist/index.js +++ b/dist/index.js @@ -86779,10 +86779,16 @@ var __webpack_exports__ = {}; // EXTERNAL MODULE: ./node_modules/.pnpm/@actions+core@1.10.1/node_modules/@actions/core/lib/core.js var core = __nccwpck_require__(9093); -;// CONCATENATED MODULE: external "node:fs" -const external_node_fs_namespaceObject = __WEBPACK_EXTERNAL_createRequire(import.meta.url)("node:fs"); +;// CONCATENATED MODULE: external "node:fs/promises" +const promises_namespaceObject = __WEBPACK_EXTERNAL_createRequire(import.meta.url)("node:fs/promises"); // EXTERNAL MODULE: external "node:os" var external_node_os_ = __nccwpck_require__(612); +;// CONCATENATED MODULE: external "node:path" +const external_node_path_namespaceObject = __WEBPACK_EXTERNAL_createRequire(import.meta.url)("node:path"); +// EXTERNAL MODULE: ./node_modules/.pnpm/tail@2.2.6/node_modules/tail/lib/tail.js +var tail = __nccwpck_require__(3707); +;// CONCATENATED MODULE: external "node:fs" +const external_node_fs_namespaceObject = __WEBPACK_EXTERNAL_createRequire(import.meta.url)("node:fs"); // EXTERNAL MODULE: external "node:util" var external_node_util_ = __nccwpck_require__(7261); // EXTERNAL MODULE: ./node_modules/.pnpm/@actions+exec@1.1.1/node_modules/@actions/exec/lib/exec.js @@ -86793,7 +86799,7 @@ var external_os_ = __nccwpck_require__(2037); const external_node_crypto_namespaceObject = __WEBPACK_EXTERNAL_createRequire(import.meta.url)("node:crypto"); // EXTERNAL MODULE: ./node_modules/.pnpm/@actions+cache@3.2.4/node_modules/@actions/cache/lib/cache.js var cache = __nccwpck_require__(6878); -;// CONCATENATED MODULE: ./node_modules/.pnpm/@sindresorhus+is@6.2.0/node_modules/@sindresorhus/is/dist/index.js +;// CONCATENATED MODULE: ./node_modules/.pnpm/@sindresorhus+is@6.3.0/node_modules/@sindresorhus/is/dist/index.js const typedArrayTypeNames = [ 'Int8Array', 'Uint8Array', @@ -87645,458 +87651,458 @@ function assertAny(predicate, ...values) { throw new TypeError(typeErrorMessageMultipleValues(expectedTypes, values)); } } -function assertArray(value, assertion) { +function assertArray(value, assertion, message) { if (!isArray(value)) { - throw new TypeError(typeErrorMessage('Array', value)); + throw new TypeError(message ?? typeErrorMessage('Array', value)); } if (assertion) { // eslint-disable-next-line unicorn/no-array-for-each, unicorn/no-array-callback-reference value.forEach(assertion); } } -function assertArrayBuffer(value) { +function assertArrayBuffer(value, message) { if (!isArrayBuffer(value)) { - throw new TypeError(typeErrorMessage('ArrayBuffer', value)); + throw new TypeError(message ?? typeErrorMessage('ArrayBuffer', value)); } } -function assertArrayLike(value) { +function assertArrayLike(value, message) { if (!isArrayLike(value)) { - throw new TypeError(typeErrorMessage('array-like', value)); + throw new TypeError(message ?? typeErrorMessage('array-like', value)); } } // eslint-disable-next-line @typescript-eslint/ban-types -function assertAsyncFunction(value) { +function assertAsyncFunction(value, message) { if (!isAsyncFunction(value)) { - throw new TypeError(typeErrorMessage('AsyncFunction', value)); + throw new TypeError(message ?? typeErrorMessage('AsyncFunction', value)); } } -function assertAsyncGenerator(value) { +function assertAsyncGenerator(value, message) { if (!isAsyncGenerator(value)) { - throw new TypeError(typeErrorMessage('AsyncGenerator', value)); + throw new TypeError(message ?? typeErrorMessage('AsyncGenerator', value)); } } -function assertAsyncGeneratorFunction(value) { +function assertAsyncGeneratorFunction(value, message) { if (!isAsyncGeneratorFunction(value)) { - throw new TypeError(typeErrorMessage('AsyncGeneratorFunction', value)); + throw new TypeError(message ?? typeErrorMessage('AsyncGeneratorFunction', value)); } } -function assertAsyncIterable(value) { +function assertAsyncIterable(value, message) { if (!isAsyncIterable(value)) { - throw new TypeError(typeErrorMessage('AsyncIterable', value)); + throw new TypeError(message ?? typeErrorMessage('AsyncIterable', value)); } } -function assertBigint(value) { +function assertBigint(value, message) { if (!isBigint(value)) { - throw new TypeError(typeErrorMessage('bigint', value)); + throw new TypeError(message ?? typeErrorMessage('bigint', value)); } } -function assertBigInt64Array(value) { +function assertBigInt64Array(value, message) { if (!isBigInt64Array(value)) { - throw new TypeError(typeErrorMessage('BigInt64Array', value)); + throw new TypeError(message ?? typeErrorMessage('BigInt64Array', value)); } } -function assertBigUint64Array(value) { +function assertBigUint64Array(value, message) { if (!isBigUint64Array(value)) { - throw new TypeError(typeErrorMessage('BigUint64Array', value)); + throw new TypeError(message ?? typeErrorMessage('BigUint64Array', value)); } } -function assertBlob(value) { +function assertBlob(value, message) { if (!isBlob(value)) { - throw new TypeError(typeErrorMessage('Blob', value)); + throw new TypeError(message ?? typeErrorMessage('Blob', value)); } } -function assertBoolean(value) { +function assertBoolean(value, message) { if (!isBoolean(value)) { - throw new TypeError(typeErrorMessage('boolean', value)); + throw new TypeError(message ?? typeErrorMessage('boolean', value)); } } // eslint-disable-next-line @typescript-eslint/ban-types -function assertBoundFunction(value) { +function assertBoundFunction(value, message) { if (!isBoundFunction(value)) { - throw new TypeError(typeErrorMessage('Function', value)); + throw new TypeError(message ?? typeErrorMessage('Function', value)); } } -function assertBuffer(value) { +function assertBuffer(value, message) { if (!isBuffer(value)) { - throw new TypeError(typeErrorMessage('Buffer', value)); + throw new TypeError(message ?? typeErrorMessage('Buffer', value)); } } -function assertClass(value) { +function assertClass(value, message) { if (!isClass(value)) { - throw new TypeError(typeErrorMessage('Class', value)); + throw new TypeError(message ?? typeErrorMessage('Class', value)); } } -function assertDataView(value) { +function assertDataView(value, message) { if (!isDataView(value)) { - throw new TypeError(typeErrorMessage('DataView', value)); + throw new TypeError(message ?? typeErrorMessage('DataView', value)); } } -function assertDate(value) { +function assertDate(value, message) { if (!isDate(value)) { - throw new TypeError(typeErrorMessage('Date', value)); + throw new TypeError(message ?? typeErrorMessage('Date', value)); } } -function assertDirectInstanceOf(instance, class_) { +function assertDirectInstanceOf(instance, class_, message) { if (!isDirectInstanceOf(instance, class_)) { - throw new TypeError(typeErrorMessage('T', instance)); + throw new TypeError(message ?? typeErrorMessage('T', instance)); } } -function assertEmptyArray(value) { +function assertEmptyArray(value, message) { if (!isEmptyArray(value)) { - throw new TypeError(typeErrorMessage('empty array', value)); + throw new TypeError(message ?? typeErrorMessage('empty array', value)); } } -function assertEmptyMap(value) { +function assertEmptyMap(value, message) { if (!isEmptyMap(value)) { - throw new TypeError(typeErrorMessage('empty map', value)); + throw new TypeError(message ?? typeErrorMessage('empty map', value)); } } -function assertEmptyObject(value) { +function assertEmptyObject(value, message) { if (!isEmptyObject(value)) { - throw new TypeError(typeErrorMessage('empty object', value)); + throw new TypeError(message ?? typeErrorMessage('empty object', value)); } } -function assertEmptySet(value) { +function assertEmptySet(value, message) { if (!isEmptySet(value)) { - throw new TypeError(typeErrorMessage('empty set', value)); + throw new TypeError(message ?? typeErrorMessage('empty set', value)); } } -function assertEmptyString(value) { +function assertEmptyString(value, message) { if (!isEmptyString(value)) { - throw new TypeError(typeErrorMessage('empty string', value)); + throw new TypeError(message ?? typeErrorMessage('empty string', value)); } } -function assertEmptyStringOrWhitespace(value) { +function assertEmptyStringOrWhitespace(value, message) { if (!isEmptyStringOrWhitespace(value)) { - throw new TypeError(typeErrorMessage('empty string or whitespace', value)); + throw new TypeError(message ?? typeErrorMessage('empty string or whitespace', value)); } } -function assertEnumCase(value, targetEnum) { +function assertEnumCase(value, targetEnum, message) { if (!isEnumCase(value, targetEnum)) { - throw new TypeError(typeErrorMessage('EnumCase', value)); + throw new TypeError(message ?? typeErrorMessage('EnumCase', value)); } } -function assertError(value) { +function assertError(value, message) { if (!isError(value)) { - throw new TypeError(typeErrorMessage('Error', value)); + throw new TypeError(message ?? typeErrorMessage('Error', value)); } } -function assertEvenInteger(value) { +function assertEvenInteger(value, message) { if (!isEvenInteger(value)) { - throw new TypeError(typeErrorMessage('even integer', value)); + throw new TypeError(message ?? typeErrorMessage('even integer', value)); } } -function assertFalsy(value) { +function assertFalsy(value, message) { if (!isFalsy(value)) { - throw new TypeError(typeErrorMessage('falsy', value)); + throw new TypeError(message ?? typeErrorMessage('falsy', value)); } } -function assertFloat32Array(value) { +function assertFloat32Array(value, message) { if (!isFloat32Array(value)) { - throw new TypeError(typeErrorMessage('Float32Array', value)); + throw new TypeError(message ?? typeErrorMessage('Float32Array', value)); } } -function assertFloat64Array(value) { +function assertFloat64Array(value, message) { if (!isFloat64Array(value)) { - throw new TypeError(typeErrorMessage('Float64Array', value)); + throw new TypeError(message ?? typeErrorMessage('Float64Array', value)); } } -function assertFormData(value) { +function assertFormData(value, message) { if (!isFormData(value)) { - throw new TypeError(typeErrorMessage('FormData', value)); + throw new TypeError(message ?? typeErrorMessage('FormData', value)); } } // eslint-disable-next-line @typescript-eslint/ban-types -function assertFunction(value) { +function assertFunction(value, message) { if (!isFunction(value)) { - throw new TypeError(typeErrorMessage('Function', value)); + throw new TypeError(message ?? typeErrorMessage('Function', value)); } } -function assertGenerator(value) { +function assertGenerator(value, message) { if (!isGenerator(value)) { - throw new TypeError(typeErrorMessage('Generator', value)); + throw new TypeError(message ?? typeErrorMessage('Generator', value)); } } -function assertGeneratorFunction(value) { +function assertGeneratorFunction(value, message) { if (!isGeneratorFunction(value)) { - throw new TypeError(typeErrorMessage('GeneratorFunction', value)); + throw new TypeError(message ?? typeErrorMessage('GeneratorFunction', value)); } } -function assertHtmlElement(value) { +function assertHtmlElement(value, message) { if (!isHtmlElement(value)) { - throw new TypeError(typeErrorMessage('HTMLElement', value)); + throw new TypeError(message ?? typeErrorMessage('HTMLElement', value)); } } -function assertInfinite(value) { +function assertInfinite(value, message) { if (!isInfinite(value)) { - throw new TypeError(typeErrorMessage('infinite number', value)); + throw new TypeError(message ?? typeErrorMessage('infinite number', value)); } } -function assertInRange(value, range) { +function assertInRange(value, range, message) { if (!isInRange(value, range)) { - throw new TypeError(typeErrorMessage('in range', value)); + throw new TypeError(message ?? typeErrorMessage('in range', value)); } } -function assertInt16Array(value) { +function assertInt16Array(value, message) { if (!isInt16Array(value)) { - throw new TypeError(typeErrorMessage('Int16Array', value)); + throw new TypeError(message ?? typeErrorMessage('Int16Array', value)); } } -function assertInt32Array(value) { +function assertInt32Array(value, message) { if (!isInt32Array(value)) { - throw new TypeError(typeErrorMessage('Int32Array', value)); + throw new TypeError(message ?? typeErrorMessage('Int32Array', value)); } } -function assertInt8Array(value) { +function assertInt8Array(value, message) { if (!isInt8Array(value)) { - throw new TypeError(typeErrorMessage('Int8Array', value)); + throw new TypeError(message ?? typeErrorMessage('Int8Array', value)); } } -function assertInteger(value) { +function assertInteger(value, message) { if (!isInteger(value)) { - throw new TypeError(typeErrorMessage('integer', value)); + throw new TypeError(message ?? typeErrorMessage('integer', value)); } } -function assertIterable(value) { +function assertIterable(value, message) { if (!isIterable(value)) { - throw new TypeError(typeErrorMessage('Iterable', value)); + throw new TypeError(message ?? typeErrorMessage('Iterable', value)); } } -function assertMap(value) { +function assertMap(value, message) { if (!isMap(value)) { - throw new TypeError(typeErrorMessage('Map', value)); + throw new TypeError(message ?? typeErrorMessage('Map', value)); } } -function assertNan(value) { +function assertNan(value, message) { if (!isNan(value)) { - throw new TypeError(typeErrorMessage('NaN', value)); + throw new TypeError(message ?? typeErrorMessage('NaN', value)); } } -function assertNativePromise(value) { +function assertNativePromise(value, message) { if (!isNativePromise(value)) { - throw new TypeError(typeErrorMessage('native Promise', value)); + throw new TypeError(message ?? typeErrorMessage('native Promise', value)); } } -function assertNegativeNumber(value) { +function assertNegativeNumber(value, message) { if (!isNegativeNumber(value)) { - throw new TypeError(typeErrorMessage('negative number', value)); + throw new TypeError(message ?? typeErrorMessage('negative number', value)); } } -function assertNodeStream(value) { +function assertNodeStream(value, message) { if (!isNodeStream(value)) { - throw new TypeError(typeErrorMessage('Node.js Stream', value)); + throw new TypeError(message ?? typeErrorMessage('Node.js Stream', value)); } } -function assertNonEmptyArray(value) { +function assertNonEmptyArray(value, message) { if (!isNonEmptyArray(value)) { - throw new TypeError(typeErrorMessage('non-empty array', value)); + throw new TypeError(message ?? typeErrorMessage('non-empty array', value)); } } -function assertNonEmptyMap(value) { +function assertNonEmptyMap(value, message) { if (!isNonEmptyMap(value)) { - throw new TypeError(typeErrorMessage('non-empty map', value)); + throw new TypeError(message ?? typeErrorMessage('non-empty map', value)); } } -function assertNonEmptyObject(value) { +function assertNonEmptyObject(value, message) { if (!isNonEmptyObject(value)) { - throw new TypeError(typeErrorMessage('non-empty object', value)); + throw new TypeError(message ?? typeErrorMessage('non-empty object', value)); } } -function assertNonEmptySet(value) { +function assertNonEmptySet(value, message) { if (!isNonEmptySet(value)) { - throw new TypeError(typeErrorMessage('non-empty set', value)); + throw new TypeError(message ?? typeErrorMessage('non-empty set', value)); } } -function assertNonEmptyString(value) { +function assertNonEmptyString(value, message) { if (!isNonEmptyString(value)) { - throw new TypeError(typeErrorMessage('non-empty string', value)); + throw new TypeError(message ?? typeErrorMessage('non-empty string', value)); } } -function assertNonEmptyStringAndNotWhitespace(value) { +function assertNonEmptyStringAndNotWhitespace(value, message) { if (!isNonEmptyStringAndNotWhitespace(value)) { - throw new TypeError(typeErrorMessage('non-empty string and not whitespace', value)); + throw new TypeError(message ?? typeErrorMessage('non-empty string and not whitespace', value)); } } // eslint-disable-next-line @typescript-eslint/ban-types -function assertNull(value) { +function assertNull(value, message) { if (!isNull(value)) { - throw new TypeError(typeErrorMessage('null', value)); + throw new TypeError(message ?? typeErrorMessage('null', value)); } } // eslint-disable-next-line @typescript-eslint/ban-types -function assertNullOrUndefined(value) { +function assertNullOrUndefined(value, message) { if (!isNullOrUndefined(value)) { - throw new TypeError(typeErrorMessage('null or undefined', value)); + throw new TypeError(message ?? typeErrorMessage('null or undefined', value)); } } -function assertNumber(value) { +function assertNumber(value, message) { if (!isNumber(value)) { - throw new TypeError(typeErrorMessage('number', value)); + throw new TypeError(message ?? typeErrorMessage('number', value)); } } -function assertNumericString(value) { +function assertNumericString(value, message) { if (!isNumericString(value)) { - throw new TypeError(typeErrorMessage('string with a number', value)); + throw new TypeError(message ?? typeErrorMessage('string with a number', value)); } } // eslint-disable-next-line @typescript-eslint/ban-types -function assertObject(value) { +function assertObject(value, message) { if (!isObject(value)) { - throw new TypeError(typeErrorMessage('Object', value)); + throw new TypeError(message ?? typeErrorMessage('Object', value)); } } -function assertObservable(value) { +function assertObservable(value, message) { if (!isObservable(value)) { - throw new TypeError(typeErrorMessage('Observable', value)); + throw new TypeError(message ?? typeErrorMessage('Observable', value)); } } -function assertOddInteger(value) { +function assertOddInteger(value, message) { if (!isOddInteger(value)) { - throw new TypeError(typeErrorMessage('odd integer', value)); + throw new TypeError(message ?? typeErrorMessage('odd integer', value)); } } -function assertPlainObject(value) { +function assertPlainObject(value, message) { if (!isPlainObject(value)) { - throw new TypeError(typeErrorMessage('plain object', value)); + throw new TypeError(message ?? typeErrorMessage('plain object', value)); } } -function assertPositiveNumber(value) { +function assertPositiveNumber(value, message) { if (!isPositiveNumber(value)) { - throw new TypeError(typeErrorMessage('positive number', value)); + throw new TypeError(message ?? typeErrorMessage('positive number', value)); } } -function assertPrimitive(value) { +function assertPrimitive(value, message) { if (!isPrimitive(value)) { - throw new TypeError(typeErrorMessage('primitive', value)); + throw new TypeError(message ?? typeErrorMessage('primitive', value)); } } -function assertPromise(value) { +function assertPromise(value, message) { if (!isPromise(value)) { - throw new TypeError(typeErrorMessage('Promise', value)); + throw new TypeError(message ?? typeErrorMessage('Promise', value)); } } -function assertPropertyKey(value) { +function assertPropertyKey(value, message) { if (!isPropertyKey(value)) { - throw new TypeError(typeErrorMessage('PropertyKey', value)); + throw new TypeError(message ?? typeErrorMessage('PropertyKey', value)); } } -function assertRegExp(value) { +function assertRegExp(value, message) { if (!isRegExp(value)) { - throw new TypeError(typeErrorMessage('RegExp', value)); + throw new TypeError(message ?? typeErrorMessage('RegExp', value)); } } -function assertSafeInteger(value) { +function assertSafeInteger(value, message) { if (!isSafeInteger(value)) { - throw new TypeError(typeErrorMessage('integer', value)); + throw new TypeError(message ?? typeErrorMessage('integer', value)); } } -function assertSet(value) { +function assertSet(value, message) { if (!isSet(value)) { - throw new TypeError(typeErrorMessage('Set', value)); + throw new TypeError(message ?? typeErrorMessage('Set', value)); } } -function assertSharedArrayBuffer(value) { +function assertSharedArrayBuffer(value, message) { if (!isSharedArrayBuffer(value)) { - throw new TypeError(typeErrorMessage('SharedArrayBuffer', value)); + throw new TypeError(message ?? typeErrorMessage('SharedArrayBuffer', value)); } } -function assertString(value) { +function assertString(value, message) { if (!isString(value)) { - throw new TypeError(typeErrorMessage('string', value)); + throw new TypeError(message ?? typeErrorMessage('string', value)); } } -function assertSymbol(value) { +function assertSymbol(value, message) { if (!isSymbol(value)) { - throw new TypeError(typeErrorMessage('symbol', value)); + throw new TypeError(message ?? typeErrorMessage('symbol', value)); } } -function assertTruthy(value) { +function assertTruthy(value, message) { if (!isTruthy(value)) { - throw new TypeError(typeErrorMessage('truthy', value)); + throw new TypeError(message ?? typeErrorMessage('truthy', value)); } } -function assertTupleLike(value, guards) { +function assertTupleLike(value, guards, message) { if (!isTupleLike(value, guards)) { - throw new TypeError(typeErrorMessage('tuple-like', value)); + throw new TypeError(message ?? typeErrorMessage('tuple-like', value)); } } -function assertTypedArray(value) { +function assertTypedArray(value, message) { if (!isTypedArray(value)) { - throw new TypeError(typeErrorMessage('TypedArray', value)); + throw new TypeError(message ?? typeErrorMessage('TypedArray', value)); } } -function assertUint16Array(value) { +function assertUint16Array(value, message) { if (!isUint16Array(value)) { - throw new TypeError(typeErrorMessage('Uint16Array', value)); + throw new TypeError(message ?? typeErrorMessage('Uint16Array', value)); } } -function assertUint32Array(value) { +function assertUint32Array(value, message) { if (!isUint32Array(value)) { - throw new TypeError(typeErrorMessage('Uint32Array', value)); + throw new TypeError(message ?? typeErrorMessage('Uint32Array', value)); } } -function assertUint8Array(value) { +function assertUint8Array(value, message) { if (!isUint8Array(value)) { - throw new TypeError(typeErrorMessage('Uint8Array', value)); + throw new TypeError(message ?? typeErrorMessage('Uint8Array', value)); } } -function assertUint8ClampedArray(value) { +function assertUint8ClampedArray(value, message) { if (!isUint8ClampedArray(value)) { - throw new TypeError(typeErrorMessage('Uint8ClampedArray', value)); + throw new TypeError(message ?? typeErrorMessage('Uint8ClampedArray', value)); } } -function assertUndefined(value) { +function assertUndefined(value, message) { if (!isUndefined(value)) { - throw new TypeError(typeErrorMessage('undefined', value)); + throw new TypeError(message ?? typeErrorMessage('undefined', value)); } } -function assertUrlInstance(value) { +function assertUrlInstance(value, message) { if (!isUrlInstance(value)) { - throw new TypeError(typeErrorMessage('URL', value)); + throw new TypeError(message ?? typeErrorMessage('URL', value)); } } // eslint-disable-next-line unicorn/prevent-abbreviations -function assertUrlSearchParams(value) { +function assertUrlSearchParams(value, message) { if (!isUrlSearchParams(value)) { - throw new TypeError(typeErrorMessage('URLSearchParams', value)); + throw new TypeError(message ?? typeErrorMessage('URLSearchParams', value)); } } -function assertUrlString(value) { +function assertUrlString(value, message) { if (!isUrlString(value)) { - throw new TypeError(typeErrorMessage('string with a URL', value)); + throw new TypeError(message ?? typeErrorMessage('string with a URL', value)); } } -function assertValidDate(value) { +function assertValidDate(value, message) { if (!isValidDate(value)) { - throw new TypeError(typeErrorMessage('valid Date', value)); + throw new TypeError(message ?? typeErrorMessage('valid Date', value)); } } -function assertValidLength(value) { +function assertValidLength(value, message) { if (!isValidLength(value)) { - throw new TypeError(typeErrorMessage('valid length', value)); + throw new TypeError(message ?? typeErrorMessage('valid length', value)); } } // eslint-disable-next-line @typescript-eslint/ban-types -function assertWeakMap(value) { +function assertWeakMap(value, message) { if (!isWeakMap(value)) { - throw new TypeError(typeErrorMessage('WeakMap', value)); + throw new TypeError(message ?? typeErrorMessage('WeakMap', value)); } } // eslint-disable-next-line @typescript-eslint/ban-types -function assertWeakRef(value) { +function assertWeakRef(value, message) { if (!isWeakRef(value)) { - throw new TypeError(typeErrorMessage('WeakRef', value)); + throw new TypeError(message ?? typeErrorMessage('WeakRef', value)); } } // eslint-disable-next-line @typescript-eslint/ban-types -function assertWeakSet(value) { +function assertWeakSet(value, message) { if (!isWeakSet(value)) { - throw new TypeError(typeErrorMessage('WeakSet', value)); + throw new TypeError(message ?? typeErrorMessage('WeakSet', value)); } } -function assertWhitespaceString(value) { +function assertWhitespaceString(value, message) { if (!isWhitespaceString(value)) { - throw new TypeError(typeErrorMessage('whitespace string', value)); + throw new TypeError(message ?? typeErrorMessage('whitespace string', value)); } } /* harmony default export */ const dist = (is); @@ -93742,13 +93748,9 @@ const got = source_create(defaults); -;// CONCATENATED MODULE: external "node:fs/promises" -const promises_namespaceObject = __WEBPACK_EXTERNAL_createRequire(import.meta.url)("node:fs/promises"); -;// CONCATENATED MODULE: external "node:path" -const external_node_path_namespaceObject = __WEBPACK_EXTERNAL_createRequire(import.meta.url)("node:path"); ;// CONCATENATED MODULE: external "node:stream/promises" const external_node_stream_promises_namespaceObject = __WEBPACK_EXTERNAL_createRequire(import.meta.url)("node:stream/promises"); -;// CONCATENATED MODULE: ./node_modules/.pnpm/github.com+DeterminateSystems+detsys-ts@56a244c061429692b1c7d80fc068d684db3ae4d2_nqhbjyaof246q4gvygpbo6m4na/node_modules/detsys-ts/dist/index.js +;// CONCATENATED MODULE: ./node_modules/.pnpm/github.com+DeterminateSystems+detsys-ts@5abcb239472d24b114a53f70800f0e42fc30819c_ey4bwtjkop43mcem42nicbf3we/node_modules/detsys-ts/dist/index.js var __defProp = Object.defineProperty; var __export = (target, all) => { for (var name in all) @@ -93909,7 +93911,7 @@ var getLinuxInfo = async () => { let data = {}; try { data = releaseInfo({ mode: "sync" }); - console.log(data); + core.debug(`Identified release info: ${JSON.stringify(data)}`); } catch (e) { core.debug(`Error collecting release info: ${e}`); } @@ -94338,46 +94340,55 @@ var IdsToolbox = class { }); } async fetch() { - core.info(`Fetching from ${this.getUrl()}`); - const correlatedUrl = this.getUrl(); - correlatedUrl.searchParams.set("ci", "github"); - correlatedUrl.searchParams.set( - "correlation", - JSON.stringify(this.identity) + core.startGroup( + `Downloading ${this.actionOptions.name} for ${this.architectureFetchSuffix}` ); - const versionCheckup = await this.client.head(correlatedUrl); - if (versionCheckup.headers.etag) { - const v = versionCheckup.headers.etag; - core.debug(`Checking the tool cache for ${this.getUrl()} at ${v}`); - const cached = await this.getCachedVersion(v); - if (cached) { - this.facts["artifact_fetched_from_cache"] = true; - core.debug(`Tool cache hit.`); - return cached; + try { + core.info(`Fetching from ${this.getUrl()}`); + const correlatedUrl = this.getUrl(); + correlatedUrl.searchParams.set("ci", "github"); + correlatedUrl.searchParams.set( + "correlation", + JSON.stringify(this.identity) + ); + const versionCheckup = await this.client.head(correlatedUrl); + if (versionCheckup.headers.etag) { + const v = versionCheckup.headers.etag; + core.debug( + `Checking the tool cache for ${this.getUrl()} at ${v}` + ); + const cached = await this.getCachedVersion(v); + if (cached) { + this.facts["artifact_fetched_from_cache"] = true; + core.debug(`Tool cache hit.`); + return cached; + } } - } - this.facts["artifact_fetched_from_cache"] = false; - core.debug( - `No match from the cache, re-fetching from the redirect: ${versionCheckup.url}` - ); - const destFile = this.getTemporaryName(); - const fetchStream = this.client.stream(versionCheckup.url); - await (0,external_node_stream_promises_namespaceObject.pipeline)( - fetchStream, - (0,external_node_fs_namespaceObject.createWriteStream)(destFile, { - encoding: "binary", - mode: 493 - }) - ); - if (fetchStream.response?.headers.etag) { - const v = fetchStream.response.headers.etag; - try { - await this.saveCachedVersion(v, destFile); - } catch (e) { - core.debug(`Error caching the artifact: ${e}`); + this.facts["artifact_fetched_from_cache"] = false; + core.debug( + `No match from the cache, re-fetching from the redirect: ${versionCheckup.url}` + ); + const destFile = this.getTemporaryName(); + const fetchStream = this.client.stream(versionCheckup.url); + await (0,external_node_stream_promises_namespaceObject.pipeline)( + fetchStream, + (0,external_node_fs_namespaceObject.createWriteStream)(destFile, { + encoding: "binary", + mode: 493 + }) + ); + if (fetchStream.response?.headers.etag) { + const v = fetchStream.response.headers.etag; + try { + await this.saveCachedVersion(v, destFile); + } catch (e) { + core.debug(`Error caching the artifact: ${e}`); + } } + return destFile; + } finally { + core.endGroup(); } - return destFile; } async fetchExecutable() { const binaryPath = await this.fetch(); @@ -94617,45 +94628,13 @@ function mungeDiagnosticEndpoint(inputUrl) { var external_http_ = __nccwpck_require__(3685); ;// CONCATENATED MODULE: external "node:child_process" const external_node_child_process_namespaceObject = __WEBPACK_EXTERNAL_createRequire(import.meta.url)("node:child_process"); -// EXTERNAL MODULE: ./node_modules/.pnpm/tail@2.2.6/node_modules/tail/lib/tail.js -var tail = __nccwpck_require__(3707); ;// CONCATENATED MODULE: ./dist/index.js -// src/index.ts +// src/helpers.ts - - - - - - -var ENV_CACHE_DAEMONDIR = "MAGIC_NIX_CACHE_DAEMONDIR"; -var gotClient = got_dist_source.extend({ - retry: { - limit: 1, - methods: ["POST", "GET", "PUT", "HEAD", "DELETE", "OPTIONS", "TRACE"] - }, - hooks: { - beforeRetry: [ - (error, retryCount) => { - core.info(`Retrying after error ${error.code}, retry #: ${retryCount}`); - } - ] - } -}); -async function fetchAutoCacher(toolbox) { - const closurePath = await toolbox.fetch(); - toolbox.recordEvent("load_closure"); - const { stdout } = await (0,external_node_util_.promisify)(external_node_child_process_namespaceObject.exec)( - `cat "${closurePath}" | xz -d | nix-store --import` - ); - const paths = stdout.split(external_node_os_.EOL); - const last_path = paths.at(-2); - return `${last_path}/bin/magic-nix-cache`; -} function tailLog(daemonDir) { const log = new tail/* Tail */.x(external_node_path_namespaceObject.join(daemonDir, "daemon.log")); core.debug(`tailing daemon.log...`); @@ -94664,138 +94643,6 @@ function tailLog(daemonDir) { }); return log; } -async function setUpAutoCache(toolbox) { - const tmpdir2 = process.env["RUNNER_TEMP"] || external_node_os_.tmpdir(); - const required_env = [ - "ACTIONS_CACHE_URL", - "ACTIONS_RUNTIME_URL", - "ACTIONS_RUNTIME_TOKEN" - ]; - let anyMissing = false; - for (const n of required_env) { - if (!process.env.hasOwnProperty(n)) { - anyMissing = true; - core.warning( - `Disabling automatic caching since required environment ${n} isn't available` - ); - } - } - if (anyMissing) { - return; - } - core.debug(`GitHub Action Cache URL: ${process.env["ACTIONS_CACHE_URL"]}`); - const daemonDir = await promises_namespaceObject.mkdtemp(external_node_path_namespaceObject.join(tmpdir2, "magic-nix-cache-")); - let daemonBin; - if (core.getInput("source-binary")) { - daemonBin = core.getInput("source-binary"); - } else { - daemonBin = await fetchAutoCacher(toolbox); - } - let runEnv; - if (core.isDebug()) { - runEnv = { - RUST_LOG: "trace,magic_nix_cache=debug,gha_cache=debug", - RUST_BACKTRACE: "full", - ...process.env - }; - } else { - runEnv = process.env; - } - const notifyPort = core.getInput("startup-notification-port"); - const notifyPromise = new Promise((resolveListening) => { - const promise = new Promise(async (resolveQuit) => { - const notifyServer = external_http_.createServer((req, res) => { - if (req.method === "POST" && req.url === "/") { - core.debug(`Notify server shutting down.`); - res.writeHead(200, { "Content-Type": "application/json" }); - res.end("{}"); - notifyServer.close(() => { - resolveQuit(); - }); - } - }); - notifyServer.listen(notifyPort, () => { - core.debug(`Notify server running.`); - resolveListening(promise); - }); - }); - }); - const outputPath = `${daemonDir}/daemon.log`; - const output = (0,external_node_fs_namespaceObject.openSync)(outputPath, "a"); - const log = tailLog(daemonDir); - const netrc = await netrcPath(); - const nixConfPath = `${process.env["HOME"]}/.config/nix/nix.conf`; - const daemonCliFlags = [ - "--startup-notification-url", - `http://127.0.0.1:${notifyPort}`, - "--listen", - core.getInput("listen"), - "--upstream", - core.getInput("upstream-cache"), - "--diagnostic-endpoint", - core.getInput("diagnostic-endpoint"), - "--nix-conf", - nixConfPath - ].concat( - core.getBooleanInput("use-flakehub") ? [ - "--use-flakehub", - "--flakehub-cache-server", - core.getInput("flakehub-cache-server"), - "--flakehub-api-server", - core.getInput("flakehub-api-server"), - "--flakehub-api-server-netrc", - netrc, - "--flakehub-flake-name", - core.getInput("flakehub-flake-name") - ] : [] - ).concat(core.getBooleanInput("use-gha-cache") ? ["--use-gha-cache"] : []); - const opts = { - stdio: ["ignore", output, output], - env: runEnv, - detached: true - }; - core.debug("Full daemon start command:"); - core.debug(`${daemonBin} ${daemonCliFlags.join(" ")}`); - const daemon = (0,external_node_child_process_namespaceObject.spawn)(daemonBin, daemonCliFlags, opts); - const pidFile = external_node_path_namespaceObject.join(daemonDir, "daemon.pid"); - await promises_namespaceObject.writeFile(pidFile, `${daemon.pid}`); - core.info("Waiting for magic-nix-cache to start..."); - await new Promise((resolve, reject) => { - notifyPromise.then((_value) => { - resolve(); - }).catch((err) => { - reject(new Error(`error in notifyPromise: ${err}`)); - }); - daemon.on("exit", async (code, signal) => { - if (signal) { - reject(new Error(`Daemon was killed by signal ${signal}`)); - } else if (code) { - reject(new Error(`Daemon exited with code ${code}`)); - } else { - reject(new Error(`Daemon unexpectedly exited`)); - } - }); - }); - daemon.unref(); - core.info("Launched Magic Nix Cache"); - core.exportVariable(ENV_CACHE_DAEMONDIR, daemonDir); - log.unwatch(); -} -async function notifyAutoCache() { - const daemonDir = process.env[ENV_CACHE_DAEMONDIR]; - if (!daemonDir) { - return; - } - try { - core.debug(`Indicating workflow start`); - const res = await gotClient.post(`http://${core.getInput("listen")}/api/workflow-start`).json(); - core.debug(`back from post: ${res}`); - } catch (e) { - core.info(`Error marking the workflow as started:`); - core.info((0,external_node_util_.inspect)(e)); - core.info(`Magic Nix Cache may not be running for this workflow.`); - } -} async function netrcPath() { const expectedNetrcPath = external_node_path_namespaceObject.join( process.env["RUNNER_TEMP"] || external_node_os_.tmpdir(), @@ -94810,7 +94657,7 @@ async function netrcPath() { "magic-nix-cache-netrc" ); try { - await flakehub_login(destinedNetrcPath); + await flakeHubLogin(destinedNetrcPath); } catch (e) { core.info("FlakeHub cache disabled."); core.debug(`Error while logging into FlakeHub: ${e}`); @@ -94818,7 +94665,7 @@ async function netrcPath() { return destinedNetrcPath; } } -async function flakehub_login(netrc) { +async function flakeHubLogin(netrc) { const jwt = await core.getIDToken("api.flakehub.com"); await promises_namespaceObject.writeFile( netrc, @@ -94830,56 +94677,242 @@ async function flakehub_login(netrc) { ); core.info("Logged in to FlakeHub."); } -async function tearDownAutoCache() { - const daemonDir = process.env[ENV_CACHE_DAEMONDIR]; - if (!daemonDir) { - core.debug("magic-nix-cache not started - Skipping"); - return; + +// src/index.ts + + + + + + + + + + +var ENV_CACHE_DAEMONDIR = "MAGIC_NIX_CACHE_DAEMONDIR"; +var MagicNixCacheAction = class { + constructor() { + this.idslib = new IdsToolbox({ + name: "magic-nix-cache", + fetchStyle: "gh-env-style", + idsProjectName: "magic-nix-cache-closure", + requireNix: "warn" + }); + this.client = got_dist_source.extend({ + retry: { + limit: 1, + methods: ["POST", "GET", "PUT", "HEAD", "DELETE", "OPTIONS", "TRACE"] + }, + hooks: { + beforeRetry: [ + (error, retryCount) => { + core.info( + `Retrying after error ${error.code}, retry #: ${retryCount}` + ); + } + ] + } + }); } - const pidFile = external_node_path_namespaceObject.join(daemonDir, "daemon.pid"); - const pid = parseInt(await promises_namespaceObject.readFile(pidFile, { encoding: "ascii" })); - core.debug(`found daemon pid: ${pid}`); - if (!pid) { - throw new Error("magic-nix-cache did not start successfully"); - } - const log = tailLog(daemonDir); - try { - core.debug(`about to post to localhost`); - const res = await gotClient.post(`http://${core.getInput("listen")}/api/workflow-finish`).json(); - core.debug(`back from post: ${res}`); - } finally { - core.debug(`unwatching the daemon log`); + async setUpAutoCache() { + const tmpdir3 = process.env["RUNNER_TEMP"] || external_node_os_.tmpdir(); + const requiredEnv = [ + "ACTIONS_CACHE_URL", + "ACTIONS_RUNTIME_URL", + "ACTIONS_RUNTIME_TOKEN" + ]; + let anyMissing = false; + for (const n of requiredEnv) { + if (!process.env.hasOwnProperty(n)) { + anyMissing = true; + core.warning( + `Disabling automatic caching since required environment ${n} isn't available` + ); + } + } + if (anyMissing) { + return; + } + core.debug( + `GitHub Action Cache URL: ${process.env["ACTIONS_CACHE_URL"]}` + ); + const daemonDir = await promises_namespaceObject.mkdtemp(external_node_path_namespaceObject.join(tmpdir3, "magic-nix-cache-")); + const sourceBinary = inputs_exports.getStringOrNull("source-binary"); + const daemonBin = sourceBinary !== null ? sourceBinary : await this.fetchAutoCacher(); + let runEnv; + if (core.isDebug()) { + runEnv = { + RUST_LOG: "trace,magic_nix_cache=debug,gha_cache=debug", + RUST_BACKTRACE: "full", + ...process.env + }; + } else { + runEnv = process.env; + } + const notifyPort = inputs_exports.getString("startup-notification-port"); + const notifyPromise = new Promise((resolveListening) => { + const promise = new Promise(async (resolveQuit) => { + const notifyServer = external_http_.createServer((req, res) => { + if (req.method === "POST" && req.url === "/") { + core.debug(`Notify server shutting down.`); + res.writeHead(200, { "Content-Type": "application/json" }); + res.end("{}"); + notifyServer.close(() => { + resolveQuit(); + }); + } + }); + notifyServer.listen(notifyPort, () => { + core.debug(`Notify server running.`); + resolveListening(promise); + }); + }); + }); + const outputPath = `${daemonDir}/daemon.log`; + const output = (0,external_node_fs_namespaceObject.openSync)(outputPath, "a"); + const log = tailLog(daemonDir); + const netrc = await netrcPath(); + const nixConfPath = `${process.env["HOME"]}/.config/nix/nix.conf`; + const hostAndPort = inputs_exports.getString("listen"); + const upstreamCache = inputs_exports.getString("upstream-cache"); + const diagnosticEndpoint = inputs_exports.getString("diagnostic-endpoint"); + const useFlakeHub = inputs_exports.getBool("use-flakehub"); + const flakeHubCacheServer = inputs_exports.getString("flakehub-cache-server"); + const flakeHubApiServer = inputs_exports.getString("flakehub-api-server"); + const flakeHubFlakeName = inputs_exports.getString("flakehub-flake-name"); + const useGhaCache = inputs_exports.getBool("use-gha-cache"); + const daemonCliFlags = [ + "--startup-notification-url", + `http://127.0.0.1:${notifyPort}`, + "--listen", + hostAndPort, + "--upstream", + upstreamCache, + "--diagnostic-endpoint", + diagnosticEndpoint, + "--nix-conf", + nixConfPath + ].concat( + useFlakeHub ? [ + "--use-flakehub", + "--flakehub-cache-server", + flakeHubCacheServer, + "--flakehub-api-server", + flakeHubApiServer, + "--flakehub-api-server-netrc", + netrc, + "--flakehub-flake-name", + flakeHubFlakeName + ] : [] + ).concat(useGhaCache ? ["--use-gha-cache"] : []); + const opts = { + stdio: ["ignore", output, output], + env: runEnv, + detached: true + }; + core.debug("Full daemon start command:"); + core.debug(`${daemonBin} ${daemonCliFlags.join(" ")}`); + const daemon = (0,external_node_child_process_namespaceObject.spawn)(daemonBin, daemonCliFlags, opts); + const pidFile = external_node_path_namespaceObject.join(daemonDir, "daemon.pid"); + await promises_namespaceObject.writeFile(pidFile, `${daemon.pid}`); + core.info("Waiting for magic-nix-cache to start..."); + await new Promise((resolve, reject) => { + notifyPromise.then((_value) => { + resolve(); + }).catch((err) => { + reject(new Error(`error in notifyPromise: ${err}`)); + }); + daemon.on("exit", async (code, signal) => { + if (signal) { + reject(new Error(`Daemon was killed by signal ${signal}`)); + } else if (code) { + reject(new Error(`Daemon exited with code ${code}`)); + } else { + reject(new Error(`Daemon unexpectedly exited`)); + } + }); + }); + daemon.unref(); + core.info("Launched Magic Nix Cache"); + core.exportVariable(ENV_CACHE_DAEMONDIR, daemonDir); log.unwatch(); } - core.debug(`killing`); - try { - process.kill(pid, "SIGTERM"); - } catch (e) { - if (typeof e === "object" && e && "code" in e && e.code !== "ESRCH") { - throw e; + async fetchAutoCacher() { + const closurePath = await this.idslib.fetch(); + this.idslib.recordEvent("load_closure"); + const { stdout } = await (0,external_node_util_.promisify)(external_node_child_process_namespaceObject.exec)( + `cat "${closurePath}" | xz -d | nix-store --import` + ); + const paths = stdout.split(external_node_os_.EOL); + const lastPath = paths.at(-2); + return `${lastPath}/bin/magic-nix-cache`; + } + async notifyAutoCache() { + const daemonDir = process.env[ENV_CACHE_DAEMONDIR]; + if (!daemonDir) { + return; } - } finally { - if (core.isDebug()) { - core.info("Entire log:"); - const entireLog = (0,external_node_fs_namespaceObject.readFileSync)(external_node_path_namespaceObject.join(daemonDir, "daemon.log")); - core.info(entireLog.toString()); + try { + core.debug(`Indicating workflow start`); + const hostAndPort = inputs_exports.getString("listen"); + const res = await this.client.post(`http://${hostAndPort}/api/workflow-start`).json(); + core.debug(`back from post: ${res}`); + } catch (e) { + core.info(`Error marking the workflow as started:`); + core.info((0,external_node_util_.inspect)(e)); + core.info(`Magic Nix Cache may not be running for this workflow.`); } } + async tearDownAutoCache() { + const daemonDir = process.env[ENV_CACHE_DAEMONDIR]; + if (!daemonDir) { + core.debug("magic-nix-cache not started - Skipping"); + return; + } + const pidFile = external_node_path_namespaceObject.join(daemonDir, "daemon.pid"); + const pid = parseInt(await promises_namespaceObject.readFile(pidFile, { encoding: "ascii" })); + core.debug(`found daemon pid: ${pid}`); + if (!pid) { + throw new Error("magic-nix-cache did not start successfully"); + } + const log = tailLog(daemonDir); + try { + core.debug(`about to post to localhost`); + const hostAndPort = inputs_exports.getString("listen"); + const res = await this.client.post(`http://${hostAndPort}/api/workflow-finish`).json(); + core.debug(`back from post: ${res}`); + } finally { + core.debug(`unwatching the daemon log`); + log.unwatch(); + } + core.debug(`killing`); + try { + process.kill(pid, "SIGTERM"); + } catch (e) { + if (typeof e === "object" && e && "code" in e && e.code !== "ESRCH") { + throw e; + } + } finally { + if (core.isDebug()) { + core.info("Entire log:"); + const entireLog = (0,external_node_fs_namespaceObject.readFileSync)(external_node_path_namespaceObject.join(daemonDir, "daemon.log")); + core.info(entireLog.toString()); + } + } + } +}; +function main() { + const cacheAction = new MagicNixCacheAction(); + cacheAction.idslib.onMain(async () => { + await cacheAction.setUpAutoCache(); + await cacheAction.notifyAutoCache(); + }); + cacheAction.idslib.onPost(async () => { + await cacheAction.tearDownAutoCache(); + }); + cacheAction.idslib.execute(); } -var idslib = new IdsToolbox({ - name: "magic-nix-cache", - fetchStyle: "gh-env-style", - idsProjectName: "magic-nix-cache-closure", - requireNix: "warn" -}); -idslib.onMain(async () => { - await setUpAutoCache(idslib); - await notifyAutoCache(); -}); -idslib.onPost(async () => { - await tearDownAutoCache(); -}); -idslib.execute(); +main(); //# sourceMappingURL=index.js.map })(); diff --git a/dist/index.js.map b/dist/index.js.map index 14c9b00..37a53a9 100644 --- a/dist/index.js.map +++ b/dist/index.js.map @@ -1 +1 @@ -{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import * as core from \"@actions/core\";\nimport { IdsToolbox } from \"detsys-ts\";\nimport got from \"got\";\nimport * as http from \"http\";\nimport { SpawnOptions, exec, spawn } from \"node:child_process\";\nimport { openSync, readFileSync } from \"node:fs\";\nimport * as fs from \"node:fs/promises\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport { inspect, promisify } from \"node:util\";\nimport { Tail } from \"tail\";\n\nconst ENV_CACHE_DAEMONDIR = \"MAGIC_NIX_CACHE_DAEMONDIR\";\n\nconst gotClient = got.extend({\n retry: {\n limit: 1,\n methods: [\"POST\", \"GET\", \"PUT\", \"HEAD\", \"DELETE\", \"OPTIONS\", \"TRACE\"],\n },\n hooks: {\n beforeRetry: [\n (error, retryCount) => {\n core.info(`Retrying after error ${error.code}, retry #: ${retryCount}`);\n },\n ],\n },\n});\n\nasync function fetchAutoCacher(toolbox: IdsToolbox): Promise {\n const closurePath = await toolbox.fetch();\n toolbox.recordEvent(\"load_closure\");\n const { stdout } = await promisify(exec)(\n `cat \"${closurePath}\" | xz -d | nix-store --import`,\n );\n\n const paths = stdout.split(os.EOL);\n // Since the export is in reverse topologically sorted order, magic-nix-cache is always the penultimate entry in the list (the empty string left by split being the last).\n const last_path = paths.at(-2);\n return `${last_path}/bin/magic-nix-cache`;\n}\n\nfunction tailLog(daemonDir: string): Tail {\n const log = new Tail(path.join(daemonDir, \"daemon.log\"));\n core.debug(`tailing daemon.log...`);\n log.on(\"line\", (line) => {\n core.info(line);\n });\n return log;\n}\n\nasync function setUpAutoCache(toolbox: IdsToolbox): Promise {\n const tmpdir = process.env[\"RUNNER_TEMP\"] || os.tmpdir();\n const required_env = [\n \"ACTIONS_CACHE_URL\",\n \"ACTIONS_RUNTIME_URL\",\n \"ACTIONS_RUNTIME_TOKEN\",\n ];\n\n let anyMissing = false;\n for (const n of required_env) {\n if (!process.env.hasOwnProperty(n)) {\n anyMissing = true;\n core.warning(\n `Disabling automatic caching since required environment ${n} isn't available`,\n );\n }\n }\n\n if (anyMissing) {\n return;\n }\n\n core.debug(`GitHub Action Cache URL: ${process.env[\"ACTIONS_CACHE_URL\"]}`);\n\n const daemonDir = await fs.mkdtemp(path.join(tmpdir, \"magic-nix-cache-\"));\n\n let daemonBin: string;\n if (core.getInput(\"source-binary\")) {\n daemonBin = core.getInput(\"source-binary\");\n } else {\n daemonBin = await fetchAutoCacher(toolbox);\n }\n\n let runEnv;\n if (core.isDebug()) {\n runEnv = {\n RUST_LOG: \"trace,magic_nix_cache=debug,gha_cache=debug\",\n RUST_BACKTRACE: \"full\",\n ...process.env,\n };\n } else {\n runEnv = process.env;\n }\n\n const notifyPort = core.getInput(\"startup-notification-port\");\n\n const notifyPromise = new Promise>((resolveListening) => {\n const promise = new Promise(async (resolveQuit) => {\n const notifyServer = http.createServer((req, res) => {\n if (req.method === \"POST\" && req.url === \"/\") {\n core.debug(`Notify server shutting down.`);\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(\"{}\");\n notifyServer.close(() => {\n resolveQuit();\n });\n }\n });\n\n notifyServer.listen(notifyPort, () => {\n core.debug(`Notify server running.`);\n resolveListening(promise);\n });\n });\n });\n\n // Start tailing the daemon log.\n const outputPath = `${daemonDir}/daemon.log`;\n const output = openSync(outputPath, \"a\");\n const log = tailLog(daemonDir);\n const netrc = await netrcPath();\n const nixConfPath = `${process.env[\"HOME\"]}/.config/nix/nix.conf`;\n\n const daemonCliFlags: string[] = [\n \"--startup-notification-url\",\n `http://127.0.0.1:${notifyPort}`,\n \"--listen\",\n core.getInput(\"listen\"),\n \"--upstream\",\n core.getInput(\"upstream-cache\"),\n \"--diagnostic-endpoint\",\n core.getInput(\"diagnostic-endpoint\"),\n \"--nix-conf\",\n nixConfPath,\n ]\n .concat(\n core.getBooleanInput(\"use-flakehub\")\n ? [\n \"--use-flakehub\",\n \"--flakehub-cache-server\",\n core.getInput(\"flakehub-cache-server\"),\n \"--flakehub-api-server\",\n core.getInput(\"flakehub-api-server\"),\n \"--flakehub-api-server-netrc\",\n netrc,\n \"--flakehub-flake-name\",\n core.getInput(\"flakehub-flake-name\"),\n ]\n : [],\n )\n .concat(core.getBooleanInput(\"use-gha-cache\") ? [\"--use-gha-cache\"] : []);\n\n const opts: SpawnOptions = {\n stdio: [\"ignore\", output, output],\n env: runEnv,\n detached: true,\n };\n\n // Display the final command for debugging purposes\n core.debug(\"Full daemon start command:\");\n core.debug(`${daemonBin} ${daemonCliFlags.join(\" \")}`);\n\n // Start the server. Once it is ready, it will notify us via the notification server.\n const daemon = spawn(daemonBin, daemonCliFlags, opts);\n\n const pidFile = path.join(daemonDir, \"daemon.pid\");\n await fs.writeFile(pidFile, `${daemon.pid}`);\n\n core.info(\"Waiting for magic-nix-cache to start...\");\n\n await new Promise((resolve, reject) => {\n notifyPromise\n // eslint-disable-next-line github/no-then\n .then((_value) => {\n resolve();\n })\n // eslint-disable-next-line github/no-then\n .catch((err) => {\n reject(new Error(`error in notifyPromise: ${err}`));\n });\n daemon.on(\"exit\", async (code, signal) => {\n if (signal) {\n reject(new Error(`Daemon was killed by signal ${signal}`));\n } else if (code) {\n reject(new Error(`Daemon exited with code ${code}`));\n } else {\n reject(new Error(`Daemon unexpectedly exited`));\n }\n });\n });\n\n daemon.unref();\n\n core.info(\"Launched Magic Nix Cache\");\n core.exportVariable(ENV_CACHE_DAEMONDIR, daemonDir);\n\n log.unwatch();\n}\n\nasync function notifyAutoCache(): Promise {\n const daemonDir = process.env[ENV_CACHE_DAEMONDIR];\n\n if (!daemonDir) {\n return;\n }\n\n try {\n core.debug(`Indicating workflow start`);\n const res: Response = await gotClient\n .post(`http://${core.getInput(\"listen\")}/api/workflow-start`)\n .json();\n core.debug(`back from post: ${res}`);\n } catch (e) {\n core.info(`Error marking the workflow as started:`);\n core.info(inspect(e));\n core.info(`Magic Nix Cache may not be running for this workflow.`);\n }\n}\n\nasync function netrcPath(): Promise {\n const expectedNetrcPath = path.join(\n process.env[\"RUNNER_TEMP\"] || os.tmpdir(),\n \"determinate-nix-installer-netrc\",\n );\n try {\n await fs.access(expectedNetrcPath);\n return expectedNetrcPath;\n } catch {\n // `nix-installer` was not used, the user may be registered with FlakeHub though.\n const destinedNetrcPath = path.join(\n process.env[\"RUNNER_TEMP\"] || os.tmpdir(),\n \"magic-nix-cache-netrc\",\n );\n try {\n await flakehub_login(destinedNetrcPath);\n } catch (e) {\n core.info(\"FlakeHub cache disabled.\");\n core.debug(`Error while logging into FlakeHub: ${e}`);\n }\n return destinedNetrcPath;\n }\n}\n\nasync function flakehub_login(netrc: string): Promise {\n const jwt = await core.getIDToken(\"api.flakehub.com\");\n\n await fs.writeFile(\n netrc,\n [\n `machine api.flakehub.com login flakehub password ${jwt}`,\n `machine flakehub.com login flakehub password ${jwt}`,\n `machine cache.flakehub.com login flakehub password ${jwt}`,\n ].join(\"\\n\"),\n );\n\n core.info(\"Logged in to FlakeHub.\");\n}\n\nasync function tearDownAutoCache(): Promise {\n const daemonDir = process.env[ENV_CACHE_DAEMONDIR];\n\n if (!daemonDir) {\n core.debug(\"magic-nix-cache not started - Skipping\");\n return;\n }\n\n const pidFile = path.join(daemonDir, \"daemon.pid\");\n const pid = parseInt(await fs.readFile(pidFile, { encoding: \"ascii\" }));\n core.debug(`found daemon pid: ${pid}`);\n if (!pid) {\n throw new Error(\"magic-nix-cache did not start successfully\");\n }\n\n const log = tailLog(daemonDir);\n\n try {\n core.debug(`about to post to localhost`);\n const res: Response = await gotClient\n .post(`http://${core.getInput(\"listen\")}/api/workflow-finish`)\n .json();\n core.debug(`back from post: ${res}`);\n } finally {\n core.debug(`unwatching the daemon log`);\n log.unwatch();\n }\n\n core.debug(`killing`);\n try {\n process.kill(pid, \"SIGTERM\");\n } catch (e) {\n if (typeof e === \"object\" && e && \"code\" in e && e.code !== \"ESRCH\") {\n throw e;\n }\n } finally {\n if (core.isDebug()) {\n core.info(\"Entire log:\");\n const entireLog = readFileSync(path.join(daemonDir, \"daemon.log\"));\n core.info(entireLog.toString());\n }\n }\n}\n\nconst idslib = new IdsToolbox({\n name: \"magic-nix-cache\",\n fetchStyle: \"gh-env-style\",\n idsProjectName: \"magic-nix-cache-closure\",\n requireNix: \"warn\",\n});\n\nidslib.onMain(async () => {\n await setUpAutoCache(idslib);\n await notifyAutoCache();\n});\nidslib.onPost(async () => {\n await tearDownAutoCache();\n});\n\nidslib.execute();\n"],"mappings":"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","names":["tmpdir"]} \ No newline at end of file +{"version":3,"sources":["../src/helpers.ts","../src/index.ts"],"sourcesContent":["import * as actionsCore from \"@actions/core\";\nimport * as fs from \"node:fs/promises\";\nimport * as os from \"node:os\";\nimport path from \"node:path\";\nimport { Tail } from \"tail\";\n\nexport function tailLog(daemonDir: string): Tail {\n const log = new Tail(path.join(daemonDir, \"daemon.log\"));\n actionsCore.debug(`tailing daemon.log...`);\n log.on(\"line\", (line) => {\n actionsCore.info(line);\n });\n return log;\n}\n\nexport async function netrcPath(): Promise {\n const expectedNetrcPath = path.join(\n process.env[\"RUNNER_TEMP\"] || os.tmpdir(),\n \"determinate-nix-installer-netrc\",\n );\n try {\n await fs.access(expectedNetrcPath);\n return expectedNetrcPath;\n } catch {\n // `nix-installer` was not used, the user may be registered with FlakeHub though.\n const destinedNetrcPath = path.join(\n process.env[\"RUNNER_TEMP\"] || os.tmpdir(),\n \"magic-nix-cache-netrc\",\n );\n try {\n await flakeHubLogin(destinedNetrcPath);\n } catch (e) {\n actionsCore.info(\"FlakeHub cache disabled.\");\n actionsCore.debug(`Error while logging into FlakeHub: ${e}`);\n }\n return destinedNetrcPath;\n }\n}\n\nasync function flakeHubLogin(netrc: string): Promise {\n const jwt = await actionsCore.getIDToken(\"api.flakehub.com\");\n\n await fs.writeFile(\n netrc,\n [\n `machine api.flakehub.com login flakehub password ${jwt}`,\n `machine flakehub.com login flakehub password ${jwt}`,\n `machine cache.flakehub.com login flakehub password ${jwt}`,\n ].join(\"\\n\"),\n );\n\n actionsCore.info(\"Logged in to FlakeHub.\");\n}\n","import { netrcPath, tailLog } from \"./helpers.js\";\nimport * as actionsCore from \"@actions/core\";\nimport { IdsToolbox, inputs } from \"detsys-ts\";\nimport got, { Got } from \"got\";\nimport * as http from \"http\";\nimport { SpawnOptions, exec, spawn } from \"node:child_process\";\nimport { openSync, readFileSync } from \"node:fs\";\nimport * as fs from \"node:fs/promises\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport { inspect, promisify } from \"node:util\";\n\nconst ENV_CACHE_DAEMONDIR = \"MAGIC_NIX_CACHE_DAEMONDIR\";\n\nclass MagicNixCacheAction {\n idslib: IdsToolbox;\n private client: Got;\n\n constructor() {\n this.idslib = new IdsToolbox({\n name: \"magic-nix-cache\",\n fetchStyle: \"gh-env-style\",\n idsProjectName: \"magic-nix-cache-closure\",\n requireNix: \"warn\",\n });\n\n this.client = got.extend({\n retry: {\n limit: 1,\n methods: [\"POST\", \"GET\", \"PUT\", \"HEAD\", \"DELETE\", \"OPTIONS\", \"TRACE\"],\n },\n hooks: {\n beforeRetry: [\n (error, retryCount) => {\n actionsCore.info(\n `Retrying after error ${error.code}, retry #: ${retryCount}`,\n );\n },\n ],\n },\n });\n }\n\n async setUpAutoCache(): Promise {\n const tmpdir = process.env[\"RUNNER_TEMP\"] || os.tmpdir();\n const requiredEnv = [\n \"ACTIONS_CACHE_URL\",\n \"ACTIONS_RUNTIME_URL\",\n \"ACTIONS_RUNTIME_TOKEN\",\n ];\n\n let anyMissing = false;\n for (const n of requiredEnv) {\n if (!process.env.hasOwnProperty(n)) {\n anyMissing = true;\n actionsCore.warning(\n `Disabling automatic caching since required environment ${n} isn't available`,\n );\n }\n }\n\n if (anyMissing) {\n return;\n }\n\n actionsCore.debug(\n `GitHub Action Cache URL: ${process.env[\"ACTIONS_CACHE_URL\"]}`,\n );\n\n const daemonDir = await fs.mkdtemp(path.join(tmpdir, \"magic-nix-cache-\"));\n const sourceBinary = inputs.getStringOrNull(\"source-binary\");\n const daemonBin =\n sourceBinary !== null ? sourceBinary : await this.fetchAutoCacher();\n\n let runEnv;\n if (actionsCore.isDebug()) {\n runEnv = {\n RUST_LOG: \"trace,magic_nix_cache=debug,gha_cache=debug\",\n RUST_BACKTRACE: \"full\",\n ...process.env,\n };\n } else {\n runEnv = process.env;\n }\n\n const notifyPort = inputs.getString(\"startup-notification-port\");\n\n const notifyPromise = new Promise>((resolveListening) => {\n const promise = new Promise(async (resolveQuit) => {\n const notifyServer = http.createServer((req, res) => {\n if (req.method === \"POST\" && req.url === \"/\") {\n actionsCore.debug(`Notify server shutting down.`);\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(\"{}\");\n notifyServer.close(() => {\n resolveQuit();\n });\n }\n });\n\n notifyServer.listen(notifyPort, () => {\n actionsCore.debug(`Notify server running.`);\n resolveListening(promise);\n });\n });\n });\n\n // Start tailing the daemon log.\n const outputPath = `${daemonDir}/daemon.log`;\n const output = openSync(outputPath, \"a\");\n const log = tailLog(daemonDir);\n const netrc = await netrcPath();\n const nixConfPath = `${process.env[\"HOME\"]}/.config/nix/nix.conf`;\n\n const hostAndPort = inputs.getString(\"listen\");\n const upstreamCache = inputs.getString(\"upstream-cache\");\n const diagnosticEndpoint = inputs.getString(\"diagnostic-endpoint\");\n const useFlakeHub = inputs.getBool(\"use-flakehub\");\n const flakeHubCacheServer = inputs.getString(\"flakehub-cache-server\");\n const flakeHubApiServer = inputs.getString(\"flakehub-api-server\");\n const flakeHubFlakeName = inputs.getString(\"flakehub-flake-name\");\n const useGhaCache = inputs.getBool(\"use-gha-cache\");\n\n const daemonCliFlags: string[] = [\n \"--startup-notification-url\",\n `http://127.0.0.1:${notifyPort}`,\n \"--listen\",\n hostAndPort,\n \"--upstream\",\n upstreamCache,\n \"--diagnostic-endpoint\",\n diagnosticEndpoint,\n \"--nix-conf\",\n nixConfPath,\n ]\n .concat(\n useFlakeHub\n ? [\n \"--use-flakehub\",\n \"--flakehub-cache-server\",\n flakeHubCacheServer,\n \"--flakehub-api-server\",\n flakeHubApiServer,\n \"--flakehub-api-server-netrc\",\n netrc,\n \"--flakehub-flake-name\",\n flakeHubFlakeName,\n ]\n : [],\n )\n .concat(useGhaCache ? [\"--use-gha-cache\"] : []);\n\n const opts: SpawnOptions = {\n stdio: [\"ignore\", output, output],\n env: runEnv,\n detached: true,\n };\n\n // Display the final command for debugging purposes\n actionsCore.debug(\"Full daemon start command:\");\n actionsCore.debug(`${daemonBin} ${daemonCliFlags.join(\" \")}`);\n\n // Start the server. Once it is ready, it will notify us via the notification server.\n const daemon = spawn(daemonBin, daemonCliFlags, opts);\n\n const pidFile = path.join(daemonDir, \"daemon.pid\");\n await fs.writeFile(pidFile, `${daemon.pid}`);\n\n actionsCore.info(\"Waiting for magic-nix-cache to start...\");\n\n await new Promise((resolve, reject) => {\n notifyPromise\n // eslint-disable-next-line github/no-then\n .then((_value) => {\n resolve();\n })\n // eslint-disable-next-line github/no-then\n .catch((err) => {\n reject(new Error(`error in notifyPromise: ${err}`));\n });\n daemon.on(\"exit\", async (code, signal) => {\n if (signal) {\n reject(new Error(`Daemon was killed by signal ${signal}`));\n } else if (code) {\n reject(new Error(`Daemon exited with code ${code}`));\n } else {\n reject(new Error(`Daemon unexpectedly exited`));\n }\n });\n });\n\n daemon.unref();\n\n actionsCore.info(\"Launched Magic Nix Cache\");\n actionsCore.exportVariable(ENV_CACHE_DAEMONDIR, daemonDir);\n\n log.unwatch();\n }\n\n private async fetchAutoCacher(): Promise {\n const closurePath = await this.idslib.fetch();\n this.idslib.recordEvent(\"load_closure\");\n const { stdout } = await promisify(exec)(\n `cat \"${closurePath}\" | xz -d | nix-store --import`,\n );\n\n const paths = stdout.split(os.EOL);\n // Since the export is in reverse topologically sorted order, magic-nix-cache is always the penultimate entry in the list (the empty string left by split being the last).\n const lastPath = paths.at(-2);\n return `${lastPath}/bin/magic-nix-cache`;\n }\n\n async notifyAutoCache(): Promise {\n const daemonDir = process.env[ENV_CACHE_DAEMONDIR];\n\n if (!daemonDir) {\n return;\n }\n\n try {\n actionsCore.debug(`Indicating workflow start`);\n const hostAndPort = inputs.getString(\"listen\");\n const res: Response = await this.client\n .post(`http://${hostAndPort}/api/workflow-start`)\n .json();\n actionsCore.debug(`back from post: ${res}`);\n } catch (e) {\n actionsCore.info(`Error marking the workflow as started:`);\n actionsCore.info(inspect(e));\n actionsCore.info(`Magic Nix Cache may not be running for this workflow.`);\n }\n }\n\n async tearDownAutoCache(): Promise {\n const daemonDir = process.env[ENV_CACHE_DAEMONDIR];\n\n if (!daemonDir) {\n actionsCore.debug(\"magic-nix-cache not started - Skipping\");\n return;\n }\n\n const pidFile = path.join(daemonDir, \"daemon.pid\");\n const pid = parseInt(await fs.readFile(pidFile, { encoding: \"ascii\" }));\n actionsCore.debug(`found daemon pid: ${pid}`);\n if (!pid) {\n throw new Error(\"magic-nix-cache did not start successfully\");\n }\n\n const log = tailLog(daemonDir);\n\n try {\n actionsCore.debug(`about to post to localhost`);\n const hostAndPort = inputs.getString(\"listen\");\n const res: Response = await this.client\n .post(`http://${hostAndPort}/api/workflow-finish`)\n .json();\n actionsCore.debug(`back from post: ${res}`);\n } finally {\n actionsCore.debug(`unwatching the daemon log`);\n log.unwatch();\n }\n\n actionsCore.debug(`killing`);\n try {\n process.kill(pid, \"SIGTERM\");\n } catch (e) {\n if (typeof e === \"object\" && e && \"code\" in e && e.code !== \"ESRCH\") {\n throw e;\n }\n } finally {\n if (actionsCore.isDebug()) {\n actionsCore.info(\"Entire log:\");\n const entireLog = readFileSync(path.join(daemonDir, \"daemon.log\"));\n actionsCore.info(entireLog.toString());\n }\n }\n }\n}\n\nfunction main(): void {\n const cacheAction = new MagicNixCacheAction();\n\n cacheAction.idslib.onMain(async () => {\n await cacheAction.setUpAutoCache();\n await cacheAction.notifyAutoCache();\n });\n cacheAction.idslib.onPost(async () => {\n await cacheAction.tearDownAutoCache();\n });\n\n cacheAction.idslib.execute();\n}\n\nmain();\n"],"mappings":"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","names":["actionsCore","fs","os","path","tmpdir"]} \ No newline at end of file diff --git a/package.json b/package.json index 89b2ca9..c8c0cce 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "@types/node": "^20.12.7", "@types/tail": "^2.2.3", "@types/uuid": "^9.0.8", - "@typescript-eslint/eslint-plugin": "^7.7.0", + "@typescript-eslint/eslint-plugin": "^7.7.1", "@vercel/ncc": "^0.38.1", "eslint": "^8.57.0", "eslint-import-resolver-typescript": "^3.6.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 52ac70f..d388965 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -19,7 +19,7 @@ dependencies: version: 2.0.1 detsys-ts: specifier: github:DeterminateSystems/detsys-ts - version: github.com/DeterminateSystems/detsys-ts/56a244c061429692b1c7d80fc068d684db3ae4d2 + version: github.com/DeterminateSystems/detsys-ts/5abcb239472d24b114a53f70800f0e42fc30819c fetch-retry: specifier: ^5.0.6 version: 5.0.6 @@ -47,8 +47,8 @@ devDependencies: specifier: ^9.0.8 version: 9.0.8 '@typescript-eslint/eslint-plugin': - specifier: ^7.7.0 - version: 7.7.0(@typescript-eslint/parser@7.7.0)(eslint@8.57.0)(typescript@5.4.5) + specifier: ^7.7.1 + version: 7.7.1(@typescript-eslint/parser@7.7.1)(eslint@8.57.0)(typescript@5.4.5) '@vercel/ncc': specifier: ^0.38.1 version: 0.38.1 @@ -57,13 +57,13 @@ devDependencies: version: 8.57.0 eslint-import-resolver-typescript: specifier: ^3.6.1 - version: 3.6.1(@typescript-eslint/parser@7.7.0)(eslint-plugin-import@2.29.1)(eslint@8.57.0) + version: 3.6.1(@typescript-eslint/parser@7.7.1)(eslint-plugin-import@2.29.1)(eslint@8.57.0) eslint-plugin-github: specifier: ^4.10.2 version: 4.10.2(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)(typescript@5.4.5) eslint-plugin-import: specifier: ^2.29.1 - version: 2.29.1(@typescript-eslint/parser@7.7.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) + version: 2.29.1(@typescript-eslint/parser@7.7.1)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) eslint-plugin-prettier: specifier: ^5.1.3 version: 5.1.3(eslint-config-prettier@9.1.0)(eslint@8.57.0)(prettier@3.2.5) @@ -844,136 +844,136 @@ packages: engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} dev: true - /@rollup/rollup-android-arm-eabi@4.16.0: - resolution: {integrity: sha512-4fDVBAfWYlw2CtYgHEWarAYSozTx5OYLsSM/cdGW7H51FwI10DaGnjKgdqWyWXY/VjugelzriCiKf1UdM20Bxg==} + /@rollup/rollup-android-arm-eabi@4.16.4: + resolution: {integrity: sha512-GkhjAaQ8oUTOKE4g4gsZ0u8K/IHU1+2WQSgS1TwTcYvL+sjbaQjNHFXbOJ6kgqGHIO1DfUhI/Sphi9GkRT9K+Q==} cpu: [arm] os: [android] requiresBuild: true dev: true optional: true - /@rollup/rollup-android-arm64@4.16.0: - resolution: {integrity: sha512-JltUBgsKgN108NO4/hj0B/dJYNrqqmdRCtUet5tFDi/w+0tvQP0FToyWBV4HKBcSX4cvFChrCyt5Rh4FX6M6QQ==} + /@rollup/rollup-android-arm64@4.16.4: + resolution: {integrity: sha512-Bvm6D+NPbGMQOcxvS1zUl8H7DWlywSXsphAeOnVeiZLQ+0J6Is8T7SrjGTH29KtYkiY9vld8ZnpV3G2EPbom+w==} cpu: [arm64] os: [android] requiresBuild: true dev: true optional: true - /@rollup/rollup-darwin-arm64@4.16.0: - resolution: {integrity: sha512-UwF7tkWf0roggMRv7Vrkof7VgX9tEZIc4vbaQl0/HNX3loWlcum+0ODp1Qsd8s7XvQGT+Zboxx1qxav3vq8YDw==} + /@rollup/rollup-darwin-arm64@4.16.4: + resolution: {integrity: sha512-i5d64MlnYBO9EkCOGe5vPR/EeDwjnKOGGdd7zKFhU5y8haKhQZTN2DgVtpODDMxUr4t2K90wTUJg7ilgND6bXw==} cpu: [arm64] os: [darwin] requiresBuild: true dev: true optional: true - /@rollup/rollup-darwin-x64@4.16.0: - resolution: {integrity: sha512-RIY42wn6+Yb0qD29T7Dvm9/AhxrkGDf7X5dgI6rUFXR19+vCLh3u45yLcKOayu2ZQEba9rf/+BX3EggVwckiIw==} + /@rollup/rollup-darwin-x64@4.16.4: + resolution: {integrity: sha512-WZupV1+CdUYehaZqjaFTClJI72fjJEgTXdf4NbW69I9XyvdmztUExBtcI2yIIU6hJtYvtwS6pkTkHJz+k08mAQ==} cpu: [x64] os: [darwin] requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-arm-gnueabihf@4.16.0: - resolution: {integrity: sha512-r2TGCIKzqk8VwjOvW7sveledh6aPao131ejUfZNIyFlWBCruF4HOu51KtLArDa7LL6qKd0vkgxGX3/2NmYpWig==} + /@rollup/rollup-linux-arm-gnueabihf@4.16.4: + resolution: {integrity: sha512-ADm/xt86JUnmAfA9mBqFcRp//RVRt1ohGOYF6yL+IFCYqOBNwy5lbEK05xTsEoJq+/tJzg8ICUtS82WinJRuIw==} cpu: [arm] os: [linux] requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-arm-musleabihf@4.16.0: - resolution: {integrity: sha512-/QwaDp0RXQTtm25wQFSl02zEm9oveRXr9qAHbdxWCm9YG9dR8esqpyqzS/3GgHDm7jHktPNz9gTENfoUKRCcXQ==} + /@rollup/rollup-linux-arm-musleabihf@4.16.4: + resolution: {integrity: sha512-tJfJaXPiFAG+Jn3cutp7mCs1ePltuAgRqdDZrzb1aeE3TktWWJ+g7xK9SNlaSUFw6IU4QgOxAY4rA+wZUT5Wfg==} cpu: [arm] os: [linux] requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-arm64-gnu@4.16.0: - resolution: {integrity: sha512-iypHsz7YEfoyNL0iHbQ7B7pY6hpymvvMgFXXaMd5+WCtvJ9zqWPZKFmo78UeWzWNmTP9JtPiNIQt6efRxx/MNA==} + /@rollup/rollup-linux-arm64-gnu@4.16.4: + resolution: {integrity: sha512-7dy1BzQkgYlUTapDTvK997cgi0Orh5Iu7JlZVBy1MBURk7/HSbHkzRnXZa19ozy+wwD8/SlpJnOOckuNZtJR9w==} cpu: [arm64] os: [linux] requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-arm64-musl@4.16.0: - resolution: {integrity: sha512-7UpYcO0uVeomnoL5MpQhrS0FT7xZUJrEXtKVLmps5bRA7x5AiA1PDuPnMbxcOBWjIM2HHIG1t3ndnRTVMIbk5A==} + /@rollup/rollup-linux-arm64-musl@4.16.4: + resolution: {integrity: sha512-zsFwdUw5XLD1gQe0aoU2HVceI6NEW7q7m05wA46eUAyrkeNYExObfRFQcvA6zw8lfRc5BHtan3tBpo+kqEOxmg==} cpu: [arm64] os: [linux] requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-powerpc64le-gnu@4.16.0: - resolution: {integrity: sha512-FSuFy4/hOQy0lH135ifnElP/6dKoHcZGHovsaRY0jrfNRR2yjMnVYaqNHKGKy0b/1I8DkD/JtclgJfq7SPti1w==} + /@rollup/rollup-linux-powerpc64le-gnu@4.16.4: + resolution: {integrity: sha512-p8C3NnxXooRdNrdv6dBmRTddEapfESEUflpICDNKXpHvTjRRq1J82CbU5G3XfebIZyI3B0s074JHMWD36qOW6w==} cpu: [ppc64] os: [linux] requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-riscv64-gnu@4.16.0: - resolution: {integrity: sha512-qxAB8MiHuDI8jU0D+WI9Gym3fvUJHA/AjKRXxbEH921SB3AeKQStq1FKFA59dAoqqCArjJ1voXM/gMvgEc1q4Q==} + /@rollup/rollup-linux-riscv64-gnu@4.16.4: + resolution: {integrity: sha512-Lh/8ckoar4s4Id2foY7jNgitTOUQczwMWNYi+Mjt0eQ9LKhr6sK477REqQkmy8YHY3Ca3A2JJVdXnfb3Rrwkng==} cpu: [riscv64] os: [linux] requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-s390x-gnu@4.16.0: - resolution: {integrity: sha512-j/9yBgWFlNFBfG/S1M2zkBNLeLkNVG59T5c4tlmlrxU+XITWJ3aMVWdpcZ/+mu7auGZftAXueAgAE9mb4lAlag==} + /@rollup/rollup-linux-s390x-gnu@4.16.4: + resolution: {integrity: sha512-1xwwn9ZCQYuqGmulGsTZoKrrn0z2fAur2ujE60QgyDpHmBbXbxLaQiEvzJWDrscRq43c8DnuHx3QorhMTZgisQ==} cpu: [s390x] os: [linux] requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-x64-gnu@4.16.0: - resolution: {integrity: sha512-SjsBA1a9wrEleNneGEsR40HdxKdwCatyHC547o/XINqwPW4cqTYiNy/lL1WTJYWU/KgWIb8HH4SgmFStbWoBzw==} + /@rollup/rollup-linux-x64-gnu@4.16.4: + resolution: {integrity: sha512-LuOGGKAJ7dfRtxVnO1i3qWc6N9sh0Em/8aZ3CezixSTM+E9Oq3OvTsvC4sm6wWjzpsIlOCnZjdluINKESflJLA==} cpu: [x64] os: [linux] requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-x64-musl@4.16.0: - resolution: {integrity: sha512-YKCs7ghJZ5po6/qgfONiXyFKOKcTK4Kerzk/Kc89QK0JT94Qg4NurL+3Y3rZh5am2tu1OlvHPpBHQNBE8cFgJQ==} + /@rollup/rollup-linux-x64-musl@4.16.4: + resolution: {integrity: sha512-ch86i7KkJKkLybDP2AtySFTRi5fM3KXp0PnHocHuJMdZwu7BuyIKi35BE9guMlmTpwwBTB3ljHj9IQXnTCD0vA==} cpu: [x64] os: [linux] requiresBuild: true dev: true optional: true - /@rollup/rollup-win32-arm64-msvc@4.16.0: - resolution: {integrity: sha512-+wtkF+z2nw0ZwwHji01wOW0loxFl24lBNxPtVAXtnPPDL9Ew0EhiCMOegXe/EAH3Zlr8Iw9tyPJXB3DltQLEyw==} + /@rollup/rollup-win32-arm64-msvc@4.16.4: + resolution: {integrity: sha512-Ma4PwyLfOWZWayfEsNQzTDBVW8PZ6TUUN1uFTBQbF2Chv/+sjenE86lpiEwj2FiviSmSZ4Ap4MaAfl1ciF4aSA==} cpu: [arm64] os: [win32] requiresBuild: true dev: true optional: true - /@rollup/rollup-win32-ia32-msvc@4.16.0: - resolution: {integrity: sha512-7qLyKTL7Lf2g0B8bduETVAEI3WVUVwBRVcECojVevPNVAmi19IW1P2X+uMSwhmWNy36Q/qEvxXsfts1I8wpawg==} + /@rollup/rollup-win32-ia32-msvc@4.16.4: + resolution: {integrity: sha512-9m/ZDrQsdo/c06uOlP3W9G2ENRVzgzbSXmXHT4hwVaDQhYcRpi9bgBT0FTG9OhESxwK0WjQxYOSfv40cU+T69w==} cpu: [ia32] os: [win32] requiresBuild: true dev: true optional: true - /@rollup/rollup-win32-x64-msvc@4.16.0: - resolution: {integrity: sha512-tkfxXt+7c3Ecgn7ln9NJPdBM+QKwQdmFFpgAP+FYhAuRS5y3tY8xeza82gFjbPpytkHmaQnVdMtuzbToCz2tuw==} + /@rollup/rollup-win32-x64-msvc@4.16.4: + resolution: {integrity: sha512-YunpoOAyGLDseanENHmbFvQSfVL5BxW3k7hhy0eN4rb3gS/ct75dVD0EXOWIqFT/nE8XYW6LP6vz6ctKRi0k9A==} cpu: [x64] os: [win32] requiresBuild: true dev: true optional: true - /@sindresorhus/is@6.2.0: - resolution: {integrity: sha512-yM/IGPkVnYGblhDosFBwq0ZGdnVSBkNV4onUtipGMOjZd4kB6GAu3ys91aftSbyMHh6A2GPdt+KDI5NoWP63MQ==} + /@sindresorhus/is@6.3.0: + resolution: {integrity: sha512-bOSPck7aIJjASXIg1qvXSIjXhVBpIEKdl2Wxg4pVqoTRPL8wWExKBrnGIh6CEnhkFQHfc36k7APhO3uXV4g5xg==} engines: {node: '>=16'} dev: false @@ -1050,8 +1050,8 @@ packages: resolution: {integrity: sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==} dev: true - /@typescript-eslint/eslint-plugin@7.7.0(@typescript-eslint/parser@7.7.0)(eslint@8.57.0)(typescript@5.4.5): - resolution: {integrity: sha512-GJWR0YnfrKnsRoluVO3PRb9r5aMZriiMMM/RHj5nnTrBy1/wIgk76XCtCKcnXGjpZQJQRFtGV9/0JJ6n30uwpQ==} + /@typescript-eslint/eslint-plugin@7.7.1(@typescript-eslint/parser@7.7.1)(eslint@8.57.0)(typescript@5.4.5): + resolution: {integrity: sha512-KwfdWXJBOviaBVhxO3p5TJiLpNuh2iyXyjmWN0f1nU87pwyvfS0EmjC6ukQVYVFJd/K1+0NWGPDXiyEyQorn0Q==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: '@typescript-eslint/parser': ^7.0.0 @@ -1062,11 +1062,11 @@ packages: optional: true dependencies: '@eslint-community/regexpp': 4.10.0 - '@typescript-eslint/parser': 7.7.0(eslint@8.57.0)(typescript@5.4.5) - '@typescript-eslint/scope-manager': 7.7.0 - '@typescript-eslint/type-utils': 7.7.0(eslint@8.57.0)(typescript@5.4.5) - '@typescript-eslint/utils': 7.7.0(eslint@8.57.0)(typescript@5.4.5) - '@typescript-eslint/visitor-keys': 7.7.0 + '@typescript-eslint/parser': 7.7.1(eslint@8.57.0)(typescript@5.4.5) + '@typescript-eslint/scope-manager': 7.7.1 + '@typescript-eslint/type-utils': 7.7.1(eslint@8.57.0)(typescript@5.4.5) + '@typescript-eslint/utils': 7.7.1(eslint@8.57.0)(typescript@5.4.5) + '@typescript-eslint/visitor-keys': 7.7.1 debug: 4.3.4 eslint: 8.57.0 graphemer: 1.4.0 @@ -1079,8 +1079,8 @@ packages: - supports-color dev: true - /@typescript-eslint/parser@7.7.0(eslint@8.57.0)(typescript@5.4.5): - resolution: {integrity: sha512-fNcDm3wSwVM8QYL4HKVBggdIPAy9Q41vcvC/GtDobw3c4ndVT3K6cqudUmjHPw8EAp4ufax0o58/xvWaP2FmTg==} + /@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5): + resolution: {integrity: sha512-vmPzBOOtz48F6JAGVS/kZYk4EkXao6iGrD838sp1w3NQQC0W8ry/q641KU4PrG7AKNAf56NOcR8GOpH8l9FPCw==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: eslint: ^8.56.0 @@ -1089,10 +1089,10 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/scope-manager': 7.7.0 - '@typescript-eslint/types': 7.7.0 - '@typescript-eslint/typescript-estree': 7.7.0(typescript@5.4.5) - '@typescript-eslint/visitor-keys': 7.7.0 + '@typescript-eslint/scope-manager': 7.7.1 + '@typescript-eslint/types': 7.7.1 + '@typescript-eslint/typescript-estree': 7.7.1(typescript@5.4.5) + '@typescript-eslint/visitor-keys': 7.7.1 debug: 4.3.4 eslint: 8.57.0 typescript: 5.4.5 @@ -1100,16 +1100,16 @@ packages: - supports-color dev: true - /@typescript-eslint/scope-manager@7.7.0: - resolution: {integrity: sha512-/8INDn0YLInbe9Wt7dK4cXLDYp0fNHP5xKLHvZl3mOT5X17rK/YShXaiNmorl+/U4VKCVIjJnx4Ri5b0y+HClw==} + /@typescript-eslint/scope-manager@7.7.1: + resolution: {integrity: sha512-PytBif2SF+9SpEUKynYn5g1RHFddJUcyynGpztX3l/ik7KmZEv19WCMhUBkHXPU9es/VWGD3/zg3wg90+Dh2rA==} engines: {node: ^18.18.0 || >=20.0.0} dependencies: - '@typescript-eslint/types': 7.7.0 - '@typescript-eslint/visitor-keys': 7.7.0 + '@typescript-eslint/types': 7.7.1 + '@typescript-eslint/visitor-keys': 7.7.1 dev: true - /@typescript-eslint/type-utils@7.7.0(eslint@8.57.0)(typescript@5.4.5): - resolution: {integrity: sha512-bOp3ejoRYrhAlnT/bozNQi3nio9tIgv3U5C0mVDdZC7cpcQEDZXvq8inrHYghLVwuNABRqrMW5tzAv88Vy77Sg==} + /@typescript-eslint/type-utils@7.7.1(eslint@8.57.0)(typescript@5.4.5): + resolution: {integrity: sha512-ZksJLW3WF7o75zaBPScdW1Gbkwhd/lyeXGf1kQCxJaOeITscoSl0MjynVvCzuV5boUz/3fOI06Lz8La55mu29Q==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: eslint: ^8.56.0 @@ -1118,8 +1118,8 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/typescript-estree': 7.7.0(typescript@5.4.5) - '@typescript-eslint/utils': 7.7.0(eslint@8.57.0)(typescript@5.4.5) + '@typescript-eslint/typescript-estree': 7.7.1(typescript@5.4.5) + '@typescript-eslint/utils': 7.7.1(eslint@8.57.0)(typescript@5.4.5) debug: 4.3.4 eslint: 8.57.0 ts-api-utils: 1.3.0(typescript@5.4.5) @@ -1128,13 +1128,13 @@ packages: - supports-color dev: true - /@typescript-eslint/types@7.7.0: - resolution: {integrity: sha512-G01YPZ1Bd2hn+KPpIbrAhEWOn5lQBrjxkzHkWvP6NucMXFtfXoevK82hzQdpfuQYuhkvFDeQYbzXCjR1z9Z03w==} + /@typescript-eslint/types@7.7.1: + resolution: {integrity: sha512-AmPmnGW1ZLTpWa+/2omPrPfR7BcbUU4oha5VIbSbS1a1Tv966bklvLNXxp3mrbc+P2j4MNOTfDffNsk4o0c6/w==} engines: {node: ^18.18.0 || >=20.0.0} dev: true - /@typescript-eslint/typescript-estree@7.7.0(typescript@5.4.5): - resolution: {integrity: sha512-8p71HQPE6CbxIBy2kWHqM1KGrC07pk6RJn40n0DSc6bMOBBREZxSDJ+BmRzc8B5OdaMh1ty3mkuWRg4sCFiDQQ==} + /@typescript-eslint/typescript-estree@7.7.1(typescript@5.4.5): + resolution: {integrity: sha512-CXe0JHCXru8Fa36dteXqmH2YxngKJjkQLjxzoj6LYwzZ7qZvgsLSc+eqItCrqIop8Vl2UKoAi0StVWu97FQZIQ==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: typescript: '*' @@ -1142,8 +1142,8 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/types': 7.7.0 - '@typescript-eslint/visitor-keys': 7.7.0 + '@typescript-eslint/types': 7.7.1 + '@typescript-eslint/visitor-keys': 7.7.1 debug: 4.3.4 globby: 11.1.0 is-glob: 4.0.3 @@ -1155,8 +1155,8 @@ packages: - supports-color dev: true - /@typescript-eslint/utils@7.7.0(eslint@8.57.0)(typescript@5.4.5): - resolution: {integrity: sha512-LKGAXMPQs8U/zMRFXDZOzmMKgFv3COlxUQ+2NMPhbqgVm6R1w+nU1i4836Pmxu9jZAuIeyySNrN/6Rc657ggig==} + /@typescript-eslint/utils@7.7.1(eslint@8.57.0)(typescript@5.4.5): + resolution: {integrity: sha512-QUvBxPEaBXf41ZBbaidKICgVL8Hin0p6prQDu6bbetWo39BKbWJxRsErOzMNT1rXvTll+J7ChrbmMCXM9rsvOQ==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: eslint: ^8.56.0 @@ -1164,9 +1164,9 @@ packages: '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) '@types/json-schema': 7.0.15 '@types/semver': 7.5.8 - '@typescript-eslint/scope-manager': 7.7.0 - '@typescript-eslint/types': 7.7.0 - '@typescript-eslint/typescript-estree': 7.7.0(typescript@5.4.5) + '@typescript-eslint/scope-manager': 7.7.1 + '@typescript-eslint/types': 7.7.1 + '@typescript-eslint/typescript-estree': 7.7.1(typescript@5.4.5) eslint: 8.57.0 semver: 7.6.0 transitivePeerDependencies: @@ -1174,11 +1174,11 @@ packages: - typescript dev: true - /@typescript-eslint/visitor-keys@7.7.0: - resolution: {integrity: sha512-h0WHOj8MhdhY8YWkzIF30R379y0NqyOHExI9N9KCzvmu05EgG4FumeYa3ccfKUSphyWkWQE1ybVrgz/Pbam6YA==} + /@typescript-eslint/visitor-keys@7.7.1: + resolution: {integrity: sha512-gBL3Eq25uADw1LQ9kVpf3hRM+DWzs0uZknHYK3hq4jcTPqVCClHGDnB6UUUV2SFeBeA4KWHWbbLqmbGcZ4FYbw==} engines: {node: ^18.18.0 || >=20.0.0} dependencies: - '@typescript-eslint/types': 7.7.0 + '@typescript-eslint/types': 7.7.1 eslint-visitor-keys: 3.4.3 dev: true @@ -1405,14 +1405,14 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true dependencies: - caniuse-lite: 1.0.30001611 - electron-to-chromium: 1.4.745 + caniuse-lite: 1.0.30001612 + electron-to-chromium: 1.4.749 node-releases: 2.0.14 update-browserslist-db: 1.0.13(browserslist@4.23.0) dev: true - /bundle-require@4.0.2(esbuild@0.19.12): - resolution: {integrity: sha512-jwzPOChofl67PSTW2SGubV9HBQAhhR2i6nskiOThauo9dzwDUgOWQScFVaJkjEfYX+UXiD+LEx8EblQMc2wIag==} + /bundle-require@4.0.3(esbuild@0.19.12): + resolution: {integrity: sha512-2iscZ3fcthP2vka4Y7j277YJevwmsby/FpFDwjgw34Nl7dtCpt7zz/4TexmHMzY6KZEih7En9ImlbbgUNNQGtA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} peerDependencies: esbuild: '>=0.17' @@ -1460,8 +1460,8 @@ packages: engines: {node: '>=6'} dev: true - /caniuse-lite@1.0.30001611: - resolution: {integrity: sha512-19NuN1/3PjA3QI8Eki55N8my4LzfkMCRLgCVfrl/slbSAchQfV0+GwjPrK3rq37As4UCLlM/DHajbKkAqbv92Q==} + /caniuse-lite@1.0.30001612: + resolution: {integrity: sha512-lFgnZ07UhaCcsSZgWW0K5j4e69dK1u/ltrL9lTUiFOwNHs12S3UMIEYgBV0Z6C6hRDev7iRnMzzYmKabYdXF9g==} dev: true /chalk@2.4.2: @@ -1668,8 +1668,8 @@ packages: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} dev: true - /electron-to-chromium@1.4.745: - resolution: {integrity: sha512-tRbzkaRI5gbUn5DEvF0dV4TQbMZ5CLkWeTAXmpC9IrYT+GE+x76i9p+o3RJ5l9XmdQlI1pPhVtE9uNcJJ0G0EA==} + /electron-to-chromium@1.4.749: + resolution: {integrity: sha512-LRMMrM9ITOvue0PoBrvNIraVmuDbJV5QC9ierz/z5VilMdPOVMjOtpICNld3PuXuTZ3CHH/UPxX9gHhAPwi+0Q==} dev: true /emoji-regex@8.0.0: @@ -1752,8 +1752,8 @@ packages: engines: {node: '>= 0.4'} dev: true - /es-iterator-helpers@1.0.18: - resolution: {integrity: sha512-scxAJaewsahbqTYrGKJihhViaM6DDZDDoucfvzNbK0pOren1g/daDQ3IAhzn+1G14rBG7w+i5N+qul60++zlKA==} + /es-iterator-helpers@1.0.19: + resolution: {integrity: sha512-zoMwbCcH5hwUkKJkT8kDIBZSz9I6mVG//+lDCinLCGov4+r7NIy0ld8o03M0cJxl2spVf6ESYVS6/gpIfq1FFw==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 @@ -1868,7 +1868,7 @@ packages: - supports-color dev: true - /eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.7.0)(eslint-plugin-import@2.29.1)(eslint@8.57.0): + /eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.7.1)(eslint-plugin-import@2.29.1)(eslint@8.57.0): resolution: {integrity: sha512-xgdptdoi5W3niYeuQxKmzVDTATvLYqhpwmykwsh7f6HIOStGWEIL9iqZgQDF9u9OEzrRwR8no5q2VT+bjAujTg==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: @@ -1878,8 +1878,8 @@ packages: debug: 4.3.4 enhanced-resolve: 5.16.0 eslint: 8.57.0 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.7.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.7.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) + eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.7.1)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.7.1)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) fast-glob: 3.3.2 get-tsconfig: 4.7.3 is-core-module: 2.13.1 @@ -1891,7 +1891,7 @@ packages: - supports-color dev: true - /eslint-module-utils@2.8.1(@typescript-eslint/parser@7.7.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0): + /eslint-module-utils@2.8.1(@typescript-eslint/parser@7.7.1)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0): resolution: {integrity: sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==} engines: {node: '>=4'} peerDependencies: @@ -1912,11 +1912,11 @@ packages: eslint-import-resolver-webpack: optional: true dependencies: - '@typescript-eslint/parser': 7.7.0(eslint@8.57.0)(typescript@5.4.5) + '@typescript-eslint/parser': 7.7.1(eslint@8.57.0)(typescript@5.4.5) debug: 3.2.7 eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.7.0)(eslint-plugin-import@2.29.1)(eslint@8.57.0) + eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.7.1)(eslint-plugin-import@2.29.1)(eslint@8.57.0) transitivePeerDependencies: - supports-color dev: true @@ -1960,8 +1960,8 @@ packages: eslint: ^8.0.1 dependencies: '@github/browserslist-config': 1.0.0 - '@typescript-eslint/eslint-plugin': 7.7.0(@typescript-eslint/parser@7.7.0)(eslint@8.57.0)(typescript@5.4.5) - '@typescript-eslint/parser': 7.7.0(eslint@8.57.0)(typescript@5.4.5) + '@typescript-eslint/eslint-plugin': 7.7.1(@typescript-eslint/parser@7.7.1)(eslint@8.57.0)(typescript@5.4.5) + '@typescript-eslint/parser': 7.7.1(eslint@8.57.0)(typescript@5.4.5) aria-query: 5.3.0 eslint: 8.57.0 eslint-config-prettier: 9.1.0(eslint@8.57.0) @@ -1969,7 +1969,7 @@ packages: eslint-plugin-eslint-comments: 3.2.0(eslint@8.57.0) eslint-plugin-filenames: 1.3.2(eslint@8.57.0) eslint-plugin-i18n-text: 1.0.1(eslint@8.57.0) - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.7.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.7.1)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) eslint-plugin-jsx-a11y: 6.8.0(eslint@8.57.0) eslint-plugin-no-only-tests: 3.1.0 eslint-plugin-prettier: 5.1.3(eslint-config-prettier@9.1.0)(eslint@8.57.0)(prettier@3.2.5) @@ -1993,7 +1993,7 @@ packages: eslint: 8.57.0 dev: true - /eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.7.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0): + /eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.7.1)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0): resolution: {integrity: sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==} engines: {node: '>=4'} peerDependencies: @@ -2003,7 +2003,7 @@ packages: '@typescript-eslint/parser': optional: true dependencies: - '@typescript-eslint/parser': 7.7.0(eslint@8.57.0)(typescript@5.4.5) + '@typescript-eslint/parser': 7.7.1(eslint@8.57.0)(typescript@5.4.5) array-includes: 3.1.8 array.prototype.findlastindex: 1.2.5 array.prototype.flat: 1.3.2 @@ -2012,7 +2012,7 @@ packages: doctrine: 2.1.0 eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.7.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) + eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.7.1)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) hasown: 2.0.2 is-core-module: 2.13.1 is-glob: 4.0.3 @@ -2043,7 +2043,7 @@ packages: axobject-query: 3.2.1 damerau-levenshtein: 1.0.8 emoji-regex: 9.2.2 - es-iterator-helpers: 1.0.18 + es-iterator-helpers: 1.0.19 eslint: 8.57.0 hasown: 2.0.2 jsx-ast-utils: 3.3.5 @@ -2454,7 +2454,7 @@ packages: resolution: {integrity: sha512-KOaPMremmsvx6l9BLC04LYE6ZFW4x7e4HkTe3LwBmtuYYQwpeS4XKqzhubTIkaQ1Nr+eXxeori0zuwupXMovBQ==} engines: {node: '>=20'} dependencies: - '@sindresorhus/is': 6.2.0 + '@sindresorhus/is': 6.3.0 '@szmarczak/http-timer': 5.0.1 cacheable-lookup: 7.0.0 cacheable-request: 10.2.14 @@ -2921,8 +2921,8 @@ packages: engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} dev: false - /lru-cache@10.2.0: - resolution: {integrity: sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==} + /lru-cache@10.2.1: + resolution: {integrity: sha512-tS24spDe/zXhWbNPErCHs/AGOzbKGHT+ybSBqmdLm8WZ1xXLWvH8Qn71QPAlqVhd0qUTWjy+Kl9JmISgDdEjsA==} engines: {node: 14 || >=16.14} dev: true @@ -3185,7 +3185,7 @@ packages: resolution: {integrity: sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==} engines: {node: '>=16 || 14 >=14.17'} dependencies: - lru-cache: 10.2.0 + lru-cache: 10.2.1 minipass: 7.0.4 dev: true @@ -3346,29 +3346,29 @@ packages: glob: 7.2.3 dev: true - /rollup@4.16.0: - resolution: {integrity: sha512-joxy/Hd4Ee289394//Q1aoebcxXyHasDieCTk8YtP4G4al4TUlx85EnuCLrfrdtLzrna9kNjH++Sx063wxSgmA==} + /rollup@4.16.4: + resolution: {integrity: sha512-kuaTJSUbz+Wsb2ATGvEknkI12XV40vIiHmLuFlejoo7HtDok/O5eDDD0UpCVY5bBX5U5RYo8wWP83H7ZsqVEnA==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true dependencies: '@types/estree': 1.0.5 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.16.0 - '@rollup/rollup-android-arm64': 4.16.0 - '@rollup/rollup-darwin-arm64': 4.16.0 - '@rollup/rollup-darwin-x64': 4.16.0 - '@rollup/rollup-linux-arm-gnueabihf': 4.16.0 - '@rollup/rollup-linux-arm-musleabihf': 4.16.0 - '@rollup/rollup-linux-arm64-gnu': 4.16.0 - '@rollup/rollup-linux-arm64-musl': 4.16.0 - '@rollup/rollup-linux-powerpc64le-gnu': 4.16.0 - '@rollup/rollup-linux-riscv64-gnu': 4.16.0 - '@rollup/rollup-linux-s390x-gnu': 4.16.0 - '@rollup/rollup-linux-x64-gnu': 4.16.0 - '@rollup/rollup-linux-x64-musl': 4.16.0 - '@rollup/rollup-win32-arm64-msvc': 4.16.0 - '@rollup/rollup-win32-ia32-msvc': 4.16.0 - '@rollup/rollup-win32-x64-msvc': 4.16.0 + '@rollup/rollup-android-arm-eabi': 4.16.4 + '@rollup/rollup-android-arm64': 4.16.4 + '@rollup/rollup-darwin-arm64': 4.16.4 + '@rollup/rollup-darwin-x64': 4.16.4 + '@rollup/rollup-linux-arm-gnueabihf': 4.16.4 + '@rollup/rollup-linux-arm-musleabihf': 4.16.4 + '@rollup/rollup-linux-arm64-gnu': 4.16.4 + '@rollup/rollup-linux-arm64-musl': 4.16.4 + '@rollup/rollup-linux-powerpc64le-gnu': 4.16.4 + '@rollup/rollup-linux-riscv64-gnu': 4.16.4 + '@rollup/rollup-linux-s390x-gnu': 4.16.4 + '@rollup/rollup-linux-x64-gnu': 4.16.4 + '@rollup/rollup-linux-x64-musl': 4.16.4 + '@rollup/rollup-win32-arm64-msvc': 4.16.4 + '@rollup/rollup-win32-ia32-msvc': 4.16.4 + '@rollup/rollup-win32-x64-msvc': 4.16.4 fsevents: 2.3.3 dev: true @@ -3709,7 +3709,7 @@ packages: typescript: optional: true dependencies: - bundle-require: 4.0.2(esbuild@0.19.12) + bundle-require: 4.0.3(esbuild@0.19.12) cac: 6.7.14 chokidar: 3.6.0 debug: 4.3.4 @@ -3719,7 +3719,7 @@ packages: joycon: 3.1.1 postcss-load-config: 4.0.2 resolve-from: 5.0.0 - rollup: 4.16.0 + rollup: 4.16.4 source-map: 0.8.0-beta.0 sucrase: 3.35.0 tree-kill: 1.2.2 @@ -3976,8 +3976,8 @@ packages: engines: {node: '>=10'} dev: true - github.com/DeterminateSystems/detsys-ts/56a244c061429692b1c7d80fc068d684db3ae4d2: - resolution: {tarball: https://codeload.github.com/DeterminateSystems/detsys-ts/tar.gz/56a244c061429692b1c7d80fc068d684db3ae4d2} + github.com/DeterminateSystems/detsys-ts/5abcb239472d24b114a53f70800f0e42fc30819c: + resolution: {tarball: https://codeload.github.com/DeterminateSystems/detsys-ts/tar.gz/5abcb239472d24b114a53f70800f0e42fc30819c} name: detsys-ts version: 1.0.0 dependencies: diff --git a/src/helpers.ts b/src/helpers.ts new file mode 100644 index 0000000..826e9d9 --- /dev/null +++ b/src/helpers.ts @@ -0,0 +1,53 @@ +import * as actionsCore from "@actions/core"; +import * as fs from "node:fs/promises"; +import * as os from "node:os"; +import path from "node:path"; +import { Tail } from "tail"; + +export function tailLog(daemonDir: string): Tail { + const log = new Tail(path.join(daemonDir, "daemon.log")); + actionsCore.debug(`tailing daemon.log...`); + log.on("line", (line) => { + actionsCore.info(line); + }); + return log; +} + +export async function netrcPath(): Promise { + const expectedNetrcPath = path.join( + process.env["RUNNER_TEMP"] || os.tmpdir(), + "determinate-nix-installer-netrc", + ); + try { + await fs.access(expectedNetrcPath); + return expectedNetrcPath; + } catch { + // `nix-installer` was not used, the user may be registered with FlakeHub though. + const destinedNetrcPath = path.join( + process.env["RUNNER_TEMP"] || os.tmpdir(), + "magic-nix-cache-netrc", + ); + try { + await flakeHubLogin(destinedNetrcPath); + } catch (e) { + actionsCore.info("FlakeHub cache disabled."); + actionsCore.debug(`Error while logging into FlakeHub: ${e}`); + } + return destinedNetrcPath; + } +} + +async function flakeHubLogin(netrc: string): Promise { + const jwt = await actionsCore.getIDToken("api.flakehub.com"); + + await fs.writeFile( + netrc, + [ + `machine api.flakehub.com login flakehub password ${jwt}`, + `machine flakehub.com login flakehub password ${jwt}`, + `machine cache.flakehub.com login flakehub password ${jwt}`, + ].join("\n"), + ); + + actionsCore.info("Logged in to FlakeHub."); +} diff --git a/src/index.ts b/src/index.ts index 6aa67ff..2fef45c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,7 @@ -import * as core from "@actions/core"; -import { IdsToolbox } from "detsys-ts"; -import got from "got"; +import { netrcPath, tailLog } from "./helpers.js"; +import * as actionsCore from "@actions/core"; +import { IdsToolbox, inputs } from "detsys-ts"; +import got, { Got } from "got"; import * as http from "http"; import { SpawnOptions, exec, spawn } from "node:child_process"; import { openSync, readFileSync } from "node:fs"; @@ -8,311 +9,286 @@ import * as fs from "node:fs/promises"; import * as os from "node:os"; import * as path from "node:path"; import { inspect, promisify } from "node:util"; -import { Tail } from "tail"; const ENV_CACHE_DAEMONDIR = "MAGIC_NIX_CACHE_DAEMONDIR"; -const gotClient = got.extend({ - retry: { - limit: 1, - methods: ["POST", "GET", "PUT", "HEAD", "DELETE", "OPTIONS", "TRACE"], - }, - hooks: { - beforeRetry: [ - (error, retryCount) => { - core.info(`Retrying after error ${error.code}, retry #: ${retryCount}`); +class MagicNixCacheAction { + idslib: IdsToolbox; + private client: Got; + + constructor() { + this.idslib = new IdsToolbox({ + name: "magic-nix-cache", + fetchStyle: "gh-env-style", + idsProjectName: "magic-nix-cache-closure", + requireNix: "warn", + }); + + this.client = got.extend({ + retry: { + limit: 1, + methods: ["POST", "GET", "PUT", "HEAD", "DELETE", "OPTIONS", "TRACE"], }, - ], - }, -}); + hooks: { + beforeRetry: [ + (error, retryCount) => { + actionsCore.info( + `Retrying after error ${error.code}, retry #: ${retryCount}`, + ); + }, + ], + }, + }); + } -async function fetchAutoCacher(toolbox: IdsToolbox): Promise { - const closurePath = await toolbox.fetch(); - toolbox.recordEvent("load_closure"); - const { stdout } = await promisify(exec)( - `cat "${closurePath}" | xz -d | nix-store --import`, - ); + async setUpAutoCache(): Promise { + const tmpdir = process.env["RUNNER_TEMP"] || os.tmpdir(); + const requiredEnv = [ + "ACTIONS_CACHE_URL", + "ACTIONS_RUNTIME_URL", + "ACTIONS_RUNTIME_TOKEN", + ]; - const paths = stdout.split(os.EOL); - // Since the export is in reverse topologically sorted order, magic-nix-cache is always the penultimate entry in the list (the empty string left by split being the last). - const last_path = paths.at(-2); - return `${last_path}/bin/magic-nix-cache`; -} - -function tailLog(daemonDir: string): Tail { - const log = new Tail(path.join(daemonDir, "daemon.log")); - core.debug(`tailing daemon.log...`); - log.on("line", (line) => { - core.info(line); - }); - return log; -} - -async function setUpAutoCache(toolbox: IdsToolbox): Promise { - const tmpdir = process.env["RUNNER_TEMP"] || os.tmpdir(); - const required_env = [ - "ACTIONS_CACHE_URL", - "ACTIONS_RUNTIME_URL", - "ACTIONS_RUNTIME_TOKEN", - ]; - - let anyMissing = false; - for (const n of required_env) { - if (!process.env.hasOwnProperty(n)) { - anyMissing = true; - core.warning( - `Disabling automatic caching since required environment ${n} isn't available`, - ); + let anyMissing = false; + for (const n of requiredEnv) { + if (!process.env.hasOwnProperty(n)) { + anyMissing = true; + actionsCore.warning( + `Disabling automatic caching since required environment ${n} isn't available`, + ); + } } - } - if (anyMissing) { - return; - } + if (anyMissing) { + return; + } - core.debug(`GitHub Action Cache URL: ${process.env["ACTIONS_CACHE_URL"]}`); + actionsCore.debug( + `GitHub Action Cache URL: ${process.env["ACTIONS_CACHE_URL"]}`, + ); - const daemonDir = await fs.mkdtemp(path.join(tmpdir, "magic-nix-cache-")); + const daemonDir = await fs.mkdtemp(path.join(tmpdir, "magic-nix-cache-")); + const sourceBinary = inputs.getStringOrNull("source-binary"); + const daemonBin = + sourceBinary !== null ? sourceBinary : await this.fetchAutoCacher(); - let daemonBin: string; - if (core.getInput("source-binary")) { - daemonBin = core.getInput("source-binary"); - } else { - daemonBin = await fetchAutoCacher(toolbox); - } + let runEnv; + if (actionsCore.isDebug()) { + runEnv = { + RUST_LOG: "trace,magic_nix_cache=debug,gha_cache=debug", + RUST_BACKTRACE: "full", + ...process.env, + }; + } else { + runEnv = process.env; + } - let runEnv; - if (core.isDebug()) { - runEnv = { - RUST_LOG: "trace,magic_nix_cache=debug,gha_cache=debug", - RUST_BACKTRACE: "full", - ...process.env, + const notifyPort = inputs.getString("startup-notification-port"); + + const notifyPromise = new Promise>((resolveListening) => { + const promise = new Promise(async (resolveQuit) => { + const notifyServer = http.createServer((req, res) => { + if (req.method === "POST" && req.url === "/") { + actionsCore.debug(`Notify server shutting down.`); + res.writeHead(200, { "Content-Type": "application/json" }); + res.end("{}"); + notifyServer.close(() => { + resolveQuit(); + }); + } + }); + + notifyServer.listen(notifyPort, () => { + actionsCore.debug(`Notify server running.`); + resolveListening(promise); + }); + }); + }); + + // Start tailing the daemon log. + const outputPath = `${daemonDir}/daemon.log`; + const output = openSync(outputPath, "a"); + const log = tailLog(daemonDir); + const netrc = await netrcPath(); + const nixConfPath = `${process.env["HOME"]}/.config/nix/nix.conf`; + + const hostAndPort = inputs.getString("listen"); + const upstreamCache = inputs.getString("upstream-cache"); + const diagnosticEndpoint = inputs.getString("diagnostic-endpoint"); + const useFlakeHub = inputs.getBool("use-flakehub"); + const flakeHubCacheServer = inputs.getString("flakehub-cache-server"); + const flakeHubApiServer = inputs.getString("flakehub-api-server"); + const flakeHubFlakeName = inputs.getString("flakehub-flake-name"); + const useGhaCache = inputs.getBool("use-gha-cache"); + + const daemonCliFlags: string[] = [ + "--startup-notification-url", + `http://127.0.0.1:${notifyPort}`, + "--listen", + hostAndPort, + "--upstream", + upstreamCache, + "--diagnostic-endpoint", + diagnosticEndpoint, + "--nix-conf", + nixConfPath, + ] + .concat( + useFlakeHub + ? [ + "--use-flakehub", + "--flakehub-cache-server", + flakeHubCacheServer, + "--flakehub-api-server", + flakeHubApiServer, + "--flakehub-api-server-netrc", + netrc, + "--flakehub-flake-name", + flakeHubFlakeName, + ] + : [], + ) + .concat(useGhaCache ? ["--use-gha-cache"] : []); + + const opts: SpawnOptions = { + stdio: ["ignore", output, output], + env: runEnv, + detached: true, }; - } else { - runEnv = process.env; - } - const notifyPort = core.getInput("startup-notification-port"); + // Display the final command for debugging purposes + actionsCore.debug("Full daemon start command:"); + actionsCore.debug(`${daemonBin} ${daemonCliFlags.join(" ")}`); - const notifyPromise = new Promise>((resolveListening) => { - const promise = new Promise(async (resolveQuit) => { - const notifyServer = http.createServer((req, res) => { - if (req.method === "POST" && req.url === "/") { - core.debug(`Notify server shutting down.`); - res.writeHead(200, { "Content-Type": "application/json" }); - res.end("{}"); - notifyServer.close(() => { - resolveQuit(); - }); + // Start the server. Once it is ready, it will notify us via the notification server. + const daemon = spawn(daemonBin, daemonCliFlags, opts); + + const pidFile = path.join(daemonDir, "daemon.pid"); + await fs.writeFile(pidFile, `${daemon.pid}`); + + actionsCore.info("Waiting for magic-nix-cache to start..."); + + await new Promise((resolve, reject) => { + notifyPromise + // eslint-disable-next-line github/no-then + .then((_value) => { + resolve(); + }) + // eslint-disable-next-line github/no-then + .catch((err) => { + reject(new Error(`error in notifyPromise: ${err}`)); + }); + daemon.on("exit", async (code, signal) => { + if (signal) { + reject(new Error(`Daemon was killed by signal ${signal}`)); + } else if (code) { + reject(new Error(`Daemon exited with code ${code}`)); + } else { + reject(new Error(`Daemon unexpectedly exited`)); } }); - - notifyServer.listen(notifyPort, () => { - core.debug(`Notify server running.`); - resolveListening(promise); - }); }); - }); - // Start tailing the daemon log. - const outputPath = `${daemonDir}/daemon.log`; - const output = openSync(outputPath, "a"); - const log = tailLog(daemonDir); - const netrc = await netrcPath(); - const nixConfPath = `${process.env["HOME"]}/.config/nix/nix.conf`; + daemon.unref(); - const daemonCliFlags: string[] = [ - "--startup-notification-url", - `http://127.0.0.1:${notifyPort}`, - "--listen", - core.getInput("listen"), - "--upstream", - core.getInput("upstream-cache"), - "--diagnostic-endpoint", - core.getInput("diagnostic-endpoint"), - "--nix-conf", - nixConfPath, - ] - .concat( - core.getBooleanInput("use-flakehub") - ? [ - "--use-flakehub", - "--flakehub-cache-server", - core.getInput("flakehub-cache-server"), - "--flakehub-api-server", - core.getInput("flakehub-api-server"), - "--flakehub-api-server-netrc", - netrc, - "--flakehub-flake-name", - core.getInput("flakehub-flake-name"), - ] - : [], - ) - .concat(core.getBooleanInput("use-gha-cache") ? ["--use-gha-cache"] : []); + actionsCore.info("Launched Magic Nix Cache"); + actionsCore.exportVariable(ENV_CACHE_DAEMONDIR, daemonDir); - const opts: SpawnOptions = { - stdio: ["ignore", output, output], - env: runEnv, - detached: true, - }; - - // Display the final command for debugging purposes - core.debug("Full daemon start command:"); - core.debug(`${daemonBin} ${daemonCliFlags.join(" ")}`); - - // Start the server. Once it is ready, it will notify us via the notification server. - const daemon = spawn(daemonBin, daemonCliFlags, opts); - - const pidFile = path.join(daemonDir, "daemon.pid"); - await fs.writeFile(pidFile, `${daemon.pid}`); - - core.info("Waiting for magic-nix-cache to start..."); - - await new Promise((resolve, reject) => { - notifyPromise - // eslint-disable-next-line github/no-then - .then((_value) => { - resolve(); - }) - // eslint-disable-next-line github/no-then - .catch((err) => { - reject(new Error(`error in notifyPromise: ${err}`)); - }); - daemon.on("exit", async (code, signal) => { - if (signal) { - reject(new Error(`Daemon was killed by signal ${signal}`)); - } else if (code) { - reject(new Error(`Daemon exited with code ${code}`)); - } else { - reject(new Error(`Daemon unexpectedly exited`)); - } - }); - }); - - daemon.unref(); - - core.info("Launched Magic Nix Cache"); - core.exportVariable(ENV_CACHE_DAEMONDIR, daemonDir); - - log.unwatch(); -} - -async function notifyAutoCache(): Promise { - const daemonDir = process.env[ENV_CACHE_DAEMONDIR]; - - if (!daemonDir) { - return; - } - - try { - core.debug(`Indicating workflow start`); - const res: Response = await gotClient - .post(`http://${core.getInput("listen")}/api/workflow-start`) - .json(); - core.debug(`back from post: ${res}`); - } catch (e) { - core.info(`Error marking the workflow as started:`); - core.info(inspect(e)); - core.info(`Magic Nix Cache may not be running for this workflow.`); - } -} - -async function netrcPath(): Promise { - const expectedNetrcPath = path.join( - process.env["RUNNER_TEMP"] || os.tmpdir(), - "determinate-nix-installer-netrc", - ); - try { - await fs.access(expectedNetrcPath); - return expectedNetrcPath; - } catch { - // `nix-installer` was not used, the user may be registered with FlakeHub though. - const destinedNetrcPath = path.join( - process.env["RUNNER_TEMP"] || os.tmpdir(), - "magic-nix-cache-netrc", - ); - try { - await flakehub_login(destinedNetrcPath); - } catch (e) { - core.info("FlakeHub cache disabled."); - core.debug(`Error while logging into FlakeHub: ${e}`); - } - return destinedNetrcPath; - } -} - -async function flakehub_login(netrc: string): Promise { - const jwt = await core.getIDToken("api.flakehub.com"); - - await fs.writeFile( - netrc, - [ - `machine api.flakehub.com login flakehub password ${jwt}`, - `machine flakehub.com login flakehub password ${jwt}`, - `machine cache.flakehub.com login flakehub password ${jwt}`, - ].join("\n"), - ); - - core.info("Logged in to FlakeHub."); -} - -async function tearDownAutoCache(): Promise { - const daemonDir = process.env[ENV_CACHE_DAEMONDIR]; - - if (!daemonDir) { - core.debug("magic-nix-cache not started - Skipping"); - return; - } - - const pidFile = path.join(daemonDir, "daemon.pid"); - const pid = parseInt(await fs.readFile(pidFile, { encoding: "ascii" })); - core.debug(`found daemon pid: ${pid}`); - if (!pid) { - throw new Error("magic-nix-cache did not start successfully"); - } - - const log = tailLog(daemonDir); - - try { - core.debug(`about to post to localhost`); - const res: Response = await gotClient - .post(`http://${core.getInput("listen")}/api/workflow-finish`) - .json(); - core.debug(`back from post: ${res}`); - } finally { - core.debug(`unwatching the daemon log`); log.unwatch(); } - core.debug(`killing`); - try { - process.kill(pid, "SIGTERM"); - } catch (e) { - if (typeof e === "object" && e && "code" in e && e.code !== "ESRCH") { - throw e; + private async fetchAutoCacher(): Promise { + const closurePath = await this.idslib.fetch(); + this.idslib.recordEvent("load_closure"); + const { stdout } = await promisify(exec)( + `cat "${closurePath}" | xz -d | nix-store --import`, + ); + + const paths = stdout.split(os.EOL); + // Since the export is in reverse topologically sorted order, magic-nix-cache is always the penultimate entry in the list (the empty string left by split being the last). + const lastPath = paths.at(-2); + return `${lastPath}/bin/magic-nix-cache`; + } + + async notifyAutoCache(): Promise { + const daemonDir = process.env[ENV_CACHE_DAEMONDIR]; + + if (!daemonDir) { + return; } - } finally { - if (core.isDebug()) { - core.info("Entire log:"); - const entireLog = readFileSync(path.join(daemonDir, "daemon.log")); - core.info(entireLog.toString()); + + try { + actionsCore.debug(`Indicating workflow start`); + const hostAndPort = inputs.getString("listen"); + const res: Response = await this.client + .post(`http://${hostAndPort}/api/workflow-start`) + .json(); + actionsCore.debug(`back from post: ${res}`); + } catch (e) { + actionsCore.info(`Error marking the workflow as started:`); + actionsCore.info(inspect(e)); + actionsCore.info(`Magic Nix Cache may not be running for this workflow.`); + } + } + + async tearDownAutoCache(): Promise { + const daemonDir = process.env[ENV_CACHE_DAEMONDIR]; + + if (!daemonDir) { + actionsCore.debug("magic-nix-cache not started - Skipping"); + return; + } + + const pidFile = path.join(daemonDir, "daemon.pid"); + const pid = parseInt(await fs.readFile(pidFile, { encoding: "ascii" })); + actionsCore.debug(`found daemon pid: ${pid}`); + if (!pid) { + throw new Error("magic-nix-cache did not start successfully"); + } + + const log = tailLog(daemonDir); + + try { + actionsCore.debug(`about to post to localhost`); + const hostAndPort = inputs.getString("listen"); + const res: Response = await this.client + .post(`http://${hostAndPort}/api/workflow-finish`) + .json(); + actionsCore.debug(`back from post: ${res}`); + } finally { + actionsCore.debug(`unwatching the daemon log`); + log.unwatch(); + } + + actionsCore.debug(`killing`); + try { + process.kill(pid, "SIGTERM"); + } catch (e) { + if (typeof e === "object" && e && "code" in e && e.code !== "ESRCH") { + throw e; + } + } finally { + if (actionsCore.isDebug()) { + actionsCore.info("Entire log:"); + const entireLog = readFileSync(path.join(daemonDir, "daemon.log")); + actionsCore.info(entireLog.toString()); + } } } } -const idslib = new IdsToolbox({ - name: "magic-nix-cache", - fetchStyle: "gh-env-style", - idsProjectName: "magic-nix-cache-closure", - requireNix: "warn", -}); +function main(): void { + const cacheAction = new MagicNixCacheAction(); -idslib.onMain(async () => { - await setUpAutoCache(idslib); - await notifyAutoCache(); -}); -idslib.onPost(async () => { - await tearDownAutoCache(); -}); + cacheAction.idslib.onMain(async () => { + await cacheAction.setUpAutoCache(); + await cacheAction.notifyAutoCache(); + }); + cacheAction.idslib.onPost(async () => { + await cacheAction.tearDownAutoCache(); + }); -idslib.execute(); + cacheAction.idslib.execute(); +} + +main();