/// <summary> /// Given a Dictionary in which the Key Represents the Project and the Value represents the list Project Dependencies, generate a DOT Graph. /// </summary> /// <param name="projectReferenceDependencies">The dictionary to generate the graph for.</param> /// <param name="anonymizeNames">Determines if the names should be anonymized.</param> /// <param name="sortProjects">Determines if the output of the DOT Graph should be sorted.</param> /// <param name="showAssemblyReferences">Determines if Assembly/PackageReferences should be shown on the graph.</param> /// <returns>A string that represents a DOT Graph</returns> internal static string CreateDOTGraph(IDictionary <string, IEnumerable <string> > projectReferenceDependencies, MSBPROptions options) { // If we are going to use a anonymizer initialize it Anonymizer <string> anonymizer = null; if (options.AnonymizeNames) { anonymizer = new Anonymizer <string>(); } StringBuilder sb = new StringBuilder(); sb.AppendLine("digraph {"); // If we need to sort the projects do so at this time IEnumerable <KeyValuePair <string, IEnumerable <string> > > projectReferenceDependenciesToPrint = projectReferenceDependencies; if (options.SortProjects) { projectReferenceDependenciesToPrint = projectReferenceDependencies.OrderBy(kvp => Path.GetFileName(kvp.Key)); } // Perform the ProjectReference Results foreach (KeyValuePair <string, IEnumerable <string> > kvp in projectReferenceDependenciesToPrint) { string projectName = Path.GetFileName(kvp.Key); if (options.AnonymizeNames) { projectName = anonymizer.Anonymoize(projectName); } IEnumerable <string> projectReferences = kvp.Value; if (options.SortProjects) { projectReferences = projectReferences.OrderBy(filePath => Path.GetFileName(filePath)); } sb.AppendLine($"\"{projectName}\""); foreach (string projectDependency in projectReferences) { string projectDependencyName = Path.GetFileName(projectDependency); if (options.AnonymizeNames) { projectDependencyName = anonymizer.Anonymoize(projectDependencyName); } sb.AppendLine($"\"{projectName}\" -> \"{projectDependencyName}\""); } } // If we need to show assembly references find them if (options.ShowAssemblyReferences) { sb.AppendLine("//--------------------------"); sb.AppendLine("// AssemblyReference Section"); sb.AppendLine("//--------------------------"); Dictionary <string, IEnumerable <string> > assemblyReferenceDependencies = ResolveAssemblyReferenceDependencies(projectReferenceDependencies.Keys); IEnumerable <string> assemblyReferenceSection = GenerateAssemblyReferenceSection(anonymizer, assemblyReferenceDependencies); if (options.SortProjects) { assemblyReferenceSection = assemblyReferenceSection.OrderBy(x => x); } foreach (string line in assemblyReferenceSection) { sb.AppendLine(line); } } if (options.ShowPackageReferences) { sb.AppendLine("//--------------------------"); sb.AppendLine("// PackageReference Section"); sb.AppendLine("//--------------------------"); Dictionary <string, IEnumerable <string> > packageReferenceDependencies = ResolvePackageReferenceDependencies(projectReferenceDependencies.Keys); IEnumerable <string> packageReferenceSection = GeneratePackageReferenceSection(anonymizer, packageReferenceDependencies); if (options.SortProjects) { packageReferenceSection = packageReferenceSection.OrderBy(x => x); } foreach (string line in packageReferenceSection) { sb.AppendLine(line); } } sb.AppendLine("}"); return(sb.ToString()); }
static void Main(string[] args) { string targetFile = string.Empty; bool showHelp = false; // Create an Options Object MSBPROptions options = new MSBPROptions(); OptionSet p = new OptionSet() { { "<>", Strings.TargetArgumentDescription, v => targetFile = v }, { "a|anonymize", Strings.AnonymizeDescription, v => options.AnonymizeNames = v != null }, { "sA|ShowAllReferences", Strings.ShowAllReferencesDescription, v => { if (v != null) { options.ShowAssemblyReferences = true; options.ShowPackageReferences = true; } } }, { "sar|ShowAssemblyReferences", Strings.ShowAssemblyReferencesDescription, v => options.ShowAssemblyReferences = v != null }, { "spr|ShowPackageReferences", Strings.ShowPackageReferencesDescription, v => options.ShowPackageReferences = v != null }, { "s|sort", Strings.SortDescription, v => options.SortProjects = v != null }, { "?|h|help", Strings.HelpDescription, v => showHelp = v != null }, }; try { p.Parse(args); } catch (OptionException) { Console.WriteLine(Strings.ShortUsageMessage); Console.WriteLine($"Try `{Strings.ProgramName} --help` for more information."); return; } if (showHelp || string.IsNullOrEmpty(targetFile)) { Environment.ExitCode = ShowUsage(p); } else if (!File.Exists(targetFile)) { Console.WriteLine(Strings.InvalidTargetArgument, targetFile); Environment.ExitCode = 9009; } else { List <string> projectsToEvaluate = new List <string>(); if (Path.GetExtension(targetFile).Equals(".sln", StringComparison.InvariantCultureIgnoreCase)) { IEnumerable <string> projectsInSolution = MSBuildUtilities.GetProjectsFromSolution(targetFile); // These come back as relative paths; we need to "expand" them // otherwise we'll get duplicates when we go to resolve. projectsInSolution = projectsInSolution.Select(relativeProjectPath => Path.GetFullPath(relativeProjectPath)); projectsToEvaluate.AddRange(projectsInSolution); } else { // Assume its just a single project FileInfo fi = new FileInfo(targetFile); projectsToEvaluate.Add(fi.FullName); } Dictionary <string, IEnumerable <string> > projectReferenceDependencies = MSBPRDependencyGraph.ResolveProjectReferenceDependencies(projectsToEvaluate); string output = MSBPRDependencyGraph.CreateDOTGraph(projectReferenceDependencies, options); Console.WriteLine(output); } }