diff --git a/NuGet.Config b/NuGet.Config index 7604d0051e16..cbeb8fa20d8f 100644 --- a/NuGet.Config +++ b/NuGet.Config @@ -2,6 +2,7 @@ + diff --git a/Universe.sln b/Universe.sln index c4f59d60fe02..d1dd9a12a560 100644 --- a/Universe.sln +++ b/Universe.sln @@ -3,8 +3,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 VisualStudioVersion = 15.0.26228.0 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BuildGraph", "tools\BuildGraph\BuildGraph.csproj", "{B0621D49-4770-4552-9425-D6BD2CF0FB50}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PinVersions", "tools\PinVersions\PinVersions.csproj", "{DACA9DFB-508E-45EA-A5CF-C0F5C2BA181B}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "shared", "shared", "{085280EC-7055-426A-BF9C-1B692B9599AB}" @@ -18,10 +16,6 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {B0621D49-4770-4552-9425-D6BD2CF0FB50}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B0621D49-4770-4552-9425-D6BD2CF0FB50}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B0621D49-4770-4552-9425-D6BD2CF0FB50}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B0621D49-4770-4552-9425-D6BD2CF0FB50}.Release|Any CPU.Build.0 = Release|Any CPU {DACA9DFB-508E-45EA-A5CF-C0F5C2BA181B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {DACA9DFB-508E-45EA-A5CF-C0F5C2BA181B}.Debug|Any CPU.Build.0 = Debug|Any CPU {DACA9DFB-508E-45EA-A5CF-C0F5C2BA181B}.Release|Any CPU.ActiveCfg = Release|Any CPU diff --git a/build/RepositoryBuild.targets b/build/RepositoryBuild.targets index f733ef2caef5..52fe532c3842 100644 --- a/build/RepositoryBuild.targets +++ b/build/RepositoryBuild.targets @@ -1,14 +1,13 @@ - - - + %(RepositoryToBuildInOrder.Order) %(RepositoryToBuildInOrder.Identity) RepositoryToBuild=%(RepositoryToBuildInOrder.Identity); - BuildRepositoryRoot=$(_CloneRepositoryRoot)%(RepositoryToBuildInOrder.Identity)\ + BuildRepositoryRoot=%(RepositoryToBuildInOrder.RepositoryPath)\; + CommitHash=%(RepositoryToBuildInOrder.Commit) @@ -18,26 +17,6 @@ false - - - - - - - - + + $(RepositoryBuildArguments) /p:BuildNumber=$(BuildNumber) /p:Configuration=$(Configuration) /p:CommitHash=$(CommitHash) + $(_RepositoryBuildTargets) $(RepositoryBuildArguments) $(BuildRepositoryRoot)artifacts $(RepositoryArtifactsRoot)\build\ @@ -83,26 +65,27 @@ + DestinationFolder="$(BuildDir)" /> + DestinationFolder="$(ArtifactsDir)msbuild\$(RepositoryToBuild)\%(RecursiveDir)" /> - + + $(RepositoryRoot)tools\PinVersions\bin\$(Configuration)\netcoreapp1.1\PinVersions.dll - $(DotNetPath) $(PinToolBinary) --graph-specs-root "$(_RestoreGraphSpecsDirectory) " -s "$(UniverseBuildDir) " "$(BuildRepositoryRoot) " + $(DotNetPath) $(PinToolBinary) --graph-specs-root "$(_RestoreGraphSpecsDirectory) " -s "$(BuildDir) " "$(BuildRepositoryRoot) " $(PinVersionArgs) -s "$(_DependencyPackagesDirectory) " diff --git a/build/repo.targets b/build/repo.targets index 7aa7207cf223..2aa28e05ab34 100644 --- a/build/repo.targets +++ b/build/repo.targets @@ -1,8 +1,9 @@ + + https://dotnet.myget.org/F/aspnetcore-volatile-dev/api/v2/package - <_BuildGraphFile>$(BuildDir)BuildGraph.proj <_CloneRepositoryRoot>$(RepositoryRoot).r\ <_DependencyBuildDirectory>$(RepositoryRoot).deps\build\ <_DependencyPackagesDirectory>$(_DependencyBuildDirectory) @@ -33,7 +34,7 @@ - + <_RepositoriesToInclude Include="$(KOREBUILD_REPOSITORY_INCLUDE)" /> - + + + - + <_CloneRepository Include="$(MSBuildProjectFullPath)"> @@ -72,6 +75,7 @@ + @@ -107,45 +111,9 @@ - - - - $(RepositoryBuildArguments) /p:BuildNumber=$(BuildNumber) /p:Configuration=$(Configuration) - - <_BuildRepositoryProperties> - UniverseBuildDir=$(BuildDir); - UniverseMSBuildDir=$(ArtifactsDir)msbuild; - BuildInParallel=$(BuildInParallel); - Configuration=$(Configuration); - DotNetPath=$(DotNetPath); - KoreBuildDirectory=$(MSBuildProjectDirectory)\; - KoreBuildProject=$(MSBuildProjectFile); - RepositoryRoot=$(RepositoryRoot); - _BuildGraphFile=$(_BuildGraphFile); - _CloneRepositoryRoot=$(_CloneRepositoryRoot); - _DependencyPackagesDirectory=$(_DependencyPackagesDirectory); - _RepositoryBuildTargets=$(_RepositoryBuildTargets); - RepositoryBuildArguments=$(RepositoryBuildArguments); - _RestoreGraphSpecsDirectory=$(_RestoreGraphSpecsDirectory); - PackagePublisherPath=$(PackagePublisherNetCoreApp) - - - <_BuildRepositoryProperties Condition="'$(PublishPackages)'=='true'"> - $(_BuildRepositoryProperties); - APIKey=$(APIKey); - NuGetPublishVolatileFeed=$(NuGetPublishVolatileFeed); - PublishPackages=$(PublishPackages) - - - - - + DependsOnTargets="_PrepareRepositories;_FindDotNetPath;_CreateRepositoriesListWithCommits;_UpdateNuGetConfig;_GenerateBuildGraph;_BuildRepositories" /> - + %(Repository.Identity) @@ -154,22 +122,26 @@ RestoreGraphOutputPath=$(_RestoreGraphSpecsDirectory)%(Solution.Repository)\%(Solution.FileName)%(Solution.Extension).json + + + + + - - - $(DotNetPath) run -r "$(_CloneRepositoryRoot) " --graph-specs-root "$(_RestoreGraphSpecsDirectory) " "$(_BuildGraphFile)" - $(BuildGrapArgs) --start-at $(BuildGraphOf) - - + + + + @@ -216,16 +188,14 @@ --> <_CloneUrl>$([System.Environment]::GetEnvironmentVariable("vcsroot.%(Repository.Identity).url")) <_CommitHash>$([System.Environment]::GetEnvironmentVariable("build.vcs.number.%(Repository.Identity)")) - - $(_CloneRepositoryRoot)%(Repository.Identity) + Condition="!Exists('%(Repository.RepositoryPath)')" /> + WorkingDirectory="%(Repository.RepositoryPath)" + Condition="'$(_CommitHash)'=='' AND Exists('%(Repository.RepositoryPath)')"> diff --git a/build/tasks/BuildGraph/CalculateBuildGraph.cs b/build/tasks/BuildGraph/CalculateBuildGraph.cs new file mode 100644 index 000000000000..6e1dc6de2b4a --- /dev/null +++ b/build/tasks/BuildGraph/CalculateBuildGraph.cs @@ -0,0 +1,65 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Linq; +using RepoTools.BuildGraph; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; + +namespace RepoTasks +{ + public class CalculateBuildGraph : Task + { + [Required] + public ITaskItem[] Repositories { get; set; } + + [Output] + public ITaskItem[] RepositoriesToBuildInOrder { get; set; } + + /// + /// The repository at which to root the graph at + /// + public string StartGraphAt { get; set; } + + /// + /// Directory that contains the package spec files. + /// + [Required] + public string PackageSpecsDirectory { get; set; } + + public override bool Execute() + { + var graphSpecProvider = new DependencyGraphSpecProvider(PackageSpecsDirectory.Trim()); + + var repositoryPaths = Repositories.Select(r => r.GetMetadata("RepositoryPath")).ToList(); + var repositories = Repository.ReadAllRepositories(repositoryPaths, graphSpecProvider); + + var graph = GraphBuilder.Generate(repositories, StartGraphAt); + var repositoriesWithOrder = new List<(ITaskItem repository, int order)>(); + foreach (var repositoryTaskItem in Repositories) + { + var repositoryName = repositoryTaskItem.ItemSpec; + var graphNodeRepository = graph.First(g => g.Repository.Name == repositoryName); + var order = TopologicalSort.GetOrder(graphNodeRepository); + repositoryTaskItem.SetMetadata("Order", order.ToString()); + repositoriesWithOrder.Add((repositoryTaskItem, order)); + } + + Log.LogMessage(MessageImportance.High, "Repository build order:"); + foreach (var buildGroup in repositoriesWithOrder.GroupBy(r => r.order).OrderBy(g => g.Key)) + { + var buildGroupRepos = buildGroup.Select(b => b.repository.ItemSpec); + Log.LogMessage(MessageImportance.High, $"{buildGroup.Key.ToString().PadLeft(2, ' ')}: {string.Join(", ", buildGroupRepos)}"); + } + + RepositoriesToBuildInOrder = repositoriesWithOrder + .OrderBy(r => r.order) + .Select(r => r.repository) + .ToArray(); + + return true; + } + } +} diff --git a/build/tasks/BuildGraph/DependencyGraphSpecProvider.cs b/build/tasks/BuildGraph/DependencyGraphSpecProvider.cs new file mode 100644 index 000000000000..805033c1c2ed --- /dev/null +++ b/build/tasks/BuildGraph/DependencyGraphSpecProvider.cs @@ -0,0 +1,21 @@ +using System.IO; +using NuGet.ProjectModel; + +namespace RepoTools.BuildGraph +{ + public class DependencyGraphSpecProvider + { + readonly string _packageSpecDirectory; + + public DependencyGraphSpecProvider(string packageSpecDirectory) + { + _packageSpecDirectory = packageSpecDirectory; + } + + public DependencyGraphSpec GetDependencyGraphSpec(string repositoryName, string solutionPath) + { + var outputFile = Path.Combine(_packageSpecDirectory, repositoryName, Path.GetFileName(solutionPath) + ".json"); + return DependencyGraphSpec.Load(outputFile); + } + } +} diff --git a/tools/BuildGraph/GraphBuilder.cs b/build/tasks/BuildGraph/GraphBuilder.cs similarity index 92% rename from tools/BuildGraph/GraphBuilder.cs rename to build/tasks/BuildGraph/GraphBuilder.cs index 0cf9fc7f241c..81993354332c 100644 --- a/tools/BuildGraph/GraphBuilder.cs +++ b/build/tasks/BuildGraph/GraphBuilder.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Linq; -namespace BuildGraph +namespace RepoTools.BuildGraph { public static class GraphBuilder { @@ -19,7 +19,7 @@ public static IList Generate(IList repositories, string r foreach (var project in repositories.SelectMany(r => r.AllProjects)) { var thisProjectRepositoryNode = graphNodes[project.Repository]; - if (root != null && string.Equals(root, project.Repository.Name, StringComparison.OrdinalIgnoreCase)) + if (!string.IsNullOrEmpty(root) && string.Equals(root, project.Repository.Name, StringComparison.OrdinalIgnoreCase)) { searchRoot = thisProjectRepositoryNode; } @@ -58,4 +58,4 @@ private static void Visit(HashSet results, GraphNode searchRoot) } } } -} \ No newline at end of file +} diff --git a/tools/BuildGraph/GraphNode.cs b/build/tasks/BuildGraph/GraphNode.cs similarity index 92% rename from tools/BuildGraph/GraphNode.cs rename to build/tasks/BuildGraph/GraphNode.cs index 236ff6aee5de..8c2a023ab2e2 100644 --- a/tools/BuildGraph/GraphNode.cs +++ b/build/tasks/BuildGraph/GraphNode.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using System.Diagnostics; -namespace BuildGraph +namespace RepoTools.BuildGraph { [DebuggerDisplay("{Repository.Name}")] public class GraphNode diff --git a/tools/BuildGraph/Project.cs b/build/tasks/BuildGraph/Project.cs similarity index 93% rename from tools/BuildGraph/Project.cs rename to build/tasks/BuildGraph/Project.cs index af8761e82922..10a821a336b1 100644 --- a/tools/BuildGraph/Project.cs +++ b/build/tasks/BuildGraph/Project.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Diagnostics; -namespace BuildGraph +namespace RepoTools.BuildGraph { [DebuggerDisplay("{Name}")] public class Project @@ -20,4 +20,4 @@ public Project(string name) public ISet PackageReferences { get; } = new HashSet(StringComparer.OrdinalIgnoreCase); } -} \ No newline at end of file +} diff --git a/tools/BuildGraph/Repository.cs b/build/tasks/BuildGraph/Repository.cs similarity index 79% rename from tools/BuildGraph/Repository.cs rename to build/tasks/BuildGraph/Repository.cs index e8893d7ff878..c71ade8555cc 100644 --- a/tools/BuildGraph/Repository.cs +++ b/build/tasks/BuildGraph/Repository.cs @@ -6,9 +6,8 @@ using System.Threading.Tasks; using NuGet.LibraryModel; using NuGet.ProjectModel; -using UniverseTools; -namespace BuildGraph +namespace RepoTools.BuildGraph { [DebuggerDisplay("{Name}")] public class Repository : IEquatable @@ -26,25 +25,17 @@ public Repository(string name) public IEnumerable AllProjects => Projects.Concat(SupportProjects); - public static IList ReadAllRepositories(string repositoriesRoot, DependencyGraphSpecProvider provider) + public static IList ReadAllRepositories(IList repositoryPaths, DependencyGraphSpecProvider provider) { - var directories = new DirectoryInfo(repositoriesRoot).GetDirectories(); - var repositories = new Repository[directories.Length]; + var repositories = new Repository[repositoryPaths.Count]; - var sw = Stopwatch.StartNew(); - Parallel.For(0, directories.Length, new ParallelOptions { MaxDegreeOfParallelism = 6 }, i => + Parallel.For(0, repositoryPaths.Count, new ParallelOptions { MaxDegreeOfParallelism = 6 }, i => { - var directoryInfo = directories[i]; - Console.WriteLine($"Gathering dependency information from {directoryInfo.Name}."); - - var repository = Read(provider, directoryInfo.Name, directoryInfo.FullName); + var repositoryPath = repositoryPaths[i]; + var repositoryName = Path.GetFileName(repositoryPath); + var repository = Read(provider, repositoryName, repositoryPath); repositories[i] = repository; - - Console.WriteLine($"Done gathering dependency information from {directoryInfo.Name}."); }); - sw.Stop(); - - Console.WriteLine($"Done reading dependency information for all repos in {sw.Elapsed}."); return repositories; } @@ -58,7 +49,8 @@ private static Repository Read(DependencyGraphSpecProvider provider, string name var repository = new Repository(name); ReadSharedSourceProjects(Path.Combine(repositoryPath, "shared"), repository, repository.Projects); - var srcDirectory = Path.Combine(repositoryPath, "src"); + var srcDirectory = Path.GetFullPath(Path.Combine(repositoryPath, "src")) + .Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar); var solutionFiles = Directory.EnumerateFiles(repositoryPath, "*.sln"); foreach (var file in solutionFiles) @@ -67,7 +59,8 @@ private static Repository Read(DependencyGraphSpecProvider provider, string name var projects = spec.Projects.OrderBy(p => p.RestoreMetadata.ProjectStyle == ProjectStyle.PackageReference ? 0 : 1); foreach (var specProject in projects) { - var projectPath = Path.GetFullPath(specProject.FilePath); + var projectPath = Path.GetFullPath(specProject.FilePath) + .Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar); var projectGroup = projectPath.StartsWith(srcDirectory, StringComparison.OrdinalIgnoreCase) ? repository.Projects : @@ -126,4 +119,4 @@ private static void ReadSharedSourceProjects(string sharedSourceProjectsRoot, Re } } } -} \ No newline at end of file +} diff --git a/tools/BuildGraph/TopologicalSort.cs b/build/tasks/BuildGraph/TopologicalSort.cs similarity index 97% rename from tools/BuildGraph/TopologicalSort.cs rename to build/tasks/BuildGraph/TopologicalSort.cs index 308d9eef7729..4d362be3e4c3 100644 --- a/tools/BuildGraph/TopologicalSort.cs +++ b/build/tasks/BuildGraph/TopologicalSort.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Linq; -namespace BuildGraph +namespace RepoTools.BuildGraph { public class TopologicalSort : IComparer { diff --git a/build/tasks/RepoTasks.csproj b/build/tasks/RepoTasks.csproj new file mode 100644 index 000000000000..d0f925d5d183 --- /dev/null +++ b/build/tasks/RepoTasks.csproj @@ -0,0 +1,13 @@ + + + + + netstandard2.0 + + + + + + + + diff --git a/build/tasks/RepoTasks.tasks b/build/tasks/RepoTasks.tasks new file mode 100644 index 000000000000..b858cdc4aa21 --- /dev/null +++ b/build/tasks/RepoTasks.tasks @@ -0,0 +1,7 @@ + + + <_RepoTaskAssembly>$(MSBuildThisFileDirectory)bin\publish\RepoTasks.dll + + + + \ No newline at end of file diff --git a/tools/BuildGraph/BuildGraph.csproj b/tools/BuildGraph/BuildGraph.csproj deleted file mode 100644 index f330542012d0..000000000000 --- a/tools/BuildGraph/BuildGraph.csproj +++ /dev/null @@ -1,16 +0,0 @@ - - - - Exe - netcoreapp1.1 - - - - - - - - - - - \ No newline at end of file diff --git a/tools/BuildGraph/DGMLFormatter.cs b/tools/BuildGraph/DGMLFormatter.cs deleted file mode 100644 index 23ea409cb1cd..000000000000 --- a/tools/BuildGraph/DGMLFormatter.cs +++ /dev/null @@ -1,56 +0,0 @@ -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Xml.Linq; - -namespace BuildGraph -{ - public class DGMLFormatter : GraphFormatter - { - public override void Format(IList nodes, string outputPath) - { - var xmlns = XNamespace.Get("http://schemas.microsoft.com/vs/2009/dgml"); - var xdoc = new XDocument( - new XElement(xmlns + "DirectedGraph", - new XElement(xmlns + "Nodes", GetNodes(xmlns, nodes).ToArray()), - new XElement(xmlns + "Links", GetLinks(xmlns, nodes).ToArray()), - new XElement(xmlns + "Properties", GetProperties(xmlns).ToArray()))); - - using (var writer = File.OpenWrite(outputPath)) - { - xdoc.Save(writer); - } - } - - private IEnumerable GetLinks(XNamespace xmlns, IEnumerable nodes) - { - foreach (var node in nodes) - { - foreach (var outgoing in node.Outgoing) - { - yield return new XElement(xmlns + "Link", - new XAttribute("Source", node.Repository.Name), - new XAttribute("Target", outgoing.Repository.Name)); - } - } - } - - private IEnumerable GetNodes(XNamespace xmlns, IEnumerable nodes) - { - foreach (var node in nodes) - { - yield return new XElement(xmlns + "Node", - new XAttribute("Id", node.Repository.Name), - new XAttribute("Label", $"{node.Repository.Name}")); - } - } - - private IEnumerable GetProperties(XNamespace xmlns) - { - yield return new XElement(xmlns + "Property", - new XAttribute("Id", "Label"), - new XAttribute("Label", "Label"), - new XAttribute("DataType", "String")); - } - } -} \ No newline at end of file diff --git a/tools/BuildGraph/GraphFormatter.cs b/tools/BuildGraph/GraphFormatter.cs deleted file mode 100644 index 878dacd4fe6a..000000000000 --- a/tools/BuildGraph/GraphFormatter.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.Collections.Generic; - -namespace BuildGraph -{ - public abstract class GraphFormatter - { - public abstract void Format(IList nodes, string outputPath); - } -} \ No newline at end of file diff --git a/tools/BuildGraph/MSBuildGraphFormatter.cs b/tools/BuildGraph/MSBuildGraphFormatter.cs deleted file mode 100644 index 4867ff217e91..000000000000 --- a/tools/BuildGraph/MSBuildGraphFormatter.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Xml.Linq; - -namespace BuildGraph -{ - public class MSBuildGraphFormatter : GraphFormatter - { - public override void Format(IList nodes, string outputPath) - { - var sortedNodes = nodes.Select(node => new { Repository = node.Repository, Order = TopologicalSort.GetOrder(node) }) - .OrderBy(item => item.Order); - var projectElement = new XElement("Project", - new XElement("ItemGroup", - sortedNodes.Select(item => new XElement("RepositoryToBuildInOrder", - new XAttribute("Include", item.Repository.Name), - new XAttribute("Order", item.Order))))); - - File.WriteAllText(outputPath, projectElement.ToString()); - } - } -} \ No newline at end of file diff --git a/tools/BuildGraph/Program.cs b/tools/BuildGraph/Program.cs deleted file mode 100644 index 3271204a7c57..000000000000 --- a/tools/BuildGraph/Program.cs +++ /dev/null @@ -1,84 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using Microsoft.Extensions.CommandLineUtils; -using UniverseTools; - -namespace BuildGraph -{ - class Program - { - static int Main(string[] args) - { - var app = new CommandLineApplication(); - var outputTypeOption = app.Option("--output-type", - "Output type of generated graph. Valid values are: msbuild, and dgml.", - CommandOptionType.SingleValue); - - var repositoriesRootOption = app.Option("-r|--repositories-root", - "Directory containing repositories to calculate graph for.", - CommandOptionType.SingleValue); - - var packageSpecsDirectoryOption = app.Option("--graph-specs-root", - "Directory containing package specs. (Optional)", - CommandOptionType.SingleValue); - - var graphRoot = app.Option("--start-at", - "Calculate the build graph starting at the specified repo. (Optional)", - CommandOptionType.SingleValue); - - var outputPathArgument = app.Argument("Output path", "Output path"); - - app.OnExecute(() => - { - if (!repositoriesRootOption.HasValue()) - { - Console.Error.WriteLine($"Option {repositoriesRootOption.Template} must have a value."); - return 1; - } - - var outputPath = outputPathArgument.Value; - if (string.IsNullOrEmpty(outputPath)) - { - Console.Error.WriteLine($"Output path not specified."); - return 1; - } - - var outputDirectory = Path.GetDirectoryName(outputPath); - Directory.CreateDirectory(outputDirectory); - - var outputType = outputTypeOption.Value() ?? "msbuild"; - - var graphSpecProvider = packageSpecsDirectoryOption.HasValue() - ? new DependencyGraphSpecProvider(packageSpecsDirectoryOption.Value().Trim()) - : DependencyGraphSpecProvider.Default; - IList repositories; - using (graphSpecProvider) - { - repositories = Repository.ReadAllRepositories(repositoriesRootOption.Value().Trim(), graphSpecProvider); - } - - var graph = GraphBuilder.Generate(repositories, graphRoot.Value()); - GraphFormatter formatter; - switch (outputType) - { - case "msbuild": - formatter = new MSBuildGraphFormatter(); - break; - case "dgml": - formatter = new DGMLFormatter(); - break; - default: - app.Error.WriteLine($"Unknown output type: {outputType}."); - return 1; - } - - formatter.Format(graph, outputPathArgument.Value); - - return 0; - }); - - return app.Execute(args); - } - } -} \ No newline at end of file