예제 #1
0
        private static void Run(InputParameters inputParameters)
        {
            Logger.Information("Run started.");
            Logger.Information(Separator);

            var graph = new AssemblyDependencyGraph();

            var baseDirectory = string.IsNullOrEmpty(inputParameters.BaseDirectory)
                ? new DirectoryInfo(Environment.CurrentDirectory)
                : new DirectoryInfo(inputParameters.BaseDirectory);

            if (!baseDirectory.Exists)
            {
                throw new DirectoryNotFoundException($"The base directory '{baseDirectory.FullName}' was not found.");
            }

            // register assembly sources
            graph.EnsureNodeWithAssemblySourceOrPatterns(inputParameters.Assemblies, baseDirectory);

            // register main assembly
            graph.EnsureNodeWithAssemblySource(inputParameters.MainAssembly, baseDirectory);

            // register additional dependencies
            foreach (var additionalDependency in inputParameters.AdditionalDependencies ?? Enumerable.Empty <InputParameters.AdditionalDependency>())
            {
                var dependant    = graph.EnsureNodeWithAssemblySource(additionalDependency.Dependant, baseDirectory);
                var dependencies = graph.EnsureNodeWithAssemblySourceOrPatterns(additionalDependency.Dependencies, baseDirectory);
                foreach (var dependency in dependencies)
                {
                    graph.RegisterDependency(dependant, dependency);
                }
            }

            // load assemblies from files
            foreach (var node in graph.GetNodesToLoadFromFile())
            {
                graph.LoadNodeFromFile(node);
            }

            // load assemblies from assembly names
            foreach (var node in graph.GetNodesToLoadFromName())
            {
                graph.LoadNodeFromName(node);
            }

            Logger.Information(Separator);
            Logger.Information("Entire graph processed.");

            // locate the main assembly
            var mainNode = graph.EnsureNodeWithAssemblySource(inputParameters.MainAssembly, baseDirectory);

            // write report
            WriteReport(mainNode, graph);

            Logger.Information(Separator);
            Logger.Information("Run finished.");
        }
예제 #2
0
        private static void WriteMainNodeDependants(AssemblyDependencyNode mainNode, AssemblyDependencyGraph graph)
        {
            var mainNodeDependants = graph.GetDirectDependants(mainNode).OrderBy(x => x.Identity).ToList();

            if (mainNodeDependants.Any())
            {
                Logger.Information(Separator);
                Logger.Warning("WARNING: Detected that there are still some assemblies that depend on the main assembly. Try to avoid this scenario. Different binding redirects might be needed for them.");
                foreach (var node in mainNodeDependants)
                {
                    Logger.Information("{AssemblyIdentity}", node.Identity);
                }
            }
        }
예제 #3
0
        private static void WriteDirectDependencies(AssemblyDependencyNode mainNode, AssemblyDependencyGraph graph)
        {
            Logger.Information(Separator);
            Logger.Information("Direct dependencies:");
            Logger.Information("");

            foreach (var dependencyGroup in graph.GetDirectDependencies(mainNode).GroupBy(x => x.Identity.Unversioned).OrderBy(x => x.Key))
            {
                Logger.Information("{AssemblyNameWithVersion}", GetSimpleName(dependencyGroup.Key, dependencyGroup.ToList()));
                foreach (var node in dependencyGroup)
                {
                    Logger.Information("-- {AssemblyIdentity}", node.Identity);
                }

                Logger.Information("");
            }
        }
예제 #4
0
        private static void WriteOtherLeafNodes(AssemblyDependencyNode mainNode, AssemblyDependencyGraph graph, List <AssemblyDependencyNode> nodes)
        {
            var otherLeafNodes = nodes.Where(x => x != mainNode && !graph.GetDirectDependantsByGroup(x.Identity.Unversioned).Any()).ToList();

            if (otherLeafNodes.Any())
            {
                Logger.Information(Separator);
                Logger.Information("Other assemblies that don't have any dependants:");

                foreach (var node in otherLeafNodes)
                {
                    Logger.Warning("{AssemblyName}", node.Name?.FullName ?? node.File.Name);
                }

                Logger.Information("If these assemblies relate to some assembly dynamically, you can add them as an additional dependency on input.");
                Logger.Information("If these are not loaded dynamically, they might also redundant.");
            }
        }
예제 #5
0
        private static void WriteReport(AssemblyDependencyNode mainNode, AssemblyDependencyGraph graph)
        {
            Logger.Information(Separator);
            Logger.Information("Overview for [{AssemblyName}]", mainNode.Name?.ToString() ?? mainNode.File.Name);

            WriteDirectDependencies(mainNode, graph);
            WriteIndirectDependencies(mainNode, graph);
            WriteAllDependencies(mainNode, graph);

            var nodes = graph.GetAllNodes()
                        .OrderBy(x => x.Identity)
                        .ToList();

            WriteAssembliesNotLoaded(nodes, graph);
            WriteAssembliesRedirectedUponLoad(nodes);
            WriteMainNodeDependants(mainNode, graph);
            WriteOtherLeafNodes(mainNode, graph, nodes);

            var allMainDependenciesIncludingEntireGroup = graph.GetAllDependenciesIncludingEntireGroup(mainNode);

            WriteNodesOutsideMainDependencyTree(mainNode, nodes, allMainDependenciesIncludingEntireGroup, graph);
            WriteBindingRedirects(allMainDependenciesIncludingEntireGroup, graph);
        }
예제 #6
0
        private static void WriteAssembliesNotLoaded(List <AssemblyDependencyNode> nodes, AssemblyDependencyGraph graph)
        {
            var nodesByGroup   = nodes.ToLookup(x => x.Identity.Unversioned);
            var nodesNotLoaded = nodes.Where(node => !node.Loaded).ToList();

            if (nodesNotLoaded.Any())
            {
                Logger.Information(Separator);
                Logger.Information("Assemblies that couldn't be loaded:");

                foreach (var node in nodesNotLoaded)
                {
                    Logger.Information(Separator);

                    if (node.Name != null)
                    {
                        Logger.Information("{AssemblyIdentity}", node.Identity);
                    }
                    else
                    {
                        Logger.Information("{File}", node.File.FullName);
                    }

                    Logger.Information("");

                    if (node.LoadedFromName == AssemblyLoadStatus.Failed)
                    {
                        Logger.Information("Couldn't load from assembly name. Exception message:");
                        Logger.Information(node.LoadedFromNameError.Message);
                    }
                    else if (node.LoadedFromFile == AssemblyLoadStatus.Failed)
                    {
                        Logger.Information("Couldn't load from file. Exception message:");
                        Logger.Information(node.LoadedFromFileError.Message);
                    }
                    else
                    {
                        throw new InvalidOperationException("Assembly not attempted to be loaded, something went wrong.");
                    }

                    var directDependants = graph.GetDirectDependants(node).ToList();
                    if (directDependants.Any())
                    {
                        Logger.Information("");
                        Logger.Information("Nodes that depend on this assembly directly:");
                        foreach (var dependant in directDependants)
                        {
                            Logger.Information("{AssemblyIdentity}", dependant.Identity);
                        }

                        var indirectDependants = graph.GetIndirectDependants(node).ToList();
                        if (indirectDependants.Any())
                        {
                            Logger.Information("");
                            Logger.Information("Nodes that depend on this assembly indirectly:");
                            foreach (var dependant in indirectDependants)
                            {
                                Logger.Information("{AssemblyIdentity}", dependant.Identity);
                            }
                        }
                    }
                    else
                    {
                        Logger.Information("");
                        Logger.Information("No nodes that depend on this were found.");
                    }

                    Logger.Information("");
                    Logger.Information("If this is an important reference, consider fixing this reference. Also make sure that you didn't omit it from the inputs.");

                    var otherNodesInGroup = nodesByGroup[node.Identity.Unversioned].Where(x => x != node && x.Loaded).ToList();
                    if (otherNodesInGroup.Any())
                    {
                        Logger.Information("");
                        Logger.Information("Other versions of this assembly were loaded:");
                        foreach (var otherVersionNode in otherNodesInGroup.OrderBy(x => x.Identity.Version))
                        {
                            Logger.Information("{Version}", otherVersionNode.Identity.Version);
                        }

                        if (otherNodesInGroup.All(x => x.Identity.Version < node.Identity.Version))
                        {
                            Logger.Warning("WARNING: This is the highest version of the assembly, yet it wasn't loaded. A downgrading binding redirect might be needed.");
                        }
                    }
                }
            }
        }
예제 #7
0
        private static void WriteNodesOutsideMainDependencyTree(AssemblyDependencyNode mainNode, List <AssemblyDependencyNode> nodes, IList <AssemblyDependencyNode> allMainDependencies, AssemblyDependencyGraph graph)
        {
            var nodesOutsideOfDependencyTree = nodes
                                               .Where(x => x != mainNode && !allMainDependencies.Contains(x))
                                               .Where(x => x.Loaded)
                                               .ToList();

            if (nodesOutsideOfDependencyTree.Any())
            {
                Logger.Information(Separator);
                Logger.Information("All assemblies that aren't in any way connected to the main, but were loaded:");

                foreach (var node in nodesOutsideOfDependencyTree)
                {
                    Logger.Information(Separator);
                    Logger.Warning("{AssemblyIdentity}", node.Identity);

                    var directDependants = graph.GetDirectDependants(node).ToList();
                    if (directDependants.Any())
                    {
                        Logger.Information("");
                        Logger.Information("Nodes that depend on this assembly directly:");
                        foreach (var dependant in directDependants)
                        {
                            Logger.Information("{AssemblyIdentity}", dependant.Identity);
                        }

                        var indirectDependants = graph.GetIndirectDependants(node).ToList();
                        if (indirectDependants.Any())
                        {
                            Logger.Information("");
                            Logger.Information("Nodes that depend on this assembly indirectly:");
                            foreach (var dependant in indirectDependants)
                            {
                                Logger.Information("{AssemblyIdentity}", dependant.Identity);
                            }
                        }
                    }
                    else
                    {
                        Logger.Information("");
                        Logger.Information("No nodes that depend on this were found.");
                    }
                }
            }
        }
예제 #8
0
        private static void WriteBindingRedirects(IList <AssemblyDependencyNode> allMainDependencies, AssemblyDependencyGraph graph)
        {
            var dependenciesGrouped = allMainDependencies
                                      .GroupBy(x => x.Identity.Unversioned)
                                      .Where(x => x.Count() > 1 && x.Any(y => y.Loaded))
                                      .OrderBy(x => x.Key)
                                      .ToList();

            if (dependenciesGrouped.Any())
            {
                Logger.Information(Separator);
                Logger.Information("Recommended binding redirects:");
                var dependentAssemblyTriples = new List <(AssemblyUnversionedIdentity Key, Version highestVersion, Version highestVersionLoaded)>();

                foreach (var group in dependenciesGrouped)
                {
                    Logger.Information(Separator);
                    Logger.Information("{AssemblyName}", group.Key.ToString());

                    Logger.Information("--- Versions ---");
                    foreach (var node in group.OrderBy(x => x.Identity.Version))
                    {
                        Logger.Information("");

                        if (node.Loaded)
                        {
                            Logger.Information("-- {Version} [Location=\"{Location}\"]", node.Identity.Version, node.File.FullName);
                        }
                        else
                        {
                            Logger.Warning("-- {Version} [Not Found]", node.Identity.Version);
                        }

                        var directDependants = graph.GetDirectDependants(node).ToList();
                        if (directDependants.Any())
                        {
                            Logger.Information("");
                            Logger.Information("Nodes that depend on this version directly:");
                            foreach (var dependant in directDependants)
                            {
                                Logger.Information("{AssemblyIdentity}", dependant.Identity);
                            }

                            var indirectDependants = graph.GetIndirectDependants(node).ToList();
                            if (indirectDependants.Any())
                            {
                                Logger.Information("");
                                Logger.Information("Nodes that depend on this version indirectly:");
                                foreach (var dependant in indirectDependants)
                                {
                                    Logger.Information("{AssemblyIdentity}", dependant.Identity);
                                }
                            }
                        }
                        else
                        {
                            Logger.Information("");
                            Logger.Warning("No nodes that depend on this version were found.");
                        }
                    }

                    var highestVersion       = group.Max(x => x.Identity.Version);
                    var highestVersionLoaded = group.Where(x => x.Loaded).Max(x => x.Identity.Version);

                    var dependentAssemblyTriple = (group.Key, highestVersion, highestVersionLoaded);
                    var element = GetAssemblyBindingXElement(dependentAssemblyTriple);

                    Logger.Information("");
                    Logger.Information("--- Recommended redirect ---\n{Element}", element);

                    if (highestVersionLoaded < highestVersion)
                    {
                        Logger.Warning("WARNING: Recommending a downgrading redirect.");
                    }

                    dependentAssemblyTriples.Add(dependentAssemblyTriple);
                }

                if (dependenciesGrouped.Count > 1)
                {
                    Logger.Information(Separator);
                    Logger.Information("Collected binding redirects:");
                    var element = GetAssemblyBindingXElement(dependentAssemblyTriples.ToArray());
                    Logger.Information("\n{Element}", element);
                }
            }
            else
            {
                Logger.Information(Separator);
                Logger.Information("No recommended binding redirects.");
            }
        }