// // WriteCodeFragment.cs // // Authors: // Marek Safar // // Copyright (C) 2014 Xamarin Inc (http://www.xamarin.com) // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // using System; using System.IO; using System.Collections; using System.Collections.Generic; using System.CodeDom; using System.CodeDom.Compiler; using System.Globalization; using Microsoft.Build.Framework; using Microsoft.Build.Utilities; namespace Microsoft.Build.Tasks { public class WriteCodeFragment : TaskExtension { public ITaskItem[] AssemblyAttributes { get; set; } [Required] public string Language { get; set; } public ITaskItem OutputDirectory { get; set; } [Output] public ITaskItem OutputFile { get; set; } public override bool Execute () { if (OutputFile == null) { if (OutputDirectory == null) return false; throw new NotImplementedException ("Temporary file in custom directory"); } else { if (OutputDirectory != null) OutputFile = new TaskItem (Path.Combine (OutputDirectory.ItemSpec, OutputFile.ItemSpec)); } if (AssemblyAttributes == null) { OutputFile = null; return true; } var file = OutputFile.ItemSpec; if (!GenerateFile (file)) return false; Log.LogMessage ("Emitted specified code into \"{0}\".", file); return true; } bool GenerateFile (string file) { var cu = new CodeCompileUnit (); var ns = new CodeNamespace (); cu.Namespaces.Add (ns); ns.Imports.Add (new CodeNamespaceImport ("System")); ns.Imports.Add (new CodeNamespaceImport ("System.Reflection")); ns.Comments.Add (new CodeCommentStatement ("Generated by the WriteCodeFragment task on " + DateTime.Now)); foreach (var attr in AssemblyAttributes) { // There is no better way to get ordered parameter data // that this horrible api var metadata = attr.CloneCustomMetadata (); List> args = null; foreach (DictionaryEntry entry in metadata) { var key = (string) entry.Key; if (!key.StartsWith ("_Parameter", StringComparison.Ordinal)) continue; int key_value; if (!int.TryParse (key.Substring (10), NumberStyles.None, CultureInfo.InvariantCulture, out key_value)) continue; if (args == null) args = new List> (); args.Add (Tuple.Create (key_value, new CodeAttributeArgument (new CodePrimitiveExpression ((string) entry.Value)))); } var cad = new CodeAttributeDeclaration (attr.ItemSpec); if (args != null) { args.Sort ((a, b) => a.Item1.CompareTo (b.Item1)); foreach (var arg in args) cad.Arguments.Add (arg.Item2); } cu.AssemblyCustomAttributes.Add (cad); } var provider = CodeDomProvider.CreateProvider (Language); using (var sw = new StreamWriter (file, false)) { provider.GenerateCodeFromCompileUnit (cu, sw, new CodeGeneratorOptions ()); } return true; } } }