diff --git a/build/tasks/AnalyzeBuildGraph.cs b/build/tasks/AnalyzeBuildGraph.cs index a135e66568..1c94093ac0 100644 --- a/build/tasks/AnalyzeBuildGraph.cs +++ b/build/tasks/AnalyzeBuildGraph.cs @@ -5,9 +5,11 @@ using System; using System.Collections; using System.Collections.Generic; using System.Linq; +using System.IO; using System.Threading; using Microsoft.Build.Framework; using Microsoft.Build.Utilities; +using RepoTools.BuildGraph; using RepoTasks.ProjectModel; using RepoTasks.Utilities; @@ -26,6 +28,8 @@ namespace RepoTasks [Required] public string Properties { get; set; } + public string StartGraphAt { get; set; } + /// /// New packages we are compiling. Used in the pin tool. /// @@ -58,7 +62,21 @@ namespace RepoTasks return false; } - PackagesProduced = solutions + EnsureConsistentGraph(solutions); + PackagesProduced = GetPackagesProduced(solutions); + RepositoryBuildOrder = GetRepositoryBuildOrder(solutions.Where(s => s.ShouldBuild)); + + return !Log.HasLoggedErrors; + } + + private void EnsureConsistentGraph(IEnumerable solutions) + { + // TODO + } + + private ITaskItem[] GetPackagesProduced(IEnumerable solutions) + { + return solutions .Where(s => s.ShouldBuild) .SelectMany(p => p.Projects) .Where(p => p.IsPackable) @@ -67,8 +85,63 @@ namespace RepoTasks ["Version"] = p.PackageVersion })) .ToArray(); + } - return !Log.HasLoggedErrors; + private ITaskItem[] GetRepositoryBuildOrder(IEnumerable solutions) + { + var repositories = solutions.Select(s => + { + var repoName = Path.GetFileName(Path.GetDirectoryName(s.FullPath)); + var repo = new Repository(repoName); + repo.Projects = s.Projects + .Where(p => p.IsPackable) + .Select(p => + new Project(p.PackageId) + { + Repository = repo, + PackageReferences = new HashSet(p.Frameworks.SelectMany(f => f.Dependencies.Keys), StringComparer.OrdinalIgnoreCase), + }) + .ToList(); + repo.SupportProjects = s.Projects + .Where(p => !p.IsPackable) + .Select(p => + new Project(p.PackageId) + { + Repository = repo, + PackageReferences = new HashSet(p.Frameworks.SelectMany(f => f.Dependencies.Keys), StringComparer.OrdinalIgnoreCase), + }) + .ToList(); + return repo; + }).ToList(); + + var graph = GraphBuilder.Generate(repositories, StartGraphAt, Log); + var repositoriesWithOrder = new List<(ITaskItem repository, int order)>(); + foreach (var repository in repositories) + { + var graphNodeRepository = graph.FirstOrDefault(g => g.Repository.Name == repository.Name); + if (graphNodeRepository == null) + { + // StartGraphAt was specified so the graph is incomplete. + continue; + } + + var order = TopologicalSort.GetOrder(graphNodeRepository); + var repositoryTaskItem = new TaskItem(repository.Name); + 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)}"); + } + + return repositoriesWithOrder + .OrderBy(r => r.order) + .Select(r => r.repository) + .ToArray(); } } } diff --git a/build/tasks/BuildGraph/Project.cs b/build/tasks/BuildGraph/Project.cs index 72b5eee254..ad03468a61 100644 --- a/build/tasks/BuildGraph/Project.cs +++ b/build/tasks/BuildGraph/Project.cs @@ -23,6 +23,6 @@ namespace RepoTools.BuildGraph public Repository Repository { get; set; } - public ISet PackageReferences { get; } = new HashSet(StringComparer.OrdinalIgnoreCase); + public ISet PackageReferences { get; set; } = new HashSet(StringComparer.OrdinalIgnoreCase); } } diff --git a/build/tasks/BuildGraph/Repository.cs b/build/tasks/BuildGraph/Repository.cs index c1e3e5c619..ed7135491c 100644 --- a/build/tasks/BuildGraph/Repository.cs +++ b/build/tasks/BuildGraph/Repository.cs @@ -22,9 +22,9 @@ namespace RepoTools.BuildGraph public string Name { get; private set; } - public IList Projects { get; } = new List(); + public IList Projects { get; set; } = new List(); - public IList SupportProjects { get; } = new List(); + public IList SupportProjects { get; set; } = new List(); public IEnumerable AllProjects => Projects.Concat(SupportProjects);