How to structure one of many commands in yargs? - yargs

I have read the yargs documetation multiple times, but can't figure out this one. Here are my requirements:
My CLI should provide two commands: cmd1 and cmd2.
The user must specify one of these two commands, otherwise the CLI must print a help message and exit.
This is my attempt:
async function main() {
await yargs(process.argv.slice(2))
.command('cmd1', 'Command 1', {}, () => console.log('Executing command1'))
.command('cmd2', 'Command 2', {}, () => console.log('Executing command2'))
.help().argv;
}
Following commands work as expected:
my-cli cmd1 # prints "Executing command1"
my-cli cmd2 # prints "Executing command2"
However following commands quit silently:
my-cli
my-cli cmd3
What am I missing?

According to the documentation and the refine of OP, the correct yarg code handling undefined arguments is as follow:
async function main() {
await yargs(process.argv.slice(2))
.command('cmd1', 'Command 1', {}, () => console.log('Executing command1'))
.command('cmd2', 'Command 2', {}, () => console.log('Executing command2'))
.strictCommands()
.demandCommand()
.help().argv;
}
strictCommands(): accepts only defined commands (i.e. does not accept undefined command like cmd3) Documentation
demandCommand(): accepts minimum 1 argument (i.e. does not accept a command with no argument); 1 is the default value of minimum; can also add max option to constraint to exactly 1 argument by demandCommand(1, 1) Documentation

Related

Unreachable command line option in MAIN

zef search includes :$update as a named argument:
multi MAIN('search', Int :$wrap = False, :$update, *#terms ($, *#))
However, it's not recognized as such:
% zef search --update
Usage:
/home/jmerelo/.rakudobrew/bin/../moar-2019.03.1/install/share/perl6/site/bin/zef [--wrap=<Int>] search [<terms> ...] -- Get a list of possible distribution candidates for the given terms
/home/jmerelo/.rakudobrew/bin/../moar-2019.03.1/install/share/perl6/site/bin/zef [--version] -- Detailed version information
/home/jmerelo/.rakudobrew/bin/../moar-2019.03.1/install/share/perl6/site/bin/zef [-h|--help]
What am I missing here? How could I assign a value to this $update?
If I run this MAIN candidate by itself, it works:
$ perl6 -e 'multi MAIN("search", Int :$wrap = False, :$update, *#terms ($, *#)) { say "foo" }' search --update
foo
so it looks to me there is more than one candidate that matches, and that causes the USAGE feedback message to appear.
Named parameters are used as tie-breakers only, unless they are made mandatory (which makes them effectively a part of the dispatch process). So maybe the fix is to make two candidates:
multi MAIN('search', Int :$wrap = False, :$update!, *#terms ($, *#)) { ... }
multi MAIN('search', Int :$wrap = False, *#terms ($, *#)) { ... }
?

how to use choice parameter in Jenkins pipeline in batch command

how to use choice parameter in Jenkins declarative pipeline in batch command.
I'm using following stage:
choice(
choices: 'apply\ndestroy\n',
description: '',
name: 'DESTROY_OR_APPLY')
stage ('temp') {
steps {
echo "type ${params.DESTROY_OR_APPLY}"
bat'echo "type01 ${params.DESTROY_OR_APPLY}"'
bat'echo "type01 %{params.DESTROY_OR_APPLY}%"'
bat'echo type01 [${params.DESTROY_OR_APPLY}]'
}
echo does resolve to correct parameter value but under bat none of the above code works.
You almost got the syntax right.
If you change it to one of the below options, the bat command receives the value of your choice.
steps {
bat "echo type01 ${DESTROY_OR_APPLY}"
}
or
steps {
bat 'echo type01 ' + DESTROY_OR_APPLY
}
You can also use ${params.DESTROY_OR_APPLY} in the first or params.DESTROY_OR_APPLY in the second example if you want to use the params definition consequently in your code.

yargs .command error: second argument to option must be an object

Suppose I have a file "test.js":
var args = require('yargs')
.command('command', 'command usage here', {alias: "c"} )
.argv;
Then I run:
>node test command
I got this error:
second argument to option must be an object
If I remove the 3rd parameter of .command:
var args = require('yargs')
.command('command', 'command usage here')
.argv;
Everything is fine.
I must make a dumb mistake. But I just cannot figure it out.
Thanks
Your 3rd argument is not required, that's why it works when you remove it. I'm pretty sure the 3rd argument has to be a function call.
var args = require('yargs')
.command('command',
'command explanation',
function(yargs){
//insert yargs.options here
yargs.options({
c:{
demand: true,//if you require the command
alias: 'c',// you will enter -c to use it
description: 'explain what it does'
}
});
})
.argv;
an example of usage might be:
C:\WorkingDirectory>node app.js command -c run
your code could include console.log(args.c);//prints out run

How to read standard input from a Bash heredoc within a Groovy script

I'm trying to make a Groovy script read standard input, so I can call it from a Bash script with a heredoc, but I get a java.lang.NullPointerException: Cannot invoke method readLine() on null object exception.
Here's a cut-down Groovy script echo.groovy:
#!/usr/bin/env groovy
for (;;)
{
String line = System.console().readLine()
if (line == null)
break
println(">>> $line")
}
Here's the equivalent Ruby script echo.rb:
#!/usr/bin/env ruby
ARGF.each do |line|
puts ">>> #{line}"
end
If I call these from a Bash shell, everything works as expected:
$ ./echo.rb
one
>>> one
two
>>> two
three
>>> three
^C
$ ./echo.groovy
one
>>> one
two
>>> two
three
>>> three
^C
This is the Bash script heredoc.sh using heredocs:
echo 'Calling echo.rb'
./echo.rb <<EOF
one
two
three
EOF
echo 'Calling echo.groovy'
./echo.groovy <<EOF
one
two
three
EOF
This is what happens when I run it:
$ ./heredoc.sh
Calling echo.rb
>>> one
>>> two
>>> three
Calling echo.groovy
Caught: java.lang.NullPointerException: Cannot invoke method readLine() on null object
java.lang.NullPointerException: Cannot invoke method readLine() on null object
at echo.run(echo.groovy:4)
Any ideas?
UPDATE
On Etan's advice, I changed echo.groovy to the following:
#!/usr/bin/env groovy
Reader reader = new BufferedReader(new InputStreamReader(System.in))
for (;;)
{
String line = reader.readLine()
if (line == null)
break
println(">>> $line")
}
It now works with heredocs:
$ ./heredoc.sh
Calling echo.rb
>>> one
>>> two
>>> three
Calling echo.groovy
>>> one
>>> two
>>> three
Thanks Etan. If you'd like to post a formal answer, I'll upvote it.
As an alternative to Etan's answer, a Groovier approach is the withReader method, which handles the cleanup of the reader afterwards, and the BufferedReader's eachLine method, which handles the infinite looping.
#!/usr/bin/env groovy
System.in.withReader { console ->
console.eachLine { line ->
println ">>> $line"
}
}
As Etan says, you need to read from System.in I think this will get the response you are after
#!/usr/bin/env groovy
System.in.withReader { r ->
r.eachLine { line ->
println ">>> $line"
}
}
Thought it's not exactly the same as the Ruby version, as ARGF will return arguments if any were passed

How can I run a sub function in Bash

How can I run a 'sub function' from a script in command line? Example:
#script_1.sh
main_function() {
sub_function() {
echo "hello world"
}
}
I tried to source this file and call the function from another script:
#script_2.sh
source script_1.sh
sub_function
But I get
script_2.sh: line 3: sub_function: command not found
while I expected to just get hello world.
Thus defined the sub_function will be defined after function is called.
So:
#script_1.sh
function() {
sub_function() {
#cmd
}
}
#script_2.sh
source script_1.sh
function
sub_function
... should work ... except you should rename function, as it's a reserved word
The step missing in your question is to invoke function first - its action is to define sub_function.
Note that sub_function doesn't 'belong' to function in any way - its definition is just a side-effect of running function.
P.S. I assume you aren't really trying to call it function - that's a reserved word in bash.

Resources