Example #1
0
        internal TargetInProgessState
        (
            EngineCallback engineCallback,
            Target target, 
            List<ProjectBuildState> waitingBuildStates,
            ProjectBuildState initiatingRequest,
            BuildRequest [] outstandingBuildRequests,
            string projectName
        )
        {
            this.targetId = new TargetIdWrapper(target);
            this.outstandingBuildRequests = outstandingBuildRequests;
            // For each waiting build context try to find the parent target
            this.parentBuildRequests = new List<BuildRequest>();
            this.parentTargets = new List<TargetIdWrapper>();
            this.projectName = projectName;

            // Process the waiting contexts if there are any
            if (waitingBuildStates != null)
            {
                for (int i = 0; i < waitingBuildStates.Count; i++)
                {
                    ProcessBuildContext(engineCallback, waitingBuildStates[i], target);
                }
            }
            // Process the initiating context
            ProcessBuildContext(engineCallback, initiatingRequest, target);
        }
Example #2
0
 /// <summary>
 /// Create a build request from the list of targets to build and build request object
 /// </summary>
 internal ProjectBuildState(BuildRequest buildRequest, ArrayList targetNamesToBuild, BuildEventContext buildEventContext)
 {
     this.buildRequest = buildRequest;
     this.indexOfTargetInProgress = 0;
     this.targetNamesToBuild = targetNamesToBuild;
     this.buildContextState = BuildContextState.StartingFirstTarget;
     this.projectBuildEventContext = buildEventContext;
 }
Example #3
0
        public void TestConstructor2andProperties()
        {

            int nodeProxyId = 1;
            string projectFileName = "ProjectFileName";
            string[] targetNames = new string[] { "Build" };
            Dictionary<string, string> dictionary = null;
            int requestId = 1;

            // Check that the initial values of the properties are set based on the constructor being run
            BuildRequest secondConstructorRequest = new BuildRequest(nodeProxyId, projectFileName, targetNames, (IDictionary)dictionary, null, requestId, false, false);
            Assert.AreEqual(1, secondConstructorRequest.HandleId, "Expected NodeProxyId to be 1");
            Assert.AreEqual(1, secondConstructorRequest.RequestId, "Expected RequestId to be 1");
            Assert.IsNull(secondConstructorRequest.GlobalProperties, "Expected GlobalProperties to be null");
            Assert.IsNull(secondConstructorRequest.GlobalPropertiesPassedByTask, "Expected GlobalPropertiesPassedByTask to be null");
            Assert.IsTrue((secondConstructorRequest.TargetNames.Length == 1) && (string.Compare("Build", secondConstructorRequest.TargetNames[0], StringComparison.OrdinalIgnoreCase) == 0), "Expected to have one target with a value of Build");
            Assert.IsTrue(string.Compare("ProjectFileName", secondConstructorRequest.ProjectFileName, StringComparison.OrdinalIgnoreCase) == 0, "Expected project file to be called ProjecFileName");
            Assert.IsNull(secondConstructorRequest.ParentEngine, "Expected parent Engine to be null");
            Assert.IsNull(secondConstructorRequest.OutputsByTarget, "Expected outputs by target to be null");
            Assert.IsFalse(secondConstructorRequest.BuildSucceeded, "Expected BuildSucceeded to be false");
            Assert.AreEqual(secondConstructorRequest.BuildSettings, BuildSettings.None, "Expected BuildSettings to be none");
            Assert.IsNull(secondConstructorRequest.ProjectToBuild, "Expected ProjectToBuild to be null");
            Assert.IsFalse(secondConstructorRequest.FireProjectStartedFinishedEvents, " Expected FireProjectStartedFinishedEvents to be false");
            Assert.IsTrue(secondConstructorRequest.IsGeneratedRequest, "Expected GeneratedRequest to be true");

            // Test that if a nodeProxyId is set to NodeProxy.invalidEngineHandle then we should get a not null dependency chain
            secondConstructorRequest = new BuildRequest(EngineCallback.invalidEngineHandle, projectFileName, targetNames, (IDictionary)dictionary, null, requestId, false, false);
            Assert.IsFalse(secondConstructorRequest.IsGeneratedRequest, "Expected GeneratedRequest to be false");

            // Create a dictionary and hash table so that we can test the second constructor more
            dictionary = new Dictionary<string, string>();
            dictionary.Add("PropertyName", "Value");
            Hashtable propertyHash = new Hashtable();
            propertyHash.Add("PropertyName", "Value");

            // If a dictionary is passed then it will be converted to a hashtable by copying the items out, we shoud
            // therefore make sure that the hashtable has the correct items inside of it
            secondConstructorRequest = new BuildRequest(nodeProxyId, projectFileName, targetNames, (IDictionary)dictionary, null, requestId, false, false);
            string buildPropertyValue = ((Hashtable)secondConstructorRequest.GlobalPropertiesPassedByTask)["PropertyName"] as string;
            Assert.IsTrue(string.Compare(buildPropertyValue, "Value", StringComparison.OrdinalIgnoreCase) == 0, "Expected buildPropertyValue to be value");

            // If a hashtable is passed then the GlobalPropertiesPassedByTask are set to that hashtable
            secondConstructorRequest = new BuildRequest(nodeProxyId, projectFileName, targetNames, propertyHash, null, requestId, false, false);
            Assert.AreEqual(propertyHash, ((Hashtable)secondConstructorRequest.GlobalPropertiesPassedByTask), "Expected propertyHash to be equal to GlobalPropertiesPassedByTask");

            //Change the parentNode to verify the working of isExternalRequest
            secondConstructorRequest.IsExternalRequest = false;
            Assert.IsFalse(secondConstructorRequest.IsExternalRequest, "Expected IsExternalRequest to return false");
            secondConstructorRequest.IsExternalRequest = true;
            Assert.IsTrue(secondConstructorRequest.IsExternalRequest, "Expected IsExternalRequest to return true");

            // Verify that the parentEngine can be set through a property
            secondConstructorRequest.ParentEngine = new Engine();
            Assert.IsNotNull(secondConstructorRequest.ParentEngine, "Expected parent Engine to not be null");
        }
Example #4
0
        /// <summary>
        /// This method is called by the node to request evaluation of a target that was
        /// requested by a task via IBuildEngine interface. It posts the
        /// request into a queue in the engine
        /// </summary>
        /// <param name="buildRequests"></param>
        public void PostBuildRequestsToHost(BuildRequest[] buildRequests)
        {
            if (buildRequests.Length > 0)
            {
                // We can safely assume that all requests need to be routed to the same engine because
                // they originated from the same task 
                for(int i = 0; i < buildRequests.Length; i++)
                {
                    ProcessBuildRequest(buildRequests[i]);
                }

                parentEngine.PostBuildRequests(buildRequests);
            }
        }
Example #5
0
 /// <summary>
 /// Default constructor for a routing context
 /// </summary>
 internal RequestRoutingContext
 (
     int handleId,
     int nodeIndex,
     int parentHandleId,
     int parentNodeIndex,
     int parentRequestId, 
     CacheScope cacheScope,
     BuildRequest triggeringBuildRequest,
     BuildEventContext buildEventContext
 )
     :base(handleId, nodeIndex, buildEventContext)
 {
     this.parentHandleId = parentHandleId;
     this.parentNodeIndex = parentNodeIndex;
     this.parentRequestId = parentRequestId;
     this.cacheScope = cacheScope;
     this.triggeringBuildRequest = triggeringBuildRequest;
 }
Example #6
0
        public void TestConstructor1andProperties()
        {

            int nodeProxyId = 1;
            string projectFileName = "ProjectFileName";
            string[] targetNames = new string[] { "Build" };
            BuildPropertyGroup globalProperties = null;
            int requestId = 1;

            BuildRequest firstConstructorRequest = new BuildRequest(nodeProxyId, projectFileName, targetNames, globalProperties, null, requestId, false, false);
            Assert.AreEqual(1, firstConstructorRequest.HandleId, "Expected firstConstructorRequest.NodeProxyId to be 1");
            firstConstructorRequest.HandleId = 2;
            Assert.AreEqual(2, firstConstructorRequest.HandleId, "Expected firstConstructorRequest.NodeProxyId to be 2");
            Assert.AreEqual(1, firstConstructorRequest.RequestId, "Expected firstConstructorRequest.RequestId to be 1");
            firstConstructorRequest.RequestId = 2;
            Assert.AreEqual(2, firstConstructorRequest.RequestId, "Expected firstConstructorRequest.RequestId to be 2");
            Assert.IsNull(firstConstructorRequest.GlobalProperties, "Expected firstConstructorRequest.GlobalProperties to be null");
            firstConstructorRequest.GlobalProperties = new BuildPropertyGroup();
            Assert.IsNotNull(firstConstructorRequest.GlobalProperties, "Expected firstConstructorRequest.GlobalProperties to not be null");
            Assert.IsTrue((firstConstructorRequest.TargetNames.Length == 1) && (string.Compare("Build", firstConstructorRequest.TargetNames[0], StringComparison.OrdinalIgnoreCase) == 0), "Expected to have one target with a value of Build in firstConstructorRequest.TargetNames");
            Assert.IsTrue(string.Compare("ProjectFileName", firstConstructorRequest.ProjectFileName, StringComparison.OrdinalIgnoreCase) == 0, "Expected firstConstructorRequest.ProjectFileName to be called ProjecFileName");

            globalProperties = new BuildPropertyGroup();
            BuildProperty propertyToAdd = new BuildProperty("PropertyName", "Value");
            globalProperties.SetProperty(propertyToAdd);

            firstConstructorRequest = new BuildRequest(nodeProxyId, projectFileName, targetNames, globalProperties, null, requestId, false, false);
            Assert.IsNotNull(firstConstructorRequest.GlobalPropertiesPassedByTask, "Expected GlobalPropertiesPassedByTask to not be null");
            Assert.IsNotNull(firstConstructorRequest.GlobalProperties, "Expected GlobalPropertiesPassedByTask to not be null");
            Assert.IsTrue(string.Compare(firstConstructorRequest.GlobalProperties["PropertyName"].Value, "Value", StringComparison.OrdinalIgnoreCase) == 0, "Expected GlobalProperties, propertyname to be equal to value");

            string buildProperty = ((Hashtable)firstConstructorRequest.GlobalPropertiesPassedByTask)["PropertyName"] as string;
            Assert.IsTrue(string.Compare(buildProperty, "Value", StringComparison.OrdinalIgnoreCase) == 0, "Expected hashtable to contain a property group with a value of value");
            Assert.IsTrue((firstConstructorRequest.TargetNames.Length == 1) && (string.Compare("Build", firstConstructorRequest.TargetNames[0], StringComparison.OrdinalIgnoreCase) == 0), "Expected to have one target with a value of Build");
            Assert.IsTrue(string.Compare("ProjectFileName", firstConstructorRequest.ProjectFileName, StringComparison.OrdinalIgnoreCase) == 0, "Expected project file to be called ProjecFileName");
      
        
        }
Example #7
0
        /// <summary>
        /// This method get a result from the cache if every target is cached.
        /// If any of the target are not present in the cache null is returned. This method is not thread safe.
        /// </summary>
        internal BuildResult GetCachedBuildResult(BuildRequest buildRequest, out ArrayList actuallyBuiltTargets)
        {
            actuallyBuiltTargets = null;

            if (!buildRequest.UseResultsCache)
            {
                return(null);
            }

            // Retrieve list of scopes by this name
            string projectName = buildRequest.ProjectToBuild == null ?
                                 buildRequest.ProjectFileName : buildRequest.ProjectToBuild.FullFileName;

            // If the list exists search for matching scope properties otherwise create the list
            CacheScope cacheScope = GetCacheScopeIfExists(projectName, buildRequest.GlobalProperties, buildRequest.ToolsetVersion, CacheContentType.BuildResults);

            // If there is no cache entry for this project return null
            if (cacheScope == null)
            {
                return(null);
            }

            return(cacheScope.GetCachedBuildResult(buildRequest, out actuallyBuiltTargets));
        }
Example #8
0
        /// <summary>
        /// Called when the engine is in the process of sending a buildRequest to a child node. The entire purpose of this method
        /// is to switch the traversal strategy of the systems if there are nodes which do not have enough work availiable to them.
        /// </summary>
        internal void NotifyOfBuildRequest(int nodeIndex, BuildRequest currentRequest, int parentHandleId)
        {
            // This will only be null when the scheduler is instantiated on a child process in which case the initialize method
            // of the scheduler will not be called and therefore not initialize totalRequestsPerNode.
            if (totalRequestsPerNode != null)
            {
                // Check if it makes sense to switch from one traversal strategy to the other
                if (parentEngine.NodeManager.TaskExecutionModule.UseBreadthFirstTraversal)
                {
                    // Check if a switch to depth first traversal is in order
                    bool useBreadthFirstTraversal = false;
                    for (int i = 0; i < totalRequestsPerNode.Length; i++)
                    {
                        // Continue using breadth-first traversal as long as the non-blocked work load for this node is below
                        // the nodeWorkloadProjectCount or its postBlockCount is non-zero
                        if ((totalRequestsPerNode[i] - blockedRequestsPerNode[i]) < nodeWorkLoadProjectCount || postBlockCount[i] != 0)
                        {
                            useBreadthFirstTraversal = true;
                            break;
                        }
                    }

                    if (!useBreadthFirstTraversal)
                    {
                        if (Engine.debugMode)
                        {
                            Console.WriteLine("Switching to depth first traversal because all node have workitems");
                        }
                        parentEngine.NodeManager.TaskExecutionModule.UseBreadthFirstTraversal = false;

                        // Switch to depth first and change the traversal strategy of the entire system by notifying all child nodes of the change
                        parentEngine.PostEngineCommand(new ChangeTraversalTypeCommand(false, false));
                    }
                }
            }
        }
Example #9
0
        internal static BuildRequest CreateFromStream(BinaryReader reader)
        {
            BuildRequest request = new BuildRequest();

            request.requestId = reader.ReadInt32();
            request.handleId  = reader.ReadInt32();
            #region ProjectFileName
            if (reader.ReadByte() == 0)
            {
                request.projectFileName = null;
            }
            else
            {
                request.projectFileName = reader.ReadString();
            }
            #endregion
            #region TargetNames
            if (reader.ReadByte() == 0)
            {
                request.targetNames = null;
            }
            else
            {
                int numberOfTargetNames = reader.ReadInt32();
                request.targetNames = new string[numberOfTargetNames];
                for (int i = 0; i < numberOfTargetNames; i++)
                {
                    if (reader.ReadByte() == 0)
                    {
                        request.targetNames[i] = null;
                    }
                    else
                    {
                        request.targetNames[i] = reader.ReadString();
                    }
                }
            }
            #endregion
            #region GlobalProperties
            if (reader.ReadByte() == 0)
            {
                request.globalProperties = null;
            }
            else
            {
                request.globalProperties = new BuildPropertyGroup();
                request.globalProperties.CreateFromStream(reader);
            }
            #endregion
            #region ToolsetVersion
            if (reader.ReadByte() == 0)
            {
                request.toolsetVersion = null;
            }
            else
            {
                request.toolsetVersion = reader.ReadString();
            }
            #endregion
            request.unloadProjectsOnCompletion = reader.ReadBoolean();
            request.useResultsCache            = reader.ReadBoolean();
            #region BuildEventContext
            if (reader.ReadByte() == 0)
            {
                request.buildEventContext = null;
            }
            else
            {
                // Re create event context
                int nodeId           = reader.ReadInt32();
                int projectContextId = reader.ReadInt32();
                int targetId         = reader.ReadInt32();
                int taskId           = reader.ReadInt32();
                request.buildEventContext = new BuildEventContext(nodeId, targetId, projectContextId, taskId);
            }
            #endregion
            #region ToolsVersionPeekedFromProjectFile
            // We need to pass this over shared memory because where ever this project is being built needs to know
            // if the tools version was an override or was retreived from the project file
            if (reader.ReadByte() == 0)
            {
                request.toolsVersionPeekedFromProjectFile = false;
            }
            else
            {
                request.toolsVersionPeekedFromProjectFile = true;
            }
            #endregion
            return(request);
        }
Example #10
0
        public void TestRequestCachingDefaultInitialTargets()
        {
            CacheManager cacheManager = new CacheManager("3.5");

            ArrayList actuallyBuiltTargets;
            CacheScope cacheScope = cacheManager.GetCacheScope("test.proj", new BuildPropertyGroup(), null, CacheContentType.BuildResults);
            cacheScope.AddCacheEntry(new PropertyCacheEntry(Constants.defaultTargetCacheName, "Target1;Target2"));
            cacheScope.AddCacheEntry(new PropertyCacheEntry(Constants.initialTargetCacheName, "Initial1"));
            cacheScope.AddCacheEntry(new PropertyCacheEntry(Constants.projectIdCacheName, "5"));
            
            CacheEntry cacheEntry = new BuildResultCacheEntry("Initial1", null, true);
            cacheManager.SetCacheEntries(new CacheEntry[] { cacheEntry }, "test.proj", new BuildPropertyGroup(), "3.5", CacheContentType.BuildResults);
            cacheEntry = new BuildResultCacheEntry("Target1", null, true);
            cacheManager.SetCacheEntries(new CacheEntry[] { cacheEntry }, "test.proj", new BuildPropertyGroup(), null, CacheContentType.BuildResults);
            cacheEntry = new BuildResultCacheEntry("Target2", null, false);
            cacheManager.SetCacheEntries(new CacheEntry[] { cacheEntry }, "test.proj", new BuildPropertyGroup(), "3.5", CacheContentType.BuildResults);
            cacheEntry = new BuildResultCacheEntry("Target3", null, true);
            cacheManager.SetCacheEntries(new CacheEntry[] { cacheEntry }, "test.proj", new BuildPropertyGroup(), null, CacheContentType.BuildResults);

            // Default target
            BuildRequest defaultRequest = new BuildRequest(1, "test.proj", null, new BuildPropertyGroup(), null, 1, true, false);
            BuildResult buildResult = cacheManager.GetCachedBuildResult(defaultRequest, out actuallyBuiltTargets);
            Assert.IsNotNull(buildResult, "Expect a cached value if scope contains data");

            Assert.AreEqual(3, actuallyBuiltTargets.Count);
            Assert.AreEqual("Initial1", actuallyBuiltTargets[0]);
            Assert.AreEqual("Target1", actuallyBuiltTargets[1]);
            Assert.AreEqual("Target2", actuallyBuiltTargets[2]);
            Assert.AreEqual(3, buildResult.ResultByTarget.Count);
            Assert.AreEqual(Target.BuildState.CompletedSuccessfully, buildResult.ResultByTarget["Initial1"]);
            Assert.AreEqual(Target.BuildState.CompletedSuccessfully, buildResult.ResultByTarget["Target1"]);
            Assert.AreEqual(Target.BuildState.CompletedUnsuccessfully, buildResult.ResultByTarget["Target2"]);
            Assert.AreEqual(false, buildResult.EvaluationResult);
            Assert.AreEqual(5, buildResult.ProjectId);

            // Specific target
            BuildRequest specificRequest = new BuildRequest(1, "test.proj", new string[] { "Target3" }, new BuildPropertyGroup(), null, 1, true, false);
            buildResult = cacheManager.GetCachedBuildResult(specificRequest, out actuallyBuiltTargets);
            Assert.IsNotNull(buildResult, "Expect a cached value if scope contains data");

            Assert.AreEqual(2, actuallyBuiltTargets.Count);
            Assert.AreEqual("Initial1", actuallyBuiltTargets[0]);
            Assert.AreEqual("Target3", actuallyBuiltTargets[1]);
            Assert.AreEqual(2, buildResult.ResultByTarget.Count);
            Assert.AreEqual(Target.BuildState.CompletedSuccessfully, buildResult.ResultByTarget["Initial1"]);
            Assert.AreEqual(Target.BuildState.CompletedSuccessfully, buildResult.ResultByTarget["Target3"]);
            Assert.AreEqual(true, buildResult.EvaluationResult);
            Assert.AreEqual(5, buildResult.ProjectId);
        }
Example #11
0
 internal LocalCallDescriptorForPostBuildRequests(BuildRequest buildRequest)
     : base(LocalCallType.PostBuildRequests)
 {
     this.buildRequests = new BuildRequest[1];
     this.buildRequests[0] = buildRequest;
 }
Example #12
0
 internal static BuildRequest CreateFromStream(BinaryReader reader)
 {
     BuildRequest request = new BuildRequest();
     request.requestId = reader.ReadInt32();
     request.handleId = reader.ReadInt32();
     #region ProjectFileName
     if (reader.ReadByte() == 0)
     {
         request.projectFileName = null;
     }
     else
     {
         request.projectFileName = reader.ReadString();
     }
     #endregion
     #region TargetNames
     if (reader.ReadByte() == 0)
     {
         request.targetNames = null;
     }
     else
     {
         int numberOfTargetNames = reader.ReadInt32();
         request.targetNames = new string[numberOfTargetNames];
         for (int i = 0; i < numberOfTargetNames; i++)
         {
             if (reader.ReadByte() == 0)
             {
                 request.targetNames[i] = null;
             }
             else
             {
                 request.targetNames[i] = reader.ReadString();
             }
         }
     }
     #endregion
     #region GlobalProperties
     if (reader.ReadByte() == 0)
     {
         request.globalProperties = null;
     }
     else
     {
         request.globalProperties = new BuildPropertyGroup();
         request.globalProperties.CreateFromStream(reader);
     }
     #endregion
     #region ToolsetVersion
     if (reader.ReadByte() == 0)
     {
         request.toolsetVersion = null;
     }
     else
     {
         request.toolsetVersion = reader.ReadString();
     }
     #endregion
     request.unloadProjectsOnCompletion = reader.ReadBoolean();
     request.useResultsCache = reader.ReadBoolean();
     #region BuildEventContext
     if (reader.ReadByte() == 0)
     {
         request.buildEventContext = null;
     }
     else
     {
         // Re create event context
         int nodeId = reader.ReadInt32();
         int projectContextId = reader.ReadInt32();
         int targetId = reader.ReadInt32();
         int taskId = reader.ReadInt32();
         request.buildEventContext = new BuildEventContext(nodeId, targetId, projectContextId, taskId);
     }
     #endregion
     #region ToolsVersionPeekedFromProjectFile
     // We need to pass this over shared memory because where ever this project is being built needs to know
     // if the tools version was an override or was retreived from the project file
     if (reader.ReadByte() == 0)
     {
         request.toolsVersionPeekedFromProjectFile = false;
     }
     else
     {
         request.toolsVersionPeekedFromProjectFile = true;
     }
     #endregion
     return request;
 }
Example #13
0
 /// <summary>
 /// Post a build request to a node, the node index is an index into the list of nodes provided by all node providers
 /// registered to the node manager, the 0 in index is a local call to taskexecutionmodule
 /// </summary>
 /// <param name="nodeIndex"></param>
 /// <param name="buildRequest"></param>
 internal void PostBuildRequestToNode(int nodeIndex, BuildRequest buildRequest)
 {
     ErrorUtilities.VerifyThrow(nodeIndex != 0, "Should not use NodeManager to post to local TEM");
     nodeList[nodeIndex - 1].NodeProvider.PostBuildRequestToNode(nodeList[nodeIndex - 1].NodeIndex, buildRequest);
 }
Example #14
0
        private void ProcessBuildRequest(BuildRequest buildRequest)
        {
            ExecutionContext executionContext = GetExecutionContextFromHandleId(buildRequest.HandleId);

            // Restore the requests non-serialized data to the correct state
            buildRequest.RestoreNonSerializedDefaults();
            buildRequest.NodeIndex = executionContext.NodeIndex;

            ErrorUtilities.VerifyThrow(buildRequest.ParentBuildEventContext != null, "Should not have a null parentBuildEventContext");
            ErrorUtilities.VerifyThrow(buildRequest.IsGeneratedRequest, "Should not be sending a non generated request from the child node to the parent node");

            // For buildRequests originating from the TEM  - additional initialization is necessary
            TaskExecutionContext taskExecutionContext = executionContext as TaskExecutionContext;

            if (taskExecutionContext != null)
            {
                Project parentProject = taskExecutionContext.ParentProject;
                buildRequest.ParentHandleId  = taskExecutionContext.TriggeringBuildRequest.HandleId;
                buildRequest.ParentRequestId = taskExecutionContext.TriggeringBuildRequest.RequestId;

                if (buildRequest.ToolsetVersion == null && parentProject.OverridingToolsVersion)
                {
                    // If the MSBuild task (or whatever) didn't give us a specific tools version,
                    // but the parent project is using an overridden tools version, then use that one
                    buildRequest.ToolsetVersion = parentProject.ToolsVersion;
                }

                try
                {
                    if (buildRequest.GlobalProperties == null)
                    {
                        try
                        {
                            // Make sure we have a blank global properties because if there is a problem merging them we wont have a crash when we try and cache the build result.
                            buildRequest.GlobalProperties = new BuildPropertyGroup();
                            buildRequest.GlobalProperties =
                                parentEngine.MergeGlobalProperties(parentProject.GlobalProperties, null,
                                                                   buildRequest.ProjectFileName,
                                                                   buildRequest.GlobalPropertiesPassedByTask);
                        }
                        catch (ArgumentException e)
                        {
                            ConvertToInvalidProjectException(buildRequest, parentProject, e);
                        }
                        catch (InvalidOperationException e)
                        {
                            ConvertToInvalidProjectException(buildRequest, parentProject, e);
                        }
                    }

                    // We need to figure out which project object this request is refering to
                    if (buildRequest.ProjectFileName == null)
                    {
                        ErrorUtilities.VerifyThrow(parentProject != null, "Parent project must be non-null");

                        // This means the caller (the MSBuild task) wants us to use the same project as the calling
                        // project.  This allows people to avoid passing in the Projects parameter on the MSBuild task.
                        Project projectToBuild = parentProject;

                        // If the parent project (the calling project) already has the same set of global properties
                        // as what is being requested, just re-use it.  Otherwise, we need to instantiate a new
                        // project object that has the same project contents but different global properties.
                        if (!projectToBuild.GlobalProperties.IsEquivalent(buildRequest.GlobalProperties) &&
                            (String.Equals(parentProject.ToolsVersion, buildRequest.ToolsetVersion, StringComparison.OrdinalIgnoreCase)))
                        {
                            projectToBuild = parentEngine.GetMatchingProject(parentProject,
                                                                             parentProject.FullFileName, buildRequest.GlobalProperties,
                                                                             buildRequest.ToolsetVersion, buildRequest.TargetNames, buildRequest.ParentBuildEventContext, buildRequest.ToolsVersionPeekedFromProjectFile);
                        }
                        buildRequest.ProjectToBuild  = projectToBuild;
                        buildRequest.ProjectFileName = projectToBuild.FullFileName;
                        buildRequest.FireProjectStartedFinishedEvents = false;
                    }
                }
                catch (InvalidProjectFileException e)
                {
                    buildRequest.BuildCompleted = true;
                    // Store message so it can be logged by the engine build loop
                    buildRequest.BuildException = e;
                }
            }
            else
            {
                RequestRoutingContext requestRoutingContext = executionContext as RequestRoutingContext;
                buildRequest.ParentHandleId  = requestRoutingContext.ParentHandleId;
                buildRequest.ParentRequestId = requestRoutingContext.ParentRequestId;
            }
        }
Example #15
0
        /// <summary>
        /// Get a cached build result if available for the given request. This method is thread safe.
        /// </summary>
        /// <param name="buildRequest"></param>
        /// <param name="actuallyBuiltTargets"></param>
        /// <returns></returns>
        internal BuildResult GetCachedBuildResult(BuildRequest buildRequest, out ArrayList actuallyBuiltTargets)
        {
            actuallyBuiltTargets = null;

            PropertyCacheEntry defaultTargetsCacheEntry, initialTargetsCacheEntry, projectIdCacheEntry;

            // No writes here, but since we're reading multiple values we want to get a consistent view of the cache
            cacheScopeReaderWriterLock.AcquireReaderLock(Timeout.Infinite);

            try
            {
                defaultTargetsCacheEntry = (PropertyCacheEntry)GetCacheEntry(Constants.defaultTargetCacheName);
                initialTargetsCacheEntry = (PropertyCacheEntry)GetCacheEntry(Constants.initialTargetCacheName);
                projectIdCacheEntry      = (PropertyCacheEntry)GetCacheEntry(Constants.projectIdCacheName);
            }
            finally
            {
                cacheScopeReaderWriterLock.ReleaseReaderLock();
            }

            // If we ever built anything in this project we must have the default and initial targets.
            if (defaultTargetsCacheEntry == null && initialTargetsCacheEntry == null)
            {
                return(null);
            }

            ErrorUtilities.VerifyThrow(projectIdCacheEntry != null, "We should always have the projectId cache entry");

            ErrorUtilities.VerifyThrow(defaultTargetsCacheEntry != null && initialTargetsCacheEntry != null,
                                       "We should have both the initial and default targets in the cache");

            ArrayList targetsToBuild = new ArrayList(initialTargetsCacheEntry.Value.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries));

            if (buildRequest.TargetNames == null || buildRequest.TargetNames.Length == 0)
            {
                targetsToBuild.AddRange(defaultTargetsCacheEntry.Value.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries));
            }
            else
            {
                targetsToBuild.AddRange(buildRequest.TargetNames);
            }

            // Create variable to hold the cached outputs
            Hashtable outputsByTargetName = new Hashtable(targetsToBuild.Count);
            Hashtable resultByTarget      = new Hashtable(targetsToBuild.Count, StringComparer.OrdinalIgnoreCase);

            bool overallSuccess = true;
            bool missingValues  = false;

            // No writes here, but since we're reading multiple values we want to get a consistent view of the cache
            cacheScopeReaderWriterLock.AcquireReaderLock(Timeout.Infinite);

            try
            {
                for (int i = 0; i < targetsToBuild.Count; i++)
                {
                    string targetName = EscapingUtilities.UnescapeAll((string)targetsToBuild[i]);
                    if (ContainsCacheEntry(targetName))
                    {
                        BuildResultCacheEntry cacheEntry = (BuildResultCacheEntry)GetCacheEntry(targetName);
                        overallSuccess             = overallSuccess && cacheEntry.BuildResult;
                        resultByTarget[targetName] = (cacheEntry.BuildResult) ?
                                                     Target.BuildState.CompletedSuccessfully : Target.BuildState.CompletedUnsuccessfully;

                        // Restore output items for successful targets
                        if (cacheEntry.BuildResult)
                        {
                            outputsByTargetName[targetName] = cacheEntry.BuildItems;
                        }
                        // We found a failed target - cut the loop short
                        else
                        {
                            break;
                        }
                    }
                    else
                    {
                        missingValues = true;
                        break;
                    }
                }
            }
            finally
            {
                cacheScopeReaderWriterLock.ReleaseReaderLock();
            }

            if (missingValues)
            {
                return(null);
            }

            actuallyBuiltTargets = targetsToBuild;

            return(new BuildResult(outputsByTargetName, resultByTarget, overallSuccess, buildRequest.HandleId, buildRequest.RequestId,
                                   int.Parse(projectIdCacheEntry.Value, CultureInfo.InvariantCulture), false /* use results cache */,
                                   defaultTargetsCacheEntry.Value, initialTargetsCacheEntry.Value, 0, 0, 0));
        }
Example #16
0
        /// <summary>
        /// For each target that has a cross node build request waiting for it to complete, iterate
        /// over the list of outstanding requests and find the matching out going request. Once
        /// the matching request is found - link the parent and child targets.
        /// </summary>
        private void LinkCrossNodeBuildRequests()
        {
            foreach (GraphNode node in dependencyGraph.Values)
            {
                TargetInProgessState.TargetIdWrapper[] parentsForBuildRequests =
                    new TargetInProgessState.TargetIdWrapper[node.targetState.ParentBuildRequests.Count];

                for (int j = 0; j < node.targetState.ParentBuildRequests.Count; j++)
                {
                    BuildRequest buildRequest = node.targetState.ParentBuildRequests[j];
                    int          nodeIndex    = buildRequest.NodeIndex;
                    int          handleId     = buildRequest.HandleId;
                    int          requestId    = buildRequest.RequestId;
                    bool         foundParent  = false;

                    // Skip requests that originated from the host
                    if (handleId == EngineCallback.invalidEngineHandle)
                    {
                        node.isRoot = true;
                        continue;
                    }

                    // If the request being analyzed came from one of the child nodes, its incoming external request's
                    // handleId will point at a routing context on the parent engine. If the outgoing request
                    // orginated from another child the two requests (outgoing and incoming) point at different
                    // routing contexts. In that case it is necessary to unwind the incoming request to the routing
                    // context of the outgoing request. If outgoing request originated from the parent node -
                    // there will be only one routing request.
                    if (node.targetState.TargetId.nodeId != 0)
                    {
                        ExecutionContext      executionContext = engineCallback.GetExecutionContextFromHandleId(buildRequest.HandleId);
                        RequestRoutingContext routingContext   = executionContext as RequestRoutingContext;
                        if (routingContext != null && routingContext.ParentHandleId != EngineCallback.invalidEngineHandle)
                        {
                            ExecutionContext nextExecutionContext = engineCallback.GetExecutionContextFromHandleId(routingContext.ParentHandleId);

                            if (nextExecutionContext is RequestRoutingContext)
                            {
                                nodeIndex = nextExecutionContext.NodeIndex;
                                handleId  = routingContext.ParentHandleId;
                                requestId = routingContext.ParentRequestId;
                            }
                        }
                        else
                        {
                            // Skip requests that originated from the host
                            node.isRoot = true;
                            continue;
                        }
                    }

                    // Iterate over all outstanding requests until a match is found
                    foreach (DictionaryEntry entry in outstandingExternalRequests)
                    {
                        BuildRequest[] externalRequests = (BuildRequest[])entry.Value;
                        for (int i = 0; i < externalRequests.Length && !foundParent; i++)
                        {
                            if (handleId == externalRequests[i].HandleId &&
                                requestId == externalRequests[i].RequestId &&
                                nodeIndex == externalRequests[i].NodeIndex)
                            {
                                // Verify that the project name is the same
                                ErrorUtilities.VerifyThrow(
                                    String.Compare(buildRequest.ProjectFileName, externalRequests[i].ProjectFileName, StringComparison.OrdinalIgnoreCase) == 0,
                                    "The two requests should have the same project name");

                                // Link the two graph nodes together
                                GraphNode parentNode = (GraphNode)dependencyGraph[entry.Key];
                                parentNode.children.Add(node);

                                parentsForBuildRequests[j] = parentNode.targetState.TargetId;

                                foundParent = true;
                            }
                        }

                        if (foundParent)
                        {
                            break;
                        }
                    }
                }
                node.targetState.ParentTargetsForBuildRequests = parentsForBuildRequests;
            }
        }
Example #17
0
        private ProjectBuildState InitializeForBuildingTargets(BuildRequest buildRequest)
        {
            ProjectBuildState buildContext = null;

            string[] targetNamesToBuild = buildRequest.TargetNames;
            
            // Initialize to the parent requests project context id
            int projectContextId = buildRequest.ParentBuildEventContext.ProjectContextId;

            BuildEventContext buildEventContext = null;

            // Determine if a project started event is required to be fired, if so we may need a new projectContextId
             if (buildRequest.FireProjectStartedFinishedEvents)
             {
                 //If we have not already used the context from the project yet, lets use that as our first event context
                 if (!haveUsedInitialProjectContextId)
                 {
                     buildEventContext = projectBuildEventContext;
                     haveUsedInitialProjectContextId = true;
                 }
                 else // We are going to need a new Project context Id and a new buildEventContext
                 {
                     projectContextId = parentEngine.GetNextProjectId();
                 }
             }

             if (buildEventContext == null)
             {
                 buildEventContext = new BuildEventContext
                                   (
                                       projectBuildEventContext.NodeId,
                                       projectBuildEventContext.TargetId,
                                       projectContextId,
                                       projectBuildEventContext.TaskId
                                    );
             }

            bool exitedDueToError = true;

            try
            {
                // Refreshing (reevaluating) a project may end up calling ResetBuildStatus which will mark
                // IsReset=true.  This is legitimate because when a project is being reevaluated, we want
                // to be explicit in saying that any targets that had run previously are no longer valid,
                // and we must rebuild them on the next build.
                this.RefreshProjectIfDirty();

                // Only log the project started event after making sure the project is reevaluated if necessary,
                // otherwise we could log stale item/property information.
                if (!ParentEngine.LoggingServices.OnlyLogCriticalEvents && buildRequest.FireProjectStartedFinishedEvents)
                {  
                    string joinedTargetNamesToBuild = null;
                    if (targetNamesToBuild != null && targetNamesToBuild.Length > 0)
                    {
                        joinedTargetNamesToBuild = EscapingUtilities.UnescapeAll(String.Join(";", targetNamesToBuild));
                    }

                    // Flag the start of the project build.
                    //
                    // This also passes all the current properties/items and their values. The logger might want to use the
                    // object it gets from this event to see updated property/item values later in the build: so be 
                    // careful to use the original "evaluatedProperties" and "evaluatedItems" table, not the clone 
                    // "EvaluatedProperties" or "EvaluatedItems" table. It's fine to pass these live tables, because we're 
                    // wrapping them in read-only proxies.
                    BuildPropertyGroup propertyGroupForStartedEvent = this.evaluatedProperties;

                    // If we are on the child process we need to fiure out which properties we need to serialize
                    if (ParentEngine.Router.ChildMode)
                    {
                        // Initially set it to empty so that we do not serialize all properties if we are on a child node
                        propertyGroupForStartedEvent = new BuildPropertyGroup();

                        // Get the list of properties to serialize to the parent node
                        string[] propertyListToSerialize = parentEngine.PropertyListToSerialize;
                        if (propertyListToSerialize != null && propertyListToSerialize.Length > 0)
                        {
                            foreach (string propertyToGet in propertyListToSerialize)
                            {
                                BuildProperty property = this.evaluatedProperties[propertyToGet];

                                //property can be null if propertyToGet does not exist
                                if (property != null)
                                {
                                    propertyGroupForStartedEvent.SetProperty(property);
                                }
                            }
                        }
                    }

                    BuildPropertyGroupProxy propertiesProxy = new BuildPropertyGroupProxy(propertyGroupForStartedEvent);
                    BuildItemGroupProxy itemsProxy = new BuildItemGroupProxy(this.evaluatedItems);

                    ParentEngine.LoggingServices.LogProjectStarted(this.projectId, buildRequest.ParentBuildEventContext, buildEventContext, FullFileName, joinedTargetNamesToBuild, propertiesProxy, itemsProxy);
                    
                    // See comment on DefaultToolsVersion setter.
                    if (treatinghigherToolsVersionsAs40)
                    {
                        ParentEngine.LoggingServices.LogComment(buildEventContext, MessageImportance.High, "TreatingHigherToolsVersionAs40", DefaultToolsVersion);
                    }

                    ParentEngine.LoggingServices.LogComment(buildEventContext, MessageImportance.Low, "ToolsVersionInEffectForBuild", ToolsVersion);
                }

                // Incrementing the building count. A single project may be building more than once at a time
                // because of callbacks by the MSBuild task.
                this.buildingCount++;

                // Because we are about to build some targets, we are no longer going to be in the "reset"
                // state.
                this.IsReset = false;

                // This is an ArrayList of strings, where each string is the name of a target that
                // we need to build.  We start out by populating it with the list of targets specified
                // in the "InitialTargets" attribute of the <Project> node.
                ArrayList completeListOfTargetNamesToBuild = this.CombinedInitialTargetNames;

                if (buildRequest.UseResultsCache)
                {
                    buildRequest.InitialTargets = string.Join(";", (string[])completeListOfTargetNamesToBuild.ToArray(typeof(string)));
                    buildRequest.DefaultTargets = (this.DefaultBuildTargets != null) ? string.Join(";", this.DefaultBuildTargets) : string.Empty;
                    buildRequest.ProjectId = this.projectId;
                }

                // If no targets were passed in, use the "defaultTargets" from the
                // project file.
                if ((targetNamesToBuild == null) || (targetNamesToBuild.Length == 0))
                {
                    string[] defaultTargetsToBuild = this.DefaultBuildTargets;

                    // There wasn't at least one target in the project, then we have
                    // a problem.
                    ProjectFileErrorUtilities.VerifyThrowInvalidProjectFile(defaultTargetsToBuild != null,
                        new BuildEventFileInfo(this.FullFileName), "NoTargetSpecified");

                    completeListOfTargetNamesToBuild.AddRange(defaultTargetsToBuild);
                }
                else
                {
                    completeListOfTargetNamesToBuild.AddRange(targetNamesToBuild);
                }

                // Check if the client requests that the project should be unloaded once it is completed
                needToUnloadProject = buildRequest.UnloadProjectsOnCompletion || needToUnloadProject;
                buildContext = new ProjectBuildState(buildRequest, completeListOfTargetNamesToBuild, buildEventContext);
                exitedDueToError = false;
            }
            catch (InvalidProjectFileException e)
            {
                // Make sure the Invalid Project error gets logged *before* ProjectFinished.  Otherwise,
                // the log is confusing.
                this.ParentEngine.LoggingServices.LogInvalidProjectFileError(buildEventContext, e);
                // Mark the build request as completed and failed. The build context is either not created
                // or discarded
                buildRequest.BuildCompleted = true;
                buildRequest.BuildSucceeded = false;
                buildContext = null;
            }
            finally
            {
                if (exitedDueToError)
                {
                    this.buildingCount--;

                    if (buildRequest.FireProjectStartedFinishedEvents)
                    {
                        ParentEngine.LoggingServices.LogProjectFinished(
                            buildEventContext,
                            FullFileName,
                            false);
                    }
                }
            }
            return buildContext;
        }
Example #18
0
        private static BuildRequest[] CreateBuildRequest()
        {
            string projectFileName = "ProjectFileName";
            string[] targetNames = new string[] { "Build" };
            BuildPropertyGroup globalProperties = null;
            string toolsVersion = "Tool35";
            int requestId = 1;
            int handleId = 4;

            globalProperties = new BuildPropertyGroup();
            BuildProperty propertyToAdd = new BuildProperty("PropertyName", "Value");
            globalProperties.SetProperty(propertyToAdd);
            BuildRequest[] requests = new BuildRequest[2];
            requests[0] = new BuildRequest(handleId, projectFileName, targetNames, globalProperties, toolsVersion, requestId, true, true);
            requests[0].ParentBuildEventContext = new BuildEventContext(1, 2, 3, 4);
            requests[1] = new BuildRequest(handleId, projectFileName, targetNames, globalProperties, toolsVersion, requestId, true, true);
            requests[1].ParentBuildEventContext = new BuildEventContext(1, 2, 3, 4);
            return requests;
        }
Example #19
0
        /// <summary>
        /// This internal method actually performs the build of the specified targets
        /// in the project.  If no targets are specified, then we build the
        /// "defaultTargets" as specified in the attribute of the &lt;Project&gt; element
        /// in the XML.
        /// </summary>
        /// <param name="buildRequest"></param>
        internal void BuildInternal
        (
            BuildRequest buildRequest
        )
        {
            // First, make sure that this project has its targets/tasks enabled.  They may have been disabled
            // by the host for security reasons.
            if (!this.BuildEnabled)
            {
                this.ParentEngine.LoggingServices.LogError(buildRequest.ParentBuildEventContext, new BuildEventFileInfo(FullFileName), "SecurityProjectBuildDisabled");
                buildRequest.BuildCompleted = true;

                if (buildRequest.HandleId != EngineCallback.invalidEngineHandle)
                {
                    ParentEngine.Router.PostDoneNotice(buildRequest);
                }
            }
            else
            {
                ProjectBuildState buildContext = InitializeForBuildingTargets(buildRequest);
                if (buildContext != null)
                {
                    ContinueBuild(buildContext, null);
                }
            }
        }
 internal void CreateFromStream(BinaryReader reader)
 {
     #region TargetId
     if (reader.ReadByte() == 0)
     {
         targetId = null;
     }
     else
     {
         targetId = new TargetIdWrapper();
         targetId.CreateFromStream(reader);
     }
     #endregion
     #region ParentTargets
     if (reader.ReadByte() == 0)
     {
         parentTargets = null;
     }
     else
     {
         int numberOfTargets = reader.ReadInt32();
         parentTargets = new List <TargetIdWrapper>(numberOfTargets);
         for (int i = 0; i < numberOfTargets; i++)
         {
             if (reader.ReadByte() == 0)
             {
                 parentTargets.Add(null);
             }
             else
             {
                 TargetIdWrapper wrapper = new TargetIdWrapper();
                 wrapper.CreateFromStream(reader);
                 parentTargets.Add(wrapper);
             }
         }
     }
     #endregion
     #region ParentBuildRequests
     if (reader.ReadByte() == 0)
     {
         parentBuildRequests = null;
     }
     else
     {
         int numberOfRequests = reader.ReadInt32();
         parentBuildRequests = new List <BuildRequest>(numberOfRequests);
         for (int i = 0; i < numberOfRequests; i++)
         {
             if (reader.ReadByte() == 0)
             {
                 parentBuildRequests.Add(null);
             }
             else
             {
                 parentBuildRequests.Add(BuildRequest.CreateFromStream(reader));
             }
         }
     }
     #endregion
     #region OutstandingBuildRequests
     if (reader.ReadByte() == 0)
     {
         outstandingBuildRequests = null;
     }
     else
     {
         int numberOfBuildRequests = reader.ReadInt32();
         outstandingBuildRequests = new BuildRequest[numberOfBuildRequests];
         for (int i = 0; i < numberOfBuildRequests; i++)
         {
             if (reader.ReadByte() == 0)
             {
                 outstandingBuildRequests[i] = null;
             }
             else
             {
                 outstandingBuildRequests[i] = BuildRequest.CreateFromStream(reader);
             }
         }
     }
     #endregion
     #region ParentTargetsForBuildRequests
     if (reader.ReadByte() == 0)
     {
         parentTargetsForBuildRequests = null;
     }
     else
     {
         int numberOfTargetsForBuildRequests = reader.ReadInt32();
         parentTargetsForBuildRequests = new TargetIdWrapper[numberOfTargetsForBuildRequests];
         for (int i = 0; i < numberOfTargetsForBuildRequests; i++)
         {
             if (reader.ReadByte() == 0)
             {
                 parentTargetsForBuildRequests[i] = null;
             }
             else
             {
                 TargetIdWrapper wrapper = new TargetIdWrapper();
                 wrapper.CreateFromStream(reader);
                 parentTargetsForBuildRequests[i] = wrapper;
             }
         }
     }
     #endregion
     #region ProjectName
     if (reader.ReadByte() == 0)
     {
         projectName = null;
     }
     else
     {
         projectName = reader.ReadString();
     }
     #endregion
 }
Example #21
0
        /// <summary>
        /// This method get a result from the cache if every target is cached.
        /// If any of the target are not present in the cache null is returned. This method is not thread safe.
        /// </summary>
        internal BuildResult GetCachedBuildResult(BuildRequest buildRequest, out ArrayList actuallyBuiltTargets)
        {
            actuallyBuiltTargets = null;

            if (!buildRequest.UseResultsCache)
            {
                return null;
            }

            // Retrieve list of scopes by this name
            string projectName = buildRequest.ProjectToBuild == null ?
                                 buildRequest.ProjectFileName : buildRequest.ProjectToBuild.FullFileName;

            // If the list exists search for matching scope properties otherwise create the list
            CacheScope cacheScope = GetCacheScopeIfExists(projectName, buildRequest.GlobalProperties, buildRequest.ToolsetVersion, CacheContentType.BuildResults);

            // If there is no cache entry for this project return null
            if (cacheScope == null)
            {
                return null;
            }

            return cacheScope.GetCachedBuildResult(buildRequest, out actuallyBuiltTargets);
        }
Example #22
0
        /// <summary>
        /// Once the buildRequests from the EngineCallback have been created they are sent to this method which will
        /// post the build requests to the parent engine and then wait on the results to come back.
        /// This method uses either a breadthFirst or depthFirst traversal strategy when sending buildRequests to the parent engine.
        /// This method will start in breadthFirst traversal. It will continue to use this strategy until one of two events occur:
        ///     1. The parent node sents a message indicating the TEM should switch to depthFirst traversal.
        ///     2. The number of buildRequests is larger than the batchRequestSize.
        /// In both of these cases the system will go from a breadthFirstTraversal to a depthFirst Traversal. In the second case
        /// a message will be sent to the parent engine to switch the system to depthFirst traversal as the system is starting to
        /// be overloaded with work.
        /// In a depth first strategy the buildRequests will be sent to the parent engine one at a time and waiting for results for
        /// each buildRequest sent. In a breadthFirst traversal strategy some number of the buildrequests will be sent to the parent engine
        /// in a batch of requests. The system will then wait on the results of ALL the build requests sent before continuing
        /// to send more build requests.
        /// </summary>
        private void WaitForBuildResults(int handleId, BuildResult[] buildResultsLocal, BuildRequest[] buildRequests)
        {
            // If the traversal strategy is breadth first and the number of requests is less than the batchRequestSize
            // or if there is only 1 build request then send ALL build requests to the parent engine and wait on the results.
            if ((breadthFirstTraversal && buildRequests.Length < batchRequestSize) || buildRequests.Length == 1)
            {
                engineCallback.PostBuildRequestsToHost(buildRequests);
                workerThread.WaitForResults(handleId, buildResultsLocal, buildRequests);
            }
            else
            {
                int currentRequestIndex    = 0; // Which build request is being processed
                int numberOfRequestsToSend = 0; // How many buildRequests are going to be sent based on the number of buildRequests remaining and the build request batch size.

                // Arrays that will be used to partion the buildRequests array when sending batches of builds requests at a time.
                BuildRequest[] wrapperArrayBreadthFirst = new BuildRequest[batchRequestSize];
                BuildResult[]  resultsArrayBreadthFirst = new BuildResult[batchRequestSize];

                // Pre allocate these arrays as they will always be only one element in size. They are assigned to and filled when doing a depth first traversal.
                BuildRequest[] wrapperArrayDepthFirst = new BuildRequest[1];
                BuildResult[]  resultsArrayDepthFirst = new BuildResult[1];

                // While there are still requests to send
                while (currentRequestIndex < buildRequests.Length)
                {
                    // If there is a breadth first traversal and there are more than batchRequestSize build requests, send the first batchRequestSize, then do the rest depth first
                    if (breadthFirstTraversal)
                    {
                        // Figure out how many requests to send, either the full batch size or only part of a batch
                        numberOfRequestsToSend = (buildRequests.Length - currentRequestIndex) < batchRequestSize ? (buildRequests.Length - currentRequestIndex) : batchRequestSize;

                        // Initialize the wrapper array to how many requests are going to be sent
                        if (numberOfRequestsToSend != wrapperArrayBreadthFirst.Length)
                        {
                            wrapperArrayBreadthFirst = new BuildRequest[numberOfRequestsToSend];
                            resultsArrayBreadthFirst = new BuildResult[numberOfRequestsToSend];
                        }

                        // Fill the wrapper array with one batch of build requests
                        for (int i = 0; i < numberOfRequestsToSend; i++)
                        {
                            wrapperArrayBreadthFirst[i]           = buildRequests[currentRequestIndex + i];
                            wrapperArrayBreadthFirst[i].RequestId = i;
                            resultsArrayBreadthFirst[i]           = null;
                        }

                        engineCallback.PostBuildRequestsToHost(wrapperArrayBreadthFirst);

                        // Only switch from breadth to depth if there are more thanbatchRequestSize items
                        if ((buildRequests.Length - currentRequestIndex) > batchRequestSize)
                        {
                            engineCallback.PostStatus(nodeId, new NodeStatus(false /* use depth first traversal*/), false /* don't block waiting on the send */);
                            breadthFirstTraversal = false;
                        }

                        workerThread.WaitForResults(handleId, resultsArrayBreadthFirst, wrapperArrayBreadthFirst);
                        Array.Copy(resultsArrayBreadthFirst, 0, buildResultsLocal, currentRequestIndex, numberOfRequestsToSend);
                        currentRequestIndex += numberOfRequestsToSend;
                    }

                    // Proceed with depth first traversal
                    while ((currentRequestIndex < buildRequests.Length) && !breadthFirstTraversal)
                    {
                        wrapperArrayDepthFirst[0] = buildRequests[currentRequestIndex];
                        buildRequests[currentRequestIndex].RequestId = 0;
                        resultsArrayDepthFirst[0] = null;

                        engineCallback.PostBuildRequestsToHost(wrapperArrayDepthFirst);
                        workerThread.WaitForResults(handleId, resultsArrayDepthFirst, wrapperArrayDepthFirst);
                        //Copy the result from an intermediate array to the full array
                        buildResultsLocal[currentRequestIndex] = resultsArrayDepthFirst[0];
                        //Check if the call failed (null result was returned)
                        if (buildResultsLocal[currentRequestIndex] == null)
                        {
                            return;
                        }

                        //Move to the next request
                        currentRequestIndex++;
                    }
                }
            }
        }
Example #23
0
 internal void PostBuildRequests(BuildRequest[] buildRequestArray)
 {
     buildRequests.EnqueueArray(buildRequestArray);
 }
Example #24
0
        /// <summary>
        /// This function will start a node and send requests to it
        /// </summary>
        private void LaunchNodeAndPostBuildRequest()
        {
            int nodeIndex = 0;

            // Find out what node to launch
            lock (nodesToLaunch)
            {
                nodeIndex = nodesToLaunch.Dequeue();
            }

            // If the provider is shutting down - don't launch the node
            if (shuttingDown)
            {
                nodeData[nodeIndex].NodeState = NodeState.NotLaunched;
                return;
            }

            try
            {
                // Either launch node or connect to an already running node
                InitializeNode(nodeIndex);

                if (!nodeData[nodeIndex].CommunicationFailed)
                {
                    // Change the state of the node to launched
                    lock (nodeStateLock)
                    {
                        nodeData[nodeIndex].NodeState = NodeState.Launched;
                    }

                    // Send all the requests to the node. Note that the requests may end up in
                    // mixed order with the request currently being posted.
                    LinkedListNode <BuildRequest> current = nodeData[nodeIndex].TargetList.First;
                    BuildRequest[] buildRequests          = new BuildRequest[nodeData[nodeIndex].TargetList.Count];
                    int            i = 0;
                    while (current != null)
                    {
                        buildRequests[i] = current.Value;
                        i++;

                        current = current.Next;
                    }
                    LocalCallDescriptorForPostBuildRequests callDescriptor =
                        new LocalCallDescriptorForPostBuildRequests(buildRequests);
                    nodeData[nodeIndex].NodeCommandQueue.Enqueue(callDescriptor);

                    nodeData[nodeIndex].TargetList = null;
                }
                else
                {
                    // Allow the engine to decide how to proceed since the node failed to launch
                    string message = ResourceUtilities.FormatResourceString("NodeProviderFailure");
                    ReportNodeCommunicationFailure(nodeIndex, new Exception(message), false);
                }
            }
            catch (Exception e)
            {
                // Allow the engine to deal with the exception
                ReportNodeCommunicationFailure(nodeIndex, e, false);
            }
        }
Example #25
0
        /// <summary>
        /// Given a build state try to find the parent target that caused this build state to
        /// come into being either via dependent, on error relationship or via IBuildEngine call
        /// </summary>
        internal TargetIdWrapper FindParentTarget
        (
            EngineCallback engineCallback,
            ProjectBuildState buildContext,
            Target target, 
            out BuildRequest parentRequest
        )
        {
            // We need to find the parent target
            parentRequest = null;

            // Skip build states that have already been filled
            if (buildContext.CurrentBuildContextState == ProjectBuildState.BuildContextState.RequestFilled)
            {
                return null;
            }

            // Check if the target was called due to a onerror or depends on call
            if (buildContext.ContainsBlockingTarget(target.Name))
            {
                // Figure out the record for the parent target
                Project containingProject = target.ParentProject;
                Target parentTarget = containingProject.Targets[buildContext.GetParentTarget(target.Name)];
                return new TargetIdWrapper(parentTarget);
            }
            else
            {
                // The build context must have formed due to IBuildEngine call
                ErrorUtilities.VerifyThrow(
                    String.Compare(EscapingUtilities.UnescapeAll(buildContext.NameOfTargetInProgress), target.Name, StringComparison.OrdinalIgnoreCase) == 0,
                    "The target should be the in progress target for the context");
                // This target is called due to IBuildEngine or host request
                return FindParentTargetForBuildRequest(engineCallback, buildContext.BuildRequest, out parentRequest);
            }
        }
Example #26
0
        private void NodeLocalEngineLoop()
        {
            buildInProgress = true;

            // Create a logging service for this build request
            localEngine =
                new Engine(parentGlobalProperties, toolsetSearchLocations, 1 /* cpus */, true /* child node */, this.nodeId, parentStartupDirectory, null);
            localEngine.Router.ChildMode  = true;
            localEngine.Router.ParentNode = this;

            this.outProcLoggingService = new EngineLoggingServicesOutProc(this, localEngine.FlushRequestEvent);

            if (nodeLoggers.Length != 0)
            {
                foreach (LoggerDescription loggerDescription in nodeLoggers)
                {
                    IForwardingLogger newLogger = null;
                    bool exitedDueToError       = true;
                    try
                    {
                        newLogger = loggerDescription.CreateForwardingLogger();
                        // Check if the class was not found in the assembly
                        if (newLogger == null)
                        {
                            InternalLoggerException.Throw(null, null, "FatalErrorWhileInitializingLogger", true, loggerDescription.Name);
                        }
                        newLogger.Verbosity  = loggerDescription.Verbosity;
                        newLogger.Parameters = loggerDescription.LoggerSwitchParameters;
                        newLogger.NodeId     = nodeId;
                        EventRedirector newRedirector = new EventRedirector(loggerDescription.LoggerId, outProcLoggingService);
                        newLogger.BuildEventRedirector = newRedirector;
                        exitedDueToError = false;
                    }
                    // Polite logger failure
                    catch (LoggerException e)
                    {
                        ReportUnhandledError(e);
                    }
                    // Logger class was not found
                    catch (InternalLoggerException e)
                    {
                        ReportUnhandledError(e);
                    }
                    catch (Exception e)
                    {
                        // Wrap the exception in a InternalLoggerException and send it to the parent node
                        string errorCode;
                        string helpKeyword;
                        string message = ResourceUtilities.FormatResourceString(out errorCode, out helpKeyword, "FatalErrorWhileInitializingLogger", loggerDescription.Name);
                        ReportUnhandledError(new InternalLoggerException(message, e, null, errorCode, helpKeyword, true));
                    }

                    // If there was a failure registering loggers, null out the engine pointer
                    if (exitedDueToError)
                    {
                        localEngine = null;
                        return;
                    }

                    localEngine.RegisterLogger(newLogger);
                }

                localEngine.ExternalLoggingServices = outProcLoggingService;
            }

            // Hook up logging service to forward all events to the central engine if necessary
            if (centralizedLogging)
            {
                if (nodeLoggers.Length != 0)
                {
                    localEngine.LoggingServices.ForwardingService = outProcLoggingService;
                    localEngine.ExternalLoggingServices           = outProcLoggingService;
                }
                else
                {
                    localEngine.LoggingServices = outProcLoggingService;
                }
            }

            localEngine.LoggingServices.OnlyLogCriticalEvents = this.logOnlyCriticalEvents;

            if (!useBreadthFirstTraversal)
            {
                localEngine.PostEngineCommand(new ChangeTraversalTypeCommand(useBreadthFirstTraversal, true));
            }

            // Post all the requests that passed in while the engine was being constructed
            // into the engine queue
            lock (buildRequests)
            {
                while (buildRequests.Count != 0)
                {
                    BuildRequest buildRequest = buildRequests.Dequeue();
                    localEngine.PostBuildRequest(buildRequest);
                }
            }

            try
            {
                // If there are forwarding loggers registered - generate a custom  build started
                if (nodeLoggers.Length > 0)
                {
                    localEngine.LoggingServices.LogBuildStarted(EngineLoggingServicesInProc.CENTRAL_ENGINE_EVENTSOURCE);
                    localEngine.LoggingServices.ProcessPostedLoggingEvents();
                }

                // Trigger the actual build if shutdown was not called while the engine was being initialized
                if (!nodeShutdown)
                {
                    localEngine.EngineBuildLoop(null);
                }
            }
            catch (Exception e)
            {
                // Unhandled exception during execution. The node has to be shutdown.
                ReportUnhandledError(e);
            }
            finally
            {
                if (localEngine != null)
                {
                    // Flush all the messages associated before shutting down
                    localEngine.LoggingServices.ProcessPostedLoggingEvents();

                    NodeManager nodeManager = localEngine.NodeManager;

                    // If the local engine is already shutting down, the TEM will be nulled out
                    if (nodeManager.TaskExecutionModule != null && nodeManager.TaskExecutionModule.TaskExecutionTime != 0)
                    {
                        TimeSpan taskTimeSpan = new TimeSpan(localEngine.NodeManager.TaskExecutionModule.TaskExecutionTime);
                        totalTaskTime = (int)taskTimeSpan.TotalMilliseconds;
                    }
                    localEngine.Shutdown();
                }
                // Flush all the events to the parent engine
                outProcLoggingService.ProcessPostedLoggingEvents();
                // Indicate that the node logger thread should exit
                exitNodeEvent.Set();
            }
        }
Example #27
0
        /// <summary>
        /// Given a build request try to find the target that caused it to come into being
        /// </summary>
        private TargetIdWrapper FindParentTargetForBuildRequest
        (
            EngineCallback engineCallback,
            BuildRequest triggeringBuildRequest,
            out BuildRequest parentTriggeringRequest
        )
        {
            parentTriggeringRequest = null;

            // If request is non-external and generated due to IBuildEngine call try
            // to find the target that caused the IBuildEngine call
            if (triggeringBuildRequest.IsGeneratedRequest && !triggeringBuildRequest.IsExternalRequest)
            {
                ExecutionContext executionContext =
                   engineCallback.GetExecutionContextFromHandleId(triggeringBuildRequest.HandleId);

                // If the parent context is not a routing context than we can
                // get the parent target from it
                if (executionContext is TaskExecutionContext)
                {
                    return new TargetIdWrapper(((TaskExecutionContext)executionContext).ParentTarget);
                }
                // If the parent context if a routing context the parent target is not available 
                // on the current node, so store the request instead
                else
                {
                    parentTriggeringRequest = triggeringBuildRequest;
                }
            }
            // If the request is external to the node - store the request since the parent target
            // is not available
            else if (triggeringBuildRequest.IsExternalRequest)
            {
                parentTriggeringRequest = triggeringBuildRequest;
            }
            else
            {
                requestedByHost = true;
            }

            return null;
        }
Example #28
0
        /// <summary>
        /// If there is an exception in process build request we will wrap it in an invalid project file exception as any exceptions caught here are really problems with a project file
        /// this exception will be handled in the engine and logged
        /// </summary>
        private static void ConvertToInvalidProjectException(BuildRequest buildRequest, Project parentProject, Exception e)
        {
            BuildEventFileInfo fileInfo = new BuildEventFileInfo(buildRequest.ProjectFileName);

            throw new InvalidProjectFileException(parentProject.FullFileName, fileInfo.Line, fileInfo.Column, fileInfo.EndLine, fileInfo.EndColumn, e.Message, null, null, null);
        }
Example #29
0
 /// <summary>
 /// If there is an exception in process build request we will wrap it in an invalid project file exception as any exceptions caught here are really problems with a project file
 /// this exception will be handled in the engine and logged
 /// </summary>
 private static void ConvertToInvalidProjectException(BuildRequest buildRequest, Project parentProject, Exception e)
 {
     BuildEventFileInfo fileInfo = new BuildEventFileInfo(buildRequest.ProjectFileName);
     throw new InvalidProjectFileException(parentProject.FullFileName, fileInfo.Line, fileInfo.Column, fileInfo.EndLine, fileInfo.EndColumn, e.Message, null, null, null);
 }
Example #30
0
 internal LocalCallDescriptorForPostBuildRequests(BuildRequest [] buildRequests)
     :base(LocalCallType.PostBuildRequests)
 {
     this.buildRequests = buildRequests;
 }
Example #31
0
        /// <summary>
        /// This method creates a new routing context. This method is not thread safe and must be called
        /// only from the engine thread.
        /// </summary>
        internal int CreateRoutingContext
        (
            int nodeIndex,
            int parentHandleId,
            int parentNodeIndex,
            int parentRequestId,
            CacheScope cacheScope,
            BuildRequest triggeringBuildRequest,
            BuildEventContext buildEventContext
        )
        {
            int handleId = nextContextId;
            nextContextId = nextContextId + 1;

            RequestRoutingContext executionContext =
                new RequestRoutingContext(handleId, nodeIndex, parentHandleId, parentNodeIndex, parentRequestId, 
                                          cacheScope, triggeringBuildRequest, buildEventContext);

            executionContexts.Add(handleId, executionContext);

            return handleId;
        }
Example #32
0
        /// <summary>
        /// This method specifies which node a particular build request has to be evaluated on.
        /// </summary>>
        /// <returns>Id of the node on which the build request should be performed</returns>
        internal int CalculateNodeForBuildRequest(BuildRequest currentRequest, int nodeIndexCurrent)
        {
            int nodeUsed = EngineCallback.inProcNode;

            if (childMode)
            {
                // If the project is already loaded on the current node or if the request
                // was sent from the parent - evaluate the request locally. In all other
                // cases send the request over to the parent
                if (nodeIndexCurrent != localNodeId && !currentRequest.IsExternalRequest)
                {
                    // This is the same as using EngineCallback.parentNode
                    nodeUsed = -1;
                }
            }
            else
            {
                // In single proc case return the current node
                if (nodes.Length == 1)
                {
                    return(nodeUsed);
                }

                // If the project is not loaded either locally or on a remote node - calculate the best node to use
                // If there are nodes with less than "nodeWorkLoadProjectCount" projects in progress, choose the node
                // with the lowest in progress projects. Otherwise choose a node which has the least
                // number of projects loaded. Resolve a tie in number of projects loaded by looking at the number
                // of inprogress projects
                nodeUsed = nodeIndexCurrent;
                // If we have not chosen an node yet, this can happen if the node was loaded previously on a child node
                if (nodeUsed == EngineCallback.invalidNode)
                {
                    if (useLoadBalancing)
                    {
                        #region UseLoadBalancing
                        int blockedNode = EngineCallback.invalidNode;
                        int blockedNodeRemainingProjectCount = nodeWorkLoadProjectCount;
                        int leastBusyNode            = EngineCallback.invalidNode;
                        int leastBusyInProgressCount = -1;
                        int leastLoadedNode          = EngineCallback.inProcNode;
                        int leastLoadedLoadCount     = totalRequestsPerNode[EngineCallback.inProcNode];
                        int leastLoadedBlockedCount  = blockedRequestsPerNode[EngineCallback.inProcNode];

                        for (int i = 0; i < nodes.Length; i++)
                        {
                            //postBlockCount indicates the number of projects which should be sent to a node to unblock it due to the
                            //node running out of work.
                            if (postBlockCount[i] != 0 && postBlockCount[i] < blockedNodeRemainingProjectCount)
                            {
                                blockedNode = i;
                                blockedNodeRemainingProjectCount = postBlockCount[i];
                            }
                            else
                            {
                                // Figure out which node has the least ammount of in progress work
                                int perNodeInProgress = totalRequestsPerNode[i] - blockedRequestsPerNode[i];
                                if ((perNodeInProgress < nodeWorkLoadProjectCount) &&
                                    (perNodeInProgress < leastBusyInProgressCount || leastBusyInProgressCount == -1))
                                {
                                    leastBusyNode            = i;
                                    leastBusyInProgressCount = perNodeInProgress;
                                }
                                // Find the node with the least ammount of requests in total
                                // or if the number of requests are the same find the node with the
                                // node with the least number of blocked requests
                                if ((totalRequestsPerNode[i] < leastLoadedLoadCount) ||
                                    (totalRequestsPerNode[i] == leastLoadedLoadCount && blockedRequestsPerNode[i] < leastLoadedBlockedCount))
                                {
                                    leastLoadedNode         = i;
                                    leastLoadedLoadCount    = totalRequestsPerNode[i];
                                    leastLoadedBlockedCount = perNodeInProgress;
                                }
                            }
                        }

                        // Give the work to a node blocked due to having no work . If there are no nodes without work
                        // give the work to the least loaded node
                        if (blockedNode != EngineCallback.invalidNode)
                        {
                            nodeUsed = blockedNode;
                            postBlockCount[blockedNode]--;
                        }
                        else
                        {
                            nodeUsed = (leastBusyNode != EngineCallback.invalidNode) ? leastBusyNode : leastLoadedNode;
                        }
                        #endregion
                    }
                    else
                    {
                        // round robin schedule the build request
                        nodeUsed = (lastUsedNode % nodes.Length);

                        // Running total of the number of times this round robin scheduler has been called
                        lastUsedNode++;

                        if (postBlockCount[nodeUsed] != 0)
                        {
                            postBlockCount[nodeUsed]--;
                        }
                    }
                }

                // Update the internal data structure to reflect the scheduling decision
                NotifyOfSchedulingDecision(currentRequest, nodeUsed);
            }
            return(nodeUsed);
        }
Example #33
0
        public void TestRequestCaching()
        {
            CacheManager cacheManager = new CacheManager("3.5");

            ArrayList actuallyBuiltTargets;

            // Test the case where we pass in null targets
            Dictionary<string, string> dictionary = new Dictionary<string,string>();
            BuildRequest emptyRequest = new BuildRequest(1, "test.proj", null, dictionary, null, 1, true, false);

            Assert.IsNull(cacheManager.GetCachedBuildResult(emptyRequest, out actuallyBuiltTargets), "Expect a null return value if T=null");

            // Test the case where we pass in length 0 targets
            BuildRequest length0Request = new BuildRequest(1, "test.proj", new string[0], dictionary, null, 1, true, false);
            Assert.IsNull(cacheManager.GetCachedBuildResult(length0Request, out actuallyBuiltTargets), "Expect a null return value if T.Length=0");

            // Test the case when the scope doesn't exist
            string[] targets = new string[1]; targets[0] = "Target1";
            BuildRequest length1Request = new BuildRequest(1, "test.proj", targets, new BuildPropertyGroup(), null, 1, true, false);
            Assert.IsNull(cacheManager.GetCachedBuildResult(length1Request, out actuallyBuiltTargets), "Expect a null return value if no scope");
            
            // Test the case when the scope exists but is empty
            CacheScope cacheScope = cacheManager.GetCacheScope("test.proj", new BuildPropertyGroup(), "3.5", CacheContentType.BuildResults);
            Assert.IsNull(cacheManager.GetCachedBuildResult(length1Request, out actuallyBuiltTargets), "Expect a null return value if scope is empty");
            
            // Test the case when the scope exists but contains wrong data
            CacheEntry cacheEntry = new BuildResultCacheEntry("Target2", null, true);
            cacheManager.SetCacheEntries(new CacheEntry[] { cacheEntry }, "test.proj", new BuildPropertyGroup(), "3.5", CacheContentType.BuildResults);
            Assert.IsNull(cacheManager.GetCachedBuildResult(length1Request, out actuallyBuiltTargets), "Expect a null return value if scope contains wrong data");
            
            // Test the case when everything is correct
            cacheScope.AddCacheEntry(new PropertyCacheEntry(Constants.defaultTargetCacheName, string.Empty));
            cacheScope.AddCacheEntry(new PropertyCacheEntry(Constants.initialTargetCacheName, string.Empty));
            cacheScope.AddCacheEntry(new PropertyCacheEntry(Constants.projectIdCacheName, "1"));
            
            cacheEntry = new BuildResultCacheEntry("Target1", null, true);
            cacheManager.SetCacheEntries(new CacheEntry[] { cacheEntry }, "test.proj", new BuildPropertyGroup(), "3.5", CacheContentType.BuildResults);
            BuildResult buildResult = cacheManager.GetCachedBuildResult(length1Request, out actuallyBuiltTargets);
            Assert.IsNotNull(buildResult, "Expect a cached value if scope contains data");
            Assert.AreEqual(1, actuallyBuiltTargets.Count);
            Assert.AreEqual("Target1", actuallyBuiltTargets[0]);
            Assert.AreEqual(1, buildResult.ResultByTarget.Count);
            Assert.AreEqual(Target.BuildState.CompletedSuccessfully, buildResult.ResultByTarget["Target1"]);

            // Test the case when the scope contains partially correct data
            targets = new string[2]; targets[0] = "Target2"; targets[1] = "Target3";
            BuildRequest length2Request = new BuildRequest(1, "test.proj", targets, new BuildPropertyGroup(), null, 1, true, false);
            Assert.IsNull(cacheManager.GetCachedBuildResult(length2Request, out actuallyBuiltTargets), "Expect a null return value if partial data in the scope");
            
            // Test the correctness case for multiple targets
            cacheEntry = new BuildResultCacheEntry("Target3", null, true);
            cacheManager.SetCacheEntries(new CacheEntry[] { cacheEntry }, "test.proj", new BuildPropertyGroup(), "3.5", CacheContentType.BuildResults);
            buildResult = cacheManager.GetCachedBuildResult(length2Request, out actuallyBuiltTargets);
            Assert.IsNotNull(buildResult, "Expect a cached value if scope contains data");

            Assert.AreEqual(2, actuallyBuiltTargets.Count);
            Assert.AreEqual("Target2", actuallyBuiltTargets[0]);
            Assert.AreEqual("Target3", actuallyBuiltTargets[1]);
            Assert.AreEqual(2, buildResult.ResultByTarget.Count);
            Assert.AreEqual(Target.BuildState.CompletedSuccessfully, buildResult.ResultByTarget["Target2"]);
            Assert.AreEqual(Target.BuildState.CompletedSuccessfully, buildResult.ResultByTarget["Target3"]);
            Assert.AreEqual(1, buildResult.ProjectId);
        }
Example #34
0
        private void HandleProjectFileInternalException(BuildRequest buildRequest)
        {
            // Flush out all the logging messages, which may have been posted outside target execution
            primaryLoggingServices.ProcessPostedLoggingEvents();
            
            // Mark evaluation as complete
            buildRequest.BuildCompleted = true;

            if (buildRequest.HandleId != EngineCallback.invalidEngineHandle)
            {
                Router.PostDoneNotice(buildRequest);
            }

            CheckForBuildCompletion();
        }
Example #35
0
 void INodeProvider.PostBuildRequestToNode(int nodeIndex, BuildRequest buildRequest)
 {
     if (nodeIndex > nodeDescriptions.Count)
     {
         throw new ArgumentException("Node index is out of range");
     }
     buildRequestsSubmittedToProvider.Add(buildRequest);
 }
Example #36
0
        private void ProcessBuildRequest(BuildRequest buildRequest)
        {
            ExecutionContext executionContext = GetExecutionContextFromHandleId(buildRequest.HandleId);
            // Restore the requests non-serialized data to the correct state
            buildRequest.RestoreNonSerializedDefaults();
            buildRequest.NodeIndex = executionContext.NodeIndex;

            ErrorUtilities.VerifyThrow(buildRequest.ParentBuildEventContext != null, "Should not have a null parentBuildEventContext");
            ErrorUtilities.VerifyThrow(buildRequest.IsGeneratedRequest == true, "Should not be sending a non generated request from the child node to the parent node");

            // For buildRequests originating from the TEM  - additional initialization is necessary
            TaskExecutionContext taskExecutionContext = executionContext as TaskExecutionContext;
            if (taskExecutionContext != null)
            {
                Project parentProject = taskExecutionContext.ParentProject;
                buildRequest.ParentHandleId = taskExecutionContext.TriggeringBuildRequest.HandleId;
                buildRequest.ParentRequestId = taskExecutionContext.TriggeringBuildRequest.RequestId;

                if (buildRequest.ToolsetVersion == null && parentProject.OverridingToolsVersion)
                {
                    // If the MSBuild task (or whatever) didn't give us a specific tools version,
                    // but the parent project is using an overridden tools version, then use that one
                    buildRequest.ToolsetVersion = parentProject.ToolsVersion;
                }

                try
                {
                    if (buildRequest.GlobalProperties == null)
                    {
                        try
                        {
                            // Make sure we have a blank global properties because if there is a problem merging them we wont have a crash when we try and cache the build result.
                            buildRequest.GlobalProperties = new BuildPropertyGroup();
                            buildRequest.GlobalProperties =
                                parentEngine.MergeGlobalProperties(parentProject.GlobalProperties, null,
                                                                   buildRequest.ProjectFileName,
                                                                   buildRequest.GlobalPropertiesPassedByTask);
                        }
                        catch (ArgumentException e) 
                        {
                            ConvertToInvalidProjectException(buildRequest, parentProject, e);
                        }
                        catch (InvalidOperationException e)
                        {
                            ConvertToInvalidProjectException(buildRequest, parentProject, e);
                        }
                    }

                    // We need to figure out which project object this request is refering to
                    if (buildRequest.ProjectFileName == null)
                    {
                        ErrorUtilities.VerifyThrow(parentProject != null, "Parent project must be non-null");

                        // This means the caller (the MSBuild task) wants us to use the same project as the calling 
                        // project.  This allows people to avoid passing in the Projects parameter on the MSBuild task.
                        Project projectToBuild = parentProject;



                        // If the parent project (the calling project) already has the same set of global properties
                        // as what is being requested, just re-use it.  Otherwise, we need to instantiate a new
                        // project object that has the same project contents but different global properties.
                        if (!projectToBuild.GlobalProperties.IsEquivalent(buildRequest.GlobalProperties) &&
                            (String.Compare(parentProject.ToolsVersion, buildRequest.ToolsetVersion, StringComparison.OrdinalIgnoreCase) == 0))
                        {
                            projectToBuild = parentEngine.GetMatchingProject(parentProject,
                                                 parentProject.FullFileName, buildRequest.GlobalProperties,
                                                 buildRequest.ToolsetVersion, buildRequest.TargetNames, buildRequest.ParentBuildEventContext, buildRequest.ToolsVersionPeekedFromProjectFile);
                        }
                        buildRequest.ProjectToBuild = projectToBuild;
                        buildRequest.ProjectFileName = projectToBuild.FullFileName;
                        buildRequest.FireProjectStartedFinishedEvents = false;
                    }
                }
                catch (InvalidProjectFileException e)
                {
                    buildRequest.BuildCompleted = true;
                    // Store message so it can be logged by the engine build loop
                    buildRequest.BuildException = e;
                }
            }
            else
            {
                RequestRoutingContext requestRoutingContext = executionContext as RequestRoutingContext;
                buildRequest.ParentHandleId = requestRoutingContext.ParentHandleId;
                buildRequest.ParentRequestId = requestRoutingContext.ParentRequestId;
            }
        }
Example #37
0
        /// <summary>
        /// This method lets the host request an evaluation of a build request. A local engine
        /// will be created if necessary.
        /// </summary>
        internal void PostBuildRequest
        (
            BuildRequest buildRequest
        )
        {
            buildRequest.RestoreNonSerializedDefaults();
            buildRequest.NodeIndex = EngineCallback.inProcNode;
            // A request has come from the parent engine, so mark it as external
            buildRequest.IsExternalRequest = true;

            if (localEngine == null)
            {
                // Check if an an engine has been allocated and if not start the thread that will do that
                lock (buildRequests)
                {
                    if (localEngine == null)
                    {
                        if (!launchedEngineLoopThread)
                        {
                            launchedEngineLoopThread = true;
                            ThreadStart threadState = new ThreadStart(this.NodeLocalEngineLoop);
                            Thread taskThread = new Thread(threadState);
                            taskThread.Name = "MSBuild Child Engine";                            
                            taskThread.SetApartmentState(ApartmentState.STA);
                            taskThread.Start();
                        }
                        buildRequests.Enqueue(buildRequest);
                    }
                    else
                    {
                        localEngine.PostBuildRequest(buildRequest);
                    }
                }
            }
            else
            {
                if (!buildInProgress)
                {
                    buildInProgress = true;
                    // If there are forwarding loggers registered - generate a custom  build started
                    if (nodeLoggers.Length > 0)
                    {
                        localEngine.LoggingServices.LogBuildStarted(EngineLoggingServicesInProc.CENTRAL_ENGINE_EVENTSOURCE);
                        localEngine.LoggingServices.ProcessPostedLoggingEvents();
                    }
                }
                localEngine.PostBuildRequest(buildRequest);
            }
        }
Example #38
0
        /// <summary>
        /// Pretend we're actually building a project when really we're just retrieving the results from the cache.
        /// </summary>
        /// <param name="buildRequest"></param>
        /// <param name="projectFileInfo"></param>
        /// <param name="actuallyBuiltTargets"></param>
        /// <param name="cachedResult"></param>
        private void ProcessCachedResult
        (
            BuildRequest buildRequest, 
            FileInfo projectFileInfo, 
            ArrayList actuallyBuiltTargets, 
            BuildResult cachedResult
        )
        {
            buildRequest.InitializeFromCachedResult(cachedResult);

            if (Engine.debugMode)
            {
                Console.WriteLine("===Reusing cached result for " + buildRequest.GetTargetNamesList() + " in " +
                                   buildRequest.ProjectFileName + " result is " + buildRequest.BuildSucceeded + " EngineNodeID: " + this.nodeId);
            }

            BuildEventContext requestContext = buildRequest.ParentBuildEventContext;
            BuildEventContext currentContext = new BuildEventContext(this.nodeId, BuildEventContext.InvalidTargetId, GetNextProjectId(), BuildEventContext.InvalidTaskId);

            primaryLoggingServices.LogProjectStarted(cachedResult.ProjectId, requestContext, currentContext, projectFileInfo.FullName,
                buildRequest.GetTargetNamesList(),
                new BuildPropertyGroupProxy(new BuildPropertyGroup()),
                new BuildItemGroupProxy(new BuildItemGroup()));
            primaryLoggingServices.LogComment(currentContext, MessageImportance.Low, "ToolsVersionInEffectForBuild", buildRequest.ToolsetVersion);

            for (int i = 0; i < actuallyBuiltTargets.Count; i++)
            {
                string builtTargetName = EscapingUtilities.UnescapeAll((string)actuallyBuiltTargets[i]);
                Target.BuildState buildState = (Target.BuildState)cachedResult.ResultByTarget[builtTargetName];
                buildRequest.ResultByTarget[builtTargetName] = buildState;

                primaryLoggingServices.LogComment(currentContext,
                    ((buildState == Target.BuildState.CompletedSuccessfully) ? "TargetAlreadyCompleteSuccess" : "TargetAlreadyCompleteFailure"),
                    builtTargetName);

                if (buildState == Target.BuildState.CompletedUnsuccessfully)
                {
                    break;
                }
            }

            primaryLoggingServices.LogProjectFinished(currentContext, projectFileInfo.FullName, cachedResult.EvaluationResult);

            if (!buildRequest.IsGeneratedRequest)
            {
                CheckForBuildCompletion();
            }
            else
            {
                Router.PostDoneNotice(buildRequest);
            }
        }
Example #39
0
 internal void PostBuildRequest(BuildRequest buildRequest)
 {
     buildRequests.Enqueue(buildRequest);
 }
        public void TargetInProgressStateCustomSerialization()
        {
            Engine engine = new Engine(@"c:\");
            Project project = ObjectModelHelpers.CreateInMemoryProject(@"
                   <Project DefaultTargets=`t` ToolsVersion=`msbuilddefaulttoolsversion` xmlns=`msbuildnamespace`>
                        <PropertyGroup>
                        <OutputPath>bin\Debug\</OutputPath>
                        <AssemblyName>MyAssembly</AssemblyName>
                        <OutputType>Exe</OutputType>
                        <Configuration>Debug</Configuration>
                      </PropertyGroup>
                      <ItemGroup>
                        <Compile Include=`Class1.cs` />
                        <EmbeddedResource Include=`Resource1.txt` />
                        <EmbeddedResource Include=`Resource2.resx` />
                      </ItemGroup>
                      <Target Name='t' DependsOnTargets='Build'/>
                    <Import Project=`$(MSBuildBinPath)\Microsoft.CSharp.Targets` />
                    </Project>
                "); 
            EngineCallback engineCallback = new EngineCallback(engine);
            Target build = project.Targets["Build"];
            List<ProjectBuildState> waitingBuildStates = null;

            int handleId = 1;
            string projectFileName = "ProjectFileName";
            string[] targetNames = new string[] { "t" };
            Dictionary<string, string> dictionary = null;
            int requestId = 1;
            BuildRequest request = new BuildRequest(handleId, projectFileName, targetNames, (IDictionary)dictionary, null, requestId, false, false);
            ArrayList targetNamesToBuild = new ArrayList();
            targetNamesToBuild.Add("t");
            ProjectBuildState initiatingRequest = new ProjectBuildState(request, targetNamesToBuild, new BuildEventContext(1, 2, 2, 2));
            initiatingRequest.AddBlockingTarget("Build");
            BuildRequest [] outstandingBuildRequests = null;
            string projectName = "SuperTestProject";
            
            

            TargetInProgessState targetInProgress1 = new TargetInProgessState(
                                                              engineCallback,
                                                              build,
                                                              waitingBuildStates,
                                                              initiatingRequest,
                                                              outstandingBuildRequests,
                                                              projectName
                                                          );
            
            targetInProgress1.ParentTargetsForBuildRequests = null;
            Assertion.AssertNull(targetInProgress1.ParentTargetsForBuildRequests);
            Assertion.Assert(!targetInProgress1.RequestedByHost);

            build = project.Targets["t"];
             request = new BuildRequest(handleId, projectFileName, targetNames, (IDictionary)dictionary, null, requestId, false, false);
            request.IsExternalRequest = true;
            targetNamesToBuild.Add("t");
            initiatingRequest = new ProjectBuildState(request, targetNamesToBuild, new BuildEventContext(1, 2, 2, 2));
            outstandingBuildRequests = new BuildRequest[]{
                new BuildRequest(1, projectFileName, targetNames, (IDictionary)dictionary, null, requestId, false, false),
                new BuildRequest(2, projectFileName, targetNames, (IDictionary)dictionary, null, requestId, false, false),
                new BuildRequest(3, projectFileName, targetNames, (IDictionary)dictionary, null, requestId, false, false),
                new BuildRequest(4, projectFileName, targetNames, (IDictionary)dictionary, null, requestId, false, false)
            };

            TargetInProgessState.TargetIdWrapper originalWrapper = new TargetInProgessState.TargetIdWrapper();
            originalWrapper.id = 1;
            originalWrapper.name = "Wrapper";
            originalWrapper.nodeId = 4;
            originalWrapper.projectId = 6;
            waitingBuildStates = new List<ProjectBuildState>();
            waitingBuildStates.Add(initiatingRequest);

            TargetInProgessState targetInProgress3 = new TargetInProgessState(
                                                              engineCallback,
                                                              build,
                                                              waitingBuildStates,
                                                              initiatingRequest,
                                                              outstandingBuildRequests,
                                                              projectName
                                                          );
            targetInProgress3.ParentTargetsForBuildRequests = new TargetInProgessState.TargetIdWrapper[] { originalWrapper };

            // Stream, writer and reader where the events will be serialized and deserialized from
            MemoryStream stream = new MemoryStream();
            BinaryWriter writer = new BinaryWriter(stream);
            BinaryReader reader = new BinaryReader(stream);
            try
            {
                stream.Position = 0;
                // Serialize
                targetInProgress3.WriteToStream(writer);
                // Get position of stream after write so it can be compared to the position after read
                long streamWriteEndPosition = stream.Position;

                // Deserialize and Verify
                stream.Position = 0;
                TargetInProgessState newInProgressState = new TargetInProgessState();
                newInProgressState.CreateFromStream(reader);
                long streamReadEndPosition = stream.Position;
                Assert.IsTrue(string.Compare(newInProgressState.ProjectName, projectName, StringComparison.OrdinalIgnoreCase) == 0);
                Assert.IsTrue(string.Compare(newInProgressState.TargetId.name, "t", StringComparison.OrdinalIgnoreCase) == 0);
                Assert.IsNotNull(newInProgressState.ParentTargets);
                Assert.IsTrue(newInProgressState.OutstandingBuildRequests.Length == 4);
                Assert.IsNotNull(newInProgressState.ParentBuildRequests);
                Assert.IsNotNull(newInProgressState.ParentTargetsForBuildRequests.Length == 1);

                stream.Position = 0;
                // Serialize
                targetInProgress1.WriteToStream(writer);
                // Get position of stream after write so it can be compared to the position after read
                 streamWriteEndPosition = stream.Position;

                // Deserialize and Verify
                stream.Position = 0;
                newInProgressState = new TargetInProgessState();
                newInProgressState.CreateFromStream(reader);
                streamReadEndPosition = stream.Position;
                Assert.IsTrue(string.Compare(newInProgressState.ProjectName, projectName,StringComparison.OrdinalIgnoreCase)==0);
                Assert.IsTrue(string.Compare(newInProgressState.TargetId.name,"Build",StringComparison.OrdinalIgnoreCase)==0);
                Assert.IsNotNull(newInProgressState.ParentTargets);
                Assert.IsNull(newInProgressState.OutstandingBuildRequests);
                Assert.IsNotNull(newInProgressState.ParentBuildRequests);

                TargetInProgessState targetInProgress2 = new TargetInProgessState();
                stream.Position = 0;
                // Serialize
                targetInProgress2.WriteToStream(writer);
                // Get position of stream after write so it can be compared to the position after read
                streamWriteEndPosition = stream.Position;

                // Deserialize and Verify
                stream.Position = 0;
                newInProgressState = new TargetInProgessState();
                newInProgressState.CreateFromStream(reader);
                streamReadEndPosition = stream.Position;
                Assert.IsNull(newInProgressState.ProjectName);
                Assert.IsNull(newInProgressState.TargetId);
                Assert.IsNull(newInProgressState.ParentTargets);
                Assert.IsNull(newInProgressState.OutstandingBuildRequests);
                Assert.IsNull(newInProgressState.ParentBuildRequests);
            }
            finally
            {
                // Close will close the writer/reader and the underlying stream
                writer.Close();
                reader.Close();
                reader = null;
                stream = null;
                writer = null;
            }
        }
Example #41
0
        /// <summary>
        /// This function implements the callback via the IBuildEngine interface
        /// </summary>
        /// <returns>result of call to engine</returns>
        virtual internal bool BuildProjectFile
        (
            int handleId, 
            string[] projectFileNames, 
            string[] targetNames, 
            IDictionary[] globalPropertiesPerProject,
            IDictionary[] targetOutputsPerProject,
            EngineLoggingServices loggingServices,
            string [] toolsVersions,
            bool useResultsCache,
            bool unloadProjectsOnCompletion, 
            BuildEventContext taskContext
        )
        {
            if (projectFileNames.Length == 0)
            {
                // Nothing to do, just return success
                return true;
            }

            string currentDir = FileUtilities.GetCurrentDirectoryStaticBuffer(currentDirectoryBuffer);

            if (Engine.debugMode)
            {
                string targetName = targetNames == null ? "null" : targetNames[0];

                bool remoteNode = false;
                for (int r = 0; r < projectFileNames.Length; r++)
                {
                    string fullProjectName = projectFileNames[r] != null ?
                       projectFileNames[r] : "null";
                    Console.WriteLine("RemoteNode: " + remoteNode + " Project " + fullProjectName + " T:" + targetName + " NodeProdyId# " + handleId + " Time " + DateTime.Now.ToLongTimeString());
                    if (globalPropertiesPerProject[r] != null)
                    {
                        foreach (DictionaryEntry entry in globalPropertiesPerProject[r])
                        {
                            Console.WriteLine(currentDir + " :GLOBAL " + entry.Key + "=" + entry.Value.ToString());
                        }
                    }
                }
            }

            BuildRequest[] buildRequests = new BuildRequest[projectFileNames.Length];
            for (int i = 0; i < buildRequests.Length; i++)
            {
                // We need to get the full path to the project before we call back
                // into the engine which has no control over current path
                string fullProjectName = projectFileNames[i] != null ?
                    Path.GetFullPath(projectFileNames[i]) : null;

                buildRequests[i] = new BuildRequest(handleId, fullProjectName, targetNames, globalPropertiesPerProject[i],
                                                    toolsVersions[i], i, useResultsCache, unloadProjectsOnCompletion);
                ErrorUtilities.VerifyThrow(buildRequests[i].IsGeneratedRequest == true, "Should not be sending non generated requests from TEM to engine");
                buildRequests[i].ParentBuildEventContext = taskContext;
            }

            BuildResult[] buildResultsLocal = new BuildResult[projectFileNames.Length];

            if (moduleMode == TaskExecutionModuleMode.SingleProcMode)
            {
                for (int i = 0; i < projectFileNames.Length; i++)
                {
                    // If we are running in a single threaded mode we need to
                    // re-enter the main build loop on the current thread in order
                    // to build the requested project, because the main build is below
                    // us on the stack
                    engineCallback.PostBuildRequestsToHost(new BuildRequest[] { buildRequests[i] });
                    buildResultsLocal[i] = engineCallback.GetParentEngine().EngineBuildLoop(buildRequests[i]);
                    buildResultsLocal[i].ConvertToTaskItems();
                }
            }
            else
            {
                WaitForBuildResults(handleId, buildResultsLocal, buildRequests);
            }

            // Store the outputs in the hashtables provided by the caller
            bool overallResult = true;
            for (int i = 0; i < buildResultsLocal.Length; i++)
            {
                // Users of the Object Model can pass in null targetOutputs for projects they do not want outputs for
                // therefore we need to make sure that there are targetoutputs and the users want the results
                if (buildResultsLocal[i] != null)
                {
                    if (buildResultsLocal[i].OutputsByTarget != null && targetOutputsPerProject[i] != null)
                    {
                        foreach (DictionaryEntry entry in buildResultsLocal[i].OutputsByTarget)
                        {
                            targetOutputsPerProject[i].Add(entry.Key, entry.Value);
                        }
                        overallResult = overallResult && buildResultsLocal[i].EvaluationResult;
                    }
                }
                else
                {
                    // The calculation was terminated prior to receiving the result
                    overallResult = false;
                }
            }

            // We're now returning from an IBuildEngine callback;
            // set the current directory back to what the tasks expect
            if (Directory.GetCurrentDirectory() != currentDir)
            {
                Directory.SetCurrentDirectory(currentDir);
            }

            if (Engine.debugMode)
            {
                bool remoteNode = false;
                string targetName = targetNames == null ? "null" : targetNames[0];
                Console.WriteLine("RemoteNode: " + remoteNode + " T:" + targetName + " HandleId# " + handleId + " Result " + overallResult);
            }

            return overallResult;
        }
Example #42
0
        internal void PostBuildRequestToHost(BuildRequest currentRequest)
        {
            // Since this request is going back to the host the local node should not have a project object for it
            ErrorUtilities.VerifyThrow(currentRequest.ProjectToBuild == null, "Should not have a project object");
            // Add the request to the mapping hashtable so that we can recognize the outputs
            CacheScope cacheScope = localEngine.CacheManager.GetCacheScope(currentRequest.ProjectFileName, currentRequest.GlobalProperties, currentRequest.ToolsetVersion, CacheContentType.BuildResults);
            NodeRequestMapping nodeRequestMapping =
                new NodeRequestMapping(currentRequest.HandleId, currentRequest.RequestId, cacheScope );
            lock (requestToLocalIdMapping)
            {
                requestToLocalIdMapping.Add(lastRequestIdUsed, nodeRequestMapping);
                // Keep the request id local for this node
                currentRequest.RequestId = lastRequestIdUsed;
                lastRequestIdUsed++;
            }

            // Find the original external request that caused us to run this task
            TaskExecutionContext taskExecutionContext = localEngine.EngineCallback.GetTaskContextFromHandleId(currentRequest.HandleId);
            while (!taskExecutionContext.BuildContext.BuildRequest.IsExternalRequest)
            {
                ErrorUtilities.VerifyThrow(taskExecutionContext.BuildContext.BuildRequest.IsGeneratedRequest, 
                                           "Must be a generated request");

                taskExecutionContext =
                   localEngine.EngineCallback.GetTaskContextFromHandleId(taskExecutionContext.BuildContext.BuildRequest.HandleId);
            }

            //Modify the request with the data that is expected by the parent engine
            currentRequest.HandleId = taskExecutionContext.BuildContext.BuildRequest.HandleId;
            currentRequest.NodeIndex = taskExecutionContext.BuildContext.BuildRequest.NodeIndex;

            try
            {
                outProcLoggingService.ProcessPostedLoggingEvents();
                parentCallback.PostBuildRequestsToHost(new BuildRequest[] { currentRequest });
            }
            catch (Exception e)
            {
                ReportUnhandledError(e);
            }
        }
Example #43
0
       /// <summary>
       /// Once the buildRequests from the EngineCallback have been created they are sent to this method which will
       /// post the build requests to the parent engine and then wait on the results to come back.
       /// This method uses either a breadthFirst or depthFirst traversal strategy when sending buildRequests to the parent engine.
       /// This method will start in breadthFirst traversal. It will continue to use this strategy until one of two events occur:
       ///     1. The parent node sents a message indicating the TEM should switch to depthFirst traversal. 
       ///     2. The number of buildRequests is larger than the batchRequestSize.
       /// In both of these cases the system will go from a breadthFirstTraversal to a depthFirst Traversal. In the second case
       /// a message will be sent to the parent engine to switch the system to depthFirst traversal as the system is starting to 
       /// be overloaded with work.
       /// In a depth first strategy the buildRequests will be sent to the parent engine one at a time and waiting for results for
       /// each buildRequest sent. In a breadthFirst traversal strategy some number of the buildrequests will be sent to the parent engine
       /// in a batch of requests. The system will then wait on the results of ALL the build requests sent before continuing
       /// to send more build requests.
       /// </summary>
       private void WaitForBuildResults(int handleId, BuildResult[] buildResultsLocal, BuildRequest[] buildRequests)
        {
            // If the traversal strategy is breadth first and the number of requests is less than the batchRequestSize
            // or if there is only 1 build request then send ALL build requests to the parent engine and wait on the results.
            if ((breadthFirstTraversal == true && buildRequests.Length < batchRequestSize) || buildRequests.Length == 1)
            {
                engineCallback.PostBuildRequestsToHost(buildRequests);
                workerThread.WaitForResults(handleId, buildResultsLocal, buildRequests);
            }
            else
            {
                int currentRequestIndex = 0; // Which build request is being processed
                int numberOfRequestsToSend = 0; // How many buildRequests are going to be sent based on the number of buildRequests remaining and the build request batch size.
                
                // Arrays that will be used to partion the buildRequests array when sending batches of builds requests at a time.
                BuildRequest[] wrapperArrayBreadthFirst = new BuildRequest[batchRequestSize];
                BuildResult[] resultsArrayBreadthFirst = new BuildResult[batchRequestSize];

                // Pre allocate these arrays as they will always be only one element in size. They are assigned to and filled when doing a depth first traversal.
                BuildRequest[] wrapperArrayDepthFirst = new BuildRequest[1];
                BuildResult[] resultsArrayDepthFirst = new BuildResult[1];

                // While there are still requests to send
                while (currentRequestIndex < buildRequests.Length)
                {
                    // If there is a breadth first traversal and there are more than batchRequestSize build requests, send the first batchRequestSize, then do the rest depth first
                    if (breadthFirstTraversal == true)
                    {
                        // Figure out how many requests to send, either the full batch size or only part of a batch
                        numberOfRequestsToSend = (buildRequests.Length - currentRequestIndex) <batchRequestSize ? (buildRequests.Length - currentRequestIndex) : batchRequestSize;

                        // Initialize the wrapper array to how many requests are going to be sent
                        if (numberOfRequestsToSend != wrapperArrayBreadthFirst.Length)
                        {
                            wrapperArrayBreadthFirst = new BuildRequest[numberOfRequestsToSend];
                            resultsArrayBreadthFirst = new BuildResult[numberOfRequestsToSend];
                        }
                        
                        // Fill the wrapper array with one batch of build requests
                        for (int i = 0; i < numberOfRequestsToSend; i++)
                        {
                            wrapperArrayBreadthFirst[i] = buildRequests[currentRequestIndex + i];
                            wrapperArrayBreadthFirst[i].RequestId = i;
                            resultsArrayBreadthFirst[i] = null;
                        }

                        engineCallback.PostBuildRequestsToHost(wrapperArrayBreadthFirst);
                        
                        // Only switch from breadth to depth if there are more thanbatchRequestSize items
                        if ((buildRequests.Length - currentRequestIndex) > batchRequestSize)
                        {
                            engineCallback.PostStatus(nodeId, new NodeStatus(false /* use depth first traversal*/), false /* don't block waiting on the send */);
                            breadthFirstTraversal = false;
                        }
                        
                        workerThread.WaitForResults(handleId, resultsArrayBreadthFirst, wrapperArrayBreadthFirst);
                        Array.Copy(resultsArrayBreadthFirst, 0, buildResultsLocal, currentRequestIndex, numberOfRequestsToSend);
                        currentRequestIndex += numberOfRequestsToSend;
                    }

                    // Proceed with depth first traversal
                    while ((currentRequestIndex < buildRequests.Length) && !breadthFirstTraversal)
                    {
                        wrapperArrayDepthFirst[0] = buildRequests[currentRequestIndex];
                        buildRequests[currentRequestIndex].RequestId = 0;
                        resultsArrayDepthFirst[0] = null;

                        engineCallback.PostBuildRequestsToHost(wrapperArrayDepthFirst);
                        workerThread.WaitForResults(handleId, resultsArrayDepthFirst, wrapperArrayDepthFirst);
                        //Copy the result from an intermediate array to the full array
                        buildResultsLocal[currentRequestIndex] = resultsArrayDepthFirst[0];
                        //Check if the call failed (null result was returned)
                        if (buildResultsLocal[currentRequestIndex] == null)
                        {
                            return;
                        }

                        //Move to the next request
                        currentRequestIndex++;
                    }
                }
            }
        }
Example #44
0
 internal LocalCallDescriptorForPostBuildRequests(BuildRequest buildRequest)
     : base(LocalCallType.PostBuildRequests)
 {
     this.buildRequests    = new BuildRequest[1];
     this.buildRequests[0] = buildRequest;
 }
Example #45
0
        /// <summary>
        /// This function implements the callback via the IBuildEngine interface
        /// </summary>
        /// <returns>result of call to engine</returns>
        virtual internal bool BuildProjectFile
        (
            int handleId,
            string[] projectFileNames,
            string[] targetNames,
            IDictionary[] globalPropertiesPerProject,
            IDictionary[] targetOutputsPerProject,
            EngineLoggingServices loggingServices,
            string [] toolsVersions,
            bool useResultsCache,
            bool unloadProjectsOnCompletion,
            BuildEventContext taskContext
        )
        {
            if (projectFileNames.Length == 0)
            {
                // Nothing to do, just return success
                return(true);
            }

            string currentDir = FileUtilities.GetCurrentDirectoryStaticBuffer(currentDirectoryBuffer);

            if (Engine.debugMode)
            {
                string targetName = targetNames == null ? "null" : targetNames[0];

                bool remoteNode = false;
                for (int r = 0; r < projectFileNames.Length; r++)
                {
                    string fullProjectName = projectFileNames[r] ?? "null";
                    Console.WriteLine("RemoteNode: " + remoteNode + " Project " + fullProjectName + " T:" + targetName + " NodeProdyId# " + handleId + " Time " + DateTime.Now.ToLongTimeString());
                    if (globalPropertiesPerProject[r] != null)
                    {
                        foreach (DictionaryEntry entry in globalPropertiesPerProject[r])
                        {
                            Console.WriteLine(currentDir + " :GLOBAL " + entry.Key + "=" + entry.Value.ToString());
                        }
                    }
                }
            }

            BuildRequest[] buildRequests = new BuildRequest[projectFileNames.Length];
            for (int i = 0; i < buildRequests.Length; i++)
            {
                // We need to get the full path to the project before we call back
                // into the engine which has no control over current path
                string fullProjectName = projectFileNames[i] != null?
                                         Path.GetFullPath(projectFileNames[i]) : null;

                buildRequests[i] = new BuildRequest(handleId, fullProjectName, targetNames, globalPropertiesPerProject[i],
                                                    toolsVersions[i], i, useResultsCache, unloadProjectsOnCompletion);
                ErrorUtilities.VerifyThrow(buildRequests[i].IsGeneratedRequest, "Should not be sending non generated requests from TEM to engine");
                buildRequests[i].ParentBuildEventContext = taskContext;
            }

            BuildResult[] buildResultsLocal = new BuildResult[projectFileNames.Length];

            if (moduleMode == TaskExecutionModuleMode.SingleProcMode)
            {
                for (int i = 0; i < projectFileNames.Length; i++)
                {
                    // If we are running in a single threaded mode we need to
                    // re-enter the main build loop on the current thread in order
                    // to build the requested project, because the main build is below
                    // us on the stack
                    engineCallback.PostBuildRequestsToHost(new BuildRequest[] { buildRequests[i] });
                    buildResultsLocal[i] = engineCallback.GetParentEngine().EngineBuildLoop(buildRequests[i]);
                    buildResultsLocal[i].ConvertToTaskItems();
                }
            }
            else
            {
                WaitForBuildResults(handleId, buildResultsLocal, buildRequests);
            }

            // Store the outputs in the hashtables provided by the caller
            bool overallResult = true;

            for (int i = 0; i < buildResultsLocal.Length; i++)
            {
                // Users of the Object Model can pass in null targetOutputs for projects they do not want outputs for
                // therefore we need to make sure that there are targetoutputs and the users want the results
                if (buildResultsLocal[i] != null)
                {
                    if (buildResultsLocal[i].OutputsByTarget != null && targetOutputsPerProject[i] != null)
                    {
                        foreach (DictionaryEntry entry in buildResultsLocal[i].OutputsByTarget)
                        {
                            targetOutputsPerProject[i].Add(entry.Key, entry.Value);
                        }
                        overallResult = overallResult && buildResultsLocal[i].EvaluationResult;
                    }
                }
                else
                {
                    // The calculation was terminated prior to receiving the result
                    overallResult = false;
                }
            }

            // We're now returning from an IBuildEngine callback;
            // set the current directory back to what the tasks expect
            if (Directory.GetCurrentDirectory() != currentDir)
            {
                Directory.SetCurrentDirectory(currentDir);
            }

            if (Engine.debugMode)
            {
                bool   remoteNode = false;
                string targetName = targetNames == null ? "null" : targetNames[0];
                Console.WriteLine("RemoteNode: " + remoteNode + " T:" + targetName + " HandleId# " + handleId + " Result " + overallResult);
            }

            return(overallResult);
        }