// 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
//
// Ian MacLean (imaclean@gmail.com)
using System;
using System.Globalization;
using System.IO;
using System.Runtime.InteropServices;
using System.Xml;
using NAnt.Core.Attributes;
using NAnt.Core.Types;
using NAnt.Core.Util;
namespace NAnt.Core.Tasks {
///
/// Sets an environment variable or a whole collection of them. Use an empty
/// attribute to clear a variable.
///
///
///
/// Variables will be set for the current NAnt process and all child
/// processes that NAnt spawns (compilers, shell tools, etc). If the
/// intention is to only set a variable for a single child process, then
/// using the and its nested
/// element might be a better option.
///
///
/// Expansion of inline environment variables is performed using the syntax
/// of the current platform. So on Windows platforms using the string %PATH%
/// in the attribute will result in the value of
/// the PATH variable being expanded in place before the variable is set.
///
///
///
/// Set the MONO_PATH environment variable on a *nix platform.
///
///
/// ]]>
///
///
///
/// Set a collection of environment variables. Note the nested variable used to set var3.
///
///
///
///
///
///
/// ]]>
///
///
///
/// Set environment variables using nested path elements.
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
/// ]]>
///
///
[TaskName("setenv")]
public class SetEnvTask : Task {
#region Private Instance Fields
private string _name;
private string _value;
private string _literalValue;
private FileInfo _file;
private DirectoryInfo _directory;
private PathSet _path;
private EnvironmentVariableCollection _environmentVariables = new EnvironmentVariableCollection();
#endregion Private Instance Fields
#region Public Instance Properties
///
/// The name of a single Environment variable to set
///
[TaskAttribute("name", Required=false)]
public string EnvName {
get { return _name; }
set { _name = StringUtils.ConvertEmptyToNull(value); }
}
///
/// The literal value for the environment variable.
///
[TaskAttribute("value")]
public string LiteralValue {
get { return _literalValue; }
set {
_value = value;
_literalValue = value;
}
}
///
/// The value for a file-based environment variable. NAnt will convert
/// it to an absolute filename.
///
[TaskAttribute("file")]
public FileInfo File {
get { return _file; }
set {
_value = value.ToString();
_file = value;
}
}
///
/// The value for a directory-based environment variable. NAnt will
/// convert it to an absolute path.
///
[TaskAttribute("dir")]
public DirectoryInfo Directory {
get { return _directory; }
set {
_value = value.ToString();
_directory = value;
}
}
///
/// The value for a PATH like environment variable. You can use
/// : or ; as path separators and NAnt will convert it to
/// the platform's local conventions.
///
[TaskAttribute("path")]
public PathSet Path {
get { return _path; }
set {
_value = value.ToString();
_path = value;
}
}
[BuildElementArray("variable", ElementType=typeof(EnvironmentVariable))]
public EnvironmentVariableCollection EnvironmentVariables {
get { return _environmentVariables; }
set { _environmentVariables = value; }
}
#endregion Public Instance Properties
#region DllImports
///
/// Win32 DllImport for the SetEnvironmentVariable function.
///
///
///
///
[DllImport("kernel32.dll", SetLastError=true)]
private static extern bool SetEnvironmentVariable(string lpName, string lpValue);
///
/// *nix dllimport for the setenv function.
///
///
///
///
///
[DllImport("libc")]
private static extern int setenv(string name, string value, int overwrite);
#endregion DllImports
#region Override implementation of Task
///
/// Checks whether the task is initialized with valid attributes.
///
///
protected override void InitializeTask(XmlNode taskNode) {
if (EnvName == null && EnvironmentVariables.Count == 0) {
throw new BuildException("Either the \"name\" attribute or at"
+ " least one nested element is required.",
Location);
}
}
///
/// Set the environment variables
///
protected override void ExecuteTask() {
if (EnvName != null && _value != null ) {
// add single environment variable
EnvironmentVariables.Add(new EnvironmentVariable(EnvName, _value));
}
foreach (EnvironmentVariable env in EnvironmentVariables) {
SetSingleEnvironmentVariable(env.VariableName, env.Value);
}
}
#endregion Override implementation of Task
#region Private Instance Methods
///
/// Do the actual work here.
///
/// The name of the environment variable.
/// The value of the environment variable.
private void SetSingleEnvironmentVariable(string name, string value) {
bool result;
Log(Level.Verbose, "Setting environment variable \"{0}\" to \"{1}\".",
name, value);
// expand any env vars in value
string expandedValue = Environment.ExpandEnvironmentVariables(value);
// set the environment variable
if (PlatformHelper.IsWin32) {
result = SetEnvironmentVariable(name, expandedValue);
} else if (PlatformHelper.IsUnix) {
result = setenv(name, expandedValue, 1) == 0;
} else {
throw new BuildException("Setenv not defined on this platform",
Location);
}
// check if setting of environment variable was succesful
if (!result) {
throw new BuildException(string.Format(CultureInfo.InvariantCulture,
"Error setting environment variable \"{0}\" to \"{1}\".",
name, value), Location);
}
}
#endregion Private Instance Methods
}
}