// NAnt - A .NET build tool // Copyright (C) 2001 Gerry Shaw // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // Gerry Shaw (gerry_shaw@yahoo.com) // Mike Krueger (mike@icsharpcode.net) // Ian MacLean (ian_maclean@another.com) namespace SourceForge.NAnt { using System; using System.Reflection; using System.Xml; public abstract class Task { /// Gets and sets how much spacing log prefix names will be padded. /// /// Includes characters for a space after the name and the [ ] brackets. Default is 12. /// public static int LogPrefixPadding = Log.IndentSize; Location _location = Location.UnknownLocation; Target _target = null; Project _project = null; /// /// Location in build file where task is defined. /// protected Location Location { get { return _location; } set { _location = value; } } public string Name { get { string name = null; TaskNameAttribute taskName = (TaskNameAttribute) Attribute.GetCustomAttribute(GetType(), typeof(TaskNameAttribute)); if (taskName != null) { name = taskName.Name; } return name; } } public string LogPrefix { get { string prefix = "[" + Name + "] "; return prefix.PadLeft(LogPrefixPadding); } } public Target Target { get { return _target; } set { _target = value; } } public Project Project { get { return _project; } set { _project = value; } } protected void AutoInitializeAttributes(XmlNode taskNode) { // TODO: BooleanValidatorAttribute and Int32ValidatorAttribute implementation in Task // Go down the inheritance tree to find the private fields in the object. // We are looking for task attributes to initialize. Type currentType = GetType(); while (currentType != typeof(object)) { FieldInfo[] fieldInfoArray = currentType.GetFields(BindingFlags.NonPublic|BindingFlags.Instance); foreach (FieldInfo fieldInfo in fieldInfoArray) { // process TaskAttribute attributes TaskAttributeAttribute taskAttribute = (TaskAttributeAttribute) Attribute.GetCustomAttribute(fieldInfo, typeof(TaskAttributeAttribute)); if (taskAttribute != null) { // get value from xml file XmlNode node = taskNode.SelectSingleNode("@" + taskAttribute.Name); // check if its required if (node == null && taskAttribute.Required) { // TODO: add Location to exception throw new BuildException(String.Format("{0} is a required attribute.", taskAttribute.Name), Location); } if (node != null) { fieldInfo.SetValue(this, Convert.ChangeType(node.Value, fieldInfo.FieldType)); } } // process TaskFileSet attributes TaskFileSetAttribute fileSetAttribute = (TaskFileSetAttribute) Attribute.GetCustomAttribute(fieldInfo, typeof(TaskFileSetAttribute)); if (fileSetAttribute != null) { // have file set initialize itself FileSet fileSet = (FileSet) fieldInfo.GetValue(this); // set task fileset belongs to fileSet.Task = this; // load values from build file XmlNode fileSetNode = taskNode.SelectSingleNode(fileSetAttribute.Name); if (fileSetNode != null) { XmlNode baseDirectoryNode = fileSetNode.SelectSingleNode("@basedir"); if (baseDirectoryNode != null) { fileSet.BaseDirectory = baseDirectoryNode.Value; } foreach (XmlNode node in fileSetNode.SelectNodes("includes")) { string pathname = node.SelectSingleNode("@name").Value; fileSet.Includes.Add(pathname); } foreach (XmlNode node in fileSetNode.SelectNodes("excludes")) { fileSet.Excludes.Add(node.SelectSingleNode("@name").Value); } } } } currentType = currentType.BaseType; } } protected void AutoExpandAttributes() { // Go down the inheritance tree to find the private fields in the object. // We are looking for task attributes to initialize. Type currentType = GetType(); while (currentType != typeof(object)) { FieldInfo[] fieldInfoArray = currentType.GetFields(BindingFlags.NonPublic|BindingFlags.Instance); foreach (FieldInfo fieldInfo in fieldInfoArray) { // proces string parameters TaskAttributeAttribute taskAttribute = (TaskAttributeAttribute) Attribute.GetCustomAttribute(fieldInfo, typeof(TaskAttributeAttribute)); if (taskAttribute != null) { if (taskAttribute.ExpandText) { string value = (string) fieldInfo.GetValue(this); value = Project.ExpandText(value); fieldInfo.SetValue(this, value); } // if a field also has a validator attribute then ensure that value is correct ValidatorAttribute[] validators = (ValidatorAttribute[]) Attribute.GetCustomAttributes(fieldInfo, typeof(ValidatorAttribute)); foreach (ValidatorAttribute validator in validators) { string errorMessage = validator.Validate(fieldInfo.GetValue(this)); if (errorMessage != null) { throw new BuildException(String.Format("Error processing '{0}' attribute in <{1}> task: {2}", taskAttribute.Name, Name, errorMessage), Location); } } } } currentType = currentType.BaseType; } } public void Initialize(XmlNode taskNode) { Initialize(taskNode, null); } public void Initialize(XmlNode taskNode, Location location) { if (location != null) { _location = location; } AutoInitializeAttributes(taskNode); InitializeTask(taskNode); } public void Execute() { AutoExpandAttributes(); ExecuteTask(); } protected virtual void InitializeTask(XmlNode taskNode) { } protected abstract void ExecuteTask(); } }