public static bool ShouldAnalyze(Compilation compilation, DurianModule module)
 {
     return
         (IsCSharpCompilationAnalyzer.Analyze(compilation) &&
          DisabledModuleAnalyzer.IsEnabled(module, compilation) &&
          DependencyAnalyzer.Analyze(compilation));
 }
示例#2
0
        public void FetchAssemblyList(string directoryPath)
        {
            ConsoleLogger consoleLogger = new ConsoleLogger(true);

            DirectoryInfo directoryInfo = new DirectoryInfo(directoryPath);

            if (!Directory.Exists(directoryPath))
            {
                consoleLogger.LogMessage(string.Format("Directory: '{0}' does not exist.", directoryPath));
                throw new ArgumentException("Cannot process files in directory: " + directoryPath);
            }

            // For each directory inside the directoryPath, analyze its dependencies
            IEnumerable <string> extensionDirs = Directory.EnumerateDirectories(directoryPath);

            foreach (string extensionDir in extensionDirs)
            {
                IDependencyAnalyzer analyzer = new DependencyAnalyzer()
                {
                    DirectoryInfo = new DirectoryInfo(extensionDir)
                };
                DependencyAnalyzerResult result = analyzer.Analyze(consoleLogger);

                // Output results to Console
                IDependencyVisualizer visualizer = new ConsoleVisualizer(result);
                visualizer.Visualize();

                // Export results to file
                IDependencyVisualizer export = new DgmlExport(result, Path.Combine(directoryPath, extensionDir + ".references.dgml"), consoleLogger);
                export.Visualize();
            }

            Console.Out.WriteLine("Finished fetching assemblies");
        }
示例#3
0
        public void AnalyzeShouldReturnSystemAssemblies()
        {
            var result = DependencyAnalyzer.Analyze(filesToAnalyse, null, logger, options);

            Assert.Contains(result.Assemblies.Values, x => x.AssemblyName.Name == "mscorlib");
            Assert.Contains(result.Assemblies.Values, x => x.AssemblyName.Name == "netstandard");
            Assert.Contains(result.Assemblies.Values, x => x.AssemblyName.Name == "System");
        }
示例#4
0
        public void AnalyzeShouldNotReturnSystemAssembliesWhenFlagIsSet()
        {
            var altOptions = new VisualizerOptions(true, false, "");
            var result     = DependencyAnalyzer.Analyze(filesToAnalyse, null, logger, altOptions);

            Assert.DoesNotContain(result.Assemblies.Values, x => x.AssemblyName.Name == "mscorlib");
            Assert.DoesNotContain(result.Assemblies.Values, x => x.AssemblyName.Name == "netstandard");
            Assert.DoesNotContain(result.Assemblies.Values, x => x.AssemblyName.Name == "System");
        }
示例#5
0
        public void AnalyzeShouldReturnTestAssemblies()
        {
            var result = DependencyAnalyzer.Analyze(filesToAnalyse, null, logger, options);

            Assert.Contains(result.Assemblies.Values, x => x.AssemblyName.Name == "AsmSpy.Core");
            Assert.Contains(result.Assemblies.Values, x => x.AssemblyName.Name == "AsmSpy.Core.Tests");
            Assert.Contains(result.Assemblies.Values, x => x.AssemblyName.Name == "AsmSpy.Core.TestLibrary");
            Assert.Contains(result.Assemblies.Values, x => x.AssemblyName.Name == "xunit.core");
        }
示例#6
0
        public void AnalyzeShouldReturnCorrectAssemblySource()
        {
            var result = DependencyAnalyzer.Analyze(filesToAnalyse, null, logger, options);

            var tests = result.Assemblies.Values.Single(x => x.AssemblyName.Name == "AsmSpy.Core.Tests");

            var mscorlib = tests.References.Single(x => x.AssemblyName.Name == "mscorlib");

            Assert.Equal(AssemblySource.GlobalAssemblyCache, mscorlib.AssemblySource);
        }
示例#7
0
        private DependencyGraph GetDependencyGraph(ILoggerFactory loggerFactory)
        {
            var             analyzer = new DependencyAnalyzer(loggerFactory);
            DependencyGraph graph;

            if (!string.IsNullOrEmpty(Package))
            {
                graph = analyzer.Analyze(Package, Version, Framework);
            }
            else if (Path.GetExtension(Project).Equals(".sln", StringComparison.OrdinalIgnoreCase))
            {
                graph = analyzer.AnalyzeSolution(Project, Framework);
            }
            else
            {
                graph = analyzer.Analyze(Project, Framework);
            }
            return(graph);
        }
示例#8
0
        public void AnalyzeShouldReturnDependencies()
        {
            var exampleClass = new ExampleClass();
            var result       = DependencyAnalyzer.Analyze(filesToAnalyse, null, logger, options);

            var tests = result.Assemblies.Values.Single(x => x.AssemblyName.Name == "AsmSpy.Core.Tests");

            Assert.Contains(tests.References, x => x.AssemblyName.Name == "AsmSpy.Core");
            Assert.Contains(tests.References, x => x.AssemblyName.Name == "AsmSpy.Core.TestLibrary");
            Assert.Contains(tests.References, x => x.AssemblyName.Name == "xunit.core");
            foreach (var reference in tests.References)
            {
                output.WriteLine(reference.AssemblyName.Name);
            }
        }
示例#9
0
        public static int Main(string[] args)
        {
            var commandLineApplication = new CommandLineApplication(throwOnUnexpectedArg: true);
            var directoryOrFile        = commandLineApplication.Argument("directoryOrFile", "The directory to search for assemblies or file path to a single assembly");
            var dgmlExport             = commandLineApplication.Option("-dg|--dgml <filename>", "Export to a dgml file", CommandOptionType.SingleValue);
            var nonsystem             = commandLineApplication.Option("-n|--nonsystem", "Ignore 'System' assemblies", CommandOptionType.NoValue);
            var all                   = commandLineApplication.Option("-a|--all", "List all assemblies and references.", CommandOptionType.NoValue);
            var noconsole             = commandLineApplication.Option("-nc|--noconsole", "Do not show references on console.", CommandOptionType.NoValue);
            var silent                = commandLineApplication.Option("-s|--silent", "Do not show any message, only warnings and errors will be shown.", CommandOptionType.NoValue);
            var bindingRedirect       = commandLineApplication.Option("-b|--bindingredirect", "Create binding-redirects", CommandOptionType.NoValue);
            var referencedStartsWith  = commandLineApplication.Option("-rsw|--referencedstartswith", "Referenced Assembly should start with <string>. Will only analyze assemblies if their referenced assemblies starts with the given value.", CommandOptionType.SingleValue);
            var includeSubDirectories = commandLineApplication.Option("-i|--includesub", "Include subdirectories in search", CommandOptionType.NoValue);
            var configurationFile     = commandLineApplication.Option("-c|--configurationFile", "Use the binding redirects of the given configuration file (Web.config or App.config)", CommandOptionType.SingleValue);
            var failOnMissing         = commandLineApplication.Option("-f|--failOnMissing", "Whether to exit with an error code when AsmSpy detected Assemblies which could not be found", CommandOptionType.NoValue);

            commandLineApplication.HelpOption("-? | -h | --help");
            commandLineApplication.OnExecute(() =>
            {
                var consoleLogger = new ConsoleLogger(!silent.HasValue());

                var directoryOrFilePath = directoryOrFile.Value;
                var directoryPath       = directoryOrFile.Value;

                if (!File.Exists(directoryOrFilePath) && !Directory.Exists(directoryOrFilePath))
                {
                    consoleLogger.LogMessage(string.Format(CultureInfo.InvariantCulture, "Directory or file: '{0}' does not exist.", directoryOrFilePath));
                    return(-1);
                }

                var configurationFilePath = configurationFile.Value();
                if (!string.IsNullOrEmpty(configurationFilePath) && !File.Exists(configurationFilePath))
                {
                    consoleLogger.LogMessage(string.Format(CultureInfo.InvariantCulture, "Directory or file: '{0}' does not exist.", configurationFilePath));
                    return(-1);
                }

                var isFilePathProvided = false;
                var fileName           = "";
                if (File.Exists(directoryOrFilePath))
                {
                    isFilePathProvided = true;
                    fileName           = Path.GetFileName(directoryOrFilePath);
                    directoryPath      = Path.GetDirectoryName(directoryOrFilePath);
                }

                var onlyConflicts = !all.HasValue();
                var skipSystem    = nonsystem.HasValue();
                var searchPattern = includeSubDirectories.HasValue() ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly;

                var directoryInfo = new DirectoryInfo(directoryPath);

                List <FileInfo> fileList;
                if (isFilePathProvided)
                {
                    fileList = directoryInfo.GetFiles(fileName, SearchOption.TopDirectoryOnly).ToList();
                    consoleLogger.LogMessage(string.Format(CultureInfo.InvariantCulture, "Check assemblies referenced in: {0}", directoryOrFilePath));
                }
                else
                {
                    fileList = directoryInfo.GetFiles("*.dll", searchPattern).Concat(directoryInfo.GetFiles("*.exe", searchPattern)).ToList();
                    consoleLogger.LogMessage(string.Format(CultureInfo.InvariantCulture, "Check assemblies in: {0}", directoryInfo));
                }

                AppDomain appDomainWithBindingRedirects = null;
                try
                {
                    var domaininfo = new AppDomainSetup
                    {
                        ConfigurationFile = configurationFilePath
                    };
                    appDomainWithBindingRedirects = AppDomain.CreateDomain("AppDomainWithBindingRedirects", null, domaininfo);
                }
                catch (Exception ex)
                {
                    consoleLogger.LogError($"Failed creating AppDomain from configuration file with message {ex.Message}");
                    return(-1);
                }

                IDependencyAnalyzer analyzer = new DependencyAnalyzer(fileList, appDomainWithBindingRedirects);

                var result = analyzer.Analyze(consoleLogger);

                if (!noconsole.HasValue())
                {
                    IDependencyVisualizer visualizer = new ConsoleVisualizer(result)
                    {
                        SkipSystem = skipSystem, OnlyConflicts = onlyConflicts, ReferencedStartsWith = referencedStartsWith.HasValue() ? referencedStartsWith.Value() : string.Empty
                    };
                    visualizer.Visualize();
                }

                if (dgmlExport.HasValue())
                {
                    IDependencyVisualizer export = new DgmlExport(result, string.IsNullOrWhiteSpace(dgmlExport.Value()) ? Path.Combine(directoryInfo.FullName, "references.dgml") : dgmlExport.Value(), consoleLogger)
                    {
                        SkipSystem = skipSystem
                    };
                    export.Visualize();
                }

                if (bindingRedirect.HasValue())
                {
                    // binding redirect export explicitly doesn't respect SkipSystem
                    IDependencyVisualizer bindingRedirects = new BindingRedirectExport(result, string.IsNullOrWhiteSpace(dgmlExport.Value()) ? Path.Combine(directoryInfo.FullName, "bindingRedirects.xml") : dgmlExport.Value(), consoleLogger);
                    bindingRedirects.Visualize();
                }

                if (failOnMissing.HasValue() && result.MissingAssemblies.Any(x => !skipSystem || !x.IsSystem))
                {
                    return(-1);
                }
                return(0);
            });
            try
            {
                if (args == null || args.Length == 0)
                {
                    commandLineApplication.ShowHelp();
                    return(0);
                }

                return(commandLineApplication.Execute(args));
            }
            catch (CommandParsingException cpe)
            {
                Console.WriteLine(cpe.Message);
                commandLineApplication.ShowHelp();
                return(0);
            }
        }
示例#10
0
        // ReSharper disable once UnusedMember.Local
        private void OnExecute()
        {
            var loggerFactory = LoggerFactory.Create(builder => builder
                                                     .SetMinimumLevel(Verbosity)
                                                     .AddConsole());

            var             analyzer = new DependencyAnalyzer(loggerFactory);
            DependencyGraph graph;

            if (!string.IsNullOrEmpty(Package))
            {
                graph = analyzer.Analyze(Package, Version, Framework);
            }
            else if (Path.GetExtension(Project).Equals(".sln", StringComparison.OrdinalIgnoreCase))
            {
                graph = analyzer.AnalyzeSolution(Project, Framework);
            }
            else
            {
                graph = analyzer.Analyze(Project, Framework);
            }

            Application.Init();

            var top = new CustomWindow();

            var left = new FrameView("Dependencies")
            {
                Width  = Dim.Percent(50),
                Height = Dim.Fill(1)
            };
            var right = new View()
            {
                X      = Pos.Right(left),
                Width  = Dim.Fill(),
                Height = Dim.Fill(1)
            };
            var helpText = new Label("Use arrow keys and Tab to move around. Ctrl+D to toggle assembly visibility. Esc to quit.")
            {
                Y = Pos.AnchorEnd(1)
            };

            var runtimeDepends = new FrameView("Runtime depends")
            {
                Width  = Dim.Fill(),
                Height = Dim.Percent(33f)
            };
            var packageDepends = new FrameView("Package depends")
            {
                Y      = Pos.Bottom(runtimeDepends),
                Width  = Dim.Fill(),
                Height = Dim.Percent(50f)
            };
            var reverseDepends = new FrameView("Reverse depends")
            {
                Y      = Pos.Bottom(packageDepends),
                Width  = Dim.Fill(),
                Height = Dim.Fill()
            };

            var orderedDependencyList = graph.Nodes.OrderBy(x => x.Id).ToImmutableList();
            var dependenciesView      = new ListView(orderedDependencyList)
            {
                CanFocus      = true,
                AllowsMarking = false
            };

            left.Add(dependenciesView);
            var runtimeDependsView = new ListView(Array.Empty <Node>())
            {
                CanFocus      = true,
                AllowsMarking = false
            };

            runtimeDepends.Add(runtimeDependsView);
            var packageDependsView = new ListView(Array.Empty <Node>())
            {
                CanFocus      = true,
                AllowsMarking = false
            };

            packageDepends.Add(packageDependsView);
            var reverseDependsView = new ListView(Array.Empty <Node>())
            {
                CanFocus      = true,
                AllowsMarking = false
            };

            reverseDepends.Add(reverseDependsView);

            right.Add(runtimeDepends, packageDepends, reverseDepends);
            top.Add(left, right, helpText);
            Application.Top.Add(top);

            top.Dependencies        = orderedDependencyList;
            top.VisibleDependencies = orderedDependencyList;
            top.DependenciesView    = dependenciesView;

            dependenciesView.SelectedItem = 0;
            UpdateLists();

            dependenciesView.SelectedChanged += UpdateLists;

            Application.Run();

            void UpdateLists()
            {
                var selectedNode = top.VisibleDependencies[dependenciesView.SelectedItem];

                runtimeDependsView.SetSource(graph.Edges.Where(x => x.Start.Equals(selectedNode) && x.End is AssemblyReferenceNode)
                                             .Select(x => x.End).ToImmutableList());
                packageDependsView.SetSource(graph.Edges.Where(x => x.Start.Equals(selectedNode) && x.End is PackageReferenceNode)
                                             .Select(x => $"{x.End}{(string.IsNullOrEmpty(x.Label) ? string.Empty : " (Wanted: " + x.Label + ")")}").ToImmutableList());
                reverseDependsView.SetSource(graph.Edges.Where(x => x.End.Equals(selectedNode))
                                             .Select(x => $"{x.Start}{(string.IsNullOrEmpty(x.Label) ? string.Empty : " (Wanted: " + x.Label + ")")}").ToImmutableList());
            }
        }
示例#11
0
        public static int Main(string[] args)
        {
            var commandLineApplication = new CommandLineApplication(throwOnUnexpectedArg: true);
            var directoryOrFile        = commandLineApplication.Argument("directoryOrFile", "The directory to search for assemblies or file path to a single assembly");

            var silent = commandLineApplication.Option("-s|--silent", "Do not show any message, only warnings and errors will be shown.", CommandOptionType.NoValue);

            var nonsystem            = commandLineApplication.Option("-n|--nonsystem", "Ignore 'System' assemblies", CommandOptionType.NoValue);
            var all                  = commandLineApplication.Option("-a|--all", "List all assemblies and references.", CommandOptionType.NoValue);
            var referencedStartsWith = commandLineApplication.Option("-rsw|--referencedstartswith", "Referenced Assembly should start with <string>. Will only analyze assemblies if their referenced assemblies starts with the given value.", CommandOptionType.SingleValue);
            var excludeAssemblies    = commandLineApplication.Option("-e|--exclude", "A partial assembly name which should be excluded. This option can be provided multiple times", CommandOptionType.MultipleValue);

            var includeSubDirectories = commandLineApplication.Option("-i|--includesub", "Include subdirectories in search", CommandOptionType.NoValue);
            var configurationFile     = commandLineApplication.Option("-c|--configurationFile", "Use the binding redirects of the given configuration file (Web.config or App.config)", CommandOptionType.SingleValue);
            var failOnMissing         = commandLineApplication.Option("-f|--failOnMissing", "Whether to exit with an error code when AsmSpy detected Assemblies which could not be found", CommandOptionType.NoValue);

            var dependencyVisualizers = GetDependencyVisualizers();

            foreach (var visualizer in dependencyVisualizers)
            {
                visualizer.CreateOption(commandLineApplication);
            }

            commandLineApplication.HelpOption("-? | -h | --help");

            commandLineApplication.OnExecute(() =>
            {
                try
                {
                    var visualizerOptions = new VisualizerOptions
                    {
                        SkipSystem           = nonsystem.HasValue(),
                        OnlyConflicts        = !all.HasValue(),
                        ReferencedStartsWith = referencedStartsWith.HasValue() ? referencedStartsWith.Value() : string.Empty,
                        Exclude = excludeAssemblies.HasValue() ? excludeAssemblies.Values : new List <string>()
                    };

                    var consoleLogger = new ConsoleLogger(!silent.HasValue());

                    var finalResult = GetFileList(directoryOrFile, includeSubDirectories, consoleLogger)
                                      .Bind(x => GetAppDomainWithBindingRedirects(configurationFile)
                                            .Map(appDomain => DependencyAnalyzer.Analyze(
                                                     x.FileList,
                                                     appDomain,
                                                     consoleLogger,
                                                     visualizerOptions,
                                                     x.RootFileName)))
                                      .Map(result => RunVisualizers(result, consoleLogger, visualizerOptions))
                                      .Bind(FailOnMissingAssemblies);

                    switch (finalResult)
                    {
                    case Failure <bool> fail:
                        consoleLogger.LogError(fail.Message);
                        return(-1);

                    case Success <bool> succeed:
                        return(0);

                    default:
                        throw new InvalidOperationException("Unexpected result type");
                    }

                    DependencyAnalyzerResult RunVisualizers(DependencyAnalyzerResult dependencyAnalyzerResult, ILogger logger, VisualizerOptions options)
                    {
                        foreach (var visualizer in dependencyVisualizers.Where(x => x.IsConfigured()))
                        {
                            visualizer.Visualize(dependencyAnalyzerResult, logger, options);
                        }
                        return(dependencyAnalyzerResult);
                    }

                    Result <bool> FailOnMissingAssemblies(DependencyAnalyzerResult dependencyAnalyzerResult)
                    => failOnMissing.HasValue() && dependencyAnalyzerResult.MissingAssemblies.Any()
                            ? "Missing Assemblies"
                            : Result <bool> .Succeed(true);
                }
                catch (Exception exception)
                {
                    Console.WriteLine(exception.ToString());
                    return(-1);
                }
            });

            try
            {
                if (args == null || args.Length == 0)
                {
                    commandLineApplication.ShowHelp();
                    return(0);
                }

                return(commandLineApplication.Execute(args));
            }
            catch (CommandParsingException cpe)
            {
                Console.WriteLine(cpe.Message);
                commandLineApplication.ShowHelp();
                return(-1);
            }
            catch (Exception)
            {
                return(-1);
            }
        }
示例#12
0
文件: Program.cs 项目: llenroc/AsmSpy
        public static void Main(string[] args)
        {
            var commandLineApplication = new CommandLineApplication(false);
            var directory            = commandLineApplication.Argument("directory", "The directory to search for assemblies");
            var dgmlExport           = commandLineApplication.Option("-dg|--dgml <filename>", "Export to a dgml file", CommandOptionType.SingleValue);
            var nonsystem            = commandLineApplication.Option("-n|--nonsystem", "Ignore 'System' assemblies", CommandOptionType.NoValue);
            var all                  = commandLineApplication.Option("-a|--all", "List all assemblies and references.", CommandOptionType.NoValue);
            var noconsole            = commandLineApplication.Option("-nc|--noconsole", "Do not show references on console.", CommandOptionType.NoValue);
            var silent               = commandLineApplication.Option("-s|--silent", "Do not show any message, only warnings and errors will be shown.", CommandOptionType.NoValue);
            var bindingRedirect      = commandLineApplication.Option("-b|--bindingredirect", "Create binding-redirects", CommandOptionType.NoValue);
            var referencedStartsWith = commandLineApplication.Option("-rsw|--referencedstartswith", "Referenced Assembly should start with <string>. Will only analyze assemblies if their referenced assemblies starts with the given value.", CommandOptionType.SingleValue);

            commandLineApplication.HelpOption("-? | -h | --help");
            commandLineApplication.OnExecute(() =>
            {
                var consoleLogger = new ConsoleLogger(!silent.HasValue());

                var directoryPath = directory.Value;
                if (!Directory.Exists(directoryPath))
                {
                    consoleLogger.LogMessage(string.Format(CultureInfo.InvariantCulture, "Directory: '{0}' does not exist.", directoryPath));
                    return(-1);
                }

                var onlyConflicts = !all.HasValue();
                var skipSystem    = nonsystem.HasValue();

                var directoryInfo = new DirectoryInfo(directoryPath);
                var fileList      = directoryInfo.GetFiles("*.dll").Concat(directoryInfo.GetFiles("*.exe"));

                IDependencyAnalyzer analyzer = new DependencyAnalyzer(fileList);

                consoleLogger.LogMessage(string.Format(CultureInfo.InvariantCulture, "Check assemblies in: {0}", directoryInfo));

                var result = analyzer.Analyze(consoleLogger);

                if (!noconsole.HasValue())
                {
                    IDependencyVisualizer visualizer = new ConsoleVisualizer(result)
                    {
                        SkipSystem = skipSystem, OnlyConflicts = onlyConflicts, ReferencedStartsWith = referencedStartsWith.HasValue() ? referencedStartsWith.Value() : string.Empty
                    };
                    visualizer.Visualize();
                }

                if (dgmlExport.HasValue())
                {
                    IDependencyVisualizer export = new DgmlExport(result, string.IsNullOrWhiteSpace(dgmlExport.Value()) ? Path.Combine(directoryInfo.FullName, "references.dgml") : dgmlExport.Value(), consoleLogger);
                    export.Visualize();
                }

                if (bindingRedirect.HasValue())
                {
                    IDependencyVisualizer bindingRedirects = new BindingRedirectExport(result, string.IsNullOrWhiteSpace(dgmlExport.Value()) ? Path.Combine(directoryInfo.FullName, "bindingRedirects.xml") : dgmlExport.Value(), consoleLogger);
                    bindingRedirects.Visualize();
                }

                return(0);
            });
            try
            {
                if (args == null || args.Length == 0)
                {
                    commandLineApplication.ShowHelp();
                }
                else
                {
                    commandLineApplication.Execute(args);
                }
            }
            catch (CommandParsingException cpe)
            {
                Console.WriteLine(cpe.Message);
                commandLineApplication.ShowHelp();
            }
        }
示例#13
0
        // ReSharper disable once UnusedMember.Local
        private void OnExecute()
        {
            var loggerFactory = new LoggerFactory()
                                .AddConsole(Verbosity);
            var analyzer = new DependencyAnalyzer(loggerFactory);
            var graph    = analyzer.Analyze(Project, Framework);

            Application.Init();

            var top = new CustomWindow();

            var left = new FrameView("Dependencies")
            {
                Width  = Dim.Percent(50),
                Height = Dim.Fill(1)
            };
            var right = new View()
            {
                X      = Pos.Right(left),
                Width  = Dim.Fill(),
                Height = Dim.Fill(1)
            };
            var helpText = new Label("Use arrow keys and Tab to move around, Esc to quit.")
            {
                Y = Pos.AnchorEnd(1)
            };

            var runtimeDepends = new FrameView("Runtime depends")
            {
                Width  = Dim.Fill(),
                Height = Dim.Percent(33f)
            };
            var packageDepends = new FrameView("Package depends")
            {
                Y      = Pos.Bottom(runtimeDepends),
                Width  = Dim.Fill(),
                Height = Dim.Percent(50f)
            };
            var reverseDepends = new FrameView("Reverse depends")
            {
                Y      = Pos.Bottom(packageDepends),
                Width  = Dim.Fill(),
                Height = Dim.Fill()
            };

            var orderedDependencyList = graph.Nodes.OrderBy(x => x.Id).ToImmutableList();
            var dependenciesView      = new ListView(orderedDependencyList)
            {
                CanFocus      = true,
                AllowsMarking = false
            };

            left.Add(dependenciesView);
            var runtimeDependsView = new ListView(Array.Empty <Node>())
            {
                CanFocus      = true,
                AllowsMarking = false
            };

            runtimeDepends.Add(runtimeDependsView);
            var packageDependsView = new ListView(Array.Empty <Node>())
            {
                CanFocus      = true,
                AllowsMarking = false
            };

            packageDepends.Add(packageDependsView);
            var reverseDependsView = new ListView(Array.Empty <Node>())
            {
                CanFocus      = true,
                AllowsMarking = false
            };

            reverseDepends.Add(reverseDependsView);

            right.Add(runtimeDepends, packageDepends, reverseDepends);
            top.Add(left, right, helpText);
            Application.Top.Add(top);

            dependenciesView.SelectedItem = 0;
            UpdateLists();

            dependenciesView.SelectedChanged += UpdateLists;

            Application.Run();

            void UpdateLists()
            {
                var selectedNode = orderedDependencyList[dependenciesView.SelectedItem];

                runtimeDependsView.SetSource(graph.Edges.Where(x => x.Start.Equals(selectedNode) && x.End is AssemblyReferenceNode)
                                             .Select(x => x.End).ToImmutableList());
                packageDependsView.SetSource(graph.Edges.Where(x => x.Start.Equals(selectedNode) && x.End is PackageReferenceNode)
                                             .Select(x => $"{x.End}{(string.IsNullOrEmpty(x.Label) ? string.Empty : " (Wanted: " + x.Label + ")")}").ToImmutableList());
                reverseDependsView.SetSource(graph.Edges.Where(x => x.End.Equals(selectedNode))
                                             .Select(x => $"{x.Start}{(string.IsNullOrEmpty(x.Label) ? string.Empty : " (Wanted: " + x.Label + ")")}").ToImmutableList());
            }
        }