Last active
August 17, 2018 10:41
-
-
Save plaurin/b4bc53428f01dc722afb to your computer and use it in GitHub Desktop.
LinqPad query to generate a DMGL of projects, libraries and NuGet packages dependencies
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<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