navy
Version:
Quick and powerful development environments using Docker and Docker Compose
230 lines (221 loc) • 15.4 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _commander = require("commander");
var _chalk = _interopRequireDefault(require("chalk"));
var _errors = require("../errors");
var _config = require("../config");
var _driverLogging = require("../driver-logging");
var _configProvider = require("../config-provider");
var _mergeActionOptions = require("./util/merge-action-options");
const loadingLabelMap = {
destroy: 'Destroying services...',
start: 'Starting services...',
stop: 'Stopping services...',
restart: 'Restarting services...',
kill: 'Killing services...',
rm: 'Removing services...',
update: 'Updating service images...',
delete: 'Deleting navy configuration...',
useTag: 'Pulling custom tag...',
resetTag: 'Resetting to default tag...',
usePort: 'Setting up port mapping...',
resetPort: 'Resetting port mapping...'
};
function removeFirstLineFromStackTrace(stack) {
return stack?.split('\n')?.slice(1)?.join('\n');
}
function normaliseLazyRequireArgs(args) {
if (args.length === 0) return args;
const last = args[args.length - 1];
if (!last || typeof last.optsWithGlobals !== 'function') {
return args;
}
const command = last;
const rest = args.slice(0, -1);
if (rest.length === 0) {
return rest;
}
const lastOpt = rest[rest.length - 1];
if (lastOpt && typeof lastOpt === 'object' && !Array.isArray(lastOpt)) {
return [...rest.slice(0, -1), (0, _mergeActionOptions.mergeActionOptions)(lastOpt, command)];
}
return rest;
}
function wrapper(res) {
if (res.catch) {
res.catch(ex => {
(0, _driverLogging.stopDriverLogging)({
success: false
});
if (ex instanceof _errors.NavyError) {
ex.prettyPrint();
} else if (ex.name === 'Invariant Violation') {
console.log();
console.log(_chalk.default.bgRed(_chalk.default.bold(' ' + ex.name + ' ')));
console.log();
console.log(' ' + ex.message.substring(ex.message.indexOf(': ') + 2));
console.log();
console.log(' ' + _chalk.default.blue('Run') + ' ' + _chalk.default.bold('navy doctor') + ' ' + _chalk.default.blue('to attempt troubleshooting'));
console.log();
console.log(_chalk.default.dim(removeFirstLineFromStackTrace(ex.stack)));
console.log();
} else {
console.error(ex.stack);
}
process.exit(1);
});
}
return res;
}
function basicCliWrapper(fnName, wrapperOpts = {}) {
const driverLogging = wrapperOpts.driverLogging == null ? true : wrapperOpts.driverLogging;
return async function (maybeServices, ...args) {
const {
getNavy
} = require('../navy');
// commander v12 invokes action handlers with a trailing Command instance
// appended after the parsed options. Strip it and merge global options
// (e.g. `navy -e dev start`) into the opts object.
let command = null;
if (args.length > 0) {
const last = args[args.length - 1];
if (last && typeof last.optsWithGlobals === 'function') {
command = last;
args = args.slice(0, -1);
}
}
let opts = args.length === 0 ? maybeServices : args[args.length - 1];
const otherArgs = args.slice(0, args.length - 1);
if (command && opts && typeof opts === 'object' && !Array.isArray(opts)) {
opts = (0, _mergeActionOptions.mergeActionOptions)(opts, command);
}
const envName = opts.navy;
if (wrapperOpts.serviceBasedAlias && maybeServices.length) {
console.log(`This command should not be called with a list of services. calling '${wrapperOpts.serviceBasedAlias}' instead`);
fnName = wrapperOpts.serviceBasedAlias;
maybeServices = maybeServices.split(' ');
}
process.on('unhandledRejection', ex => {
(0, _driverLogging.stopDriverLogging)({
success: false
});
if (ex instanceof _errors.NavyError) {
ex.prettyPrint();
} else {
console.error(ex.stack);
}
process.exit();
});
if (driverLogging) (0, _driverLogging.startDriverLogging)(loadingLabelMap[fnName]);
const navy = getNavy(envName);
await navy.ensurePluginsLoaded();
await navy.emitAsync(`cli.before.${fnName}`, fnName);
const returnVal = await navy[fnName](Array.isArray(maybeServices) && maybeServices.length === 0 ? undefined : maybeServices, ...otherArgs);
await navy.emitAsync(`cli.after.${fnName}`, fnName);
if (driverLogging) (0, _driverLogging.stopDriverLogging)();
if (Array.isArray(returnVal)) {
return console.log(returnVal.join('\n'));
}
if (returnVal != null) {
console.log(returnVal);
}
};
}
function lazyRequire(path) {
return function (...args) {
const mod = require(path);
const normalised = normaliseLazyRequireArgs(args);
return wrapper((mod.default || mod)(...normalised));
};
}
const defaultNavy = process.env.NAVY_NAME || (0, _config.getConfig)().defaultNavy;
// Strictly separate parent and subcommand options so an option that isn't
// declared on a subcommand (e.g. `navy status -e foo`) is reported as
// unknown rather than silently absorbed by the parent program.
_commander.program.enablePositionalOptions();
_commander.program.option('-e, --navy [env]', `set the navy name to be used [${defaultNavy}]`, defaultNavy);
const importCommand = _commander.program.command('import').option('-e, --navy [env]', `set the navy name to be used [${defaultNavy}]`, defaultNavy).description('Imports docker compose configuration from the current working directory and initialises a new navy').action(lazyRequire('./import'));
(0, _configProvider.getImportCommandLineOptions)().forEach(opt => importCommand.option(...opt));
_commander.program.command('launch [services...]').option('-e, --navy [env]', `set the navy name to be used [${defaultNavy}]`, defaultNavy).description('Launches the given services in a navy').action(lazyRequire('./launch')).on('--help', () => console.log(`
This will prompt you for the services that you want to bring up.
You can optionally provide the names of services to bring up which will disable the interactive prompt.
`));
_commander.program.command('destroy').option('-e, --navy [env]', `set the navy name to be used [${defaultNavy}]`, defaultNavy).description('Destroys a navy and all related data and services').action(basicCliWrapper('destroy', {
serviceBasedAlias: 'kill'
})).on('--help', () => console.log(`
This will destroy an entire navy and all of its data and services.
Examples:
$ navy destroy # destroy "${defaultNavy}" navy
$ navy destroy -e dev # destroy "dev" navy
$ navy destroy -e test # destroy "test" navy
`));
_commander.program.command('delete').option('-e, --navy [env]', `set the navy name to be used [${defaultNavy}]`, defaultNavy).description('Removes a navy configuration without removing any docker containers or services').action(basicCliWrapper('delete'));
_commander.program.command('ps').option('-e, --navy [env]', `set the navy name to be used [${defaultNavy}]`, defaultNavy).option('--json', 'output JSON instead of a table').description('Lists the running services for a navy').action(lazyRequire('./ps'));
_commander.program.command('start [services...]').option('-e, --navy [env]', `set the navy name to be used [${defaultNavy}]`, defaultNavy).description('Starts the given services').action(basicCliWrapper('start'));
_commander.program.command('stop [services...]').option('-e, --navy [env]', `set the navy name to be used [${defaultNavy}]`, defaultNavy).description('Stops the given services').action(basicCliWrapper('stop'));
_commander.program.command('restart [services...]').option('-e, --navy [env]', `set the navy name to be used [${defaultNavy}]`, defaultNavy).description('Restarts the given services').action(basicCliWrapper('restart'));
_commander.program.command('kill [services...]').option('-e, --navy [env]', `set the navy name to be used [${defaultNavy}]`, defaultNavy).description('Kills the given services').action(basicCliWrapper('kill'));
_commander.program.command('rm [services...]').option('-e, --navy [env]', `set the navy name to be used [${defaultNavy}]`, defaultNavy).description('Removes the given services').action(basicCliWrapper('rm'));
_commander.program.command('update [services...]').option('-e, --navy [env]', `set the navy name to be used [${defaultNavy}]`, defaultNavy).description('Pulls the given services\' images from their respective registries and relaunches the services').action(basicCliWrapper('update'));
_commander.program.command('updates').option('-e, --navy [env]', `set the navy name to be used [${defaultNavy}]`, defaultNavy).description('Checks for updates for all the launched services').action(lazyRequire('./updates'));
_commander.program.command('logs [services...]').option('-e, --navy [env]', `set the navy name to be used [${defaultNavy}]`, defaultNavy).description('Streams logs for the given services').action(lazyRequire('./logs'));
_commander.program.command('health').option('-e, --navy [env]', `set the navy name to be used [${defaultNavy}]`, defaultNavy).description('Shows the health status for all of the launched services').action(lazyRequire('./health'));
_commander.program.command('wait-for-healthy [services...]').option('-e, --navy [env]', `set the navy name to be used [${defaultNavy}]`, defaultNavy).description('Waits for the given services to be healthy').action(lazyRequire('./wait-for-healthy'));
_commander.program.command('use-tag <service> <tag>').option('-e, --navy [env]', `set the navy name to be used [${defaultNavy}]`, defaultNavy).description('Uses a specific tag for the given service').action(basicCliWrapper('useTag'));
_commander.program.command('reset-tag <service>').option('-e, --navy [env]', `set the navy name to be used [${defaultNavy}]`, defaultNavy).description('Resets any tag override on the given service').action(basicCliWrapper('resetTag'));
_commander.program.command('https [services...]').option('-e, --navy [env]', `set the navy name to be used [${defaultNavy}]`, defaultNavy).option('-d, --disable <service>', 'disable https (deletes cert) for a given service', null).option('-s, --setup', 'generate the Navy root CA (if needed) and install it in the system trust store').option('-a, --all', 'enable HTTPS for every service in this navy').option('-i, --issue <url>', 'issue a TLS certificate and key for a URL (non-Navy service), signed with the Navy root CA').option('-o, --issue-out <dir>', 'output directory for --issue (default: current working directory)').description('Prints or enables HTTPS services').action(lazyRequire('./https')).on('--help', () => console.log(`
Examples:
List urls of services that listen on https:
$ navy https
Enable https for mywebservice and anotherwebservice services
$ navy https mywebservice anotherwebservice
Enable https for all services
$ navy https --all
Disable https for mywebservice
$ navy https -d mywebservice
Generate the Navy root CA and install it for this user (no service names)
$ navy https --setup
Issue a cert for an external host (writes leaf key/cert + navy-root-ca.crt)
$ navy https --issue https://api.example.test
$ navy https --issue https://api.example.test -o ./tls
`));
_commander.program.command('use-port <service> <internal> <external>').option('-e, --navy [env]', `set the navy name to be used [${defaultNavy}]`, defaultNavy).description('Uses a specific external port for the given service and internal port').action(basicCliWrapper('usePort'));
_commander.program.command('reset-port <service> <internal>').option('-e, --navy [env]', `set the navy name to be used [${defaultNavy}]`, defaultNavy).description('Resets a specific external port mapping set by use-port').action(basicCliWrapper('resetPort'));
_commander.program.command('url <service>').option('-e, --navy [env]', `set the navy name to be used [${defaultNavy}]`, defaultNavy).description('Prints the external URL for the given service if it is a web service').action(basicCliWrapper('url', {
driverLogging: false
})).on('--help', () => console.log(`
Examples:
$ navy url mywebserver
http://mywebserver.dev.127.0.0.1.nip.io
`));
_commander.program.command('open <service>').option('-e, --navy [env]', `set the navy name to be used [${defaultNavy}]`, defaultNavy).description('Opens the given service in the default web browser, if the service is configured with a URL').action(lazyRequire('./open')).on('--help', () => console.log(`
Examples:
$ navy open mywebserver
Opening mywebserver...
`));
_commander.program.command('port <service> <port>').option('-e, --navy [env]', `set the navy name to be used [${defaultNavy}]`, defaultNavy).description('Prints the external port for the given internal port of the given service').action(basicCliWrapper('port', {
driverLogging: false
})).on('--help', () => console.log(`
Examples:
$ navy port mywebserver 80
35821
`));
_commander.program.command('available-services').option('-e, --navy [env]', `set the navy name to be used [${defaultNavy}]`, defaultNavy).description('Prints the names of the services that are launched or can be launched').action(basicCliWrapper('getAvailableServiceNames', {
driverLogging: false
}));
_commander.program.command('develop [service]').option('-e, --navy [env]', `set the navy name to be used [${defaultNavy}]`, defaultNavy).description('Puts the given service into development using the current working directory').action(lazyRequire('./develop'));
_commander.program.command('live [service]').option('-e, --navy [env]', `set the navy name to be used [${defaultNavy}]`, defaultNavy).description('Takes the given service out of development').action(lazyRequire('./live'));
_commander.program.command('run <name> [args...]').option('-e, --navy [env]', `set the navy name to be used [${defaultNavy}]`, defaultNavy).description('Runs a named command specific to the given Navy').action(lazyRequire('./run'));
_commander.program.command('refresh-config').option('-e, --navy [env]', `set the navy name to be used [${defaultNavy}]`, defaultNavy).description('Refreshes the configuration for the given Navy').action(lazyRequire('./refresh-config'));
_commander.program.command('status').option('--json', 'output JSON instead of a table').description('List all of the imported navies').action(lazyRequire('./status'));
_commander.program.command('doctor').description('Identifies and tries to fix some common issues which might cause Navy to stop working').action(lazyRequire('./doctor'));
_commander.program.command('config').description('Modify and get Navy global config - run `navy config` for help').action(lazyRequire('./config/wrapper'));
_commander.program.command('external-ip').description('Prints the external IP which services are accessible on').action(lazyRequire('./external-ip'));
_commander.program.command('use-lan-ip').description('Use your LAN ip address for connecting to Navy services').action(lazyRequire('./lan-ip'));
_commander.program.command('use-local-ip').description('Use your local ip address (127.0.0.1) for connecting to Navy services').action(lazyRequire('./local-ip'));
var _default = exports.default = _commander.program;
module.exports = exports.default;