Exemplo n.º 1
0
        /// <summary>
        /// Loads a project file from disk, and builds the specified list of targets.  This overload
        /// takes a set of global properties to use for the build, returns the target outputs, and also
        /// allows the caller to specify additional build flags.
        /// </summary>
        /// <remarks>
        /// If this project file is already in our list of in-progress projects, we use the
        /// existing Project object instead of instantiating a new one. Always use this method to 
        /// build projects within projects, otherwise the build won't be optimized.
        /// </remarks>
        internal void BuildProjectFileInternal
            (
                BuildRequest buildRequest
            )
        {
            string projectFile = buildRequest.ProjectFileName;

            error.VerifyThrowArgumentNull(projectFile, "projectFileName");
            error.VerifyThrowArgument(projectFile.Length > 0, "EmptyProjectFileName");
            // When we get to this point the global properties should not be null, as they are used to determine if a project has already been loaded / built before.
            error.VerifyThrow(buildRequest.GlobalProperties != null, "Global Properties should not be null");

            // Convert the project filename to a fully qualified path.
            FileInfo projectFileInfo = new FileInfo(projectFile);

            // If the project file doesn't actually exist on disk, it's a failure.
            ErrorUtilities.VerifyThrowArgument(projectFileInfo.Exists, "ProjectFileNotFound", projectFile);

            try
            {
                ArrayList actuallyBuiltTargets;

                // If the tools version is empty take a quick peek at the project file to determine if it has a tools version defined
                if(String.IsNullOrEmpty(buildRequest.ToolsetVersion))
                {
                    buildRequest.ToolsetVersion = XmlUtilities.GetAttributeValueForElementFromFile(buildRequest.ProjectFileName, XMakeAttributes.project, XMakeAttributes.toolsVersion);
                    buildRequest.ToolsVersionPeekedFromProjectFile = true;
                }

                // Check if there is a cached result available for this build
                BuildResult cachedResult = cacheManager.GetCachedBuildResult(buildRequest, out actuallyBuiltTargets);
                if (cachedResult != null)
                {
                    // Notify the scheduler of the dependecy and indicate that it will be evaluated (aka retrieved from the cache locally)
                    Scheduler.NotifyOfSchedulingDecision(buildRequest, this.nodeId);
                    ProcessCachedResult(buildRequest, projectFileInfo, actuallyBuiltTargets, cachedResult);
                }
                else
                {
                    // There's no cached result: we have to build it. Figure out which node to build it on.
                    Project matchingProjectCurrentlyLoaded = null;
                    Project projectCurrentlyLoaded = null;

                    // See if we have a project loaded by the host already that matches the full path, in the
                    // list of projects which were loaded at the beginning of the build.
                    projectCurrentlyLoaded = (Project)this.projectsLoadedByHost[projectFileInfo.FullName];

                    if (projectCurrentlyLoaded != null)
                    {
                        // See if the global properties and tools version match.
                        if (projectCurrentlyLoaded.IsEquivalentToProject
                                    (
                                    projectCurrentlyLoaded.FullFileName,
                                    buildRequest.GlobalProperties,
                                    buildRequest.ToolsetVersion
                                    )
                            )
                        {
                            // If so, use it.
                            matchingProjectCurrentlyLoaded = projectCurrentlyLoaded;
                        }
                    }

                    // Decide to build the project on either the current node or remote node
                    string toolsVersionToUse = buildRequest.ToolsetVersion == null ? DefaultToolsVersion : buildRequest.ToolsetVersion;

                    // If a matching project is currently loaded, we will build locally.
                    bool isLocal = (matchingProjectCurrentlyLoaded != null);

                    // If not, we need to search our cache of building projects to see if we have built this project
                    // locally already.
                    if (!isLocal)
                    {
                        // Determine if the project was previously loaded, but is now unloaded.
                        bool projectWasPreviouslyLoaded = this.cacheOfBuildingProjects.HasProjectBeenLoaded(projectFileInfo.FullName, buildRequest.GlobalProperties, toolsVersionToUse);

                        // We do this check because we need to know if the project is already building on this node.
                        // Unlike the check of projectsLoadedByHost, this will also find projects which were added
                        // after the start of the build, such as MSBuild task-generated build requests.
                        bool projectIsLoaded = this.cacheOfBuildingProjects.GetProject(projectFileInfo.FullName, buildRequest.GlobalProperties, toolsVersionToUse) != null;

                        isLocal = projectWasPreviouslyLoaded || projectIsLoaded;
                    }

                    int nodeIndex = EngineCallback.inProcNode;

                    // If the project, properties and tools version is not known locally, it is either being services by a remote node
                    // or we need to let the scheduler pick a node for it to be serviced by using its algorithm.
                    if (!isLocal)
                    {
                        nodeIndex = cacheOfBuildingProjects.GetRemoteProject(projectFileInfo.FullName, buildRequest.GlobalProperties, toolsVersionToUse);
                    }

                    int evaluationNode = Scheduler.CalculateNodeForBuildRequest(buildRequest, nodeIndex);
                    if (matchingProjectCurrentlyLoaded == null && evaluationNode == EngineCallback.inProcNode)
                    {
                        // We haven't already got this project loaded in this Engine, or it was previously unloaded from this Engine,
                        // and we've been scheduled to build it on this node. So create a new project if necessary.
                        // If we peeked at the project file then we need to make sure that if the tools version in the project is not marked as an override then
                        // the project's tools version is the same. If they are the same then override should be false.
                        try
                        {
                            matchingProjectCurrentlyLoaded = GetMatchingProject(projectCurrentlyLoaded,
                                projectFileInfo.FullName, buildRequest.GlobalProperties,
                                buildRequest.ToolsetVersion, buildRequest.TargetNames, buildRequest.ParentBuildEventContext, buildRequest.ToolsVersionPeekedFromProjectFile);
                        }
                        catch (InvalidProjectFileException e)
                        {
                            primaryLoggingServices.LogInvalidProjectFileError(buildRequest.ParentBuildEventContext, e);
                            throw;
                        }
                    }

                    if (evaluationNode != EngineCallback.inProcNode)
                    {
                        // The project will be evaluated remotely so add a record 
                        // indicating where this project is being evaluated
                        if (evaluationNode != EngineCallback.parentNode)
                        {
                            cacheOfBuildingProjects.AddRemoteProject(projectFileInfo.FullName, buildRequest.GlobalProperties, toolsVersionToUse, evaluationNode);
                        }
                    }

                    if (Engine.debugMode)
                    {
                        Console.WriteLine("###Missing cached result for " + buildRequest.GetTargetNamesList() + " in " +
                                           buildRequest.ProjectFileName + " - building");
                    }

                    if (evaluationNode == EngineCallback.inProcNode)
                    {
                        ErrorUtilities.VerifyThrow(cacheOfBuildingProjects.GetRemoteProject(projectFileInfo.FullName, buildRequest.GlobalProperties, toolsVersionToUse) == EngineCallback.invalidNode,
                                                   "Should not build remote projects");
                        buildRequest.ProjectToBuild = matchingProjectCurrentlyLoaded;
                        this.BuildProjectInternal(buildRequest, null, null, true);
                    }
                    else
                    {
                        // Increment number of projects in progress 
                        if (!buildRequest.IsGeneratedRequest)
                        {
                            IncrementProjectsInProgress();
                        }
                       Router.PostBuildRequest(buildRequest, evaluationNode);
                    }
                }
            }
            catch (InvalidProjectFileException)
            {
                // eat the exception because it has already been logged
                HandleProjectFileInternalException(buildRequest);
            }
        }
Exemplo n.º 2
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);
            }
        }
Exemplo n.º 3
0
        public void GetTargetNamesList()
        {
            int nodeProxyId = 1;
            string projectFileName = "ProjectFileName";
            string[] targetNames = null; 
            
            Dictionary<string, string> dictionary = null;
            int requestId = 1;

            // Test the case where we pass in null targets
            BuildRequest buildRequest = new BuildRequest(nodeProxyId, projectFileName, targetNames, (IDictionary)dictionary, null, requestId, false, false);
            Assert.IsNull(buildRequest.GetTargetNamesList(), "Expected GetTargetNamesList to be null");

            // Test the case where we pass in one target
            targetNames = new string[] { "Build" };
            buildRequest = new BuildRequest(nodeProxyId, projectFileName, targetNames, (IDictionary)dictionary, null, requestId, false, false);
            Assert.IsTrue(string.Compare("Build", buildRequest.GetTargetNamesList(),StringComparison.OrdinalIgnoreCase)==0, "Expected to see Build as the targetNamesList");
           
            //Test the case where we pass in multiple targets
            targetNames = new string[] {"Build","Build2"};
            buildRequest = new BuildRequest(nodeProxyId, projectFileName, targetNames, (IDictionary)dictionary, null, requestId, false, false);
            Assert.IsTrue(string.Compare("Build;Build2;", buildRequest.GetTargetNamesList(),StringComparison.OrdinalIgnoreCase)==0, "Expected to see Build;Build2; as the targetNamesList");
         }