public QAMockTargetBuilder()
 {
     _host = null;
     _testDataProvider = null;
     _testDefinition = null;
     _requestCallBack = null;
     _requestEntry = null;
     _projectLoggingContext = null;
     _buildDone = new AutoResetEvent(false);
 }
Beispiel #2
0
 /// <summary>
 /// Requests to reacquire the node.
 /// Thread safe, however Reaquire cannot be called unless the
 /// last call to Yield or Reaquire was Yield.
 /// </summary>
 public void Reacquire()
 {
     lock (_callbackMonitor)
     {
         IRequestBuilderCallback builderCallback = _requestEntry.Builder as IRequestBuilderCallback;
         ErrorUtilities.VerifyThrow(_yieldThreadId != -1, "Cannot call Reacquire() before Yield().");
         ErrorUtilities.VerifyThrow(_yieldThreadId == Thread.CurrentThread.ManagedThreadId, "Cannot call Reacquire() on thread {0} when Yield() was called on thread {1}", Thread.CurrentThread.ManagedThreadId, _yieldThreadId);
         builderCallback.Reacquire();
         _yieldThreadId = -1;
     }
 }
Beispiel #3
0
 /// <summary>
 /// Requests to yield the node.
 /// Thread safe, however Yield cannot be called unless the
 /// last call to Yield or Reacquire was Reacquire.
 /// </summary>
 public void Yield()
 {
     lock (_callbackMonitor)
     {
         IRequestBuilderCallback builderCallback = _requestEntry.Builder as IRequestBuilderCallback;
         ErrorUtilities.VerifyThrow(_yieldThreadId == -1, "Cannot call Yield() while yielding.");
         _yieldThreadId = Thread.CurrentThread.ManagedThreadId;
         MSBuildEventSource.Log.ExecuteTaskYieldStart(_taskLoggingContext.TaskName, _taskLoggingContext.BuildEventContext.TaskId);
         builderCallback.Yield();
     }
 }
Beispiel #4
0
        /// <summary>
        /// Builds the specified targets of an entry. The cancel event should only be set to true if we are planning
        /// on simulating execution time when a target is built
        /// </summary>
        public Task <BuildResult> BuildTargets(ProjectLoggingContext loggingContext, BuildRequestEntry entry, IRequestBuilderCallback callback, string[] targetNames, Lookup baseLookup, CancellationToken cancellationToken)
        {
            this.requestEntry          = entry;
            this.projectLoggingContext = loggingContext;
            this.requestCallBack       = callback;
            this.testDefinition        = this.testDataProvider[entry.Request.ConfigurationId];
            this.cancellationToken     = cancellationToken;
            BuildResult result = GenerateResults(targetNames);

            return(Task <BuildResult> .FromResult(result));
        }
        /// <summary>
        /// Builds the specified targets of an entry. The cancel event should only be set to true if we are planning
        /// on simulating execution time when a target is built
        /// </summary>
        public Task<BuildResult> BuildTargets(ProjectLoggingContext loggingContext, BuildRequestEntry entry, IRequestBuilderCallback callback, string[] targetNames, Lookup baseLookup, CancellationToken cancellationToken)
        {
            _requestEntry = entry;
            _projectLoggingContext = loggingContext;
            _requestCallBack = callback;
            _testDefinition = _testDataProvider[entry.Request.ConfigurationId];
            _cancellationToken = cancellationToken;
            BuildResult result = GenerateResults(targetNames);

            return Task<BuildResult>.FromResult(result);
        }
Beispiel #6
0
 /// <summary>
 /// Requests to reacquire the node.
 /// Thread safe, however Reacquire cannot be called unless the
 /// last call to Yield or Reacquire was Yield.
 /// </summary>
 public void Reacquire()
 {
     lock (_callbackMonitor)
     {
         IRequestBuilderCallback builderCallback = _requestEntry.Builder as IRequestBuilderCallback;
         ErrorUtilities.VerifyThrow(_yieldThreadId != -1, "Cannot call Reacquire() before Yield().");
         ErrorUtilities.VerifyThrow(_yieldThreadId == Thread.CurrentThread.ManagedThreadId, "Cannot call Reacquire() on thread {0} when Yield() was called on thread {1}", Thread.CurrentThread.ManagedThreadId, _yieldThreadId);
         MSBuildEventSource.Log.ExecuteTaskYieldStop(_taskLoggingContext.TaskName, _taskLoggingContext.BuildEventContext.TaskId);
         MSBuildEventSource.Log.ExecuteTaskReacquireStart(_taskLoggingContext.TaskName, _taskLoggingContext.BuildEventContext.TaskId);
         builderCallback.Reacquire();
         MSBuildEventSource.Log.ExecuteTaskReacquireStop(_taskLoggingContext.TaskName, _taskLoggingContext.BuildEventContext.TaskId);
         _yieldThreadId = -1;
     }
 }
        public Task <BuildResult> BuildTargets(ProjectLoggingContext loggingContext, BuildRequestEntry entry, IRequestBuilderCallback callback, string[] targets, Lookup baseLookup, CancellationToken cancellationToken)
        {
            _requestBuilderCallback = callback;

            if (cancellationToken.WaitHandle.WaitOne(1500))
            {
                BuildResult result = new BuildResult(entry.Request);
                foreach (string target in targets)
                {
                    result.AddResultsForTarget(target, BuildResultUtilities.GetEmptyFailingTargetResult());
                }
                return(Task <BuildResult> .FromResult(result));
            }

            if (_newRequests != null)
            {
                string[] projectFiles = new string[_newRequests.Length];
                PropertyDictionary <ProjectPropertyInstance>[] properties = new PropertyDictionary <ProjectPropertyInstance> [_newRequests.Length];
                string[] toolsVersions = new string[_newRequests.Length];

                for (int i = 0; i < projectFiles.Length; ++i)
                {
                    projectFiles[i]  = _newRequests[i].Config.ProjectFullPath;
                    properties[i]    = new PropertyDictionary <ProjectPropertyInstance>(_newRequests[i].Config.GlobalProperties);
                    toolsVersions[i] = _newRequests[i].Config.ToolsVersion;
                }

                _requestBuilderCallback.BuildProjects(projectFiles, properties, toolsVersions, _newRequests[0].Targets, _newRequests[0].ResultsNeeded);

                if (cancellationToken.WaitHandle.WaitOne(1500))
                {
                    BuildResult result = new BuildResult(entry.Request);
                    foreach (string target in targets)
                    {
                        result.AddResultsForTarget(target, BuildResultUtilities.GetEmptyFailingTargetResult());
                    }
                    return(Task <BuildResult> .FromResult(result));
                }
            }

            return(Task <BuildResult> .FromResult(_cache.GetResultForRequest(entry.Request)));
        }
        /// <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.
            ResultsCache resultsCache        = (ResultsCache)_componentHost.GetComponent(BuildComponentType.ResultsCache);
            BuildResult  existingBuildResult = null;

            resultsCache.ResultsDictionary.TryGetValue(_requestEntry.Request.ConfigurationId, out existingBuildResult);

            _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.
            BuildResult resultsToReport = new BuildResult(_buildResult, targetNames);

            // Return after-build project state if requested.
            if (_requestEntry.Request.BuildRequestDataFlags.HasFlag(BuildRequestDataFlags.ProvideProjectStateAfterBuild))
            {
                resultsToReport.ProjectStateAfterBuild = _projectInstance;
            }

            configuration.IsCacheable = previousCacheableStatus;

            return(resultsToReport);
        }
Beispiel #9
0
        /// <summary>
        /// Async version of BuildProjectFilesInParallel.
        /// </summary>
        /// <param name="projectFileNames">The list of projects to build</param>
        /// <param name="targetNames">The set of targets to build</param>
        /// <param name="globalProperties">The global properties to use for each project</param>
        /// <param name="undefineProperties">The list of global properties to undefine</param>
        /// <param name="toolsVersion">The tools versions to use</param>
        /// <param name="returnTargetOutputs">Should the target outputs be returned in the BuildEngineResult</param>
        /// <param name="skipNonexistentTargets">If set, skip targets that are not defined in the projects to be built.</param>
        /// <returns>A Task returning a structure containing the result of the build, success or failure and the list of target outputs per project</returns>
        private async Task <BuildEngineResult> BuildProjectFilesInParallelAsync(string[] projectFileNames, string[] targetNames, IDictionary[] globalProperties, IList <String>[] undefineProperties, string[] toolsVersion, bool returnTargetOutputs, bool skipNonexistentTargets = false)
        {
            ErrorUtilities.VerifyThrowArgumentNull(projectFileNames, "projectFileNames");
            ErrorUtilities.VerifyThrowArgumentNull(globalProperties, "globalProperties");
            VerifyActiveProxy();

            List <IDictionary <string, ITaskItem[]> > targetOutputsPerProject = null;

#if FEATURE_FILE_TRACKER
            using (FullTracking.Suspend())
#endif
            {
                bool overallSuccess = true;

                if (projectFileNames.Length == 1 && projectFileNames[0] == null && globalProperties[0] == null && (undefineProperties == null || undefineProperties[0] == null) && toolsVersion[0] == null)
                {
                    // This is really a legacy CallTarget invocation
                    ITargetResult[] results = await _targetBuilderCallback.LegacyCallTarget(targetNames, ContinueOnError, _taskLocation);

                    if (returnTargetOutputs)
                    {
                        targetOutputsPerProject = new List <IDictionary <string, ITaskItem[]> >(1)
                        {
                            new Dictionary <string, ITaskItem[]>(StringComparer.OrdinalIgnoreCase)
                        };
                    }

                    for (int i = 0; i < targetNames.Length; i++)
                    {
                        targetOutputsPerProject[0][targetNames[i]] = results[i].Items;
                        if (results[i].ResultCode == TargetResultCode.Failure)
                        {
                            overallSuccess = false;
                        }
                    }
                }
                else
                {
                    // UNDONE: (Refactor) Investigate making this a ReadOnly collection of some sort.
                    PropertyDictionary <ProjectPropertyInstance>[] propertyDictionaries = new PropertyDictionary <ProjectPropertyInstance> [projectFileNames.Length];

                    for (int i = 0; i < projectFileNames.Length; i++)
                    {
                        // Copy in the original project's global properties
                        propertyDictionaries[i] = new PropertyDictionary <ProjectPropertyInstance>(_requestEntry.RequestConfiguration.Project.GlobalPropertiesDictionary);

                        // Now add/replace any which may have been specified.
                        if (globalProperties[i] != null)
                        {
                            foreach (DictionaryEntry entry in globalProperties[i])
                            {
                                propertyDictionaries[i].Set(ProjectPropertyInstance.Create(entry.Key as string, entry.Value as string, _taskLocation));
                            }
                        }

                        // Finally, remove any which were requested to be removed.
                        if (undefineProperties?[i] != null)
                        {
                            foreach (string property in undefineProperties[i])
                            {
                                propertyDictionaries[i].Remove(property);
                            }
                        }
                    }

                    IRequestBuilderCallback builderCallback = _requestEntry.Builder as IRequestBuilderCallback;
                    BuildResult[]           results         = await builderCallback.BuildProjects(
                        projectFileNames,
                        propertyDictionaries,
                        toolsVersion ?? Array.Empty <string>(),
                        targetNames ?? Array.Empty <string>(),
                        waitForResults : true,
                        skipNonexistentTargets : skipNonexistentTargets);

                    // Even if one of the projects fails to build and therefore has no outputs, it should still have an entry in the results array (albeit with an empty list in it)
                    ErrorUtilities.VerifyThrow(results.Length == projectFileNames.Length, "{0}!={1}.", results.Length, projectFileNames.Length);

                    if (returnTargetOutputs)
                    {
                        targetOutputsPerProject = new List <IDictionary <string, ITaskItem[]> >(results.Length);
                    }

                    // Now walk through the results, and report that subset which was asked for.
                    for (int i = 0; i < results.Length; i++)
                    {
                        if (targetOutputsPerProject != null)
                        {
                            targetOutputsPerProject.Add(new Dictionary <string, ITaskItem[]>(StringComparer.OrdinalIgnoreCase));
                        }

                        foreach (KeyValuePair <string, TargetResult> resultEntry in results[i].ResultsByTarget)
                        {
                            if (targetOutputsPerProject != null)
                            {
                                // We need to clone the task items because if we did not then we would be passing live references
                                // out to the caller of the msbuild callback and any modifications they make to those items
                                // would appear in the results cache.
                                ITaskItem[] clonedTaskItem = new ITaskItem[resultEntry.Value.Items.Length];
                                for (int j = 0; j < resultEntry.Value.Items.Length; j++)
                                {
                                    clonedTaskItem[j] = ((TaskItem)resultEntry.Value.Items[j]).DeepClone();
                                }

                                targetOutputsPerProject[i][resultEntry.Key] = clonedTaskItem;
                            }
                        }

                        if (results[i].OverallResult == BuildResultCode.Failure)
                        {
                            overallSuccess = false;
                        }

                        if (!string.IsNullOrEmpty(results[i].SchedulerInducedError))
                        {
                            LoggingContext.LogErrorFromText(
                                subcategoryResourceName: null,
                                errorCode: null,
                                helpKeyword: null,
                                file: new BuildEventFileInfo(ProjectFileOfTaskNode, LineNumberOfTaskNode, ColumnNumberOfTaskNode),
                                message: results[i].SchedulerInducedError);
                        }
                    }

                    ErrorUtilities.VerifyThrow(results.Length == projectFileNames.Length || overallSuccess == false, "The number of results returned {0} cannot be less than the number of project files {1} unless one of the results indicated failure.", results.Length, projectFileNames.Length);
                }

                BuildRequestsSucceeded = overallSuccess;

                return(new BuildEngineResult(overallSuccess, targetOutputsPerProject));
            }
        }
        public Task<BuildResult> BuildTargets(ProjectLoggingContext loggingContext, BuildRequestEntry entry, IRequestBuilderCallback callback, string[] targets, Lookup baseLookup, CancellationToken cancellationToken)
        {
            _requestBuilderCallback = callback;

            if (cancellationToken.WaitHandle.WaitOne(1500, false))
            {
                BuildResult result = new BuildResult(entry.Request);
                foreach (string target in targets)
                {
                    result.AddResultsForTarget(target, TestUtilities.GetEmptyFailingTargetResult());
                }
                return Task<BuildResult>.FromResult(result);
            }

            if (null != _newRequests)
            {
                string[] projectFiles = new string[_newRequests.Length];
                PropertyDictionary<ProjectPropertyInstance>[] properties = new PropertyDictionary<ProjectPropertyInstance>[_newRequests.Length];
                string[] toolsVersions = new string[_newRequests.Length];

                for (int i = 0; i < projectFiles.Length; ++i)
                {
                    projectFiles[i] = _newRequests[i].Config.ProjectFullPath;
                    properties[i] = new PropertyDictionary<ProjectPropertyInstance>(_newRequests[i].Config.Properties);
                    toolsVersions[i] = _newRequests[i].Config.ToolsVersion;
                }

                _requestBuilderCallback.BuildProjects(projectFiles, properties, toolsVersions, _newRequests[0].Targets, _newRequests[0].ResultsNeeded);

                if (cancellationToken.WaitHandle.WaitOne(1500, false))
                {
                    BuildResult result = new BuildResult(entry.Request);
                    foreach (string target in targets)
                    {
                        result.AddResultsForTarget(target, TestUtilities.GetEmptyFailingTargetResult());
                    }
                    return Task<BuildResult>.FromResult(result);
                }
            }

            return Task<BuildResult>.FromResult(_cache.GetResultForRequest(entry.Request));
        }
Beispiel #11
0
        /// <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>
        /// <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.
            ResultsCache resultsCache = (ResultsCache)_componentHost.GetComponent(BuildComponentType.ResultsCache);
            BuildResult existingBuildResult = null;
            resultsCache.ResultsDictionary.TryGetValue(_requestEntry.Request.ConfigurationId, out existingBuildResult);

            _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)
            {
                targets.Add(new TargetSpecification(targetName, _projectInstance.Targets.ContainsKey(targetName) ? _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, TargetPushType.Normal);

            // 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.
            BuildResult resultsToReport = new BuildResult(_buildResult, targetNames);

            // Return after-build project state if requested.
            if (_requestEntry.Request.BuildRequestDataFlags.HasFlag(BuildRequestDataFlags.ProvideProjectStateAfterBuild))
            {
                resultsToReport.ProjectStateAfterBuild = _projectInstance;
            }

            configuration.IsCacheable = previousCacheableStatus;

            return resultsToReport;
        }
Beispiel #12
0
        /// <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, nameof(entry));
            ErrorUtilities.VerifyThrowArgumentNull(callback, "requestBuilderCallback");
            ErrorUtilities.VerifyThrowArgumentNull(targetNames, nameof(targetNames));
            ErrorUtilities.VerifyThrowArgumentNull(baseLookup, nameof(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.TryGetValue(targetName, out ProjectTargetInstance targetInstance);
                if (!targetExists && entry.Request.BuildRequestDataFlags.HasFlag(BuildRequestDataFlags.SkipNonexistentTargets))
                {
                    _projectLoggingContext.LogComment(Framework.MessageImportance.Low,
                                                      "TargetSkippedWhenSkipNonexistentTargets", targetName);
                }
                else
                {
                    targets.Add(new TargetSpecification(targetName, targetExists ? targetInstance.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;

            var staticGraph = new StaticGraph();

            staticGraph.ProjectPath = _projectInstance.FullPath;
            try
            {
                await ProcessTargetStack(taskBuilder, staticGraph.StaticTargets);
            }
            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();
            }

            if (entry.IsStatic)
            {
                using (var stream = new FileStream(Environment.GetEnvironmentVariable("MSBUILDSTATIC_OUTPUT"), FileMode.Create, FileAccess.ReadWrite, FileShare.Read))
                {
                    staticGraph.Files = SimulatedFileSystem.Instance.KnownFiles.ToList();
                    new System.Runtime.Serialization.Json.DataContractJsonSerializer(typeof(StaticGraph)).WriteObject(stream, staticGraph);
                }
            }

            // 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);
        }
Beispiel #13
0
 /// <summary>
 /// Shuts down the component.
 /// </summary>
 public void ShutdownComponent()
 {
     _host = null;
     _testDataProvider = null;
     _testDefinition = null;
     _requestCallBack = null;
     _requestEntry = null;
     _projectLoggingContext = null;
 }