Esempio n. 1
0
        /// <summary>
        /// Given a string of semi-colon delimited name=value pairs, this method parses it and creates 
        /// a hash table containing the property names as keys and the property values as values.  
        /// </summary>
        /// <param name="log"></param>
        /// <param name="propertyList"></param>
        /// <param name="propertiesTable"></param>
        /// <returns>true on success, false on failure.</returns>
        static internal bool GetTable(TaskLoggingHelper log, string parameterName, string[] propertyList, out Hashtable propertiesTable)
        {
            propertiesTable = null;

            if (propertyList != null)
            {
                propertiesTable = new Hashtable(StringComparer.OrdinalIgnoreCase);

                // Loop through the array.  Each string in the array should be of the form:
                //          MyPropName=MyPropValue
                foreach (string propertyNameValuePair in propertyList)
                {
                    string propertyName = String.Empty;
                    string propertyValue = String.Empty;

                    // Find the first '=' sign in the string.
                    int indexOfEqualsSign = propertyNameValuePair.IndexOf('=');

                    // If we found one, then grab the stuff before it and put it into "propertyName",
                    // and grab the stuff after it and put it into "propertyValue".  But trim the 
                    // whitespace from beginning and end of both name and value.  (When authoring a 
                    // project/targets file, people like to use whitespace and newlines to pretty up 
                    // the file format.)
                    if (indexOfEqualsSign != -1)
                    {
                        propertyName = propertyNameValuePair.Substring(0, indexOfEqualsSign).Trim();
                        propertyValue = propertyNameValuePair.Substring(indexOfEqualsSign + 1).Trim();
                    }

                    // Make sure we have a property name and property value (though the value is allowed to be blank).
                    if (propertyName.Length == 0)
                    {
                        // No equals sign?  No property name?  That's no good to us.
                        if (log != null)
                        {
                            log.LogErrorWithCodeFromResources("General.InvalidPropertyError", parameterName, propertyNameValuePair);
                        }

                        return false;
                    }

                    // Bag the property and its value.  Trim whitespace from beginning and end of
                    // both name and value.  (When authoring a project/targets file, people like to 
                    // use whitespace and newlines to pretty up the file format.)
                    propertiesTable[propertyName] = propertyValue;
                }
            }

            return true;
        }
Esempio n. 2
0
        internal static bool GetTable(TaskLoggingHelper log, string parameterName, string[] propertyList, out Dictionary <string, string> propertiesTable)
        {
            propertiesTable = null;

            if (propertyList != null)
            {
                propertiesTable = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase);

                // Loop through the array.  Each string in the array should be of the form:
                //          MyPropName=MyPropValue
                foreach (string propertyNameValuePair in propertyList)
                {
                    string propertyName  = String.Empty;
                    string propertyValue = String.Empty;

                    // Find the first '=' sign in the string.
                    int indexOfEqualsSign = propertyNameValuePair.IndexOf('=');

                    // If we found one, then grab the stuff before it and put it into "propertyName",
                    // and grab the stuff after it and put it into "propertyValue".  But trim the
                    // whitespace from beginning and end of both name and value.  (When authoring a
                    // project/targets file, people like to use whitespace and newlines to pretty up
                    // the file format.)
                    if (indexOfEqualsSign != -1)
                    {
                        propertyName  = propertyNameValuePair.Substring(0, indexOfEqualsSign).Trim();
                        propertyValue = propertyNameValuePair.Substring(indexOfEqualsSign + 1).Trim();
                    }

                    // Make sure we have a property name and property value (though the value is allowed to be blank).
                    if (propertyName.Length == 0)
                    {
                        // No equals sign?  No property name?  That's no good to us.
                        log?.LogErrorWithCodeFromResources("General.InvalidPropertyError", parameterName, propertyNameValuePair);

                        return(false);
                    }

                    // Bag the property and its value.  Trim whitespace from beginning and end of
                    // both name and value.  (When authoring a project/targets file, people like to
                    // use whitespace and newlines to pretty up the file format.)
                    propertiesTable[propertyName] = propertyValue;
                }
            }

            return(true);
        }
Esempio n. 3
0
        /// <summary>
        /// Create a taskfactory instance which contains the data that needs to be refreshed between task invocations
        /// </summary>
        public ITask CreateTask(IBuildEngine loggingHost)
        {
            // The assembly will have been compiled during class factory initialization, create an instance of it
            if (_compiledAssembly != null)
            {
                // In order to use the resource strings from the tasks assembly we need to register the resources with the task logging helper.
                var log = new TaskLoggingHelper(loggingHost, _nameOfTask)
                {
                    TaskResources     = AssemblyResources.PrimaryResources,
                    HelpKeywordPrefix = "MSBuild."
                };

                ITask taskInstance = Activator.CreateInstance(TaskType) as ITask;
                if (taskInstance == null)
                {
                    log.LogErrorWithCodeFromResources("CodeTaskFactory.NeedsITaskInterface", _nameOfTask);
                }

                return(taskInstance);
            }
            return(null);
        }
Esempio n. 4
0
        /// <summary>
        /// Allows tool to handle the return code.
        /// This method will only be called with non-zero exitCode. If the non zero code is an acceptable one then we return true
        /// </summary>
        /// <returns>The return value of this method will be used as the task return value</returns>
        protected override bool HandleTaskExecutionErrors()
        {
            if (IsAcceptableReturnValue())
            {
                return(true);
            }

            // We don't want to use ToolTask's implementation because it doesn't report the command line that failed.
            if (ExitCode == NativeMethods.SE_ERR_ACCESSDENIED)
            {
                _logPrivate.LogErrorWithCodeFromResources("Xaml.CommandFailedAccessDenied", this.CommandLine, ExitCode);
            }
            else
            {
                _logPrivate.LogErrorWithCodeFromResources("Xaml.CommandFailed", this.CommandLine, ExitCode);
            }
            return(false);
        }
Esempio n. 5
0
        protected override int ExecuteTool(string pathToTool, string responseFileCommands, string commandLineCommands)
        {
            if (ProvideCommandLineArgs)
            {
                CommandLineArgs = GetArguments(commandLineCommands, responseFileCommands)
                                  .Select(arg => new TaskItem(arg)).ToArray();
            }

            if (SkipCompilerExecution)
            {
                return(0);
            }

            try
            {
                using var logger = new CompilerServerLogger();
                string workingDir = CurrentDirectoryToUse();
                string?tempDir    = BuildServerConnection.GetTempPath(workingDir);

                if (!UseSharedCompilation ||
                    HasToolBeenOverridden ||
                    !BuildServerConnection.IsCompilerServerSupported)
                {
                    LogCompilationMessage(logger, CompilationKind.Tool, $"using command line tool by design '{pathToTool}'");
                    return(base.ExecuteTool(pathToTool, responseFileCommands, commandLineCommands));
                }

                _sharedCompileCts = new CancellationTokenSource();
                logger.Log($"CommandLine = '{commandLineCommands}'");
                logger.Log($"BuildResponseFile = '{responseFileCommands}'");

                var clientDir = Path.GetDirectoryName(PathToManagedTool);
                if (clientDir is null || tempDir is null)
                {
                    LogCompilationMessage(logger, CompilationKind.Tool, $"using command line tool because we could not find client directory '{PathToManagedTool}'");
                    return(base.ExecuteTool(pathToTool, responseFileCommands, commandLineCommands));
                }

                var buildPaths = new BuildPathsAlt(
                    clientDir: clientDir,
                    workingDir: workingDir,
                    // MSBuild doesn't need the .NET SDK directory
                    sdkDir: null,
                    tempDir: tempDir);

                // Note: using ToolArguments here (the property) since
                // commandLineCommands (the parameter) may have been mucked with
                // (to support using the dotnet cli)
                var responseTask = BuildServerConnection.RunServerCompilationAsync(
                    Language,
                    RoslynString.IsNullOrEmpty(SharedCompilationId) ? null : SharedCompilationId,
                    GetArguments(ToolArguments, responseFileCommands).ToList(),
                    buildPaths,
                    keepAlive: null,
                    libEnvVariable: LibDirectoryToUse(),
                    logger: logger,
                    cancellationToken: _sharedCompileCts.Token);

                responseTask.Wait(_sharedCompileCts.Token);

                ExitCode = HandleResponse(responseTask.Result, pathToTool, responseFileCommands, commandLineCommands, logger);
            }
            catch (OperationCanceledException)
            {
                ExitCode = 0;
            }
            catch (Exception e)
            {
                var util = new TaskLoggingHelper(this);
                util.LogErrorWithCodeFromResources("Compiler_UnexpectedException");
                util.LogErrorFromException(e, showStackTrace: true, showDetail: true, file: null);
                ExitCode = -1;
            }
            finally
            {
                _sharedCompileCts?.Dispose();
                _sharedCompileCts = null;
            }

            return(ExitCode);
        }
Esempio n. 6
0
        /// <summary>
        /// MSBuild engine will call this to initialize the factory. This should initialize the factory enough so that the factory can be asked
        ///  whether or not task names can be created by the factory.
        /// </summary>
        public bool Initialize(string taskName, IDictionary <string, TaskPropertyInfo> taskParameters, string taskElementContents, IBuildEngine taskFactoryLoggingHost)
        {
            ErrorUtilities.VerifyThrowArgumentNull(taskName, nameof(taskName));
            ErrorUtilities.VerifyThrowArgumentNull(taskParameters, nameof(taskParameters));

            var log = new TaskLoggingHelper(taskFactoryLoggingHost, taskName)
            {
                TaskResources     = AssemblyResources.PrimaryResources,
                HelpKeywordPrefix = "MSBuild."
            };

            if (taskElementContents == null)
            {
                log.LogErrorWithCodeFromResources("Xaml.MissingTaskBody");
                return(false);
            }

            TaskElementContents = taskElementContents.Trim();

            // Attempt to load the task
            TaskParser parser = new TaskParser();

            bool parseSuccessful = parser.Parse(TaskElementContents, taskName);

            TaskName      = parser.GeneratedTaskName;
            TaskNamespace = parser.Namespace;
            var generator = new TaskGenerator(parser);

            CodeCompileUnit dom = generator.GenerateCode();

            string pathToMSBuildBinaries = ToolLocationHelper.GetPathToBuildTools(ToolLocationHelper.CurrentToolsVersion);

            // create the code generator options
            // Since we are running msbuild 12.0 these had better load.
            var compilerParameters = new CompilerParameters
                                     (
                new[]
            {
                "System.dll",
                Path.Combine(pathToMSBuildBinaries, "Microsoft.Build.Framework.dll"),
                Path.Combine(pathToMSBuildBinaries, "Microsoft.Build.Utilities.Core.dll"),
                Path.Combine(pathToMSBuildBinaries, "Microsoft.Build.Tasks.Core.dll")
            }
                                     )
            {
                GenerateInMemory      = true,
                TreatWarningsAsErrors = false
            };

            // create the code provider
            var             codegenerator = CodeDomProvider.CreateProvider("cs");
            CompilerResults results;
            bool            debugXamlTask = Environment.GetEnvironmentVariable("MSBUILDWRITEXAMLTASK") == "1";

            if (debugXamlTask)
            {
                using (var outputWriter = new StreamWriter(taskName + "_XamlTask.cs"))
                {
                    var options = new CodeGeneratorOptions
                    {
                        BlankLinesBetweenMembers = true,
                        BracingStyle             = "C"
                    };

                    codegenerator.GenerateCodeFromCompileUnit(dom, outputWriter, options);
                }

                results = codegenerator.CompileAssemblyFromFile(compilerParameters, taskName + "_XamlTask.cs");
            }
            else
            {
                results = codegenerator.CompileAssemblyFromDom(compilerParameters, dom);
            }

            try
            {
                _taskAssembly = results.CompiledAssembly;
            }
            catch (FileNotFoundException)
            {
                // This occurs if there is a failure to compile the assembly.  We just pass through because we will take care of the failure below.
            }

            if (_taskAssembly == null)
            {
                var errorList = new StringBuilder();
                errorList.AppendLine();
                foreach (CompilerError error in results.Errors)
                {
                    if (error.IsWarning)
                    {
                        continue;
                    }

                    if (debugXamlTask)
                    {
                        errorList.AppendFormat(Thread.CurrentThread.CurrentUICulture, "({0},{1}) {2}", error.Line, error.Column, error.ErrorText).AppendLine();
                    }
                    else
                    {
                        errorList.AppendLine(error.ErrorText);
                    }
                }

                log.LogErrorWithCodeFromResources("Xaml.TaskCreationFailed", errorList.ToString());
            }

            return(!log.HasLoggedErrors);
        }
Esempio n. 7
0
        public bool Initialize(string taskName, IDictionary <string, TaskPropertyInfo> taskParameters, string taskElementContents, IBuildEngine taskFactoryLoggingHost)
        {
            CompilerResults results;

            Microsoft.Build.Shared.ErrorUtilities.VerifyThrowArgumentNull(taskName, "taskName");
            Microsoft.Build.Shared.ErrorUtilities.VerifyThrowArgumentNull(taskParameters, "taskParameters");
            TaskLoggingHelper helper = new TaskLoggingHelper(taskFactoryLoggingHost, taskName)
            {
                TaskResources     = Microsoft.Build.Shared.AssemblyResources.PrimaryResources,
                HelpKeywordPrefix = "MSBuild."
            };

            if (taskElementContents == null)
            {
                helper.LogErrorWithCodeFromResources("Xaml.MissingTaskBody", new object[0]);
                return(false);
            }
            this.TaskElementContents = taskElementContents.Trim();
            TaskParser parser = new TaskParser();

            parser.Parse(this.TaskElementContents, taskName);
            this.TaskName      = parser.GeneratedTaskName;
            this.TaskNamespace = parser.Namespace;
            CodeCompileUnit    compileUnit = new TaskGenerator(parser).GenerateCode();
            Assembly           assembly    = Assembly.LoadWithPartialName("System");
            Assembly           assembly2   = Assembly.LoadWithPartialName("Microsoft.Build.Framework");
            Assembly           assembly3   = Assembly.LoadWithPartialName("Microsoft.Build.Utilities.V4.0");
            Assembly           assembly4   = Assembly.LoadWithPartialName("Microsoft.Build.Tasks.V4.0");
            CompilerParameters parameters  = new CompilerParameters(new string[] { assembly.Location, assembly2.Location, assembly3.Location, assembly4.Location })
            {
                GenerateInMemory      = true,
                TreatWarningsAsErrors = false
            };
            CodeDomProvider provider = CodeDomProvider.CreateProvider("cs");
            bool            flag     = Environment.GetEnvironmentVariable("MSBUILDWRITEXAMLTASK") == "1";

            if (flag)
            {
                using (StreamWriter writer = new StreamWriter(taskName + "_XamlTask.cs"))
                {
                    CodeGeneratorOptions options = new CodeGeneratorOptions {
                        BlankLinesBetweenMembers = true,
                        BracingStyle             = "C"
                    };
                    provider.GenerateCodeFromCompileUnit(compileUnit, writer, options);
                }
                results = provider.CompileAssemblyFromFile(parameters, new string[] { taskName + "_XamlTask.cs" });
            }
            else
            {
                results = provider.CompileAssemblyFromDom(parameters, new CodeCompileUnit[] { compileUnit });
            }
            try
            {
                this.taskAssembly = results.CompiledAssembly;
            }
            catch (FileNotFoundException)
            {
            }
            if (this.taskAssembly == null)
            {
                StringBuilder builder = new StringBuilder();
                builder.AppendLine();
                foreach (CompilerError error in results.Errors)
                {
                    if (!error.IsWarning)
                    {
                        if (flag)
                        {
                            builder.AppendLine(string.Format(Thread.CurrentThread.CurrentUICulture, "({0},{1}) {2}", new object[] { error.Line, error.Column, error.ErrorText }));
                        }
                        else
                        {
                            builder.AppendLine(error.ErrorText);
                        }
                    }
                }
                helper.LogErrorWithCodeFromResources("Xaml.TaskCreationFailed", new object[] { builder.ToString() });
            }
            return(!helper.HasLoggedErrors);
        }
Esempio n. 8
0
        /// <summary>
        /// This method will take a sdkToolsPath and a toolName and return the path to the tool if it is found and exists.
        ///
        /// First the method will try and find the tool under the sdkToolsPath taking into account the current processor architecture
        /// If the tool could not be found the method will try and find the tool under the sdkToolsPath (which should point to the x86 sdk directory).
        ///
        /// Finally if the method has not found the tool yet it will fallback and use the toolslocation helper method to try and find the tool.
        /// </summary>
        /// <returns>Path including the toolName of the tool if found, null if it is not found</returns>
        internal static string GeneratePathToTool(FileExists fileExists, string currentArchitecture, string sdkToolsPath, string toolName, TaskLoggingHelper log, bool logErrorsAndWarnings)
        {
            // Null until we combine the toolname with the path.
            string pathToTool = null;

            if (!String.IsNullOrEmpty(sdkToolsPath))
            {
                string processorSpecificToolDirectory = String.Empty;
                try
                {
                    switch (currentArchitecture)
                    {
                    // There may not be an arm directory so we will fall back to the x86 tool location
                    // but if there is then we should try and use it.
                    case ProcessorArchitecture.ARM:
                        processorSpecificToolDirectory = Path.Combine(sdkToolsPath, "arm");
                        break;

                    case ProcessorArchitecture.AMD64:
                        processorSpecificToolDirectory = Path.Combine(sdkToolsPath, "x64");
                        break;

                    case ProcessorArchitecture.IA64:
                        processorSpecificToolDirectory = Path.Combine(sdkToolsPath, "ia64");
                        break;

                    case ProcessorArchitecture.X86:
                    default:
                        processorSpecificToolDirectory = sdkToolsPath;
                        break;
                    }

                    pathToTool = Path.Combine(processorSpecificToolDirectory, toolName);

                    if (!fileExists(pathToTool))
                    {
                        // Try falling back to the x86 location
                        if (currentArchitecture != ProcessorArchitecture.X86)
                        {
                            pathToTool = Path.Combine(sdkToolsPath, toolName);
                        }
                    }
                    else
                    {
                        return(pathToTool);
                    }
                }
                catch (ArgumentException e)
                {
                    // Catch exceptions from path.combine
                    log.LogErrorWithCodeFromResources("General.SdkToolsPathError", toolName, e.Message);
                    return(null);
                }

                if (fileExists(pathToTool))
                {
                    return(pathToTool);
                }
                else
                {
                    if (logErrorsAndWarnings)
                    {
                        // Log an error indicating we could not find it in the processor specific architecture or x86 locations.
                        // We could not find the tool at all, lot a error.
                        log.LogWarningWithCodeFromResources("General.PlatformSDKFileNotFoundSdkToolsPath", toolName, processorSpecificToolDirectory, sdkToolsPath);
                    }
                }
            }
            else
            {
                if (logErrorsAndWarnings)
                {
                    log.LogMessageFromResources(MessageImportance.Low, "General.SdkToolsPathNotSpecifiedOrToolDoesNotExist", toolName, sdkToolsPath);
                }
            }

            // Fall back and see if we can find it with the toolsLocation helper methods. This is not optimal because
            // the location they are looking at is based on when the Microsoft.Build.Utilities.dll was compiled
            // but it is better than nothing.
            if (null == pathToTool || !fileExists(pathToTool))
            {
                pathToTool = FindSDKToolUsingToolsLocationHelper(toolName);

                if (pathToTool == null && logErrorsAndWarnings)
                {
                    log.LogErrorWithCodeFromResources("General.SdkToolsPathToolDoesNotExist", toolName, sdkToolsPath, ToolLocationHelper.GetDotNetFrameworkSdkRootRegistryKey(TargetDotNetFrameworkVersion.VersionLatest, VisualStudioVersion.VersionLatest));
                }
            }

            return(pathToTool);
        }
        internal static string GeneratePathToTool(Microsoft.Build.Shared.FileExists fileExists, string currentArchitecture, string sdkToolsPath, string toolName, TaskLoggingHelper log, bool logErrorsAndWarnings)
        {
            string path = null;

            if (!string.IsNullOrEmpty(sdkToolsPath))
            {
                string str2 = string.Empty;
                try
                {
                    string str4 = currentArchitecture;
                    if (str4 == null)
                    {
                        goto Label_0061;
                    }
                    if (!(str4 == "AMD64"))
                    {
                        if (str4 == "IA64")
                        {
                            goto Label_0053;
                        }
                        if (str4 == "x86")
                        {
                        }
                        goto Label_0061;
                    }
                    str2 = Path.Combine(sdkToolsPath, "x64");
                    goto Label_0063;
Label_0053:
                    str2 = Path.Combine(sdkToolsPath, "ia64");
                    goto Label_0063;
Label_0061:
                    str2 = sdkToolsPath;
Label_0063:
                    path = Path.Combine(str2, toolName);
                    if (!fileExists(path))
                    {
                        if (currentArchitecture != "x86")
                        {
                            path = Path.Combine(sdkToolsPath, toolName);
                        }
                    }
                    else
                    {
                        return(path);
                    }
                }
                catch (ArgumentException exception)
                {
                    log.LogErrorWithCodeFromResources("General.SdkToolsPathError", new object[] { toolName, exception.Message });
                    return(null);
                }
                if (fileExists(path))
                {
                    return(path);
                }
                if (logErrorsAndWarnings)
                {
                    log.LogWarningWithCodeFromResources("General.PlatformSDKFileNotFoundSdkToolsPath", new object[] { toolName, str2, sdkToolsPath });
                }
            }
            else if (logErrorsAndWarnings)
            {
                log.LogMessageFromResources(MessageImportance.Low, "General.SdkToolsPathNotSpecifiedOrToolDoesNotExist", new object[] { toolName, sdkToolsPath });
            }
            if ((path == null) || !fileExists(path))
            {
                path = FindSDKToolUsingToolsLocationHelper(toolName);
                if ((path == null) && logErrorsAndWarnings)
                {
                    log.LogErrorWithCodeFromResources("General.SdkToolsPathToolDoesNotExist", new object[] { toolName, sdkToolsPath, ToolLocationHelper.GetDotNetFrameworkSdkRootRegistryKey(TargetDotNetFrameworkVersion.Version40) });
                }
            }
            return(path);
        }
Esempio n. 10
0
        /// <summary>
        /// Given a string of semi-colon delimited name=value pairs, this method parses it and creates 
        /// a hash table containing the property names as keys and the property values as values.  
        /// This method escapes any special characters found in the property values, in case they 
        /// are going to be passed to a method (such as that expects the appropriate escaping to have happened
        /// already.
        /// </summary>
        /// <param name="log"></param>
        /// <param name="propertyList"></param>
        /// <param name="propertiesTable"></param>
        /// <returns>true on success, false on failure.</returns>
        static internal bool GetTableWithEscaping(TaskLoggingHelper log, string parameterName, string syntaxName, string[] propertyNameValueStrings, out Hashtable finalPropertiesTable)
        {
            finalPropertiesTable = null;

            if (propertyNameValueStrings != null)
            {
                finalPropertiesTable = new Hashtable(StringComparer.OrdinalIgnoreCase);
                List<PropertyNameValuePair> finalPropertiesList = new List<PropertyNameValuePair>();

                // Loop through the array.  Each string in the array should be of the form:
                //          MyPropName=MyPropValue
                foreach (string propertyNameValueString in propertyNameValueStrings)
                {
                    // Find the first '=' sign in the string.
                    int indexOfEqualsSign = propertyNameValueString.IndexOf('=');

                    if (indexOfEqualsSign != -1)
                    {
                        // If we found one, then grab the stuff before it and put it into "propertyName",
                        // and grab the stuff after it and put it into "propertyValue".  But trim the 
                        // whitespace from beginning and end of both name and value.  (When authoring a 
                        // project/targets file, people like to use whitespace and newlines to pretty up 
                        // the file format.)
                        string propertyName = propertyNameValueString.Substring(0, indexOfEqualsSign).Trim();
                        string propertyValue = EscapingUtilities.Escape(propertyNameValueString.Substring(indexOfEqualsSign + 1).Trim());

                        // Make sure we have a property name and property value (though the value is allowed to be blank).
                        if (propertyName.Length == 0)
                        {
                            // No property name?  That's no good to us.
                            if (log != null)
                            {
                                log.LogErrorWithCodeFromResources("General.InvalidPropertyError", syntaxName, propertyNameValueString);
                            }

                            return false;
                        }

                        // Store the property in our list.
                        finalPropertiesList.Add(new PropertyNameValuePair(propertyName, propertyValue));
                    }
                    else
                    {
                        // There's no '=' sign in the string.  When this happens, we treat this string as basically
                        // an appendage on the value of the previous property.  For example, if the project file contains
                        //
                        //      <PropertyGroup>
                        //          <WarningsAsErrors>1234;5678;9999</WarningsAsErrors>
                        //      </PropertyGroup>
                        //      <Target Name="Build">
                        //          <MSBuild Projects="ConsoleApplication1.csproj"
                        //                   Properties="WarningsAsErrors=$(WarningsAsErrors)"/>
                        //      </Target>
                        //
                        // , then this method (GetTableWithEscaping) will see this:
                        //
                        //      propertyNameValueStrings[0] = "WarningsAsErrors=1234"
                        //      propertyNameValueStrings[1] = "5678"
                        //      propertyNameValueStrings[2] = "9999"
                        //
                        // And what we actually want to end up with in our final hashtable is this:
                        //
                        //      NAME                    VALUE
                        //      ===================     ================================
                        //      WarningsAsErrors        1234;5678;9999
                        //
                        if (finalPropertiesList.Count > 0)
                        {
                            // There was a property definition previous to this one.  Append the current string
                            // to that previous value, using semicolon as a separator.
                            string propertyValue = EscapingUtilities.Escape(propertyNameValueString.Trim());
                            finalPropertiesList[finalPropertiesList.Count - 1].Value.Append(';');
                            finalPropertiesList[finalPropertiesList.Count - 1].Value.Append(propertyValue);
                        }
                        else
                        {
                            // No equals sign in the very first property?  That's a problem.
                            if (log != null)
                            {
                                log.LogErrorWithCodeFromResources("General.InvalidPropertyError", syntaxName, propertyNameValueString);
                            }

                            return false;
                        }
                    }
                }

                // Convert the data in the List to a Hashtable, because that's what the MSBuild task eventually
                // needs to pass onto the engine.
                if (log != null)
                {
                    log.LogMessageFromText(parameterName, MessageImportance.Low);
                }

                foreach (PropertyNameValuePair propertyNameValuePair in finalPropertiesList)
                {
                    string propertyValue = OpportunisticIntern.StringBuilderToString(propertyNameValuePair.Value);
                    finalPropertiesTable[propertyNameValuePair.Name] = propertyValue;
                    if (log != null)
                    {
                        log.LogMessageFromText(String.Format(CultureInfo.InvariantCulture, "  {0}={1}",
                            propertyNameValuePair.Name, propertyValue),
                            MessageImportance.Low);
                    }
                }
            }

            return true;
        }
Esempio n. 11
0
        internal static bool GetTableWithEscaping(TaskLoggingHelper log, string parameterName, string syntaxName, string[] propertyNameValueStrings, out Dictionary <string, string> finalPropertiesTable)
        {
            finalPropertiesTable = null;

            if (propertyNameValueStrings != null)
            {
                finalPropertiesTable = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase);
                var finalPropertiesList = new List <PropertyNameValuePair>();

                // Loop through the array.  Each string in the array should be of the form:
                //          MyPropName=MyPropValue
                foreach (string propertyNameValueString in propertyNameValueStrings)
                {
                    // Find the first '=' sign in the string.
                    int indexOfEqualsSign = propertyNameValueString.IndexOf('=');

                    if (indexOfEqualsSign != -1)
                    {
                        // If we found one, then grab the stuff before it and put it into "propertyName",
                        // and grab the stuff after it and put it into "propertyValue".  But trim the
                        // whitespace from beginning and end of both name and value.  (When authoring a
                        // project/targets file, people like to use whitespace and newlines to pretty up
                        // the file format.)
                        string propertyName  = propertyNameValueString.Substring(0, indexOfEqualsSign).Trim();
                        string propertyValue = EscapingUtilities.Escape(propertyNameValueString.Substring(indexOfEqualsSign + 1).Trim());

                        // Make sure we have a property name and property value (though the value is allowed to be blank).
                        if (propertyName.Length == 0)
                        {
                            // No property name?  That's no good to us.
                            log?.LogErrorWithCodeFromResources("General.InvalidPropertyError", syntaxName, propertyNameValueString);

                            return(false);
                        }

                        // Store the property in our list.
                        finalPropertiesList.Add(new PropertyNameValuePair(propertyName, propertyValue));
                    }
                    else
                    {
                        // There's no '=' sign in the string.  When this happens, we treat this string as basically
                        // an appendage on the value of the previous property.  For example, if the project file contains
                        //
                        //      <PropertyGroup>
                        //          <WarningsAsErrors>1234;5678;9999</WarningsAsErrors>
                        //      </PropertyGroup>
                        //      <Target Name="Build">
                        //          <MSBuild Projects="ConsoleApplication1.csproj"
                        //                   Properties="WarningsAsErrors=$(WarningsAsErrors)"/>
                        //      </Target>
                        //
                        // , then this method (GetTableWithEscaping) will see this:
                        //
                        //      propertyNameValueStrings[0] = "WarningsAsErrors=1234"
                        //      propertyNameValueStrings[1] = "5678"
                        //      propertyNameValueStrings[2] = "9999"
                        //
                        // And what we actually want to end up with in our final hashtable is this:
                        //
                        //      NAME                    VALUE
                        //      ===================     ================================
                        //      WarningsAsErrors        1234;5678;9999
                        //
                        if (finalPropertiesList.Count > 0)
                        {
                            // There was a property definition previous to this one.  Append the current string
                            // to that previous value, using semicolon as a separator.
                            string propertyValue = EscapingUtilities.Escape(propertyNameValueString.Trim());
                            finalPropertiesList[finalPropertiesList.Count - 1].Value.Add(propertyValue);
                        }
                        else
                        {
                            // No equals sign in the very first property?  That's a problem.
                            log?.LogErrorWithCodeFromResources("General.InvalidPropertyError", syntaxName, propertyNameValueString);

                            return(false);
                        }
                    }
                }

                // Convert the data in the List to a Hashtable, because that's what the MSBuild task eventually
                // needs to pass onto the engine.
                log?.LogMessageFromText(parameterName, MessageImportance.Low);

                using SpanBasedStringBuilder stringBuilder = Strings.GetSpanBasedStringBuilder();
                foreach (PropertyNameValuePair propertyNameValuePair in finalPropertiesList)
                {
                    stringBuilder.Clear();
                    bool needsSemicolon = false;
                    foreach (string valueFragment in propertyNameValuePair.Value)
                    {
                        if (needsSemicolon)
                        {
                            stringBuilder.Append(";");
                        }
                        needsSemicolon = true;
                        stringBuilder.Append(valueFragment);
                    }

                    string propertyValue = stringBuilder.ToString();
                    finalPropertiesTable[propertyNameValuePair.Name] = propertyValue;
                    log?.LogMessageFromText(
                        $"  {propertyNameValuePair.Name}={propertyValue}",
                        MessageImportance.Low);
                }
            }

            return(true);
        }
        /// <summary>
        /// Attempts to resolve assembly references that were specified by the user.
        /// </summary>
        /// <param name="log">A <see cref="TaskLoggingHelper"/> used for logging.</param>
        /// <param name="taskInfo">A <see cref="TaskInfo"/> object containing details about the task.</param>
        /// <param name="items">Receives the list of full paths to resolved assemblies.</param>
        /// <returns><code>true</code> if all assemblies could be resolved, otherwise <code>false</code>.</returns>
        /// <remarks>The user can specify a short name like My.Assembly or My.Assembly.dll.  In this case we'll
        /// attempt to look it up in the directory containing our reference assemblies.  They can also specify a
        /// full path and we'll do no resolution.  At this time, these are the only two resolution mechanisms.
        /// Perhaps in the future this could be more powerful by using NuGet to resolve assemblies but we think
        /// that is too complicated for a simple in-line task.  If users have more complex requirements, they
        /// can compile their own task library.</remarks>
        internal static bool TryResolveAssemblyReferences(TaskLoggingHelper log, TaskInfo taskInfo, out ITaskItem[] items)
        {
            // Store the list of resolved assemblies because a user can specify a short name or a full path
            //
            ISet <string> resolvedAssemblyReferences = new HashSet <string>(StringComparer.OrdinalIgnoreCase);

            // Keeps track if there were one or more unresolved assemblies
            //
            bool hasInvalidReference = false;

            // Start with the user specified references and include all of the default references that are language agnostic
            //
            IEnumerable <string> references = taskInfo.References.Union(DefaultReferences[String.Empty]);

            if (DefaultReferences.ContainsKey(taskInfo.CodeLanguage))
            {
                // Append default references for the specific language
                //
                references = references.Union(DefaultReferences[taskInfo.CodeLanguage]);
            }

            // Loop through the user specified references as well as the default references
            //
            foreach (string reference in references)
            {
                // The user specified a full path to an assembly, so there is no need to resolve
                //
                if (File.Exists(reference))
                {
                    // The path could be relative like ..\Assembly.dll so we need to get the full path
                    //
                    resolvedAssemblyReferences.Add(Path.GetFullPath(reference));
                    continue;
                }

                // Attempt to "resolve" the assembly by getting a full path to our distributed reference assemblies
                //
                string assemblyFileName = reference.EndsWith(".dll", StringComparison.OrdinalIgnoreCase) || reference.EndsWith(".exe", StringComparison.OrdinalIgnoreCase)
                    ? reference
                    : $"{reference}.dll";

                string possiblePath = Path.Combine(ThisAssemblyParentDirectoryLazy.Value, ReferenceAssemblyDirectoryName, assemblyFileName);

                if (File.Exists(possiblePath))
                {
                    resolvedAssemblyReferences.Add(possiblePath);
                    continue;
                }

                // Could not resolve the assembly.  We currently don't support looking things up the GAC so that in-line task
                // assemblies are portable across platforms
                //
                log.LogErrorWithCodeFromResources("CodeTaskFactory_CouldNotFindReferenceAssembly", reference);
                hasInvalidReference = true;
            }

            // Transform the list of resolved assemblies to TaskItems if they were all resolved
            //
            items = hasInvalidReference ? null : resolvedAssemblyReferences.Select(i => (ITaskItem) new TaskItem(i)).ToArray();

            return(!hasInvalidReference);
        }
        ///  <summary>
        ///  Parses and validates the body of the &lt;UsingTask /&gt;.
        ///  </summary>
        ///  <param name="log">A <see cref="TaskLoggingHelper"/> used to log events during parsing.</param>
        ///  <param name="taskName">The name of the task.</param>
        ///  <param name="taskBody">The raw inner XML string of the &lt;UsingTask />&gt; to parse and validate.</param>
        /// <param name="parameters">An <see cref="ICollection{TaskPropertyInfo}"/> containing parameters for the task.</param>
        /// <param name="taskInfo">A <see cref="TaskInfo"/> object that receives the details of the parsed task.</param>
        /// <returns><code>true</code> if the task body was successfully parsed, otherwise <code>false</code>.</returns>
        ///  <remarks>
        ///  The <paramref name="taskBody"/> will look like this:
        ///  <![CDATA[
        ///
        ///    <Using Namespace="Namespace" />
        ///    <Reference Include="AssemblyName|AssemblyPath" />
        ///    <Code Type="Fragment|Method|Class" Language="cs|vb" Source="Path">
        ///      // Source code
        ///    </Code>
        ///
        ///  ]]>
        ///  </remarks>
        internal static bool TryLoadTaskBody(TaskLoggingHelper log, string taskName, string taskBody, ICollection <TaskPropertyInfo> parameters, out TaskInfo taskInfo)
        {
            taskInfo = new TaskInfo()
            {
                CodeLanguage = "CS",
                CodeType     = CodeTaskFactoryCodeType.Fragment,
                Name         = taskName,
            };

            XDocument document;

            try
            {
                // For legacy reasons, the inner XML of the <UsingTask /> has no document element.  So we have to add a top-level
                // element around it so it can be parsed.
                //
                document = XDocument.Parse($"<Task>{taskBody}</Task>");
            }
            catch (Exception e)
            {
                log.LogErrorWithCodeFromResources("CodeTaskFactory_InvalidTaskXml", e.Message);
                return(false);
            }

            if (document.Root == null)
            {
                log.LogErrorWithCodeFromResources("CodeTaskFactory_InvalidTaskXml");
                return(false);
            }

            XElement codeElement = null;

            // Loop through the children, ignoring ones we don't care about, parsing valid ones, and logging an error if we
            // encounter any element that is not recognized.
            //
            foreach (XNode node in document.Root.Nodes()
                     .Where(i => i.NodeType != XmlNodeType.Comment && i.NodeType != XmlNodeType.Whitespace))
            {
                switch (node.NodeType)
                {
                case XmlNodeType.Element:
                    XElement child = (XElement)node;

                    // Parse known elements and go to the default case if its an unknown element
                    //
                    if (child.Name.LocalName.Equals("Code", StringComparison.OrdinalIgnoreCase))
                    {
                        if (codeElement != null)
                        {
                            // Only one <Code /> element is allowed.
                            //
                            log.LogErrorWithCodeFromResources("CodeTaskFactory_MultipleCodeNodes");
                            return(false);
                        }

                        codeElement = child;
                    }
                    else if (child.Name.LocalName.Equals("Reference", StringComparison.OrdinalIgnoreCase))
                    {
                        XAttribute includeAttribute = child.Attributes().FirstOrDefault(i => i.Name.LocalName.Equals("Include", StringComparison.OrdinalIgnoreCase));

                        if (String.IsNullOrWhiteSpace(includeAttribute?.Value))
                        {
                            // A <Reference Include="" /> is not allowed.
                            //
                            log.LogErrorWithCodeFromResources("CodeTaskFactory_AttributeEmpty", "Include", "Reference");
                            return(false);
                        }

                        // Store the reference in the list
                        //
                        taskInfo.References.Add(includeAttribute.Value.Trim());
                    }
                    else if (child.Name.LocalName.Equals("Using", StringComparison.OrdinalIgnoreCase))
                    {
                        XAttribute namespaceAttribute = child.Attributes().FirstOrDefault(i => i.Name.LocalName.Equals("Namespace", StringComparison.OrdinalIgnoreCase));

                        if (String.IsNullOrWhiteSpace(namespaceAttribute?.Value))
                        {
                            // A <Using Namespace="" /> is not allowed
                            //
                            log.LogErrorWithCodeFromResources("CodeTaskFactory_AttributeEmpty", "Namespace", "Using");
                            return(false);
                        }

                        // Store the using in the list
                        //
                        taskInfo.Namespaces.Add(namespaceAttribute.Value.Trim());
                    }
                    else
                    {
                        log.LogErrorWithCodeFromResources("CodeTaskFactory_InvalidElementLocation",
                                                          child.Name.LocalName,
                                                          document.Root.Name.LocalName,
                                                          "  Valid child elements are <Code>, <Reference>, and <Using>.");
                        return(false);
                    }

                    break;

                default:
                    log.LogErrorWithCodeFromResources("CodeTaskFactory_InvalidElementLocation",
                                                      node.NodeType,
                                                      document.Root.Name.LocalName,
                                                      "  Valid child elements are <Code>, <Reference>, and <Using>.");
                    return(false);
                }
            }

            if (codeElement == null)
            {
                // <Code /> element is required so if we didn't find it then we need to error
                //
                log.LogErrorWithCodeFromResources("CodeTaskFactory_CodeElementIsMissing", taskName);
                return(false);
            }

            // Copies the source code from the inner text of the <Code /> element.  This might be override later if the user specified
            // a file instead.
            //
            taskInfo.SourceCode = codeElement.Value;

            // Parse the attributes of the <Code /> element
            //
            XAttribute languageAttribute = codeElement.Attributes().FirstOrDefault(i => i.Name.LocalName.Equals("Language", StringComparison.OrdinalIgnoreCase));
            XAttribute sourceAttribute   = codeElement.Attributes().FirstOrDefault(i => i.Name.LocalName.Equals("Source", StringComparison.OrdinalIgnoreCase));
            XAttribute typeAttribute     = codeElement.Attributes().FirstOrDefault(i => i.Name.LocalName.Equals("Type", StringComparison.OrdinalIgnoreCase));

            if (sourceAttribute != null)
            {
                if (String.IsNullOrWhiteSpace(sourceAttribute.Value))
                {
                    // A <Code Source="" /> is not allowed
                    //
                    log.LogErrorWithCodeFromResources("CodeTaskFactory_AttributeEmpty", "Source", "Code");
                    return(false);
                }

                // Instead of using the inner text of the <Code /> element, read the specified file as source code
                //
                taskInfo.CodeType   = CodeTaskFactoryCodeType.Class;
                taskInfo.SourceCode = File.ReadAllText(sourceAttribute.Value.Trim());
            }
            else if (typeAttribute != null)
            {
                if (String.IsNullOrWhiteSpace(typeAttribute.Value))
                {
                    // A <Code Type="" /> is not allowed
                    //
                    log.LogErrorWithCodeFromResources("CodeTaskFactory_AttributeEmpty", "Type", "Code");
                    return(false);
                }

                // Attempt to parse the code type as a CodeTaskFactoryCodeType
                //
                if (!Enum.TryParse(typeAttribute.Value.Trim(), ignoreCase: true, result: out CodeTaskFactoryCodeType codeType))
                {
                    log.LogErrorWithCodeFromResources("CodeTaskFactory_InvalidCodeType", typeAttribute.Value, String.Join(", ", Enum.GetNames(typeof(CodeTaskFactoryCodeType))));
                    return(false);
                }

                taskInfo.CodeType = codeType;
            }

            // Warn that <ParameterGroup/> is ignored if any parameters are supplied when Type="Class".
            //
            if (taskInfo.CodeType == CodeTaskFactoryCodeType.Class && parameters.Any())
            {
                log.LogWarningWithCodeFromResources("CodeTaskFactory_ParameterGroupIgnoredForCodeTypeClass");
            }

            if (languageAttribute != null)
            {
                if (String.IsNullOrWhiteSpace(languageAttribute.Value))
                {
                    // A <Code Language="" /> is not allowed
                    //
                    log.LogErrorWithCodeFromResources("CodeTaskFactory_AttributeEmpty", "Language", "Code");
                    return(false);
                }

                if (ValidCodeLanguages.ContainsKey(languageAttribute.Value))
                {
                    // The user specified one of the primary code languages using our vernacular
                    //
                    taskInfo.CodeLanguage = languageAttribute.Value.ToUpperInvariant();
                }
                else
                {
                    bool foundValidCodeLanguage = false;

                    // Attempt to map the user specified value as an alias to our vernacular for code languages
                    //
                    foreach (string validLanguage in ValidCodeLanguages.Keys)
                    {
                        if (ValidCodeLanguages[validLanguage].Contains(languageAttribute.Value))
                        {
                            taskInfo.CodeLanguage  = validLanguage;
                            foundValidCodeLanguage = true;
                            break;
                        }
                    }

                    if (!foundValidCodeLanguage)
                    {
                        // The user specified a code language we don't support
                        //
                        log.LogErrorWithCodeFromResources("CodeTaskFactory_InvalidCodeLanguage", languageAttribute.Value, String.Join(", ", ValidCodeLanguages.Keys));
                        return(false);
                    }
                }
            }

            if (String.IsNullOrWhiteSpace(taskInfo.SourceCode))
            {
                // The user did not specify a path to source code or source code within the <Code /> element.
                //
                log.LogErrorWithCodeFromResources("CodeTaskFactory_NoSourceCode");
                return(false);
            }

            ApplySourceCodeTemplate(taskInfo, parameters);

            return(true);
        }
Esempio n. 14
0
        internal bool TryResolveAssemblyReferences(TaskLoggingHelper log, RoslynCodeTaskFactoryTaskInfo taskInfo, out ITaskItem[] items)
        {
            // Store the list of resolved assemblies because a user can specify a short name or a full path
            ISet <string> resolvedAssemblyReferences = new HashSet <string>(StringComparer.OrdinalIgnoreCase);

            // Keeps track if there were one or more unresolved assemblies
            bool hasInvalidReference = false;

            // Start with the user specified references and include all of the default references that are language agnostic
            IEnumerable <string> references = taskInfo.References.Union(DefaultReferences[String.Empty]);

            if (DefaultReferences.ContainsKey(taskInfo.CodeLanguage))
            {
                // Append default references for the specific language
                references = references.Union(DefaultReferences[taskInfo.CodeLanguage]);
            }

            List <string> directoriesToAddToAppDomain = new();

            // Loop through the user specified references as well as the default references
            foreach (string reference in references)
            {
                // The user specified a full path to an assembly, so there is no need to resolve
                if (FileSystems.Default.FileExists(reference))
                {
                    // The path could be relative like ..\Assembly.dll so we need to get the full path
                    string fullPath = Path.GetFullPath(reference);
                    directoriesToAddToAppDomain.Add(Path.GetDirectoryName(fullPath));
                    resolvedAssemblyReferences.Add(fullPath);
                    continue;
                }

                // Attempt to "resolve" the assembly by getting a full path to our distributed reference assemblies
                string assemblyFileName = reference.EndsWith(".dll", StringComparison.OrdinalIgnoreCase) || reference.EndsWith(".exe", StringComparison.OrdinalIgnoreCase)
                    ? reference
                    : $"{reference}.dll";

                string resolvedDir = new[]
                {
                    Path.Combine(ThisAssemblyDirectoryLazy.Value, ReferenceAssemblyDirectoryName),
                    ThisAssemblyDirectoryLazy.Value,
                }
                .Concat(MonoLibDirs)
                .FirstOrDefault(p => File.Exists(Path.Combine(p, assemblyFileName)));

                if (resolvedDir != null)
                {
                    resolvedAssemblyReferences.Add(Path.Combine(resolvedDir, assemblyFileName));
                    continue;
                }

                // Could not resolve the assembly.  We currently don't support looking things up the GAC so that in-line task
                // assemblies are portable across platforms
                log.LogErrorWithCodeFromResources("CodeTaskFactory.CouldNotFindReferenceAssembly", reference);

                hasInvalidReference = true;
            }

            // Transform the list of resolved assemblies to TaskItems if they were all resolved
            items = hasInvalidReference ? null : resolvedAssemblyReferences.Select(i => (ITaskItem) new TaskItem(i)).ToArray();

            handlerAddedToAppDomain = (_, eventArgs) => TryLoadAssembly(directoriesToAddToAppDomain, new AssemblyName(eventArgs.Name));
            AppDomain.CurrentDomain.AssemblyResolve += handlerAddedToAppDomain;

            return(!hasInvalidReference);
Esempio n. 15
0
        /// <summary>
        /// Initialze the task factory
        /// </summary>
        public bool Initialize(string taskName, IDictionary <string, TaskPropertyInfo> taskParameters, string taskElementContents, IBuildEngine taskFactoryLoggingHost)
        {
            _nameOfTask = taskName;
            _log        = new TaskLoggingHelper(taskFactoryLoggingHost, taskName)
            {
                TaskResources     = AssemblyResources.PrimaryResources,
                HelpKeywordPrefix = "MSBuild."
            };

            XmlNode taskContent = ExtractTaskContent(taskElementContents);

            if (taskContent == null)
            {
                // Just return false because we have already logged the error in ExtractTaskContents
                return(false);
            }

            bool validatedTaskNode = ValidateTaskNode();

            if (!validatedTaskNode)
            {
                return(false);
            }

            if (taskContent.Attributes["Type"] != null)
            {
                _type = taskContent.Attributes["Type"].Value;
                if (_type.Length == 0)
                {
                    _log.LogErrorWithCodeFromResources("CodeTaskFactory.AttributeEmpty", "Type");
                    return(false);
                }
            }

            if (taskContent.Attributes["Language"] != null)
            {
                _language = taskContent.Attributes["Language"].Value;
                if (_language.Length == 0)
                {
                    _log.LogErrorWithCodeFromResources("CodeTaskFactory.AttributeEmpty", "Language");
                    return(false);
                }
            }

            if (taskContent.Attributes["Source"] != null)
            {
                _sourcePath = taskContent.Attributes["Source"].Value;

                if (_sourcePath.Length == 0)
                {
                    _log.LogErrorWithCodeFromResources("CodeTaskFactory.AttributeEmpty", "Source");
                    return(false);
                }

                if (_type == null)
                {
                    _type = "Class";
                }
            }

            _referencedAssemblies = ExtractReferencedAssemblies();

            if (_log.HasLoggedErrors)
            {
                return(false);
            }

            _usingNamespaces = ExtractUsingNamespaces();

            if (_log.HasLoggedErrors)
            {
                return(false);
            }

            _sourceCode = taskContent.InnerText;

            if (_type == null)
            {
                _type = "Fragment";
            }

            if (_language == null)
            {
                _language = "cs";
            }

            if (String.Equals(_type, "Fragment", StringComparison.OrdinalIgnoreCase))
            {
                _typeIsFragment = true;
                _typeIsMethod   = false;
            }
            else if (String.Equals(_type, "Method", StringComparison.OrdinalIgnoreCase))
            {
                _typeIsFragment = false;
                _typeIsMethod   = true;
            }

            _taskParameterTypeInfo = taskParameters;

            _compiledAssembly = CompileInMemoryAssembly();

            // If it wasn't compiled, it logged why.
            // If it was, continue.
            if (_compiledAssembly != null)
            {
                // Now go find the type int he compiled assembly.
                Type[] exportedTypes = _compiledAssembly.GetExportedTypes();

                Type fullNameMatch    = null;
                Type partialNameMatch = null;

                foreach (Type exportedType in exportedTypes)
                {
                    string exportedTypeName = exportedType.FullName;
                    if (exportedTypeName.Equals(_nameOfTask, StringComparison.OrdinalIgnoreCase))
                    {
                        fullNameMatch = exportedType;
                        break;
                    }
                    else if (partialNameMatch == null && exportedTypeName.EndsWith(_nameOfTask, StringComparison.OrdinalIgnoreCase))
                    {
                        partialNameMatch = exportedType;
                    }
                }

                TaskType = fullNameMatch ?? partialNameMatch;
                if (TaskType == null)
                {
                    _log.LogErrorWithCodeFromResources("CodeTaskFactory.CouldNotFindTaskInAssembly", _nameOfTask);
                }
            }

            return(!_log.HasLoggedErrors);
        }
Esempio n. 16
0
        internal static bool TryLoadTaskBody(TaskLoggingHelper log, string taskName, string taskBody, ICollection <TaskPropertyInfo> parameters, out RoslynCodeTaskFactoryTaskInfo taskInfo)
        {
            taskInfo = new RoslynCodeTaskFactoryTaskInfo
            {
                CodeLanguage = "CS",
                CodeType     = RoslynCodeTaskFactoryCodeType.Fragment,
                Name         = taskName,
            };

            XDocument document;

            try
            {
                // For legacy reasons, the inner XML of the <UsingTask /> has no document element.  So we have to add a top-level
                // element around it so it can be parsed.
                document = XDocument.Parse($"<Task>{taskBody}</Task>");
            }
            catch (Exception e)
            {
                log.LogErrorWithCodeFromResources("CodeTaskFactory.InvalidTaskXml", e.Message);
                return(false);
            }

            if (document.Root == null)
            {
                log.LogErrorWithCodeFromResources("CodeTaskFactory.InvalidTaskXml", String.Empty);
                return(false);
            }

            XElement codeElement = null;

            // Loop through the children, ignoring ones we don't care about, parsing valid ones, and logging an error if we
            // encounter any element that is not recognized.
            foreach (XNode node in document.Root.Nodes()
                     .Where(i => i.NodeType != XmlNodeType.Comment && i.NodeType != XmlNodeType.Whitespace))
            {
                switch (node.NodeType)
                {
                case XmlNodeType.Element:
                    XElement child = (XElement)node;

                    // Parse known elements and go to the default case if its an unknown element
                    if (child.Name.LocalName.Equals("Code"))
                    {
                        if (codeElement != null)
                        {
                            // Only one <Code /> element is allowed.
                            log.LogErrorWithCodeFromResources("CodeTaskFactory.MultipleCodeNodes");
                            return(false);
                        }

                        codeElement = child;
                    }
                    else if (child.Name.LocalName.Equals("Reference"))
                    {
                        XAttribute includeAttribute = child.Attributes().FirstOrDefault(i => i.Name.LocalName.Equals("Include"));

                        if (String.IsNullOrWhiteSpace(includeAttribute?.Value))
                        {
                            // A <Reference Include="" /> is not allowed.
                            log.LogErrorWithCodeFromResources("CodeTaskFactory.AttributeEmptyWithElement", "Include", "Reference");
                            return(false);
                        }

                        // Store the reference in the list
                        taskInfo.References.Add(includeAttribute.Value.Trim());
                    }
                    else if (child.Name.LocalName.Equals("Using"))
                    {
                        XAttribute namespaceAttribute = child.Attributes().FirstOrDefault(i => i.Name.LocalName.Equals("Namespace"));

                        if (String.IsNullOrWhiteSpace(namespaceAttribute?.Value))
                        {
                            // A <Using Namespace="" /> is not allowed
                            log.LogErrorWithCodeFromResources("CodeTaskFactory.AttributeEmptyWithElement", "Namespace", "Using");
                            return(false);
                        }

                        // Store the using in the list
                        taskInfo.Namespaces.Add(namespaceAttribute.Value.Trim());
                    }
                    else
                    {
                        log.LogErrorWithCodeFromResources("CodeTaskFactory.InvalidElementLocation",
                                                          child.Name.LocalName,
                                                          document.Root.Name.LocalName);
                        return(false);
                    }

                    break;

                default:
                    log.LogErrorWithCodeFromResources("CodeTaskFactory.InvalidElementLocation",
                                                      node.NodeType,
                                                      document.Root.Name.LocalName);
                    return(false);
                }
            }

            if (codeElement == null)
            {
                // <Code /> element is required so if we didn't find it then we need to error
                log.LogErrorWithCodeFromResources("CodeTaskFactory.CodeElementIsMissing", taskName);
                return(false);
            }

            // Copies the source code from the inner text of the <Code /> element.  This might be override later if the user specified
            // a file instead.
            taskInfo.SourceCode = codeElement.Value;

            // Parse the attributes of the <Code /> element
            XAttribute languageAttribute = null;
            XAttribute sourceAttribute   = null;
            XAttribute typeAttribute     = null;

            // TODO: Unit test for this logic and the error message
            foreach (XAttribute attribute in codeElement.Attributes().Where(i => !i.IsNamespaceDeclaration))
            {
                switch (attribute.Name.LocalName)
                {
                case "Language":
                    languageAttribute = attribute;
                    break;

                case "Source":
                    sourceAttribute = attribute;
                    break;

                case "Type":
                    typeAttribute = attribute;
                    break;

                default:
                    log.LogErrorWithCodeFromResources("CodeTaskFactory.InvalidCodeElementAttribute",
                                                      attribute.Name.LocalName);
                    return(false);
                }
            }

            if (sourceAttribute != null)
            {
                if (String.IsNullOrWhiteSpace(sourceAttribute.Value))
                {
                    // A <Code Source="" /> is not allowed
                    log.LogErrorWithCodeFromResources("CodeTaskFactory.AttributeEmptyWithElement", "Source", "Code");
                    return(false);
                }

                // Instead of using the inner text of the <Code /> element, read the specified file as source code
                taskInfo.CodeType   = RoslynCodeTaskFactoryCodeType.Class;
                taskInfo.SourceCode = File.ReadAllText(sourceAttribute.Value.Trim());
            }
            else if (typeAttribute != null)
            {
                if (String.IsNullOrWhiteSpace(typeAttribute.Value))
                {
                    // A <Code Type="" /> is not allowed
                    log.LogErrorWithCodeFromResources("CodeTaskFactory.AttributeEmptyWithElement", "Type", "Code");
                    return(false);
                }

                // Attempt to parse the code type as a CodeTaskFactoryCodeType
                if (!Enum.TryParse(typeAttribute.Value.Trim(), ignoreCase: true, result: out RoslynCodeTaskFactoryCodeType codeType))
                {
                    log.LogErrorWithCodeFromResources("CodeTaskFactory.InvalidCodeType", typeAttribute.Value, String.Join(", ", Enum.GetNames(typeof(RoslynCodeTaskFactoryCodeType))));
                    return(false);
                }

                taskInfo.CodeType = codeType;
            }

            if (languageAttribute != null)
            {
                if (String.IsNullOrWhiteSpace(languageAttribute.Value))
                {
                    // A <Code Language="" /> is not allowed
                    log.LogErrorWithCodeFromResources("CodeTaskFactory.AttributeEmptyWithElement", "Language", "Code");
                    return(false);
                }

                if (ValidCodeLanguages.ContainsKey(languageAttribute.Value))
                {
                    // The user specified one of the primary code languages using our vernacular
                    taskInfo.CodeLanguage = languageAttribute.Value.ToUpperInvariant();
                }
                else
                {
                    bool foundValidCodeLanguage = false;

                    // Attempt to map the user specified value as an alias to our vernacular for code languages
                    foreach (KeyValuePair <string, ISet <string> > validLanguage in ValidCodeLanguages)
                    {
                        if (validLanguage.Value.Contains(languageAttribute.Value))
                        {
                            taskInfo.CodeLanguage  = validLanguage.Key;
                            foundValidCodeLanguage = true;
                            break;
                        }
                    }

                    if (!foundValidCodeLanguage)
                    {
                        // The user specified a code language we don't support
                        log.LogErrorWithCodeFromResources("CodeTaskFactory.InvalidCodeLanguage", languageAttribute.Value, String.Join(", ", ValidCodeLanguages.Keys));
                        return(false);
                    }
                }
            }

            if (String.IsNullOrWhiteSpace(taskInfo.SourceCode))
            {
                // The user did not specify a path to source code or source code within the <Code /> element.
                log.LogErrorWithCodeFromResources("CodeTaskFactory.NoSourceCode");
                return(false);
            }

            taskInfo.SourceCode = GetSourceCode(taskInfo, parameters);

            return(true);
        }
Esempio n. 17
0
        protected override int ExecuteTool(string pathToTool, string responseFileCommands, string commandLineCommands)
        {
            if (ProvideCommandLineArgs)
            {
                CommandLineArgs = GetArguments(commandLineCommands, responseFileCommands)
                                  .Select(arg => new TaskItem(arg)).ToArray();
            }

            if (SkipCompilerExecution)
            {
                return(0);
            }

            try
            {
                string workingDir = CurrentDirectoryToUse();
                string?tempDir    = BuildServerConnection.GetTempPath(workingDir);

                if (!UseSharedCompilation ||
                    HasToolBeenOverridden ||
                    !BuildServerConnection.IsCompilerServerSupported)
                {
                    return(base.ExecuteTool(pathToTool, responseFileCommands, commandLineCommands));
                }

                using var logger = new CompilerServerLogger();
                using (_sharedCompileCts = new CancellationTokenSource())
                {
                    logger.Log($"CommandLine = '{commandLineCommands}'");
                    logger.Log($"BuildResponseFile = '{responseFileCommands}'");

                    var clientDir = Path.GetDirectoryName(PathToManagedTool);
                    if (clientDir is null || tempDir is null)
                    {
                        return(base.ExecuteTool(pathToTool, responseFileCommands, commandLineCommands));
                    }

                    // Note: we can't change the "tool path" printed to the console when we run
                    // the Csc/Vbc task since MSBuild logs it for us before we get here. Instead,
                    // we'll just print our own message that contains the real client location
                    Log.LogMessage(ErrorString.UsingSharedCompilation, clientDir);

                    var buildPaths = new BuildPathsAlt(
                        clientDir: clientDir,
                        workingDir: workingDir,
                        // MSBuild doesn't need the .NET SDK directory
                        sdkDir: null,
                        tempDir: tempDir);

                    // Note: using ToolArguments here (the property) since
                    // commandLineCommands (the parameter) may have been mucked with
                    // (to support using the dotnet cli)
                    var responseTask = BuildServerConnection.RunServerCompilationAsync(
                        Language,
                        RoslynString.IsNullOrEmpty(SharedCompilationId) ? null : SharedCompilationId,
                        GetArguments(ToolArguments, responseFileCommands).ToList(),
                        buildPaths,
                        keepAlive: null,
                        libEnvVariable: LibDirectoryToUse(),
                        logger: logger,
                        cancellationToken: _sharedCompileCts.Token);

                    responseTask.Wait(_sharedCompileCts.Token);

                    var response = responseTask.Result;
                    if (response != null)
                    {
                        ExitCode = HandleResponse(response, pathToTool, responseFileCommands, commandLineCommands, logger);
                    }
                    else
                    {
                        logger.LogError($"Server compilation failed, falling back to {pathToTool}");
                        Log.LogMessage(ErrorString.SharedCompilationFallback, pathToTool);

                        ExitCode = base.ExecuteTool(pathToTool, responseFileCommands, commandLineCommands);
                    }
                }
            }
            catch (OperationCanceledException)
            {
                ExitCode = 0;
            }
            catch (Exception e)
            {
                var util = new TaskLoggingHelper(this);
                util.LogErrorWithCodeFromResources("Compiler_UnexpectedException");
                util.LogErrorFromException(e, showStackTrace: true, showDetail: true, file: null);
                ExitCode = -1;
            }

            return(ExitCode);
        }