Esempio n. 1
0
        protected static CommandLineConfig Parse(params String[] args)
        {
            var frames = new StackTrace().GetFrames().Select(f =>
            {
                var m    = f.GetMethod();
                var decl = m.DeclaringType;
                while (decl != null && decl.IsCompilerGenerated())
                {
                    decl = decl.DeclaringType;
                }
                return(decl);
            }).ToReadOnly();

            frames = frames.SkipWhile(decl => decl == null || decl == typeof(CommandLineConfig)).ToReadOnly();
            frames = frames.SkipWhile(decl => decl == null || decl == typeof(Func)).ToReadOnly();
            frames = frames.SkipWhile(decl => decl == null || decl == typeof(CommandLineConfig)).ToReadOnly();
            var t = frames.AssertFirst(decl => decl != null && decl != typeof(CommandLineConfig));

            try
            {
                var ctor = t.GetConstructors(BF.All).Single(ci => ci.Params().SingleOrDefault2() == typeof(String[]));
                return((CommandLineConfig)ctor.Invoke(args.MkArray()));
            }
            catch (TargetInvocationException tie)
            {
                var cex = tie.InnerException as ConfigException;
                if (cex != null)
                {
                    var error = Logger.Get(t).Error;
                    if (cex.Message != null)
                    {
                        if (args.Last() != "/verbose")
                        {
                            var asm_name = t.Assembly.GetName().Name;
                            var cfg_name = t.Attr <ConfigAttribute>().Name;
                            error.WriteLine("Command line was: {0} {1}", cfg_name ?? asm_name, args.StringJoin(" "));
                        }

                        error.WriteLine(cex.Message);
                    }

                    error.EnsureBlankLine();
                    Banners.Help();
                    return(null);
                }
                else
                {
                    throw;
                }
            }
        }
Esempio n. 2
0
        protected CommandLineConfig(String[] s_args)
        {
            Log          = Logger.Get(GetType());
            Log.MinLevel = Level.Info;

            if (s_args.Count() == 1 && s_args[0] == "/?")
            {
                Banners.About();
                throw new ConfigException(String.Empty);
            }
            else
            {
                if (s_args.LastOrDefault() == "/verbose")
                {
                    IsVerbose = true;
                    s_args    = s_args.SkipLast().ToArray();

                    Info.WriteLine("Detected the \"/verbose\" switch, entering verbose mode.");
                    Log.MinLevel = Level.Debug;

                    Debug.EnsureBlankLine();
                    Debug.Write("Command line args are: ");
                    if (s_args.IsEmpty())
                    {
                        Debug.WriteLine("empty");
                    }
                    else
                    {
                        Debug.WriteLine("({0} arg{1})", s_args.Count(), s_args.Count() == 1 ? "" : "s");
                    }
                    s_args.ForEach((arg, i) => Debug.WriteLine("{0}: {1}", i + 1, arg));
                }

                Debug.EnsureBlankLine();
                Debug.WriteLine("Pre-parsing arguments...");
                var named_args    = new Dictionary <String, String>();
                var shortcut_args = new List <String>();
                foreach (var s_arg in s_args)
                {
                    var m     = s_arg.Parse("^-(?<name>.*?):(?<value>.*)$");
                    var name  = m != null ? m["name"] : null;
                    var value = m != null ? m["value"] : s_arg;
                    if (m != null)
                    {
                        Debug.WriteLine("Parsed \"{0}\" as name/value pair: {1} => \"{2}\".", s_arg, name, value);
                    }
                    else
                    {
                        Debug.WriteLine("Parsed \"{0}\" as raw value.", s_arg);
                    }

                    if (name == null)
                    {
                        if (named_args.IsNotEmpty())
                        {
                            throw new ConfigException("Fatal error: shortcut arguments must be specified before named arguments.");
                        }
                        else
                        {
                            shortcut_args.Add(value);
                        }
                    }
                    else
                    {
                        if (named_args.ContainsKey(name))
                        {
                            throw new ConfigException("Fatal error: duplicate argument \"{0}\".", name);
                        }
                        else
                        {
                            named_args.Add(name, value);
                        }
                    }
                }
                Debug.WriteLine("Pre-parse completed: found {0} named argument{1} and {2} shortcut argument{3}.",
                                named_args.Count(), named_args.Count() == 1 ? "" : "s",
                                shortcut_args.Count(), shortcut_args.Count() == 1 ? "" : "s");

                Debug.EnsureBlankLine();
                Debug.WriteLine("Parsing arguments...");

                var parsed_args = new Dictionary <PropertyInfo, Object>();
                if (named_args.IsNotEmpty())
                {
                    Debug.WriteLine("Parsing named arguments...");
                    parsed_args = ParseArgs(named_args);
                }

                if (shortcut_args.IsNotEmpty())
                {
                    Debug.WriteLine("Parsing shortcut arguments...");

                    Dictionary <PropertyInfo, Object> parsed_shortcut_args = null;
                    var shortcuts   = GetType().Attrs <ShortcutAttribute>().OrderBy(shortcut => shortcut.Priority);
                    var bind_errors = new Dictionary <String, String>();
                    foreach (var shortcut in shortcuts)
                    {
                        Debug.WriteLine("Considering shortcut schema \"{0}\"...", shortcut.Schema);
                        var words = shortcut.Schema.SplitWords();
                        if (words.Count() != shortcut_args.Count())
                        {
                            var message = String.Format("argument count mismatch.");
                            bind_errors.Add(shortcut.Schema, message);
                            Debug.WriteLine("Schema \"{0}\" won't work: {1}", shortcut.Schema, message);
                            continue;
                        }

                        try { parsed_shortcut_args = ParseArgs(words.Zip(shortcut_args).ToDictionary(t => t.Item1, t => t.Item2)); }
                        catch (ConfigException cex)
                        {
                            bind_errors.Add(shortcut.Schema, cex.Message);
                            Debug.WriteLine(cex.Message);
                            Debug.WriteLine("Schema \"{0}\" won't work: failed to parse arguments.", shortcut.Schema);

                            continue;
                        }

                        var dupes = Set.Intersect(parsed_args.Keys, parsed_shortcut_args.Keys);
                        if (dupes.IsNotEmpty())
                        {
                            var a    = dupes.AssertFirst().Attr <ParamAttribute>();
                            var name = named_args.Keys.Single(k => a.Aliases.Contains(k));
                            Debug.WriteLine("Schema \"{0}\" won't work: shortcut argument duplicates parsed argument \"{1}\".", shortcut.Schema, name);
                            parsed_shortcut_args = null;
                            continue;
                        }
                        else
                        {
                            Debug.WriteLine("Schema \"{0}\" works fine, skipping other schemas (if any).", shortcut.Schema);
                            break;
                        }
                    }

                    if (parsed_shortcut_args == null)
                    {
                        var message      = "Fatal error: failed to match the shortcuts.";
                        var bind_summary = bind_errors.Select(kvp => String.Format("Failed to match \"{0}\": {1}", kvp.Key, kvp.Value.Replace("Fatal error: ", String.Empty))).StringJoin(Environment.NewLine);
                        if (!IsVerbose)
                        {
                            message = message + Environment.NewLine + bind_summary;
                        }
                        throw new ConfigException(message);
                    }
                    else
                    {
                        parsed_args.AddElements(parsed_shortcut_args);
                    }
                }

                Debug.WriteLine("Parse completed.");
                Debug.EnsureBlankLine();
                Debug.WriteLine("Setting configuration parameters...");
                var props = this.GetType().GetProperties(BF.AllInstance).Where(p => p.HasAttr <ParamAttribute>()).OrderBy(p => p.Attr <ParamAttribute>().Priority);
                props.ForEach(p =>
                {
                    if (parsed_args.ContainsKey(p))
                    {
                        var value = parsed_args[p];
                        Debug.WriteLine("Resolved %{0} as {1}.", p.Name, value.ToLog());
                        p.SetValue(this, value, null);
                    }
                    else
                    {
                        var p_default = this.GetType().GetProperty("Default" + p.Name, BF.AllStatic);
                        if (p_default == null)
                        {
                            throw new ConfigException("Fatal error: parameter \"{0}\" must be specified.");
                        }

                        var value = p_default.GetValue(null, null);
                        Debug.WriteLine("Defaulted %{0} to {1}.", p.Name, value.ToLog());
                        p.SetValue(this, value, null);
                    }
                });
                Debug.WriteLine("Configuration parameters successfully set.");
            }
        }