Example #1
0
        /// <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, "request");
            ErrorUtilities.VerifyThrowArgumentNull(requestConfiguration, "requestConfiguration");
            ErrorUtilities.VerifyThrow(requestConfiguration.ConfigurationId == request.ConfigurationId, "Configuration id mismatch");

            _dataMonitor             = new Object();
            _request                 = request;
            _requestConfiguration    = requestConfiguration;
            _blockingGlobalRequestId = BuildRequest.InvalidGlobalRequestId;
            _completedResult         = null;
            ChangeState(BuildRequestEntryState.Ready);
        }
Example #2
0
        /// <summary>
        /// Adds the specified configuration to the cache.
        /// </summary>
        /// <param name="config">The configuration to add.</param>
        public void AddConfiguration(BuildRequestConfiguration config)
        {
            ErrorUtilities.VerifyThrowArgumentNull(config, "config");
            ErrorUtilities.VerifyThrow(config.ConfigurationId != 0, "Invalid configuration ID");

            lock (_lockObject)
            {
                int configId = GetKeyForConfiguration(config);
                ErrorUtilities.VerifyThrow(!_configurations.ContainsKey(configId), "Configuration {0} already cached", config.ConfigurationId);
                _configurations.Add(configId, config);
                _configurationIdsByMetadata.Add(new ConfigurationMetadata(config), configId);
            }
        }
Example #3
0
        /// <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);
        }
Example #4
0
        /// <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="skipStaticGraphIsolationConstraints">Whether to skip the constraints of static graph isolation.</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;
        }
Example #5
0
        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>
        /// 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);
        }
Example #7
0
 protected int GetKeyForConfiguration(BuildRequestConfiguration config)
 {
     return(config.ConfigurationId);
 }
Example #8
0
 public BuildRequestConfiguration GetMatchingConfiguration(BuildRequestConfiguration config)
 {
     ErrorUtilities.VerifyThrowArgumentNull(config, nameof(config));
     return(GetMatchingConfiguration(new ConfigurationMetadata(config)));
 }
Example #9
0
 /// <summary>
 /// Handles the BuildRequestConfiguration packet.
 /// </summary>
 private void HandleBuildRequestConfiguration(BuildRequestConfiguration configuration)
 {
     // Configurations are already in the cache, which we share with the BuildManager.
 }
Example #10
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);
        }