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
  //
  // Clayton Harbour (claytonharbour@sporadicism.com)
  // Marcin Hoppe (marcin.hoppe@gmail.com)
  
  using System;
  using System.Diagnostics;
  using System.IO;
  using System.Text;
  
  using NAnt.Core;
  using NAnt.Core.Attributes;
  using NAnt.Core.Tasks;
  using NAnt.Core.Types;
  using NAnt.Core.Util;
  
  using NAnt.SourceControl.Tasks;
  
  namespace NAnt.Contrib.Tasks.Svn {
      /// <summary>
      /// A base class for creating tasks for executing CVS client commands on a 
      /// CVS repository.
      /// </summary>
      public abstract class AbstractSvnTask : AbstractSourceControlTask {
          #region Protected Static Fields
  
          /// <summary>
          /// An environment variable that holds path information about where
          /// svn is located.
          /// </summary>
          protected const string SVN_HOME = "SVN_HOME";
  
          /// <summary>
          /// The prefix used for command arguments.
          /// </summary>
          protected const string ARG_PREFIX = "--";
  
          /// <summary>
          /// Name of the password file that is used to cash password settings.
          /// </summary>
          protected static readonly String SVN_PASSFILE = 
              Path.Combine(".subversion", "auth");
  
          /// <summary>
          /// The name of the svn executable.
          /// </summary>
          protected const string SVN_EXE = "svn.exe";
  
          /// <summary>
          /// Environment variable that holds the executable name that is used for
          /// ssh communication.
          /// </summary>
          protected const string SVN_RSH = "RSH";
  
          #endregion Protected Static Fields
  
          #region Protected Instance Constructors
  
          /// <summary>
          /// Initializes a new instance of the <see cref="AbstractSvnTask" /> 
          /// class.
          /// </summary>
          protected AbstractSvnTask () : base() {
              SetPropertiesDefaults();
          }
  
          #endregion Protected Instance Constructors
  
          #region Protected Instance Properties
  
          /// <summary>
          /// The name of the executable.
          /// </summary>
          protected override string VcsExeName {
              get { return SVN_EXE; }
          }
  
          /// <summary>
          /// The name of the password file.
          /// </summary>
          protected override string PassFileName {
              get { return SVN_PASSFILE; }
          }
  
          /// <summary>
          /// Name of the home environment variable.
          /// </summary>
          protected override string VcsHomeEnv {
              get { return SVN_HOME; }
          }
  
          /// <summary>
          /// The name of the ssh/ rsh environment variable.
          /// </summary>
          protected override string SshEnv {
              get { return SVN_RSH; }
          }
  
          #endregion Protected Instance Properties
  
          #region Public Instance Properties
  
          /// <summary>
          /// The full path of the svn executable.
          /// </summary>
          public override string ExeName {
              get { return GetSvnExePath(); }
          }
  
          /// <summary>
          /// <para>
          /// TODO: Add more documentation when I understand all svn root possibilities/
          /// protocols.
          /// The svn root is usually in the form of a URL from which the server, protocol
          /// and path information can be derived.  Although the path to the repository
          /// can also be determined from this the information is more implicit
          /// than explicit.  For example a subversion root URL of:
          ///
          /// http://svn.collab.net/repos/svn/trunk/doc/book/tools
          ///
          /// would have the following components:
          ///     protocol:       http/ web_dav
          ///     username:       anonymous
          ///     servername:     svn.collab.net
          ///     repository:     /repos/svn
          ///     server path:    /trunk/doc/book/tools
          ///     
          ///     In addition the revision path or branch can also be determined as
          ///     subversion stores this information as a seperate physical directory.
          ///     In this example:
          ///     
          ///     revision: trunk
          /// </para>
          /// </summary>
          [TaskAttribute("uri", Required=true)]
          [StringValidator(AllowEmpty=false)]
          public override string Root {
              get { return base.Root; }
              set { base.Root = StringUtils.ConvertEmptyToNull(value); }
          }
  
          /// <summary>
          /// The user performing the checkout.
          /// </summary>
          [TaskAttribute("username", Required=false)]
          public string UserName {
              get {return ((Option)this.CommandOptions["username"]).Value;}
              set {this.SetCommandOption("username", 
                       String.Format("username={0}", value), true);}
          }
  
          /// <summary>
          /// The pasword to use to login to svn.
          /// </summary>
          [TaskAttribute("password", Required=false)]
          public new string Password {
              get {return ((Option)this.CommandOptions["password"]).Value;}
              set {this.SetCommandOption("password", String.Format("password={0}", value), true);}
          }
  
          /// <summary>
          /// Indicates whether the task should be interactive or not.  This is
          /// set to <see langword="false" /> by default, and I don't see a reason
          /// to expose this to the NAnt task.
          /// </summary>
          public bool Interactive {
              get {return ((Option)this.CommandOptions["interactive"]).IfDefined;}
              set {this.SetCommandOption("interactive", "non-interactive", !value);}
          }
  
          /// <summary>
          /// The executable to use for ssh communication.
          /// </summary>
          [TaskAttribute("rsh", Required=false)]
          public override FileInfo Ssh {
              get { return base.Ssh; }
              set { base.Ssh = value; }
          }
  
          /// <summary>
          /// The command to execute.
          /// </summary>
          [TaskAttribute("command", Required=false)]
          public override string CommandName {
              get { return base.CommandName; }
              set { base.CommandName = value; }
          }
  
          /// <summary>
          /// Specifies whether to print as little information as possible.
          /// The default is <see langword="false" />.
          /// </summary>
          [TaskAttribute("quiet", Required=false)]
   		[BooleanValidator()]
          public bool Quiet {
              get {
                  Option option = (Option) this.CommandOptions["quiet"];
                  if (option != null && option.IfDefined) {
                      return true;
                  }
                  return false;
              }
              set {
                  if (value) {
                      this.SetCommandOption("quiet", "quiet", value);
                  } else {
                      this.CommandOptions.Remove("quiet");
                  }
              }
          }
  
          #endregion Public Instance Properties
  
          #region Override implementation of ExternalProgramBase
  
          /// <summary>
          /// Build up the command line arguments, determine which executable is being
          /// used and find the path to that executable and set the working 
          /// directory.
          /// </summary>
          /// <param name="process">The process to prepare.</param>
          protected override void PrepareProcess (Process process) {
              Log(Level.Verbose, "Command name: {0}", this.CommandName);
              if (null == this.Arguments || 0 == this.Arguments.Count) {
                  this.AppendGlobalOptions();
                  this.Arguments.Add(new Argument(this.CommandName));
  
gt:                 if (IsRootUsed) {