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.
- package/.devcontainer/Dockerfile +5 -0
- package/.devcontainer/devcontainer.json +40 -0
- package/README.md +13 -86
- package/SUMMARY.md +43 -0
- package/build.schema.json +56 -2
- package/dist/cli.js +97 -0
- package/dist/cli.spec.js +5 -0
- package/dist/console/console-context-mock.js +11 -0
- package/dist/console/get-logger.js +23 -0
- package/dist/docker/pull.js +5 -5
- package/dist/docker/remove-container.js +21 -0
- package/dist/docker/stream.js +14 -10
- package/dist/docker/using-container.js +28 -0
- package/dist/environment/get-process-env.js +4 -4
- package/dist/environment/replace-env-variables.js +2 -3
- package/dist/executer/abort.js +13 -0
- package/dist/executer/check-readiness.js +25 -0
- package/dist/executer/create-scheduler-state.js +32 -0
- package/dist/executer/docker-node.js +123 -0
- package/dist/executer/docker-service.js +113 -0
- package/dist/executer/environment-mock.js +17 -0
- package/dist/executer/event-cache.js +165 -0
- package/dist/executer/execute-command.js +42 -0
- package/dist/executer/execute-docker.js +59 -195
- package/dist/executer/execute.spec.js +37 -37
- package/dist/executer/execution-steps.js +57 -0
- package/dist/executer/get-docker-executor.js +6 -100
- package/dist/executer/hierarchy-scheduler.js +94 -0
- package/dist/executer/kubernetes-service.js +64 -0
- package/dist/executer/label-values.js +65 -0
- package/dist/executer/local-node.js +57 -0
- package/dist/executer/print-container-options.js +17 -0
- package/dist/{logging/log-strategy.js → executer/process-item.js} +1 -1
- package/dist/executer/process-listener.js +3 -0
- package/dist/executer/process-manager.js +111 -0
- package/dist/executer/process-manager.spec.js +91 -0
- package/dist/executer/{executor.js → process.js} +1 -1
- package/dist/executer/{execute-result.js → readonly-state.js} +1 -1
- package/dist/executer/schedule.js +139 -0
- package/dist/executer/scheduler/check-for-loop.js +21 -0
- package/dist/executer/scheduler/enqueue-next.js +27 -0
- package/dist/{testing/test-context.js → executer/scheduler/node-state.js} +1 -1
- package/dist/executer/scheduler/scheduler-result.js +3 -0
- package/dist/executer/scheduler/scheduler-state.js +3 -0
- package/dist/executer/scheduler/service-state.js +3 -0
- package/dist/executer/service-dns.js +6 -0
- package/dist/executer/set-user-permission.js +16 -0
- package/dist/executer/start-node.js +59 -0
- package/dist/executer/state-listener.js +3 -0
- package/dist/executer/state.js +49 -0
- package/dist/executer/states.js +4 -159
- package/dist/executer/watch-node.js +57 -0
- package/dist/executer/watch-service.js +54 -0
- package/dist/executer/work-scope.js +10 -0
- package/dist/file/get-file-context-mock.spec.js +5 -5
- package/dist/file/get-file-context.js +41 -18
- package/dist/file/move-files.js +1 -1
- package/dist/get-work-context.js +29 -0
- package/dist/index.js +8 -4
- package/dist/log.js +197 -50
- package/dist/logging/grouped-logger.js +31 -19
- package/dist/logging/interactive-logger.js +20 -23
- package/dist/logging/live-logger.js +7 -17
- package/dist/optimizer/calculate-checksum.js +1 -1
- package/dist/optimizer/get-cache-directory.js +8 -13
- package/dist/optimizer/get-work-node-cache-stats.js +68 -21
- package/dist/optimizer/read-work-node-cache.js +2 -2
- package/dist/optimizer/work-node-cache-description.js +12 -11
- package/dist/optimizer/write-work-node-cache.js +9 -8
- package/dist/{executer/execution-context.js → parser/build-file-service.js} +1 -1
- package/dist/{optimizer → parser}/cache-method.js +0 -0
- package/dist/parser/get-build-file.js +1 -1
- package/dist/parser/parse-boolean.js +29 -0
- package/dist/parser/parse-boolean.spec.js +48 -0
- package/dist/parser/parse-build-file-references.js +2 -2
- package/dist/parser/parse-build-file-services.js +58 -0
- package/dist/parser/parse-build-file-task-command.js +6 -5
- package/dist/parser/parse-build-file-task-source.js +5 -5
- package/dist/parser/parse-build-file.js +39 -15
- package/dist/parser/parse-context.js +13 -0
- package/dist/parser/parse-envs.js +4 -3
- package/dist/parser/parse-healthcheck.js +28 -0
- package/dist/parser/parse-label-arguments.js +23 -0
- package/dist/parser/parse-service-selector.js +39 -0
- package/dist/parser/parse-string-array.js +6 -5
- package/dist/parser/parse-string-map.js +30 -0
- package/dist/parser/parse-string.js +20 -0
- package/dist/parser/read-build-file.js +16 -5
- package/dist/parser/read-env-file.js +3 -3
- package/dist/planner/utils/get-container-mounts.js +24 -0
- package/dist/planner/utils/normalize-path.js +17 -0
- package/dist/planner/utils/parse-work-node-mount.js +3 -14
- package/dist/planner/utils/parse-work-node-mount.spec.js +10 -10
- package/dist/planner/utils/parse-work-service-volume.js +21 -0
- package/dist/planner/utils/plan-work-command.js +1 -1
- package/dist/planner/utils/plan-work-dependency.js +14 -8
- package/dist/planner/utils/plan-work-node.js +203 -128
- package/dist/planner/utils/plan-work-nodes.js +59 -14
- package/dist/planner/utils/plan-work-tree.js +8 -4
- package/dist/planner/utils/plan-work-volume.js +29 -0
- package/dist/planner/validate.js +56 -8
- package/dist/planner/work-context.js +20 -0
- package/dist/planner/work-mount.js +3 -0
- package/dist/planner/work-node-id.js +4 -4
- package/dist/planner/work-node-id.spec.js +11 -8
- package/dist/planner/work-node-path.js +0 -1
- package/dist/planner/work-node-status.js +121 -18
- package/dist/planner/work-node.js +3 -3
- package/dist/planner/work-service-id.js +13 -0
- package/dist/planner/work-service-volume.js +3 -0
- package/dist/planner/work-service.js +6 -0
- package/dist/planner/work-services.js +3 -0
- package/dist/planner/work-volume.js +3 -0
- package/dist/program.js +155 -90
- package/dist/program.spec.js +20 -0
- package/dist/start-watch-processes.js +28 -0
- package/dist/testing/cli.js +73 -0
- package/dist/testing/create-build-file.js +1 -1
- package/dist/testing/example-test-suite.js +54 -0
- package/dist/testing/expect.js +35 -18
- package/dist/testing/get-logger.js +23 -0
- package/dist/testing/get-node.js +2 -2
- package/dist/testing/get-test-context.js +5 -3
- package/dist/testing/get-test-suite.js +2 -50
- package/dist/testing/integration/cache.spec.js +25 -28
- package/dist/testing/integration/cancellation.spec.js +19 -21
- package/dist/testing/integration/clean.spec.js +25 -28
- package/dist/testing/integration/cmd.spec.js +5 -8
- package/dist/testing/integration/concurrency.spec.js +8 -17
- package/dist/testing/integration/docker.spec.js +6 -9
- package/dist/testing/integration/env.spec.js +27 -34
- package/dist/testing/integration/error.spec.js +5 -9
- package/dist/testing/integration/extend.spec.js +32 -0
- package/dist/testing/integration/glob.spec.js +35 -28
- package/dist/testing/integration/include.spec.js +17 -16
- package/dist/testing/integration/invalid.spec.js +3 -2
- package/dist/testing/integration/invalid_loop.spec.js +13 -0
- package/dist/testing/integration/kubernetes.spec.js +15 -0
- package/dist/testing/integration/labels.spec.js +47 -0
- package/dist/testing/integration/local.spec.js +4 -7
- package/dist/testing/integration/monorepo.spec.js +5 -9
- package/dist/testing/integration/multi-line.spec.js +4 -4
- package/dist/testing/integration/program.spec.js +3 -10
- package/dist/testing/integration/reference.spec.js +10 -13
- package/dist/testing/integration/services.spec.js +14 -0
- package/dist/testing/integration/store.spec.js +42 -38
- package/dist/testing/integration/unknown.spec.js +4 -4
- package/dist/testing/integration/validate.spec.js +4 -4
- package/dist/testing/integration/watch.spec.js +34 -33
- package/dist/testing/lazy.js +17 -0
- package/dist/testing/start-watch-processes.js +29 -0
- package/dist/testing/test-suite-setup.js +3 -0
- package/dist/utils/abort-event.js +14 -1
- package/dist/utils/abortable-function.js +71 -0
- package/dist/utils/debouncer.spec.js +8 -8
- package/dist/utils/environment-config.js +13 -0
- package/dist/utils/fail-never.js +1 -1
- package/dist/utils/sleep.spec.js +3 -3
- package/package.json +24 -21
- package/dist/console/get-console-context-mock.js +0 -33
- package/dist/executer/clean.js +0 -17
- package/dist/executer/execute-local.js +0 -59
- package/dist/executer/execute.js +0 -139
- package/dist/executer/execution-context-event.js +0 -3
- package/dist/executer/execution-context-mock.js +0 -3
- package/dist/executer/executor-mock.js +0 -61
- package/dist/executer/get-environment-mock.js +0 -16
- package/dist/executer/get-execution-context-mock.js +0 -18
- package/dist/executer/get-local-executor.js +0 -56
- package/dist/executer/restore.js +0 -19
- package/dist/executer/store.js +0 -19
- package/dist/logging/get-logger.js +0 -23
- package/dist/logging/message-to-console.js +0 -16
- package/dist/optimizer/optimize.js +0 -32
- package/dist/optimizer/work-node-description.js +0 -12
- package/dist/planner/utils/find-build-task.js +0 -18
- package/dist/testing/create-work-tree.js +0 -11
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createSchedulerState = void 0;
|
|
4
|
+
const plan_work_nodes_1 = require("../planner/utils/plan-work-nodes");
|
|
5
|
+
const check_for_loop_1 = require("./scheduler/check-for-loop");
|
|
6
|
+
const state_1 = require("./state");
|
|
7
|
+
function createSchedulerState(input) {
|
|
8
|
+
const state = {
|
|
9
|
+
service: {},
|
|
10
|
+
node: {},
|
|
11
|
+
cacheMethod: input.cacheMethod,
|
|
12
|
+
watch: input.watch,
|
|
13
|
+
};
|
|
14
|
+
for (const node of (0, plan_work_nodes_1.iterateWorkNodes)(input.nodes)) {
|
|
15
|
+
state.node[node.id] = {
|
|
16
|
+
type: 'pending',
|
|
17
|
+
node: node,
|
|
18
|
+
stateKey: null,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
for (const service of (0, plan_work_nodes_1.iterateWorkServices)(input.services)) {
|
|
22
|
+
state.service[service.id] = {
|
|
23
|
+
type: 'pending',
|
|
24
|
+
service,
|
|
25
|
+
stateKey: null,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
(0, check_for_loop_1.checkForLoop)(state);
|
|
29
|
+
return new state_1.State(state);
|
|
30
|
+
}
|
|
31
|
+
exports.createSchedulerState = createSchedulerState;
|
|
32
|
+
//# sourceMappingURL=create-scheduler-state.js.map
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.dockerNode = void 0;
|
|
4
|
+
const service_dns_1 = require("./service-dns");
|
|
5
|
+
const execute_docker_1 = require("./execute-docker");
|
|
6
|
+
const abort_1 = require("./abort");
|
|
7
|
+
const write_work_node_cache_1 = require("../optimizer/write-work-node-cache");
|
|
8
|
+
const log_1 = require("../log");
|
|
9
|
+
const states_1 = require("./states");
|
|
10
|
+
const execution_steps_1 = require("./execution-steps");
|
|
11
|
+
const using_container_1 = require("../docker/using-container");
|
|
12
|
+
const print_container_options_1 = require("./print-container-options");
|
|
13
|
+
function buildCreateOptions(node, serviceContainers) {
|
|
14
|
+
const links = [];
|
|
15
|
+
const hosts = [];
|
|
16
|
+
for (const need of node.needs) {
|
|
17
|
+
const dns = serviceContainers[need.id];
|
|
18
|
+
if ((0, service_dns_1.isHostServiceDns)(dns)) {
|
|
19
|
+
hosts.push(`${need.name}:${dns.host}`);
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
if (!dns.containerId) {
|
|
23
|
+
throw new Error(`service ${need.name} is not running`);
|
|
24
|
+
}
|
|
25
|
+
links.push(`${dns.containerId}:${need.name}`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
Image: node.image,
|
|
30
|
+
Tty: true,
|
|
31
|
+
Entrypoint: node.shell,
|
|
32
|
+
Cmd: ['-c', 'sleep 3600'],
|
|
33
|
+
Env: Object.keys(node.envs).map((k) => `${k}=${node.envs[k]}`),
|
|
34
|
+
WorkingDir: (0, execute_docker_1.convertToPosixPath)(node.cwd),
|
|
35
|
+
Labels: { app: 'hammerkit', 'hammerkit-id': node.id, 'hammerkit-type': 'task' },
|
|
36
|
+
HostConfig: {
|
|
37
|
+
Binds: [
|
|
38
|
+
...node.mounts.map((v) => `${v.localPath}:${(0, execute_docker_1.convertToPosixPath)(v.containerPath)}`),
|
|
39
|
+
...node.volumes.map((v) => `${v.name}:${(0, execute_docker_1.convertToPosixPath)(v.containerPath)}`),
|
|
40
|
+
],
|
|
41
|
+
PortBindings: node.ports.reduce((map, port) => {
|
|
42
|
+
map[`${port.containerPort}/tcp`] = [{ HostPort: `${port.hostPort}` }];
|
|
43
|
+
return map;
|
|
44
|
+
}, {}),
|
|
45
|
+
ExtraHosts: hosts,
|
|
46
|
+
Links: links,
|
|
47
|
+
AutoRemove: true,
|
|
48
|
+
},
|
|
49
|
+
ExposedPorts: node.ports.reduce((map, port) => {
|
|
50
|
+
map[`${port.containerPort}/tcp`] = {};
|
|
51
|
+
return map;
|
|
52
|
+
}, {}),
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
function dockerNode(node, stateKey, serviceContainers, state, environment) {
|
|
56
|
+
return async (abort, started) => {
|
|
57
|
+
const status = environment.status.task(node);
|
|
58
|
+
status.write('info', `execute ${node.name} in container`);
|
|
59
|
+
try {
|
|
60
|
+
await (0, execution_steps_1.prepareMounts)(node, environment);
|
|
61
|
+
(0, abort_1.checkForAbort)(abort.signal);
|
|
62
|
+
await (0, execution_steps_1.pullImage)(node, environment);
|
|
63
|
+
(0, abort_1.checkForAbort)(abort.signal);
|
|
64
|
+
await (0, execution_steps_1.prepareVolume)(node, environment);
|
|
65
|
+
(0, abort_1.checkForAbort)(abort.signal);
|
|
66
|
+
const containerOptions = buildCreateOptions(node, serviceContainers);
|
|
67
|
+
(0, print_container_options_1.printContainerOptions)(status, containerOptions);
|
|
68
|
+
const success = await (0, using_container_1.usingContainer)(environment, node, containerOptions, async (container) => {
|
|
69
|
+
await (0, execution_steps_1.setUserPermissions)(node, container, environment);
|
|
70
|
+
for (const cmd of node.cmds) {
|
|
71
|
+
(0, abort_1.checkForAbort)(abort.signal);
|
|
72
|
+
status.write('info', `execute cmd "${cmd.cmd}" in container`);
|
|
73
|
+
const result = await (0, execute_docker_1.execCommand)(status, environment, container, (0, execute_docker_1.convertToPosixPath)(cmd.path), [node.shell, '-c', cmd.cmd], node.user, undefined, abort.signal);
|
|
74
|
+
if (result.type === 'timeout') {
|
|
75
|
+
throw new Error(`command ${cmd.cmd} timed out`);
|
|
76
|
+
}
|
|
77
|
+
if (result.type === 'canceled') {
|
|
78
|
+
throw new abort_1.AbortError();
|
|
79
|
+
}
|
|
80
|
+
if (result.result.ExitCode !== 0) {
|
|
81
|
+
state.patchNode({
|
|
82
|
+
node,
|
|
83
|
+
stateKey,
|
|
84
|
+
type: 'crash',
|
|
85
|
+
exitCode: result.result.ExitCode ?? 1,
|
|
86
|
+
}, stateKey);
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return true;
|
|
91
|
+
});
|
|
92
|
+
if (success) {
|
|
93
|
+
await (0, write_work_node_cache_1.writeWorkNodeCache)(node, environment);
|
|
94
|
+
state.patchNode({
|
|
95
|
+
node,
|
|
96
|
+
stateKey,
|
|
97
|
+
type: 'completed',
|
|
98
|
+
cached: false,
|
|
99
|
+
duration: (0, states_1.getDuration)(started),
|
|
100
|
+
}, stateKey);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
catch (e) {
|
|
104
|
+
if (e instanceof abort_1.AbortError) {
|
|
105
|
+
state.patchNode({
|
|
106
|
+
node,
|
|
107
|
+
stateKey,
|
|
108
|
+
type: 'canceled',
|
|
109
|
+
}, stateKey);
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
state.patchNode({
|
|
113
|
+
node,
|
|
114
|
+
stateKey,
|
|
115
|
+
type: 'error',
|
|
116
|
+
errorMessage: (0, log_1.getErrorMessage)(e),
|
|
117
|
+
}, stateKey);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
exports.dockerNode = dockerNode;
|
|
123
|
+
//# sourceMappingURL=docker-node.js.map
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.dockerService = void 0;
|
|
4
|
+
const abort_1 = require("./abort");
|
|
5
|
+
const execute_docker_1 = require("./execute-docker");
|
|
6
|
+
const stream_1 = require("../docker/stream");
|
|
7
|
+
const abort_event_1 = require("../utils/abort-event");
|
|
8
|
+
const log_1 = require("../log");
|
|
9
|
+
const remove_container_1 = require("../docker/remove-container");
|
|
10
|
+
const check_readiness_1 = require("./check-readiness");
|
|
11
|
+
const execution_steps_1 = require("./execution-steps");
|
|
12
|
+
function dockerService(service, stateKey, state, environment) {
|
|
13
|
+
return async (abort) => {
|
|
14
|
+
const status = environment.status.service(service);
|
|
15
|
+
let container = null;
|
|
16
|
+
await (0, execution_steps_1.prepareMounts)(service, environment);
|
|
17
|
+
(0, abort_1.checkForAbort)(abort.signal);
|
|
18
|
+
await (0, execution_steps_1.pullImage)(service, environment);
|
|
19
|
+
(0, abort_1.checkForAbort)(abort.signal);
|
|
20
|
+
await (0, execution_steps_1.prepareVolume)(service, environment);
|
|
21
|
+
(0, abort_1.checkForAbort)(abort.signal);
|
|
22
|
+
try {
|
|
23
|
+
(0, abort_1.checkForAbort)(abort.signal);
|
|
24
|
+
status.write('debug', `create container with image ${service.image}`);
|
|
25
|
+
container = await environment.docker.createContainer({
|
|
26
|
+
Image: service.image,
|
|
27
|
+
Env: Object.keys(service.envs).map((k) => `${k}=${service.envs[k]}`),
|
|
28
|
+
Labels: { app: 'hammerkit', 'hammerkit-id': service.id, 'hammerkit-type': 'service' },
|
|
29
|
+
ExposedPorts: service.ports.reduce((map, port) => {
|
|
30
|
+
map[`${port.containerPort}/tcp`] = {};
|
|
31
|
+
return map;
|
|
32
|
+
}, {}),
|
|
33
|
+
Cmd: service.cmd ? service.cmd.split(' ') : undefined,
|
|
34
|
+
HostConfig: {
|
|
35
|
+
Binds: [
|
|
36
|
+
...service.mounts.map((v) => `${v.localPath}:${(0, execute_docker_1.convertToPosixPath)(v.containerPath)}`),
|
|
37
|
+
...service.volumes.map((v) => `${v.name}:${(0, execute_docker_1.convertToPosixPath)(v.containerPath)}`),
|
|
38
|
+
],
|
|
39
|
+
PortBindings: service.ports.reduce((map, port) => {
|
|
40
|
+
map[`${port.containerPort}/tcp`] = [{ HostPort: `${port.hostPort}` }];
|
|
41
|
+
return map;
|
|
42
|
+
}, {}),
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
const stream = await container.attach({ stream: true, stdout: true, stderr: true });
|
|
46
|
+
(0, stream_1.logStream)(status, stream);
|
|
47
|
+
await container.start();
|
|
48
|
+
// await setUserPermissions(service, container, environment)
|
|
49
|
+
if (!service.healthcheck) {
|
|
50
|
+
state.patchService({
|
|
51
|
+
type: 'running',
|
|
52
|
+
service,
|
|
53
|
+
dns: { containerId: container.id },
|
|
54
|
+
stateKey,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
let ready = false;
|
|
59
|
+
do {
|
|
60
|
+
ready = await (0, check_readiness_1.checkReadiness)(status, service.healthcheck, environment, container, abort.signal);
|
|
61
|
+
if (!ready) {
|
|
62
|
+
await new Promise((resolve) => setTimeout(() => resolve(), 1000));
|
|
63
|
+
}
|
|
64
|
+
} while (!ready && !abort.signal.aborted);
|
|
65
|
+
if (ready) {
|
|
66
|
+
state.patchService({
|
|
67
|
+
type: 'running',
|
|
68
|
+
service,
|
|
69
|
+
dns: { containerId: container.id },
|
|
70
|
+
stateKey,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
await (0, abort_event_1.waitOnAbort)(abort.signal);
|
|
75
|
+
state.patchService({
|
|
76
|
+
type: 'end',
|
|
77
|
+
service,
|
|
78
|
+
stateKey,
|
|
79
|
+
reason: 'terminated',
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
catch (e) {
|
|
83
|
+
if (e instanceof abort_1.AbortError) {
|
|
84
|
+
state.patchService({
|
|
85
|
+
type: 'canceled',
|
|
86
|
+
service,
|
|
87
|
+
stateKey,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
status.write('error', (0, log_1.getErrorMessage)(e));
|
|
92
|
+
state.patchService({
|
|
93
|
+
type: 'end',
|
|
94
|
+
service,
|
|
95
|
+
reason: 'crash',
|
|
96
|
+
stateKey,
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
finally {
|
|
101
|
+
if (container) {
|
|
102
|
+
try {
|
|
103
|
+
await (0, remove_container_1.removeContainer)(container);
|
|
104
|
+
}
|
|
105
|
+
catch (e) {
|
|
106
|
+
status.write('error', `remove of container failed ${(0, log_1.getErrorMessage)(e)}`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
exports.dockerService = dockerService;
|
|
113
|
+
//# sourceMappingURL=docker-service.js.map
|
|
@@ -1,3 +1,20 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.environmentMock = void 0;
|
|
4
|
+
const work_node_status_1 = require("../planner/work-node-status");
|
|
5
|
+
const console_context_mock_1 = require("../console/console-context-mock");
|
|
6
|
+
const get_file_context_1 = require("../file/get-file-context");
|
|
7
|
+
const execute_docker_1 = require("./execute-docker");
|
|
8
|
+
function environmentMock(cwd) {
|
|
9
|
+
return {
|
|
10
|
+
cwd,
|
|
11
|
+
file: (0, get_file_context_1.getFileContext)(cwd),
|
|
12
|
+
console: (0, console_context_mock_1.consoleContextMock)(),
|
|
13
|
+
abortCtrl: new AbortController(),
|
|
14
|
+
processEnvs: {},
|
|
15
|
+
status: (0, work_node_status_1.statusConsole)(),
|
|
16
|
+
docker: (0, execute_docker_1.getContainerCli)(),
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
exports.environmentMock = environmentMock;
|
|
3
20
|
//# sourceMappingURL=environment-mock.js.map
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.cleanCache = exports.storeCache = exports.restoreCache = void 0;
|
|
4
|
+
const plan_work_nodes_1 = require("../planner/utils/plan-work-nodes");
|
|
5
|
+
const get_cache_directory_1 = require("../optimizer/get-cache-directory");
|
|
6
|
+
const path_1 = require("path");
|
|
7
|
+
const move_files_1 = require("../file/move-files");
|
|
8
|
+
const execute_docker_1 = require("./execute-docker");
|
|
9
|
+
const get_docker_executor_1 = require("./get-docker-executor");
|
|
10
|
+
const tar_1 = require("tar");
|
|
11
|
+
const work_node_1 = require("../planner/work-node");
|
|
12
|
+
const using_container_1 = require("../docker/using-container");
|
|
13
|
+
const work_service_1 = require("../planner/work-service");
|
|
14
|
+
const plan_work_volume_1 = require("../planner/utils/plan-work-volume");
|
|
15
|
+
async function restoreCache(path, workTree, environment) {
|
|
16
|
+
for (const node of (0, plan_work_nodes_1.iterateWorkNodes)(workTree.nodes)) {
|
|
17
|
+
const cachePath = (0, get_cache_directory_1.getCacheDirectory)(node.id);
|
|
18
|
+
const sourceCacheDir = (0, path_1.join)(path, node.id);
|
|
19
|
+
await (0, move_files_1.moveFiles)(node, environment, function* () {
|
|
20
|
+
yield { from: (0, path_1.join)(sourceCacheDir, 'stats.json'), to: (0, path_1.join)(cachePath, 'stats.json') };
|
|
21
|
+
yield { from: (0, path_1.join)(sourceCacheDir, 'description.json'), to: (0, path_1.join)(cachePath, 'description.json') };
|
|
22
|
+
});
|
|
23
|
+
if ((0, work_node_1.isContainerWorkNode)(node)) {
|
|
24
|
+
await restoreContainer(environment, node, sourceCacheDir);
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
await restoreLocal(environment, node, sourceCacheDir);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
exports.restoreCache = restoreCache;
|
|
32
|
+
async function restoreLocal(environment, node, path) {
|
|
33
|
+
for (const generate of getGenerates(node, path)) {
|
|
34
|
+
if (await environment.file.exists(generate.filename)) {
|
|
35
|
+
await (0, tar_1.extract)({
|
|
36
|
+
file: generate.filename,
|
|
37
|
+
cwd: node.cwd,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
async function restoreContainer(environment, node, path) {
|
|
43
|
+
await (0, using_container_1.usingContainer)(environment, node, {
|
|
44
|
+
Image: node.image,
|
|
45
|
+
Tty: true,
|
|
46
|
+
Entrypoint: 'sh',
|
|
47
|
+
Cmd: ['-c', 'sleep 3600'],
|
|
48
|
+
WorkingDir: (0, execute_docker_1.convertToPosixPath)(node.cwd),
|
|
49
|
+
Labels: { app: 'hammerkit', 'hammerkit-id': node.id, 'hammerkit-type': 'task' },
|
|
50
|
+
HostConfig: {
|
|
51
|
+
AutoRemove: true,
|
|
52
|
+
Binds: [...node.volumes.map((v) => `${v.name}:${(0, execute_docker_1.convertToPosixPath)(v.containerPath)}`)],
|
|
53
|
+
},
|
|
54
|
+
}, async (container) => {
|
|
55
|
+
for (const generate of getGenerates(node, path)) {
|
|
56
|
+
if (await environment.file.exists(generate.filename)) {
|
|
57
|
+
await container.putArchive(environment.file.readStream(generate.filename), {
|
|
58
|
+
path: (0, path_1.dirname)(generate.path),
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
function* getGenerates(node, path) {
|
|
65
|
+
const generates = node.generates.filter((g) => !g.inherited);
|
|
66
|
+
for (const generate of generates) {
|
|
67
|
+
const generateId = (0, path_1.relative)(node.cwd, generate.path).split(path_1.sep).join('-');
|
|
68
|
+
yield {
|
|
69
|
+
filename: (0, path_1.join)(path, generateId + '-generates.tgz'),
|
|
70
|
+
path: generate.path,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
async function archiveContainer(environment, node, path) {
|
|
75
|
+
await (0, using_container_1.usingContainer)(environment, node, {
|
|
76
|
+
Image: node.image,
|
|
77
|
+
Tty: true,
|
|
78
|
+
Entrypoint: 'sh',
|
|
79
|
+
Cmd: ['-c', 'sleep 3600'],
|
|
80
|
+
WorkingDir: (0, execute_docker_1.convertToPosixPath)(node.cwd),
|
|
81
|
+
Labels: { app: 'hammerkit', 'hammerkit-id': node.id, 'hammerkit-type': 'task' },
|
|
82
|
+
HostConfig: {
|
|
83
|
+
AutoRemove: true,
|
|
84
|
+
Binds: [...node.volumes.map((v) => `${v.name}:${(0, execute_docker_1.convertToPosixPath)(v.containerPath)}`)],
|
|
85
|
+
},
|
|
86
|
+
}, async (container) => {
|
|
87
|
+
for (const generatedArchive of getGenerates(node, path)) {
|
|
88
|
+
const readable = await container.getArchive({
|
|
89
|
+
path: generatedArchive.path,
|
|
90
|
+
});
|
|
91
|
+
await environment.file.writeStream(generatedArchive.filename, readable);
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
async function archiveLocal(environment, node, path) {
|
|
96
|
+
for (const generatedArchive of getGenerates(node, path)) {
|
|
97
|
+
await environment.file.writeStream(generatedArchive.filename, (0, tar_1.create)({
|
|
98
|
+
cwd: node.cwd,
|
|
99
|
+
gzip: true,
|
|
100
|
+
}, [(0, path_1.relative)(node.cwd, generatedArchive.path)]));
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
async function storeCache(path, workTree, environment) {
|
|
104
|
+
for (const node of (0, plan_work_nodes_1.iterateWorkNodes)(workTree.nodes)) {
|
|
105
|
+
const cachePath = (0, get_cache_directory_1.getCacheDirectory)(node.id);
|
|
106
|
+
const sourceCacheDir = (0, path_1.join)(path, node.id);
|
|
107
|
+
await (0, move_files_1.moveFiles)(node, environment, function* () {
|
|
108
|
+
yield { from: (0, path_1.join)(cachePath, 'stats.json'), to: (0, path_1.join)(sourceCacheDir, 'stats.json') };
|
|
109
|
+
yield { from: (0, path_1.join)(cachePath, 'description.json'), to: (0, path_1.join)(sourceCacheDir, 'description.json') };
|
|
110
|
+
});
|
|
111
|
+
if ((0, work_node_1.isContainerWorkNode)(node)) {
|
|
112
|
+
await archiveContainer(environment, node, sourceCacheDir);
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
await archiveLocal(environment, node, sourceCacheDir);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
exports.storeCache = storeCache;
|
|
120
|
+
async function cleanCache(workTree, environment, options) {
|
|
121
|
+
for (const node of (0, plan_work_nodes_1.iterateWorkNodes)(workTree.nodes)) {
|
|
122
|
+
const nodeStatus = environment.status.task(node);
|
|
123
|
+
for (const generate of node.generates) {
|
|
124
|
+
if (generate.inherited) {
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
const volumeName = (0, plan_work_volume_1.getVolumeName)(generate.path);
|
|
128
|
+
const volumeExists = await (0, get_docker_executor_1.existsVolume)(environment, volumeName);
|
|
129
|
+
if (volumeExists) {
|
|
130
|
+
nodeStatus.write('info', `remove volume ${volumeName}`);
|
|
131
|
+
const volume = await environment.docker.getVolume(volumeName);
|
|
132
|
+
await volume.remove();
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
nodeStatus.write('info', `generate ${generate} has no volume ${volumeName}`);
|
|
136
|
+
}
|
|
137
|
+
nodeStatus.write('info', `remove local directory ${generate.path}`);
|
|
138
|
+
await environment.file.remove(generate.path);
|
|
139
|
+
}
|
|
140
|
+
const cachePath = (0, get_cache_directory_1.getCacheDirectory)(node.id);
|
|
141
|
+
if (await environment.file.exists(cachePath)) {
|
|
142
|
+
nodeStatus.write('info', `remove cache ${cachePath}`);
|
|
143
|
+
await environment.file.remove(cachePath);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
if (options.service) {
|
|
147
|
+
for (const service of (0, plan_work_nodes_1.iterateWorkServices)(workTree.services)) {
|
|
148
|
+
if (!(0, work_service_1.isContainerWorkService)(service)) {
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
const nodeStatus = environment.status.service(service);
|
|
152
|
+
for (const volume of service.volumes) {
|
|
153
|
+
const volumeExists = await (0, get_docker_executor_1.existsVolume)(environment, volume.name);
|
|
154
|
+
if (!volumeExists) {
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
nodeStatus.write('info', `remove volume ${volume.name}`);
|
|
158
|
+
const containerVolume = await environment.docker.getVolume(volume.name);
|
|
159
|
+
await containerVolume.remove();
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
exports.cleanCache = cleanCache;
|
|
165
|
+
//# sourceMappingURL=event-cache.js.map
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.executeCommand = void 0;
|
|
4
|
+
const child_process_1 = require("child_process");
|
|
5
|
+
const os_1 = require("os");
|
|
6
|
+
const log_1 = require("../log");
|
|
7
|
+
const abort_1 = require("./abort");
|
|
8
|
+
const abort_event_1 = require("../utils/abort-event");
|
|
9
|
+
async function executeCommand(status, abortSignal, cwd, command, envs) {
|
|
10
|
+
return new Promise((resolve, reject) => {
|
|
11
|
+
const ps = (0, child_process_1.exec)(command, {
|
|
12
|
+
env: envs,
|
|
13
|
+
cwd,
|
|
14
|
+
shell: (0, os_1.platform)() === 'win32' ? 'powershell.exe' : undefined,
|
|
15
|
+
});
|
|
16
|
+
ps.stdout?.on('data', async (data) => {
|
|
17
|
+
for (const log of (0, log_1.getLogs)(data)) {
|
|
18
|
+
status.console('stdout', log);
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
ps.stderr?.on('data', async (data) => {
|
|
22
|
+
for (const log of (0, log_1.getLogs)(data)) {
|
|
23
|
+
status.console('stderr', log);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
ps.on('error', (err) => {
|
|
27
|
+
reject(err);
|
|
28
|
+
});
|
|
29
|
+
ps.on('close', (code) => {
|
|
30
|
+
if (abortSignal.aborted) {
|
|
31
|
+
reject(new abort_1.AbortError());
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
resolve(code ?? 0);
|
|
35
|
+
});
|
|
36
|
+
(0, abort_event_1.listenOnAbort)(abortSignal, () => {
|
|
37
|
+
ps.kill();
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
exports.executeCommand = executeCommand;
|
|
42
|
+
//# sourceMappingURL=execute-command.js.map
|