Skip to content

How to implement countable flags? Ref. -vvv for "triple verbosity" #523

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
x10an14 opened this issue Oct 15, 2019 · 11 comments
Closed

How to implement countable flags? Ref. -vvv for "triple verbosity" #523

x10an14 opened this issue Oct 15, 2019 · 11 comments
Labels

Comments

@x10an14
Copy link

x10an14 commented Oct 15, 2019

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.

@moh-hassan
Copy link
Collaborator

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.`

@x10an14
Copy link
Author

x10an14 commented Oct 15, 2019

Thanks! =)

@x10an14 x10an14 closed this as completed Oct 15, 2019
@x10an14 x10an14 reopened this Oct 15, 2019
@x10an14
Copy link
Author

x10an14 commented Oct 15, 2019

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.

@moh-hassan
Copy link
Collaborator

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.

@x10an14
Copy link
Author

x10an14 commented Oct 15, 2019

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; }
}

?

@moh-hassan
Copy link
Collaborator

moh-hassan commented Oct 15, 2019

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

@x10an14
Copy link
Author

x10an14 commented Oct 16, 2019

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.
-> $ 

@x10an14
Copy link
Author

x10an14 commented Oct 16, 2019

Here's a reference of how Rust's Structopt1 (based on Clap2) enables the same feature as I'm asking for

1: https://github.com/TeXitoi/structopt
2: https://github.com/clap-rs/clap

@moh-hassan
Copy link
Collaborator

moh-hassan commented Oct 17, 2019

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 args
    

    Working 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)

@nomicode
Copy link

nomicode commented Oct 2, 2021

rename "term limit" to results limit, or else add both ngrams limit and results limit

this is also per brad's feedback

@poizan42
Copy link

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

@x10an14 x10an14 closed this as completed Jan 29, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants