UNPKG

3.13 kBJavaScriptView Raw
1"use strict";
2var __importDefault = (this && this.__importDefault) || function (mod) {
3 return (mod && mod.__esModule) ? mod : { "default": mod };
4};
5Object.defineProperty(exports, "__esModule", { value: true });
6const os_1 = __importDefault(require("os"));
7const path_1 = __importDefault(require("path"));
8const stream_1 = __importDefault(require("stream"));
9const dockerode_1 = __importDefault(require("dockerode"));
10/**
11 * Executes a Docker environment.
12 *
13 * This class has a single method, `execute`, which starts a container from an
14 * image and runs the command specified in the Dockerfile `CMD` instruction.
15 *
16 * It mounts the project's directory into the container a `/work` and uses it
17 * as the working directory.
18 *
19 * It also sets the current user and group as the
20 * user and group in the container. This means that within the container the
21 * command that runs has the same permissions as the current user does in the
22 * `/work` directory.
23 *
24 * Finally, it removes the container (but not the image).
25 *
26 * This then is the equivalent of running the container with Docker from within
27 * the project directory using,
28 *
29 * docker run --rm --volume $(pwd):/work --workdir=/work --user=$(id -u):$(id -g) <image>
30 */
31class DockerExecutor {
32 /**
33 * Run a Docker container
34 *
35 * @param name Name of the Docker image to use
36 * @param folder Path of the project folder which will be mounted into the image
37 */
38 async execute(name, folder, command = '') {
39 // Capture stdout so we can attempt to parse it
40 // to JSON
41 let out = '';
42 let stdout = new stream_1.default.Writable({
43 write(chunk, encoding, callback) {
44 out += chunk.toString();
45 callback();
46 }
47 });
48 // Just write errors through to local console error
49 let stderr = new stream_1.default.Writable({
50 write(chunk, encoding, callback) {
51 console.error(chunk.toString());
52 callback();
53 }
54 });
55 // Get and set user:group
56 const userInfo = os_1.default.userInfo();
57 const user = `${userInfo.uid}:${userInfo.gid}`;
58 // Run the container!
59 // Options from https://docs.docker.com/engine/api/v1.37/#operation/ContainerCreate
60 const docker = new dockerode_1.default();
61 // If the user has specified a command thaen use that, otherwise fallback to the
62 // CMD in the Dockerfile
63 let cmd;
64 if (command)
65 cmd = command.split(' ');
66 const container = await docker.run(name, [], [stdout, stderr], {
67 Cmd: cmd,
68 HostConfig: {
69 Binds: [
70 `${path_1.default.resolve(folder)}:/work`
71 ]
72 },
73 Tty: false,
74 User: user,
75 WorkingDir: '/work'
76 });
77 container.remove();
78 // Attempt to parse output as JSON
79 try {
80 return JSON.parse(out);
81 }
82 catch (_a) {
83 return out.trim();
84 }
85 }
86}
87exports.default = DockerExecutor;