How to implement countable flags? Ref. -vvv for "triple verbosity"
I'm not sure whether or not what I describe is part of the GNU getopt standard.
But ssh is a good example for what I'm trying to do.
Anyone using Github can perform the following (as long as they've set-up SSH keys):
-> $ ssh -T [email protected]
Hi x10an14! You've successfully authenticated, but GitHub does not provide shell access.
And....
Long SSH example output
-> $ ssh -Tvv [email protected]
OpenSSH_7.6p1 Ubuntu-4ubuntu0.3, OpenSSL 1.0.2n 7 Dec 2017
debug1: Reading configuration data /home/x10an14/.ssh/config
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: /etc/ssh/ssh_config line 19: Applying options for *
debug2: resolving "github.com" port 22
debug2: ssh_connect_direct: needpriv 0
debug1: Connecting to github.com [140.82.118.4] port 22.
debug1: Connection established.
debug1: identity file /home/x10an14/.ssh/id_rsa type 0
debug1: key_load_public: No such file or directory
debug1: identity file /home/x10an14/.ssh/id_rsa-cert type -1
debug1: key_load_public: No such file or directory
debug1: identity file /home/x10an14/.ssh/id_dsa type -1
debug1: key_load_public: No such file or directory
debug1: identity file /home/x10an14/.ssh/id_dsa-cert type -1
debug1: key_load_public: No such file or directory
debug1: identity file /home/x10an14/.ssh/id_ecdsa type -1
debug1: key_load_public: No such file or directory
debug1: identity file /home/x10an14/.ssh/id_ecdsa-cert type -1
debug1: key_load_public: No such file or directory
debug1: identity file /home/x10an14/.ssh/id_ed25519 type -1
debug1: key_load_public: No such file or directory
debug1: identity file /home/x10an14/.ssh/id_ed25519-cert type -1
debug1: Local version string SSH-2.0-OpenSSH_7.6p1 Ubuntu-4ubuntu0.3
debug1: Remote protocol version 2.0, remote software version babeld-003ebee6
debug1: no match: babeld-003ebee6
debug2: fd 3 setting O_NONBLOCK
debug1: Authenticating to github.com:22 as 'git'
debug1: SSH2_MSG_KEXINIT sent
debug1: SSH2_MSG_KEXINIT received
debug2: local client KEXINIT proposal
debug2: KEX algorithms: curve25519-sha256,[email protected],ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha1,diffie-hellman-group14-sha256,diffie-hellman-group14-sha1,ext-info-c
debug2: host key algorithms: [email protected],rsa-sha2-512,rsa-sha2-256,ssh-rsa,[email protected],[email protected],[email protected],[email protected],ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,ssh-ed25519
debug2: ciphers ctos: [email protected],aes128-ctr,aes192-ctr,aes256-ctr,[email protected],[email protected]
debug2: ciphers stoc: [email protected],aes128-ctr,aes192-ctr,aes256-ctr,[email protected],[email protected]
debug2: MACs ctos: [email protected],[email protected],[email protected],[email protected],[email protected],[email protected],[email protected],hmac-sha2-256,hmac-sha2-512,hmac-sha1
debug2: MACs stoc: [email protected],[email protected],[email protected],[email protected],[email protected],[email protected],[email protected],hmac-sha2-256,hmac-sha2-512,hmac-sha1
debug2: compression ctos: none,[email protected],zlib
debug2: compression stoc: none,[email protected],zlib
debug2: languages ctos:
debug2: languages stoc:
debug2: first_kex_follows 0
debug2: reserved 0
debug2: peer server KEXINIT proposal
debug2: KEX algorithms: curve25519-sha256,[email protected],ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256
debug2: host key algorithms: ssh-dss,rsa-sha2-512,rsa-sha2-256,ssh-rsa
debug2: ciphers ctos: [email protected],[email protected],[email protected],aes256-ctr,aes192-ctr,aes128-ctr,aes256-cbc,aes192-cbc,aes128-cbc
debug2: ciphers stoc: [email protected],[email protected],[email protected],aes256-ctr,aes192-ctr,aes128-ctr,aes256-cbc,aes192-cbc,aes128-cbc
debug2: MACs ctos: [email protected],[email protected],[email protected],hmac-sha2-256,hmac-sha2-512,hmac-sha1
debug2: MACs stoc: [email protected],[email protected],[email protected],hmac-sha2-256,hmac-sha2-512,hmac-sha1
debug2: compression ctos: none,zlib,[email protected]
debug2: compression stoc: none,zlib,[email protected]
debug2: languages ctos:
debug2: languages stoc:
debug2: first_kex_follows 0
debug2: reserved 0
debug1: kex: algorithm: curve25519-sha256
debug1: kex: host key algorithm: rsa-sha2-512
debug1: kex: server->client cipher: [email protected] MAC: <implicit> compression: none
debug1: kex: client->server cipher: [email protected] MAC: <implicit> compression: none
debug1: expecting SSH2_MSG_KEX_ECDH_REPLY
debug1: Server host key: ssh-rsa SHA256:nThbg6kXUpJWGl7E1IGOCspRomTxdCARLviKw6E5SY8
debug1: Host 'github.com' is known and matches the RSA host key.
debug1: Found key in /home/x10an14/.ssh/known_hosts:3
debug2: set_newkeys: mode 1
debug1: rekey after 134217728 blocks
debug1: SSH2_MSG_NEWKEYS sent
debug1: expecting SSH2_MSG_NEWKEYS
debug1: SSH2_MSG_NEWKEYS received
debug2: set_newkeys: mode 0
debug1: rekey after 134217728 blocks
debug2: key: /home/x10an14/.ssh/id_rsa (0x562872240bf0), agent
debug2: key: /home/x10an14/.ssh/id_dsa ((nil))
debug2: key: /home/x10an14/.ssh/id_ecdsa ((nil))
debug2: key: /home/x10an14/.ssh/id_ed25519 ((nil))
debug1: SSH2_MSG_EXT_INFO received
debug1: kex_input_ext_info: server-sig-algs=<ssh-ed25519,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,ssh-rsa,rsa-sha2-512,rsa-sha2-256,ssh-dss>
debug2: service_accept: ssh-userauth
debug1: SSH2_MSG_SERVICE_ACCEPT received
debug1: Authentications that can continue: publickey
debug1: Next authentication method: publickey
debug1: Offering public key: RSA SHA256:ll1aqkyno22aTX/zV1FtKkZ/id+7h8vn/uWY1bDWXbo /home/x10an14/.ssh/id_rsa
debug2: we sent a publickey packet, wait for reply
debug1: Server accepts key: pkalg ssh-rsa blen 1047
debug2: input_userauth_pk_ok: fp SHA256:ll1aqkyno22aTX/zV1FtKkZ/id+7h8vn/uWY1bDWXbo
debug1: Authentication succeeded (publickey).
Authenticated to github.com ([140.82.118.4]:22).
debug1: channel 0: new [client-session]
debug2: channel 0: send open
debug1: Entering interactive session.
debug1: pledge: network
debug2: channel_input_open_confirmation: channel 0: callback start
debug2: fd 3 setting TCP_NODELAY
debug2: client_session2_setup: id 0
debug1: Sending environment.
debug1: Sending env LC_MEASUREMENT = nb_NO.UTF-8
debug2: channel 0: request env confirm 0
debug1: Sending env LC_PAPER = nb_NO.UTF-8
debug2: channel 0: request env confirm 0
debug1: Sending env LC_MONETARY = nb_NO.UTF-8
debug2: channel 0: request env confirm 0
debug1: Sending env LANG = en_US.UTF-8
debug2: channel 0: request env confirm 0
debug1: Sending env LC_NAME = nb_NO.UTF-8
debug2: channel 0: request env confirm 0
debug1: Sending env LC_ADDRESS = nb_NO.UTF-8
debug2: channel 0: request env confirm 0
debug1: Sending env LC_NUMERIC = nb_NO.UTF-8
debug2: channel 0: request env confirm 0
debug1: Sending env LC_TELEPHONE = nb_NO.UTF-8
debug2: channel 0: request env confirm 0
debug1: Sending env LC_IDENTIFICATION = nb_NO.UTF-8
debug2: channel 0: request env confirm 0
debug2: channel 0: request shell confirm 1
debug2: channel_input_open_confirmation: channel 0: callback done
debug2: channel 0: open confirm rwindow 32000 rmax 35000
debug2: channel_input_status_confirm: type 99 id 0
debug2: shell request accepted on channel 0
debug2: channel 0: rcvd ext data 89
debug1: client_input_channel_req: channel 0 rtype exit-status reply 0
debug2: channel 0: rcvd eof
debug2: channel 0: output open -> drain
debug2: channel 0: rcvd close
debug2: channel 0: close_read
debug2: channel 0: input open -> closed
debug2: channel 0: obuf_empty delayed efd 7/(89)
Hi x10an14! You've successfully authenticated, but GitHub does not provide shell access.
debug2: channel 0: written 89 to efd 7
debug2: channel 0: obuf empty
debug2: channel 0: close_write
debug2: channel 0: output drain -> closed
debug2: channel 0: almost dead
debug2: channel 0: gc: notify user
debug2: channel 0: gc: user detached
debug2: channel 0: send close
debug2: channel 0: is dead
debug2: channel 0: garbage collecting
debug1: channel 0: free: client-session, nchannels 1
Transferred: sent 5396, received 2996 bytes, in 0.2 seconds
Bytes per second: sent 23560.2, received 13081.3
debug1: Exit status 1
So in short, I can supply -v, -vv, or -vvv to the ssh command, and get increasing levels of verbosity.
I enjoy the opportunity to supply -v (--verbose) and -q (--quiet) flags in CLIs I implement.
Switches can be merged together:
-tv parsed as -t -v
Using the following Option class
class Options
{
[Option('v')]
public string Verbose { get; set; }
}
The commandline:
-vv =parsed to=> -v v =result to=> options.verbose = "v"
-vvv =parsed to=> -v vv =result to=> options.verbose = "vv"
-v raise error `Option 'v' has no value.`
Thanks! =)
Oh wait, I was a bit hasty, sorry!
-v raise error Option 'v' has no value.
Is that a necessity? It's not possible to give the flag -v (and just -v), and therefore set verbosityLevel to 1 as opposed to a default of 0?
Edit: To clarify, I'm under the impression now that what I quoted of your answer is something decided by the framework, not just an implementation detail you suggested.
Verbose is defined as string not bool (so it's a Scalar option not a boolean Switch ) to accept string values as described above. Any scalar option should have a value in the commandline.
it's not possible to give the flag -v (and just -v), and therefore set verbosityLevel to 1 as opposed to a default of 0?
Do you mean: -v1 => -v 1 -v2 => -v 2
in that case Verbose can be integer.
Just to clarify (but I think we understand each other now):
"<nothing" => "verbosity level 0"
"-v" => "verbosity level 1"
"-vv" => "verbosity level 2"
"-vvv" => "verbosity level 3"
That's as easy as;
class Options
{
[Option(
'v',
MetaName = "verbosity")]
public uint Verbosity { get; set; }
}
?
In that case, verbose will be uint : v1 or v2 or v3 and no way to map against -v or -vv or -vvv Just, a trick, if you want to use triple vvv:
enum VerboseEnum
{
v =1,
vv,
vvv
}
class Options
{
[Option(
'v',
MetaName = "verbosity",
Default=VerboseEnum.v)]
public VerboseEnum Verbosity { get; set; }
}
The command can be:
-vv /-vvv /-vvvv
That is Quad verbosity not a triple ;) :)
Edit in case of enum, you can use both int and enum, all are valid:
-v1 or -vv
-v2 or -vvv
-v3 or -vvvv
I'm still not getting it =/
Here's my code;
namespace Slackbot
{
// Std libs
using System;
// External libs
using CommandLine;
public class Program
{
protected enum VerbosityEnum
{
v = 1,
vv = 2,
vvv = 3,
}
public static void Main(string[] args)
{
Console.WriteLine("Hello World!");
Parser.Default.ParseArguments<Options>(args)
.WithParsed<Options>( options =>
{
Console.WriteLine(
$"Current Arguments: -v {options.Verbosity}"
+ "\nQuick start example.");
});
}
protected class Options
{
[Option(
'v',
HelpText = "Verbosity level.",
Default=VerbosityEnum.v)]
public uint Verbosity { get; set; }
}
}
}
Here's my output from testing;
-> $ dotnet run -- -vv
program.cs(22,37): warning SA1008: Opening parenthesis should not be followed by a space. [/home/x10an14/Documents/project/project.csproj]
program.cs(13,13): warning SA1300: Element 'v' should begin with an uppercase letter [/home/x10an14/Documents/project/project.csproj]
program.cs(14,13): warning SA1300: Element 'vv' should begin with an uppercase letter [/home/x10an14/Documents/project/project.csproj]
program.cs(15,13): warning SA1300: Element 'vvv' should begin with an uppercase letter [/home/x10an14/Documents/project/project.csproj]
Hello World!
slackbot 1.0.0
Copyright (C) 2019 slackbot
ERROR(S):
Option 'v' is defined with a bad format.
Error setting value to option 'v': Check if Option or Value attribute values are set properly for the given type.
-v (Default: v) Verbosity level.
--help Display this help screen.
--version Display version information.
-> $ dotnet run --
Hello World!
slackbot 1.0.0
Copyright (C) 2019 slackbot
ERROR(S):
Error setting value to option 'v': Check if Option or Value attribute values are set properly for the given type.
-v (Default: v) Verbosity level.
--help Display this help screen.
--version Display version information.
-> $ dotnet run -- -v
Hello World!
slackbot 1.0.0
Copyright (C) 2019 slackbot
ERROR(S):
Option 'v' has no value.
Error setting value to option 'v': Check if Option or Value attribute values are set properly for the given type.
-v (Default: v) Verbosity level.
--help Display this help screen.
--version Display version information.
-> $
Here's a reference of how Rust's Structopt1 (based on Clap2) enables the same feature as I'm asking for
- https://github.com/rust-cli/clap-verbosity-flag
1: https://github.com/TeXitoi/structopt 2: https://github.com/clap-rs/clap
I'm still not getting it
- You need not to use the separate doubledash
-- - The option Verbosity is VerbosityEnum not uint
[Option( 'v',
HelpText = "Verbosity level: v or vv or vvv Or int values 1 or 2 or 3",
Default=VerbosityEnum.v)]
public VerbosityEnum Verbosity { get; set; }
-
Commandline Arguments can be:
-vv //its 'v v' with VerbosityLevel: v or 1 -vvv //its 'v vv' with VerbosityLevel: vv or 2 -vvvv //its 'v vvv' with VerbosityLevel: vvv or 3 //using int values -v1 //its 'v v' with VerbosityLevel: v or 1 -v2 //its 'v vv' with VerbosityLevel: vv or 2 -v3 //its 'v vvv' with VerbosityLevel: vvv or 3 //no argument, so use default value: v or 1 //-v //Not allowed, raise error: Option 'v' has no value. //note: don't use the prefix doubledash -- before argsWorking Demo: Try it online
Edit:
clab in Rust define the argument verbose with short_name(v) and compute the number of occurrence of the command (e.g for vvv ==>occurrence =3) using a method matches.occurrences_of (v)
rename "term limit" to results limit, or else add both ngrams limit and results limit
this is also per brad's feedback
This issue seems to have been fixed by #684
You need to set FlagCounter=true in the attribute and enable GetoptMode on the parser. (there seems to have been some talk about changing GetoptMode to an enum instead in the future, see #690)
var parser = new Parser(with =>
{
with.GetoptMode = true;
});
...
class Options
{
[Option('v', FlagCounter = true, HelpText = "Verbosity level: v or vv, vvv or vvvv")]
public int Verbosity { get; set; }
}
Online demo: https://dotnetfiddle.net/E8Q3sL