my first pass at command line parsing support

25 views
Skip to first unread message

Brannon

unread,
Feb 23, 2012, 1:59:36 PM2/23/12
to Autofac
Here is code for my first attempt at adding command line parsing
support. It seems to work pretty well. Run the code with -sp 23 or --
someProp asldjlsdjf to see how it works.

Possible Todo:
1. Support a parameter to output the usage.
2. Support required parameters.
3. Support generating an XML schema and a parameter to load parameters
from XML.
4. Warn about unused command line parameters


using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Text;
using Autofac;
using Autofac.Core;

namespace TestAutofac
{
class Program
{
static void Main()
{
var builder = new ContainerBuilder();
var ret = builder.RegisterType<MyService>();
var cp = new ConfigurablePropertyParameter("SomeProp", "I'm a
command-line settable property");
ret.WithProperty(cp);

try
{
var container = builder.Build();
var service = container.Resolve<MyService>();
Console.WriteLine("Prop = " + service.SomeProp);
}
catch (DependencyResolutionException ex)
{
Console.WriteLine("Unable to successfully parse the parameter: " +
ex.InnerException.Source);

Console.WriteLine(ConfigurablePropertyParameter.GenerateCommandLineUsage());
}
if (Debugger.IsAttached)
Console.ReadKey();
}
}

class MyService
{
public int SomeProp { get; set; }
}

class ConfigurablePropertyParameter: Parameter
{
public static string GenerateCommandLineUsage()
{
var sb = new StringBuilder("Supported Parameters: ");
lock(_descriptions)
{
foreach (var desc in _descriptions.OrderBy(d => d.Key))
{
sb.AppendLine();
var sn = GenerateShortName(desc.Key);
var ln = GenerateLongName(desc.Key);
sb.Append("\t");
sb.Append(sn);
sb.Append("/");
sb.Append(ln);
sb.Append(" <value>\t");
sb.Append(desc.Value);
}
}
return sb.ToString();
}

protected static readonly Dictionary<string, string> _descriptions =
new Dictionary<string, string>();
protected static readonly HashSet<string> _shortNames = new
HashSet<string>();

public readonly string PropertyName;
public ConfigurablePropertyParameter(string propertyName, string
propertyDescription)
{
PropertyName = propertyName;
var sn = GenerateShortName(propertyName);
lock(_shortNames)
{
if (!_shortNames.Add(sn))
throw new ArgumentException("This short propertyName has already
been registerd: " + sn, "propertyName");
}
lock (_descriptions)
{
if(_descriptions.ContainsKey(propertyName)) throw new
ArgumentException("This propertyName has already been registerd: " +
propertyName, "propertyName");
_descriptions.Add(propertyName, propertyDescription);
}
}

private static string GenerateLongName(string longName)
{
return "--" + char.ToLower(longName[0]) + longName.Substring(1);
}

private static string GenerateShortName(string longName)
{
var matches = longName.Where(char.IsUpper);
return "-" + string.Join("", matches).ToLower();
}

public override bool CanSupplyValue(ParameterInfo pi,
IComponentContext context, out Func<object> valueProvider)
{
return FoundInCommandLine(pi, out valueProvider);
}

private bool FoundInCommandLine(ParameterInfo pi, out Func<object>
valueProvider)
{
var args = Environment.GetCommandLineArgs();
var idx = Array.IndexOf(args, GenerateShortName(PropertyName));
if(idx < 0)
{
idx = Array.IndexOf(args, GenerateLongName(PropertyName));
}
if(idx < 0)
{
valueProvider = null;
return false;
}

valueProvider = () =>
{
try
{
return Convert.ChangeType(args[idx + 1], pi.ParameterType);
}
catch(Exception ex)
{
ex.Source = GenerateShortName(PropertyName) + "/" +
GenerateLongName(PropertyName);
throw;
}
};
return true;
}
}
}
Reply all
Reply to author
Forward
0 new messages