/// <summary> /// Creates a new <see cref="SolutionDependencyContext"/>, possibly for a different subset of projects /// of the <see cref="Solutions"/> than the default set (all projects except build projects). /// </summary> /// <param name="m">The monitor to use.</param> /// <param name="traceGraphDetails">True to trace the details of the input and output (sorted) graphs.</param> /// <param name="projectFilter"> /// Optional project filter. /// By default all projects are considered except build projects (see <see cref="Solution.BuildProject"/>). /// </param> /// <returns>The context or null on error.</returns> public SolutionDependencyContext CreateDependencyContext(IActivityMonitor m, bool traceGraphDetails, Func <IProject, bool> projectFilter = null) { if (projectFilter == null) { projectFilter = p => !p.IsBuildProject; } var sortables = new Dictionary <ISolution, SolutionItem>(); foreach (var s in _solutions) { var sItem = new SolutionItem(s, s.Projects.Where(p => projectFilter(p)).Select(p => _projects[p])); sortables.Add(s, sItem); } var options = new DependencySorterOptions(); if (traceGraphDetails) { options.HookInput = i => i.Trace(m); options.HookOutput = i => i.Trace(m); } IDependencySorterResult result = DependencySorter.OrderItems(m, sortables.Values, null, options); if (!result.IsComplete) { result.LogError(m); return(new SolutionDependencyContext(this, result, GetBuildProjectInfo(m))); } // Building the list of SolutionDependencyContext.DependencyRow. var table = result.SortedItems // 1 - Selects solutions along with their ordered index. .Where(sorted => sorted.GroupForHead == null && sorted.Item is SolutionItem) .Select(sorted => ( Solution: (Solution)sorted.StartValue, // The projects from this solution that reference packages that are // produced by local solutions have a direct requires to a Package // that has a local Project. // 2 - First Map: LocalRefs is a set of value tuple (Project Origin, Package Target). LocalRefs: sorted.Children .Select(c => (SProject: c, Project: (Project)c.StartValue)) .SelectMany(c => c.SProject.DirectRequires .Select(r => r.Item) .OfType <LocalPackageItem>() .Select(package => (Origin: c.Project, Target: package)) ))) // 3 - Second Map: Expands the LocalRefs. .SelectMany(s => s.LocalRefs.Any() ? s.LocalRefs.Select(r => new DependentSolution.Row ( s.Solution, r.Origin, r.Target.Project )) : new[] { new DependentSolution.Row(s.Solution, null, null) } ) .ToList(); // Now that the table of SolutionDependencyContext.DependencyRow is built, use it to compute the // pure solution dependency graph. // var index = new Dictionary <object, DependentSolution>(); ISolution current = null; var depSolutions = new DependentSolution[sortables.Count]; int idx = 0; foreach (var r in table) { if (current != r.Solution) { current = r.Solution; var newDependent = new DependentSolution(current, table, s => index[s]); depSolutions[idx++] = newDependent; index.Add(current.Name, newDependent); index.Add(current, newDependent); } } Array.Sort(depSolutions, (d1, d2) => { int cmp = d1.Rank - d2.Rank; if (cmp == 0) { cmp = d1.Solution.Name.CompareTo(d2.Solution.Name); } return(cmp); }); for (int i = 0; i < depSolutions.Length; ++i) { depSolutions[i].Index = i; } return(new SolutionDependencyContext(this, index, result, table, depSolutions, GetBuildProjectInfo(m))); }
/// <summary> /// Gets the information about build projects (see <see cref="Solution.BuildProject"/>) /// and their dependencies. /// </summary> /// <param name="m">The monitor to use.</param> /// <param name="traceGraphDetails">True to trace the details of the input and output (sorted) graphs.</param> /// <returns>The build projects information.</returns> BuildProjectsInfo GetBuildProjectInfo(IActivityMonitor m) { Debug.Assert(!_projects.PureProjectsMode); _projects.PureProjectsMode = true; try { using (m.OpenTrace($"Creating Build Projects information.")) { IDependencySorterResult rBuildProjects = DependencySorter.OrderItems(m, _projects.AllProjectItems.Where(p => p.Project.IsBuildProject), null); if (!rBuildProjects.IsComplete) { rBuildProjects.LogError(m); return(new BuildProjectsInfo(rBuildProjects, null)); } else { var rankedProjects = rBuildProjects.SortedItems .Where(i => i.Item is ProjectItem) .Select(i => (i.Rank, ((ProjectItem)i.Item).Project, DirectDeps: i.Requires .Select(s => s.Item) .OfType <ProjectItem>() .Select(p => p.Project), AllDeps: i.GetAllRequires() .Select(s => s.Item) .OfType <ProjectItem>() .Select(p => p.Project))); var zeroBuildProjects = rankedProjects.Select((p, idx) => new ZeroBuildProjectInfo( idx, p.Rank, p.Project, // UpgradePackages: Among direct dependencies, consider only the // published projects and the ones who are actually referenced // as a package (ignores ProjectReference). p.DirectDeps .Where(d => d.IsPublished && p.Project.PackageReferences.Any(r => d.GeneratedArtifacts .Select(a => a.Artifact) .Contains(r.Target.Artifact))) .ToArray(), // UpgradeZeroProjects: Among direct dependencies, consider all the // published projects, the ones who are actually referenced // as a package AND the ones that are ProjectReference. // ProjectReference MUST be transformed into PackageReference // during ZeroBuild. p.DirectDeps .Where(d => d.IsPublished) .ToArray(), // Dependencies: Considers all the projects. p.AllDeps.ToArray() )) .ToArray(); Debug.Assert(zeroBuildProjects.Select(z => z.Rank).IsSortedLarge()); Debug.Assert(zeroBuildProjects.Select(z => z.Index).IsSortedStrict()); return(new BuildProjectsInfo(rBuildProjects, zeroBuildProjects)); } } } finally { _projects.PureProjectsMode = false; } }