context: // NAnt - A .NET build tool
  // Copyright (C) 2001-2003 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)
  // Ian MacLean (imaclean@gmail.com)
  // Scott Hernandez (ScottHernandez@hotmail.com)
  // William E. Caputo (wecaputo@thoughtworks.com | logosity@yahoo.com)
  
  using System;
  using System.Collections;
  using System.Collections.Specialized;
  using System.ComponentModel;
  using System.Configuration;
  using System.Globalization;
  using System.IO;
  using System.Reflection;
  using System.Text;
  using System.Xml;
  
  using Microsoft.Win32;
  
  using NAnt.Core.Tasks;
  using NAnt.Core.Util;
  
  namespace NAnt.Core {
      /// <summary>
      /// Central representation of a NAnt project.
      /// </summary>
      /// <example>
      ///   <para>
      ///   The <see cref="Run" /> method will initialize the project with the build
      ///   file specified in the constructor and execute the default target.
      ///   </para>
      ///   <code>
      ///     <![CDATA[
      /// Project p = new Project("foo.build", Level.Info);
      /// p.Run();
      ///     ]]>
      ///   </code>
      /// </example>
      /// <example>
      ///   <para>
      ///   If no target is given, the default target will be executed if specified 
      ///   in the project.
      ///   </para>
      ///   <code>
      ///     <![CDATA[
      /// Project p = new Project("foo.build", Level.Info);
      /// p.Execute("build");
      ///     ]]>
      ///   </code>
      /// </example>
      [Serializable()]
      public class Project {
          #region Private Static Fields
  
          /// <summary>
          /// Holds the logger for this class.
          /// </summary>
          private static readonly log4net.ILog logger = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
  
          // XML element and attribute names that are not defined in metadata
          private const string RootXml = "project";
          private const string ProjectNameAttribute = "name";
          private const string ProjectDefaultAttribte = "default";
          private const string ProjectBaseDirAttribute = "basedir";
          private const string TargetXml = "target";
          private const string WildTarget = "*";
  
          /// <summary>
          /// Constant for the "visiting" state, used when traversing a DFS of 
          /// target dependencies.
          /// </summary>
          private const string Visiting = "VISITING";
  
          /// <summary>
          /// Constant for the "visited" state, used when traversing a DFS of 
          /// target dependencies.
          /// </summary>
          private const string Visited = "VISITED";
  
          #endregion Private Static Fields
  
          #region Internal Static Fields
  
          // named properties
          internal const string NAntPlatform = "nant.platform";
          internal const string NAntPlatformName = NAntPlatform + ".name";
          internal const string NAntPropertyFileName = "nant.filename";
          internal const string NAntPropertyVersion = "nant.version";
          internal const string NAntPropertyLocation = "nant.location";
          internal const string NAntPropertyProjectName = "nant.project.name";
          internal const string NAntPropertyProjectBuildFile = "nant.project.buildfile";
          internal const string NAntPropertyProjectBaseDir = "nant.project.basedir";
          internal const string NAntPropertyProjectDefault = "nant.project.default";
          internal const string NAntPropertyOnSuccess = "nant.onsuccess";
          internal const string NAntPropertyOnFailure = "nant.onfailure";
  
          #endregion Internal Static Fields
  
          #region Public Instance Events
  
          public event BuildEventHandler BuildStarted;
          public event BuildEventHandler BuildFinished;
          public event BuildEventHandler TargetStarted;
          public event BuildEventHandler TargetFinished;
          public event BuildEventHandler TaskStarted;
          public event BuildEventHandler TaskFinished;
          public event BuildEventHandler MessageLogged;
  
          #endregion Public Instance Events
  
          #region Private Instance Fields
  
          private string _baseDirectory;
          private string _projectName = "";
          private string _defaultTargetName;
          private int _indentationSize = 4;
          private int _indentationLevel = 0;
          private BuildListenerCollection _buildListeners = new BuildListenerCollection();
          private StringCollection _buildTargets = new StringCollection();
          private TargetCollection _targets = new TargetCollection();
          private LocationMap _locationMap = new LocationMap();
          private PropertyDictionary _properties;
          private PropertyDictionary _frameworkNeutralProperties;
          private Target _currentTarget;
  
          // info about frameworks
          private FrameworkInfoDictionary _frameworks = new FrameworkInfoDictionary();
          private FrameworkInfo _runtimeFramework;
          private FrameworkInfo _targetFramework;
  
          [NonSerialized()]
          private XmlNode _configurationNode;
          [NonSerialized()]
          private XmlDocument _doc; // set in ctorHelper
          [NonSerialized()]
          private XmlNamespaceManager _nsMgr = new XmlNamespaceManager(new NameTable()); //used to map "nant" to default namespace.
          [NonSerialized()]
          private DataTypeBaseDictionary _dataTypeReferences = new DataTypeBaseDictionary();
  
          /// <summary>
          /// Holds the default threshold for build loggers.
          /// </summary>
          private Level _threshold = Level.Info;
  
          #endregion Private Instance Fields
  
          #region Public Instance Constructors
  
          /// <summary>
          /// Initializes a new <see cref="Project" /> class with the given 
          /// document, message threshold and indentation level.
          /// </summary>
          /// <param name="doc">Any valid build format will do.</param>
          /// <param name="threshold">The message threshold.</param>
          /// <param name="indentLevel">The project indentation level.</param>
          public Project(XmlDocument doc, Level threshold, int indentLevel) {
              // use NAnt settings from application configuration file for loading 
              // internal configuration settings
              _configurationNode = GetConfigurationNode();
  
              // initialize project
              CtorHelper(doc, threshold, indentLevel, Optimizations.None);
          }
  
          /// <summary>
          /// Initializes a new <see cref="Project" /> class with the given 
          /// document, message threshold and indentation level, and using 
          /// the specified <see cref="XmlNode" /> to load internal configuration
          /// settings.
          /// </summary>
          /// <param name="doc">Any valid build format will do.</param>
          /// <param name="threshold">The message threshold.</param>
          /// <param name="indentLevel">The project indentation level.</param>
          /// <param name="configurationNode">The <see cref="XmlNode" /> NAnt should use to initialize configuration settings.</param>
          /// <remarks>
          /// This constructor is useful for developers using NAnt as a class
          /// library.
          /// </remarks>
          public Project(XmlDocument doc, Level threshold, int indentLevel, XmlNode configurationNode) {
              // set configuration node to use for loading internal configuration 
              // settings
              _configurationNode = configurationNode;
  
              // initialize project
              CtorHelper(doc, threshold, indentLevel, Optimizations.None);
          }
  
          /// <summary>
          /// Initializes a new <see cref="Project" /> class with the given 
          /// source, message threshold and indentation level.
          /// </summary>
          /// <param name="uriOrFilePath">
          /// <para>The full path to the build file.</para>
          /// <para>This can be of any form that <see cref="M:XmlDocument.Load(string)" /> accepts.</para>
          /// </param>
          /// <param name="threshold">The message threshold.</param>
          /// <param name="indentLevel">The project indentation level.</param>
          /// <remarks>
          /// If the source is a uri of form 'file:///path' then use the path part.
          /// </remarks>
          public Project(string uriOrFilePath, Level threshold, int indentLevel) {
              // use NAnt settings from application configuration file for loading 
              // internal configuration settings
              _configurationNode = GetConfigurationNode();
  
              // initialize project
              CtorHelper(LoadBuildFile(uriOrFilePath), threshold, indentLevel,
                  Optimizations.None);
          }
  
          /// <summary>
          /// Initializes a new <see cref="Project" /> class with the given 
          /// source, message threshold and indentation level, and using 
          /// the specified <see cref="XmlNode" /> to load internal configuration
          /// settings.
          /// </summary>
          /// <param name="uriOrFilePath">
          /// <para>The full path to the build file.</para>
          /// <para>This can be of any form that <see cref="M:XmlDocument.Load(string)" /> accepts.</para>
          /// </param>
          /// <param name="threshold">The message threshold.</param>
          /// <param name="indentLevel">The project indentation level.</param>
          /// <param name="configurationNode">The <see cref="XmlNode" /> NAnt should use to initialize configuration settings.</param>
          /// <exception cref="ArgumentNullException"><paramref name="configurationNode" /> is <see langword="null" />.</exception>
          /// <remarks>
          /// If the source is a uri of form 'file:///path' then use the path part.
          /// </remarks>
          public Project(string uriOrFilePath, Level threshold, int indentLevel, XmlNode configurationNode) {
              // set configuration node to use for loading internal configuration 
              // settings
              _configurationNode = configurationNode;
  
              // initialize project
              CtorHelper(LoadBuildFile(uriOrFilePath), threshold, indentLevel,
                  Optimizations.None);
          }
  
          #endregion Public Instance Constructors
  
          #region Internal Instance Constructors
  
          /// <summary>
          /// Initializes a <see cref="Project" /> as subproject of the specified
          /// <see cref="Project" />.
          /// </summary>
          /// <param name="uriOrFilePath">
          /// <para>The full path to the build file.</para>
          /// <para>This can be of any form that <see cref="M:XmlDocument.Load(string)" /> accepts.</para>
          /// </param>
          /// <param name="parent">The parent <see cref="Project" />.</param>
          /// <remarks>
          /// Optimized for framework initialization projects, by skipping automatic
          /// discovery of extension assemblies and framework configuration.
          /// </remarks>
          internal Project(string uriOrFilePath, Project parent) {
              // set configuration node to use for loading internal configuration 
              // settings
              _configurationNode = parent.ConfigurationNode;
  
              // initialize project
              CtorHelper(LoadBuildFile(uriOrFilePath), parent.Threshold, 
                  parent.IndentationLevel + 1, Optimizations.SkipFrameworkConfiguration);
  
              // add listeners of current project to new project
              AttachBuildListeners(parent.BuildListeners);
  
              // inherit discovered frameworks from current project
              foreach (FrameworkInfo framework in parent.Frameworks) {
                  Frameworks.Add(framework.Name, framework);
              }
  
              // have the new project inherit the runtime framework from the 
              // current project
              RuntimeFramework = parent.RuntimeFramework;
  
              // have the new project inherit the current framework from the 
              // current project 
              TargetFramework = parent.TargetFramework;
          }
  
          /// <summary>
          /// Initializes a <see cref="Project" /> with <see cref="Threshold" />
          /// set to <see cref="Level.None" />, and <see cref="IndentationLevel" />
          /// set to 0.
          /// </summary>
          /// <param name="doc">An <see cref="XmlDocument" /> containing the build script.</param>
          /// <remarks>
          /// Optimized for framework initialization projects, by skipping automatic
          /// discovery of extension assemblies and framework configuration.
          /// </remarks>
          internal Project(XmlDocument doc) {
              // initialize project
              CtorHelper(doc, Level.None, 0, Optimizations.SkipAutomaticDiscovery |
                  Optimizations.SkipFrameworkConfiguration);
          }
      
          #endregion Internal Instance Constructors
  
          #region Public Instance Properties
  
          /// <summary>
          /// Gets or sets the indendation level of the build output.
          /// </summary>
          /// <value>
          /// The indentation level of the build output.
          /// </value>
          /// <remarks>
          /// To change the <see cref="IndentationLevel" />, the <see cref="Indent()" /> 
          /// and <see cref="Unindent()" /> methods should be used.
          /// </remarks>
          public int IndentationLevel {
  
gt:             get { return _indentationLevel; }