public bool Initialize (string taskName, IDictionary<string, string> factoryIdentityParameters, IDictionary<string, TaskPropertyInfo> parameterGroup, string taskBody, IBuildEngine taskFactoryLoggingHost) { task_name = taskName; if (parameterGroup != null) parameter_group = new Dictionary<string, TaskPropertyInfo> (parameterGroup); List<string> references = new List<string> (); List<string> namespace_uses = new List<string> (); namespace_uses.Add ("Microsoft.Build.Framework"); string type = null, language = null, code = null; var xml = XmlReader.Create (new StringReader (taskBody), new XmlReaderSettings () { ConformanceLevel = ConformanceLevel.Fragment }); for (xml.MoveToContent (); !xml.EOF; xml.MoveToContent ()) { switch (xml.NodeType) { case XmlNodeType.Element: switch (xml.LocalName) { case "Reference": references.Add (xml.GetAttribute ("Include")); xml.Skip (); break; case "Using": namespace_uses.Add (xml.GetAttribute ("Namespace")); xml.Skip (); break; case "Code": // MSB3757: Multiple Code elements have been found, this is not allowed. if (code != null) throw new InvalidProjectFileException (null, "Multiple Code elements are not allowed", "MSB", "3757", null); type = xml.GetAttribute ("Type"); language = xml.GetAttribute ("Language"); code = xml.ReadElementContentAsString (); break; } break; default: xml.Skip (); break; } } if (language == "vb") throw new NotImplementedException (string.Format ("{0} is not supported language for inline task", language)); if (language != "cs") throw new InvalidProjectFileException (null, string.Format ("{0} is not supported language for inline task", language), "MSB", "4175", null); string gen = null; // The documentation says "ITask", but the very first example shows "Log" which is not in ITask! It is likely that the generated code uses Task or TaskExtension. string classTemplate = @"public class " + taskName + " : Microsoft.Build.Utilities.Task { @@EXECUTE@@ }"; foreach (var ns in namespace_uses) gen += "using " + ns + ";\n"; switch (type) { case "Class": gen += code; break; case "Method": gen += classTemplate.Replace ("@@EXECUTE@@", code); break; case "Fragment": gen += classTemplate.Replace ("@@EXECUTE@@", "public override bool Execute () { " + code + " return true; }"); break; } var cscParams = new CompilerParameters (); cscParams.ReferencedAssemblies.Add ("Microsoft.Build.Framework.dll"); cscParams.ReferencedAssemblies.Add ("Microsoft.Build.Utilities.v4.0.dll"); // since we use Task, it depends on this dll. var results = new CSharpCodeProvider ().CompileAssemblyFromSource (cscParams, gen); var errors = new CompilerError [results.Errors.Count]; results.Errors.CopyTo (errors, 0); if (errors.Any (e => !e.IsWarning)) { string msg = string.Format ("Invalid '{0}' source code of '{1}' type: {2}", language, type, string.Join (" ", errors.Where (e => !e.IsWarning).Select (e => e.ToString ()))); throw new InvalidProjectFileException (null, msg, "MSB", "3758", null); } assembly = results.CompiledAssembly; return true; }
bool Initialize(string taskName, IDictionary <string, string> factoryIdentityParameters, IDictionary <string, TaskPropertyInfo> parameterGroup, string taskBody, IBuildEngine taskFactoryLoggingHost) { task_name = taskName; if (parameterGroup != null) { parameter_group = new Dictionary <string, TaskPropertyInfo> (parameterGroup); } List <string> references = new List <string> (); List <string> namespace_uses = new List <string> (); namespace_uses.Add("Microsoft.Build.Framework"); string type = null, language = null, code = null; var xml = XmlReader.Create(new StringReader(taskBody), new XmlReaderSettings() { ConformanceLevel = ConformanceLevel.Fragment }); for (xml.MoveToContent(); !xml.EOF; xml.MoveToContent()) { switch (xml.NodeType) { case XmlNodeType.Element: switch (xml.LocalName) { case "Reference": references.Add(xml.GetAttribute("Include")); xml.Skip(); break; case "Using": namespace_uses.Add(xml.GetAttribute("Namespace")); xml.Skip(); break; case "Code": // MSB3757: Multiple Code elements have been found, this is not allowed. if (code != null) { throw new InvalidProjectFileException(null, "Multiple Code elements are not allowed", "MSB", "3757", null); } type = xml.GetAttribute("Type"); language = xml.GetAttribute("Language"); code = xml.ReadElementContentAsString(); break; } break; default: xml.Skip(); break; } } if (language == "vb") { throw new NotImplementedException(string.Format("{0} is not supported language for inline task", language)); } if (language != "cs") { throw new InvalidProjectFileException(null, string.Format("{0} is not supported language for inline task", language), "MSB", "4175", null); } string gen = null; // The documentation says "ITask", but the very first example shows "Log" which is not in ITask! It is likely that the generated code uses Task or TaskExtension. string classTemplate = @"public class " + taskName + " : Microsoft.Build.Utilities.Task { @@EXECUTE@@ }"; foreach (var ns in namespace_uses) { gen += "using " + ns + ";\n"; } switch (type) { case "Class": gen += code; break; case "Method": gen += classTemplate.Replace("@@EXECUTE@@", code); break; case "Fragment": gen += classTemplate.Replace("@@EXECUTE@@", "public override bool Execute () { " + code + " return true; }"); break; } var cscParams = new CompilerParameters(); cscParams.ReferencedAssemblies.Add("Microsoft.Build.Framework.dll"); cscParams.ReferencedAssemblies.Add("Microsoft.Build.Utilities.v4.0.dll"); // since we use Task, it depends on this dll. var results = new CSharpCodeProvider().CompileAssemblyFromSource(cscParams, gen); var errors = new CompilerError [results.Errors.Count]; results.Errors.CopyTo(errors, 0); if (errors.Any(e => !e.IsWarning)) { string msg = string.Format("Invalid '{0}' source code of '{1}' type: {2}", language, type, string.Join(" ", errors.Where(e => !e.IsWarning).Select(e => e.ToString()))); throw new InvalidProjectFileException(null, msg, "MSB", "3758", null); } assembly = results.CompiledAssembly; return(true); }
bool Initialize(string taskName, IDictionary <string, string> factoryIdentityParameters, IDictionary <string, TaskPropertyInfo> parameterGroup, string taskBody, IBuildEngine taskFactoryLoggingHost) { task_name = taskName; if (parameterGroup != null) { parameter_group = new Dictionary <string, TaskPropertyInfo> (parameterGroup); } List <string> references = new List <string> (); List <string> namespace_uses = new List <string> (); namespace_uses.Add("Microsoft.Build.Framework"); string type = null, language = null, code = null; var xml = XmlReader.Create(new StringReader(taskBody), new XmlReaderSettings() { ConformanceLevel = ConformanceLevel.Fragment }); for (xml.MoveToContent(); !xml.EOF; xml.MoveToContent()) { switch (xml.NodeType) { case XmlNodeType.Element: switch (xml.LocalName) { case "Reference": references.Add(xml.GetAttribute("Include")); xml.Skip(); break; case "Using": namespace_uses.Add(xml.GetAttribute("Namespace")); xml.Skip(); break; case "Code": // MSB3757: Multiple Code elements have been found, this is not allowed. if (code != null) { throw new InvalidProjectFileException(null, "Multiple Code elements are not allowed", "MSB", "3757", null); } type = xml.GetAttribute("Type"); language = xml.GetAttribute("Language"); code = xml.ReadElementContentAsString(); break; } break; default: xml.Skip(); break; } } if (language != "cs" && language != "vb") { throw new InvalidProjectFileException(null, string.Format("{0} is not supported language for inline task", language), "MSB", "4175", null); } CodeCompileUnit ccu; if (type == "Class") // 'code' contains the whole class that implements the task { ccu = new CodeSnippetCompileUnit(code); } else // 'code' contains parts of the class that implements the task { ccu = new CodeCompileUnit(); var nsp = new CodeNamespace(); nsp.Imports.AddRange(namespace_uses.Select(x => new CodeNamespaceImport(x)).ToArray()); ccu.Namespaces.Add(nsp); var taskClass = new CodeTypeDeclaration { IsClass = true, Name = taskName, TypeAttributes = TypeAttributes.Public }; var parameters = new List <CodeMemberProperty> (); var parametersBackingFields = new List <CodeMemberField> (); // add a public property + backing field for each parameter foreach (var param in parameter_group) { var prop = new CodeMemberProperty { Attributes = MemberAttributes.Public | MemberAttributes.Final, Name = param.Value.Name, Type = new CodeTypeReference(param.Value.PropertyType) }; var propBf = new CodeMemberField { Attributes = MemberAttributes.Private, Name = "_" + prop.Name, Type = prop.Type }; // add getter and setter to the property prop.GetStatements.Add(new CodeMethodReturnStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), propBf.Name))); prop.SetStatements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), propBf.Name), new CodePropertySetValueReferenceExpression())); parameters.Add(prop); parametersBackingFields.Add(propBf); } taskClass.Members.AddRange(parameters.ToArray()); taskClass.Members.AddRange(parametersBackingFields.ToArray()); taskClass.BaseTypes.Add("Microsoft.Build.Utilities.Task"); // The documentation says "ITask", but the very first example shows "Log" which is not in ITask! It is likely that the generated code uses Task or TaskExtension. if (type == "Method") // 'code' contains the 'Execute' method directly { taskClass.Members.Add(new CodeSnippetTypeMember(code)); } else if (type == "Fragment") // 'code' contains the body of the 'Execute' method { var method = new CodeMemberMethod { Attributes = MemberAttributes.Public | MemberAttributes.Override, Name = "Execute", ReturnType = new CodeTypeReference(typeof(bool)) }; // add the code and a 'return true' at the end of the method method.Statements.Add(new CodeSnippetStatement(code)); method.Statements.Add(new CodeMethodReturnStatement(new CodePrimitiveExpression(true))); taskClass.Members.Add(method); } else { throw new ArgumentException("Invalid type: " + type); } nsp.Types.Add(taskClass); } var cscParams = new CompilerParameters(); cscParams.ReferencedAssemblies.Add("Microsoft.Build.Framework.dll"); cscParams.ReferencedAssemblies.Add("Microsoft.Build.Utilities.v4.0.dll"); // since we use Task, it depends on this dll. cscParams.ReferencedAssemblies.AddRange(GetReferences(references, taskFactoryLoggingHost)); cscParams.GenerateInMemory = true; var results = CodeDomProvider.CreateProvider(language).CompileAssemblyFromDom(cscParams, ccu); var errors = new CompilerError [results.Errors.Count]; results.Errors.CopyTo(errors, 0); if (errors.Any(e => !e.IsWarning)) { string msg = string.Format("Invalid '{0}' source code of '{1}' type: {2}", language, type, string.Join(" ", errors.Where(e => !e.IsWarning).Select(e => e.ToString()))); throw new InvalidProjectFileException(null, msg, "MSB", "3758", null); } assembly = results.CompiledAssembly; return(true); }
bool Initialize (string taskName, IDictionary<string, string> factoryIdentityParameters, IDictionary<string, TaskPropertyInfo> parameterGroup, string taskBody, IBuildEngine taskFactoryLoggingHost) { task_name = taskName; if (parameterGroup != null) parameter_group = new Dictionary<string, TaskPropertyInfo> (parameterGroup); List<string> references = new List<string> (); List<string> namespace_uses = new List<string> (); namespace_uses.Add ("Microsoft.Build.Framework"); string type = null, language = null, code = null; var xml = XmlReader.Create (new StringReader (taskBody), new XmlReaderSettings () { ConformanceLevel = ConformanceLevel.Fragment }); for (xml.MoveToContent (); !xml.EOF; xml.MoveToContent ()) { switch (xml.NodeType) { case XmlNodeType.Element: switch (xml.LocalName) { case "Reference": references.Add (xml.GetAttribute ("Include")); xml.Skip (); break; case "Using": namespace_uses.Add (xml.GetAttribute ("Namespace")); xml.Skip (); break; case "Code": // MSB3757: Multiple Code elements have been found, this is not allowed. if (code != null) throw new InvalidProjectFileException (null, "Multiple Code elements are not allowed", "MSB", "3757", null); type = xml.GetAttribute ("Type"); language = xml.GetAttribute ("Language"); code = xml.ReadElementContentAsString (); break; } break; default: xml.Skip (); break; } } if (language != "cs" && language != "vb") throw new InvalidProjectFileException (null, string.Format ("{0} is not supported language for inline task", language), "MSB", "4175", null); CodeCompileUnit ccu; if (type == "Class") { // 'code' contains the whole class that implements the task ccu = new CodeSnippetCompileUnit (code); } else { // 'code' contains parts of the class that implements the task ccu = new CodeCompileUnit (); var nsp = new CodeNamespace (); nsp.Imports.AddRange (namespace_uses.Select (x => new CodeNamespaceImport (x)).ToArray ()); ccu.Namespaces.Add (nsp); var taskClass = new CodeTypeDeclaration { IsClass = true, Name = taskName, TypeAttributes = TypeAttributes.Public }; var parameters = new List<CodeMemberProperty> (); var parametersBackingFields = new List<CodeMemberField> (); // add a public property + backing field for each parameter foreach (var param in parameter_group) { var prop = new CodeMemberProperty { Attributes = MemberAttributes.Public | MemberAttributes.Final, Name = param.Value.Name, Type = new CodeTypeReference (param.Value.PropertyType) }; var propBf = new CodeMemberField { Attributes = MemberAttributes.Private, Name = "_" + prop.Name, Type = prop.Type }; // add getter and setter to the property prop.GetStatements.Add (new CodeMethodReturnStatement (new CodeFieldReferenceExpression (new CodeThisReferenceExpression (), propBf.Name))); prop.SetStatements.Add (new CodeAssignStatement (new CodeFieldReferenceExpression (new CodeThisReferenceExpression (), propBf.Name), new CodePropertySetValueReferenceExpression ())); parameters.Add (prop); parametersBackingFields.Add (propBf); } taskClass.Members.AddRange (parameters.ToArray ()); taskClass.Members.AddRange (parametersBackingFields.ToArray ()); taskClass.BaseTypes.Add ("Microsoft.Build.Utilities.Task"); // The documentation says "ITask", but the very first example shows "Log" which is not in ITask! It is likely that the generated code uses Task or TaskExtension. if (type == "Method") { // 'code' contains the 'Execute' method directly taskClass.Members.Add (new CodeSnippetTypeMember (code)); } else if (type == "Fragment") { // 'code' contains the body of the 'Execute' method var method = new CodeMemberMethod { Attributes = MemberAttributes.Public | MemberAttributes.Override, Name = "Execute", ReturnType = new CodeTypeReference (typeof (bool)) }; // add the code and a 'return true' at the end of the method method.Statements.Add (new CodeSnippetStatement (code)); method.Statements.Add (new CodeMethodReturnStatement (new CodePrimitiveExpression (true))); taskClass.Members.Add (method); } else { throw new ArgumentException ("Invalid type: " + type); } nsp.Types.Add (taskClass); } var cscParams = new CompilerParameters (); cscParams.ReferencedAssemblies.Add ("Microsoft.Build.Framework.dll"); cscParams.ReferencedAssemblies.Add ("Microsoft.Build.Utilities.v4.0.dll"); // since we use Task, it depends on this dll. cscParams.ReferencedAssemblies.AddRange (GetReferences (references, taskFactoryLoggingHost)); cscParams.GenerateInMemory = true; var results = CodeDomProvider.CreateProvider (language).CompileAssemblyFromDom (cscParams, ccu); var errors = new CompilerError [results.Errors.Count]; results.Errors.CopyTo (errors, 0); if (errors.Any (e => !e.IsWarning)) { string msg = string.Format ("Invalid '{0}' source code of '{1}' type: {2}", language, type, string.Join (" ", errors.Where (e => !e.IsWarning).Select (e => e.ToString ()))); throw new InvalidProjectFileException (null, msg, "MSB", "3758", null); } assembly = results.CompiledAssembly; return true; }