// SharpDevelop samples
// Copyright (c) 2007, AlphaSierraPapa
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// - Redistributions of source code must retain the above copyright notice, this list
// of conditions and the following disclaimer.
//
// - Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other materials
// provided with the distribution.
//
// - Neither the name of the SharpDevelop team nor the names of its contributors may be used to
// endorse or promote products derived from this software without specific prior written
// permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS &AS IS& AND ANY EXPRESS
// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
using System;
using System.IO;
using System.Xml;
namespace ICSharpCode.NAnt
{
///
/// Represents a NAnt Build File.
///
public class NAntBuildFile
{
///
/// Standard NAnt build file's extension.
///
public static readonly string BuildFileNameExtension = ".build";
///
/// Standard NAnt include file's extension.
///
public static readonly string IncludeFileNameExtension = ".include";
static readonly string TargetElementName = "target";
static readonly string ProjectElementName = "project";
static readonly string NameAttributeName = "name";
static readonly string DefaultAttributeName = "default";
string directory = String.Empty;
string fileName = String.Empty;
string name = String.Empty;
string defaultTargetName = String.Empty;
NAntBuildFileError buildFileError;
NAntBuildTargetCollection targets = new NAntBuildTargetCollection();
NAntBuildTarget defaultTarget;
enum ParseState
{
Nothing = 0,
WaitingForProjectName = 1,
WaitingForTargetName = 2
}
///
/// Creates a new instance of the
/// class.
///
/// The build filename.
public NAntBuildFile(string fileName)
{
this.directory = Path.GetDirectoryName(fileName);
this.fileName = Path.GetFileName(fileName);
ReadBuildFile(fileName);
}
///
/// Creates a new instance of the
/// class.
///
/// The used to
/// feed the XML data into the
/// object.
public NAntBuildFile(TextReader reader)
{
ParseBuildFile(reader);
}
///
/// Gets or sets the filename without the path information.
///
public string FileName {
get {
return fileName;
}
set {
fileName = value;
}
}
///
/// Gets the build file's path information.
///
public string Directory {
get {
return directory;
}
}
///
/// Gets the project name.
///
public string Name {
get {
return name;
}
}
///
/// Checks the build file is a NAnt build file.
///
public static bool IsBuildFile(string fileName)
{
bool isBuildFile = false;
string extension = Path.GetExtension(fileName);
if (String.Compare(extension, BuildFileNameExtension, true) == 0) {
isBuildFile = true;
} else if (String.Compare(extension, IncludeFileNameExtension, true) == 0) {
isBuildFile = true;
}
return isBuildFile;
}
///
/// Gets the NAnt build targets.
///
public NAntBuildTargetCollection Targets {
get {
return targets;
}
}
///
/// Gets the default NAnt target.
///
public NAntBuildTarget DefaultTarget {
get {
return defaultTarget;
}
}
///
/// Gets whether there is an error with this build file.
///
public bool HasError {
get {
return (buildFileError != null);
}
}
///
/// Gets the error associated with the build file.
///
public NAntBuildFileError Error {
get {
return buildFileError;
}
}
///
/// Reads the NAnt build file and extracts target names.
///
/// The name of the build file.
void ReadBuildFile(string fileName)
{
StreamReader reader = new StreamReader(fileName, true);
ParseBuildFile(reader);
}
///
/// Gets the default target's name or returns an empty string.
///
/// The root node of the build file.
/// The default target's name or an empty string if
/// it does not exist.
string GetDefaultTargetName(XmlElement root)
{
string defaultTargetName = String.Empty;
XmlAttribute nameAttribute = root.Attributes["default"];
if (nameAttribute != null) {
defaultTargetName = nameAttribute.Value;
}
return defaultTargetName;
}
///
/// Gets the build file's project name or returns an empty string.
///
/// The root node of the build file.
/// The project name or an empty string if
/// it does not exist.
string GetProjectName(XmlElement root)
{
string projectName = String.Empty;
XmlAttribute nameAttribute = root.Attributes["name"];
if (nameAttribute != null) {
projectName = nameAttribute.Value;
}
return projectName;
}
///
/// Tests whether matches the
/// default target name.
///
/// The default target
/// name.
/// A target's name.
/// if the target name matches
/// the default; otherwise .
bool IsDefaultTargetName(string defaultTargetName, string targetName)
{
bool isDefault = false;
if (defaultTargetName.Length > 0) {
if (String.Compare(defaultTargetName, targetName, true) == 0) {
isDefault = true;
}
}
return isDefault;
}
///
/// Parse the NAnt build file.
///
/// A TextReader from which to read
/// the build file.
void ParseBuildFile(TextReader textReader)
{
XmlTextReader xmlReader = new XmlTextReader(textReader);
try
{
ParseState state = ParseState.WaitingForProjectName;
while(xmlReader.Read())
{
if (state == ParseState.WaitingForProjectName) {
if (IsProjectElement(xmlReader)) {
ParseProjectElement(xmlReader);
state = ParseState.WaitingForTargetName;
}
} else {
if (IsTargetElement(xmlReader)) {
ParseTargetElement(xmlReader);
}
}
}
} catch(XmlException ex) {
buildFileError = new NAntBuildFileError(ex.Message, ex.LineNumber, ex.LinePosition);
} finally {
xmlReader.Close();
}
}
///
/// Parses the current XmlTextReader node if it
/// is the NAnt Project element.
///
/// An XmlTextReader currently being
/// read.
void ParseProjectElement(XmlTextReader xmlReader)
{
name = GetAttribute(xmlReader, NameAttributeName);
defaultTargetName = GetAttribute(xmlReader, DefaultAttributeName);
}
///
/// Tests whether the current element is the project element.
///
///
/// if the current
/// element is the project element;
/// otherwise
bool IsProjectElement(XmlTextReader xmlReader)
{
bool isProjectElement = false;
if (xmlReader.NodeType == XmlNodeType.Element) {
if (xmlReader.Name == ProjectElementName) {
isProjectElement = true;
}
}
return isProjectElement;
}
///
/// Tests whether the current element is a target element.
///
/// An xml text reader currently
/// reading the build file xml.
/// if the current
/// element is a target element;
/// otherwise
bool IsTargetElement(XmlTextReader xmlReader)
{
bool isTargetElement = false;
if (xmlReader.NodeType == XmlNodeType.Element) {
if (xmlReader.Name == TargetElementName) {
isTargetElement = true;
}
}
return isTargetElement;
}
///
/// Parses the current XmlTextReader node if it
/// is the NAnt Target element.
///
void ParseTargetElement(XmlTextReader xmlReader)
{
int line = xmlReader.LineNumber;
int col = xmlReader.LinePosition;
string targetName = GetAttribute(xmlReader, NameAttributeName);
bool isDefaultTarget = IsDefaultTargetName(defaultTargetName, targetName);
NAntBuildTarget target =
new NAntBuildTarget(targetName, isDefaultTarget, line, col);
targets.Add(target);
if (isDefaultTarget) {
defaultTarget = target;
}
}
///
/// Gets the named attribute's value.
///
/// The attribute's value or an empty string if
/// it was not found.
///
string GetAttribute(XmlTextReader xmlReader, string name)
{
string attributeValue = String.Empty;
if (xmlReader.MoveToAttribute(name)) {
if (xmlReader.Value != null) {
attributeValue = xmlReader.Value;
}
}
return attributeValue;
}
}
}