File: Microsoft\Build\Tasks\Xaml\CompilationPass2Task.cs
Project: ndp\cdf\src\NetFx40\XamlBuildTask\XamlBuildTask.csproj (XamlBuildTask)
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//------------------------------------------------------------
 
namespace Microsoft.Build.Tasks.Xaml
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Reflection;
    using System.Runtime;
    using Microsoft.Build.Framework;
    using Microsoft.Build.Utilities;
    using XamlBuildTask;
 
    [Fx.Tag.XamlVisible(true)]
    public class CompilationPass2Task : Task
    {
        List<ITaskItem> generatedCodeFiles = new List<ITaskItem>();
 
        // We will do Dev10 behavior if NONE of the new required properties are specified. This can happen
        // if a Dev10 version of the Microsoft.Xaml.Targets file is being used with Dev11 installed.
        // The new required properties for Dev11 are:
        //    Language
        //    OutputPath
        //    MSBuildProjectDirectory
        //    ApplicationMarkupWithTypeName
        //
        // If ANY of these are specified, then ALL must be specified.
        bool supportExtensions = false;
        string language;
        string outputPath;
        string msBuildProjectDirectory;
        ITaskItem[] applicationMarkupWithTypeName;
 
        public CompilationPass2Task()
        {
        }
 
        [Fx.Tag.KnownXamlExternal]
        public ITaskItem[] ApplicationMarkup { get; set; }
 
        public string AssemblyName
        { get; set; }
 
        [Fx.Tag.KnownXamlExternal]
        public ITaskItem[] References { get; set; }
 
        // Required in Dev11, but for backward compatibility with a Dev10 targets file, not marking as required.
        public string Language
        {
            get
            {
                return this.language;
            }
 
            set
            {
                this.language = value;
                this.supportExtensions = true;
            }
        }
 
        // Required in Dev11, but for backward compatibility with a Dev10 targets file, not marking as required.
        public string OutputPath
        {
            get
            {
                return this.outputPath;
            }
 
            set
            {
                this.outputPath = value;
                this.supportExtensions = true;
            }
        }
 
        // Required in Dev11, but for backward compatibility with a Dev10 targets file, not marking as required.
        public string MSBuildProjectDirectory
        {
            get
            {
                return this.msBuildProjectDirectory;
            }
 
            set
            {
                this.msBuildProjectDirectory = value;
                this.supportExtensions = true;
            }
        }
 
        public bool IsInProcessXamlMarkupCompile
        { get; set; }
 
        [Fx.Tag.KnownXamlExternal]
        public ITaskItem[] SourceCodeFiles
        { get; set; }
        
        public ITaskItem[] XamlBuildTypeInspectionExtensionNames
        { get; set; }
 
        // Required in Dev11, but for backward compatibility with a Dev10 targets file, not marking as required.
        public ITaskItem[] ApplicationMarkupWithTypeName
        {
            get
            {
                return this.applicationMarkupWithTypeName;
            }
 
            set
            {
                this.applicationMarkupWithTypeName = value;
                this.supportExtensions = true;
            }
        }
 
        public string LocalAssemblyReference
        { get; set; }
 
        public string RootNamespace
        { get; set; }
 
        public string BuildTaskPath
        { get; set; }
 
        [Output]
        public ITaskItem[] ExtensionGeneratedCodeFiles
        {
            get
            {
                return generatedCodeFiles.ToArray();
            }
            set
            {
                generatedCodeFiles = new List<ITaskItem>(value);
            }
        }
 
        public override bool Execute()
        {
            AppDomain appDomain = null;
 
            try
            {
                ValidateRequiredDev11Properties();
 
                appDomain = XamlBuildTaskServices.CreateAppDomain("CompilationPass2AppDomain_" + Guid.NewGuid(), BuildTaskPath);
 
                CompilationPass2TaskInternal wrapper = (CompilationPass2TaskInternal)appDomain.CreateInstanceAndUnwrap(
                    Assembly.GetExecutingAssembly().FullName,
                    typeof(CompilationPass2TaskInternal).FullName);
 
                PopulateBuildArtifacts(wrapper);
 
                bool ret = wrapper.Execute();
 
                ExtractBuiltArtifacts(wrapper);
 
                if (!ret)
                {
                    foreach (LogData logData in wrapper.LogData)
                    {
                        XamlBuildTaskServices.LogException(
                            this.Log,
                            logData.Message,
                            logData.FileName,
                            logData.LineNumber,
                            logData.LinePosition);
                    }
                }
 
                return ret;
            }
            catch (Exception e)
            {
                if (Fx.IsFatal(e))
                {
                    throw;
                }
 
                XamlBuildTaskServices.LogException(this.Log, e.Message);
                return false;
            }
            finally
            {
                if (appDomain != null)
                {
                    AppDomain.Unload(appDomain);
                }
            }
        }
 
        string SeparateWithComma(string originalString, string stringToAppend)
        {
            if (!String.IsNullOrEmpty(originalString))
            {
                return String.Join(", ", originalString, stringToAppend);
            }
            else
            {
                return stringToAppend;
            }
        }
 
        void ValidateRequiredDev11Properties()
        {
            if (this.supportExtensions)
            {
                string requiredPropertiesNotSpecified = "";
                if (this.language == null)
                {
                    requiredPropertiesNotSpecified = SeparateWithComma(requiredPropertiesNotSpecified, "Language");
                }
                if (this.outputPath == null)
                {
                    requiredPropertiesNotSpecified = SeparateWithComma(requiredPropertiesNotSpecified, "OutputPath");
                }
                if (this.msBuildProjectDirectory == null)
                {
                    requiredPropertiesNotSpecified = SeparateWithComma(requiredPropertiesNotSpecified, "MSBuildProjectDirectory");
                }
                if (this.applicationMarkupWithTypeName == null)
                {
                    requiredPropertiesNotSpecified = SeparateWithComma(requiredPropertiesNotSpecified, "ApplicationMarkupWithTypeName");
                }
                if (!String.IsNullOrEmpty(requiredPropertiesNotSpecified))
                {
                    throw FxTrace.Exception.AsError(new InvalidOperationException(SR.MissingRequiredParametersCompilationPass2Task(requiredPropertiesNotSpecified)));
                }
            }
        }
 
        void PopulateBuildArtifacts(CompilationPass2TaskInternal wrapper)
        {
            if (!this.supportExtensions)
            {
                IList<string> applicationMarkup = new List<string>(this.ApplicationMarkup.Length);
                foreach (ITaskItem taskItem in this.ApplicationMarkup)
                {
                    applicationMarkup.Add(taskItem.ItemSpec);
                }
                wrapper.ApplicationMarkup = applicationMarkup;
            }
 
            wrapper.SupportExtensions = this.supportExtensions;
 
            wrapper.BuildLogger = this.Log;
 
            wrapper.References = this.References
                .Select(i => new DelegatingTaskItem(i) as ITaskItem).ToList();
 
            wrapper.LocalAssemblyReference = this.LocalAssemblyReference;
 
            wrapper.AssemblyName = this.AssemblyName;
 
            wrapper.RootNamespace = this.RootNamespace;
 
            wrapper.Language = this.Language;
 
            wrapper.OutputPath = this.OutputPath;
 
            wrapper.IsInProcessXamlMarkupCompile = this.IsInProcessXamlMarkupCompile;
 
            wrapper.MSBuildProjectDirectory = this.MSBuildProjectDirectory;
 
            IList<string> sourceCodeFiles = null;
            if (this.SourceCodeFiles != null)
            {
                sourceCodeFiles = new List<string>(this.SourceCodeFiles.Length);
                foreach (ITaskItem taskItem in this.SourceCodeFiles)
                {
                    sourceCodeFiles.Add(taskItem.ItemSpec);
                }
            }
            wrapper.SourceCodeFiles = sourceCodeFiles;
 
            if (this.supportExtensions)
            {
                wrapper.XamlBuildTaskTypeInspectionExtensionNames = XamlBuildTaskServices.GetXamlBuildTaskExtensionNames(this.XamlBuildTypeInspectionExtensionNames);
 
                // Here we create a Dictionary of Type Full Name and corresponding TaskItem
                // This is passed to the extensions which enables them to look up 
                // metadata about a type like file name.
                IDictionary<string, ITaskItem> applicationMarkupWithTypeName = null;
                if (this.ApplicationMarkupWithTypeName != null)
                {
                    applicationMarkupWithTypeName = new Dictionary<string, ITaskItem>();
                }
                foreach (ITaskItem taskItem in this.ApplicationMarkupWithTypeName)
                {
                    string typeName = taskItem.GetMetadata("typeName");
                    if (!String.IsNullOrWhiteSpace(typeName))
                    {
                        applicationMarkupWithTypeName.Add(typeName, new DelegatingTaskItem(taskItem));
                    }
                }
                wrapper.ApplicationMarkupWithTypeName = applicationMarkupWithTypeName;
            }
        }
 
        void ExtractBuiltArtifacts(CompilationPass2TaskInternal wrapper)
        {
            if (wrapper.GeneratedCodeFiles == null)
            {
                return;
            }
            foreach (string code in wrapper.GeneratedCodeFiles)
            {
                this.generatedCodeFiles.Add(new TaskItem(code));
            }
        }
    }
}