示例#1
0
        /// <summary>
        /// Returns help content derived from the provided assembly and parsable object.
        /// </summary>
        /// <param name="parsable"></param>
        /// <param name="asm"></param>
        /// <param name="template"></param>
        /// <param name="argumentTemplate"></param>
        /// <param name="maxLineLength">The maximum number of characters in a line before it is wrapped</param>
        /// <returns></returns>
        public static string GetHelpInfoFromAssembly(Parsable parsable, Assembly asm, string template, string argumentTemplate, int maxLineLength = 80)
        {
            if (parsable == null) throw new ArgumentNullException("parsable");
            if(asm == null) throw new ArgumentNullException("asm");
            if (string.IsNullOrEmpty(template)) return "";

            var parsableClass = Helper.GetObjectAttribute(parsable, typeof(ParsableClassAttribute)) as ParsableClassAttribute;
            if (parsableClass == null)
                throw new CliParseException("Unable to find 'ParsableClass' attribute on provided object.");

            var title = GetAssemblyAttribute(asm, typeof (AssemblyTitleAttribute));
            template = template.Replace("{title}", title);
            
            var version = asm.GetName().Version.ToString();
            template = template.Replace("{version}", version);

            var company = GetAssemblyAttribute(asm, typeof(AssemblyCompanyAttribute));
            template = template.Replace("{company}", company);

            var description = GetAssemblyAttribute(asm, typeof (AssemblyDescriptionAttribute));
            template = template.Replace("{description}", description);

            var syntax = GetSyntaxInfo(parsable, argumentTemplate, parsableClass.AllowedPrefixes);
            template = template.Replace("{syntax}", syntax);
            
            var copyright = GetAssemblyAttribute(asm, typeof (AssemblyCopyrightAttribute));
            template = template.Replace("{copyright}", copyright);
            
            var footer = GetAssemblyMetadataAttribute(asm, "footer");
            template = template.Replace("{footer}", footer);

            return FormatTextForScreen(template.Trim(), maxLineLength);
        }
示例#2
0
        /// <summary>
        /// Parses the provided args collection and uses its values to set the appropriate properties on the parsable object.
        /// </summary>
        /// <param name="parsable"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        public static CliParseResult Parse(Parsable parsable, IEnumerable<string> args)
        {
            if (args == null) throw new CliParseException("Parameter 'args' cannot be null.");
            if (parsable == null) throw new CliParseException("Parameter 'parsable' cannot be null.");

            var result = new CliParseResult();
            try
            {
                // single enumeration.
                var argumentList = args as IList<string> ?? args.ToList();
                parsable.PreParse(argumentList, result);
                if (result.Successful == false || result.ShowHelp) return result;
                result = MapArguments(parsable, argumentList);
                parsable.PostParse(argumentList, result);
            }
            catch (CliParseException ex) 
            {
                result.AddMessageFromException(ex);
            }
            return result;
        }
示例#3
0
        /// <summary>
        /// Returns help content derived from the provided parsable object.
        /// </summary>
        /// <param name="parsable"></param>
        /// <param name="template"></param>
        /// <param name="argumentTemplate"></param>
        /// <param name="maxLineLength">The maximum number of characters in a line before it is wrapped</param>
        /// <returns></returns>
        public static string GetHelpInfo(Parsable parsable, string template, string argumentTemplate, int maxLineLength = 80)
        {
            if (parsable == null) throw new ArgumentNullException("parsable");
            if (string.IsNullOrEmpty(template)) return "";

            var parsableClass = Helper.GetObjectAttribute(parsable, typeof(ParsableClassAttribute)) as ParsableClassAttribute;
            if(parsableClass == null)
                throw new CliParseException("Unable to find 'ParsableClass' attribute on provided object.");

            template = template.Replace("{title}", parsableClass.Title);
            template = template.Replace("{description}", parsableClass.Description);

            template = template.Replace("{copyright}", string.IsNullOrEmpty(parsableClass.Copyright) ? "" : parsableClass.Copyright);
            template = template.Replace("{version}", parsableClass.Version);

            var syntax = GetSyntaxInfo(parsable, argumentTemplate, parsableClass.AllowedPrefixes);
            template = template.Replace("{syntax}", syntax);

            template = template.Replace("{example}", parsableClass.ExampleText);
            template = template.Replace("{footer}", parsableClass.FooterText);

            return FormatTextForScreen(template.Trim(), maxLineLength);
        }
示例#4
0
 public static object GetObjectAttribute(Parsable parsable, Type type)
 {
     var parsableType = parsable.GetType();
     return parsableType.GetCustomAttributes(true).FirstOrDefault(x => x.GetType() == type);
 }
示例#5
0
        private static CliParseResult MapArguments(Parsable parsable, IEnumerable<string> args)
        {
            var result = new CliParseResult();

            var parsableClass = Helper.GetObjectAttribute(parsable, typeof(ParsableClassAttribute)) as ParsableClassAttribute;
            var allowedPrefixes = GetParsableClassAllowedPrefixs(parsableClass);
            var ignoreUnknowns = parsableClass != null && parsableClass.IgnoreUnknowns;

            var tokens = Tokenizer.Tokenize(args, allowedPrefixes).ToList();
            result.ShowHelp = tokens.Any(token=>IsHelpToken(token, parsable));
            if (tokens.Count == 0)
            {
                if (parsableClass == null || parsableClass.ShowHelpWhenNoArgumentsProvided) result.ShowHelp = true;
            }

            var parsableType = parsable.GetType();

            List<PropertyInfo> unsetProperties = parsableType.GetProperties().ToList();
            List<PropertyInfo> tmpSetProperties = new List<PropertyInfo>();

            // find by names
            foreach (var prop in unsetProperties)
            {
                foreach (var argument in prop.GetCustomAttributes(true).OfType<ParsableArgumentAttribute>())
                {
                    // find by name
                    var token = GetTokenForArgumentByName(tokens, argument);
                    var propertySet = false;
                    if(token != null) 
                        propertySet = SetPropertyValue(parsable, token, tokens, argument, prop);

                    if (!propertySet)
                    {
                        // find by position
                        token = GetTokenForArgumentByPosition(tokens, argument);
                        propertySet = SetPropertyValue(parsable, token, tokens, argument, prop);
                    }
                    // flag property as set and remove later.
                    if (propertySet)
                    {
                        tmpSetProperties.Add(prop);
                    }
                }
            }
            tmpSetProperties.ForEach(x => unsetProperties.Remove(x));

            foreach (var unsetProperty in unsetProperties)
            {
                foreach (var argument in unsetProperty.GetCustomAttributes(true).OfType<ParsableArgumentAttribute>())
                {
                    if(argument.Required)
                        result.AddErrorMessage(string.Format(CultureInfo.CurrentCulture,"Required argument '{0}' was not supplied.", argument.Name));
                }
            }

            
            // unknown/unused aruments
            if (!result.ShowHelp && !ignoreUnknowns)
            {
                tokens.Where(x => !x.Taken)
                    .ToList()
                    .ForEach(
                        x =>
                            result.AddErrorMessage(string.Format(CultureInfo.CurrentCulture,
                                "Unknown argument '{0}' was supplied.", x.Value.ToString())));
            }

            return result;
        }
示例#6
0
        private static bool SetPropertyValue(Parsable parsable, Token token, IEnumerable<Token> tokens, ParsableArgumentAttribute parsableArgument, PropertyInfo prop)
        {
            if (token == null)
            {
                if (parsableArgument.DefaultValue != null)
                {
                    prop.SetValue(parsable, parsableArgument.DefaultValue);
                    return true;
                }
                return false;    // couldnt find matching token, return false.
            }

            Token tokenValue = null;
            if(token.Type == TokenType.Field)
            {
                if (prop.PropertyType == typeof (bool))
                {
                    // check if we have been provided a "true" or "false" value.
                    tokenValue =
                        tokens.FirstOrDefault(x => !x.Taken && x.Index == token.Index + 1 && x.Type == TokenType.Value);

                    var optionValue = true;
                    if (tokenValue != null && !Boolean.TryParse(tokenValue.Value.ToString(), out optionValue))
                    {
                        // tokenValue did not contain a valid bool so do not use its value, set it back to null so it will not be flagged as Taken.
                        tokenValue = null;
                        optionValue = true;
                    }
                    prop.SetValue(parsable, optionValue); // set property to true if flag was provided.
                }
                else
                {
                    tokenValue =
                        tokens.FirstOrDefault(x => !x.Taken && x.Index == token.Index + 1 && x.Type == TokenType.Value);
                    if (tokenValue == null)
                        throw new CliParseException(string.Format(CultureInfo.CurrentCulture, "Missing value for ParsableArgument {0}", token.Value));

                    PropertyDescriptor propertyDescriptor = TypeDescriptor.GetProperties(parsable)[prop.Name];
                    prop.SetValue(parsable,
                        propertyDescriptor.Converter != null
                            ? propertyDescriptor.Converter.ConvertFrom(tokenValue.Value)
                            : tokenValue);
                }
            }
            
            if (token.Type == TokenType.Value)
            {
                PropertyDescriptor propertyDescriptor = TypeDescriptor.GetProperties(parsable)[prop.Name];
                prop.SetValue(parsable,
                    propertyDescriptor.Converter != null
                        ? propertyDescriptor.Converter.ConvertFrom(token.Value)
                        : token.Value);
            }

            token.Taken = true;
            if (tokenValue != null) tokenValue.Taken = true;

            return true;
        }
示例#7
0
 private static bool IsHelpToken(Token token, Parsable parsable)
 {
     var parsableClass = Helper.GetObjectAttribute(parsable, typeof(ParsableClassAttribute)) as ParsableClassAttribute ?? new ParsableClassAttribute("");
     var defaultHelpArgs = parsableClass.ShowHelpParameters;
     
     return token.Type == TokenType.Field && defaultHelpArgs.Contains(token.Value.ToString());
 }
示例#8
0
        private static string GetSyntaxInfo(Parsable parsable, string argumentTemplate, ICollection<char> prefixes)
        {
            var arguments = GetListArgumentAttributes(parsable);

            var sb = new StringBuilder();

            var prefix = "-"; // default
            if (prefixes.Count > 1)
            {
                prefix = prefixes.FirstOrDefault().ToString();
                var allowedPrefixes = "";
                prefixes.ToList().ForEach(x => allowedPrefixes += "'" + x + "',");
                allowedPrefixes = allowedPrefixes.Substring(0, allowedPrefixes.Length - 1);
                sb.AppendLine("The following argument prefix characters can be used: "+allowedPrefixes);
            }

            foreach (var argument in arguments)
            {
                sb.AppendLine(argument.GetSyntax(argumentTemplate, prefix));
            }

            return sb.ToString();
        }
示例#9
0
        private static IEnumerable<ParsableArgumentAttribute> GetListArgumentAttributes(Parsable parsable)
        {
            var parsableType = parsable.GetType();
            var properties = parsableType.GetProperties();

            var arguments = new List<ParsableArgumentAttribute>();
            foreach (var prop in properties)
            {
                arguments.AddRange(prop.GetCustomAttributes(true).OfType<ParsableArgumentAttribute>());
            }
            return arguments;
        }