/ src / main-process / parse-command-line.js
parse-command-line.js
  1  'use strict';
  2  
  3  const dedent = require('dedent');
  4  const yargs = require('yargs');
  5  const { app } = require('electron');
  6  
  7  module.exports = function parseCommandLine(processArgs) {
  8    const options = yargs(processArgs).wrap(yargs.terminalWidth());
  9    const version = app.getVersion();
 10    options.usage(
 11      dedent`Atom Editor v${version}
 12  
 13      Usage:
 14        atom
 15        atom [options] [path ...]
 16        atom file[:line[:column]]
 17  
 18      One or more paths to files or folders may be specified. If there is an
 19      existing Atom window that contains all of the given folders, the paths
 20      will be opened in that window. Otherwise, they will be opened in a new
 21      window.
 22  
 23      A file may be opened at the desired line (and optionally column) by
 24      appending the numbers right after the file name, e.g. \`atom file:5:8\`.
 25  
 26      Paths that start with \`atom://\` will be interpreted as URLs.
 27  
 28      Environment Variables:
 29  
 30        ATOM_DEV_RESOURCE_PATH  The path from which Atom loads source code in dev mode.
 31                                Defaults to \`~/github/atom\`.
 32  
 33        ATOM_HOME               The root path for all configuration files and folders.
 34                                Defaults to \`~/.atom\`.`
 35    );
 36    // Deprecated 1.0 API preview flag
 37    options
 38      .alias('1', 'one')
 39      .boolean('1')
 40      .describe('1', 'This option is no longer supported.');
 41    options
 42      .boolean('include-deprecated-apis')
 43      .describe(
 44        'include-deprecated-apis',
 45        'This option is not currently supported.'
 46      );
 47    options
 48      .alias('d', 'dev')
 49      .boolean('d')
 50      .describe('d', 'Run in development mode.');
 51    options
 52      .alias('f', 'foreground')
 53      .boolean('f')
 54      .describe('f', 'Keep the main process in the foreground.');
 55    options
 56      .alias('h', 'help')
 57      .boolean('h')
 58      .describe('h', 'Print this usage message.');
 59    options
 60      .alias('l', 'log-file')
 61      .string('l')
 62      .describe('l', 'Log all output to file.');
 63    options
 64      .alias('n', 'new-window')
 65      .boolean('n')
 66      .describe('n', 'Open a new window.');
 67    options
 68      .boolean('profile-startup')
 69      .describe(
 70        'profile-startup',
 71        'Create a profile of the startup execution time.'
 72      );
 73    options
 74      .alias('r', 'resource-path')
 75      .string('r')
 76      .describe(
 77        'r',
 78        'Set the path to the Atom source directory and enable dev-mode.'
 79      );
 80    options
 81      .boolean('safe')
 82      .describe(
 83        'safe',
 84        'Do not load packages from ~/.atom/packages or ~/.atom/dev/packages.'
 85      );
 86    options
 87      .boolean('benchmark')
 88      .describe(
 89        'benchmark',
 90        'Open a new window that runs the specified benchmarks.'
 91      );
 92    options
 93      .boolean('benchmark-test')
 94      .describe(
 95        'benchmark-test',
 96        'Run a faster version of the benchmarks in headless mode.'
 97      );
 98    options
 99      .alias('t', 'test')
100      .boolean('t')
101      .describe(
102        't',
103        'Run the specified specs and exit with error code on failures.'
104      );
105    options
106      .alias('m', 'main-process')
107      .boolean('m')
108      .describe('m', 'Run the specified specs in the main process.');
109    options
110      .string('timeout')
111      .describe(
112        'timeout',
113        'When in test mode, waits until the specified time (in minutes) and kills the process (exit code: 130).'
114      );
115    options
116      .alias('v', 'version')
117      .boolean('v')
118      .describe('v', 'Print the version information.');
119    options
120      .alias('w', 'wait')
121      .boolean('w')
122      .describe('w', 'Wait for window to be closed before returning.');
123    options
124      .alias('a', 'add')
125      .boolean('a')
126      .describe('add', 'Open path as a new project in last used window.');
127    options.string('user-data-dir');
128    options
129      .boolean('clear-window-state')
130      .describe('clear-window-state', 'Delete all Atom environment state.');
131    options
132      .boolean('enable-electron-logging')
133      .describe(
134        'enable-electron-logging',
135        'Enable low-level logging messages from Electron.'
136      );
137    options.boolean('uri-handler');
138  
139    let args = options.argv;
140  
141    // If --uri-handler is set, then we parse NOTHING else
142    if (args.uriHandler) {
143      args = {
144        uriHandler: true,
145        'uri-handler': true,
146        _: args._.filter(str => str.startsWith('atom://')).slice(0, 1)
147      };
148    }
149  
150    if (args.help) {
151      process.stdout.write(options.help());
152      process.exit(0);
153    }
154  
155    if (args.version) {
156      process.stdout.write(
157        `Atom    : ${app.getVersion()}\n` +
158          `Electron: ${process.versions.electron}\n` +
159          `Chrome  : ${process.versions.chrome}\n` +
160          `Node    : ${process.versions.node}\n`
161      );
162      process.exit(0);
163    }
164  
165    const addToLastWindow = args['add'];
166    const safeMode = args['safe'];
167    const benchmark = args['benchmark'];
168    const benchmarkTest = args['benchmark-test'];
169    const test = args['test'];
170    const mainProcess = args['main-process'];
171    const timeout = args['timeout'];
172    const newWindow = args['new-window'];
173    let executedFrom = null;
174    if (args['executed-from'] && args['executed-from'].toString()) {
175      executedFrom = args['executed-from'].toString();
176    } else {
177      executedFrom = process.cwd();
178    }
179  
180    if (newWindow && addToLastWindow) {
181      process.stderr.write(
182        `Only one of the --add and --new-window options may be specified at the same time.\n\n${options.help()}`
183      );
184  
185      // Exiting the main process with a nonzero exit code on MacOS causes the app open to fail with the mysterious
186      // message "LSOpenURLsWithRole() failed for the application /Applications/Atom Dev.app with error -10810."
187      process.exit(0);
188    }
189  
190    let pidToKillWhenClosed = null;
191    if (args['wait']) {
192      pidToKillWhenClosed = args['pid'];
193    }
194  
195    const logFile = args['log-file'];
196    const userDataDir = args['user-data-dir'];
197    const profileStartup = args['profile-startup'];
198    const clearWindowState = args['clear-window-state'];
199    let pathsToOpen = [];
200    let urlsToOpen = [];
201    let devMode = args['dev'];
202  
203    for (const path of args._) {
204      if (path.startsWith('atom://')) {
205        urlsToOpen.push(path);
206      } else {
207        pathsToOpen.push(path);
208      }
209    }
210  
211    if (args.resourcePath || test) {
212      devMode = true;
213    }
214  
215    if (args['path-environment']) {
216      // On Yosemite the $PATH is not inherited by the "open" command, so we have to
217      // explicitly pass it by command line, see http://git.io/YC8_Ew.
218      process.env.PATH = args['path-environment'];
219    }
220  
221    return {
222      pathsToOpen,
223      urlsToOpen,
224      executedFrom,
225      test,
226      version,
227      pidToKillWhenClosed,
228      devMode,
229      safeMode,
230      newWindow,
231      logFile,
232      userDataDir,
233      profileStartup,
234      timeout,
235      clearWindowState,
236      addToLastWindow,
237      mainProcess,
238      benchmark,
239      benchmarkTest,
240      env: process.env
241    };
242  };