hammerkit 1.4.0-beta.6 → 1.5.0-alpha.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 (182) hide show
  1. package/.devcontainer/Dockerfile +5 -0
  2. package/.devcontainer/devcontainer.json +40 -0
  3. package/Dockerfile +1 -1
  4. package/README.md +13 -86
  5. package/SUMMARY.md +43 -0
  6. package/build.schema.json +56 -2
  7. package/dist/cli.js +97 -0
  8. package/dist/cli.spec.js +5 -0
  9. package/dist/console/console-context-mock.js +11 -0
  10. package/dist/console/get-logger.js +23 -0
  11. package/dist/docker/pull.js +5 -5
  12. package/dist/docker/remove-container.js +21 -0
  13. package/dist/docker/stream.js +19 -21
  14. package/dist/docker/using-container.js +28 -0
  15. package/dist/environment/get-process-env.js +4 -4
  16. package/dist/environment/replace-env-variables.js +2 -3
  17. package/dist/executer/abort.js +13 -0
  18. package/dist/executer/check-readiness.js +25 -0
  19. package/dist/executer/create-scheduler-state.js +32 -0
  20. package/dist/executer/docker-node.js +123 -0
  21. package/dist/executer/docker-service.js +113 -0
  22. package/dist/executer/environment-mock.js +17 -0
  23. package/dist/executer/event-cache.js +165 -0
  24. package/dist/executer/execute-command.js +42 -0
  25. package/dist/executer/execute-docker.js +73 -223
  26. package/dist/executer/execute.spec.js +37 -37
  27. package/dist/executer/execution-steps.js +57 -0
  28. package/dist/executer/get-docker-executor.js +21 -20
  29. package/dist/executer/hierarchy-scheduler.js +94 -0
  30. package/dist/executer/kubernetes-service.js +64 -0
  31. package/dist/executer/label-values.js +65 -0
  32. package/dist/executer/local-node.js +57 -0
  33. package/dist/executer/print-container-options.js +17 -0
  34. package/dist/{logging/log-strategy.js → executer/process-item.js} +1 -1
  35. package/dist/executer/process-listener.js +3 -0
  36. package/dist/executer/process-manager.js +111 -0
  37. package/dist/executer/process-manager.spec.js +91 -0
  38. package/dist/executer/{executor.js → process.js} +1 -1
  39. package/dist/executer/{execute-result.js → readonly-state.js} +1 -1
  40. package/dist/executer/schedule.js +139 -0
  41. package/dist/executer/scheduler/check-for-loop.js +21 -0
  42. package/dist/executer/scheduler/enqueue-next.js +27 -0
  43. package/dist/{testing/test-context.js → executer/scheduler/node-state.js} +1 -1
  44. package/dist/executer/scheduler/scheduler-result.js +3 -0
  45. package/dist/executer/scheduler/scheduler-state.js +3 -0
  46. package/dist/executer/scheduler/service-state.js +3 -0
  47. package/dist/executer/service-dns.js +6 -0
  48. package/dist/executer/set-user-permission.js +16 -0
  49. package/dist/executer/start-node.js +59 -0
  50. package/dist/executer/state-listener.js +3 -0
  51. package/dist/executer/state.js +49 -0
  52. package/dist/executer/states.js +4 -129
  53. package/dist/executer/watch-node.js +57 -0
  54. package/dist/executer/watch-service.js +54 -0
  55. package/dist/executer/work-scope.js +10 -0
  56. package/dist/file/get-file-context-mock.js +1 -0
  57. package/dist/file/get-file-context-mock.spec.js +28 -27
  58. package/dist/file/get-file-context.js +73 -63
  59. package/dist/file/move-files.js +1 -1
  60. package/dist/get-work-context.js +29 -0
  61. package/dist/index.js +11 -10
  62. package/dist/log.js +209 -52
  63. package/dist/logging/grouped-logger.js +31 -19
  64. package/dist/logging/interactive-logger.js +20 -23
  65. package/dist/logging/live-logger.js +7 -17
  66. package/dist/optimizer/calculate-checksum.js +1 -1
  67. package/dist/optimizer/get-cache-directory.js +8 -13
  68. package/dist/optimizer/get-work-node-cache-stats.js +68 -21
  69. package/dist/optimizer/read-work-node-cache.js +2 -2
  70. package/dist/optimizer/work-node-cache-description.js +12 -11
  71. package/dist/optimizer/write-work-node-cache.js +9 -8
  72. package/dist/{executer/execution-context.js → parser/build-file-service.js} +1 -1
  73. package/dist/{optimizer → parser}/cache-method.js +0 -0
  74. package/dist/parser/get-build-file.js +1 -1
  75. package/dist/parser/parse-boolean.js +29 -0
  76. package/dist/parser/parse-boolean.spec.js +48 -0
  77. package/dist/parser/parse-build-file-references.js +2 -2
  78. package/dist/parser/parse-build-file-services.js +58 -0
  79. package/dist/parser/parse-build-file-task-command.js +6 -5
  80. package/dist/parser/parse-build-file-task-source.js +5 -5
  81. package/dist/parser/parse-build-file.js +29 -17
  82. package/dist/parser/parse-context.js +13 -0
  83. package/dist/parser/parse-envs.js +4 -3
  84. package/dist/parser/parse-healthcheck.js +28 -0
  85. package/dist/parser/parse-label-arguments.js +23 -0
  86. package/dist/parser/parse-service-selector.js +39 -0
  87. package/dist/parser/parse-string-array.js +6 -5
  88. package/dist/parser/parse-string-map.js +30 -0
  89. package/dist/parser/parse-string.js +20 -0
  90. package/dist/parser/read-build-file.js +16 -5
  91. package/dist/parser/read-env-file.js +7 -7
  92. package/dist/planner/utils/get-container-mounts.js +24 -0
  93. package/dist/planner/utils/normalize-path.js +17 -0
  94. package/dist/planner/utils/parse-work-node-mount.js +3 -14
  95. package/dist/planner/utils/parse-work-node-mount.spec.js +10 -10
  96. package/dist/planner/utils/parse-work-service-volume.js +21 -0
  97. package/dist/planner/utils/plan-work-command.js +1 -1
  98. package/dist/planner/utils/plan-work-dependency.js +29 -24
  99. package/dist/planner/utils/plan-work-node.js +203 -120
  100. package/dist/planner/utils/plan-work-nodes.js +60 -12
  101. package/dist/planner/utils/plan-work-tree.js +8 -4
  102. package/dist/planner/utils/plan-work-volume.js +25 -0
  103. package/dist/planner/validate.js +56 -8
  104. package/dist/planner/work-context.js +20 -0
  105. package/dist/planner/work-mount.js +3 -0
  106. package/dist/planner/work-node-id.js +4 -4
  107. package/dist/planner/work-node-id.spec.js +11 -8
  108. package/dist/planner/work-node-path.js +0 -1
  109. package/dist/planner/work-node-status.js +121 -18
  110. package/dist/planner/work-node.js +3 -3
  111. package/dist/planner/work-service-id.js +13 -0
  112. package/dist/planner/work-service-volume.js +3 -0
  113. package/dist/planner/work-service.js +6 -0
  114. package/dist/planner/work-services.js +3 -0
  115. package/dist/planner/work-volume.js +3 -0
  116. package/dist/program.js +155 -91
  117. package/dist/program.spec.js +20 -0
  118. package/dist/start-watch-processes.js +28 -0
  119. package/dist/testing/cli.js +73 -0
  120. package/dist/testing/create-build-file.js +1 -1
  121. package/dist/testing/example-test-suite.js +54 -0
  122. package/dist/testing/expect.js +30 -18
  123. package/dist/testing/get-logger.js +23 -0
  124. package/dist/testing/get-node.js +2 -2
  125. package/dist/testing/get-test-context.js +6 -5
  126. package/dist/testing/get-test-suite.js +2 -51
  127. package/dist/testing/integration/cache.spec.js +25 -28
  128. package/dist/testing/integration/cancellation.spec.js +19 -21
  129. package/dist/testing/integration/clean.spec.js +29 -13
  130. package/dist/testing/integration/cmd.spec.js +5 -8
  131. package/dist/testing/integration/concurrency.spec.js +8 -17
  132. package/dist/testing/integration/docker.spec.js +6 -9
  133. package/dist/testing/integration/env.spec.js +27 -34
  134. package/dist/testing/integration/error.spec.js +5 -9
  135. package/dist/testing/integration/extend.spec.js +32 -0
  136. package/dist/testing/integration/glob.spec.js +35 -28
  137. package/dist/testing/integration/include.spec.js +17 -16
  138. package/dist/testing/integration/invalid.spec.js +3 -2
  139. package/dist/testing/integration/invalid_loop.spec.js +13 -0
  140. package/dist/testing/integration/kubernetes.spec.js +15 -0
  141. package/dist/testing/integration/labels.spec.js +47 -0
  142. package/dist/testing/integration/local.spec.js +4 -7
  143. package/dist/testing/integration/monorepo.spec.js +6 -30
  144. package/dist/testing/integration/multi-line.spec.js +4 -4
  145. package/dist/testing/integration/program.spec.js +3 -10
  146. package/dist/testing/integration/reference.spec.js +10 -13
  147. package/dist/testing/integration/services.spec.js +14 -0
  148. package/dist/testing/integration/store.spec.js +42 -35
  149. package/dist/testing/integration/unknown.spec.js +4 -4
  150. package/dist/testing/integration/validate.spec.js +4 -4
  151. package/dist/testing/integration/watch.spec.js +25 -23
  152. package/dist/testing/lazy.js +17 -0
  153. package/dist/testing/start-watch-processes.js +29 -0
  154. package/dist/testing/test-suite-setup.js +3 -0
  155. package/dist/utils/abort-event.js +24 -0
  156. package/dist/utils/abortable-function.js +71 -0
  157. package/dist/utils/debouncer.spec.js +8 -8
  158. package/dist/utils/environment-config.js +13 -0
  159. package/dist/utils/fail-never.js +1 -1
  160. package/dist/utils/sleep.spec.js +3 -3
  161. package/package.json +24 -21
  162. package/dist/console/get-console-context-mock.js +0 -33
  163. package/dist/executer/clean.js +0 -22
  164. package/dist/executer/execute-local.js +0 -58
  165. package/dist/executer/execute.js +0 -95
  166. package/dist/executer/execution-context-event.js +0 -3
  167. package/dist/executer/execution-context-mock.js +0 -3
  168. package/dist/executer/executor-mock.js +0 -39
  169. package/dist/executer/get-environment-mock.js +0 -17
  170. package/dist/executer/get-execution-context-mock.js +0 -19
  171. package/dist/executer/get-local-executor.js +0 -22
  172. package/dist/executer/get-ready-work-nodes.js +0 -15
  173. package/dist/executer/restore.js +0 -22
  174. package/dist/executer/store.js +0 -23
  175. package/dist/logging/get-logger.js +0 -23
  176. package/dist/logging/message-to-console.js +0 -16
  177. package/dist/optimizer/optimize.js +0 -32
  178. package/dist/optimizer/work-node-description.js +0 -12
  179. package/dist/planner/utils/find-build-task.js +0 -18
  180. package/dist/testing/create-work-tree.js +0 -11
  181. package/dist/utils/defer.js +0 -57
  182. package/dist/utils/defer.spec.js +0 -76
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.startService = exports.startNode = void 0;
4
+ const enqueue_next_1 = require("./scheduler/enqueue-next");
5
+ const states_1 = require("./states");
6
+ const work_service_1 = require("../planner/work-service");
7
+ const get_work_node_cache_stats_1 = require("../optimizer/get-work-node-cache-stats");
8
+ async function startNode(node, state, environment) {
9
+ const cacheState = await (0, enqueue_next_1.checkCacheState)(node.node, state.current.cacheMethod, environment);
10
+ const currentState = state.current.node[node.node.id];
11
+ if (!!currentState.stateKey && currentState.stateKey !== cacheState.stateKey) {
12
+ const status = environment.status.task(node.node);
13
+ status.write('debug', `cache check for ${node.node.name} no longer valid, skipping result`);
14
+ return;
15
+ }
16
+ if (cacheState.cached) {
17
+ state.patchNode({
18
+ type: 'completed',
19
+ node: node.node,
20
+ cached: true,
21
+ stateKey: cacheState.stateKey,
22
+ duration: currentState.type === 'starting' ? (0, states_1.getDuration)(currentState.started) : 0,
23
+ }, node.stateKey);
24
+ }
25
+ else {
26
+ state.patchNode({
27
+ type: 'ready',
28
+ node: node.node,
29
+ stateKey: cacheState.stateKey,
30
+ started: currentState.type === 'starting' ? currentState.started : new Date(),
31
+ }, node.stateKey);
32
+ }
33
+ }
34
+ exports.startNode = startNode;
35
+ async function startService(service, state, environment) {
36
+ if (!(0, work_service_1.isContainerWorkService)(service)) {
37
+ state.patchService({
38
+ type: 'ready',
39
+ service,
40
+ stateKey: '', // TODO statekey from kube config
41
+ });
42
+ return;
43
+ }
44
+ const fileStats = await (0, get_work_node_cache_stats_1.getServiceNodeCacheStats)(service, environment);
45
+ const fileStateKey = (0, get_work_node_cache_stats_1.getStateKey)(fileStats, 'checksum');
46
+ const currentState = state.current.service[service.id];
47
+ if (!!currentState.stateKey && currentState.stateKey !== fileStateKey) {
48
+ const status = environment.status.service(service);
49
+ status.write('debug', `cache check for ${service.name} no longer valid, skipping result`);
50
+ return;
51
+ }
52
+ state.patchService({
53
+ type: 'ready',
54
+ service,
55
+ stateKey: fileStateKey,
56
+ });
57
+ }
58
+ exports.startService = startService;
59
+ //# sourceMappingURL=start-node.js.map
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=state-listener.js.map
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.State = void 0;
4
+ class State {
5
+ constructor(current) {
6
+ this.current = current;
7
+ this.listeners = [];
8
+ }
9
+ assignState(state, newValue) {
10
+ const currentKeys = Object.keys(state);
11
+ const newKeys = Object.keys(newValue);
12
+ const keysToRemove = currentKeys.filter((k) => newKeys.indexOf(k) === -1);
13
+ for (const key of keysToRemove) {
14
+ delete state[key];
15
+ }
16
+ for (const key of newKeys) {
17
+ state[key] = newValue[key];
18
+ }
19
+ }
20
+ resetNode(newState) {
21
+ const state = this.current.node[newState.node.id];
22
+ this.assignState(state, newState);
23
+ this.notifyListeners(this.current);
24
+ return state;
25
+ }
26
+ patchNode(newState, stateKey) {
27
+ const state = this.current.node[newState.node.id];
28
+ if (state.stateKey === stateKey) {
29
+ this.assignState(state, newState);
30
+ this.notifyListeners(this.current);
31
+ }
32
+ return state;
33
+ }
34
+ patchService(newState) {
35
+ this.assignState(this.current.service[newState.service.id], newState);
36
+ this.notifyListeners(this.current);
37
+ }
38
+ on(listener) {
39
+ this.listeners.push(listener);
40
+ listener(this.current);
41
+ }
42
+ notifyListeners(evt) {
43
+ for (const listener of this.listeners) {
44
+ listener(evt);
45
+ }
46
+ }
47
+ }
48
+ exports.State = State;
49
+ //# sourceMappingURL=state.js.map
@@ -1,133 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.cancelNodes = exports.resetNode = exports.failNode = exports.completeNode = exports.runNode = void 0;
4
- const plan_work_nodes_1 = require("../planner/utils/plan-work-nodes");
5
- const defer_1 = require("../utils/defer");
6
- function getDuration(state) {
7
- if (state.type === 'running') {
8
- return new Date().getTime() - state.started.getTime();
9
- }
10
- return 0;
3
+ exports.getDuration = void 0;
4
+ function getDuration(started) {
5
+ return new Date().getTime() - started.getTime();
11
6
  }
12
- function runNode(workTree, nodeId, context) {
13
- const runningState = { type: 'running', started: new Date(), cancelDefer: new defer_1.Defer() };
14
- context.environment.cancelDefer.promise.then(() => {
15
- if (!runningState.cancelDefer.isResolved) {
16
- runningState.cancelDefer.resolve();
17
- }
18
- });
19
- const currentState = workTree.nodes[nodeId].status.state;
20
- workTree.nodes[nodeId].status.state = runningState;
21
- context.runningNodes[nodeId] = workTree.nodes[nodeId];
22
- context.events.emit({ oldState: currentState, newState: runningState, nodeId, workTree });
23
- return runningState.cancelDefer;
24
- }
25
- exports.runNode = runNode;
26
- function completeNode(workTree, nodeId, context, resetCompletedNodes) {
27
- const node = workTree.nodes[nodeId];
28
- const currentState = node.status.state;
29
- const completedState = {
30
- type: 'completed',
31
- ended: new Date(),
32
- duration: getDuration(currentState),
33
- };
34
- node.status.state = completedState;
35
- if (!context.watch && !node.status.defer.isResolved) {
36
- node.status.defer.resolve();
37
- }
38
- delete context.runningNodes[node.id];
39
- for (const otherNode of plan_work_nodes_1.iterateWorkNodes(workTree.nodes)) {
40
- const dependency = otherNode.status.pendingDependencies[node.id];
41
- if (dependency) {
42
- delete otherNode.status.pendingDependencies[node.id];
43
- otherNode.status.completedDependencies[node.id] = dependency;
44
- }
45
- const completedDepNode = otherNode.status.completedDependencies[node.id];
46
- if (resetCompletedNodes && completedDepNode) {
47
- resetNode(workTree, otherNode.id, context);
48
- }
49
- }
50
- context.events.emit({ oldState: currentState, newState: completedState, nodeId, workTree });
51
- }
52
- exports.completeNode = completeNode;
53
- function failNode(workTree, nodeId, context, error) {
54
- const node = workTree.nodes[nodeId];
55
- delete context.runningNodes[nodeId];
56
- node.status.console.write('internal', 'error', error.message);
57
- const canceledExecution = context.environment.cancelDefer.isResolved;
58
- const currentState = node.status.state;
59
- if (currentState.type === 'running') {
60
- const newState = canceledExecution
61
- ? { type: 'aborted' }
62
- : { type: 'failed', ended: new Date(), duration: getDuration(node.status.state), error };
63
- node.status.state = newState;
64
- context.events.emit({ nodeId: node.id, workTree, newState, oldState: currentState });
65
- }
66
- else if (currentState.type === 'cancel') {
67
- const newState = canceledExecution ? { type: 'aborted' } : { type: 'pending' };
68
- node.status.state = newState;
69
- context.events.emit({ nodeId: node.id, workTree, newState, oldState: currentState });
70
- }
71
- if (!canceledExecution && !context.watch) {
72
- cancelPendingNodes(workTree, nodeId, context);
73
- }
74
- if ((canceledExecution || !context.watch) && !node.status.defer.isResolved) {
75
- node.status.defer.resolve();
76
- }
77
- }
78
- exports.failNode = failNode;
79
- function resetNode(workTree, nodeId, context) {
80
- const node = workTree.nodes[nodeId];
81
- const currentState = node.status.state;
82
- if (currentState.type === 'running') {
83
- const cancelState = { type: 'cancel' };
84
- node.status.state = cancelState;
85
- currentState.cancelDefer.resolve();
86
- context.events.emit({ workTree, nodeId, oldState: currentState, newState: cancelState });
87
- }
88
- else if (currentState.type === 'completed' || currentState.type === 'failed') {
89
- const pendingState = { type: 'pending' };
90
- node.status.state = pendingState;
91
- context.events.emit({ workTree, nodeId, oldState: currentState, newState: pendingState });
92
- }
93
- }
94
- exports.resetNode = resetNode;
95
- function cancelPendingNodes(workTree, nodeId, context) {
96
- for (const node of plan_work_nodes_1.iterateWorkNodes(workTree.nodes)) {
97
- if (!node.status.pendingDependencies[nodeId]) {
98
- continue;
99
- }
100
- const currentState = node.status.state;
101
- if (currentState.type === 'pending') {
102
- const cancelState = { type: 'cancel' };
103
- node.status.state = cancelState;
104
- context.events.emit({ workTree, nodeId, oldState: currentState, newState: cancelState });
105
- if (!context.watch) {
106
- node.status.defer.resolve();
107
- }
108
- cancelPendingNodes(workTree, node.id, context);
109
- }
110
- }
111
- }
112
- function cancelNodes(workTree, context) {
113
- for (const node of plan_work_nodes_1.iterateWorkNodes(workTree.nodes)) {
114
- const currentState = node.status.state;
115
- if (currentState.type === 'pending') {
116
- const abortState = { type: 'aborted' };
117
- node.status.state = abortState;
118
- node.status.defer.resolve();
119
- context.events.emit({ nodeId: node.id, workTree, newState: abortState, oldState: currentState });
120
- }
121
- else if (currentState.type === 'running') {
122
- const cancelState = { type: 'cancel' };
123
- node.status.state = cancelState;
124
- currentState.cancelDefer.resolve();
125
- context.events.emit({ workTree, nodeId: node.id, oldState: currentState, newState: cancelState });
126
- }
127
- else if ((currentState.type === 'completed' || currentState.type === 'failed') && !node.status.defer.isResolved) {
128
- node.status.defer.resolve();
129
- }
130
- }
131
- }
132
- exports.cancelNodes = cancelNodes;
7
+ exports.getDuration = getDuration;
133
8
  //# sourceMappingURL=states.js.map
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.watchNode = void 0;
4
+ const get_work_node_cache_stats_1 = require("../optimizer/get-work-node-cache-stats");
5
+ const debouncer_1 = require("../utils/debouncer");
6
+ const path_1 = require("path");
7
+ const abort_event_1 = require("../utils/abort-event");
8
+ function watchNode(node, state, processManager, environment) {
9
+ return async (abort) => {
10
+ const status = environment.status.task(node);
11
+ let currentState = await (0, get_work_node_cache_stats_1.getWorkNodeCacheStats)(node, environment);
12
+ const debouncer = new debouncer_1.Debouncer(async () => {
13
+ if (environment.abortCtrl.signal.aborted) {
14
+ return;
15
+ }
16
+ const newStats = await (0, get_work_node_cache_stats_1.getWorkNodeCacheStats)(node, environment);
17
+ const currentFileState = (0, get_work_node_cache_stats_1.getCacheState)(status, { name: node.name, caching: node.caching ?? state.current.cacheMethod }, currentState, newStats);
18
+ currentState = newStats;
19
+ const currentNodeState = state.current.node[node.id];
20
+ if (currentNodeState.stateKey === currentFileState.stateKey) {
21
+ return;
22
+ }
23
+ status.write('debug', `source changed for node ${node.name}, restart process`);
24
+ state.resetNode({
25
+ type: 'pending',
26
+ node,
27
+ stateKey: currentFileState.stateKey,
28
+ });
29
+ // TODO set dependants as pending
30
+ }, 100);
31
+ const fileWatchers = [];
32
+ const sources = [];
33
+ for (const src of node.src) {
34
+ status.write('debug', `watch ${src.absolutePath} source`);
35
+ const watcher = environment.file.watch(src.absolutePath, async (fileName) => {
36
+ const absoluteFileName = (0, path_1.join)(src.absolutePath, fileName);
37
+ if (src.matcher(absoluteFileName, node.cwd)) {
38
+ status.write('debug', `source ${absoluteFileName} change for watched task ${node.name}`);
39
+ debouncer.bounce();
40
+ }
41
+ });
42
+ sources.push(src.absolutePath);
43
+ fileWatchers.push(watcher);
44
+ }
45
+ await (0, abort_event_1.waitOnAbort)(abort.signal);
46
+ debouncer.clear();
47
+ for (const watcher of fileWatchers) {
48
+ watcher.close();
49
+ }
50
+ return {
51
+ type: 'node-watch-canceled',
52
+ node,
53
+ };
54
+ };
55
+ }
56
+ exports.watchNode = watchNode;
57
+ //# sourceMappingURL=watch-node.js.map
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.watchService = void 0;
4
+ const get_work_node_cache_stats_1 = require("../optimizer/get-work-node-cache-stats");
5
+ const debouncer_1 = require("../utils/debouncer");
6
+ const path_1 = require("path");
7
+ const abort_event_1 = require("../utils/abort-event");
8
+ function watchService(service, state, processManager, environment) {
9
+ return async (abort) => {
10
+ let currentState = await (0, get_work_node_cache_stats_1.getServiceNodeCacheStats)(service, environment);
11
+ const status = environment.status.service(service);
12
+ const debouncer = new debouncer_1.Debouncer(async () => {
13
+ if (environment.abortCtrl.signal.aborted) {
14
+ return;
15
+ }
16
+ const newStats = await (0, get_work_node_cache_stats_1.getServiceNodeCacheStats)(service, environment);
17
+ const currentFileState = (0, get_work_node_cache_stats_1.getCacheState)(status, { name: service.name, caching: state.current.cacheMethod }, currentState, newStats);
18
+ currentState = newStats;
19
+ const currentServiceState = state.current.service[service.id];
20
+ if (currentServiceState.stateKey === currentFileState.stateKey) {
21
+ return;
22
+ }
23
+ status.write('debug', `source changed for service ${service.name}, restart process`);
24
+ state.patchService({
25
+ type: 'pending',
26
+ service,
27
+ stateKey: currentFileState.stateKey,
28
+ });
29
+ }, 100);
30
+ const fileWatchers = [];
31
+ const mounts = [];
32
+ for (const mount of service.mounts) {
33
+ status.write('debug', `watch ${mount.localPath} mount`);
34
+ const watcher = environment.file.watch(mount.localPath, async (fileName) => {
35
+ const absoluteFileName = (0, path_1.join)(mount.localPath, fileName);
36
+ status.write('debug', `source ${absoluteFileName} change for watched service ${service.name}`);
37
+ debouncer.bounce();
38
+ });
39
+ mounts.push(mount.localPath);
40
+ fileWatchers.push(watcher);
41
+ }
42
+ await (0, abort_event_1.waitOnAbort)(abort.signal);
43
+ debouncer.clear();
44
+ for (const watcher of fileWatchers) {
45
+ watcher.close();
46
+ }
47
+ return {
48
+ type: 'service-watch-canceled',
49
+ service,
50
+ };
51
+ };
52
+ }
53
+ exports.watchService = watchService;
54
+ //# sourceMappingURL=watch-service.js.map
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isContextTaskFilter = exports.emptyWorkLabelScope = void 0;
4
+ function emptyWorkLabelScope() {
5
+ return { excludeLabels: {}, filterLabels: {} };
6
+ }
7
+ exports.emptyWorkLabelScope = emptyWorkLabelScope;
8
+ const isContextTaskFilter = (target) => 'taskName' in target;
9
+ exports.isContextTaskFilter = isContextTaskFilter;
10
+ //# sourceMappingURL=work-scope.js.map
@@ -103,6 +103,7 @@ function getFileContextMock() {
103
103
  }
104
104
  }
105
105
  notifyChange(parts, path);
106
+ return path;
106
107
  },
107
108
  async copy(source, destination) {
108
109
  const destinationPath = destination.split(path_1.sep);
@@ -1,55 +1,56 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const get_file_context_mock_1 = require("./get-file-context-mock");
4
- const defer_1 = require("../utils/defer");
5
4
  describe('file/get-file-context-mock', () => {
6
5
  it('should create directory', async () => {
7
- const ctx = get_file_context_mock_1.getFileContextMock();
6
+ const ctx = (0, get_file_context_mock_1.getFileContextMock)();
8
7
  await ctx.createDirectory('/home/user/repo');
9
8
  expect(await ctx.listFiles('/home/user')).toEqual(['repo']);
10
9
  });
11
10
  it('should list files', async () => {
12
- const ctx = get_file_context_mock_1.getFileContextMock();
11
+ const ctx = (0, get_file_context_mock_1.getFileContextMock)();
13
12
  await ctx.createDirectory('/home/user/repo');
14
13
  await ctx.writeFile('/home/user/test', 'abc');
15
14
  expect(await ctx.listFiles('/home/user')).toEqual(['repo', 'test']);
16
15
  });
17
16
  it('should emit listener if file below gets changed', async () => {
18
- const ctx = get_file_context_mock_1.getFileContextMock();
17
+ const ctx = (0, get_file_context_mock_1.getFileContextMock)();
19
18
  await ctx.createDirectory('/home/user/repo');
20
19
  await ctx.writeFile('/home/user/test', 'abc');
21
- const defer = new defer_1.Defer();
22
- const watch = ctx.watch('/home/user', (fileName) => {
23
- expect(fileName).toEqual('/home/user/test');
24
- defer.resolve();
20
+ await new Promise((resolve) => {
21
+ const watch = ctx.watch('/home/user', (fileName) => {
22
+ expect(fileName).toEqual('/home/user/test');
23
+ watch.close();
24
+ resolve();
25
+ });
26
+ ctx.appendFile('/home/user/test', 'def');
25
27
  });
26
- await ctx.appendFile('/home/user/test', 'def');
27
- await defer.promise;
28
- watch.close();
29
28
  });
30
29
  it('should emit listener if directory below gets created', async () => {
31
- const ctx = get_file_context_mock_1.getFileContextMock();
30
+ const ctx = (0, get_file_context_mock_1.getFileContextMock)();
32
31
  await ctx.createDirectory('/home/user/repo');
33
- const defer = new defer_1.Defer();
34
- const watch = ctx.watch('/home/user', (fileName) => {
35
- expect(fileName).toEqual('/home/user/repo/test');
36
- defer.resolve();
32
+ await new Promise((resolve) => {
33
+ const watch = ctx.watch('/home/user', (fileName) => {
34
+ expect(fileName).toEqual('/home/user/repo/test');
35
+ watch.close();
36
+ resolve();
37
+ });
38
+ ctx.createDirectory('/home/user/repo/test');
37
39
  });
38
- await ctx.createDirectory('/home/user/repo/test');
39
- await defer.promise;
40
- watch.close();
41
40
  });
42
41
  it('should not emit listener if directory above gets created', async () => {
43
- const ctx = get_file_context_mock_1.getFileContextMock();
42
+ const ctx = (0, get_file_context_mock_1.getFileContextMock)();
44
43
  await ctx.createDirectory('/home/user/repo');
45
- const defer = new defer_1.Defer();
46
- const watch = ctx.watch('/home/user', () => {
47
- defer.reject();
44
+ await new Promise((resolve, reject) => {
45
+ const watch = ctx.watch('/home/user', () => {
46
+ watch.close();
47
+ reject();
48
+ });
49
+ ctx.createDirectory('/home/test').then(() => {
50
+ watch.close();
51
+ resolve();
52
+ });
48
53
  });
49
- await ctx.createDirectory('/home/test');
50
- defer.resolve();
51
- await defer.promise;
52
- watch.close();
53
54
  });
54
55
  });
55
56
  //# sourceMappingURL=get-file-context-mock.spec.js.map
@@ -4,113 +4,123 @@ exports.getFileContext = void 0;
4
4
  const fs_1 = require("fs");
5
5
  const path_1 = require("path");
6
6
  const chokidar_1 = require("chokidar");
7
- const defer_1 = require("../utils/defer");
8
- function handleCallback(defer) {
9
- return (err, value) => {
10
- if (err) {
11
- defer.reject(err);
12
- }
13
- else {
14
- defer.resolve(value);
15
- }
16
- };
7
+ function handleCallback(callback) {
8
+ return new Promise((resolve, reject) => {
9
+ callback((err, value) => {
10
+ if (err) {
11
+ reject(err);
12
+ }
13
+ else {
14
+ resolve(value);
15
+ }
16
+ });
17
+ });
17
18
  }
18
- function getFileContext() {
19
+ function getAbsolutePath(cwd, path) {
20
+ if ((0, path_1.isAbsolute)(path)) {
21
+ return path;
22
+ }
23
+ else {
24
+ return (0, path_1.join)(cwd, path);
25
+ }
26
+ }
27
+ function getFileContext(cwd) {
19
28
  return {
20
29
  stats(path) {
21
- const defer = new defer_1.Defer();
22
- fs_1.stat(path, (err, stats) => {
23
- if (err) {
24
- defer.reject(err);
25
- }
26
- else {
27
- if (stats.isDirectory()) {
28
- defer.resolve({ type: 'directory' });
29
- }
30
- else if (stats.isFile()) {
31
- defer.resolve({ type: 'file', lastModified: stats.mtimeMs });
30
+ return new Promise((resolve, reject) => {
31
+ (0, fs_1.stat)(getAbsolutePath(cwd, path), (err, stats) => {
32
+ if (err) {
33
+ reject(err);
32
34
  }
33
35
  else {
34
- defer.resolve({ type: 'other' });
36
+ if (stats.isDirectory()) {
37
+ resolve({ type: 'directory' });
38
+ }
39
+ else if (stats.isFile()) {
40
+ resolve({ type: 'file', lastModified: stats.mtimeMs });
41
+ }
42
+ else {
43
+ resolve({ type: 'other' });
44
+ }
35
45
  }
36
- }
46
+ });
37
47
  });
38
- return defer.promise;
39
48
  },
40
49
  appendFile(path, content) {
41
- const defer = new defer_1.Defer();
42
- fs_1.appendFile(path, content, handleCallback(defer));
43
- return defer.promise;
50
+ return handleCallback((cb) => (0, fs_1.appendFile)(getAbsolutePath(cwd, path), content, cb));
44
51
  },
45
52
  writeFile(path, content) {
46
- const defer = new defer_1.Defer();
47
- fs_1.writeFile(path, content, handleCallback(defer));
48
- return defer.promise;
53
+ return handleCallback((cb) => (0, fs_1.writeFile)(getAbsolutePath(cwd, path), content, cb));
54
+ },
55
+ async writeStream(path, stream) {
56
+ const writeStream = (0, fs_1.createWriteStream)(path);
57
+ await new Promise((resolve, reject) => {
58
+ stream
59
+ .pipe(writeStream)
60
+ .on('error', (err) => reject(err))
61
+ .on('close', () => resolve());
62
+ });
49
63
  },
50
64
  listFiles(path) {
51
- const defer = new defer_1.Defer();
52
- fs_1.readdir(path, handleCallback(defer));
53
- return defer.promise;
65
+ return handleCallback((cb) => (0, fs_1.readdir)(getAbsolutePath(cwd, path), cb));
54
66
  },
55
67
  exists(path) {
56
- const defer = new defer_1.Defer();
57
- fs_1.stat(path, (err) => {
68
+ return handleCallback((cb) => (0, fs_1.stat)(getAbsolutePath(cwd, path), (err) => {
58
69
  if (err) {
59
- defer.resolve(false);
70
+ cb(null, false);
60
71
  }
61
72
  else {
62
- defer.resolve(true);
73
+ cb(null, true);
63
74
  }
64
- });
65
- return defer.promise;
75
+ }));
76
+ },
77
+ readStream(path) {
78
+ return (0, fs_1.createReadStream)(path);
66
79
  },
67
80
  read(path) {
68
- const defer = new defer_1.Defer();
69
- fs_1.readFile(path, (err, content) => {
81
+ return handleCallback((cb) => (0, fs_1.readFile)(getAbsolutePath(cwd, path), (err, content) => {
70
82
  if (err) {
71
- defer.reject(err);
83
+ cb(err, null);
72
84
  }
73
85
  else {
74
- defer.resolve(content.toString());
86
+ cb(null, content.toString());
75
87
  }
76
- });
77
- return defer.promise;
88
+ }));
78
89
  },
79
90
  async copy(source, destination) {
80
- const exists = await this.exists(source);
91
+ const absoluteSource = getAbsolutePath(cwd, source);
92
+ const absoluteDestination = getAbsolutePath(cwd, destination);
93
+ const exists = await this.exists(absoluteSource);
81
94
  if (!exists) {
82
95
  return;
83
96
  }
84
- const stats = await this.stats(source);
97
+ const stats = await this.stats(absoluteSource);
85
98
  if (stats.type === 'directory') {
86
- await this.createDirectory(destination);
87
- for (const child of await this.listFiles(source)) {
88
- await this.copy(path_1.join(source, child), path_1.join(destination, child));
99
+ await this.createDirectory(absoluteDestination);
100
+ for (const child of await this.listFiles(absoluteSource)) {
101
+ await this.copy((0, path_1.join)(absoluteSource, child), (0, path_1.join)(absoluteDestination, child));
89
102
  }
90
103
  }
91
104
  else {
92
- const destinationDirectory = path_1.dirname(destination);
105
+ const destinationDirectory = (0, path_1.dirname)(absoluteDestination);
93
106
  const existsDestinationDirectory = await this.exists(destinationDirectory);
94
107
  if (!existsDestinationDirectory) {
95
108
  await this.createDirectory(destinationDirectory);
96
109
  }
97
- const defer = new defer_1.Defer();
98
- fs_1.copyFile(source, destination, handleCallback(defer));
99
- return defer.promise;
110
+ return handleCallback((cb) => (0, fs_1.copyFile)(absoluteSource, absoluteDestination, cb));
100
111
  }
101
112
  },
102
113
  createDirectory(path) {
103
- const defer = new defer_1.Defer();
104
- fs_1.mkdir(path, { recursive: true }, handleCallback(defer));
105
- return defer.promise.then();
114
+ return handleCallback((cb) => (0, fs_1.mkdir)(getAbsolutePath(cwd, path), { recursive: true }, cb));
106
115
  },
107
- remove(path) {
108
- const defer = new defer_1.Defer();
109
- fs_1.rmdir(path, { recursive: true }, handleCallback(defer));
110
- return defer.promise;
116
+ async remove(path) {
117
+ const absolutePath = getAbsolutePath(cwd, path);
118
+ if (await this.exists(absolutePath)) {
119
+ return handleCallback((cb) => (0, fs_1.rm)(absolutePath, { recursive: true }, cb));
120
+ }
111
121
  },
112
122
  watch(path, callback) {
113
- const watcher = chokidar_1.watch(path);
123
+ const watcher = (0, chokidar_1.watch)(getAbsolutePath(cwd, path));
114
124
  watcher.on('add', (fileName) => {
115
125
  callback(fileName);
116
126
  });