/// <summary> /// Tries to turn a project into a pip and add it to the pip graph /// </summary> public static Possible <ProcessOutputs> TrySchedulePipForProject <TProject>(this IProjectToPipConstructor <TProject> constructor, TProject project, QualifierId qualifierId) where TProject : IProjectWithDependencies <TProject> { return(constructor.TryCreatePipForProject(project, qualifierId).Then(creationResult => constructor.TrySchedulePipForProject(creationResult, qualifierId))); }
/// <summary> /// Creates a pip graph that corresponds to all the specified projects in the graph /// </summary> public async Task <Possible <ProjectGraphSchedulingResult <TProject> > > TrySchedulePipsForFilesAsync(IReadOnlySet <TProject> projectsToEvaluate, QualifierId qualifierId, Func <ProjectCreationResult <TProject>, Possible <ProcessOutputs> > customScheduler = null) { Contract.Requires(qualifierId.IsValid); if (!TryTopoSortProjectsAndComputeClosure(projectsToEvaluate, out PriorityQueue <(TProject, int tier)> topoSortedQueue, out IEnumerable <TProject> cycle)) { return(new Possible <ProjectGraphSchedulingResult <TProject> >(new CycleInProjectsFailure <TProject>(cycle))); } bool success = true; // Observe in case of multiple failure we non-deterministically report one Failure failure = null; var processOutputs = new ConcurrentDictionary <TProject, ProcessOutputs>(); ActionBlock <TProject> createActionBlockForTier() { return(new ActionBlock <TProject>( project => { // If a previous tier had any errors (which is guaranteed to be completed before the next tier is scheduled), just return, since the current tier may depend on pips that in the end // were not scheduled if (!success) { return; } // We only schedule the project if the project does not rule itself out from being added to the graph if (project.CanBeScheduled()) { var maybeResult = m_pipConstructor.TryCreatePipForProject(project, qualifierId); if (!maybeResult.Succeeded) { // Error is already logged success = false; failure = maybeResult.Failure; return; } // If a custom scheduler is not present, or it returns null when called, we add the resulting pip as the pip constructor created it if (customScheduler == null || (customScheduler(maybeResult.Result) is var maybeCustomSchedulingOutputs && maybeCustomSchedulingOutputs.Succeeded && maybeCustomSchedulingOutputs.Result == null)) { var maybeOutputs = m_pipConstructor.TrySchedulePipForProject(maybeResult.Result, qualifierId); if (!maybeOutputs.Succeeded) { // Error is already logged success = false; failure = maybeOutputs.Failure; return; } processOutputs.TryAdd(project, maybeOutputs.Result); } else if (maybeCustomSchedulingOutputs.Succeeded) { // In this case the custom scheduler should have already added the pip. Notify the pip constructor and keep track of the project -> output association m_pipConstructor.NotifyCustomProjectScheduled(project, maybeCustomSchedulingOutputs.Result, qualifierId); processOutputs.TryAdd(project, maybeCustomSchedulingOutputs.Result); } else { // In this case the custom scheduler evaluated to an error success = false; failure = maybeCustomSchedulingOutputs.Failure; return; } }