Get multiple command option using commander - node.js

I'm creating a CLI using Nodejs and commander and i need to implement an option/command like this.
--create user --f-name="Kevin"
I tried various options but could get it working
#!/usr/bin/env node
const program = require("commander");
function collect(val, memo) {
memo.push(val);
return memo;
}
program.version("0.0.1", "-v, --version")
.option(
"-c, --create <items>",
"Create user",
collect,
[]
).parse(process.argv);
console.log(' collect: %j', program.create );
This works only when i execute with like this --create user,a,d,v and it gives out an array collect: ["user,a,d,v"]. Any idea on how to implement this using Commander.js

Try this script:
program
.option('-c, --create', 'Create User')
.option('-un, --user-name <type>', 'Username');
program.parse(process.argv);
console.log(program.userName, `userName: ${program.userName}`)
And execute like this from the terminal:
node command.js --create user --user-name=NameUser

Related

Commander.js - Implementing sub commands that executes when the previous one is finished

I'm using Commander.js to write my own CLI. I managed to write commands that work individually but now I need to implement sub commands but the docs are a bit vague and confusing so I haven't been able to figure out.
What I want is the connect command to connect to a MongoDB instance and when it has done that proceed to execute the get command. How can I achieve this?
These are the commands and package.json:
./package.json:
{
...
"main": "./commands/my-cli.js",
"bin": "./commands/my-cli.js",
...
}
./commands/my-cli.js:
const commander = require('commander');
const program = new commander.Command();
const connect = require('./my-cli-connect');
const get = require('./my-cli-get');
// Initialize each command
connect(program);
get(program);
./commands/my-cli-connect.js:
function connect(program) {
program
.command('connect <db> <username> <password>', 'Connects to a database')
.action((db, username, password) => {
MongoClient.connect(<some-mongo-url>, {useNewUrlParser: true}, (err, connection) => {
assert.equal(null, err, 'Failed to connect to MongoDB instance');
// Continue here with the get command
});
});
program.parse(process.argv);
}
module.exports = connect;
./commands/my-cli-get.js:
function get(program) {
program
.command('get <collection>')
.option('-q,--query <query>', 'Search terms', jsonParser, {})
.description('Returns documents from a MongoDB collection')
.action(action);
program.parse(process.argv);
function action(collection, options) {
// This never runs
console.log('hello world');
}
}
module.exports = get;
Running my-cli --help shows these available commands:
...
Commands:
connect <db> <username> <password> Connects to a database
help [cmd] display help for [cmd]
Example command execution that should call both connect and then get when connect has finished connecting:
$ my-cli connect myDb myUser myPass get users -q '{"email": "foo#gmail.com"}'
Right now the get command's action function never runs.

Node.js - exec shell commands with .bashrc initialized

I'm writing a small utility tool for development to sync files over ssh. Normally I use ssh-agent set up in .bashrc file to connect to my dev server easily. I'd like to use exec in the script, but calling ssh-agent, every time I make a request sounds a bit inoptimal.
Is there a way I could execute the agent code once, and then have it working for all subsequent ssh requests I make? E.g. to spawn a shell process like a terminal emulator, and then use that process to execute a command, rather than invoking a new shell with each command.
The reason I want to do this, is I don't want to store the password in a config file.
You can create one ssh process, and then execute other commands using same process. Here is an example how to use it for bash. I'm creating a new bash shell and execugte the command ls -la and exit you can execute other commands.
const cp = require("child_process")
class MyShell {
constructor(command) {
this._spawned = cp.spawn(command, {
stdio: ["pipe", "pipe", "inherit"],
})
}
execute(command, callback) {
this._spawned.stdin.write(command + "\n")
this._spawned.stdout.on("data", (chunk) => {
if (callback) {
callback(chunk.toString())
}
})
}
}
var myShell = new MyShell("bash")
myShell.execute("ls -la", (result) => {
console.log(result)
})
myShell.execute("exit")

Mongodb Shell command execution to drop collection via nodejs

I have a test setup in which mongoimport and mongoexportcommands are used to populate an exiting mongoDB database, say testDB from folder testDump.
The problem occurs for the files which are empty in the folder from which testDB is initially populated and then restored.
Eg. a collection file called abcInstance.json is empty in the testDump.
$ cat abcInstance.json
[]
Now when I run some test, this collection gets populated in testDB but at the end when I restore all collections from the testDump folder using mongoimport command it fails for empty files.
So, I am trying to drop those collections using mongo and spawn command.
if (statSync(collectionFile).size === 4) {
const options = [
'testDB',
'--eval',
'"db.abcInstance.drop()"'
];
const dropDB = spawn('mongo', options, { stdio: 'inherit' });
if (dropDB.status !== 0) {
throw new Error('failed to drop collection ');
}}
But this is also failing and I cannot figure out the error.
I have tested that the same command runs successfully on command line:
$ mongo testDB --eval "db.abcInstance.drop()"
MongoDB shell version v3.6.4
connecting to: mongodb://127.0.0.1:27017/alyneKickStartDB
MongoDB server version: 3.6.4
true
Any idea where I am going wrong?
So, I was able to solve the problem of executing the mongo command by a slightly different approach as stated here.
Basically, the problem I figured out was that my parent process was exiting without waiting for the child process to finish execution as both spawn and exec are asynchronous functions. So I modified my code as follows:
const { promisify } = require('util');
const exec = promisify(require('child_process').exec)
async func test () {
const res = await exec('mongo testDB --eval "db.abcInstance.drop()" --quiet')
return { res }
}
Now, when I call this test() function, my collection is successfully dropped.
Does anybody know of any problem with this approach or a better way?

Commander throws error for command with description

Here is a simple example of adding command in nodejs using commander:
'use strict';
const {Command} = require('commander');
const run = () => {
const program = new Command();
console.log('CMD');
program.command('cmd [opts...]')
.action((opts) => {
console.log('OPTS');
});
program.parse(process.argv);
};
run();
In this case everything works fine, but when I'm adding description and options, commander throws an error:
program.command('cmd [opts...]', 'DESCRIPTION', {isDefault: true})
node test-commander.js cmd opts
test-commander-cmd(1) does not exist, try --help
My env:
node v8.9.3
npm 5.3.0
commander 2.12.2
That is the declared behavior of commander. From the npm page under Git-style sub-commands...
When .command() is invoked with a description argument, no .action(callback) should be called to handle sub-commands, otherwise there will be an error. This tells commander that you're going to use separate executables for sub-commands, much like git(1) and other popular tools.
The commander will try to search the executables in the directory of the entry script (like ./examples/pm) with the name program-command, like pm-install, pm-search.
So, when you add a description like you have, it'll assume you have another executable file called test-commander-cmd for the sub command.
If commander's behavior is not what you were expecting, I might recommend looking into a package I published, called wily-cli... only if you're not committed to commander, of course ;)
Assuming your code rests in file.js, your example with wily-cli would look like this...
const cli = require('wily-cli');
const run = () => {
cli
.command('cmd [opts...]', 'DESCRIPTION', (options, parameters) => { console.log(parameters.opts); })
.defaultCommand('cmd');
};
run();
// "node file.js option1 option2" will output "[ 'option1', 'option2' ]"

Accessing google play store data using GSUTIL on nodejs

I am trying to access data from google play store using GSUTIL in nodejs.
when I run the following command on my command line, I am able to get the files:
gsutil cp -r gs://mybucket /mylocalmachine
How do I run this command on my node server to get the same result? The below code doesnot yield any result
var exec = require('child_process').exec;
function copyUsingGSUTIL() {
return new Promise(function (resolve, reject) {
var child = exec("gsutil cp -r", ["gs://mybucket", "mylocalmachine"],{cwd:"/Applications/gsutil"});
console.log(child)
child.on('close', function (code) {
console.log('Exit code' + code);
});
});
}
gsutil is a python program so you have to invoke python and use the full paths in the exec command like
String command = "python c:/gsutil/gsutil.py cp -r gs://mybucket/mylocalmachine" + "C:/your absolute path here/Applications/gsutil";
...
...
var child = exec(command);
console.log(child);
...
...
There is also a java alternative for gsutil see this https://developers.google.com/api-client-library/java/apis/storage/v1
See also this thread Google cloud storage gsutil tool with Java

Resources