Katteker/Creator/Helper/SimpleCommandLineParser.cs
Holger Boerchers d383f0ef1c Initial commit
2018-03-21 20:07:40 +01:00

166 lines
6.5 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Reflection;
namespace KattekerCreator.Helper
{
public class SimpleCommandLineParser<TObject> where TObject : new()
{
private TObject _parsedObject;
public SimpleCommandLineParser(IEnumerable<string> args)
{
Parse(args);
}
private IDictionary<string, string[]> Arguments { get; } = new Dictionary<string, string[]>();
public bool Contains(string name) => Arguments.ContainsKey(name);
public TObject GetObject()
{
if (!EqualityComparer<TObject>.Default.Equals(_parsedObject, default(TObject)))
return _parsedObject;
_parsedObject = new TObject();
try
{
LoopProperties(pi =>
{
var displayName = GetDisplayName(pi);
if (displayName == null) return;
if (!Arguments.TryGetValue(displayName.ToLowerInvariant(), out var argument)) return;
if (pi.PropertyType == typeof(bool))
{
pi.SetValue(_parsedObject, true);
return;
}
if (pi.PropertyType.IsArray)
pi.SetValue(_parsedObject, argument);
else
pi.SetValue(_parsedObject, argument.FirstOrDefault());
});
}
catch (Exception e)
{
Log.WriteErrorLine("Error parsing commandline arguments: " + e.Message);
ShowHelp();
}
return _parsedObject;
}
public void ShowHelp(TextWriter textWriter = null)
{
if (textWriter == null) textWriter = Console.Out;
var executable = Assembly.GetExecutingAssembly().GetName().Name + ".exe";
var assemblyTitle = ((AssemblyTitleAttribute) Attribute.GetCustomAttribute(Assembly.GetExecutingAssembly(), typeof(AssemblyTitleAttribute), false))?.Title ?? executable;
var assemblyDescription = ((AssemblyDescriptionAttribute) Attribute.GetCustomAttribute(Assembly.GetExecutingAssembly(), typeof(AssemblyDescriptionAttribute), false))?.Description;
textWriter.WriteLine();
textWriter.WriteLine(assemblyTitle);
textWriter.WriteLine();
textWriter.WriteLine(assemblyDescription);
textWriter.WriteLine();
textWriter.WriteLine(executable + " <options>");
textWriter.WriteLine();
var dict = new Dictionary<string, string>();
LoopProperties(pi =>
{
var displayName = GetDisplayName(pi);
if (displayName == null) return;
var description = GetDescription(pi);
if (pi.PropertyType == typeof(bool)) description = "(Switch) " + description;
dict.Add(displayName, description);
});
var longestWord = dict.Keys.Max(x => x.Length);
foreach (var kv in dict)
{
textWriter.Write("-" + kv.Key.PadRight(longestWord + 3, ' '));
textWriter.WriteLine(kv.Value);
}
textWriter.WriteLine();
textWriter.WriteLine("A switch will be set to true, if it will called.");
textWriter.WriteLine($"Example: {executable} <Switch>");
textWriter.WriteLine();
textWriter.WriteLine("A parameter will be set.");
textWriter.WriteLine($"Example: {executable} <Key> \"Value\"");
}
/// <summary>
/// Shows the current set options.
/// </summary>
/// <param name="textWriter">If not set Console.Out will be set.</param>
public void ShowProgramArguments(TextWriter textWriter = null)
{
if (textWriter == null) textWriter = Console.Out;
LoopProperties(pi =>
{
var displayName = GetDisplayName(pi) ?? pi.Name;
var value = pi.GetValue(_parsedObject);
textWriter.Write(displayName.PadRight(20, ' '));
if (value == null)
{
textWriter.WriteLine("<NOT SET>");
}
else
{
if (value.GetType().IsArray)
{
var arrayAsString = ((IEnumerable) value)
.Cast<object>()
.Aggregate(string.Empty, (current, x) => current + x?.ToString() + ", ");
textWriter.WriteLine(arrayAsString);
}
else
{
textWriter.WriteLine(value.ToString());
}
}
});
}
private static TAttribute GetAttribute<TAttribute>(MemberInfo memberInfo) where TAttribute : Attribute =>
(TAttribute) Attribute.GetCustomAttribute(memberInfo, typeof(TAttribute));
private static string GetDescription(MemberInfo memberInfo) => GetAttribute<DescriptionAttribute>(memberInfo)?.Description;
private static string GetDisplayName(MemberInfo memberInfo) => GetAttribute<DisplayNameAttribute>(memberInfo)?.DisplayName;
private static void LoopProperties(Action<PropertyInfo> action)
{
var properties = typeof(TObject).GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (var propertyInfo in properties)
action.Invoke(propertyInfo);
}
private void Parse(IEnumerable<string> args)
{
var currentName = "";
var values = new List<string>();
foreach (var arg in args)
{
if (arg.StartsWith("-", StringComparison.Ordinal))
{
if (!string.IsNullOrWhiteSpace(currentName))
Arguments[currentName.ToLowerInvariant()] = values.ToArray();
values.Clear();
currentName = arg.Substring(1);
}
else if (string.IsNullOrWhiteSpace(currentName))
{
Arguments[arg] = new string[0];
}
else
{
values.Add(arg);
}
}
if (currentName != "")
Arguments[currentName.ToLowerInvariant()] = values.ToArray();
}
}
}