forked from oshvartz/GenerateNugetDependencyGraph
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Program.cs
122 lines (107 loc) · 4.78 KB
/
Program.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
using CommandLine;
using Graphviz4Net;
using Graphviz4Net.Dot;
using Graphviz4Net.Graphs;
using Newtonsoft.Json;
using NuGet.ProjectModel;
using NuGet.Protocol;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace DGVisulizer
{
public class Options
{
[Option('g', "dependency graph", Required = true, HelpText = "Path of the dependency graph generated by msbuild.")]
public string DependencyGrapthPath { get; set; }
[Option('v' ,"graphviz bin", Required = true, HelpText = "Path of the graphviz bin folder.")]
public string GraphvizBinPath { get; set; }
[Option('o', "output file path", Required = true, HelpText = "Path of the output file.")]
public string OutputFilePath { get; set; }
}
class Program
{
//https://www.jerriepelser.com/blog/analyze-dotnet-project-dependencies-part-1/
//dotnet msbuild /t:GenerateRestoreGraphFile /p:RestoreGraphOutputPath=graph.dg
static void Main(string[] args)
{
CommandLine.Parser.Default.ParseArguments<Options>(args)
.WithParsed(GenerateGraph);
}
private static void GenerateGraph(Options options)
{
var dependencyGraph = DependencyGraphSpec.Load(options.DependencyGrapthPath);
var graph = new Graph<string>();
var projectVersions = new Dictionary<string, string>();
foreach (var project in dependencyGraph.Projects.Where(p => p.RestoreMetadata.ProjectStyle == ProjectStyle.PackageReference))
{
//filtering test
if (project.Name.Contains("test", StringComparison.OrdinalIgnoreCase))
{
continue;
}
graph.AddVertex(project.Name);
projectVersions.Add(project.Name, project.Version.ToNormalizedString());
}
foreach (var project in dependencyGraph.Projects.Where(p => p.RestoreMetadata.ProjectStyle == ProjectStyle.PackageReference))
{
//filtering test
if (project.Name.Contains("test", StringComparison.OrdinalIgnoreCase))
{
continue;
}
Console.WriteLine(project.Name);
HashSet<string> dep = new HashSet<string>();
foreach (var targetFramework in project.TargetFrameworks)
{
foreach (var dependency in targetFramework.Dependencies)
{
//remove duplication
if (dep.Contains(dependency.Name))
{
continue;
}
dep.Add(dependency.Name);
if (graph.Vertices.Any(v => v == dependency.Name))
{
var notLastVersion = projectVersions[dependency.Name] != dependency.LibraryRange.VersionRange.ToShortString();
var attributes = new Dictionary<string, string>() { { "label", dependency.LibraryRange.VersionRange.ToShortString() } };
if (notLastVersion)
{
attributes.Add("color", "red");
}
else
{
attributes.Add("color", "green");
}
graph.AddEdge(new Edge<string>(project.Name, dependency.Name, attributes: attributes));
}
}
}
}
var writer = new StringWriter();
new GraphToDotConverter().Convert(writer, graph, new AttributesProvider(projectVersions));
var graphContent = writer.GetStringBuilder().ToString().Trim();
var dotFile = Path.ChangeExtension(options.OutputFilePath,"dot");
File.WriteAllText(dotFile,graphContent);
var dotExec = Path.Combine(options.GraphvizBinPath, "dot.exe");
var arguments = $"-Tjpg {dotFile} -o {options.OutputFilePath}";
ProcessAsyncHelper.ExecuteShellCommand(dotExec , arguments,int.MaxValue).Wait();
}
}
public class AttributesProvider : IAttributesProvider
{
private Dictionary<string, string> versions;
public AttributesProvider(Dictionary<string, string> versions)
{
this.versions = versions;
}
public IDictionary<string, string> GetVertexAttributes(object vertex)
{
var proj = vertex.ToString();
var ver = versions[proj];
return new Dictionary<string, string>() { { "label", vertex.ToString() + "\n" + ver } };
}
}
}