This repository has been archived by the owner on Feb 12, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 51
/
docker.js
143 lines (129 loc) · 3.95 KB
/
docker.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
var path = require('path');
var child = require('child_process');
var fs = require('fs');
var _ = require('lodash');
var uuid = require('node-uuid');
var crypto = require('crypto');
var os = require('os');
var cli = require('heroku-cli-util');
var directory = require('./directory');
require('prototypes');
const FILENAME = 'Dockerfile';
module.exports = {
filename: FILENAME,
silent: false,
buildImage: buildImage,
ensureExecImage: ensureExecImage,
ensureStartImage: ensureStartImage,
imageExists: imageExists,
getAllImages: getAllImages,
runImage: runImage,
execSync: execSync
};
function execSync(command, streamOutput) {
var stdio = (streamOutput && !this.silent) ? [ 0, 1, 'pipe'] : [ 0, 'pipe', 'pipe' ];
try {
return child.execSync(`docker ${command}`, {
encoding: 'utf8',
stdio: stdio
});
}
catch (e) {
var msg = e.message.toLowerCase();
// TODO: more specific error messages
if (msg.indexOf('/var/run/docker.sock') >= 0) {
throw new Error('Unable to send commands to docker. Have you started docker (and boot2docker if necessary)?');
}
else if (msg.indexOf('an error occurred trying to connect') >= 0) {
throw new Error('Unable to send commands to docker. Have you started docker (and boot2docker if necessary)?');
}
else {
throw e;
}
}
}
function runImage(imageId, cwd, command, mount) {
if (!imageId) return;
var mountDir = crossPlatformCwd(cwd);
var mountComponent = mount ? `-v "${mountDir}:/app/src"` : '';
var envArgComponent = directory.getFormattedEnvArgComponent(cwd);
var runCommand = `run -w /app/src -p 3000:3000 --rm -it ${mountComponent} ${envArgComponent} ${imageId} sh -c "${command}" || true`;
return this.execSync(runCommand, true);
}
function buildImage(dir, id, dockerfile) {
cli.log('building image...');
var dockerfile = dockerfile || path.join(dir, FILENAME);
this.execSync(`build --force-rm --file="${dockerfile}" --tag="${id}" "${dir}"`, true);
return id;
}
function ensureExecImage(dir) {
var dockerfile = path.join(dir, FILENAME);
try {
var contents = fs.readFileSync(dockerfile, { encoding: 'utf8' });
var hash = createHash(contents);
var imageId = getImageId(hash);
this.imageExists(imageId) || this.buildImage(dir, imageId);
return imageId;
}
catch (e) {
if (e.code === 'ENOENT') {
cli.error('No Dockerfile found, did you run `heroku docker:init`?');
return;
}
else {
throw e;
}
}
}
function ensureStartImage(dir) {
var execImageId = this.ensureExecImage(dir);
if (!execImageId) {
return;
}
var contents = `FROM ${execImageId}`;
var imageId = `${execImageId}-start`;
var filename = `.Dockerfile-${uuid.v1()}`;
var filepath = path.join(dir, filename);
fs.writeFileSync(filepath, contents, { encoding: 'utf8' });
try {
this.buildImage(dir, imageId, filepath);
}
catch (e) {
fs.unlinkSync(filepath);
throw new Error('Unable to create start image');
}
fs.unlinkSync(filepath);
return imageId;
}
function createHash(contents) {
var md5 = crypto.createHash('md5');
md5.update(contents, 'utf8');
var digest = md5.digest('hex');
return digest;
}
function getImageId(hash) {
return `heroku-docker-${hash}`;
}
function imageExists(id) {
return this.getAllImages().indexOf(id) !== -1;
}
function getAllImages() {
var stdout = this.execSync('images', false);
if (!stdout) return [];
return _.map(_.filter(stdout.split('\n'), isImage), lineToId);
function isImage(line) {
return line.indexOf('heroku-docker') === 0;
}
function lineToId(line) {
return line.split(' ')[0];
}
}
function crossPlatformCwd(cwd){
if (os.platform() == 'win32') {
// this is due to how volumes are mounted by boot2docker/virtualbox
var p = path.parse(cwd);
return path.posix.sep + p.root.split(':')[0].toLowerCase() + path.posix.sep
+ p.dir.substring(p.root.length).replaceAll(path.sep, path.posix.sep) + path.posix.sep + p.base;
}
return cwd;
}