gsscoder / commandline Goto Github PK
View Code? Open in Web Editor NEWTerse syntax C# command line parser for .NET with F# support
Terse syntax C# command line parser for .NET with F# support
As stated in other threads, I'm working on this.
Next commit very soon (may be today).
Regards, Giacomo
Name: develop-1.9.8-beta.
This is the new official current development branch, please send PR that differs from this.
cc: @mizipzor @nemec & others contrib
(Informative issue, will be closed soon).
CommandLine.Text
namespace will be moved to root namespace.CommandLine.Parser::WasVerbOptionInvoked
will be replaced by consistent way of performing the same task (evaluating various option at the moment).If you look at the (for instance) man page for grep, you'll see something like:
grep [OPTIONS] PATTERN [FILE...]
So, [OPTIONS]
are what the library currently parse without a problem, however how to define required or optional parameters without a switch at the beginning or end (like PATTERN
or [FILE...]
here)? Naturally, one can preprocess the string, splice it and then pass to the library, but why not have it out of the box? :) It would be cool to define them in attributes in a way like "first", "first after options" or something similar. What do you think? Or maybe there is such an option and I missed it.
Sometimes it's nice to call a program with MyProg.exe input_file output_file
, without having to define specific -i
and -o
flags if both parameters are required. This could be as simple as, after the fact, popping off the first N values of ValueList and converting them into properties or adding more logic to the parser.
As you seen with latest release a lot was done to simplify the library.
Don't get me wrong, I'll not change basic concepts of the API; but I'd like to embrace good design from functional world for make our library strongest.
When you declare the options type:
var options = new Options();
options
is in state X (initialized) and after
var result = new Parser().ParseArguments(args, options);
options
is in state Y (with parsed values)
So we can say that ParseArguments
caused side effects. Another one, is the result (also influenced by the same function... opssss method!).
Incredibly the solution is quite easy:
T Parser.ParseArguments<T>(string[] args, Action onFail)
The method with this new signature constructs the instance and returns it.
ParserStateAttribute
is used, the generic errors list will be available as always.But if parsing fails an appropriate delegate (Action onFail
) is called.
Other advantages: convergence of standard methods with strict methods (@nemec suggested feature).
Functional paradigms proves their effectiveness from '70 (and before), please dig into the argument if not convinced. :))
As always, opinions (or flames) are welcome.
PS:
Some side effects for the moment will remain. E.g.: printing out the help. As said, I'm moving to a removing the most evident of these.
Hi.
I like this library a lot! But one thing I'm missing is support for "verbs". Like when the first argument on command line is a verb which then has options specific to that verb. Similar to git commit -m "message"
.
I put the code below together as a proof of concept. Though, looking at it now I think I would have preferred to have the Option
attribute assigned to parameters of the method instead of a dedicated class, but that would require some more intrusive changes. Is this something you would be interested in exploring or is totally out of scope for this library?
using System;
using System.Linq;
using System.Reflection;
using CommandLine;
namespace SampleApp
{
public class VerbProgram
{
private static void Main(string[] args)
{
//MyVerbs.FooOptions options = new MyVerbs.FooOptions();
//if (!CommandLineParser.Default.ParseArguments(
// new[] { "--flag" }, options))
//{
// Environment.Exit(1);
//}
MyVerbs verbs = new MyVerbs();
if (!VerbParser.Default.ParseArguments(
new[] { "foo", "--flag" }, verbs))
{
Environment.Exit(1);
}
Environment.Exit(0);
}
}
internal class MyVerbs
{
internal class FooOptions : CommandLineOptionsBase
{
[Option("f", "flag", Required = true)]
public bool Flag { get; set; }
}
[Verb]
public void Foo(FooOptions options)
{
Console.WriteLine(options.Flag);
}
}
public class VerbAttribute : Attribute
{
/// <summary>
/// By default the name of the verb is a lowercase version of the
/// method name, set this property to override.
/// </summary>
public string Name { get; set; }
public string HelpText { get; set; }
}
internal class VerbParser
{
public static VerbParser Default = new VerbParser();
internal ICommandLineParser ArgumentParser = CommandLineParser.Default;
public bool ParseArguments(string[] args, object verbs)
{
// store name of verb and remove it from args
var verbName = args[0];
args = args.Skip(1).ToArray();
// find verb method
Pair<MethodInfo, VerbAttribute> verb = null;
foreach (Pair<MethodInfo, VerbAttribute> pair in
ReflectionUtil.RetrieveMethods<VerbAttribute>(verbs))
{
string name = pair.Right.Name;
if (string.IsNullOrEmpty(name))
{
name = pair.Left.Name.ToLower();
}
if (verbName.Equals(name))
{
verb = pair;
break;
}
}
if (verb == null)
{
return false; // verb not found
}
object options = Activator.CreateInstance(
verb.Left.GetParameters()[0].ParameterType);
if (!ArgumentParser.ParseArguments(args, options))
{
return false; // couldnt parse verb arguments
}
verb.Left.Invoke(verbs, new[] {options});
return true;
}
}
}
I'd like for there to be a method on at least the default parser that, if parsing fails, it automatically displays the help screen (or generate one automatically, if there is no defined help), then quit (eg. Environment.Exit(1)
). It's a common enough process that I think it deserves its own method.
Currently to be able to display the list of errors, it is necessary to extend CommandLineOptionsBase.
It seems that the reason is because the parsing state and errors are stored in that parent class.
Why not move the parser state in a static variable in the CommandLineParser?
Or another option, make the error list as an option of the method with the HelpOption attribute.
And last option, make the GetUsage(...) method as an option of ParseArguments
My issue with extending CommandLineOptionsBase is that it requires to propagate the assembly everywhere.
I would like to be able to specify the HelpText
for an Option
in a Resources.resx
file.
I'm trying to keep my code shorter than 80 characters and reflowing the helptext is cumbersome (but its great that the lib reflows them on output). Also being able to localize the help text is a nice bonus.
Due to nemec's off topic vote to split the source files I hereby register the official request. His words are better than mine:
Now that the project has a NuGet package, no one should be adding the .cs file manually to a project. If anything, the .nupkg file is a single file and just as easy to include in a project as a binary while leaving the source easy to navigate in multiple files.
The initial response from gsscoder was:
These day I was reasoning over the question of splitting source in more files. For development is better use a splitted source while for deployment I prefer one or two files.
I'd argue that this GitHub repository is mainly for development, rather than deployment, hence multiple source files should be used.
If I have a option as follow
[Option("z", "zzz")]
public int Test { get; set; }
[HelpOption]
public string GetUsage()
{
return HelpText.AutoBuild(this, current => HelpText.DefaultParsingErrorsHandler(this, current));
}*
And I call my executable as follow (without specifying the value to the argument z)
sample.exe -z
It would correctly detect that something wrong happenned but it does not display any error. It would simply display the help text.
Created from
http://stackoverflow.com/questions/15208931/default-values-for-lists-arrays-using-command-line-parser-library
by @pheiberg.
@pheiberg, thank you for taking time to report issue. As the previous, will be fixed ASAP.
Regards, Giacomo
Resharper tells me that the 'first' variable is never changed from its default true value therefore the code in the then block in the for/next loop will never be executed.
Actually, looks like the condition should be "if (first)" not "if (!first)"
Cheers
Simon
Using the sample code in https://github.com/gsscoder/commandline/wiki/Display-A-Help-Screen section "Handling Parsing Errors" to print errors:
RenderParsingErrorsText() returns a string with linebreaks if there are multiple errors. When passed to Add<>OptionsLine, it is wrapped every 80 characters regardless of newlines, causing incorrect wrapping.
[ParserState]
public IParserState LastParserState { get; set; }
[Option('a', "qwe", Required = true)]
public string a { get; set; }
[Option('b', "asd", Required = true)]
public double b { get; set; }
[Option('c', "zxc", Required = true)]
public bool c { get; set; }
[HelpOption]
public string GetUsage()
{
var help = new HelpText();
// ...
if (this.LastParserState.Errors.Count > 0)
{
var errors = help.RenderParsingErrorsText(this, 2); // indent with two spaces
if (!string.IsNullOrEmpty(errors))
{
help.AddPreOptionsLine(string.Concat("\n", "ERROR(S):"));
help.AddPreOptionsLine(errors);
}
}
// ...
return help;
}
>foo.exe
ERROR(S):
-a/--qwe required option is missing.
-b/--asd required option is
missing.
-c/--zxc required option is missing.
As you can see, the second error line gets incorrectly wrapped.
Good day, developer team!
Using last version of CommandLineParser library I found incorrect library behaviour. When I pass next parameters
-read ReadFileName
your library consider -read
argument as -r
command with ead
parameter.
I am using test project from "demo" folder. Looks like in parsing process CommandLineParser process on first short option name, and than process long option name.
I attached screenshot. You can view parsing result in Watch 1 window.
While performing some tests about how looks using the current development version of CommandLine with FSharp, I've found an issue that also the current stable has.
If someone is curious the gist is here.
Unfortunately the development branch now diverges too much from the stable and time lacks to work on two different versions.
The good news is that all (and more) tests of the development branch are green, the public API should not change (expect for some refactoring to simplify HelpText); so it will merged as soon to the master
branch.
If you can't way, you will know when the issue is fixed in the development branch -> clone it -> compile and use it.
For reference (but remember API is even simplified and still not documented - but I can help if you write me): https://github.com/gsscoder/commandline/tree/develop-1.9.8-beta
Have nice day!
When using HelpText.AutoBuild, instead of the application name and version specified in AssemblyInfo.cs, I always get CommandLine 1.9.2.4
Using VS 2010, in C#; Options class subclasses CommandLineOptionsBase. In my Main method I tried either instantiating a CommandLineParser or using CommandLineParser.Default; both doesn't make any difference.
@nemec, strict parsing (suggested by you) led me to think that CoC (convention over configuration) is gaining consensus between developers (see ASP.NET MVC, see Grails in Java World etc).
What about something like this:
bool result = CommandLineParser.AutoParse(); // or CommandLineParser.Default.AutoParse() ???
Inside the method calls Environment.GetArgs()
and inspect the assembly for a type marked with an attribute (or by naming convention), say
[ParserTarget] // <- maybe marking also the class is more explicit
class Options {
// everything as usual here...
[ParserTarget] // <- maybe the lib could use just this attr to discover the options type
public static Options Instance {get; set;}
}
When ::AutoParse()
returns (and if returns) true
product of parsing will be dressed up into Options::Instance
static member.
Opinions? (Everyone invited).
Dear gsscoder,
Command line parser uses the culture setting of the hosting process to interpret input and set property values of option class. The data feed from command line might not match the culture of the process hosting parser. In the worst case, the hosting process doesn't know which culture is used to format the input it is interpreting. It means that the hosting process cannot adapt to input culture by altering Thread.CurrentThread.CurrentCulture before calling CommandLine.CommandLineParser.ParseArguments.
So, I propose a special CultureAttribute to be implemented. The idea is that programmer can decorate one property of the option class with CultureAttribute. The parser should interpret input with culture specified via command line. An example of option class property with a new CultureAttribute attribute:
[Culture('c', "culture", MetaValue = "NAME", DefaultValue = "en-US", HelpText = "Specify which culture NAME is used to interpret command line options.")]
public System.Globalization.CultureInfo Culture { get; set; }
As a result, app.exe can be called with input formatted in multiple ways:
app.exe --culture en-US --value 1023.45
app.exe --culture fi-FI --value "1 234,45"
I suggest that CultureAttribute attribute should understand culture names known by CreateSpecificCulture method of CultureInfo class. For more information, look at:
http://msdn.microsoft.com/en-us/library/system.globalization.cultureinfo.createspecificculture.aspx
Parser should change Thread.CurrentThread.CurrentCulture if CultureAttribute attribute has Permanent property (defaults to false) switched on. Otherwise, culture setting should affect input parsing only.
This is my weak attempt to describe what CultureAttribute might look like:
/// <summary>
/// Models an culture specification.
/// </summary>
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public sealed class CultureAttribute : BaseOptionAttribute
{
/// <summary>
/// Initializes a new instance of the <see cref="CommandLine.CultureAttribute"/> class.
/// </summary>
/// <param name="shortName">The short name of the culture option..</param>
public CultureAttribute(char shortName)
: base(shortName, null)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="CommandLine.CultureAttribute"/> class.
/// </summary>
/// <param name="longName">The long name of the culture option.</param>
public CultureAttribute(string longName)
: base(null, longName)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="CommandLine.CultureAttribute"/> class.
/// </summary>
/// <param name="shortName">The short name of the culture option.</param>
/// <param name="longName">The long name of the culture option or null if not used.</param>
public CultureAttribute(char shortName, string longName)
: base(shortName, longName)
{
}
/// <summary>
/// Gets or sets the persistence mode of the culture setting.
/// </summary>
public bool Permanent { get; set; }
/// <summary>
/// Helper factory method for testing purpose.
/// </summary>
internal OptionInfo CreateOptionInfo()
{
return new OptionInfo(base.ShortName, base.LongName);
}
}
Thanks for your devotion to this library. It has helped me a lot!
Kind regards,
Olli-Pekka Isola
After spleeping on (and some research) I finally came to conclusion that source inclusion will not be impaired by multiple file splitting (exactly one file per type, java-like).
I'll arrange the project to be included in others using git submodules (or equivalent technologies of other source version control systems).
This will be done today 10 Jan (local time at moment of writing this post 13:47 PM).
So please do not submit pull requests until next commit.
Regards,
Giacomo
Looks like you might have the best command line parser for .NET.
The one thing I see missing however (and maybe I just overlooked it), is the ability to map command line switches to environment variables.
If you have decoupled build from deployment, with a tool like Capistrano and intend to run with a Procfile
on Linux (in our case, exported to Upstart), then it's pretty standard to config the application via environment variables. So rather than pass options through command line or .config
files... we export some environment variables during deployment.
Have you given this any thought? It would be very useful to us.
Thanks!
Downloading master.zip (to rule out that git does something) and checking line endings in Notepad++, it considers CommandLine.cs
to have Windows eol and CommandLineText.cs
to have Unix eol. It would be nice if they were the same.
When calling a program with an option that isn't specified, the general usage information is rendered, but no indication on what went wrong is shown. Also there is no information on the error in the IParserState
. It would be very useful to be able to get information on the error.
In typical command line parsers, using a double-dash as a token (eg. git add -- -u nothing
) forces all tokens after the --
to be read as values (equivalent to what's stored in your ValueList), even though -u
is otherwise a valid commandline flag. This allows, for instance, files starting with a dash to be added to a git repository.
My current level of skill / knowledge disagree that this interface (and main implementation CommandLine.Parser
) exposes so much overloads.
I'm thinking to reduce with this philosophy:
Few examples:
You know that if you set an TextWriter
for help output in settings, you can override the value with this overload?
bool ParseArguments(string[] args, object options, TextWriter helpWriter)
I'm sorry but mr. overload, I think I'm gonna kill you! :D
And all ParseArgumentStrict(...)
can be reduced to:
bool ParseArgumentsStrict(string[] args, object options, Action onFail = null);
I'm quite to near to next RC0, so opinions are welcome. Support me or try to make me change idea...
Want me to remove or maintain the Nuget package on www.nuget.org (http://nuget.org/packages/CommandLineParser)? The packages already has 581 download and was created from version 1.8 stable on codeplex (Release name 1.8.1.0 to cope with semantic versionning of nuget, allowing user to upgrade from 1.8.0.7 beta).
This is a question that is known to me from earlier versions.
Anyway to be honest I've always postponed. It does not affect functionality. But for me naming is a really important point.
Few (AND IMPORTANT!) class are named:
CommandLineParser
CommandLineParserSettings
and others
ParserState
etc...
So seeing that CLR has no real concept of namespace (they exist only at language level), the parser class is named
CommandLine.CommandLineParser
This could be acceptable if also other follow the same rule (but this is not true); and also internal type are subject to this reasoning.
I'm really considering (and probably I'll do) to removing the repeated CommandLine
from type name. So we will have:
CommandLine.Parser
CommandLine.ParserSettings
Impact? This class are named in few parts in a client project (I know this, because I also use my library in my open/closed source project...) -> so impact for me is not a big issue.
Result -> Nothing less that consistent naming!
PS: Why now? I'm projecting new extensions of Public API and I do not want keep a naming defect in new types. So when I'll decide to change, I will have to rename more type (than now).
Opinions?
It looks like this could be fixed by adding an IsNumeric method in CommandLine.cs and calling it in the following places:
public static ArgumentParser Create(string argument, bool ignoreUnknownArguments = false)
{
if (IsNumeric(argument))
return null;
...
public static bool IsInputValue(string argument)
{
if (IsNumeric(argument))
return true;
...
Hi, I'm using the latest beta so that I can use VerbOptions. It appears that if I start my command line arguments with the name of a valid VerbOption and then follow that VerbOption with an unknown argument I do not get a parser error (e.g. an extraneous character surrounded by spaces such as in "myapp doit x -y" where x is not a valid option for the "doit" verb but -y is).
It seems that an "else" clause is needed in Parser.cs at line 213 in the DoParseArgumentsCore method. Like so:
// this handles when an unknown entry is present in the command line after a valid verboption
else
{
hadError = true;
}
Thanks
The next Beta will break some public API compatibility (nothing drastic!), for this reason the version will jump to 1.9.4.9* increasing until will reach first 1.9.5.0 Stable.
But you are not interested in my version naming policies, right?
All new and "unfixed" issues will be taken into account for this new release.
So please don't expect pull-requests made on 1.9.3.* to be merged: I can't keep more branches active on this project. Anyway don't stop posting! Good ideas will be incorporated if possible in 1.9.4.9* Beta.
Please be patient if some good pull request were not merged, but consider also that sometime is more simple to me fix something by description that solve source code conflicts.
Anyway thanks everyone, for interest in this library. Your collaboration made it better!
Regards,
Giacomo Stelluti Scala
I got an exception during the parsing step. After some debugging, I finally found that the error was that I used 2-letter strings for the short name of my options. This made me wonder why a string was used for the "ShortName" instead of a char. It seems not consistent with the fact that for the separator character in an OptionList, one really uses a character.
I just started using this library, so forgive me if this is stupid request:
When an empty option list is parsed, shouldn't a format error be added to the PostParsingState? As I'm sure you know, It would be a one line change to add
DefineOptionThatViolatesFormat(option);
to the block that tests whether the option is empty. (OptionGroupParser.cs L54)
e.g.
class Options
{
[OptionList('d', "date-range", Separator = ':')]
public List<string> DateRange { get; set; }
}
>foo.exe -d
-d/--date-range option violates format
>
The CommandLineParser
is an instance created used and (hopefully) discarded by Garbage Collector. After first call (except in plugin scenario) there's no reason for call ParseArguments
again.
In favor of readability I'm wondering if a fluent builder can live side by side (or replace?) CommandLineParserSettings
.
Pseudocode:
var parser = new CommandLineBuilder()
.WriteHelpTo(Console.Error)
.IsCaseSensitive()
.IsMutuallyExclusive()
.IgnoreUnknownArguments().Build()
parser.ParseArguments(args); // or chaining also this call, if you want
Opinions?
If we do something like the following
[Option("r", "read", Required = true,
HelpText = "Input file to be processed.")]
public string InputFile { get; set; }
and we run something like this (notice the single - in front of read)
run.exe -read
the parser believes that "ead" is the input file name
It seems you format your code with ReSharper (which is great!) could you commit the code style to the repository so I don't have to match it by hand?
In Visual Studio: ReSharper -> Options -> Code Style Sharing
I haven't used rake before so this is a great excuse to try it. However, simply running rake
in the root folder ends with the following lines. Did I do something wrong?
(in C:/dev/commandline)
packages/xunit.runners.1.9.1/tools/xunit.console.clr4.exe C:/dev/commandline/build/out/CommandLine.Tests.dll
rake aborted!
Command failed with status (1): [packages/xunit.runners.1.9.1/tools/xunit.c...]
C:/Ruby192/lib/ruby/1.9.1/rake.rb:993:in `block in sh'
C:/Ruby192/lib/ruby/1.9.1/rake.rb:1008:in `call'
C:/Ruby192/lib/ruby/1.9.1/rake.rb:1008:in `sh'
C:/Ruby192/lib/ruby/1.9.1/rake.rb:1092:in `sh'
C:/dev/commandline/Rakefile.rb:68:in `block in <top (required)>'
C:/Ruby192/lib/ruby/1.9.1/rake.rb:634:in `call'
C:/Ruby192/lib/ruby/1.9.1/rake.rb:634:in `block in execute'
C:/Ruby192/lib/ruby/1.9.1/rake.rb:629:in `each'
C:/Ruby192/lib/ruby/1.9.1/rake.rb:629:in `execute'
C:/Ruby192/lib/ruby/1.9.1/rake.rb:595:in `block in invoke_with_call_chain'
C:/Ruby192/lib/ruby/1.9.1/monitor.rb:201:in `mon_synchronize'
C:/Ruby192/lib/ruby/1.9.1/rake.rb:588:in `invoke_with_call_chain'
C:/Ruby192/lib/ruby/1.9.1/rake.rb:605:in `block in invoke_prerequisites'
C:/Ruby192/lib/ruby/1.9.1/rake.rb:602:in `each'
C:/Ruby192/lib/ruby/1.9.1/rake.rb:602:in `invoke_prerequisites'
C:/Ruby192/lib/ruby/1.9.1/rake.rb:594:in `block in invoke_with_call_chain'
C:/Ruby192/lib/ruby/1.9.1/monitor.rb:201:in `mon_synchronize'
C:/Ruby192/lib/ruby/1.9.1/rake.rb:588:in `invoke_with_call_chain'
C:/Ruby192/lib/ruby/1.9.1/rake.rb:581:in `invoke'
C:/Ruby192/lib/ruby/1.9.1/rake.rb:2041:in `invoke_task'
C:/Ruby192/lib/ruby/1.9.1/rake.rb:2019:in `block (2 levels) in top_level'
C:/Ruby192/lib/ruby/1.9.1/rake.rb:2019:in `each'
C:/Ruby192/lib/ruby/1.9.1/rake.rb:2019:in `block in top_level'
C:/Ruby192/lib/ruby/1.9.1/rake.rb:2058:in `standard_exception_handling'
C:/Ruby192/lib/ruby/1.9.1/rake.rb:2013:in `top_level'
C:/Ruby192/lib/ruby/1.9.1/rake.rb:1992:in `run'
C:/Ruby192/bin/rake:31:in `<main>'
Edit:
It stops on Tests complete: 102 of 161
.
Edit2:
I can get it to work by running:
git clean -f
git reset --hard
Clean and rebuild in Visual Studio and manually running:
.\packages\xunit.runners.1.9.1\tools\xunit.console.clr4.exe .\build\out\CommandLine.Tests.dll
All tests are run and pass. But if I ever run just rake
it starts failing again and I need to redo the above steps.
Dear actual or future contributors,
due to deep changes to command line parser kernel, I'm not able to accept PR without previous coordination.
This is true for both master and devel-* branch.
This is a general good rule, but in this case is a key necessity.
PR are always welcome, but when there are such ongoing change -> merging could be difficult (or impossible) and so coordination is required.
Hope this don't stop you from sending PR.
develop-* branch:
Giacomo Stelluti Scala
PS: this guide helped me, but don't take the title as statement of mine (http://goo.gl/xJFE1) -> read it!
Currently implementing verb support in my project (great fun), ran across a problem when generating the help text. The GetUsage
method is from the wiki, am I missing something?
internal class MyVerbs
{
internal class FooOptions
{
[Option("bar", HelpText = "bar help")]
string Bar { get; set; }
}
[VerbOption("foo", HelpText = "foo help")]
public FooOptions Foo { get; set; }
// this code taken from the wiki
[HelpVerbOption]
public string GetUsage(string verb)
{
bool found;
var instance = CommandLineParser.GetVerbOptionsInstanceByName(
verb, this, out found);
var verbsIndex = verb == null || !found;
var target = verbsIndex ? this : instance;
// found is true but instance is null,
// throws ArgumentNullException
return HelpText.AutoBuild(
target,
current => HelpText.DefaultParsingErrorsHandler(target, current),
verbsIndex);
}
}
internal class Program
{
private static void Main(string[] args)
{
MyVerbs verbs = new MyVerbs();
args = "help foo".Split();
CommandLineParser.Default.ParseArguments(args, verbs);
}
}
Basically, I created an option that accept a integer. When I pass a long to it and I try to parse it, it generates an overflow exception. I'm not sure if I should handle it on my side but the example giving leads me to think that it should be done by the parser.
Here are some sample code.
public class Options : CommandLineOptionsBase
{
[Option("i", "Identification", Required = true, HelpText = "Some Id.")]
public int Identification { get; set; }
}
public static void Main(string[] args)
{
var options = new Options();
// crash here
if (!CommandLineParser.Default.ParseArguments(args, options))
{
Environment.Exit(-1);
}
Thank you for sharing us this great library.
I was wondering if OptionAttribute accepts PropertyName as default long name (and also UniqueName) when short name and long name are not available.
It's very convenient if we don't have to provide short name and long name, just use property name as command option name.
Thank you
Hi,
I was wondering what was the best way to pass arguments that may contain spaces (especially filenames).
I think most command line apps will support quoting filenames to work around the space issue. For example, on Windows the following command will create 2 directories, Test and 1:
mkdir Test 1
Whereas the following will create 1 directory named Test 1:
mkdir "Test 1"
This is supported by most commands that deal with files.
I may be missing something but I haven't seen such support in the CommandLine library?
The best I could come up with was using an OptionList or ValueList, joining the parts back together and possibly stripping the quotes, but it can get quite complex when you consider that this should also be supported:
mkdir "Test 1" "Test 2"
What are your thoughts on this? If you were interested in supporting this and wanted to point me in the right direction I might be able to implement it and submit a patch.
Cheers
Xavier
As you can see these days I've started some refactoring.
The problem is that verb additions made CommandLineParser grow and I feel that code must be internally reorganized in order to promote an easier extension (and easier contributions too).
Even with verb addition this class is grown too much.
I'm evaluating various options to decoupling internal parts. Opinions as always are wellcome.
Another thing,
I'd like to reference CommandLine.dll rather than including sources in CommandLine.Tests.dll.
I'v generated the public key from snk file. Copied it to InternalsVisibleTo but the framework still not match the assembly. Maybe this is an issue concerning the FullName (culture etc).
If anyone can help on this point, I can proceed with refactoring.
The StringBuilder
inside CopyrightInfo
is reused and never reset. The reproducing code is very simple:
class Program
{
static void Main(string[] args)
{
var copyrightInfo = new CopyrightInfo("TheAuthor", 2012);
int len1 = copyrightInfo.ToString().Length; // 28
int len2 = copyrightInfo.ToString().Length; // 56
}
}
[Option("s", "source", Required = true, HelpText = "Source Word2007+ document path")]
public string SourceDocument { get; set; }
[Option("o", "output", Required = true, HelpText = "Output Excel2007+ spreadsheet path")]
public string OutputSpreadsheet { get; set; }
[OptionArray("h", "headers", Required = true, HelpText = "List of coords to cells with headers")]
public uint[] Headers { get; set; }
[OptionArray("c", "content", Required = true, HelpText = "List of coords to cells with content")]
public uint[] Content { get; set; }
[Option("v", "verbose", Required = false, DefaultValue = false, HelpText = "Print details during execution")]
public bool Verbose { get; set; }
app.exe --source d:/document.docx --output d:/document.xlsx --headers 0 1 1 1 --content 0 2 1 2 --verbose
.NET 4.0, Windows 7, C# Express 2010
This isn't so much an issue, more that it's not documented anywhere. Took me a while to figure out why this wasn't working. Awesome project otherwise!
Would be great - for those of us making our own usage formats - to expose a read-only property that returns a string of the multi-line text.
I think this impacts AssemblyLicenseAttribute and AssemblyUsageAttribute which are both derived from MultiLineTextAttribute.
My thought was add a virtual property to MultiLineTextAttribute called 'Value'. Could be overriden in derived class if needed. If not, the default behavior simply concatenates all non-blank lines with Environment.NewLine.
Come to think of it, maybe I'll issue a pull request with the desired behavior.
to follow up on a twitter conversation with @gsscoder
There are times when it could be useful to have a boolean argument that allows the user to override default behavior by explicitly setting the value to false.
For instance:
[Option('r', "recursive", DefaultValue = true, HelpText = "Recurse through subdirectories.")]
public bool Recursive { get; set; }}}
but this doesn't work:
> myapp -r false
still sets Recursive to true.
(I get this is non-standard now)
I can see this getting closed as 'won't do'.
But I did want to record it in more than 140 characters in case any one else sees the value or logic in allowing for this type of behavior.
When creating an application that has a group of options of which one must be given and only one of them can be given at a time, there is currently no way to do that. MutuallyExclusiveSet
and Required
can't be used together.
Example: I have an application where the user either can process files using
MyApp --files myfile.txt
or get a list of possible languages to use to process the files
MyApp --list-languages
or get a list of available plugins
MyApp --list-plugins
etc
Using more than one option or none of them would render an error.
A verb based approach could solve it, but seems wrong since the applications only real command is to process files and the rest of the command would just be some sort of help commands.
The Plossum Command Line Parser is using the notion of OptionGroups, where a group can have a setting of:
- None
This is the default, and it means that no restrictions are placed on the options in this group (other than those explicitly specified for each option)- AtMostOne
This indicates that at most one of the options contained within this group must be specified. It means that either none of the options in the group, or one of the options in the group may be specified, but no more.- AtLeastOne
This indicates that at least one of the options contained within this group must be specified, i.e. one or more options from this group must be specified.- ExactlyOne
This indicates that exactly one option from this group must be specified, no more and no less.- All
Indicates that all options from this group must be specified on the command line.
This would be a good way to solve it IMO.
Another alternative I can think of - off the top of my head - would be to allow MutuallyExclusiveSet
and Required
to be combined. An option with Required
would then cause it's MutuallyExclusiveSet
to be required instead of the option.
A stackoverflow question on this issue is posted here.
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.