/// <summary> /// Dumps the <see cref="Solutions"/> order by their index along with optional details. /// </summary> /// <param name="m">The monitor to use.</param> /// <param name="current">The current solution (a star will precede its name).</param> /// <param name="solutionLineDetail">Optional details to be appended on the information, header, line.</param> /// <param name="solutionDetail"> /// Optional detailed log generator. /// When not null, a group is opened by solution and this is called. /// </param> public void LogSolutions( IActivityMonitor m, DependentSolution current = null, Func <DependentSolution, string> solutionLineDetail = null, Action <IActivityMonitor, DependentSolution> solutionDetail = null) { int rank = -1; foreach (var s in Solutions) { if (rank != s.Rank) { rank = s.Rank; m.Info($" -- Rank {rank}"); } if (solutionDetail != null) { using (m.OpenInfo($"{(s == current ? '*' : ' ')} {s.Index} - {s} {solutionLineDetail?.Invoke( s )}")) { solutionDetail(m, s); } } else { m.Info($"{(s == current ? '*' : ' ')} {s.Index} - {s} {solutionLineDetail?.Invoke( s )}"); } } }
/// <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))); }