コード例 #1
0
        /// <summary>
        /// Given a task name, this method retrieves the task class. If the task has been requested before, it will be found in
        /// the class cache; otherwise, &lt;UsingTask&gt; declarations will be used to search the appropriate assemblies.
        /// </summary>
        /// <param name="taskName"></param>
        /// <param name="taskProjectFile"></param>
        /// <param name="taskNode"></param>
        /// <param name="exactMatchRequired"></param>
        /// <param name="loggingServices"></param>
        /// <param name="buildEventContext"></param>
        /// <param name="taskClass"></param>
        /// <returns>true, if task is found</returns>
        public bool GetRegisteredTask
        (
            string taskName,
            string taskProjectFile,
            XmlNode taskNode,
            bool exactMatchRequired,
            EngineLoggingServices loggingServices,
            BuildEventContext buildEventContext,
            out LoadedType taskClass
        )
        {
            taskClass = null;

            // If there are no using tags in the project don't bother caching or looking for tasks
            if (registeredTasks == null)
            {
                return(false);
            }

            Hashtable cachedTaskClasses = exactMatchRequired ? this.cachedTaskClassesWithExactMatch : this.cachedTaskClassesWithFuzzyMatch;

            if (cachedTaskClasses.Contains(taskName))
            {
                // Caller has asked us before for this same task name, and for the same value of "bool exactMatchRequired".
                // Return whatever the previous result was, even if it was null.   Why would the result be different than
                // it was before?  NOTE:  Hash tables CAN have "null" as their value, and this still returns "true" for Contains(...).
                taskClass = (LoadedType)cachedTaskClasses[taskName];
            }
            else
            {
                Hashtable registeredTasksFound;

                // look for the given task name in the registry; if not found, gather all registered task names that partially
                // match the given name
                if (FindRegisteredTasks(taskName, exactMatchRequired, out registeredTasksFound))
                {
                    foreach (DictionaryEntry registeredTaskFound in registeredTasksFound)
                    {
                        string mostSpecificTaskName = (string)registeredTaskFound.Key;

                        // if the given task name is longer than the registered task name
                        if (taskName.Length > ((string)registeredTaskFound.Key).Length)
                        {
                            // we will use the longer name to help disambiguate between multiple matches
                            mostSpecificTaskName = taskName;
                        }

                        if (GetTaskFromAssembly(mostSpecificTaskName, (ArrayList)registeredTaskFound.Value, taskProjectFile, taskNode, loggingServices, buildEventContext, out taskClass))
                        {
                            // Whilst we are within the processing of the task, we haven't actually started executing it, so
                            // our using task message needs to be in the context of the target. However any errors should be reported
                            // at the point where the task appears in the project.
                            BuildEventContext usingTaskContext = new BuildEventContext(buildEventContext.NodeId, buildEventContext.TargetId, buildEventContext.ProjectContextId, BuildEventContext.InvalidTaskId);
                            loggingServices.LogComment(usingTaskContext, "TaskFound", taskName, taskClass.Assembly.ToString());
                            break;
                        }
                    }
                }

                // Cache the result, even if it is null.  We should never again do the work we just did, for this task name.
                cachedTaskClasses[taskName] = taskClass;
            }

            return(taskClass != null);
        }
コード例 #2
0
        /// <summary>
        /// Stub implementation -- forwards to engine being proxied.
        /// </summary>
        public void LogErrorEvent(BuildErrorEventArgs e)
        {
            ErrorUtilities.VerifyThrowArgumentNull(e, nameof(e));
            ErrorUtilities.VerifyThrowInvalidOperation(activeProxy, "AttemptingToLogFromInactiveTask");

            if (parentModule.IsRunningMultipleNodes && !e.GetType().IsSerializable)
            {
                loggingServices.LogWarning(buildEventContext, new BuildEventFileInfo(string.Empty), "ExpectedEventToBeSerializable", e.GetType().Name);
                return;
            }

            string message = GetUpdatedMessage(e.File, e.Message, parentProjectFullFileName);

            if (ContinueOnError)
            {
                // Convert the error into a warning.  We do this because the whole point of
                // ContinueOnError is that a project author expects that the task might fail,
                // but wants to ignore the failures.  This implies that we shouldn't be logging
                // errors either, because you should never have a successful build with errors.
                BuildWarningEventArgs warningEvent = new BuildWarningEventArgs
                                                         (e.Subcategory,
                                                         e.Code,
                                                         e.File,
                                                         e.LineNumber,
                                                         e.ColumnNumber,
                                                         e.EndLineNumber,
                                                         e.EndColumnNumber,
                                                         message, // this is the new message from above
                                                         e.HelpKeyword,
                                                         e.SenderName);

                warningEvent.BuildEventContext = buildEventContext;
                loggingServices.LogWarningEvent(warningEvent);

                // Log a message explaining why we converted the previous error into a warning.
                loggingServices.LogComment(buildEventContext, MessageImportance.Normal, "ErrorConvertedIntoWarning");
            }
            else
            {
                if (e.GetType().Equals(BuildErrorEventArgsType))
                {
                    // We'd like to add the project file to the subcategory, but since this property
                    // is read-only on the BuildErrorEventArgs type, this requires creating a new
                    // instance.  However, if some task logged a custom error type, we don't want to
                    // impolitely (as we already do above on ContinueOnError) throw the custom type
                    // data away.
                    e = new BuildErrorEventArgs
                        (
                        e.Subcategory,
                        e.Code,
                        e.File,
                        e.LineNumber,
                        e.ColumnNumber,
                        e.EndLineNumber,
                        e.EndColumnNumber,
                        message,      // this is the new message from above
                        e.HelpKeyword,
                        e.SenderName
                        );
                }

                e.BuildEventContext = buildEventContext;
                loggingServices.LogErrorEvent(e);
            }
        }
コード例 #3
0
        /// <summary>
        /// Validates a project against the given schema -- if no schema is provided, uses the default schema.
        /// </summary>
        /// <owner>JomoF</owner>
        /// <param name="contentReader"></param>
        /// <param name="schemaFile">Can be null.</param>
        /// <param name="projectFile"></param>
        private void VerifyProjectSchema
        (
            TextReader contentReader,
            string schemaFile,
            string projectFile
        )
        {
            // Options for XmlReader object can be set only in constructor. After the object is created, they
            // become read-only. Because of that we need to create
            // XmlSettings structure, fill it in with correct parameters and pass into XmlReader constructor.

            XmlReaderSettings validatorSettings = new XmlReaderSettings();

            validatorSettings.ValidationType          = ValidationType.Schema;
            validatorSettings.XmlResolver             = null;
            validatorSettings.ValidationEventHandler += this.OnSchemaValidationError;

            if (string.IsNullOrEmpty(schemaFile))
            {
                schemaFile = Path.Combine(binPath, "Microsoft.Build.xsd");
            }

            // Log the schema file we're using, particularly since it can vary
            // according to  the toolset being used
            engineLoggingServices.LogComment(buildEventContext, "SchemaFileLocation", schemaFile);

            XmlTextReader schemaReader = new XmlTextReader(schemaFile);

            schemaReader.DtdProcessing = DtdProcessing.Ignore;
            using (schemaReader)
            {
                try
                {
                    validatorSettings.Schemas.Add(XMakeAttributes.defaultXmlNamespace, schemaReader);

                    // We need full path to the project file to be able handle it as URI in ValidationEventHandler.
                    // Uri class cannot instantiate with relative paths.
                    if (projectFile.Length != 0)
                    {
                        projectFile = Path.GetFullPath(projectFile);
                    }

                    using (XmlReader validator = XmlReader.Create(contentReader, validatorSettings, projectFile)) // May also throw XmlSchemaException
                    {
                        this.syntaxError = false;
                        bool couldRead = true;

                        while (couldRead)
                        {
                            try
                            {
                                couldRead = validator.Read();
                            }
                            catch (XmlException)
                            {
                                // We swallow exception here because XmlValidator fires the validation event to report the error
                                // And we handle the event. Also XmlValidator can continue parsing Xml text after throwing an exception.
                                // Thus we don't need any special recover here.
                            }
                        }

                        ProjectFileErrorUtilities.VerifyThrowInvalidProjectFile(!this.syntaxError, "SubCategoryForSchemaValidationErrors",
                                                                                new BuildEventFileInfo(projectFile), "ProjectSchemaErrorHalt");
                    }
                }
                // handle errors in the schema itself
                catch (XmlException e)
                {
                    ProjectFileErrorUtilities.VerifyThrowInvalidProjectFile(false, "SubCategoryForSchemaValidationErrors", new BuildEventFileInfo(e),
                                                                            "InvalidSchemaFile", schemaFile, e.Message);
                }
                // handle errors in the schema itself
                catch (XmlSchemaException e)
                {
                    ProjectFileErrorUtilities.VerifyThrowInvalidProjectFile(false, "SubCategoryForSchemaValidationErrors", new BuildEventFileInfo(e),
                                                                            "InvalidSchemaFile", schemaFile, e.Message);
                }
            }
        }
コード例 #4
0
ファイル: TaskRegistry.cs プロジェクト: nikson/msbuild
        /// <summary>
        /// Given a task name, this method retrieves the task class. If the task has been requested before, it will be found in
        /// the class cache; otherwise, &lt;UsingTask&gt; declarations will be used to search the appropriate assemblies.
        /// </summary>
        /// <param name="taskName"></param>
        /// <param name="taskProjectFile"></param>
        /// <param name="taskNode"></param>
        /// <param name="exactMatchRequired"></param>
        /// <param name="loggingServices"></param>
        /// <param name="buildEventContext"></param>
        /// <param name="taskClass"></param>
        /// <returns>true, if task is found</returns>
        public bool GetRegisteredTask
        (
            string taskName,
            string taskProjectFile,
            XmlNode taskNode,
            bool exactMatchRequired,
            EngineLoggingServices loggingServices,
            BuildEventContext buildEventContext,
            out LoadedType taskClass
        )
        {
            taskClass = null;

            // If there are no using tags in the project don't bother caching or looking for tasks
            if (registeredTasks == null)
            {
                return false;
            }

            Hashtable cachedTaskClasses = exactMatchRequired ? this.cachedTaskClassesWithExactMatch : this.cachedTaskClassesWithFuzzyMatch;
            
            if (cachedTaskClasses.Contains(taskName))
            {
                // Caller has asked us before for this same task name, and for the same value of "bool exactMatchRequired".
                // Return whatever the previous result was, even if it was null.   Why would the result be different than
                // it was before?  NOTE:  Hash tables CAN have "null" as their value, and this still returns "true" for Contains(...).
                taskClass = (LoadedType) cachedTaskClasses[taskName];
            }
            else
            {
                Hashtable registeredTasksFound;

                // look for the given task name in the registry; if not found, gather all registered task names that partially
                // match the given name
                if (FindRegisteredTasks(taskName, exactMatchRequired, out registeredTasksFound))
                {
                    foreach (DictionaryEntry registeredTaskFound in registeredTasksFound)
                    {
                        string mostSpecificTaskName = (string)registeredTaskFound.Key;

                        // if the given task name is longer than the registered task name
                        if (taskName.Length > ((string)registeredTaskFound.Key).Length)
                        {
                            // we will use the longer name to help disambiguate between multiple matches
                            mostSpecificTaskName = taskName;
                        }

                        if (GetTaskFromAssembly(mostSpecificTaskName, (ArrayList)registeredTaskFound.Value, taskProjectFile, taskNode, loggingServices, buildEventContext, out taskClass))
                        {
                            // Whilst we are within the processing of the task, we haven't actually started executing it, so
                            // our using task message needs to be in the context of the target. However any errors should be reported
                            // at the point where the task appears in the project.
                            BuildEventContext usingTaskContext = new BuildEventContext(buildEventContext.NodeId, buildEventContext.TargetId, buildEventContext.ProjectContextId, BuildEventContext.InvalidTaskId);
                            loggingServices.LogComment(usingTaskContext, "TaskFound", taskName, taskClass.Assembly.ToString());
                            break;
                        }
                    }
                }

                // Cache the result, even if it is null.  We should never again do the work we just did, for this task name.
                cachedTaskClasses[taskName] = taskClass;
            }

            return (taskClass != null);
        }