SkillAgentSearch skills...

Cmdr.Core

Useful POSIX command line arguments parser for .Net. Hierarchical-configuration Store for app.

Install / Use

/learn @hedzr/Cmdr.Core

README

Cmdr.Core

CircleCI Nuget (with prereleases)

Useful POSIX command line arguments parser for dotNet. Hierarchical configurations Store for app.

Supported:

  • dotNet 6 (since v1.3+)
  • dotNet Core 3.1 (since v1.1+)
  • dotNet Standard 2.1+ (since v1.1+)
  • ~~dotNet 4.8+ [?] (NOT SURE)~~

NOTED .NET 5 has been ignored.

NuGet

PM> Install-Package HzNS.Cmdr.Core -Version 1.0.29
# Or CLI
$ dotnet add package HzNS.Cmdr.Core --version 1.0.29

Please replace 1.0.29 with the newest version (stable or pre-release), see the nuget badge icon.

Features

Cmdr.Core has rich features:

  • [x] POSIX Compatible (Unix getopt(3))
  • [x] IEEE Standard Compartiblities
  • [x] builds multi-level command and sub-commands
  • [x] builds short, long and alias options with kinds of data types
  • [x] defines commands and options via fluent api style
  • [x] full featured Options Store for hosting any application configurations
    • watchable external config file and child directory conf.d.
    • watchable option value merging event: while option value modified in external config file, it'll be loaded and merged automatically.
    • watchable option value modifying event: while option value modified (from config file, or programmatically)
    • connectable with external configuration-center

More

  • Unix getopt(3) representation but without its programmatic interface.

    • [x] Options with short names (-h)
    • [x] Options with long names (--help)
    • [x] Options with aliases (--helpme, --usage, --info)
    • [x] Options with and without arguments (bool v.s. other type)
    • [x] Options with optional arguments and default values
    • [x] Multiple option groups each containing a set of options
    • [x] Supports the compat short options -aux == -a -u -x, -vvv == -v -v -v (HitCount=3)
    • [x] Supports namespaces for (nested) option groups see also: option store and hierarchical data
  • [x] Supports for -D+, -D- to enable/disable a bool option.

  • [x] Supports for PassThrough by --. (Passing remaining command line arguments after -- (optional))

  • [x] Automatic help screen generation (Generates and prints well-formatted help message)

  • [x] Predefined commands and flags:

    • Help: -h, -?, --help, --info, --usage, --helpme, ...
    • Version & Build Info: --version/--ver/-V, --build-info/-#
      • Simulating version at runtime with —version-sim 1.9.1
      • [ ] generally, conf.AppName and conf.Version are originally.
      • --tree: list all commands and sub-commands.
      • --config <location>: specify the location of the root config file.
      • version command available.
    • Verbose & Debug: —verbose/-v, —debug/-D, —quiet/-q
  • [x] Sortable commands and options/flags: sorted by alphabetic order or not (worker.SortByAlphabeticAscending).

  • [x] Grouped commands and options/flags.

    Group Title may have a non-displayable prefix for sorting, separated by '.'.

    Sortable group name can be [0-9A-Za-z]+\..+ format typically, or any string tailed '.', eg:

    • 1001.c++, 1100.golang, 1200.java, …;
    • abcd.c++, b999.golang, zzzz.java, …;
  • [x] Supports for unlimited multi-level sub-commands.

  • [x] Overrides by environment variables.

    priority level: defaultValue -> config-file -> env-var -> command-line opts

  • [x] Option Store - Unify option value extraction.

  • [x] Walkable

    • Customizable Painter interface to loop each command and flag.
    • Walks on all commands with Walk(from, commandWalker, flagWalker).
  • [x] Supports -I/usr/include -I=/usr/include -I /usr/include -I:/usr option argument specifications Automatically allows those formats (applied to long option too):

    • -I file, -Ifile, and -I=files
    • -I 'file', -I'file', and -I='files'
    • -I "file", -I"file", and -I="files"
  • [x] Supports for PassThrough by --. (Passing remaining command line arguments after -- (optional))

  • [x] Predefined external config file locations:

    • /etc/<appname>/<appname>.yml and conf.d sub-directory.

    • /usr/local/etc/<appname>/<appname>.yml and conf.d sub-directory.

    • $HOME/.config/<appname>/<appname>.yml and conf.d sub-directory.

    • $HOME/.<appname>/<appname>.yml and conf.d sub-directory.

    • the predefined locations are:

      predefinedLocations: []string{
      	"./ci/etc/%s/%s.yml",       // for developer
      	"/etc/%s/%s.yml",           // regular location: /etc/$APPNAME/$APPNAME.yml
      	"/usr/local/etc/%s/%s.yml", // regular macOS HomeBrew location
      	"$HOME/.config/%s/%s.yml",  // per user: $HOME/.config/$APPNAME/$APPNAME.yml
      	"$HOME/.%s/%s.yml",         // ext location per user
      	"$THIS/%s.yml",             // executable's directory
      	"%s.yml",                   // current directory
      },
      
    • [x] Watch conf.d directory, the name is customizable (worker.).

    • RegisterExternalConfigurationsLoader(loader, ...)

  • [x] Handlers

    • Global Handlers: RootCommand.OnPre/Post/Action(), OnSet() will be triggered before/after the concrete Command.OnPre/Post/Action()/OnSet()
    • Command Actions: Command.OnPreAction/OnAction/OnPostAction(), OnSet
    • Flag Actions: Flag.OnPreAction/OnAction/OnPostAction(), OnSet
    • Parsing Events:
      • bool OnDuplicatedCommandChar(worker, cmd, isShort, matchingString)
      • bool OnDuplicatedFlagChar(worker, cmd, flag, isShort, matchingString)
      • bool OnCommandCannotMatched(ICommand parsedCommand, string matchingArg)
      • bool OnCommandCannotMatched(ICommand parsingCommand, string fragment, bool isShort, string matchingArg)
      • bool OnSuggestingForCommand(object worker, Dictionary&lt;string, ICommand&gt; dataset, string token)
      • bool OnSuggestingForFlag(object worker, Dictionary&lt;string, IFlag&gt; dataset, string token)
      • ...
    • More...
  • Unhandled Exception cmdr handled AppDomain.CurrentDomain.UnhandledException for better display. But you can override it always:

    static int Main(string[] args) {
        AppDomain.CurrentDomain.UnhandledException+=(sender,e)=>{};
        Cmdr.NewWorker(...).Run();
    }
    
  • Smart suggestions for wrong command and flags

    based on Jaro-Winkler distance.

Option Store - Hierarchical Configurations Store

Standard primitive types and non-primitive types.

Get(), GetAs<T>()

Set<T>(), SetWithoutPrefix<T>()

Delete()

HasKeys(), HasKeysWithoutPrefix()

var exists = Cmdr.Instance.Store.HasKeys("tags.mode.s1.s2");
var exists = Cmdr.Instance.Store.HasKeys(new string[] { "tags", "mode", "s1", "s2" });
var exists = Cmdr.Instance.Store.HasKeysWithoutPrefix(new string[] { "app", "tags", "mode", "s1", "s2" });
Console.WriteLine(Cmdr.Instance.Store.Prefix);

FindBy()

var (slot, valueKey) = Cmdr.Instance.Store.FindBy("tags.mode.s1.s2");
if (slot != null){
  if (string.IsNullOrWhiteSpace(valueKey)) {
    // a child slot node matched
  } else {
    // a value entry matched, inside a slot node
  }
}

Walk()

GetAsMap()

return a SlotEntries map so that you can yaml it:

  // NOTE: Cmdr.Instance.Store == worker.OptionsStore
  var map = worker.OptionsStore.GetAsMap("tags.mode");
  // worker.log.Information("tag.mode => {OptionsMap}", map);
  {
      var serializer = new SerializerBuilder().Build();
      var yaml = serializer.Serialize(map);
      Console.WriteLine(yaml);
  }

CMDR EnvVars

CMDR_DUMP

enable Store entries dumping at the end of help screen.

CMDR_DUMP_NO_STORE, CMDR_DUMP_NO_HIT

To prevent the store dump, or hit options dump.

CMDR_DEBUG

= Worker.EnableCmdrLogDebug

allows the display output in defaultOnSet.

CMDR_TRACE

= Worker.EnableCmdrLogTrace

allows the worker logDebug().

CMDR_VERBOSE

allows more logging output.

Getting Start

Fluent API

Basically, the Main program looks like:

static int Main(string[] args) => 
  Cmdr.NewWorker(RootCommand.New(
    new AppInfo(),  // your app information, desc, ...
    buildRootCmd(), // to attach the sub-commands and options to the RootCommand
    workerOpts,     // to customize the Cmdr Worker
  ))
  .Run(args, postRun);

Your first app with Cmdr.Core could be:

<details> <summary> Expand to source codes </summary>
namespace Simple
{
    class Program
    {
        static int Main(string[] args) => Cmdr.NewWorker(

                #region RootCmd Definitions

                RootCommand.New(
                    new AppInfo
                    {
                        AppName = "tag-tool",
                        Author = "hedzr",
                        Copyright = "Copyright © Hedzr Studio, 2020. All Rights Reserved.",
                    },
                    (root) =>
                    {
                        root.Description = "description here";
                        root.DescriptionLong = "long description here";
                        root.Examples = "examples here";

                        // for "dz"
                        _a = 0;

                        root.AddCommand(new Command
                            {
                                Long = "dz", Short = "dz", Description = "test divide by zero",
                                Action = (worker, opt, remainArgs) => { C

Related Skills

View on GitHub
GitHub Stars5
CategoryDevelopment
Updated2y ago
Forks0

Languages

C#

Security Score

75/100

Audited on Oct 15, 2023

No findings