Skip to content

Instantly share code, notes, and snippets.

@plaurin
Last active August 17, 2018 10:41
Show Gist options
  • Save plaurin/b4bc53428f01dc722afb to your computer and use it in GitHub Desktop.
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
<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