natemcmaster / commandlineutils Goto Github PK
View Code? Open in Web Editor NEWCommand line parsing and utilities for .NET
Home Page: https://natemcmaster.github.io/CommandLineUtils/
License: Apache License 2.0
Command line parsing and utilities for .NET
Home Page: https://natemcmaster.github.io/CommandLineUtils/
License: Apache License 2.0
Hi there
In your sample: CommandLineUtils/samples/Subcommands/Inheritance.cs
How would you go about showing app.ShowHelp() so that if you typed
dotnet run add it will show the help for the Files command
I tried the following:
protected override int OnExecute(CommandLineApplication app)
{
if (Files.Length == 0)
{
// this shows help even if the --help option isn't specified
app.ShowHelp();
return 1;
}
return 0;
}
This seemed to work, but when I actually passed arguments it still kept showing the help
`dotnet run add files test1,test2' still showed help?
Is it possible to implement the following logic:
--option mandatory_value [optional_value1] [optional_value2]
without making to specify --option
flag multiple times?
Flags are one of the most common kinds of options in CLIs, but as is, there is no way to tell if an Optional is called without values or not called at all.
I'm trying to create a command line application with a single required argument ("version"):
var versionArgument = app.Argument("version", "The version to set the project as.").IsRequired();
As expected, I get an error message when trying to run my program without specifying this argument:
$ dotnet bin/Release/netcoreapp2.0/dotnet-setversion.dll
The version field is required.
Specify --help for a list of available options and commands.
However, I don't expect to get this error when displaying information (help or version), but that's what currently happens:
$ dotnet bin/Release/netcoreapp2.0/dotnet-setversion.dll --help
Usage: dotnet-setversion [arguments] [options]
Arguments:
version The version to set the project as.
Options:
-h|--help Show help information
-f|--file Identifies the csproj file to update. Looks in the current working directory if not set.
The version field is required.
Specify --help for a list of available options and commands.
Presently I believe it is not possible to provide an IHelpGenerator to the CommandLineApplication.ExecuteAsync<MainArgs>()
method.
It would be good to add support for this: As a use case, I'd like to inject extra metadata (outside the scope of this tool) into help messages
A simple solution is to add another overload to ExecuteAsync
.
A more interesting idea might be to allow for creating a CommandLineApplication
instance, which can then be modified, and to add an instance method version of Execute<T>
and ExecuteAsync<T>
which builds off the existing CommandLineApplication instance. This approach might prove more general (fewer ways to configure the same thing, allows access to other functionality like ValidationErrorHandler
) and allow for other interesting things (like mixed builder and reflection generation).
I'm happy to make a contribution but would appreciate guidance on public APIs.
Followup to #59
We should
As a bonus, we could either
Hello,
is it a bug, that program is taken the control before async sub-command OnExecute is done?
a demo example:
static int Main(string[] args)
{
var app = new CommandLineApplication();
app.HelpOption("-h|--help");
var optionSubject = app.Option("-s|--subject <SUBJECT>", "The subject", CommandOptionType.SingleValue);
app.Command("subCmd", cmd =>
{
cmd.FullName = "Sub-command";
cmd.Description = "Demo sub-command";
cmd.ExtendedHelpText = "An extended help text...";
cmd.HelpOption();
var subCmdArg = cmd.Argument("SubArg", "The argument");
cmd.OnExecute(async () =>
{
Console.WriteLine("sub-command starting ...");
await Task.Delay(4000);
Console.WriteLine("... sub-command: done - arg: " + subCmdArg.Value);
});
});
app.OnExecute(async () =>
{
var subject = optionSubject.HasValue()
? optionSubject.Value()
: "world";
Console.Write($"Hello");
// This pause here is just for indication that some awaitable operation could happens here.
await Task.Delay(5000);
Console.WriteLine($" {subject}!");
return 0;
});
var result = app.Execute(args);
Console.WriteLine("Press any key to end...");
Console.ReadKey();
return result;
}
Try searching for ResponseFileParser.
Sorry, forked repositories are not currently searchable.
You could try searching the parent repository.
https://github.com/blog/1381-a-whole-new-code-search
"Repository forks will not be searchable unless the fork has more stars than the parent repository."
We can advertise and be awesome, then maybe we can get more stars than aspnet/Common. But then we have to continue to get more stars as the more and more people find and star aspnet/Common
. Seems like it could be a battle as aspnet/Common
has a free advertising mechanism, being connected to Microsoft.
StackOverflow knows all things.
https://stackoverflow.com/a/16052845/5167537
"You can contact github support and ask them to switch your repository to "normal mode".
On this page, "Commit was made in a fork" paragraph, it is explained that one has to go through support to switch. Therefore, it is likely that there is no way to do that by yourself (unless you destroy and recreate your repo which is explained before... if you do so be careful if you have tickets or a wiki attached to your project as they will be deleted!)." -- Thomas Moulard
Currently, it is up to the application developer using CommandLineUtils
to validate command line input and display an appropriate error if an Option that is required is left out. I propose that CommandLineUtils
take on this responsibility, allowing the library user to designate parameters as required and provide appropriate feedback to the user when the parameter is not provided.
This may be a nice feature to do after #8 so the user of the library need only add an attribute of [Required] to make this designation.
The OnExecute
extension method provides a way to pass an Action
delegate rather than a Func<int>
delegate, but it also breaks if the delegate is an async
method.
/// <summary>
/// Sets <see cref="CommandLineApplication.Invoke"/> with a return code of <c>0</c>.
/// </summary>
/// <param name="app"></param>
/// <param name="action"></param>
public static void OnExecute(this CommandLineApplication app, Action action)
=> app.OnExecute(() =>
{
action();
return 0;
});
This breaks (because the method is not awaited):
app.OnExecute(async () => {
...
if(someReason)
throw new SomeException();
});
But this works:
app.OnExecute(async () => {
...
if(someReason)
throw new SomeException();
return 0;
});
Hi,
Now, I wonder, whether it is possible to add a code in one of that already defined Sub-commands class, which will create inner sub-comands programmatically. (I face to a list of sub-comands definition, which comes from an external service, which could continuously grow, I would like to map that metadata to generate the CommandLineUtils sub-command structure on the fly).
From other point of view - is it possible to combine the attribute SubCommand with a code for defining of sub-commands?
TIA,
Mojmir
In the vein of automating as much as possible, it would be nice to be able to supply our own value parsers to the library. This is useful when an application has its own data structures because it removes boilerplate from argument parsing.
For example, we are parsing DateTimeOffsets
, TimeSpans
, Color
structs, and some other domain-specific types.
If you think this would be a valuable contribution I'd be happy to implement it, but I'd appreciate a suggestion on how I should extend the public API. A trivial (but perhaps naive) way to do it would be to add an AddParser
method ValueParserProvider
.
Problem
Users who prefer the builder API can't take advantage of the automatic type parsing available in the attribute api for int
, List<T>
, etc. Part of the difficulty is that CommandLineApplication
, CommandArgument
, and CommandOption
only provide string-based properties.
Proposal
Add CommandOption<T>
and CommandArgument<T>
.
There is acts as an implicit requirement that values can be parsed to typeof(T)
.
For custom types, users can provide a custom converter to parse string
into typeof(T)
. CLU will provide parsers for most commonly used types like int
, double
, bool
, etc.
Usage
public static int Main(string[] args)
{
var app = new CommandLineApplication();
CommandArgument<int> arg = app.Argument<int>("arg", "argument");
CommandOption<int> option = app.Option<int>("--arg", CommandOptionType.SingleValue)
.Accepts().Range(0, 100);
CommandOption<IPAddress> option2 = app.Option<IPAddress>("--addres", CommandOptionType.SingleValue)
.UseConverter(val => IPAddress.Parse(val));
app.OnExecute(() =>
{
int[] values = option.Values;
});
return app.Execute(args);
}
hi @natemcmaster ,
I am struggling to find an example of how it is envisioned to define commands that accept custom dependencies injected using declarative syntax.
Is there any place where you could point me to see an example of how to do this?
Because shorter is better.
I chose "McMaster.Extensions.CommandLineUtils" because it was very similar to the original "Microsoft.Extensions.CommandLineUtils". I don't really love that my name is in the title though. Plus long package names are annoying to type out all the way.
cc @ScotiaBaker
It would be nice if this supported checkboxes like this: https://www.npmjs.com/package/prompt-checkbox
If possible I'll try to implement in during my free time this week.
Currently CLU targets either full .NET Framework 4.5 or the new .NET Standard 2.0.
The advice from Microsoft for library authors is to target the lowest version of .NET Standard that you can get away with.
To support CLU on more .NET platforms out of the box, it would be better to see if lower versions of .NET Standard can be targeted.
With the latest NuGet release, an option is available to set the short name of an option, but the help message outputs what seems like an autogenerated (incorrect) one.
[Option(CommandOptionType.SingleValue, Description = "...", ValueName = "...", ShortName = "c")]
public string ConfigPath { get; set; }
[Option(CommandOptionType.SingleValue, Description = "...", ValueName = "...", ShortName = "s")]
public string CSharpPath { get; set; }
The following is the output line from help:
-c|--config-path ¥<CONFIG_PATH> ...
-c|--csharp-path ¥<CSHARP_PATH> ...
The options parses correctly when passed but the help text is misleading.
Make it possible to write an app that supports tab completion in bash, powershell, and others.
Neither of the HelpOption
methods in the builder API provide the ability to specify that the option should be inherited. It is common to use the same help option for subcommands, so it would be nice to specify the option once on the root CommandLineApplication
instance and not have to do it for every subcommand.
I also think since this is such a common practice for CLI tools (see git or dotnet), the help option should be inherited by default, but this could be considered a breaking change.
In the event that this feature is rejected, I would like to point out that the generated help from calling the .ShowHelp
method suggests the help option for subcommands even if there is no help option specified on them.
i have added an extension method to CommandLineApplication to support convention based command handling. see here https://github.com/shovonnn/artisancommandline
i tried to create a pull request for this repo. but it wont compile. few too many error. maybe cause of netcore1.x
i am on a tight schedule at the moment. so can't work much.
In #20, I added initial work to support validating parameters before OnExecute is called. I added the .IsRequired()
extension method for CommandOption and CommandArgument. I also added support for using ValidationAttribute
in the attribute binding API.
I'd like to expand the API to include commonly used validations. This might include
I know this isn't really the forum for this, but currently I am using this project my small CLI util. But so far I can only find resources online, that indicate that when I want to run a dontet console app, I need to invoke it as such:
dotnet my-data-loader.dll --foo bar
or during debug/dev dotnet run -- --foo bar
Are there any docs / resources online that use this project (either in its current or prior states), that explain how to go from the examples above to something like:
my-data-loader --foo
.
Thanks in advance :)
Currently, value parsers use the current culture for parsing (that is: no culture is specified). This means that on systems not running on an en-US locale, problems will occur because scripts & response files are non-portable (my 1.234 is your 1,234 and vice versa, and the same with dates).
If all parsing code were to use the Invariant culture by default, these problems would disappear.
Currently this is thrown and unhandled. This requires users to implement their own catch. The library should instead catch this, print to stderr, and exit before calling OnExecute.
Hi there I was wondering if you have a dependency injection example?
Usually I would use something like below but I'm not sure how I would call your code?
class Program
{
static int Main(string[] args)
{
// setup our DI
var services = new ServiceCollection();
services.AddTransient<IHelloService, HelloService>();
var serviceProvider = services.BuildServiceProvider();
// ---------------------------------------------------
// Not sure how to use this ???
var app = serviceProvider.GetService<Calculator>();
//app.Run(args);
///------------------------------------------------
}
}
Hi Nate,
I just started using this library and there are so many good things in here (for example the dependency injection and conventions). But sadly it is not very easy to get to grips with all of the concepts, or even know of their existence unless you work through the sample apps and answers for previous Issues. Also, the API reference in the docs is good for reference, but not very helpful to explain the concepts.
I'd love to help you sort out the docs, but I don't just want to jump in without checking with you first.
I blog regularly and worked for Auth0 on their docs, so I am comfortable with writing and doing this for you. I am also familiar with using DocFx, as I have used it for some of the Auth0 libraries I wrote.
So before I just start hammering away, do you have any ideas in your mind with regards to the outline for the docs of the various parts needing to be addressed?
Exception throws when user leaves option values blank.
Unhandled Exception: McMaster.Extensions.CommandLineUtils.CommandParsingException: Missing value for option 'opt'
at McMaster.Extensions.CommandLineUtils.CommandLineProcessor.ProcessOption()
at McMaster.Extensions.CommandLineUtils.CommandLineProcessor.ProcessNext()
at McMaster.Extensions.CommandLineUtils.CommandLineProcessor.Process()
at McMaster.Extensions.CommandLineUtils.ReflectionAppBuilder`1.Bind(IConsole console, String[] args)
at McMaster.Extensions.CommandLineUtils.CommandLineApplication.Execute[TApp](IConsole console, String[] args)
at Program.Main(String[] args)
Is there any possibility to control this exception with a more global like solution? It is currently a blocker for my requirements, because it cannot be controlled. The property 'ThrowOnUnexpectedArgument' does not affect the behavior. A similar way would be awesome. Maybe the property can be considered in the function.
Within CommandLineProcessor.cs the exception simply throws. In my opinion, there must be a more sensitive solution. I tried to implement an validation attribute with the latest release to check whether the value is set or not. It does not work. The exception has been thrown before. Maybe it would be better to output (custom) error message without having the problem, that the application crashed before.
I've seen there are new values for CommandOptionTypes. Is the desired solution to set the value 'SingleOrNoValue' to prevent the exception?
Thanks for the clarification.
As title suggests, GetPassword should return a SecureString
object instead of a plain string.
Awesome work!
I have Delay1
and Delay2
options, which obviously clash in "-d"
Would be great if I could specify just the short override to "-d1" and "-d2"!
Usage
class Program : IDisposable
{
private readonly MyResource _resource;
public Program()
{
_resource = new MyResource();
}
public void OnExecute()
{
}
public void Dispose() // <--- This should be invoked before the app exits.
{
_resource.Dispose();
}
}
Hi, I'm using this library for a pretty large CLI application. One command, in particular, has many options with similar names, for example:
[Option(Description = "...")]
public string AnalysisIdentifier { get; set; }
[Option(Description = "...")]
public TimeAlignment AlignToMinute { get; set; } = TimeAlignment.None;
[Option(Description = "...")]
public bool WhenExitCopyLog { get; set; }
[Option(Description = "...")]
public bool WhenExitCopyConfig { get; set; }
The automatic short name generator complains if two short names are the same (fair enough) but what I'd like to do is disable short names for lesser-used options. I've tried:
ShortName
to null
but that doesn't work because of https://github.com/natemcmaster/CommandLineUtils/blob/master/src/CommandLineUtils/Attributes/OptionAttributeBase.cs#L60ShortName
to ""
(empty string) but it considers empty strings to be duplicate names (https://github.com/natemcmaster/CommandLineUtils/blob/master/src/CommandLineUtils/Internal/ReflectionAppBuilder.cs#L270)I realise I could use the template string form and omit the short name part, but I've got a couple hundred options over a dozen subcommands and I don't want to maintain a separate string for all of those options (the auto kebab casing for full names is a great help!).
What do you think?
I've got three ideas:
""
to represent a not having short namebool NoShortName
property to OptionAttribute
(eww)LongOptionAttribute
class which will not set ShortName
because it won't have the Configure
method from OptionAttribute
OptionAttributeBase
are limited howeverI would like to build a CLI where commands are related to subjects, like the Docker CLI:
docker container ls -a
docker image ls -a
docker container run --name some-redis -d redis
Where docker
is the application, container
/ image
etc. the subject and ls
/ run
etc. the command, with commands belonging to the subject and with arguments only applying to the specific command.
The subcommand example only used app command -arg
, so the level of "subjects" is missing. But it seems to be possible with building a hierarchy with the Parent
attribute, at least from how I understand the subcommand tests.
It would be nice to have some kind of documentation about how to "nest" subcommands to create a Docker-like CLI.
And a question: In a Docker-like CLI it shouldn't be possible to use multiple subjects in one line, e.g. docker container ls -a image ls -a
. But for example this line in the tests looks like that's currently possible when using subcommands in CommandLineUtils. Is there a way to restrict that?
Only a simple question:
Why this further project, when Microsoft continues with this command line parser (of the second generation)?
When running dotnet .\bin\Debug\netcoreapp2.0\HelloWorld.Attributes.dll --help
I get the expected output:
Usage: [options]
Options:
-?|-h|--help Show help information
-s|--subject <SUBJECT> The subject
But when running dotnet .\bin\Debug\netcoreapp2.0\HelloWorld.Attributes.dll -h
I get an error:
Usage: [options]
Options:
-?|-h|--help Show help information
-s|--subject <SUBJECT> The subject
Unhandled Exception: System.NullReferenceException: Object reference not set to an instance of an object.
at McMaster.Extensions.CommandLineUtils.CommandLineApplication.Bind[TApp](IConsole console, String[] args) in X:\Path\To\CommandLineUtils\src\CommandLineUtils\CommandLineApplication.Execute.cs:line 150
at McMaster.Extensions.CommandLineUtils.CommandLineApplication.Execute[TApp](IConsole console, String[] args) in X:\Path\To\CommandLineUtils\src\CommandLineUtils\CommandLineApplication.Execute.cs:line 48
at McMaster.Extensions.CommandLineUtils.CommandLineApplication.Execute[TApp](String[] args) in X:\Path\To\CommandLineUtils\src\CommandLineUtils\CommandLineApplication.Execute.cs:line 31
at Program.Main(String[] args) in X:\Path\To\CommandLineUtils\samples\HelloWorld.Attributes\Program.cs:line 11
master
as of 2017-12-03T00:13:42Z, 1a843bd4db8d536e54f9d7ae9b58ebf53f16b521, which is newer than the latest tag v2.1.0-beta
dotnet --version
: 2.0.0
POSIX examples:
git clean -xfd --git-dir ./.git/
Windows CMD examples
taskkill /T /F /IM git.exe
PowerShell example
Remove-Item -Recurse -Force ./node_modules/
Currently, this library only supports parsing the POSIX
git mv {Microsoft => McMaster}.Extensions.CommandLineUtils
The ASP.NET Core team is in the business of producing a web framework, and not in producing .NET libraries in general. In the early days of what later became ASP.NET Core, Microsoft.Extensions.CommandLineUtils was created as a requirement of producing dnx and ASP.NET vNext. It was never intended to be the Microsoft-official way to write command line apps. After later refactoring of the architecture of dnx into dotnet, and reassignments of resources, the ASP.NET Core team no longer maintains much command-line code, so they decided to stop active development on their CommandLineUtils library. See dotnet/extensions#257.
Hence, I've forked the project. This project will maintain and improve upon the 1.0 and 1.1 versions of the library.
Fork is the operative word here. Not branch, not update, not replace.
This repo is open to community contributions under the Apache 2.0 License. Please read the contributing guidelines, and tag me @natemcmaster in the pull-request.
Cheers,
Nate. 🍻
Simple fancy feature that allows working with util as with WebHostBuilder for ex.
Keeping docs in sync with code is a pain. Let's automate this, if we can. We already have a generate which produces console output. Would be awesome if it could produce that output in a format that could be piped to a file.
tool --help:man > tool.1.man
tool --help:html > tool-help.html
When Subcommands project is being started it prompts to choose for one of 3 options.
When the option 3 is chosen - the app just exits without allowing to interact with fake-npm command.
Minimal spec
public class Program
{
[Argument(0)]
public string Command { get; set; }
[Option]
public string Message { get; set; }
[Option("-F <file>")]
public string File { get; set; }
[Option]
public bool Amend { get; set; }
[Option("--no-edit")]
public bool NoEdit { get; set; }
public static void Main(string[] args)
=> CommandLineApplication.Execute<Program>(args);
private void OnExecute()
{}
}
Currently, it's not possible to write your own RequiredAttribute
, because the validators are called once for every given value.
First off, thank you for forking this and continuing to work on it!
Many CLI apps let you pass in a file path argument as such --filepath="C:\Users\foo\file"
(Windows) and --filepath="/home/foo/file"
(Linux). When trying to do this with a C# Console app, the quotes are escaped as "\"C:\\Users\\foo\\file\""
and "\"/home/foo/file\""
. This causes an exception to be thrown when using LegalFilePathAttribute because new FileInfo(path)
throws a System.NotSupportedException with message "The given path's format is not supported.". I understand that this is not a bug from this library. I'd like to open a conversation about supporting this type of argument behavior.
This would allow more complex validation scenarios.
app.ShowVersion();
I've looked into the code and there doesn't seem to be a way to prevent throwing when you use the attribute API. I know you can set the property on CommandLineApplication instances, but CommandLineApplication.Execute<Program>(args) doesn't give you such object?
The alternative would be to add the argument on the Execute static methods and pass it on the ReflectionAppBuilder?
First and foremost required arguments (non-null/empty)?
Thanks :)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.