Skip to content

Instantly share code, notes, and snippets.

@jogibear9988
Forked from plaurin/DependenciesVisualizer.linq
Last active August 17, 2018 10:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jogibear9988/90d28cea04cbf8c8ee2ea5763ce24673 to your computer and use it in GitHub Desktop.
Save jogibear9988/90d28cea04cbf8c8ee2ea5763ce24673 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 = @"F:\csharp\git\mcc5\MCC.V1.0";
private string outputFolder = @"F:\csharp\git\mcc5\";
private string nugetFolder = @"C:\Users\jkuehner\.nuget\packages\";
private int intend = 4;
void Main()
{
LoadAllProjects();
LoadAllPackagesConfig();
GenerateDGML(Path.Combine(outputFolder, "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 Package()
{
this.Packages = new List<Package>();
}
public string Name { get; set; }
public string Version { get; set; }
public List<Package> Packages { get; private 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)
{
Debug.WriteLine("Project: " + project.Name);
var projectDoc = XDocument.Load(project.Path);
foreach (var pr in projectDoc.Descendants(ns + "PackageReference"))
{
var package = GetOrCreatePackage(pr.Attribute("Include").Value, pr.Element(ns + "Version").Value);
project.Packages.Add(package);
}
foreach (var pr in projectDoc.Descendants(ns + "ProjectReference"))
{
var prj = projects.SingleOrDefault(p => p.Name == pr.Element(ns + "Name").Value);
if (prj != null) {
if (!this.packages.Any(l => l.Name.Equals(pr.Element(ns + "Name").Value, StringComparison.InvariantCultureIgnoreCase)))
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, int currentLevel = 1)
{
if (version.StartsWith("[") && version.EndsWith("]"))
version = version.Substring(1, version.Length - 2);
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); }
var folderVersion = version;
if (!Directory.Exists(Path.Combine(nugetFolder, name, version))) {
folderVersion = version.Count(x => x == '.') == 3 ? version.Substring(0, version.LastIndexOf('.')) : version;
}
var nuspec = Path.Combine(nugetFolder, name, folderVersion, name + ".nuspec");
Debug.WriteLine("".PadLeft(currentLevel * intend) + name + version);
XNamespace ns = "http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd";
if (File.Exists(nuspec))
{
var depsList = XDocument.Load(nuspec).Descendants(ns + "group");
if (depsList.Any()) {
var deps = depsList.OrderBy(x => x.Attribute("targetFramework").Value == ".NETFramework4.6.2")
.ThenBy(x => x.Attribute("targetFramework").Value == ".NETFramework4.6.1")
.ThenBy(x => x.Attribute("targetFramework").Value == ".NETFramework4.6")
.ThenBy(x => x.Attribute("targetFramework").Value == ".NETFramework4.5")
.ThenBy(x => x.Attribute("targetFramework").Value == ".NETStandard2.0")
.ThenBy(x => x.Attribute("targetFramework").Value == ".NETStandard1.6")
.ThenBy(x => x.Attribute("targetFramework").Value == ".NETStandard1.5")
.ThenBy(x => x.Attribute("targetFramework").Value == ".NETStandard1.4")
.ThenBy(x => x.Attribute("targetFramework").Value == ".NETStandard1.3")
.FirstOrDefault();
if (deps != null) {
foreach (var dep in deps.Descendants())
{
Debug.WriteLine("".PadLeft(currentLevel * intend) + "-> " + dep.Attribute("id").Value + dep.Attribute("version").Value);
var package = GetOrCreatePackage(dep.Attribute("id").Value, dep.Attribute("version").Value, currentLevel++);
if(!p.Packages.Contains(package))
p.Packages.Add(package);
}
}
} else {
var deps = XDocument.Load(nuspec).Descendants(ns + "dependencies").FirstOrDefault();
if (deps != null) {
foreach (var dep in deps.Descendants())
{
Debug.WriteLine("".PadLeft(currentLevel * intend) + "-> " + dep.Attribute("id").Value + dep.Attribute("version").Value);
var package = GetOrCreatePackage(dep.Attribute("id").Value, dep.Attribute("version").Value, currentLevel++);
if(!p.Packages.Contains(package))
p.Packages.Add(package);
}
}
}
} else {
Debug.WriteLine("".PadLeft(currentLevel * intend) + "-> !!! Nuspec not found!");
}
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.OrderBy(x => x.Name).Select (p => CreateNode(p.Name, "Project")),
this.libraries.OrderBy(x => x.Name).Select (l => CreateNode(l.Name, l.IsGAC ? "GAC Library" : "Library", l.Name.Split(',')[0])),
this.packages.OrderBy(x => x.Name).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.packages.SelectMany(p => p.Packages.Select(pa => new { Source = p, Target = pa } ))
.Select (l => CreateLink(l.Source.Name + " " + l.Source.Version, l.Target.Name + " " + l.Target.Version, "Packages Reference")),
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