@laurence79/wireit 0.14.13-shared-cache.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +1062 -0
  3. package/bin/wireit.js +9 -0
  4. package/lib/analyzer.js +1600 -0
  5. package/lib/caching/cache.js +7 -0
  6. package/lib/caching/github-actions-cache.js +832 -0
  7. package/lib/caching/local-cache.js +78 -0
  8. package/lib/caching/shared-cache.js +256 -0
  9. package/lib/cli-options.js +495 -0
  10. package/lib/cli.js +177 -0
  11. package/lib/config.js +18 -0
  12. package/lib/error.js +160 -0
  13. package/lib/event.js +7 -0
  14. package/lib/execution/base.js +108 -0
  15. package/lib/execution/no-command.js +32 -0
  16. package/lib/execution/service.js +1017 -0
  17. package/lib/execution/standard.js +683 -0
  18. package/lib/executor.js +249 -0
  19. package/lib/fingerprint.js +164 -0
  20. package/lib/ide.js +583 -0
  21. package/lib/language-server.js +135 -0
  22. package/lib/logging/combination-logger.js +41 -0
  23. package/lib/logging/debug-logger.js +43 -0
  24. package/lib/logging/logger.js +38 -0
  25. package/lib/logging/metrics-logger.js +108 -0
  26. package/lib/logging/quiet/run-tracker.js +597 -0
  27. package/lib/logging/quiet/stack-map.js +41 -0
  28. package/lib/logging/quiet/writeover-line.js +197 -0
  29. package/lib/logging/quiet-logger.js +78 -0
  30. package/lib/logging/simple-logger.js +296 -0
  31. package/lib/logging/watch-logger.js +81 -0
  32. package/lib/script-child-process.js +270 -0
  33. package/lib/util/ast.js +71 -0
  34. package/lib/util/async-cache.js +24 -0
  35. package/lib/util/copy.js +120 -0
  36. package/lib/util/deferred.js +35 -0
  37. package/lib/util/delete.js +120 -0
  38. package/lib/util/dispose.js +16 -0
  39. package/lib/util/fs.js +258 -0
  40. package/lib/util/glob.js +255 -0
  41. package/lib/util/line-monitor.js +69 -0
  42. package/lib/util/manifest.js +31 -0
  43. package/lib/util/optimize-mkdirs.js +55 -0
  44. package/lib/util/package-json-reader.js +61 -0
  45. package/lib/util/package-json.js +179 -0
  46. package/lib/util/script-data-dir.js +19 -0
  47. package/lib/util/shuffle.js +16 -0
  48. package/lib/util/unreachable.js +12 -0
  49. package/lib/util/windows.js +87 -0
  50. package/lib/util/worker-pool.js +61 -0
  51. package/lib/watcher.js +396 -0
  52. package/package.json +470 -0
  53. package/schema.json +132 -0
  54. package/wireit.svg +1 -0
package/lib/error.js ADDED
@@ -0,0 +1,160 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2022 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import * as pathlib from 'path';
7
+ export class DiagnosticPrinter {
8
+ #cwd;
9
+ /**
10
+ * @param workingDir Paths are printed relative to this directory.
11
+ */
12
+ constructor(workingDir) {
13
+ this.#cwd = workingDir;
14
+ }
15
+ print(diagnostic) {
16
+ if (diagnostic.location.range.length < 0) {
17
+ throw new Error(`Internal error: got a negative length squiggle for ${diagnostic.message}: ${diagnostic.location.range.length}`);
18
+ }
19
+ const path = this.#formatPath(diagnostic.location);
20
+ let result = `❌ ${path} ${diagnostic.message}
21
+ ${drawSquiggle(diagnostic.location, 4)}`;
22
+ if (diagnostic.supplementalLocations) {
23
+ for (const supplementalLocation of diagnostic.supplementalLocations) {
24
+ result += '\n\n' + this.#printSupplemental(supplementalLocation);
25
+ }
26
+ }
27
+ return result;
28
+ }
29
+ #printSupplemental(supplemental) {
30
+ const squiggle = drawSquiggle(supplemental.location, 8);
31
+ const path = this.#formatPath(supplemental.location);
32
+ return ` ${path} ${supplemental.message}\n${squiggle}`;
33
+ }
34
+ #formatPath(location) {
35
+ const relPath = pathlib.relative(this.#cwd, location.file.path);
36
+ const { line, character } = this.#offsetToPosition(location.file, location.range.offset);
37
+ return `${CYAN}${relPath}${RESET}:${YELLOW}${line}${RESET}:${YELLOW}${character}${RESET}`;
38
+ }
39
+ #offsetToPosition(file, offset) {
40
+ return OffsetToPositionConverter.get(file).toPosition(offset);
41
+ }
42
+ }
43
+ export class OffsetToPositionConverter {
44
+ static #cache = new WeakMap();
45
+ static get(file) {
46
+ let converter = OffsetToPositionConverter.#cache.get(file);
47
+ if (converter === undefined) {
48
+ converter = new OffsetToPositionConverter(file.contents);
49
+ OffsetToPositionConverter.#cache.set(file, converter);
50
+ }
51
+ return converter;
52
+ }
53
+ static createUncachedForTest(contents) {
54
+ return new OffsetToPositionConverter(contents);
55
+ }
56
+ constructor(contents) {
57
+ const indexes = [];
58
+ for (let i = 0; i < contents.length; i++) {
59
+ if (contents[i] === '\n') {
60
+ indexes.push(i);
61
+ }
62
+ }
63
+ this.newlineIndexes = indexes;
64
+ }
65
+ toPosition(offset) {
66
+ if (this.newlineIndexes.length === 0) {
67
+ return { line: 1, character: offset + 1 };
68
+ }
69
+ const line = this.newlineIndexes.findIndex((index) => index >= offset);
70
+ if (line === 0) {
71
+ return { line: 1, character: offset + 1 };
72
+ }
73
+ if (line === -1) {
74
+ return {
75
+ line: this.newlineIndexes.length + 1,
76
+ character: offset - (this.newlineIndexes[this.newlineIndexes.length - 1] ?? 0),
77
+ };
78
+ }
79
+ return {
80
+ line: line + 1,
81
+ character: offset - (this.newlineIndexes[line - 1] ?? 0),
82
+ };
83
+ }
84
+ toIdePosition(offset) {
85
+ const position = this.toPosition(offset);
86
+ return { line: position.line - 1, character: position.character - 1 };
87
+ }
88
+ toIdeRange(range) {
89
+ const start = this.toIdePosition(range.offset);
90
+ const end = this.toIdePosition(range.offset + range.length);
91
+ return { start, end };
92
+ }
93
+ idePositionToOffset(position) {
94
+ let lineOffset = this.newlineIndexes[position.line - 1];
95
+ lineOffset = lineOffset === undefined ? 0 : lineOffset + 1;
96
+ return lineOffset + position.character;
97
+ }
98
+ ideRangeToRange(range) {
99
+ const start = this.idePositionToOffset(range.start);
100
+ const end = this.idePositionToOffset(range.end);
101
+ return { offset: start, length: end - start };
102
+ }
103
+ }
104
+ const CYAN = '\x1b[36m';
105
+ const YELLOW = '\x1b[33m';
106
+ const RED = '\x1b[31m';
107
+ const RESET = '\x1b[0m';
108
+ // Exported for testing
109
+ export function drawSquiggle(location, indent) {
110
+ let { range: { offset, length }, } = location;
111
+ const fileContents = location.file.contents;
112
+ const startOfInitialLine = fileContents.slice(0, offset).lastIndexOf('\n') + 1;
113
+ const uncorrectedFirstNewlineIndexAfter = fileContents
114
+ .slice(offset + length)
115
+ .indexOf('\n');
116
+ const endOfLastLine = uncorrectedFirstNewlineIndexAfter === -1
117
+ ? undefined
118
+ : offset + length + uncorrectedFirstNewlineIndexAfter;
119
+ offset = offset - startOfInitialLine;
120
+ const sectionToPrint = fileContents.slice(startOfInitialLine, endOfLastLine);
121
+ let result = '';
122
+ for (const line of sectionToPrint.split('\n')) {
123
+ result += `${' '.repeat(indent)}${line}\n`;
124
+ const squiggleLength = Math.min(line.length - offset, length);
125
+ result +=
126
+ ' '.repeat(offset + indent) +
127
+ `${RED}${'~'.repeat(squiggleLength)}${RESET}\n`;
128
+ offset = 0;
129
+ length -= squiggleLength + 1; // +1 to account for the newline
130
+ }
131
+ // Drop the last newline.
132
+ return result.slice(0, -1);
133
+ }
134
+ export const offsetInsideRange = (offset, range) => offset >= range.offset && offset < range.offset + range.length;
135
+ export const offsetInsideNamedNode = (offset, namedNode) => {
136
+ const valueEnd = namedNode.offset + namedNode.length;
137
+ const totalLength = valueEnd - namedNode.name.offset;
138
+ return offsetInsideRange(offset, {
139
+ offset: namedNode.name.offset,
140
+ length: totalLength,
141
+ });
142
+ };
143
+ /**
144
+ * Convert an unexpected exception to a {@link UnknownErrorThrown} failure,
145
+ * which includes the sript context for better debugging.
146
+ */
147
+ export function convertExceptionToFailure(error, script) {
148
+ return {
149
+ ok: false,
150
+ error: [
151
+ {
152
+ type: 'failure',
153
+ reason: 'unknown-error-thrown',
154
+ script,
155
+ error,
156
+ },
157
+ ],
158
+ };
159
+ }
160
+ //# sourceMappingURL=error.js.map
package/lib/event.js ADDED
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2022 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=event.js.map
@@ -0,0 +1,108 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2022 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { shuffle } from '../util/shuffle.js';
7
+ import { Deferred } from '../util/deferred.js';
8
+ import { convertExceptionToFailure } from '../error.js';
9
+ let executionConstructorHook;
10
+ /**
11
+ * For GC testing only. A function that is called whenever an Execution is
12
+ * constructed.
13
+ */
14
+ export function registerExecutionConstructorHook(fn) {
15
+ executionConstructorHook = fn;
16
+ }
17
+ /**
18
+ * A single execution of a specific script.
19
+ */
20
+ export class BaseExecution {
21
+ #fingerprint;
22
+ constructor(config, executor, logger) {
23
+ executionConstructorHook?.(this);
24
+ this._config = config;
25
+ this._executor = executor;
26
+ this._logger = logger;
27
+ }
28
+ /**
29
+ * Execute this script and return its fingerprint. Cached, so safe to call
30
+ * multiple times.
31
+ */
32
+ async execute() {
33
+ try {
34
+ return await (this.#fingerprint ??= this._execute());
35
+ }
36
+ catch (error) {
37
+ return convertExceptionToFailure(error, this._config);
38
+ }
39
+ }
40
+ /**
41
+ * Execute all of this script's dependencies.
42
+ */
43
+ async _executeDependencies() {
44
+ // Randomize the order we execute dependencies to make it less likely for a
45
+ // user to inadvertently depend on any specific order, which could indicate
46
+ // a missing edge in the dependency graph.
47
+ shuffle(this._config.dependencies);
48
+ const dependencyResults = await Promise.all(this._config.dependencies.map((dependency) => {
49
+ return this._executor.getExecution(dependency.config).execute();
50
+ }));
51
+ const results = [];
52
+ const errors = new Set();
53
+ for (let i = 0; i < dependencyResults.length; i++) {
54
+ const result = dependencyResults[i];
55
+ if (!result.ok) {
56
+ for (const error of result.error) {
57
+ errors.add(error);
58
+ }
59
+ }
60
+ else {
61
+ results.push([this._config.dependencies[i], result.value]);
62
+ }
63
+ }
64
+ if (errors.size > 0) {
65
+ return { ok: false, error: [...errors] };
66
+ }
67
+ return { ok: true, value: results };
68
+ }
69
+ }
70
+ /**
71
+ * A single execution of a specific script which has a command.
72
+ */
73
+ export class BaseExecutionWithCommand extends BaseExecution {
74
+ constructor() {
75
+ super(...arguments);
76
+ this._servicesNotNeeded = new Deferred();
77
+ /**
78
+ * Resolves when this script no longer needs any of its service dependencies
79
+ * to be running. This could happen because it finished, failed, or never
80
+ * needed to run at all.
81
+ */
82
+ this.servicesNotNeeded = this._servicesNotNeeded.promise;
83
+ /**
84
+ * Resolves when any of the services this script depends on have terminated
85
+ * (see {@link ServiceScriptExecution.terminated} for exact definiton).
86
+ */
87
+ this._anyServiceTerminated = Promise.race(this._config.services.map((service) => this._executor.getExecution(service).terminated));
88
+ }
89
+ /**
90
+ * Ensure that all of the services this script depends on are running.
91
+ */
92
+ async _startServices() {
93
+ if (this._config.services.length > 0) {
94
+ const results = await Promise.all(this._config.services.map((service) => this._executor.getExecution(service).start()));
95
+ const errors = [];
96
+ for (const result of results) {
97
+ if (!result.ok) {
98
+ errors.push(result.error);
99
+ }
100
+ }
101
+ if (errors.length > 0) {
102
+ return { ok: false, error: errors };
103
+ }
104
+ }
105
+ return { ok: true, value: undefined };
106
+ }
107
+ }
108
+ //# sourceMappingURL=base.js.map
@@ -0,0 +1,32 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2022 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { BaseExecution } from './base.js';
7
+ import { Fingerprint } from '../fingerprint.js';
8
+ /**
9
+ * Execution for a {@link NoCommandScriptConfig}.
10
+ */
11
+ export class NoCommandScriptExecution extends BaseExecution {
12
+ async _execute() {
13
+ const dependencyFingerprints = await this._executeDependencies();
14
+ if (!dependencyFingerprints.ok) {
15
+ return dependencyFingerprints;
16
+ }
17
+ const fingerprint = await Fingerprint.compute(this._config, dependencyFingerprints.value);
18
+ if (!fingerprint.ok) {
19
+ return {
20
+ ok: false,
21
+ error: [fingerprint.error],
22
+ };
23
+ }
24
+ this._logger.log({
25
+ script: this._config,
26
+ type: 'success',
27
+ reason: 'no-command',
28
+ });
29
+ return { ok: true, value: fingerprint.value };
30
+ }
31
+ }
32
+ //# sourceMappingURL=no-command.js.map