Skip to content

Commit

Permalink
Rework executeableFIle support
Browse files Browse the repository at this point in the history
- add to README
- rename option
- include support for executableFile for alias and default command
- consistent use of node to launch javascript files
  • Loading branch information
shadowspawn committed Jul 20, 2019
1 parent 2c4d743 commit 6d5e11a
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 33 deletions.
3 changes: 3 additions & 0 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,7 @@ Configuration options can be passed with the call to `.command()`. Specifying `t
When `.command()` is invoked with a description argument, this tells commander that you're going to use separate executables for sub-commands, much like `git(1)` and other popular tools.
Commander will search the executables in the directory of the entry script (like `./examples/pm`) with the name `program-subcommand`, like `pm-install`, `pm-search`.
You can specify a custom name with the `executableFile` configuration option.
You handle the options for an executable (sub)command in the executable, and don't declare them at the top-level.
Expand All @@ -341,11 +342,13 @@ program
.version('0.1.0')
.command('install [name]', 'install one or more packages')
.command('search [query]', 'search with optional query')
.command('update', 'update installed packages', {executableFile: 'myUpdateSubCommand'})
.command('list', 'list packages installed', {isDefault: true})
.parse(process.argv);
```
Configuration options can be passed with the call to `.command()`. Specifying `true` for `opts.noHelp` will remove the command from the generated help output. Specifying `true` for `opts.isDefault` will run the subcommand if no other subcommand is specified.
Specifying a name with `executableFile` will override the default constructed name.
If the program is designed to be installed globally, make sure the executables have proper modes, like `755`.
Expand Down
67 changes: 37 additions & 30 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ Command.prototype.command = function(nameAndArgs, actionOptsOrExecDesc, execOpts
cmd._helpDescription = this._helpDescription;
cmd._helpShortFlag = this._helpShortFlag;
cmd._helpLongFlag = this._helpLongFlag;
cmd._specifySubcommand = opts.subcommand;
cmd._executableFile = opts.executableFile; // Custom name for executable file
this.commands.push(cmd);
cmd.parseExpectedArgs(args);
cmd.parent = this;
Expand Down Expand Up @@ -460,34 +460,37 @@ Command.prototype.parse = function(argv) {

// executable sub-commands
var name = result.args[0];
var subCommand = null;

var aliasCommand = null;
// check alias of sub commands
// Look for subcommand
if (name) {
aliasCommand = this.commands.filter(function(command) {
subCommand = this.commands.find(function(command) {
return command._name === name;
});
}

// Look for alias
if (!subCommand && name) {
subCommand = this.commands.find(function(command) {
return command.alias() === name;
})[0];
});
if (subCommand) {
name = subCommand._name;
args[0] = name;
}
}

var specifySubcommand = null;
if (name) {
specifySubcommand = this.commands.filter(function(command) {
return command._name === name && command._specifySubcommand != null;
})[0];
// Look for default subcommand
if (!subCommand && this.defaultExecutable) {
name = this.defaultExecutable;
args.unshift(name);
subCommand = this.commands.find(function(command) {
return command._name === name;
});
}

if (specifySubcommand) {
return this.executeSubCommand(argv, args, parsed.unknown, specifySubcommand._specifySubcommand);
} else if (this._execs[name] && typeof this._execs[name] !== 'function') {
return this.executeSubCommand(argv, args, parsed.unknown);
} else if (aliasCommand) {
// is alias of a subCommand
args[0] = aliasCommand._name;
return this.executeSubCommand(argv, args, parsed.unknown);
} else if (this.defaultExecutable) {
// use the default subcommand
args.unshift(this.defaultExecutable);
return this.executeSubCommand(argv, args, parsed.unknown);
if (this._execs[name] && typeof this._execs[name] !== 'function') {
return this.executeSubCommand(argv, args, parsed.unknown, subCommand ? subCommand._executableFile : undefined);
}

return result;
Expand All @@ -503,7 +506,7 @@ Command.prototype.parse = function(argv) {
* @api private
*/

Command.prototype.executeSubCommand = function(argv, args, unknown, specifySubcommand) {
Command.prototype.executeSubCommand = function(argv, args, unknown, executableFile) {
args = args.concat(unknown);

if (!args.length) this.help();
Expand All @@ -515,27 +518,31 @@ Command.prototype.executeSubCommand = function(argv, args, unknown, specifySubco
args[1] = this._helpLongFlag;
}

var isExplicitJS = false; // Whether to use node to launch "executable"

// executable
var f = argv[1];
// name of the subcommand, link `pm-install`
var bin = basename(f, path.extname(f)) + '-' + args[0];
if (specifySubcommand != null) {
bin = specifySubcommand;
var pm = argv[1];
// name of the subcommand, like `pm-install`
var bin = basename(pm, path.extname(pm)) + '-' + args[0];
if (executableFile != null) {
bin = executableFile;
// Check for same extensions as we scan for below so get consistent launch behaviour.
var executableExt = path.extname(executableFile);
isExplicitJS = executableExt === '.js' || executableExt === '.ts' || executableExt === '.mjs';
}

// In case of globally installed, get the base dir where executable
// subcommand file should be located at
var baseDir;

var resolvedLink = fs.realpathSync(f);
var resolvedLink = fs.realpathSync(pm);

baseDir = dirname(resolvedLink);

// prefer local `./<bin>` to bin in the $PATH
var localBin = path.join(baseDir, bin);

// whether bin file is a js script with explicit `.js` or `.ts` extension
var isExplicitJS = false;
if (exists(localBin + '.js')) {
bin = localBin + '.js';
isExplicitJS = true;
Expand Down
6 changes: 3 additions & 3 deletions test/fixtures/pm
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ program
.command('list', 'list packages installed')
.command('listen', 'listen for supported signal events').alias('l')
.command('publish', 'publish or update package').alias('p')
.command('default', 'default command', {noHelp: true, isDefault: true})
.command('specifyInstall', 'specify install subcommand', {subcommand: 'pm-install'})
.command('specifyPublish', 'specify publish subcommand', {subcommand: 'pm-publish'})
.command('default', 'default command', { noHelp: true, isDefault: true })
.command('specifyInstall', 'specify install subcommand', { executableFile: 'pm-install' })
.command('specifyPublish', 'specify publish subcommand', { executableFile: 'pm-publish' })
.parse(process.argv);

0 comments on commit 6d5e11a

Please sign in to comment.