/// <summary> /// Parses the bebop config file and assigns entries to their corresponding commandline flag. /// </summary> /// <param name="flagStore">A <see cref="CommandLineFlags"/> instance.</param> /// <param name="configPath">The fully qualified path to the bebop config file, or null to trigger searching.</param> /// <returns>true if the config could be parsed without error, otherwise false.</returns> private static bool TryParseConfig(CommandLineFlags flagStore, string?configPath = null) { configPath ??= FindBebopConfig(); if (string.IsNullOrWhiteSpace(configPath)) { return(false); } if (!new FileInfo(configPath).Exists) { return(false); } using var doc = JsonDocument.Parse(File.ReadAllText(configPath)); var root = doc.RootElement; if (root.TryGetProperty("inputFiles", out var inputFileElement)) { flagStore.SchemaFiles = new List <string>(inputFileElement.GetArrayLength()); foreach (var fileElement in inputFileElement.EnumerateArray()) { if (fileElement.GetString() is not { } filePath) { continue; } flagStore.SchemaFiles.Add(filePath); } } if (root.TryGetProperty("inputDirectory", out var inputDirectoryElement)) { flagStore.SchemaDirectory = inputDirectoryElement.GetString(); } if (root.TryGetProperty("generators", out var generatorsElement)) { foreach (var generatorElement in generatorsElement.EnumerateArray()) { if (generatorElement.TryGetProperty("alias", out var aliasElement) && generatorElement.TryGetProperty("destinationPath", out var destinationElement)) { foreach (var flagAttribute in GetFlagAttributes() .Where(flagAttribute => flagAttribute.Attribute.IsGeneratorFlag && flagAttribute.Attribute.Name.Equals(aliasElement.GetString()))) { flagAttribute.Property.SetValue(flagStore, destinationElement.GetString()); } } } } return(true); }
private static async Task <int> Main() { Log.Formatter = CommandLineFlags.FindLogFormatter(Environment.GetCommandLineArgs()); if (!CommandLineFlags.TryParse(Environment.GetCommandLineArgs(), out _flags, out var message)) { await Log.Error(new CompilerException(message)); return(1); } if (_flags.Version) { await Lager.StandardOut($"{ReservedWords.CompilerName} {VersionInfo.Informational}"); return(0); } if (_flags.Help) { await WriteHelpText(); return(0); } if (_flags.CheckSchemaFile is not null) { if (string.IsNullOrWhiteSpace(_flags.CheckSchemaFile)) { await Log.Error(new CompilerException("No textual schema was read from standard input.")); return(1); } return(await CheckSchema(_flags.CheckSchemaFile)); } if (_flags.CheckSchemaFiles is not null) { if (_flags.CheckSchemaFiles.Count > 0) { return(await CheckSchemas(_flags.CheckSchemaFiles)); } await Log.Error(new CompilerException("No schemas specified in check.")); return(1); } if (!_flags.GetParsedGenerators().Any()) { await Log.Error(new CompilerException("No code generators were specified.")); return(1); } if (_flags.SchemaDirectory is not null && _flags.SchemaFiles is not null) { await Log.Error( new CompilerException("Can't specify both an input directory and individual input files")); return(1); } List <string> paths; if (_flags.SchemaDirectory is not null) { paths = new DirectoryInfo(_flags.SchemaDirectory !) .GetFiles($"*.{ReservedWords.SchemaExt}", SearchOption.AllDirectories) .Select(f => f.FullName) .ToList(); } else if (_flags.SchemaFiles is not null) { paths = _flags.SchemaFiles; } else { await Log.Error(new CompilerException("Specify one or more input files with --dir or --files.")); return(1); } if (paths.Count == 0) { await Log.Error(new CompilerException("No input files were found at the specified target location.")); return(1); } foreach (var parsedGenerator in _flags.GetParsedGenerators()) { if (!GeneratorUtils.ImplementedGenerators.ContainsKey(parsedGenerator.Alias)) { await Log.Error(new CompilerException($"'{parsedGenerator.Alias}' is not a recognized code generator")); return(1); } if (string.IsNullOrWhiteSpace(parsedGenerator.OutputFile)) { await Log.Error(new CompilerException("No output file was specified.")); return(1); } var result = await CompileSchema(GeneratorUtils.ImplementedGenerators[parsedGenerator.Alias], paths, new FileInfo(parsedGenerator.OutputFile), _flags.Namespace ?? ""); if (result != Ok) { return(result); } } return(Ok); }
/// <summary> /// Attempts to parse commandline flags into a <see cref="CommandLineFlags"/> instance /// </summary> /// <param name="args">the array of arguments to parse</param> /// <param name="flagStore">An instance which contains all parsed flags and their values</param> /// <param name="errorMessage">A human-friendly message describing why parsing failed.</param> /// <returns> /// If the provided /// <param name="args"></param> /// were parsed this method returns true. /// </returns> public static bool TryParse(string[] args, out CommandLineFlags flagStore, out string errorMessage) { errorMessage = string.Empty; var props = GetFlagAttributes(); var stringBuilder = new IndentedStringBuilder(); stringBuilder.AppendLine("Usage:"); stringBuilder.Indent(4); foreach (var prop in props.Where(prop => !string.IsNullOrWhiteSpace(prop.Attribute.UsageExample))) { stringBuilder.AppendLine($"{ReservedWords.CompilerName} {prop.Attribute.UsageExample}"); } stringBuilder.Dedent(4); stringBuilder.AppendLine(string.Empty); stringBuilder.AppendLine(string.Empty); stringBuilder.AppendLine("Options:"); stringBuilder.Indent(4); foreach (var prop in props) { stringBuilder.AppendLine($"--{prop.Attribute.Name} {prop.Attribute.HelpText}"); } flagStore = new CommandLineFlags(stringBuilder.ToString()); var parsedFlags = GetFlags(args); if (parsedFlags.Count == 0) { if (TryParseConfig(flagStore)) { return(true); } errorMessage = "No commandline flags found."; return(false); } if (parsedFlags.ContainsKey("config")) { var configPath = parsedFlags["config"]; if (string.IsNullOrWhiteSpace(configPath)) { configPath = null; } return(TryParseConfig(flagStore, configPath)); } if (parsedFlags.ContainsKey("help")) { flagStore.Help = true; return(true); } if (parsedFlags.ContainsKey("version")) { flagStore.Version = true; return(true); } foreach (var flag in props) { if (!parsedFlags.ContainsKey(flag.Attribute.Name)) { continue; } var parsedValue = parsedFlags[flag.Attribute.Name]?.Trim(); var propertyType = flag.Property.PropertyType; if (flag.Attribute.Name.Equals("check-schema")) { using var reader = new StreamReader(Console.OpenStandardInput()); flagStore.CheckSchemaFile = reader.ReadToEnd(); continue; } if (propertyType == typeof(bool)) { flag.Property.SetValue(flagStore, true); continue; } if (string.IsNullOrWhiteSpace(parsedValue)) { errorMessage = $"Commandline flag '{flag.Attribute.Name}' was not assigned a value."; return(false); } if (propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(List <>)) { Type itemType = propertyType.GetGenericArguments()[0]; if (!(Activator.CreateInstance(typeof(List <>).MakeGenericType(itemType)) is IList genericList)) { errorMessage = $"Failed to activate '{flag.Property.Name}'."; return(false); } foreach (var item in parsedValue.Split(" ", StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries)) { genericList.Add(Convert.ChangeType(item.Trim(), itemType)); } flag.Property.SetValue(flagStore, genericList, null); } else if (propertyType.IsEnum) { if (!Enum.TryParse(propertyType, parsedValue, true, out var parsedEnum)) { errorMessage = $"Failed to parse '{parsedValue}' into a member of '{propertyType}'."; return(false); } flag.Property.SetValue(flagStore, parsedEnum, null); } else { flag.Property.SetValue(flagStore, Convert.ChangeType(parsedValue, flag.Property.PropertyType), null); } } errorMessage = string.Empty; return(true); }