/// <summary> /// Creates a build request entry from a build request. /// </summary> /// <param name="request">The originating build request.</param> /// <param name="requestConfiguration">The build request configuration.</param> internal BuildRequestEntry(BuildRequest request, BuildRequestConfiguration requestConfiguration) { ErrorUtilities.VerifyThrowArgumentNull(request, nameof(request)); ErrorUtilities.VerifyThrowArgumentNull(requestConfiguration, nameof(requestConfiguration)); ErrorUtilities.VerifyThrow(requestConfiguration.ConfigurationId == request.ConfigurationId, "Configuration id mismatch"); GlobalLock = new Object(); Request = request; RequestConfiguration = requestConfiguration; _blockingGlobalRequestId = BuildRequest.InvalidGlobalRequestId; Result = null; ChangeState(BuildRequestEntryState.Ready); }
/// <summary> /// Initializes a build request. /// </summary> /// <param name="config">The configuration to use for the request.</param> /// <param name="targets">The set of targets to build.</param> /// <param name="resultsNeeded">Whether or not to wait for the results of this request.</param> /// <param name="flags">Flags specified for the build request.</param> public FullyQualifiedBuildRequest( BuildRequestConfiguration config, string[] targets, bool resultsNeeded, bool skipStaticGraphIsolationConstraints = false, BuildRequestDataFlags flags = BuildRequestDataFlags.None ) { ErrorUtilities.VerifyThrowArgumentNull(config, nameof(config)); ErrorUtilities.VerifyThrowArgumentNull(targets, nameof(targets)); Config = config; Targets = targets; ResultsNeeded = resultsNeeded; SkipStaticGraphIsolationConstraints = skipStaticGraphIsolationConstraints; BuildRequestDataFlags = flags; }
/// <summary> /// Gets a matching configuration. If no such configuration exists, one is created and optionally loaded. /// </summary> public BuildRequestConfiguration GetMatchingConfiguration(ConfigurationMetadata configMetadata, ConfigCreateCallback callback, bool loadProject) { lock (_lockObject) { BuildRequestConfiguration configuration = GetMatchingConfiguration(configMetadata); // If there is no matching configuration, let the caller create one. if (configuration == null) { configuration = callback(null, loadProject); AddConfiguration(configuration); } else if (loadProject) { // We already had a configuration, load the project // If it exists but it cached, retrieve it if (configuration.IsCached) { configuration.RetrieveFromCache(); } // If it is still not loaded (because no instance was ever created here), let the caller populate the instance. if (!configuration.IsLoaded) { callback(configuration, loadProject: true); } } // In either case, make sure the project is loaded if it was requested. if (loadProject) { ErrorUtilities.VerifyThrow(configuration.IsLoaded, "Request to create configuration did not honor request to also load project."); } return(configuration); } }
/// <summary> /// Override which determines the key for entry into the collection from the specified build request configuration. /// </summary> /// <param name="config">The build request configuration.</param> /// <returns>The configuration id.</returns> protected int GetKeyForConfiguration(BuildRequestConfiguration config) { return(config.ConfigurationId); }
/// <summary> /// Returns the entry in the cache which matches the specified config. /// </summary> /// <param name="config">The configuration to match</param> /// <returns>A matching configuration if one exists, null otherwise.</returns> public BuildRequestConfiguration GetMatchingConfiguration(BuildRequestConfiguration config) { ErrorUtilities.VerifyThrowArgumentNull(config, "config"); return(GetMatchingConfiguration(new ConfigurationMetadata(config))); }
/// <summary> /// Builds the specified targets. /// </summary> /// <param name="loggingContext">The logging context for the project.</param> /// <param name="entry">The BuildRequestEntry for which we are building targets.</param> /// <param name="callback">The callback to be used to handle new project build requests.</param> /// <param name="targetNames">The names of the targets to build.</param> /// <param name="baseLookup">The Lookup containing all current items and properties for this target.</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> to use when building the targets.</param> /// <returns>The target's outputs and result codes</returns> public async Task <BuildResult> BuildTargets(ProjectLoggingContext loggingContext, BuildRequestEntry entry, IRequestBuilderCallback callback, string[] targetNames, Lookup baseLookup, CancellationToken cancellationToken) { ErrorUtilities.VerifyThrowArgumentNull(loggingContext, "projectLoggingContext"); ErrorUtilities.VerifyThrowArgumentNull(entry, "entry"); ErrorUtilities.VerifyThrowArgumentNull(callback, "requestBuilderCallback"); ErrorUtilities.VerifyThrowArgumentNull(targetNames, "targetNames"); ErrorUtilities.VerifyThrowArgumentNull(baseLookup, "baseLookup"); ErrorUtilities.VerifyThrow(targetNames.Length > 0, "List of targets must be non-empty"); ErrorUtilities.VerifyThrow(_componentHost != null, "InitializeComponent must be called before building targets."); _requestEntry = entry; _requestBuilderCallback = callback; _projectLoggingContext = loggingContext; _cancellationToken = cancellationToken; // Clone the base lookup so that if we are re-entered by another request while this one in blocked, we don't have visibility to // their state, and they have no visibility into ours. _baseLookup = baseLookup.Clone(); _targetsToBuild = new ConcurrentStack <TargetEntry>(); // Get the actual target objects from the names BuildRequestConfiguration configuration = _requestEntry.RequestConfiguration; bool previousCacheableStatus = configuration.IsCacheable; configuration.IsCacheable = false; configuration.RetrieveFromCache(); _projectInstance = configuration.Project; // Now get the current results cache entry. IResultsCache resultsCache = (IResultsCache)_componentHost.GetComponent(BuildComponentType.ResultsCache); BuildResult existingBuildResult = resultsCache.GetResultsForConfiguration(_requestEntry.Request.ConfigurationId); _buildResult = new BuildResult(entry.Request, existingBuildResult, null); if (existingBuildResult == null) { // Add this result so that if our project gets re-entered we won't rebuild any targets we have already built. resultsCache.AddResult(_buildResult); } List <TargetSpecification> targets = new List <TargetSpecification>(targetNames.Length); foreach (string targetName in targetNames) { var targetExists = _projectInstance.Targets.ContainsKey(targetName); if (!targetExists && entry.Request.BuildRequestDataFlags.HasFlag(BuildRequestDataFlags.SkipNonexistentTargets)) { _projectLoggingContext.LogComment(Framework.MessageImportance.Low, "TargetSkippedWhenSkipNonexistentTargets", targetName); continue; } targets.Add(new TargetSpecification(targetName, targetExists ? _projectInstance.Targets[targetName].Location : _projectInstance.ProjectFileLocation)); } // Push targets onto the stack. This method will reverse their push order so that they // get built in the same order specified in the array. await PushTargets(targets, null, baseLookup, false, false, TargetBuiltReason.None); // Now process the targets ITaskBuilder taskBuilder = _componentHost.GetComponent(BuildComponentType.TaskBuilder) as ITaskBuilder; try { await ProcessTargetStack(taskBuilder); } finally { // If there are still targets left on the stack, they need to be removed from the 'active targets' list foreach (TargetEntry target in _targetsToBuild) { configuration.ActivelyBuildingTargets.Remove(target.Name); } ((IBuildComponent)taskBuilder).ShutdownComponent(); } if (_cancellationToken.IsCancellationRequested) { throw new BuildAbortedException(); } // Gather up outputs for the requested targets and return those. All of our information should be in the base lookup now. ComputeAfterTargetFailures(targetNames); BuildResult resultsToReport = new BuildResult(_buildResult, targetNames); // Return after-build project state if requested. if (_requestEntry.Request.BuildRequestDataFlags.HasFlag(BuildRequestDataFlags.ProvideProjectStateAfterBuild)) { resultsToReport.ProjectStateAfterBuild = _projectInstance; } if (_requestEntry.Request.RequestedProjectState != null) { resultsToReport.ProjectStateAfterBuild = _projectInstance.FilteredCopy(_requestEntry.Request.RequestedProjectState); } configuration.IsCacheable = previousCacheableStatus; return(resultsToReport); }