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
package/dist/log.js CHANGED
@@ -3,10 +3,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.showCursor = exports.hideCursor = exports.writeWorkTreeStatus = exports.formatDate = exports.getNodeName = exports.getNodeNameLength = exports.printWorkTreeResult = exports.isVerbose = exports.consoleContext = exports.getLogLevel = exports.getLogs = void 0;
6
+ exports.showCursor = exports.hideCursor = exports.writeWorkTreeStatus = exports.formatDate = exports.writeNodeLogToConsole = exports.getNodeName = exports.getNodeNameLengthForWorkTree = exports.getNodeNameLength = exports.printTitle = exports.printItem = exports.printProperty = exports.getNodeNameLengthForSchedulerState = exports.printWorkTreeResult = exports.getType = exports.isVerbose = exports.consoleContext = exports.getErrorMessage = exports.getLogLevel = exports.getLogs = void 0;
7
7
  const readline_1 = require("readline");
8
8
  const plan_work_nodes_1 = require("./planner/utils/plan-work-nodes");
9
9
  const colors_1 = __importDefault(require("colors"));
10
+ const fail_never_1 = require("./utils/fail-never");
10
11
  function getLogs(chunk) {
11
12
  return chunk
12
13
  .toString()
@@ -27,44 +28,88 @@ function getLogLevel(level) {
27
28
  }
28
29
  }
29
30
  exports.getLogLevel = getLogLevel;
31
+ function getErrorMessage(e) {
32
+ if (e instanceof Error) {
33
+ return e.message;
34
+ }
35
+ else if (typeof e === 'string') {
36
+ return e;
37
+ }
38
+ else {
39
+ return `unknown error ${e}`;
40
+ }
41
+ }
42
+ exports.getErrorMessage = getErrorMessage;
30
43
  function consoleContext() {
31
44
  return {
32
45
  debug(message) {
33
- process.stdout.write(`${getLogLevel('debug')}: ${message}\n`);
46
+ process.stdout.write(`${formatDate(new Date())} ${getType('cli')} ${getLogLevel('debug')}: ${message}\n`);
34
47
  },
35
48
  error(message) {
36
- process.stdout.write(`${getLogLevel('error')}: ${message}\n`);
49
+ process.stdout.write(`${formatDate(new Date())} ${getType('cli')} ${getLogLevel('error')}: ${message}\n`);
37
50
  },
38
51
  info(message) {
39
- process.stdout.write(`${getLogLevel('info')}: ${message}\n`);
52
+ process.stdout.write(`${formatDate(new Date())} ${getType('cli')} ${getLogLevel('info')}: ${message}\n`);
40
53
  },
41
54
  warn(message) {
42
- process.stdout.write(`${getLogLevel('warn')}: ${message}\n`);
55
+ process.stdout.write(`${formatDate(new Date())} ${getType('cli')} ${getLogLevel('warn')}: ${message}\n`);
43
56
  },
44
57
  };
45
58
  }
46
59
  exports.consoleContext = consoleContext;
47
60
  exports.isVerbose = process.argv.some((a) => a === '--verbose');
48
- async function printWorkTreeResult(workTree, result, logConsoleOnFail) {
49
- const maxNodeNameLength = getNodeNameLength(workTree);
50
- if (logConsoleOnFail && (!result.success || exports.isVerbose)) {
51
- for (const node of plan_work_nodes_1.iterateWorkNodes(workTree.nodes)) {
52
- if (node.status.state.type === 'failed' || exports.isVerbose) {
53
- const logs = await node.status.console.read();
54
- for (const log of logs) {
55
- if (log.level === 'debug' && !exports.isVerbose) {
56
- continue;
57
- }
58
- process.stdout.write(`${colors_1.default.grey('task:')} ${getNodeName(node, maxNodeNameLength)} ${formatDate(log.date)} ${getLogLevel(log.level)}: ${log.message}\n`);
59
- }
60
- process.stdout.write('-----------------\n');
61
+ const typeLength = ['service', 'task', 'cli']
62
+ .map((s) => s.length)
63
+ .reduce((max, current) => (max > current ? max : current), 0);
64
+ function getType(type) {
65
+ return colors_1.default.grey(getNodeName(type, typeLength) + ':');
66
+ }
67
+ exports.getType = getType;
68
+ async function printWorkTreeResult(schedulerState, env) {
69
+ const maxNodeNameLength = getNodeNameLengthForSchedulerState(schedulerState);
70
+ for (const log of env.status.read()) {
71
+ if (exports.isVerbose || (log.type === 'status' && log.level === 'error')) {
72
+ process.stdout.write(`${formatDate(log.date)} ${getType(log.context.type)} ${getNodeName(log.context.name, maxNodeNameLength)} - ${colors_1.default.white(log.message)}\n`);
73
+ }
74
+ }
75
+ for (const state of (0, plan_work_nodes_1.iterateWorkServices)(schedulerState.service)) {
76
+ if (state.type === 'end' && state.reason === 'crash') {
77
+ const message = `${getType('service')} ${getNodeName(state.service.name, maxNodeNameLength)}`;
78
+ for (const log of env.status.service(state.service).logs()) {
79
+ process.stdout.write(`${formatDate(log.date)} ${message} - ${log.console}: ${log.message}\n`);
80
+ }
81
+ }
82
+ }
83
+ for (const state of (0, plan_work_nodes_1.iterateWorkNodes)(schedulerState.node)) {
84
+ if (state.type === 'error' || state.type === 'crash') {
85
+ const message = `${getType('task')} ${getNodeName(state.node.name, maxNodeNameLength)}`;
86
+ for (const log of env.status.task(state.node).logs()) {
87
+ process.stdout.write(`${formatDate(log.date)} ${message} - ${log.console}: ${log.message}\n`);
88
+ }
89
+ }
90
+ }
91
+ for (const state of (0, plan_work_nodes_1.iterateWorkServices)(schedulerState.service)) {
92
+ let message = `${formatDate(new Date())} ${getType('service')} ${getNodeName(state.service.name, maxNodeNameLength)} - ${getStateText(state)}`;
93
+ if (state.type === 'end') {
94
+ if (state.reason === 'crash') {
95
+ message += ` crashed`;
61
96
  }
97
+ process.stdout.write(`${message}\n`);
62
98
  }
63
99
  }
64
- for (const node of plan_work_nodes_1.iterateWorkNodes(workTree.nodes)) {
65
- let message = `${colors_1.default.grey('task:')} ${getNodeName(node, maxNodeNameLength)} - ${getStateText(node.status.state)}`;
66
- if (node.status.state.type === 'completed') {
67
- message += ` in ${node.status.state.duration}ms`;
100
+ for (const state of (0, plan_work_nodes_1.iterateWorkNodes)(schedulerState.node)) {
101
+ let message = `${formatDate(new Date())} ${getType('task')} ${getNodeName(state.node.name, maxNodeNameLength)} - ${getStateText(state)}`;
102
+ if (state.type === 'completed') {
103
+ message += ` in ${state.duration}ms`;
104
+ if (state.cached) {
105
+ message += ' [CACHED]';
106
+ }
107
+ }
108
+ if (state.type === 'crash') {
109
+ message += ` exited with ${state.exitCode}`;
110
+ }
111
+ if (state.type === 'error') {
112
+ message += ` with message ${state.errorMessage}`;
68
113
  }
69
114
  process.stdout.write(`${message}\n`);
70
115
  }
@@ -75,40 +120,95 @@ function getStateText(state) {
75
120
  if (state.type === 'running') {
76
121
  return colors_1.default.blue(state.type);
77
122
  }
78
- else if (state.type === 'pending') {
123
+ else if (state.type === 'pending' || state.type === 'starting') {
79
124
  return colors_1.default.yellow(state.type);
80
125
  }
81
126
  else if (state.type === 'completed') {
82
127
  return colors_1.default.green(state.type);
83
128
  }
84
- else if (state.type === 'failed') {
129
+ else if (state.type === 'crash') {
85
130
  return colors_1.default.red(state.type);
86
131
  }
87
- else if (state.type === 'aborted') {
132
+ else if (state.type === 'error') {
88
133
  return colors_1.default.red(state.type);
89
134
  }
90
- else if (state.type === 'cancel') {
135
+ else if (state.type === 'end') {
136
+ return colors_1.default.bgRed(state.type);
137
+ }
138
+ else if (state.type === 'canceled') {
91
139
  return colors_1.default.bgRed(state.type);
92
140
  }
141
+ else if (state.type === 'ready') {
142
+ return colors_1.default.blue(state.type);
143
+ }
93
144
  else {
94
- //TODO fail never
95
- return '';
145
+ (0, fail_never_1.failNever)(state, 'unknown node state');
146
+ }
147
+ }
148
+ function getNodeNameLengthForSchedulerState(schedulerState) {
149
+ function* Names() {
150
+ for (const node of (0, plan_work_nodes_1.iterateWorkNodes)(schedulerState.node)) {
151
+ yield node.node.name;
152
+ }
153
+ for (const service of (0, plan_work_nodes_1.iterateWorkServices)(schedulerState.service)) {
154
+ yield service.service.name;
155
+ }
96
156
  }
157
+ return getNodeNameLength(Names);
158
+ }
159
+ exports.getNodeNameLengthForSchedulerState = getNodeNameLengthForSchedulerState;
160
+ function printProperty(name, value) {
161
+ process.stdout.write(` ${colors_1.default.grey(`${name}:`)} ${value}\n`);
162
+ }
163
+ exports.printProperty = printProperty;
164
+ function printItem(item) {
165
+ process.stdout.write(`• ${item.name}${item.description ? `: ${colors_1.default.white(item.description)}` : ''}\n`);
97
166
  }
98
- function getNodeNameLength(workTree) {
167
+ exports.printItem = printItem;
168
+ function printTitle(name) {
169
+ process.stdout.write(`${colors_1.default.bgWhite(name + ':\n')}`);
170
+ }
171
+ exports.printTitle = printTitle;
172
+ function getNodeNameLength(names) {
99
173
  let maxNodeNameLength = 0;
100
- for (const node of plan_work_nodes_1.iterateWorkNodes(workTree.nodes)) {
101
- if (node.name.length > maxNodeNameLength) {
102
- maxNodeNameLength = node.name.length;
174
+ for (const name of names()) {
175
+ if (name.length > maxNodeNameLength) {
176
+ maxNodeNameLength = name.length;
103
177
  }
104
178
  }
105
179
  return maxNodeNameLength;
106
180
  }
107
181
  exports.getNodeNameLength = getNodeNameLength;
108
- function getNodeName(node, maxNodeNameLength) {
109
- return colors_1.default.white(node.name) + ' '.repeat(maxNodeNameLength - node.name.length);
182
+ function getNodeNameLengthForWorkTree(nodes, services) {
183
+ function* Names() {
184
+ for (const node of (0, plan_work_nodes_1.iterateWorkNodes)(nodes)) {
185
+ yield node.node.name;
186
+ }
187
+ for (const service of (0, plan_work_nodes_1.iterateWorkServices)(services)) {
188
+ yield service.service.name;
189
+ }
190
+ }
191
+ return getNodeNameLength(Names);
192
+ }
193
+ exports.getNodeNameLengthForWorkTree = getNodeNameLengthForWorkTree;
194
+ function getNodeName(name, maxNodeNameLength) {
195
+ return colors_1.default.white(name) + ' '.repeat(Math.max(0, maxNodeNameLength - name.length));
110
196
  }
111
197
  exports.getNodeName = getNodeName;
198
+ function writeNodeLogToConsole(log, maxNodeNameLength) {
199
+ if (log.type === 'status') {
200
+ if (log.level === 'debug' && !exports.isVerbose) {
201
+ return;
202
+ }
203
+ }
204
+ const content = log.type === 'console'
205
+ ? log.console === 'stdout'
206
+ ? colors_1.default.white(log.message)
207
+ : colors_1.default.red(log.message)
208
+ : `${getLogLevel(log.level)} - ${log.message}`;
209
+ process.stdout.write(`${formatDate(log.date)} ${colors_1.default.grey(log.context.type + ':')} ${getNodeName(log.context.name, maxNodeNameLength)} - ${log.date.toLocaleTimeString()} - ${content}\n`);
210
+ }
211
+ exports.writeNodeLogToConsole = writeNodeLogToConsole;
112
212
  function formatDate(date) {
113
213
  return colors_1.default.grey(`[${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, '0')}-${date
114
214
  .getDay()
@@ -122,34 +222,81 @@ function formatDate(date) {
122
222
  .padStart(3, '0')}]`);
123
223
  }
124
224
  exports.formatDate = formatDate;
125
- function writeWorkTreeStatus(workTree, ticker) {
126
- readline_1.clearScreenDown(process.stdout);
127
- const maxNodeNameLength = getNodeNameLength(workTree);
225
+ function writeWorkTreeStatus(schedulerState, env, ticker) {
226
+ (0, readline_1.clearScreenDown)(process.stdout);
227
+ const maxNodeNameLength = getNodeNameLengthForSchedulerState(schedulerState);
128
228
  let count = 0;
129
- for (const node of plan_work_nodes_1.iterateWorkNodes(workTree.nodes)) {
130
- let message = `${colors_1.default.grey('task:')} ${getNodeName(node, maxNodeNameLength)} - ${getStateText(node.status.state)}`;
131
- if (node.status.state.type === 'pending') {
132
- const totalDepCount = node.deps.length;
133
- const completedDepCount = totalDepCount - Object.keys(node.status.state.pendingDependencies).length;
229
+ for (const state of (0, plan_work_nodes_1.iterateWorkServices)(schedulerState.service)) {
230
+ let message = `${getType('service')} ${getNodeName(state.service.name, maxNodeNameLength)} - ${getStateText(state)}`;
231
+ const currentMessage = env.status.service(state.service).current();
232
+ if (currentMessage) {
233
+ message += ` ${currentMessage.message}`;
234
+ }
235
+ count += printWithTruncate(message);
236
+ }
237
+ for (const state of (0, plan_work_nodes_1.iterateWorkNodes)(schedulerState.node)) {
238
+ let message = `${getType('task')} ${getNodeName(state.node.name, maxNodeNameLength)} - ${getStateText(state)}`;
239
+ if (state.type === 'pending') {
240
+ const totalDepCount = state.node.deps.length;
241
+ const totalServiceCount = state.node.needs.length;
242
+ const completedDepCount = state.node.deps.filter((d) => schedulerState.node[d.id]?.type === 'completed').length;
243
+ const runningServiceCount = state.node.needs.filter((n) => schedulerState.service[n.id]?.type === 'ready').length;
134
244
  if (totalDepCount > 0 && completedDepCount !== totalDepCount) {
135
245
  message += ` | ${colors_1.default.grey(` awaiting dependencies (${completedDepCount}/${totalDepCount})`)}`;
136
246
  }
247
+ if (totalServiceCount > 0 && runningServiceCount !== totalServiceCount) {
248
+ message += ` | ${colors_1.default.grey(` awaiting service (${runningServiceCount}/${totalServiceCount})`)}`;
249
+ }
137
250
  }
138
- if (node.status.state.type === 'running') {
251
+ if (state.type === 'starting' || state.type === 'ready') {
139
252
  message += ` | ${spinner[ticker % spinner.length]}`;
140
- if (node.status.console.current) {
141
- message += ` ${node.status.console.current.message}`;
253
+ const currentMessage = env.status.task(state.node).current();
254
+ if (currentMessage) {
255
+ message += ` ${currentMessage.message}`;
142
256
  }
143
257
  }
144
- else if (node.status.state.type === 'completed') {
145
- message += ` in ${node.status.state.duration}ms`;
258
+ else if (state.type === 'running') {
259
+ message += ` | ${spinner[ticker % spinner.length]}`;
260
+ const currentMessage = env.status.task(state.node).currentLog();
261
+ if (currentMessage) {
262
+ message += ` ${currentMessage.message}`;
263
+ }
146
264
  }
147
- process.stdout.write(`${message}\n`);
148
- count++;
265
+ else if (state.type === 'completed') {
266
+ message += ` in ${state.duration}ms`;
267
+ if (state.cached) {
268
+ message += ' [CACHED]';
269
+ }
270
+ }
271
+ else if (state.type === 'error') {
272
+ message += ` ${state.errorMessage}`;
273
+ }
274
+ count += printWithTruncate(message);
149
275
  }
150
- readline_1.moveCursor(process.stdout, 0, -1 * count);
276
+ (0, readline_1.moveCursor)(process.stdout, 0, -1 * count);
151
277
  }
152
278
  exports.writeWorkTreeStatus = writeWorkTreeStatus;
279
+ function countChar(message, char) {
280
+ let result = 0;
281
+ for (let i = 0; i < message.length; i++) {
282
+ if (message[i] === char) {
283
+ result++;
284
+ }
285
+ }
286
+ return result;
287
+ }
288
+ function printWithTruncate(message) {
289
+ let lineCount = 0;
290
+ let index = 0;
291
+ do {
292
+ const newLineCount = countChar(message, '\n');
293
+ process.stdout.write(`${message.substr(index, process.stdout.columns)}\n`);
294
+ index += process.stdout.columns;
295
+ lineCount++;
296
+ lineCount += newLineCount;
297
+ } while (index < message.length);
298
+ return lineCount;
299
+ }
153
300
  function hideCursor() {
154
301
  process.stdout.write('\x1B[?25l');
155
302
  }
@@ -2,26 +2,38 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.groupedLogger = void 0;
4
4
  const log_1 = require("../log");
5
- const message_to_console_1 = require("./message-to-console");
6
- function groupedLogger() {
7
- let maxNodeNameLength = 0;
8
- return {
9
- start(executionContext, workTree) {
10
- maxNodeNameLength = log_1.getNodeNameLength(workTree);
11
- executionContext.events.on(async (evt) => {
12
- if (evt.newState.type === 'completed' || evt.newState.type === 'failed' || evt.newState.type === 'aborted') {
13
- const node = workTree.nodes[evt.nodeId];
14
- for (const log of await node.status.console.read()) {
15
- message_to_console_1.logMessageToConsole(node, log, maxNodeNameLength);
16
- }
5
+ const plan_work_nodes_1 = require("../planner/utils/plan-work-nodes");
6
+ function groupedLogger(state, env) {
7
+ const maxNodeNameLength = (0, log_1.getNodeNameLengthForWorkTree)(state.current.node, state.current.service);
8
+ const completedNodes = [];
9
+ const completedServices = [];
10
+ state.on((currentState) => {
11
+ for (const node of (0, plan_work_nodes_1.iterateWorkNodes)(currentState.node)) {
12
+ if (completedNodes.indexOf(node.node.id) >= 0) {
13
+ continue;
14
+ }
15
+ if (node.type === 'crash' || node.type === 'error' || node.type === 'completed') {
16
+ completedNodes.push(node.node.id);
17
+ for (const log of env.status.task(node.node).read()) {
18
+ (0, log_1.writeNodeLogToConsole)(log, maxNodeNameLength);
17
19
  }
18
- });
19
- },
20
- async finish(workTree, result) {
21
- await log_1.printWorkTreeResult(workTree, result, false);
22
- },
23
- abort(e) {
24
- process.stderr.write(`${e.message}\n`);
20
+ }
21
+ }
22
+ for (const service of (0, plan_work_nodes_1.iterateWorkServices)(currentState.service)) {
23
+ if (completedServices.indexOf(service.service.id) >= 0) {
24
+ continue;
25
+ }
26
+ if (service.type === 'end') {
27
+ completedServices.push(service.service.id);
28
+ for (const log of env.status.service(service.service).read()) {
29
+ (0, log_1.writeNodeLogToConsole)(log, maxNodeNameLength);
30
+ }
31
+ }
32
+ }
33
+ });
34
+ return {
35
+ async complete(evt, env) {
36
+ await (0, log_1.printWorkTreeResult)(evt.state, env);
25
37
  },
26
38
  };
27
39
  }
@@ -3,33 +3,30 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.interactiveLogger = void 0;
4
4
  const log_1 = require("../log");
5
5
  const readline_1 = require("readline");
6
- function interactiveLogger() {
6
+ function interactiveLogger(state, env) {
7
7
  let running = true;
8
8
  let count = 0;
9
+ const tickerFn = () => {
10
+ if (!running) {
11
+ return;
12
+ }
13
+ count++;
14
+ (0, log_1.writeWorkTreeStatus)(state.current, env, count);
15
+ if (running) {
16
+ setTimeout(tickerFn, 100);
17
+ }
18
+ };
19
+ (0, log_1.hideCursor)();
20
+ tickerFn();
21
+ state.on((currentState) => {
22
+ (0, log_1.writeWorkTreeStatus)(currentState, env, count);
23
+ });
9
24
  return {
10
- start(executionContext, workTree) {
11
- log_1.hideCursor();
12
- log_1.writeWorkTreeStatus(workTree, count);
13
- const tickerFn = () => {
14
- count++;
15
- log_1.writeWorkTreeStatus(workTree, count);
16
- if (running) {
17
- setTimeout(tickerFn, 100);
18
- }
19
- };
20
- tickerFn();
21
- executionContext.events.on(({ workTree }) => {
22
- log_1.writeWorkTreeStatus(workTree, count);
23
- });
24
- },
25
- async finish(workTree, result) {
25
+ async complete(evt, env) {
26
26
  running = false;
27
- readline_1.clearScreenDown(process.stdout);
28
- await log_1.printWorkTreeResult(workTree, result, true);
29
- log_1.showCursor();
30
- },
31
- abort(e) {
32
- process.stderr.write(`${e.message}\n`);
27
+ (0, readline_1.clearScreenDown)(process.stdout);
28
+ await (0, log_1.printWorkTreeResult)(evt.state, env);
29
+ (0, log_1.showCursor)();
33
30
  },
34
31
  };
35
32
  }
@@ -2,24 +2,14 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.liveLogger = void 0;
4
4
  const log_1 = require("../log");
5
- const plan_work_nodes_1 = require("../planner/utils/plan-work-nodes");
6
- const message_to_console_1 = require("./message-to-console");
7
- function liveLogger() {
8
- let maxNodeNameLength = 0;
5
+ function liveLogger(state, env) {
6
+ const maxNodeNameLength = (0, log_1.getNodeNameLengthForWorkTree)(state.current.node, state.current.service);
7
+ env.status.on((log) => {
8
+ (0, log_1.writeNodeLogToConsole)(log, maxNodeNameLength);
9
+ });
9
10
  return {
10
- start(executionContext, workTree) {
11
- maxNodeNameLength = log_1.getNodeNameLength(workTree);
12
- for (const node of plan_work_nodes_1.iterateWorkNodes(workTree.nodes)) {
13
- node.status.console.on((log) => {
14
- message_to_console_1.logMessageToConsole(node, log, maxNodeNameLength);
15
- });
16
- }
17
- },
18
- async finish(workTree, result) {
19
- await log_1.printWorkTreeResult(workTree, result, false);
20
- },
21
- abort(e) {
22
- process.stderr.write(`${e.message}\n`);
11
+ async complete(evt, env) {
12
+ await (0, log_1.printWorkTreeResult)(evt.state, env);
23
13
  },
24
14
  };
25
15
  }
@@ -4,7 +4,7 @@ exports.calculateChecksum = void 0;
4
4
  const crypto_1 = require("crypto");
5
5
  async function calculateChecksum(environment, path) {
6
6
  const input = await environment.file.read(path);
7
- return crypto_1.createHash('sha1').update(input).digest('hex');
7
+ return (0, crypto_1.createHash)('sha1').update(input).digest('hex');
8
8
  }
9
9
  exports.calculateChecksum = calculateChecksum;
10
10
  //# sourceMappingURL=calculate-checksum.js.map
@@ -1,33 +1,28 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getHammerkitDirectory = exports.getCacheStatsFile = exports.getCacheStatsDirectory = exports.getCacheDescriptionFile = exports.getCacheDirectory = void 0;
3
+ exports.getHammerkitDirectory = exports.getCacheStatsFile = exports.getCacheDescriptionFile = exports.getCacheDirectory = void 0;
4
4
  const path_1 = require("path");
5
- const crypto_1 = require("crypto");
6
5
  function getCacheDirectory(nodeId) {
7
- return path_1.join(getHammerkitDirectory(), 'cache', nodeId);
6
+ return (0, path_1.join)(getHammerkitDirectory(), 'cache', nodeId);
8
7
  }
9
8
  exports.getCacheDirectory = getCacheDirectory;
10
9
  function getCacheDescriptionFile(nodeId) {
11
- return path_1.join(getCacheDirectory(nodeId), 'description.json');
10
+ return (0, path_1.join)(getCacheDirectory(nodeId), 'description.json');
12
11
  }
13
12
  exports.getCacheDescriptionFile = getCacheDescriptionFile;
14
- function getCacheStatsDirectory(nodeId, cwd) {
15
- return path_1.join(getCacheDirectory(nodeId), crypto_1.createHash('sha1').update(cwd).digest('hex'));
16
- }
17
- exports.getCacheStatsDirectory = getCacheStatsDirectory;
18
- function getCacheStatsFile(nodeId, cwd) {
19
- return path_1.join(getCacheStatsDirectory(nodeId, cwd), 'stats.json');
13
+ function getCacheStatsFile(nodeId) {
14
+ return (0, path_1.join)(getCacheDirectory(nodeId), 'stats.json');
20
15
  }
21
16
  exports.getCacheStatsFile = getCacheStatsFile;
22
17
  function getHammerkitDirectory() {
23
18
  if (process.platform === 'win32') {
24
- return path_1.join(process.env.APPDATA, 'hammerkit');
19
+ return (0, path_1.join)(process.env.APPDATA, 'hammerkit');
25
20
  }
26
21
  else if (process.platform === 'darwin') {
27
- return path_1.join(process.env.HOME, 'Library', 'Application Support', 'hammerkit');
22
+ return (0, path_1.join)(process.env.HOME, 'Library', 'Application Support', 'hammerkit');
28
23
  }
29
24
  else {
30
- return path_1.join(process.env.HOME, '.hammerkit');
25
+ return (0, path_1.join)(process.env.HOME, '.hammerkit');
31
26
  }
32
27
  }
33
28
  exports.getHammerkitDirectory = getHammerkitDirectory;
@@ -1,51 +1,98 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.hasStatsChanged = exports.getWorkNodeCacheStats = void 0;
3
+ exports.getStateKey = exports.getCacheState = exports.getWorkNodeCacheStats = exports.getServiceNodeCacheStats = void 0;
4
4
  const calculate_checksum_1 = require("./calculate-checksum");
5
5
  const path_1 = require("path");
6
- async function addWorkNodeCacheStats(result, path, matcher, context) {
6
+ const crypto_1 = require("crypto");
7
+ async function addWorkNodeCacheStats(result, cwd, path, matcher, context) {
8
+ const exists = await context.file.exists(path);
9
+ if (!exists) {
10
+ return;
11
+ }
7
12
  const stats = await context.file.stats(path);
8
13
  if (stats.type === 'file') {
9
14
  if (matcher(path)) {
10
- const checksum = await calculate_checksum_1.calculateChecksum(context, path);
11
- result.files[path_1.relative(result.cwd, path)] = { lastModified: stats.lastModified, checksum };
15
+ const checksum = await (0, calculate_checksum_1.calculateChecksum)(context, path);
16
+ result.files[(0, path_1.relative)(cwd, path)] = { lastModified: stats.lastModified, checksum };
12
17
  }
13
18
  }
14
19
  else if (stats.type === 'directory') {
15
20
  const files = await context.file.listFiles(path);
16
21
  for (const file of files) {
17
- const subPath = path_1.join(path, file);
22
+ const subPath = (0, path_1.join)(path, file);
18
23
  if (matcher(subPath)) {
19
- await addWorkNodeCacheStats(result, path_1.join(path, file), matcher, context);
24
+ await addWorkNodeCacheStats(result, cwd, (0, path_1.join)(path, file), matcher, context);
20
25
  }
21
26
  }
22
27
  }
23
28
  }
29
+ async function addWorkServiceCacheStats(result, path, context) {
30
+ const exists = await context.file.exists(path);
31
+ if (!exists) {
32
+ return;
33
+ }
34
+ const stats = await context.file.stats(path);
35
+ if (stats.type === 'file') {
36
+ const checksum = await (0, calculate_checksum_1.calculateChecksum)(context, path);
37
+ result.files[path] = { lastModified: stats.lastModified, checksum };
38
+ }
39
+ else if (stats.type === 'directory') {
40
+ const files = await context.file.listFiles(path);
41
+ for (const file of files) {
42
+ await addWorkServiceCacheStats(result, (0, path_1.join)(path, file), context);
43
+ }
44
+ }
45
+ }
46
+ async function getServiceNodeCacheStats(cache, environment) {
47
+ const result = {
48
+ files: {},
49
+ };
50
+ for (const mount of cache.mounts) {
51
+ await addWorkServiceCacheStats(result, mount.localPath, environment);
52
+ }
53
+ return result;
54
+ }
55
+ exports.getServiceNodeCacheStats = getServiceNodeCacheStats;
24
56
  async function getWorkNodeCacheStats(cache, environment) {
25
57
  const result = {
26
- cwd: cache.cwd,
58
+ created: new Date(),
27
59
  files: {},
28
60
  };
29
61
  for (const src of cache.src) {
30
- await addWorkNodeCacheStats(result, src.absolutePath, (file) => src.matcher(file, cache.cwd), environment);
62
+ await addWorkNodeCacheStats(result, cache.cwd, src.absolutePath, (file) => src.matcher(file, cache.cwd), environment);
31
63
  }
32
64
  return result;
33
65
  }
34
66
  exports.getWorkNodeCacheStats = getWorkNodeCacheStats;
35
- async function hasStatsChanged(node, cache, current, cacheMethod) {
36
- let changed = false;
37
- for (const key of Object.keys(cache.files)) {
38
- if ((cacheMethod === 'checksum' && current.files[key]?.checksum !== cache.files[key].checksum) ||
39
- (cacheMethod === 'modify-date' && current.files[key]?.lastModified !== cache.files[key].lastModified)) {
40
- node.status.console.write('internal', 'debug', cacheMethod === 'checksum'
41
- ? `${key} changed from checksum ${cache.files[key].checksum} to ${current.files[key]?.checksum}`
42
- : `${key} changed from last modified ${cache.files[key].lastModified} to ${current.files[key]?.lastModified}`);
43
- node.status.console.write('internal', 'debug', `${node.name} can't be skipped because ${key} has been modified`);
44
- changed = true;
45
- break;
67
+ function getCacheState(status, node, cache, current) {
68
+ if (cache) {
69
+ for (const key of Object.keys(cache.files)) {
70
+ if ((node.caching === 'checksum' && current.files[key]?.checksum !== cache.files[key].checksum) ||
71
+ (node.caching === 'modify-date' && current.files[key]?.lastModified !== cache.files[key].lastModified)) {
72
+ status.write('debug', node.caching === 'checksum'
73
+ ? `${key} changed from checksum ${cache.files[key].checksum} to ${current.files[key]?.checksum}`
74
+ : `${key} changed from last modified ${cache.files[key].lastModified} to ${current.files[key]?.lastModified}`);
75
+ status.write('debug', `${node.name} can't be skipped because ${key} has been modified`);
76
+ break;
77
+ }
78
+ }
79
+ }
80
+ return {
81
+ stateKey: getStateKey(current, node.caching),
82
+ };
83
+ }
84
+ exports.getCacheState = getCacheState;
85
+ function getStateKey(stats, cacheMethod) {
86
+ const contents = [];
87
+ for (const key of Object.keys(stats.files)) {
88
+ if (cacheMethod === 'checksum') {
89
+ contents.push(`${key}:${stats.files[key].checksum}`);
90
+ }
91
+ else if (cacheMethod === 'modify-date') {
92
+ contents.push(`${key}:${stats.files[key].lastModified}`);
46
93
  }
47
94
  }
48
- return changed;
95
+ return (0, crypto_1.createHash)('md5').update(contents.join(',')).digest('hex');
49
96
  }
50
- exports.hasStatsChanged = hasStatsChanged;
97
+ exports.getStateKey = getStateKey;
51
98
  //# sourceMappingURL=get-work-node-cache-stats.js.map