public static void Main(string[] args) { _masterCsvFile = args[0]; _messageCsvFile = args[1]; _templateDirectory = args[2]; _targetDirectory = args[3]; if (args.Length != 4) { Console.WriteLine("Usage: IncrementalGenerator <RuleInventory CSV file> <FxCop Messages CSV file> <Template Files Directory> <Target Directory>"); } if (!Directory.Exists(_targetDirectory)) { Console.WriteLine("ERROR: target directory doesn't exist: " + _targetDirectory); Console.WriteLine(" (SolutionGenerator could be used to generate all files from scratch)"); return; } _sourceFilesDirectory = Path.Combine(_targetDirectory, "src"); if (!Directory.Exists(_sourceFilesDirectory)) { throw new ArgumentException($"Error: {_sourceFilesDirectory} doesn't exist."); } // Build the list of checks from the rule inventory spreadsheet var allChecks = Utilities.BuildIdToChecksMap(_masterCsvFile, c => c.Port == PortStatus.Yes && (c.RevisedPriority == Priority.High || c.OriginalPriority == Priority.High)); // reorg the dictionary by check name Dictionary <string, CheckData> allChecksByName = new Dictionary <string, CheckData>(); foreach (var pair in allChecks) { Debug.Assert(!allChecksByName.ContainsKey(pair.Value.Name), $"Error: Duplicate check name found: {pair.Value.Name}"); allChecksByName[pair.Value.Name] = pair.Value; } // Read core project files of existing analyzers and build a list of already implemented rules. // We assume all the existing analyzers follow the naming convention. var existingChecksByName = GetExistingChecksFromCoreProjects(_targetDirectory, allChecksByName); // generate a list of existing analyzer projects var existingAnalyzers = new HashSet <string>(); foreach (var analyzer in existingChecksByName.Select(c => c.Value.AnalyzerProject)) { existingAnalyzers.Add(analyzer); } // Build the list of checks that doesn't exist in target directory. var newChecksToAdd = new Dictionary <string, CheckData>(); var newChecksToCreate = new Dictionary <string, CheckData>(); foreach (var check in allChecksByName) { if (existingChecksByName.ContainsKey(check.Key)) { continue; } if (!existingAnalyzers.Contains(check.Value.AnalyzerProject)) { newChecksToCreate[check.Value.Id] = check.Value; } else { newChecksToAdd[check.Value.Id] = check.Value; } } // Add FxCop messages CsvOperations.ParseCheckMessages(_messageCsvFile, newChecksToAdd); // rebuild the data, organized by analyzer project var newChecksToAddByAnalyzer = Utilities.BuildAnalyzerToChecksMap(newChecksToAdd.Values); // generate new files and insert them to existing projects foreach (var pair in newChecksToAddByAnalyzer) { var analyzer = pair.Key; var checks = pair.Value; AddNewChecksToCoreProject(analyzer, checks); AddNewChecksToCSharpProject(analyzer, checks); AddNewChecksToVisualBasicProject(analyzer, checks); AddNewChecksToUnitTestsProject(analyzer, checks); AddNewStringsToResxFile(analyzer, checks); } Console.WriteLine("Added checks:"); foreach (var pair in newChecksToAddByAnalyzer) { Console.WriteLine($"\t{pair.Key}"); foreach (var check in pair.Value) { Console.WriteLine($"\t\t{check.Id}"); } } if (newChecksToCreate.Count > 0) { if (!Directory.Exists(_templateDirectory)) { Console.WriteLine("ERROR: Template files directory doesn't exist: " + _templateDirectory); return; } CsvOperations.ParseCheckMessages(_messageCsvFile, newChecksToCreate); var newChecksToCreateByAnalyzer = Utilities.BuildAnalyzerToChecksMap(newChecksToCreate.Values); // create new projects var projectGuids = new Dictionary <string, Dictionary <string, string> >(); var categories = new Dictionary <string, IEnumerable <string> >(); foreach (var pair in newChecksToCreateByAnalyzer) { categories[pair.Key] = Utilities.GetCategories(pair.Value); } Utilities.EmitAnalyzerProjects(newChecksToCreateByAnalyzer, _targetDirectory, _templateDirectory, categories, projectGuids); Console.WriteLine("Created checks:"); foreach (var pair in newChecksToCreateByAnalyzer) { Console.WriteLine($"\t{pair.Key}"); foreach (var check in pair.Value) { Console.WriteLine($"\t\t{check.Id}"); } } } }
static void Main(string[] args) { _masterCsvFile = args[0]; _messageCsvFile = args[1]; _sourceDirectory = args[2]; _outputDirectory = args[3]; _projectGuids = new Dictionary <string, Dictionary <string, string> >(); bool force = false; if (args.Length == 5 && args[4].Equals("/force")) { force = true; } if (Directory.Exists(_outputDirectory)) { if (!force) { Console.WriteLine("ERROR: can't overwrite existing directory: " + _outputDirectory); Console.WriteLine(" pass /force on the command-line to delete and regenerate this content."); return; } Directory.Delete(_outputDirectory, true); } CopyStarterFilesToOutputLocation(_sourceDirectory, _outputDirectory); // TODOS: add priorization data // Build a global list of checks. This operation ensures // no check id is reused between any entries Dictionary <string, CheckData> checks = Utilities.BuildIdToChecksMap(_masterCsvFile, c => c.Port == PortStatus.Yes || c.Port == PortStatus.Ported); // Add FxCop resolutions as messages for checks ported from FxCop CsvOperations.ParseCheckMessages(_messageCsvFile, checks); // Now we will rebuild the data, organizing it by project Dictionary <string, List <CheckData> > analyzers = Utilities.BuildAnalyzerToChecksMap(checks.Values); _categories = new Dictionary <string, IEnumerable <string> >(); foreach (var pair in analyzers) { _categories[pair.Key] = Utilities.GetCategories(pair.Value); } // Emit projects associated with each analyzer. These include a core project, a C# // project (for C#-specific AST analyzers), a VB project (ditto) and test project Utilities.EmitAnalyzerProjects(analyzers, _outputDirectory, _sourceDirectory, _categories, _projectGuids); // TODO emit table that can be published as wiki page to track porting progress // EmitWikiTable(analyzers); EmitAnalyzerVersionsTargetsFile(analyzers); EmitNuGetPackagingProjFile(analyzers); EmitBuildAndTestProjFile(analyzers); EmitSolution(analyzers); Console.WriteLine("Done"); }