/// <summary>
        /// This method is used to flag errors in the project file being processed. Do NOT use this method in place of
        /// ErrorUtilities.VerifyThrow(), because ErrorUtilities.VerifyThrow() is used to flag internal/programming errors.
        /// 
        /// PERF WARNING: calling a method that takes a variable number of arguments is expensive, because memory is allocated for
        /// the array of arguments -- do not call this method repeatedly in performance-critical scenarios
        /// </summary>
        /// <owner>SumedhK</owner>
        /// <param name="condition">The condition to check.</param>
        /// <param name="errorSubCategoryResourceName">The resource string for the error sub-category (can be null).</param>
        /// <param name="projectFile">The invalid project file.</param>
        /// <param name="resourceName">The resource string for the error message.</param>
        /// <param name="args">Extra arguments for formatting the error message.</param>
        internal static void VerifyThrowInvalidProjectFile
        (
            bool condition,
            string errorSubCategoryResourceName,
            BuildEventFileInfo projectFile,
            string resourceName,
            params object[] args
        )
        {
            ErrorUtilities.VerifyThrow(projectFile != null, "Must specify the invalid project file. If project file is not available, use VerifyThrowInvalidProject() and pass in the XML node instead.");

#if DEBUG
            if (errorSubCategoryResourceName != null)
            {
                ResourceUtilities.VerifyResourceStringExists(errorSubCategoryResourceName);
            }

            ResourceUtilities.VerifyResourceStringExists(resourceName);
#endif
            if (!condition)
            {
                string errorSubCategory = null;

                if (errorSubCategoryResourceName != null)
                {
                    errorSubCategory = AssemblyResources.GetString(errorSubCategoryResourceName);
                }

                string errorCode;
                string helpKeyword;
                string message = ResourceUtilities.FormatResourceString(out errorCode, out helpKeyword, resourceName, args);

                throw new InvalidProjectFileException(projectFile.File, projectFile.Line, projectFile.Column, projectFile.EndLine, projectFile.EndColumn, message, errorSubCategory, errorCode, helpKeyword);
            }
        }
 /// <summary>
 /// This method is used to flag errors in the project file being processed. Do NOT use this method in place of
 /// ErrorUtilities.VerifyThrow(), because ErrorUtilities.VerifyThrow() is used to flag internal/programming errors.
 /// 
 /// PERF WARNING: calling a method that takes a variable number of arguments is expensive, because memory is allocated for
 /// the array of arguments -- do not call this method repeatedly in performance-critical scenarios
 /// </summary>
 /// <owner>SumedhK</owner>
 /// <param name="condition">The condition to check.</param>
 /// <param name="projectFile">The invalid project file.</param>
 /// <param name="resourceName">The resource string for the error message.</param>
 /// <param name="args">Extra arguments for formatting the error message.</param>
 internal static void VerifyThrowInvalidProjectFile
 (
     bool condition,
     BuildEventFileInfo projectFile,
     string resourceName,
     params object[] args
 )
 {
     VerifyThrowInvalidProjectFile(condition, null, projectFile, resourceName, args);
 }
Beispiel #3
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);
 }
        /// <summary>
        /// Logs a warning with all registered loggers using the given text.
        /// </summary>
        /// <owner>SumedhK</owner>
        /// <param name="subcategoryResourceName">Can be null.</param>
        /// <param name="warningCode">Can be null.</param>
        /// <param name="helpKeyword">Can be null.</param>
        /// <param name="file"></param>
        /// <param name="message"></param>
        virtual internal void LogWarningFromText(BuildEventContext buildEventContext, string subcategoryResourceName, string warningCode, string helpKeyword, BuildEventFileInfo file, string message)
        {
            ErrorUtilities.VerifyThrow(file != null, "Must specify the associated file.");
            ErrorUtilities.VerifyThrow(message != null, "Need warning message.");

            string subcategory = null;

            if (subcategoryResourceName != null)
            {
                subcategory = AssemblyResources.GetString(subcategoryResourceName);
            }


            BuildWarningEventArgs e = new BuildWarningEventArgs
                (
                    subcategory,
                    warningCode,
                    file.File,
                    file.Line,
                    file.Column,
                    file.EndLine,
                    file.EndColumn,
                    message,
                    helpKeyword,
                    "MSBuild"
                );
            e.BuildEventContext = buildEventContext;
            PostLoggingEvent(e);
        }
        /// <summary>
        /// Logs a warning with all registered loggers using the specified resource string.
        /// </summary>
        /// <owner>SumedhK</owner>
        /// <param name="subcategoryResourceName">Can be null.</param>
        /// <param name="file"></param>
        /// <param name="messageResourceName"></param>
        /// <param name="messageArgs"></param>
        virtual internal void LogWarning(BuildEventContext buildEventContext, string subcategoryResourceName, BuildEventFileInfo file, string messageResourceName, params object[] messageArgs)
        {
            ErrorUtilities.VerifyThrow(messageResourceName != null, "Need resource string for warning message.");

            string warningCode;
            string helpKeyword;
            string message = ResourceUtilities.FormatResourceString(out warningCode, out helpKeyword, messageResourceName, messageArgs);

            LogWarningFromText(buildEventContext, subcategoryResourceName, warningCode, helpKeyword, file, message);
        }
 /// <summary>
 /// Logs a warning with all registered loggers using the specified resource string.
 /// </summary>
 /// <owner>SumedhK</owner>
 /// <param name="file"></param>
 /// <param name="messageResourceName"></param>
 /// <param name="messageArgs"></param>
  virtual internal void LogWarning(BuildEventContext buildEventContext, BuildEventFileInfo file, string messageResourceName, params object[] messageArgs)
 {
     LogWarning(buildEventContext,null, file, messageResourceName, messageArgs);
 }
        /**************************************************************************************************************************
         * WARNING: Do not add overloads that allow raising events without specifying a file. In general ALL events should have a
         * file associated with them. We've received a LOT of feedback from dogfooders about the lack of information in our
         * events. If an event TRULY does not have an associated file, then String.Empty can be passed in for the file. However,
         * that burden should lie on the caller -- these wrapper methods should NOT make it easy to skip the filename.
         *************************************************************************************************************************/

        /// <summary>
        /// Logs an warning regarding an unexpected task failure with all registered loggers.
        /// This will include a stack dump.
        /// </summary>
        /// <owner>RGoel</owner>
        /// <param name="exception"></param>
        /// <param name="file"></param>
        /// <param name="taskName"></param>
        virtual internal void LogTaskWarningFromException(BuildEventContext buildEventContext, Exception exception, BuildEventFileInfo file, string taskName)
        {
            ErrorUtilities.VerifyThrow(taskName != null, "Must specify the name of the task that failed.");
            ErrorUtilities.VerifyThrow(file != null, "Must specify the associated file.");

            string warningCode;
            string helpKeyword;
            string message = ResourceUtilities.FormatResourceString(out warningCode, out helpKeyword, "FatalTaskError", taskName);
            #if DEBUG
            message += Environment.NewLine + "This is an unhandled exception -- PLEASE OPEN A BUG.";
            #endif

            if (exception != null)
            {
                message += Environment.NewLine + exception.ToString();
            }

            LogWarningFromText(buildEventContext, null, warningCode, helpKeyword, file, message);
        }
        /// <summary>
        /// Logs an error regarding an unexpected failure with all registered loggers using the specified resource string.
        /// This will include a stack dump.
        /// </summary>
        /// <owner>SumedhK</owner>
        /// <param name="exception"></param>
        /// <param name="file"></param>
        /// <param name="messageResourceName"></param>
        /// <param name="messageArgs"></param>
        virtual internal void LogFatalError(BuildEventContext buildEventContext, Exception exception, BuildEventFileInfo file, string messageResourceName, params object[] messageArgs)
        {
            ErrorUtilities.VerifyThrow(messageResourceName != null, "Need resource string for error message.");

            string errorCode;
            string helpKeyword;
            string message = ResourceUtilities.FormatResourceString(out errorCode, out helpKeyword, messageResourceName, messageArgs);
            #if DEBUG
            message += Environment.NewLine + "This is an unhandled exception -- PLEASE OPEN A BUG.";
            #endif
            if (exception != null)
            {
                message += Environment.NewLine + exception.ToString();
            }

            LogErrorFromText(buildEventContext, null, errorCode, helpKeyword, file, message);
        }
 /// <summary>
 /// Logs an error regarding an unexpected build failure with all registered loggers.
 /// This will include a stack dump.
 /// </summary>
 /// <owner>SumedhK</owner>
 /// <param name="exception"></param>
 /// <param name="file"></param>
 virtual internal void LogFatalBuildError(BuildEventContext buildEventContext, Exception exception, BuildEventFileInfo file)
 {
     LogFatalError(buildEventContext, exception, file, "FatalBuildError");
 }
Beispiel #10
0
        /**************************************************************************************************************************
         * WARNING: Do not add overloads that allow raising events without specifying a file. In general ALL events should have a
         * file associated with them. We've received a LOT of feedback from dogfooders about the lack of information in our
         * events. If an event TRULY does not have an associated file, then String.Empty can be passed in for the file. However,
         * that burden should lie on the caller -- these wrapper methods should NOT make it easy to skip the filename.
         *************************************************************************************************************************/

        /// <summary>
        /// Logs an error with all registered loggers using the specified resource string.
        /// </summary>
        /// <owner>SumedhK</owner>
        /// <param name="file"></param>
        /// <param name="messageResourceName"></param>
        /// <param name="messageArgs"></param>
        virtual internal void LogError(BuildEventContext location, BuildEventFileInfo file, string messageResourceName, params object[] messageArgs)
        {
            LogError(location, null, file, messageResourceName, messageArgs);
        }
Beispiel #11
0
        /// <summary>
        /// Loads the XML for the specified project that is being imported into the main project.
        /// </summary>
        /// <owner>RGoel, SumedhK</owner>
        /// <param name="import">The project being imported</param>
        /// <returns>XML for imported project; null, if duplicate import.</returns>
        private XmlDocument LoadImportedProject(Import import)
        {
            XmlDocument importedDocument = null;
            bool importedFileExists = File.Exists(import.EvaluatedProjectPath);

            // NOTE: don't use ErrorUtilities.VerifyThrowFileExists() here because that exception doesn't carry XML node
            // information, and we need that data to show a better error message

            if (!importedFileExists)
            {
                ProjectErrorUtilities.VerifyThrowInvalidProject((this.loadSettings & ProjectLoadSettings.IgnoreMissingImports) != 0,
                    import.ProjectPathAttribute, "ImportedProjectNotFound", import.EvaluatedProjectPath);
            }

            // Make sure that the file we're about to import hasn't been imported previously.
            // This is how we prevent circular dependencies.  It so happens that this mechanism
            // also prevents the same file from being imported twice, even it it's not a
            // circular dependency, but that's fine -- no good reason to do that anyway.
            if ((this.imports[import.EvaluatedProjectPath] != null) ||
                (string.Compare(this.FullFileName, import.EvaluatedProjectPath, StringComparison.OrdinalIgnoreCase) == 0))
            {
                ParentEngine.LoggingServices.LogWarning(projectBuildEventContext, Utilities.CreateBuildEventFileInfo(import.ProjectPathAttribute, FullFileName),
                    "DuplicateImport", import.EvaluatedProjectPath);
            }
            else
            {
                // See if the imported project is also a top-level project that has been loaded
                // by the engine.  If so, use the in-memory copy of the imported project instead
                // of reading the copy off of the disk.  This way, we can reflect any changes
                // that have been made to the in-memory copy.
                Project importedProject = this.ParentEngine.GetLoadedProject(import.EvaluatedProjectPath);
                if (importedProject != null)
                {
                    importedDocument = importedProject.XmlDocument;
                }
                // The imported project is not part of the engine, so read it off of disk.
                else
                {
                    // If the file doesn't exist on disk but we're told to ignore missing imports, simply skip it
                    if (importedFileExists)
                    {
                        // look up the engine's cache to see if we've already loaded this imported project on behalf of another
                        // top-level project
                        ImportedProject previouslyImportedProject = (ImportedProject)ParentEngine.ImportedProjectsCache[import.EvaluatedProjectPath];
                        
                        // if this project hasn't been imported before, or if it has changed on disk, we need to load it
                        if ((previouslyImportedProject == null) || previouslyImportedProject.HasChangedOnDisk(import.EvaluatedProjectPath))
                        {
                            try
                            {
                                // Do not validate the imported file against a schema.
                                // We only validate the parent project against a schema in V1, because without custom
                                // namespace support, we would have to pollute the msbuild namespace with everything that
                                // appears anywhere in our targets file.

                                // cache this imported project, so that if another top-level project also imports this project, we
                                // will not re-parse the XML (unless it changes)
                                previouslyImportedProject = new ImportedProject(import.EvaluatedProjectPath);
                                ParentEngine.ImportedProjectsCache[import.EvaluatedProjectPath] = previouslyImportedProject;
                            }
                            // catch XML exceptions early so that we still have the imported project file name
                            catch (XmlException e)
                            {
                                BuildEventFileInfo fileInfo = new BuildEventFileInfo(e);
                                ProjectFileErrorUtilities.VerifyThrowInvalidProjectFile(false,
                                    fileInfo,
                                    "InvalidImportedProjectFile", e.Message);
                            }
                            // catch IO exceptions, for example for when the file is in use. DDB #36839
                            catch (Exception e)
                            {
                                if (ExceptionHandling.NotExpectedException(e))
                                    throw;

                                BuildEventFileInfo fileInfo = new BuildEventFileInfo(import.EvaluatedProjectPath);
                                ProjectFileErrorUtilities.VerifyThrowInvalidProjectFile(false,
                                    fileInfo,
                                    "InvalidImportedProjectFile", e.Message);
                            }
                        }

                        importedDocument = previouslyImportedProject.Xml;
                    }
                }

                // Add the imported filename to our list, so we can be sure not to import
                // it again.  This helps prevent infinite recursion.
                this.imports[import.EvaluatedProjectPath] = import;
            }

            return importedDocument;
        }
Beispiel #12
0
        /// <summary>
        /// Reads in the contents of this project from a string containing the Xml contents.
        /// </summary>
        /// <exception cref="InvalidProjectFileException"></exception>
        public void LoadXml
        (
            string projectXml,
            ProjectLoadSettings projectLoadSettings
        )
        {
            ErrorUtilities.VerifyThrowArgumentNull(projectXml, "projectXml");

            try
            {
                XmlDocument projectDocument = new XmlDocument();
                // XmlDocument.Load() may throw an XmlException
                projectDocument.LoadXml(projectXml);

                InternalLoadFromXmlDocument(projectDocument, projectLoadSettings);

                // This means that as far as we know, this project hasn't been saved to disk yet.
                this.dirtyNeedToSaveProjectFile = true;
            }
            // handle errors in project syntax
            catch (InvalidProjectFileException e)
            {
                ParentEngine.LoggingServices.LogInvalidProjectFileError(projectBuildEventContext, e);
                throw;
            }
            // handle XML parsing errors (when reading XML contents)
            catch (XmlException e)
            {
                BuildEventFileInfo fileInfo = new BuildEventFileInfo(e);

                ParentEngine.LoggingServices.LogError(projectBuildEventContext, null,fileInfo, "InvalidProjectFile", e.Message);

                ProjectFileErrorUtilities.VerifyThrowInvalidProjectFile(false, fileInfo,
                    "InvalidProjectFile", e.Message);
            }
        }
Beispiel #13
0
        /// <summary>
        /// Reads in the contents of this project from a project XML file on disk.
        /// </summary>
        /// <exception cref="InvalidProjectFileException"></exception>
        internal void Load
        (
            string projectFileName,
            BuildEventContext buildEventContext,
            ProjectLoadSettings projectLoadSettings
        )
        {
            ErrorUtilities.VerifyThrowArgumentNull(projectFileName, "projectFileName");
            ErrorUtilities.VerifyThrowArgument(projectFileName.Length > 0, "EmptyProjectFileName");
            ErrorUtilities.VerifyThrowArgument(File.Exists(projectFileName), "ProjectFileNotFound", projectFileName);

#if (!STANDALONEBUILD)
            using (new CodeMarkerStartEnd(CodeMarkerEvent.perfMSBuildProjectLoadFromFileBegin, CodeMarkerEvent.perfMSBuildProjectLoadFromFileEnd))
#endif
            {
                string projectFullFileName = Path.GetFullPath(projectFileName);

                try
                {
#if MSBUILDENABLEVSPROFILING 
                string beginProjectLoad = String.Format(CultureInfo.CurrentCulture, "Load Project {0} Using Old OM - Start", projectFullFileName);
                DataCollection.CommentMarkProfile(8806, beginProjectLoad);
#endif
                    XmlDocument projectDocument = null;
                    if (IsSolutionFilename(projectFileName))
                    {
                        SolutionParser sp = new SolutionParser();

                        sp.SolutionFile = projectFileName;
                        sp.ParseSolutionFile();

                        // Log any comments from the solution parser
                        if (sp.SolutionParserComments.Count > 0)
                        {
                            foreach (string comment in sp.SolutionParserComments)
                            {
                                ParentEngine.LoggingServices.LogCommentFromText(buildEventContext, MessageImportance.Low, comment);
                            }
                        }

                        // Pass the toolsVersion of this project through, which will be not null if there was a /tv:nn switch
                        // Although we only get an XmlDocument, not a Project object back, it's still needed
                        // to determine which <UsingTask> tags to put in, whether to put a ToolsVersion parameter
                        // on <MSBuild> task tags, and what MSBuildToolsPath to use when scanning child projects
                        // for dependency information.
                        SolutionWrapperProject.Generate(sp, this, toolsVersion, buildEventContext);

                    }
                    else if (IsVCProjFilename(projectFileName))
                    {
                        ProjectFileErrorUtilities.VerifyThrowInvalidProjectFile(false, new BuildEventFileInfo(projectFileName), "ProjectUpgradeNeededToVcxProj", projectFileName);
                    }
                    else
                    {
                        projectDocument = new XmlDocument();
                        // XmlDocument.Load() may throw an XmlException
                        projectDocument.Load(projectFileName);
                    }

                    // Setting the FullFileName causes this project to be "registered" with
                    // the engine.  (Well, okay, "registered" is the wrong word ... but the
                    // engine starts keeping close track of this project in its tables.)
                    // We want to avoid this until we're sure that the XML is valid and
                    // the document can be read in.  Bug VSWhidbey 415236.
                    this.FullFileName = projectFullFileName;

                    if (!IsSolutionFilename(projectFileName))
                    {
                        InternalLoadFromXmlDocument(projectDocument, projectLoadSettings);
                    }


                    // This project just came off the disk, so it is certainly not dirty yet.
                    this.dirtyNeedToSaveProjectFile = false;
                }
                // handle errors in project syntax
                catch (InvalidProjectFileException e)
                {
                    ParentEngine.LoggingServices.LogInvalidProjectFileError(buildEventContext, e);
                    throw;
                }
                // handle errors in path resolution
                catch (SecurityException e)
                {
                    ParentEngine.LoggingServices.LogError(buildEventContext, new BuildEventFileInfo(FullFileName), "InvalidProjectFile", e.Message);

                    ProjectFileErrorUtilities.VerifyThrowInvalidProjectFile(false, new BuildEventFileInfo(FullFileName),
                        "InvalidProjectFile", e.Message);
                }
                // handle errors in path resolution
                catch (NotSupportedException e)
                {
                    ParentEngine.LoggingServices.LogError(buildEventContext, new BuildEventFileInfo(FullFileName), "InvalidProjectFile", e.Message);

                    ProjectFileErrorUtilities.VerifyThrowInvalidProjectFile(false, new BuildEventFileInfo(FullFileName),
                        "InvalidProjectFile", e.Message);
                }
                // handle errors in loading project file
                catch (IOException e)
                {
                    ParentEngine.LoggingServices.LogError(buildEventContext, new BuildEventFileInfo(FullFileName), "InvalidProjectFile", e.Message);

                    ProjectFileErrorUtilities.VerifyThrowInvalidProjectFile(false, new BuildEventFileInfo(FullFileName),
                        "InvalidProjectFile", e.Message);
                }
                // handle errors in loading project file
                catch (UnauthorizedAccessException e)
                {
                    ParentEngine.LoggingServices.LogError(buildEventContext, new BuildEventFileInfo(FullFileName), "InvalidProjectFile", e.Message);
                    ProjectFileErrorUtilities.VerifyThrowInvalidProjectFile(false, new BuildEventFileInfo(FullFileName),
                        "InvalidProjectFile", e.Message);
                }
                // handle XML parsing errors (when reading project file)
                catch (XmlException e)
                {
                    BuildEventFileInfo fileInfo = new BuildEventFileInfo(e);

                    ParentEngine.LoggingServices.LogError(buildEventContext, fileInfo, "InvalidProjectFile", e.Message);

                    ProjectFileErrorUtilities.VerifyThrowInvalidProjectFile(false, fileInfo,
                        "InvalidProjectFile", e.Message);
                }
                finally
                {
                    // Flush the logging queue
                    ParentEngine.LoggingServices.ProcessPostedLoggingEvents();
#if MSBUILDENABLEVSPROFILING 
                DataCollection.CommentMarkProfile(8807, "Load Project Using Old OM - End");
#endif
                }
            }
        }
Beispiel #14
0
        /// <summary>
        /// This method generates an XmlDocument representing an MSBuild project wrapper for a VC project
        /// </summary>
        /// <owner>LukaszG</owner>
        static internal XmlDocument GenerateVCWrapperProject(Engine parentEngine, string vcProjectFilename, string toolsVersion)
        {
            string projectPath = Path.GetFullPath(vcProjectFilename);
            Project msbuildProject = null;

            try
            {
                msbuildProject = new Project(parentEngine, toolsVersion);
            }
            catch (InvalidOperationException)
            {
                BuildEventFileInfo fileInfo = new BuildEventFileInfo(projectPath);
                string errorCode;
                string helpKeyword;
                string message = ResourceUtilities.FormatResourceString(out errorCode, out helpKeyword, "UnrecognizedToolsVersion", toolsVersion);
                throw new InvalidProjectFileException(projectPath, fileInfo.Line, fileInfo.Column, fileInfo.EndLine, fileInfo.EndColumn, message, null, errorCode, helpKeyword);
            }

            msbuildProject.IsLoadedByHost = false;
            msbuildProject.DefaultTargets = "Build";

            string wrapperProjectToolsVersion = SolutionWrapperProject.DetermineWrapperProjectToolsVersion(toolsVersion);
            msbuildProject.DefaultToolsVersion = wrapperProjectToolsVersion;

            BuildPropertyGroup propertyGroup = msbuildProject.AddNewPropertyGroup(true /* insertAtEndOfProject = true */);
            propertyGroup.Condition = " ('$(Configuration)' != '') and ('$(Platform)' == '') ";
            propertyGroup.AddNewProperty("ConfigurationName", "$(Configuration)");

            propertyGroup = msbuildProject.AddNewPropertyGroup(true /* insertAtEndOfProject = true */);
            propertyGroup.Condition = " ('$(Configuration)' != '') and ('$(Platform)' != '') ";
            propertyGroup.AddNewProperty("ConfigurationName", "$(Configuration)|$(Platform)");

            // only use PlatformName if we only have the platform part
            propertyGroup = msbuildProject.AddNewPropertyGroup(true /* insertAtEndOfProject = true */);
            propertyGroup.Condition = " ('$(Configuration)' == '') and ('$(Platform)' != '') ";
            propertyGroup.AddNewProperty("PlatformName", "$(Platform)");

            AddVCBuildTarget(msbuildProject, projectPath, "Build", null);
            AddVCBuildTarget(msbuildProject, projectPath, "Clean", "Clean");
            AddVCBuildTarget(msbuildProject, projectPath, "Rebuild", "Rebuild");
            AddVCBuildTarget(msbuildProject, projectPath, "Publish", "Publish");

            // Special environment variable to allow people to see the in-memory MSBuild project generated
            // to represent the VC project.
            if (Environment.GetEnvironmentVariable("MSBuildEmitSolution") != null)
            {
                msbuildProject.Save(vcProjectFilename + ".proj");
            }

            return msbuildProject.XmlDocument;
        }
Beispiel #15
0
        /// <summary>
        /// Logs an error regarding an unexpected task failure with all registered loggers.
        /// This will include a stack dump.
        /// </summary>
        /// <owner>SumedhK</owner>
        /// <param name="exception"></param>
        /// <param name="file"></param>
        /// <param name="taskName"></param>
        virtual internal void LogFatalTaskError(BuildEventContext buildEventContext, Exception exception, BuildEventFileInfo file, string taskName)
        {
            ErrorUtilities.VerifyThrow(taskName != null, "Must specify the name of the task that failed.");

            LogFatalError(buildEventContext, exception, file, "FatalTaskError", taskName);
        }
 /// <summary>
 /// Create a new project to construct a solution wrapper cache inside
 /// </summary>
 private static Project CreateNewProject(SolutionParser solution, string wrapperProjectToolsVersion, Engine parentEngine, Project solutionProject)
 {
     try
     {
         solutionProject = new Project(parentEngine, wrapperProjectToolsVersion);
         solutionProject.DefaultTargets = "Build";
         solutionProject.DefaultToolsVersion = wrapperProjectToolsVersion;
         solutionProject.IsLoadedByHost = false;
     }
     catch (InvalidOperationException)
     {
         BuildEventFileInfo fileInfo = new BuildEventFileInfo(solution.SolutionFile);
         string errorCode;
         string helpKeyword;
         string message = ResourceUtilities.FormatResourceString(out errorCode, out helpKeyword, "UnrecognizedToolsVersion", wrapperProjectToolsVersion);
         throw new InvalidProjectFileException(solution.SolutionFile, fileInfo.Line, fileInfo.Column, fileInfo.EndLine, fileInfo.EndColumn, message, null, errorCode, helpKeyword);
     }
     return solutionProject;
 }
Beispiel #17
0
        /// <summary>
        /// Returns a project object that matches the full path and global properties passed in.
        /// First, it checks our cache of building projects to see if such a project already exists.
        /// If so, we reuse that.  Otherwise, we create a new Project object with the specified
        /// full path and global properties.  The "existingProject" parameter passed in is just
        /// so we can reuse the Xml if there's already a project available with the same full path.
        /// </summary>
        /// <param name="existingProject"></param>
        /// <param name="projectFullPath"></param>
        /// <param name="globalPropertiesToUse"></param>
        /// <param name="buildEventContext"></param>
        internal Project GetMatchingProject
            (
            Project existingProject,
            string projectFullPath,
            BuildPropertyGroup globalPropertiesToUse,
            string toolsVersion,
            string [] targetNames,
            BuildEventContext buildEventContext,
            bool toolsVersionPeekedFromProjectFile
            )
        {
            // See if we already have a project with the exact same full path and global properties
            // that the caller is requesting us to build.  If so, use that.
            Project returnProject = this.cacheOfBuildingProjects.GetProject(projectFullPath, globalPropertiesToUse, toolsVersion);

            // If this project was not found in our list, create a new project,
            // and load the contents from the project file.
            if (returnProject == null)
            {
                #if DEBUG
                if (!String.IsNullOrEmpty(Environment.GetEnvironmentVariable("MSBUILDASSERTONLOADMULTIPLECOPIESOFPROJECT")))
                {
                    if (this.projectsLoadedByHost.Contains(projectFullPath))
                    {
                        // We're about to load a second copy of a project that is already loaded in the IDE.
                        // This assert can fire when different projects in the IDE have different sets of
                        // global properties.  For example, suppose there are two projects loaded in the IDE,
                        // ProjectA and ProjectB.  Suppose the project system has given ProjectA two global
                        // properties (e.g., Configuration=Debug and Platform=AnyCPU), and has given ProjectB
                        // three global properties (e.g., Configuration=Foobar, Platform=x86, and DevEnvDir=c:\vs).
                        // Now, if ProjectB has a P2P reference to ProjectA, we've got a problem because when
                        // ProjectB calls the <MSBuild> task to grab the output of ProjectA, the engine is going
                        // to try and merge together the global properties, and the merged set will consist
                        // of all three properties.  Since we won't have a copy of ProjectA in our projectsLoadedByHost
                        // list that has all three of the same global properties, we'll decide we have to create
                        // a new Project object, and this is a big unnecessary perf hit (as well as being incorrect).
                        // If a user customized his build process and is explicitly passing in Properties to the
                        // <MSBuild> task, then we would be entering this codepath for a totally legitimate
                        // scenario, so we don't want to disallow it.  We just want to know about it if it happens
                        // to anyone before we ship, just so we can investigate to see if there may be a bug 
                        // somewhere.
                        if (this.projectsLoadedByHost.Count > 1)
                        {
                            // The assert condition (projectsLoadedByHost.Count == 1) is there because
                            // for command-line builds using msbuild.exe, the # of projects loaded by the host will
                            // always be exactly 1.  We don't want to assert for command-line builds, because then
                            // we'd be firing this all the time for perfectly legitimate scenarios.
                            // We also don't want to assert in razzle, because the razzle build is expected to do this
                            // to accomplish traversal.
                            Debug.Assert(!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("_NTROOT")),
                                "This assertion is here to catch potential bugs wrt MSBuild and VS integration.  " +
                                "It is okay to ignore this assert only if you are in the IDE and have customized " +
                                "your build process such that you are passing the Properties parameter into the " +
                                "<MSBuild> task in way that causes the same project to be built with different " +
                                "sets of global properties.  However, if you are just using a standard VS-generated project, " +
                                "this assert should not fire, so please open a bug under the \\VSCORE\\MSBuild\\VSIntegration " +
                                "path.");
                        }
                    }
                }
                #endif

                // Check if the project has been previously unloaded due to a user request during the current build
                // In this case reloaded a project is an error because we can't ensure a consistent state of the reloaded project
                // and the cached resulted of the original
                string toolsVersionToUse = toolsVersion == null ? DefaultToolsVersion : toolsVersion;
                if (this.cacheOfBuildingProjects.HasProjectBeenLoaded(projectFullPath, globalPropertiesToUse, toolsVersionToUse))
                {
                    string joinedNames = ResourceUtilities.FormatResourceString("DefaultTargets");
                    if (targetNames != null && targetNames.Length > 0)
                    {
                        joinedNames = EscapingUtilities.UnescapeAll(String.Join(";", targetNames));
                    }
                    BuildEventFileInfo fileInfo = new BuildEventFileInfo(projectFullPath);
                    string errorCode;
                    string helpKeyword;
                    string message = ResourceUtilities.FormatResourceString(out errorCode, out helpKeyword, "ReloadingPreviouslyUnloadedProject", projectFullPath, joinedNames);
                    throw new InvalidProjectFileException(projectFullPath, fileInfo.Line, fileInfo.Column, fileInfo.EndLine, fileInfo.EndColumn, message, null, errorCode, helpKeyword);
                }
                // This creates a new project.
                try
                {
                    // If the tools version was peeked from the project file then we reset the tools version to null as the tools version is read by the project object again
                    // when setting or getting the ToolsVersion property. If the tools version was not peeked from the project file than it is an override.
                    if (toolsVersionPeekedFromProjectFile)
                    {
                        toolsVersion = null;
                    }
                    returnProject = new Project(this, toolsVersion);
                }
                catch (InvalidOperationException)
                {
                    BuildEventFileInfo fileInfo = new BuildEventFileInfo(projectFullPath);
                    string errorCode;
                    string helpKeyword;
                    string message = ResourceUtilities.FormatResourceString(out errorCode, out helpKeyword, "UnrecognizedToolsVersion", toolsVersion);
                    throw new InvalidProjectFileException(projectFullPath,fileInfo.Line,fileInfo.Column,fileInfo.EndLine, fileInfo.EndColumn,message, null, errorCode,helpKeyword);
                }

                // We're only building this project ... it is not loaded by a host, and we
                // should feel free to discard this whenever we like.
                returnProject.IsLoadedByHost = false;

                // Give it the global properties that were requested.
                returnProject.GlobalProperties = globalPropertiesToUse;

                // Load the project file.  If we don't already have an XmlDocument for this
                // project file, load it off disk.  Otherwise, use one of the XmlDocuments
                // that we already have.  Two advantages:  1.) perf  2.) using the in-memory
                // contents that the host may have altered.
                if (existingProject != null)
                {
                    //Console.WriteLine("Reusing an existing project: " + projectFullPath);
                    returnProject.FullFileName = projectFullPath;
                    returnProject.LoadFromXmlDocument(existingProject.XmlDocument, buildEventContext, existingProject.LoadSettings);
                }
                else
                {
                    //Console.WriteLine("Found new project: " + projectFullPath);
                    returnProject.Load(projectFullPath, buildEventContext, ProjectLoadSettings.None);
                }

                // Add the newly created Project object to the ProjectManager.
                this.cacheOfBuildingProjects.AddProject(returnProject);
            }

            return returnProject;
        }