workflow-cmd
Version:
Command line interface for workflow.
396 lines (343 loc) • 10.3 kB
JavaScript
;
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
var shell = _interopDefault(require('shelljs'));
var child_process = require('child_process');
var os = _interopDefault(require('os'));
var path = require('path');
var WorkflowCore = require('workflow-core');
var readPkgUp = _interopDefault(require('read-pkg-up'));
var execa = _interopDefault(require('execa'));
var fs = _interopDefault(require('fs'));
var prompt = _interopDefault(require('prompt'));
var util = require('util');
var yargs = _interopDefault(require('yargs'));
function args(args) {
const parsedArgs = {
named: {},
positional: []
};
const argsLength = args.length;
for (let i = 2; i < argsLength; i++) {
const arg = args[i];
if (arg[0] === '-') {
const name = getArgName(arg);
if (args[i + 1] === undefined) {
parsedArgs.named[name] = true;
} else {
parsedArgs.named[name] = args[i + 1];
}
i++;
} else {
parsedArgs.positional.push(arg);
}
}
return parsedArgs;
}
function getArgName(arg) {
let sliceIndex;
const isWordArg = arg[1] === '-';
if (isWordArg) {
if (arg.length === 3) throw new Error(`expected ${arg} to be a word arg`);
sliceIndex = 2;
} else {
sliceIndex = 1;
}
return arg.slice(sliceIndex, arg.length);
}
/* eslint-disable import/prefer-default-export */
function which(cmd) {
return shell.exec(`which ${cmd}`, { silent: true, async: false });
}
/* eslint-env node */
const platform = process.platform;
function isRunningI3() {
try {
child_process.execSync("i3-msg 'exec echo 1'", { stdio: 'ignore' });
return true;
} catch (e) {
return false;
}
}
function isRunningWmctrl() {
return which('wmctrl').code === 0;
}
const wm = (() => {
switch (platform) {
case 'win32':
case 'darwin':
return 'default';
case 'linux':
{
if (isRunningI3()) {
return 'i3';
} else if (isRunningWmctrl()) {
return 'wmctrl';
}
return 'unknown';
}
}
return 'unknown';
})();
const dev = process.env.WORKFLOW_DEV_MODE === 'true';
const homedir = process.env.WORKFLOW_HOME;
const devhomedir = process.env.WORKFLOW_DEV_HOME;
const { config } = args(process.argv).named;
let configPath;
let baseFolder;
(() => {
if (dev) {
if (devhomedir) {
baseFolder = devhomedir;
configPath = path.join(devhomedir, 'config.js');
} else {
baseFolder = path.join(__dirname, '..', '..', 'workflow-template', 'config.js');
configPath = path.join(baseFolder, 'config.js');
}
} else {
if (config) {
baseFolder = path.dirname(config);
configPath = config;
} else if (homedir) {
baseFolder = homedir;
configPath = path.join(baseFolder, 'config.js');
} else {
configPath = path.join(os.homedir(), '.workflow', 'config.js');
baseFolder = `${os.homedir()}/.workflow`;
}
}
})();
/* eslint-env node */
const { config: config$1 } = require(path.resolve(configPath));
const workflow = new WorkflowCore.workflow(config$1);
async function resolveFlow(path$$1) {
const absolutePath = await workflow.resolve(path$$1);
const { flow } = await workflow.load(absolutePath);
return flow;
}
async function apply(flow, args) {
flow = await workflow.transform(flow, { args });
const screen = await workflow.screen();
const layout = await workflow.layout(flow, { screen });
await workflow.apply(layout);
}
/* eslint-env node */
async function version({ verbose }) {
const { pkg } = await readPkgUp({ cwd: __dirname });
console.log('workflow:', pkg.version);
if (verbose) {
console.log();
console.log('Config:', configPath);
console.log();
console.log(`Dependencies: `);
await printDependenciesVersion();
}
}
async function printDependenciesVersion() {
const { pkg } = await readPkgUp({ cwd: baseFolder });
for (let [key, value] of Object.entries(pkg.dependencies)) {
console.log(` - ${key}: ${value}`);
}
}
/* eslint-env node */
const promptGetAsync = util.promisify(prompt.get);
async function update(args) {
if (args.force || (await noUncommitChanges(baseFolder))) {
if (args.force) {
console.log('Ignoring uncommited changes with `--force` flag');
}
await updateWorkflowCommand();
await updateWorkflowHome(args);
} else {
console.log('Uncommited changes was found in', baseFolder);
console.log('Either commit the changes or re-run this command with `--force`.');
}
}
async function noUncommitChanges(folder) {
if (which('git').code === 1) {
console.log('`git` command was not found. Disabling uncommited changes check.');
return true;
}
if (!fs.existsSync(path.join(folder, '.git'))) {
console.log(`Could not find a git repo in ${folder}. Disabling uncommited changes check.`);
return true;
}
try {
await execa('git', ['rev-parse', '--is-inside-work-tree']);
} catch (e) {
if (e.code !== 128) {
console.error(e);
process.exit(1);
} else {
return false;
}
}
try {
await execa('git', ['diff-index', '--quiet', 'HEAD', '--'], { cwd: folder });
return true;
} catch (e) {
if (e.code === 1) {
return false;
} else {
console.error(e);
process.exit(1);
}
}
return false;
}
async function updateWorkflowCommand() {
try {
const { stdout: version } = await execa('workflow', ['--version']);
const { stdout: latest } = await execa('npm', ['show', 'workflow', 'version']);
if (version.toString() !== latest.toString()) {
await execa('npm', ['install', '--global', 'workflow'], { stdio: 'inherit' });
} else {
console.log('workflow is up to date at', version.trim());
}
} catch (e) {
console.error(e);
process.exit(1);
}
}
async function updateWorkflowHome(args) {
try {
await execa('npm', ['outdated'], { cwd: baseFolder, stdio: 'inherit' });
console.log('workflow home is up to date');
return;
} catch (e) {
if (e.code !== 1) {
throw e;
}
}
if (!args.force) {
prompt.message = '';
prompt.start();
const { update } = await promptGetAsync({
properties: {
update: {
type: 'string',
pattern: '^[ynYN]$',
description: 'Are you sure? (Y/n)',
default: 'y'
}
}
});
if (update === 'n' || update === 'N') {
console.log();
console.log('Exit without making changes to', baseFolder);
process.exit(0);
}
}
let stdout;
try {
await execa('npm', ['outdated'], { cwd: baseFolder });
} catch (e) {
stdout = e.stdout;
}
const updatedPackages = parsePackages(stdout);
try {
for (let pkg of updatedPackages) {
if (args.latest) {
await execa('npm', ['install', `${pkg}@latest`], { cwd: baseFolder, stdio: 'inherit' });
} else {
await execa('npm', ['update', pkg], { cwd: baseFolder, stdio: 'inherit' });
}
}
} catch (e) {
console.error(e);
process.exit(1);
}
try {
await execa('npm', ['install'], { cwd: baseFolder, stdio: 'inherit' });
} catch (e) {
console.error(e);
process.exit(1);
}
}
function parsePackages(outdatedOutput) {
const packages = [];
const lines = outdatedOutput.split('\n');
for (let line of lines) {
if (!line.startsWith('Package')) {
if (line.split(' ')[0]) {
packages.push(line.split(' ')[0]);
}
}
}
return packages;
}
/* eslint-env node */
const [command, path$1] = args(process.argv).positional;
const commands = ['update', 'version', 'help', 'apply'];
const isApplyWithFlow = (command, path$$1) => command === 'apply' && path$$1;
const isImplicitApplyWithFlow = command => !!command && !commands.includes(command);
(async function exec() {
let flow;
try {
if (isApplyWithFlow(command, path$1)) {
flow = await resolveFlow(path$1);
} else if (isImplicitApplyWithFlow(command)) {
flow = await resolveFlow(command);
}
} catch (e) {
console.error(e);
process.exit(1);
}
yargs.scriptName('workflow').usage('$0 [<cmd>]').command('version', 'Show the version', () => {}, version).command('update', 'Update workflow and workflow-home dependencies', yargs$$1 => yargs$$1.option('latest', {
type: 'boolean',
description: 'Updates dependencies in workflow-home to @latest'
}).option('force', {
type: 'boolean',
description: 'Ignore uncommited check when updating workflow-home'
}), update).command(['apply <flow>' + positionalArguments(flow), '* <flow>' + positionalArguments(flow)], 'apply the flow', yargs$$1 => buildFlowArgs(yargs$$1, flow), async args$$1 => apply(flow, args$$1)).option('config', {
alias: 'c',
type: 'string',
description: 'Set the workflow-home by path to config.js'
}).option('verbose', {
alias: 'vv',
type: 'boolean',
description: 'Set output mode to verbose'
}).help().parse();
})().catch(err => console.error(err));
function positionalArguments(flow) {
let args$$1 = '';
if (flow) {
if (typeof flow.args === 'string') {
args$$1 += ' <' + flow.args + '>';
} else if (Array.isArray(flow.args)) {
for (let arg of flow.args) {
args$$1 += ' <' + arg + '>';
}
}
}
return args$$1;
}
function buildFlowArgs(yargs$$1, flow) {
yargs$$1.positional('flow', {
type: 'string',
describe: 'the flow file to load'
});
yargs$$1.require('flow');
if (!flow) {
return;
}
if (typeof flow.args === 'string') {
yargs$$1.positional(flow.args, {
type: 'string',
describe: flow.args
});
yargs$$1.require(flow.args);
} else if (Array.isArray(flow.args)) {
for (let arg of flow.args) {
yargs$$1.positional(arg, { type: 'string', describe: arg });
yargs$$1.require(arg);
}
} else if (flow.args !== null && typeof flow.args === 'object') {
for (let [key, value] of Object.entries(flow.args)) {
yargs$$1.option(key, { description: value });
yargs$$1.demandOption(key);
}
} else if (flow.args) {
console.error('Misconfigured flow, unknown args property: ' + JSON.stringify(flow));
process.exit(1);
}
}