// NAnt - A .NET build tool // Copyright (C) 2001-2004 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 // // Gert Driesen (gert.driesen@ardatis.com) using System; using System.Globalization; using System.IO; using System.Text.RegularExpressions; using System.Xml; using NAnt.Core; using NAnt.Core.Util; using NAnt.VSNet.Tasks; namespace NAnt.VSNet { public class VcAssemblyReference : AssemblyReferenceBase { public VcAssemblyReference(XmlElement xmlDefinition, ReferencesResolver referencesResolver, ProjectBase parent, GacCache gacCache) : base(xmlDefinition, referencesResolver, parent, gacCache) { XmlAttribute privateAttribute = xmlDefinition.Attributes["CopyLocal"]; if (privateAttribute != null) { _isPrivateSpecified = true; _isPrivate = bool.Parse(privateAttribute.Value); } // determine name of reference by taking filename part of relative // path, without extension XmlAttribute relativePathAttribute = XmlDefinition.Attributes["RelativePath"]; if (relativePathAttribute != null) { _name = Path.GetFileNameWithoutExtension(relativePathAttribute.Value); } _assemblyFile = ResolveAssemblyReference(); } #region Override implementation of AssemblyReferenceBase protected override bool IsPrivate { get { return _isPrivate; } } protected override bool IsPrivateSpecified { get { return _isPrivateSpecified; } } /// /// Resolves an assembly reference. /// /// /// The full path to the resolved assembly, or /// if the assembly reference could not be resolved. /// protected override string ResolveAssemblyReference() { // check if assembly reference was resolved before if (_assemblyFile != null) { // if assembly file actually exists, there's no need to resolve // the assembly reference again if (File.Exists(_assemblyFile)) { return _assemblyFile; } } XmlElement referenceElement = XmlDefinition; string assemblyFileName = null; string relativePath = referenceElement.GetAttribute("RelativePath"); if (relativePath == null) { throw new BuildException("For Visual C++ projects only assembly" + " references using relative paths are supported.", Location.UnknownLocation); } else { // expand macro's in RelativePath assemblyFileName = _rxMacro.Replace(relativePath, new MatchEvaluator(EvaluateMacro)); // TODO: support locating assemblies in VCConfiguration.ReferencesPath, // but for now just remove it from reference filename and // search all assembly folders assemblyFileName = assemblyFileName.Replace("{ReferencesPath}\\", ""); } // 1. The RelativePath might be fully qualified (after macro expansion) if (Path.IsPathRooted(assemblyFileName)) { // consider assembly resolve although we're not sure whether // the file actually exists // // the file might actually be created as result of building // a project return assemblyFileName; } // 2. The project directory // NOT SURE IF THIS IS CORRECT // 3. The ReferencePath // NOT SURE WE SHOULD DO THIS ONE // 4. The .NET Framework directory string resolvedAssemblyFile = ResolveFromFramework(assemblyFileName); if (resolvedAssemblyFile != null) { return resolvedAssemblyFile; } // 5. AssemblyFolders resolvedAssemblyFile = ResolveFromAssemblyFolders(referenceElement, Path.GetFileName(assemblyFileName)); if (resolvedAssemblyFile != null) { return resolvedAssemblyFile; } // assembly reference could not be resolved return null; } #endregion Override implementation of AssemblyReferenceBase #region Override implementation of ReferenceBase /// /// Gets the name of the referenced assembly. /// /// /// The name of the referenced assembly, or if /// the name could not be determined. /// public override string Name { get { return _name; } } #endregion Override implementation of ReferenceBase #region Private Instance Methods /// /// Is called each time a regular expression match is found during a /// operation. /// /// The resulting from a single regular expression match during a . /// /// The expanded . /// /// The macro is not supported. /// Expansion of a given macro is not yet implemented. private string EvaluateMacro(Match m) { string macro = m.Groups[1].Value; // expand using solution level macro's string expandedMacro = SolutionTask.ExpandMacro(macro); if (expandedMacro != null) { return expandedMacro; } // expand using project level macro's expandedMacro = Parent.ExpandMacro(macro); if (expandedMacro != null) { return expandedMacro; } throw new BuildException(string.Format(CultureInfo.InvariantCulture, "Macro \"{0}\", used by assembly reference \"{1}\" in project" + " \"{2}\" is not supported in assembly references.", macro, Name, Parent.Name), Location.UnknownLocation); } #endregion Private Instance Methods #region Private Instance Fields private string _assemblyFile; private readonly bool _isPrivateSpecified; private readonly bool _isPrivate; private readonly string _name = string.Empty; private readonly Regex _rxMacro = new Regex(@"\$\((\w+)\)"); #endregion Private Instance Fields } }