hammerkit 1.4.0 → 1.5.0-alpha.1

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 (177) hide show
  1. package/.devcontainer/Dockerfile +5 -0
  2. package/.devcontainer/devcontainer.json +40 -0
  3. package/README.md +13 -86
  4. package/SUMMARY.md +43 -0
  5. package/build.schema.json +56 -2
  6. package/dist/cli.js +97 -0
  7. package/dist/cli.spec.js +5 -0
  8. package/dist/console/console-context-mock.js +11 -0
  9. package/dist/console/get-logger.js +23 -0
  10. package/dist/docker/pull.js +5 -5
  11. package/dist/docker/remove-container.js +21 -0
  12. package/dist/docker/stream.js +14 -10
  13. package/dist/docker/using-container.js +28 -0
  14. package/dist/environment/get-process-env.js +4 -4
  15. package/dist/environment/replace-env-variables.js +2 -3
  16. package/dist/executer/abort.js +13 -0
  17. package/dist/executer/check-readiness.js +25 -0
  18. package/dist/executer/create-scheduler-state.js +32 -0
  19. package/dist/executer/docker-node.js +123 -0
  20. package/dist/executer/docker-service.js +113 -0
  21. package/dist/executer/environment-mock.js +17 -0
  22. package/dist/executer/event-cache.js +165 -0
  23. package/dist/executer/execute-command.js +42 -0
  24. package/dist/executer/execute-docker.js +59 -195
  25. package/dist/executer/execute.spec.js +37 -37
  26. package/dist/executer/execution-steps.js +57 -0
  27. package/dist/executer/get-docker-executor.js +6 -100
  28. package/dist/executer/hierarchy-scheduler.js +94 -0
  29. package/dist/executer/kubernetes-service.js +64 -0
  30. package/dist/executer/label-values.js +65 -0
  31. package/dist/executer/local-node.js +57 -0
  32. package/dist/executer/print-container-options.js +17 -0
  33. package/dist/{logging/log-strategy.js → executer/process-item.js} +1 -1
  34. package/dist/executer/process-listener.js +3 -0
  35. package/dist/executer/process-manager.js +111 -0
  36. package/dist/executer/process-manager.spec.js +91 -0
  37. package/dist/executer/{executor.js → process.js} +1 -1
  38. package/dist/executer/{execute-result.js → readonly-state.js} +1 -1
  39. package/dist/executer/schedule.js +139 -0
  40. package/dist/executer/scheduler/check-for-loop.js +21 -0
  41. package/dist/executer/scheduler/enqueue-next.js +27 -0
  42. package/dist/{testing/test-context.js → executer/scheduler/node-state.js} +1 -1
  43. package/dist/executer/scheduler/scheduler-result.js +3 -0
  44. package/dist/executer/scheduler/scheduler-state.js +3 -0
  45. package/dist/executer/scheduler/service-state.js +3 -0
  46. package/dist/executer/service-dns.js +6 -0
  47. package/dist/executer/set-user-permission.js +16 -0
  48. package/dist/executer/start-node.js +59 -0
  49. package/dist/executer/state-listener.js +3 -0
  50. package/dist/executer/state.js +49 -0
  51. package/dist/executer/states.js +4 -159
  52. package/dist/executer/watch-node.js +57 -0
  53. package/dist/executer/watch-service.js +54 -0
  54. package/dist/executer/work-scope.js +10 -0
  55. package/dist/file/get-file-context-mock.spec.js +5 -5
  56. package/dist/file/get-file-context.js +41 -18
  57. package/dist/file/move-files.js +1 -1
  58. package/dist/get-work-context.js +29 -0
  59. package/dist/index.js +8 -4
  60. package/dist/log.js +197 -50
  61. package/dist/logging/grouped-logger.js +31 -19
  62. package/dist/logging/interactive-logger.js +20 -23
  63. package/dist/logging/live-logger.js +7 -17
  64. package/dist/optimizer/calculate-checksum.js +1 -1
  65. package/dist/optimizer/get-cache-directory.js +8 -13
  66. package/dist/optimizer/get-work-node-cache-stats.js +68 -21
  67. package/dist/optimizer/read-work-node-cache.js +2 -2
  68. package/dist/optimizer/work-node-cache-description.js +12 -11
  69. package/dist/optimizer/write-work-node-cache.js +9 -8
  70. package/dist/{executer/execution-context.js → parser/build-file-service.js} +1 -1
  71. package/dist/{optimizer → parser}/cache-method.js +0 -0
  72. package/dist/parser/get-build-file.js +1 -1
  73. package/dist/parser/parse-boolean.js +29 -0
  74. package/dist/parser/parse-boolean.spec.js +48 -0
  75. package/dist/parser/parse-build-file-references.js +2 -2
  76. package/dist/parser/parse-build-file-services.js +58 -0
  77. package/dist/parser/parse-build-file-task-command.js +6 -5
  78. package/dist/parser/parse-build-file-task-source.js +5 -5
  79. package/dist/parser/parse-build-file.js +39 -15
  80. package/dist/parser/parse-context.js +13 -0
  81. package/dist/parser/parse-envs.js +4 -3
  82. package/dist/parser/parse-healthcheck.js +28 -0
  83. package/dist/parser/parse-label-arguments.js +23 -0
  84. package/dist/parser/parse-service-selector.js +39 -0
  85. package/dist/parser/parse-string-array.js +6 -5
  86. package/dist/parser/parse-string-map.js +30 -0
  87. package/dist/parser/parse-string.js +20 -0
  88. package/dist/parser/read-build-file.js +16 -5
  89. package/dist/parser/read-env-file.js +3 -3
  90. package/dist/planner/utils/get-container-mounts.js +24 -0
  91. package/dist/planner/utils/normalize-path.js +17 -0
  92. package/dist/planner/utils/parse-work-node-mount.js +3 -14
  93. package/dist/planner/utils/parse-work-node-mount.spec.js +10 -10
  94. package/dist/planner/utils/parse-work-service-volume.js +21 -0
  95. package/dist/planner/utils/plan-work-command.js +1 -1
  96. package/dist/planner/utils/plan-work-dependency.js +14 -8
  97. package/dist/planner/utils/plan-work-node.js +203 -128
  98. package/dist/planner/utils/plan-work-nodes.js +59 -14
  99. package/dist/planner/utils/plan-work-tree.js +8 -4
  100. package/dist/planner/utils/plan-work-volume.js +29 -0
  101. package/dist/planner/validate.js +56 -8
  102. package/dist/planner/work-context.js +20 -0
  103. package/dist/planner/work-mount.js +3 -0
  104. package/dist/planner/work-node-id.js +4 -4
  105. package/dist/planner/work-node-id.spec.js +11 -8
  106. package/dist/planner/work-node-path.js +0 -1
  107. package/dist/planner/work-node-status.js +121 -18
  108. package/dist/planner/work-node.js +3 -3
  109. package/dist/planner/work-service-id.js +13 -0
  110. package/dist/planner/work-service-volume.js +3 -0
  111. package/dist/planner/work-service.js +6 -0
  112. package/dist/planner/work-services.js +3 -0
  113. package/dist/planner/work-volume.js +3 -0
  114. package/dist/program.js +155 -90
  115. package/dist/program.spec.js +20 -0
  116. package/dist/start-watch-processes.js +28 -0
  117. package/dist/testing/cli.js +73 -0
  118. package/dist/testing/create-build-file.js +1 -1
  119. package/dist/testing/example-test-suite.js +54 -0
  120. package/dist/testing/expect.js +35 -18
  121. package/dist/testing/get-logger.js +23 -0
  122. package/dist/testing/get-node.js +2 -2
  123. package/dist/testing/get-test-context.js +5 -3
  124. package/dist/testing/get-test-suite.js +2 -50
  125. package/dist/testing/integration/cache.spec.js +25 -28
  126. package/dist/testing/integration/cancellation.spec.js +19 -21
  127. package/dist/testing/integration/clean.spec.js +25 -28
  128. package/dist/testing/integration/cmd.spec.js +5 -8
  129. package/dist/testing/integration/concurrency.spec.js +8 -17
  130. package/dist/testing/integration/docker.spec.js +6 -9
  131. package/dist/testing/integration/env.spec.js +27 -34
  132. package/dist/testing/integration/error.spec.js +5 -9
  133. package/dist/testing/integration/extend.spec.js +32 -0
  134. package/dist/testing/integration/glob.spec.js +35 -28
  135. package/dist/testing/integration/include.spec.js +17 -16
  136. package/dist/testing/integration/invalid.spec.js +3 -2
  137. package/dist/testing/integration/invalid_loop.spec.js +13 -0
  138. package/dist/testing/integration/kubernetes.spec.js +15 -0
  139. package/dist/testing/integration/labels.spec.js +47 -0
  140. package/dist/testing/integration/local.spec.js +4 -7
  141. package/dist/testing/integration/monorepo.spec.js +5 -9
  142. package/dist/testing/integration/multi-line.spec.js +4 -4
  143. package/dist/testing/integration/program.spec.js +3 -10
  144. package/dist/testing/integration/reference.spec.js +10 -13
  145. package/dist/testing/integration/services.spec.js +14 -0
  146. package/dist/testing/integration/store.spec.js +42 -38
  147. package/dist/testing/integration/unknown.spec.js +4 -4
  148. package/dist/testing/integration/validate.spec.js +4 -4
  149. package/dist/testing/integration/watch.spec.js +34 -33
  150. package/dist/testing/lazy.js +17 -0
  151. package/dist/testing/start-watch-processes.js +29 -0
  152. package/dist/testing/test-suite-setup.js +3 -0
  153. package/dist/utils/abort-event.js +14 -1
  154. package/dist/utils/abortable-function.js +71 -0
  155. package/dist/utils/debouncer.spec.js +8 -8
  156. package/dist/utils/environment-config.js +13 -0
  157. package/dist/utils/fail-never.js +1 -1
  158. package/dist/utils/sleep.spec.js +3 -3
  159. package/package.json +24 -21
  160. package/dist/console/get-console-context-mock.js +0 -33
  161. package/dist/executer/clean.js +0 -17
  162. package/dist/executer/execute-local.js +0 -59
  163. package/dist/executer/execute.js +0 -139
  164. package/dist/executer/execution-context-event.js +0 -3
  165. package/dist/executer/execution-context-mock.js +0 -3
  166. package/dist/executer/executor-mock.js +0 -61
  167. package/dist/executer/get-environment-mock.js +0 -16
  168. package/dist/executer/get-execution-context-mock.js +0 -18
  169. package/dist/executer/get-local-executor.js +0 -56
  170. package/dist/executer/restore.js +0 -19
  171. package/dist/executer/store.js +0 -19
  172. package/dist/logging/get-logger.js +0 -23
  173. package/dist/logging/message-to-console.js +0 -16
  174. package/dist/optimizer/optimize.js +0 -32
  175. package/dist/optimizer/work-node-description.js +0 -12
  176. package/dist/planner/utils/find-build-task.js +0 -18
  177. package/dist/testing/create-work-tree.js +0 -11
@@ -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,163 +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 abort_event_1 = require("../utils/abort-event");
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 = {
14
- type: 'running',
15
- started: new Date(),
16
- abortCtrl: new AbortController(),
17
- };
18
- abort_event_1.listenOnAbort(context.environment.abortCtrl.signal, () => {
19
- runningState.abortCtrl.abort();
20
- });
21
- const currentState = workTree.nodes[nodeId].status.state;
22
- workTree.nodes[nodeId].status.state = runningState;
23
- context.events.emit({ oldState: currentState, newState: runningState, nodeId, workTree });
24
- return runningState.abortCtrl;
25
- }
26
- exports.runNode = runNode;
27
- function completeNode(workTree, nodeId, context) {
28
- const node = workTree.nodes[nodeId];
29
- const currentState = node.status.state;
30
- const completedState = {
31
- type: 'completed',
32
- ended: new Date(),
33
- duration: getDuration(currentState),
34
- };
35
- node.status.state = completedState;
36
- if (!context.watch && !node.status.defer.signal.aborted) {
37
- node.status.defer.abort();
38
- }
39
- context.events.emit({ oldState: currentState, newState: completedState, nodeId, workTree });
40
- for (const otherNode of plan_work_nodes_1.iterateWorkNodes(workTree.nodes)) {
41
- if (otherNode.status.state.type !== 'pending') {
42
- continue;
43
- }
44
- const pendingDependencies = otherNode.status.state.pendingDependencies;
45
- const dependency = pendingDependencies[node.id];
46
- if (!dependency) {
47
- continue;
48
- }
49
- const newState = {
50
- type: 'pending',
51
- pendingDependencies: Object.keys(pendingDependencies).reduce((map, key) => {
52
- if (pendingDependencies[key].status.state.type !== 'completed') {
53
- map[key] = pendingDependencies[key];
54
- }
55
- return map;
56
- }, {}),
57
- };
58
- const evt = {
59
- oldState: otherNode.status.state,
60
- nodeId: otherNode.id,
61
- workTree,
62
- newState,
63
- };
64
- otherNode.status.state = newState;
65
- context.events.emit(evt);
66
- }
67
- }
68
- exports.completeNode = completeNode;
69
- function failNode(workTree, nodeId, context, error) {
70
- const node = workTree.nodes[nodeId];
71
- node.status.console.write('internal', 'error', error.message);
72
- const canceledExecution = context.environment.abortCtrl.signal.aborted;
73
- const currentState = node.status.state;
74
- if (currentState.type === 'running') {
75
- const newState = canceledExecution
76
- ? { type: 'aborted' }
77
- : { type: 'failed', ended: new Date(), duration: getDuration(node.status.state), error };
78
- node.status.state = newState;
79
- context.events.emit({ nodeId: node.id, workTree, newState, oldState: currentState });
80
- }
81
- else if (currentState.type === 'cancel') {
82
- const newState = canceledExecution ? { type: 'aborted' } : getPendingState(node);
83
- node.status.state = newState;
84
- context.events.emit({ nodeId: node.id, workTree, newState, oldState: currentState });
85
- }
86
- if (!canceledExecution && !context.watch) {
87
- cancelPendingNodes(workTree, nodeId, context);
88
- }
89
- if ((canceledExecution || !context.watch) && !node.status.defer.signal.aborted) {
90
- node.status.defer.abort();
91
- }
92
- }
93
- exports.failNode = failNode;
94
- function getPendingState(node) {
95
- return {
96
- type: 'pending',
97
- pendingDependencies: node.deps.reduce((map, dep) => {
98
- if (dep.status.state.type !== 'completed') {
99
- map[dep.id] = dep;
100
- }
101
- return map;
102
- }, {}),
103
- };
104
- }
105
- function resetNode(workTree, nodeId, context) {
106
- const node = workTree.nodes[nodeId];
107
- const currentState = node.status.state;
108
- if (currentState.type === 'running') {
109
- const cancelState = { type: 'cancel' };
110
- node.status.state = cancelState;
111
- currentState.abortCtrl.abort();
112
- context.events.emit({ workTree, nodeId, oldState: currentState, newState: cancelState });
113
- }
114
- else if (currentState.type === 'completed' || currentState.type === 'failed') {
115
- const pendingState = getPendingState(node);
116
- node.status.state = pendingState;
117
- context.events.emit({ workTree, nodeId, oldState: currentState, newState: pendingState });
118
- }
119
- }
120
- exports.resetNode = resetNode;
121
- function cancelPendingNodes(workTree, nodeId, context) {
122
- for (const node of plan_work_nodes_1.iterateWorkNodes(workTree.nodes)) {
123
- if (node.status.state.type !== 'pending') {
124
- continue;
125
- }
126
- if (!node.status.state.pendingDependencies[nodeId]) {
127
- continue;
128
- }
129
- const currentState = node.status.state;
130
- if (currentState.type === 'pending') {
131
- const cancelState = { type: 'cancel' };
132
- node.status.state = cancelState;
133
- context.events.emit({ workTree, nodeId, oldState: currentState, newState: cancelState });
134
- if (!context.watch) {
135
- node.status.defer.abort();
136
- }
137
- cancelPendingNodes(workTree, node.id, context);
138
- }
139
- }
140
- }
141
- function cancelNodes(workTree, context) {
142
- for (const node of plan_work_nodes_1.iterateWorkNodes(workTree.nodes)) {
143
- const currentState = node.status.state;
144
- if (currentState.type === 'pending') {
145
- const abortState = { type: 'aborted' };
146
- node.status.state = abortState;
147
- node.status.defer.abort();
148
- context.events.emit({ nodeId: node.id, workTree, newState: abortState, oldState: currentState });
149
- }
150
- else if (currentState.type === 'running') {
151
- const cancelState = { type: 'cancel' };
152
- node.status.state = cancelState;
153
- currentState.abortCtrl.abort();
154
- context.events.emit({ workTree, nodeId: node.id, oldState: currentState, newState: cancelState });
155
- }
156
- else if ((currentState.type === 'completed' || currentState.type === 'failed') &&
157
- !node.status.defer.signal.aborted) {
158
- node.status.defer.abort();
159
- }
160
- }
161
- }
162
- exports.cancelNodes = cancelNodes;
7
+ exports.getDuration = getDuration;
163
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
@@ -3,18 +3,18 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const get_file_context_mock_1 = require("./get-file-context-mock");
4
4
  describe('file/get-file-context-mock', () => {
5
5
  it('should create directory', async () => {
6
- const ctx = get_file_context_mock_1.getFileContextMock();
6
+ const ctx = (0, get_file_context_mock_1.getFileContextMock)();
7
7
  await ctx.createDirectory('/home/user/repo');
8
8
  expect(await ctx.listFiles('/home/user')).toEqual(['repo']);
9
9
  });
10
10
  it('should list files', async () => {
11
- const ctx = get_file_context_mock_1.getFileContextMock();
11
+ const ctx = (0, get_file_context_mock_1.getFileContextMock)();
12
12
  await ctx.createDirectory('/home/user/repo');
13
13
  await ctx.writeFile('/home/user/test', 'abc');
14
14
  expect(await ctx.listFiles('/home/user')).toEqual(['repo', 'test']);
15
15
  });
16
16
  it('should emit listener if file below gets changed', async () => {
17
- const ctx = get_file_context_mock_1.getFileContextMock();
17
+ const ctx = (0, get_file_context_mock_1.getFileContextMock)();
18
18
  await ctx.createDirectory('/home/user/repo');
19
19
  await ctx.writeFile('/home/user/test', 'abc');
20
20
  await new Promise((resolve) => {
@@ -27,7 +27,7 @@ describe('file/get-file-context-mock', () => {
27
27
  });
28
28
  });
29
29
  it('should emit listener if directory below gets created', async () => {
30
- const ctx = get_file_context_mock_1.getFileContextMock();
30
+ const ctx = (0, get_file_context_mock_1.getFileContextMock)();
31
31
  await ctx.createDirectory('/home/user/repo');
32
32
  await new Promise((resolve) => {
33
33
  const watch = ctx.watch('/home/user', (fileName) => {
@@ -39,7 +39,7 @@ describe('file/get-file-context-mock', () => {
39
39
  });
40
40
  });
41
41
  it('should not emit listener if directory above gets created', async () => {
42
- const ctx = get_file_context_mock_1.getFileContextMock();
42
+ const ctx = (0, get_file_context_mock_1.getFileContextMock)();
43
43
  await ctx.createDirectory('/home/user/repo');
44
44
  await new Promise((resolve, reject) => {
45
45
  const watch = ctx.watch('/home/user', () => {
@@ -16,11 +16,19 @@ function handleCallback(callback) {
16
16
  });
17
17
  });
18
18
  }
19
- 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) {
20
28
  return {
21
29
  stats(path) {
22
30
  return new Promise((resolve, reject) => {
23
- fs_1.stat(path, (err, stats) => {
31
+ (0, fs_1.stat)(getAbsolutePath(cwd, path), (err, stats) => {
24
32
  if (err) {
25
33
  reject(err);
26
34
  }
@@ -39,16 +47,25 @@ function getFileContext() {
39
47
  });
40
48
  },
41
49
  appendFile(path, content) {
42
- return handleCallback((cb) => fs_1.appendFile(path, content, cb));
50
+ return handleCallback((cb) => (0, fs_1.appendFile)(getAbsolutePath(cwd, path), content, cb));
43
51
  },
44
52
  writeFile(path, content) {
45
- return handleCallback((cb) => fs_1.writeFile(path, content, cb));
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
+ });
46
63
  },
47
64
  listFiles(path) {
48
- return handleCallback((cb) => fs_1.readdir(path, cb));
65
+ return handleCallback((cb) => (0, fs_1.readdir)(getAbsolutePath(cwd, path), cb));
49
66
  },
50
67
  exists(path) {
51
- return handleCallback((cb) => fs_1.stat(path, (err) => {
68
+ return handleCallback((cb) => (0, fs_1.stat)(getAbsolutePath(cwd, path), (err) => {
52
69
  if (err) {
53
70
  cb(null, false);
54
71
  }
@@ -57,8 +74,11 @@ function getFileContext() {
57
74
  }
58
75
  }));
59
76
  },
77
+ readStream(path) {
78
+ return (0, fs_1.createReadStream)(path);
79
+ },
60
80
  read(path) {
61
- return handleCallback((cb) => fs_1.readFile(path, (err, content) => {
81
+ return handleCallback((cb) => (0, fs_1.readFile)(getAbsolutePath(cwd, path), (err, content) => {
62
82
  if (err) {
63
83
  cb(err, null);
64
84
  }
@@ -68,36 +88,39 @@ function getFileContext() {
68
88
  }));
69
89
  },
70
90
  async copy(source, destination) {
71
- 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);
72
94
  if (!exists) {
73
95
  return;
74
96
  }
75
- const stats = await this.stats(source);
97
+ const stats = await this.stats(absoluteSource);
76
98
  if (stats.type === 'directory') {
77
- await this.createDirectory(destination);
78
- for (const child of await this.listFiles(source)) {
79
- 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));
80
102
  }
81
103
  }
82
104
  else {
83
- const destinationDirectory = path_1.dirname(destination);
105
+ const destinationDirectory = (0, path_1.dirname)(absoluteDestination);
84
106
  const existsDestinationDirectory = await this.exists(destinationDirectory);
85
107
  if (!existsDestinationDirectory) {
86
108
  await this.createDirectory(destinationDirectory);
87
109
  }
88
- return handleCallback((cb) => fs_1.copyFile(source, destination, cb));
110
+ return handleCallback((cb) => (0, fs_1.copyFile)(absoluteSource, absoluteDestination, cb));
89
111
  }
90
112
  },
91
113
  createDirectory(path) {
92
- return handleCallback((cb) => fs_1.mkdir(path, { recursive: true }, cb));
114
+ return handleCallback((cb) => (0, fs_1.mkdir)(getAbsolutePath(cwd, path), { recursive: true }, cb));
93
115
  },
94
116
  async remove(path) {
95
- if (await this.exists(path)) {
96
- return handleCallback((cb) => fs_1.rm(path, { recursive: true }, cb));
117
+ const absolutePath = getAbsolutePath(cwd, path);
118
+ if (await this.exists(absolutePath)) {
119
+ return handleCallback((cb) => (0, fs_1.rm)(absolutePath, { recursive: true }, cb));
97
120
  }
98
121
  },
99
122
  watch(path, callback) {
100
- const watcher = chokidar_1.watch(path);
123
+ const watcher = (0, chokidar_1.watch)(getAbsolutePath(cwd, path));
101
124
  watcher.on('add', (fileName) => {
102
125
  callback(fileName);
103
126
  });
@@ -19,7 +19,7 @@ async function moveFiles(node, context, folder) {
19
19
  if (await context.file.exists(folder.to)) {
20
20
  await context.file.remove(folder.to);
21
21
  }
22
- node.status.console.write('internal', 'debug', `copy ${folder.from} to ${folder.to}`);
22
+ context.status.task(node).write('debug', `copy ${folder.from} to ${folder.to}`);
23
23
  await context.file.copy(folder.from, folder.to);
24
24
  }
25
25
  }
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getWorkScope = void 0;
4
+ const plan_work_tree_1 = require("./planner/utils/plan-work-tree");
5
+ const plan_work_nodes_1 = require("./planner/utils/plan-work-nodes");
6
+ const work_scope_1 = require("./executer/work-scope");
7
+ const replace_env_variables_1 = require("./environment/replace-env-variables");
8
+ const work_service_1 = require("./planner/work-service");
9
+ const work_node_1 = require("./planner/work-node");
10
+ const get_process_env_1 = require("./environment/get-process-env");
11
+ function getWorkScope(buildFile, contextFilter, environment) {
12
+ const tree = (0, work_scope_1.isContextTaskFilter)(contextFilter)
13
+ ? (0, plan_work_tree_1.planWorkTree)(buildFile, { taskName: contextFilter.taskName })
14
+ : (0, plan_work_nodes_1.planWorkNodes)(buildFile, contextFilter);
15
+ for (const node of (0, plan_work_nodes_1.iterateWorkNodes)(tree.nodes)) {
16
+ node.envs = (0, replace_env_variables_1.replaceEnvVariables)(node.envs, environment.processEnvs);
17
+ if (!(0, work_node_1.isContainerWorkNode)(node)) {
18
+ node.envs = (0, get_process_env_1.extendHostVariables)(node.envs, environment);
19
+ }
20
+ }
21
+ for (const service of (0, plan_work_nodes_1.iterateWorkServices)(tree.services)) {
22
+ if ((0, work_service_1.isContainerWorkService)(service)) {
23
+ service.envs = (0, replace_env_variables_1.replaceEnvVariables)(service.envs, environment.processEnvs);
24
+ }
25
+ }
26
+ return tree;
27
+ }
28
+ exports.getWorkScope = getWorkScope;
29
+ //# sourceMappingURL=get-work-context.js.map
package/dist/index.js CHANGED
@@ -4,17 +4,21 @@ Object.defineProperty(exports, "__esModule", { value: true });
4
4
  const program_1 = require("./program");
5
5
  const log_1 = require("./log");
6
6
  const get_file_context_1 = require("./file/get-file-context");
7
+ const work_node_status_1 = require("./planner/work-node-status");
8
+ const execute_docker_1 = require("./executer/execute-docker");
7
9
  const abortCtrl = new AbortController();
8
10
  process.on('SIGINT', function () {
9
11
  abortCtrl.abort();
10
12
  });
11
- program_1.getProgram({
13
+ (0, program_1.getProgram)({
12
14
  cwd: process.cwd(),
13
15
  abortCtrl,
14
16
  processEnvs: process.env,
15
- file: get_file_context_1.getFileContext(),
16
- console: log_1.consoleContext(),
17
+ file: (0, get_file_context_1.getFileContext)(process.cwd()),
18
+ console: (0, log_1.consoleContext)(),
19
+ status: (0, work_node_status_1.statusConsole)(),
20
+ docker: (0, execute_docker_1.getContainerCli)(),
17
21
  }, process.argv).then(({ program, args }) => {
18
- program.parse(args);
22
+ return program.parseAsync(args);
19
23
  });
20
24
  //# sourceMappingURL=index.js.map