//------------------------------------------------------------ // 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 generatedCodeFiles = new List(); // 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(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 applicationMarkup = new List(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 sourceCodeFiles = null; if (this.SourceCodeFiles != null) { sourceCodeFiles = new List(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 applicationMarkupWithTypeName = null; if (this.ApplicationMarkupWithTypeName != null) { applicationMarkupWithTypeName = new Dictionary(); } 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)); } } } }