navy
Version:
Quick and powerful development environments using Docker and Docker Compose
196 lines (151 loc) • 5 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = createDockerComposeDriver;
var _jsYaml = _interopRequireDefault(require("js-yaml"));
var _fs = _interopRequireDefault(require("../../util/fs"));
var _dockerClient = _interopRequireDefault(require("../../util/docker-client"));
var _client = require("./client");
var _service = require("../../service");
const debug = require('debug')('navy:docker-compose');
function getArgsFromOptions(opts, argMap) {
return Object.keys(opts).map(key => argMap[key]).filter(arg => arg);
}
const launchArgMap = {
noDeps: '--no-deps',
forceRecreate: '--force-recreate'
};
function createDockerComposeDriver(navy) {
const {
exec,
getCompiledDockerComposePath
} = (0, _client.createComposeClient)(navy);
const driver = {
async launch(services, opts = {}) {
const additionalArgs = [];
debug('Got launch', services, opts);
if (opts) {
additionalArgs.push(...getArgsFromOptions(opts, launchArgMap));
debug('Resolve opts to args', additionalArgs);
}
if (!services) {
services = [];
}
await exec('up', ['-d', ...additionalArgs, ...services]);
},
async destroy() {
await exec('kill');
await exec('down', ['-v']);
},
async ps(service) {
const projectName = navy.normalisedName;
const psOptions = {
all: true,
filters: {
label: [`com.docker.compose.project=${projectName}`]
}
};
if (service) {
psOptions.filters.label.push(`com.docker.compose.service=${service}`);
}
const ps = await _dockerClient.default.listContainers(psOptions);
const inspect = await Promise.all(ps.map(container => _dockerClient.default.getContainer(container.Id).inspect()));
return inspect.map(service => ({
id: service.Id,
name: service.Config.Labels['com.docker.compose.service'],
image: service.Config.Image,
status: service.State.Running === true ? _service.Status.RUNNING : _service.Status.EXITED,
raw: service
}));
},
async start(services) {
await exec('start', services);
},
async stop(services) {
await exec('stop', services);
},
async restart(services) {
await exec('restart', services);
},
async kill(services) {
await exec('kill', services);
},
async rm(services) {
if (!services) {
services = [];
}
await exec('rm', ['-f', '-v', ...services]);
},
async update(services) {
if (!services) {
services = [];
}
await exec('pull', services); // only relaunch services which are already running
const launchedServiceNames = toLookupTable(await this.getLaunchedServiceNames());
const servicesToRelaunch = services.filter(name => launchedServiceNames[name]);
if (servicesToRelaunch.length) {
await exec('up', ['-d', '--no-deps', ...servicesToRelaunch]);
}
},
async spawnLogStream(services) {
if (!services) {
services = [];
}
await exec('logs', ['-f', '--tail=250', ...services], {
pipeLog: true,
maxBuffer: Infinity
});
},
async port(service, privatePort, index) {
if (index == null) index = 1;
const container = (await this.ps(service)).pop();
if (!container) {
return null;
}
const portConfig = container.raw.NetworkSettings.Ports[`${privatePort}/tcp`];
if (!Array.isArray(portConfig) || portConfig.length === 0) {
return null;
}
return Number(portConfig[0].HostPort);
},
async writeConfig(config) {
const yamlOut = _jsYaml.default.safeDump(config, {
skipInvalid: true
});
await _fs.default.writeFileAsync(getCompiledDockerComposePath(), yamlOut);
debug('Wrote docker-compose.tmp.yml', yamlOut);
},
async getConfig() {
const output = await exec('config', [], {
useOriginalDockerComposeFiles: true,
noLog: true
});
const config = _jsYaml.default.safeLoad(output);
return config;
},
async getLaunchedServiceNames() {
const projectName = navy.normalisedName;
const ps = await _dockerClient.default.listContainers({
all: true,
filters: {
label: [`com.docker.compose.project=${projectName}`]
}
});
const names = ps.map(container => container.Labels['com.docker.compose.service']);
return names;
},
async getAvailableServiceNames() {
const config = await driver.getConfig();
return Object.keys(config.services);
}
};
return driver;
}
function toLookupTable(keys) {
const lookupTable = {};
keys.forEach(key => lookupTable[key] = true);
return lookupTable;
}
module.exports = exports.default;