LinqPad query to generate a DMGL of projects, libraries and NuGet packages dependencies
<Query Kind="Program" /> | |
private string[] projectExtensionExclusions = new[] { ".vdproj", ".ndproj", ".wdproj", ".shfbproj" }; | |
private string rootFolder = @"C:\Users\Pascal\Dev\MyProject"; | |
void Main() | |
{ | |
LoadAllProjects(); | |
LoadAllPackagesConfig(); | |
GenerateDGML(Path.Combine(rootFolder, "Dependencies.dgml")); | |
} | |
// Define other methods and classes here | |
private List<Project> projects = new List<Project>(); | |
private List<Package> packages = new List<Package>(); | |
private List<Library> libraries = new List<Library>(); | |
#region "Structs" | |
public class Project | |
{ | |
public Project() | |
{ | |
this.Projects = new List<Project>(); | |
this.Libraries = new List<Library>(); | |
this.Packages = new List<Package>(); | |
} | |
public string Path { get; set; } | |
public string Name { get; set; } | |
public List<Project> Projects { get; private set; } | |
public List<Library> Libraries { get; private set; } | |
public List<Package> Packages { get; private set; } | |
} | |
public class Package | |
{ | |
public string Name { get; set; } | |
public string Version { get; set; } | |
} | |
public class Library | |
{ | |
public string Name { get; set; } | |
public bool IsGAC { get; set; } | |
} | |
#endregion | |
private void LoadAllProjects() | |
{ | |
XNamespace ns = "http://schemas.microsoft.com/developer/msbuild/2003"; | |
var projectFiles = Directory.GetFiles(rootFolder, "*.*proj", SearchOption.AllDirectories) | |
.Where (pf => !projectExtensionExclusions.Any(ex => pf.EndsWith(ex))); | |
foreach (var pf in projectFiles) | |
this.projects.Add(new Project { Path = pf, Name = Path.GetFileNameWithoutExtension(pf) }); | |
// Get all projects, local libraries and GAC references | |
foreach (var project in this.projects) | |
{ | |
var projectDoc = XDocument.Load(project.Path); | |
foreach (var pr in projectDoc.Descendants(ns + "ProjectReference")) | |
{ | |
var prj = projects.SingleOrDefault(p => p.Name == pr.Element(ns + "Name").Value); | |
if (prj != null) | |
project.Projects.Add(prj); | |
else | |
(pr.Element(ns + "Name").Value + " project reference not found in file " + project.Path).Dump(); | |
} | |
foreach (var r in projectDoc.Descendants(ns + "Reference").Where (r => !r.Value.Contains(@"\packages\"))) | |
project.Libraries.Add(GetOrCreateLibrary(r.Attribute("Include").Value, !r.Elements(ns + "HintPath").Any())); | |
} | |
} | |
private void LoadAllPackagesConfig() | |
{ | |
foreach (var pk in Directory.GetFiles(rootFolder, "packages.config", SearchOption.AllDirectories) | |
.Where (pc => !pc.Contains(".nuget"))) | |
{ | |
var project = this.projects.SingleOrDefault(p => Path.GetDirectoryName(p.Path) == Path.GetDirectoryName(pk)); | |
if (project == null) | |
("Project not found in same folder than package " + pk).Dump(); | |
else | |
{ | |
foreach (var pr in XDocument.Load(pk).Descendants("package")) | |
{ | |
var package = GetOrCreatePackage(pr.Attribute("id").Value, pr.Attribute("version").Value); | |
project.Packages.Add(package); | |
} | |
} | |
} | |
} | |
private Package GetOrCreatePackage(string name, string version) | |
{ | |
var p = this.packages.SingleOrDefault (l => l.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase) && l.Version == version); | |
if (p == null) { p = new Package { Name = name, Version = version }; this.packages.Add(p); } | |
return p; | |
} | |
private Library GetOrCreateLibrary(string name, bool isGAC) | |
{ | |
var lib = this.libraries.SingleOrDefault (l => l.Name == name); | |
if (lib == null) { lib = new Library { Name = name, IsGAC = isGAC }; this.libraries.Add(lib); } | |
return lib; | |
} | |
#region DGML | |
private XNamespace dgmlns = "http://schemas.microsoft.com/vs/2009/dgml"; | |
private void GenerateDGML(string filename) | |
{ | |
var graph = new XElement(dgmlns + "DirectedGraph", new XAttribute("GraphDirection", "LeftToRight"), | |
new XElement(dgmlns + "Nodes", | |
this.projects.Select (p => CreateNode(p.Name, "Project")), | |
this.libraries.Select (l => CreateNode(l.Name, l.IsGAC ? "GAC Library" : "Library", l.Name.Split(',')[0])), | |
this.packages.Select (p => CreateNode(p.Name + " " + p.Version, "Package")), | |
CreateNode("AllProjects", "Project", label: "All Projects", @group: "Expanded"), | |
CreateNode("AllPackages", "Package", label: "All Packages", @group: "Expanded"), | |
CreateNode("LocalLibraries", "Library", label: "Local Libraries", @group: "Expanded"), | |
CreateNode("GlobalAssemblyCache", "GAC Library", label: "Global Assembly Cache", @group: "Collapsed")), | |
new XElement(dgmlns + "Links", | |
this.projects.SelectMany(p => p.Projects.Select(pr => new { Source = p, Target = pr } )) | |
.Select (l => CreateLink(l.Source.Name, l.Target.Name, "Project Reference")), | |
this.projects.SelectMany(p => p.Libraries.Select(l => new { Source = p, Target = l } )) | |
.Select (l => CreateLink(l.Source.Name, l.Target.Name, "Library Reference")), | |
this.projects.SelectMany(p => p.Packages.Select(pa => new { Source = p, Target = pa } )) | |
.Select (l => CreateLink(l.Source.Name, l.Target.Name + " " + l.Target.Version, "Installed Package")), | |
this.projects.Select (p => CreateLink("AllProjects", p.Name, "Contains")), | |
this.packages.Select (p => CreateLink("AllPackages", p.Name + " " + p.Version, "Contains")), | |
this.libraries.Where (l => !l.IsGAC).Select (l => CreateLink("LocalLibraries", l.Name, "Contains")), | |
this.libraries.Where (l => l.IsGAC).Select (l => CreateLink("GlobalAssemblyCache", l.Name, "Contains"))), | |
// No need to declare Categories, auto generated | |
new XElement(dgmlns + "Styles", | |
CreateStyle("Project", "Blue"), | |
CreateStyle("Package", "Purple"), | |
CreateStyle("Library", "Green"), | |
CreateStyle("GAC Library", "LightGreen"))); | |
var doc = new XDocument(graph); | |
doc.Save(filename); | |
} | |
private XElement CreateNode(string name, string category, string label = null, string @group = null) | |
{ | |
var labelAtt = label != null ? new XAttribute("Label", label) : null; | |
var groupAtt = @group != null ? new XAttribute("Group", @group) : null; | |
return new XElement(dgmlns + "Node", new XAttribute("Id", name), labelAtt, groupAtt, new XAttribute("Category", category)); | |
} | |
private XElement CreateLink(string source, string target, string category) | |
{ | |
return new XElement(dgmlns + "Link", new XAttribute("Source", source), new XAttribute("Target", target), new XAttribute("Category", category)); | |
} | |
private XElement CreateStyle(string label, string color) | |
{ | |
return new XElement(dgmlns + "Style", new XAttribute("TargetType", "Node"), new XAttribute("GroupLabel", label), new XAttribute("ValueLabel", "True"), | |
new XElement(dgmlns + "Condition", new XAttribute("Expression", "HasCategory('" + label + "')")), | |
new XElement(dgmlns + "Setter", new XAttribute("Property", "Background"), new XAttribute("Value", color))); | |
} | |
#endregion |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment