Skip to content

Commit 60d92af

Browse files
authored
Merge pull request #19 from magda-io/fix-relative-path-vol-support
Add local files volume mount support for both relative path and absolute path
2 parents 037ac99 + 34d8fac commit 60d92af

2 files changed

Lines changed: 96 additions & 14 deletions

File tree

lib/services.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ async function down(docker, projectName, recipe, output, options) {
2424
async function up(docker, projectName, recipe, output, options) {
2525
var services = [];
2626
var serviceNames = tools.sortServices(recipe);
27+
const cwdPath = path.dirname(output.file);
2728
for (var serviceName of serviceNames) {
2829
var pathScope = {};
2930
pathScope.file = output.file;
@@ -153,7 +154,12 @@ async function up(docker, projectName, recipe, output, options) {
153154
var opts = {
154155
name: projectName + '_' + serviceName + '_1',
155156
Image: service.image,
156-
HostConfig: servicesTools.buildHostConfig(projectName, service, recipe),
157+
HostConfig: servicesTools.buildHostConfig(
158+
projectName,
159+
service,
160+
recipe,
161+
cwdPath
162+
),
157163
Env: servicesTools.buildEnvVars(service),
158164
NetworkingConfig: {
159165
EndpointsConfig: {},
@@ -167,7 +173,7 @@ async function up(docker, projectName, recipe, output, options) {
167173
if (service.networks !== undefined) {
168174
servicesTools.buildNetworks(projectName, serviceName, service.networks, networksToAttach, opts);
169175
} else {
170-
opts.HostConfig.NetworkMode = projectName + '_default'
176+
opts.HostConfig.NetworkMode = projectName + '_default';
171177
opts.NetworkingConfig.EndpointsConfig[projectName + '_default'] = {
172178
IPAMConfig: null,
173179
Links: null,

lib/servicesTools.js

Lines changed: 88 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,39 @@ const tar = require('tar-fs');
33
const path = require('path');
44
const stream = require('stream');
55

6+
/**
7+
* if host path in the volume string (e.g. `./mylocal/file:/container/file`) is not absolute path,
8+
* this function will convert it to an absolute path using `cwd` (current working directory) parameter.
9+
* Otherwise, it will return volume string as it is.
10+
*
11+
* @param {*} volumeStr
12+
* @param {*} cwd
13+
*/
14+
function standardizeVolumeStr(volumeStr, cwd) {
15+
if (typeof volumeStr !== 'string' || volumeStr.length < 1) {
16+
return volumeStr;
17+
}
18+
volumeStr = volumeStr.trim();
19+
if (
20+
volumeStr.substring(0, 2) !== './' &&
21+
volumeStr.substring(0, 3) !== '../'
22+
) {
23+
return volumeStr;
24+
}
25+
const parts = volumeStr.split(':');
26+
if (parts.length !== 2) {
27+
return volumeStr;
28+
}
29+
if (!cwd) {
30+
throw new Error(
31+
'Current working dir path not available when local path is a relative path: ' +
32+
parts[0]
33+
);
34+
}
35+
const localPath = parts[0];
36+
return path.resolve(cwd, localPath) + ':' + parts[1];
37+
}
38+
639
module.exports = {
740
buildPorts: function (servicePorts, output) {
841
var ports = {};
@@ -41,15 +74,19 @@ module.exports = {
4174

4275
for (let index in split_port_split0_array) {
4376
ports[split_port_split1_array[index] + '/tcp'] = [
44-
{ HostPort: split_port_split0_array[index].toString() },
77+
{
78+
HostPort: split_port_split0_array[index].toString(),
79+
},
4580
];
4681
}
4782
} else if (port_split[0].includes('-')) {
4883
// "3000-3005"
4984
let split_port_split = port_split[0].split('-');
5085
ports[port_split[1] + '/tcp'] = [];
5186
for (let i = split_port_split[0]; i <= split_port_split[1]; i++) {
52-
ports[port_split[1] + '/tcp'].push({ HostPort: i.toString() });
87+
ports[port_split[1] + '/tcp'].push({
88+
HostPort: i.toString(),
89+
});
5390
}
5491
} else if (port_split[1].includes('/')) {
5592
// "6060:6060/udp"
@@ -114,7 +151,7 @@ module.exports = {
114151
},
115152

116153
//ToDo: complete the compose specification
117-
buildHostConfig: function (projectName, service, recipe) {
154+
buildHostConfig: function (projectName, service, recipe, cwd) {
118155
var output = {
119156
RestartPolicy: { Name: service.restart },
120157
};
@@ -123,12 +160,24 @@ module.exports = {
123160
for (var volume_from of service.volumes_from) {
124161
var vf = volume_from.split(':');
125162
var svf = recipe.services[vf[0]];
126-
this.buildVolumesHostconfig(projectName, svf.volumes, output, vf[1]);
163+
this.buildVolumesHostconfig(
164+
projectName,
165+
svf.volumes,
166+
output,
167+
vf[1],
168+
cwd
169+
);
127170
}
128171
}
129172

130173
if (service.volumes !== undefined) {
131-
this.buildVolumesHostconfig(projectName, service.volumes, output);
174+
this.buildVolumesHostconfig(
175+
projectName,
176+
service.volumes,
177+
output,
178+
undefined,
179+
cwd
180+
);
132181
}
133182

134183
if (service.ports !== undefined) {
@@ -334,22 +383,46 @@ module.exports = {
334383
return output;
335384
},
336385

337-
buildVolumesHostconfig: function (projectName, volumes, output, type) {
386+
buildVolumesHostconfig: function (projectName, volumes, output, type, cwd) {
338387
if (output['Binds'] === undefined) {
339388
output['Binds'] = [];
340389
}
341390
for (var volume of volumes) {
342391
if (typeof volume === 'string' || volume instanceof String) {
343-
var aux = projectName + '_' + volume;
344-
if (type == 'ro') {
345-
aux += ':ro';
392+
if (
393+
volume.substring(0, 2) === './' ||
394+
volume.substring(0, 3) === '../' ||
395+
volume[0] === '/'
396+
) {
397+
const stdVolume = standardizeVolumeStr(volume, cwd);
398+
const aux = stdVolume;
399+
if (type == 'ro') {
400+
aux += ':ro';
401+
}
402+
output['Binds'].push(aux);
403+
} else {
404+
var aux = projectName + '_' + volume;
405+
if (type == 'ro') {
406+
aux += ':ro';
407+
}
408+
output['Binds'].push(aux);
346409
}
347-
output['Binds'].push(aux);
348410
} else {
349411
var volumestr = '';
350412
if (volume.source && volume.target) {
351-
volumestr +=
352-
projectName + '_' + volume.source + ':' + volume.target + ':';
413+
if (
414+
volume.source.substring(0, 2) === './' ||
415+
volume.source.substring(0, 3) === '../' ||
416+
volume.source[0] === '/'
417+
) {
418+
volumestr += standardizeVolumeStr(
419+
volume.source + ':' + volume.target,
420+
cwd
421+
);
422+
} else {
423+
volumestr +=
424+
projectName + '_' + volume.source + ':' + volume.target + ':';
425+
}
353426
}
354427
if (volume.read_only || type == 'ro') {
355428
volumestr += 'ro,';
@@ -371,6 +444,9 @@ module.exports = {
371444
opts['Volumes'] = {};
372445
}
373446
for (var volume of volumes) {
447+
if (volume.substring(0, 2) === './' || volume[0] === '/') {
448+
continue;
449+
}
374450
if (typeof volume === 'string' || volume instanceof String) {
375451
var v = volume.split(':');
376452
opts['Volumes'][v[1]] = {};

0 commit comments

Comments
 (0)