// 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 } }