// 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
//
// Matthew Mastracci (matt@aclaro.com)
// Scott Ford (sford@RJKTECH.com)
// Gert Driesen (gert.driesen@ardatis.com)
using System;
using System.Collections;
using System.Collections.Specialized;
using System.Globalization;
using System.IO;
using System.Xml;
using Microsoft.Win32;
using NAnt.Core;
using NAnt.Core.Util;
using NAnt.VSNet.Tasks;
namespace NAnt.VSNet {
public abstract class AssemblyReferenceBase : FileReferenceBase {
#region Protected Instance Constructors
protected AssemblyReferenceBase(XmlElement xmlDefinition, ReferencesResolver referencesResolver, ProjectBase parent, GacCache gacCache) : base(xmlDefinition, referencesResolver, parent, gacCache) {
}
#endregion Protected Instance Constructors
#region Protected Instance Properties
protected abstract bool IsPrivate {
get;
}
protected abstract bool IsPrivateSpecified {
get;
}
#endregion Protected Instance Properties
#region Override implementation of ReferenceBase
///
/// Gets a value indicating whether the output file(s) of this reference
/// should be copied locally.
///
///
/// if the output file(s) of this reference
/// should be copied locally; otherwise, .
///
public override bool CopyLocal {
get {
if (IsPrivateSpecified) {
return IsPrivate;
} else {
// only copy local if assembly reference could be resolved,
// if not a system assembly and is not in the GAC
string assemblyFile = ResolveAssemblyReference();
return assemblyFile != null && !IsSystem &&
!GacCache.IsAssemblyInGac(assemblyFile);
}
}
}
///
/// Gets a value indicating whether this reference represents a system
/// assembly.
///
///
/// if this reference represents a system
/// assembly; otherwise, .
///
protected override bool IsSystem {
get {
// if the assembly cannot be resolved, we consider it not to
// be a system assembly
string assemblyFile = ResolveAssemblyReference();
if (assemblyFile == null) {
return false;
}
// check if assembly is stored in the framework assembly
// directory
return string.Compare(Path.GetDirectoryName(assemblyFile),
SolutionTask.Project.TargetFramework.FrameworkAssemblyDirectory.FullName,
true, CultureInfo.InvariantCulture) == 0;
}
}
///
/// Gets the path of the reference, without taking the "copy local"
/// setting into consideration.
///
/// The solution configuration that is built.
///
/// The output path of the reference.
///
public override string GetPrimaryOutputFile(string solutionConfiguration) {
return ResolveAssemblyReference();
}
///
/// Gets the complete set of output files for the referenced project.
///
/// The solution configuration that is built.
/// The set of output files to be updated.
///
/// The key of the case-insensitive is the
/// full path of the output file and the value is the path relative to
/// the output directory.
///
public override void GetOutputFiles(string solutionConfiguration, Hashtable outputFiles) {
string assemblyFile = ResolveAssemblyReference();
if (assemblyFile != null) {
base.GetAssemblyOutputFiles(assemblyFile, outputFiles);
}
}
///
/// Gets the complete set of assemblies that need to be referenced when
/// a project references this component.
///
/// The solution configuration that is built.
///
/// The complete set of assemblies that need to be referenced when a
/// project references this component.
///
public override StringCollection GetAssemblyReferences(string solutionConfiguration) {
// if we're dealing with an assembly reference, then we only
// need to reference that assembly itself as VS.NET forces users
// to add all dependent assemblies to the project itself
StringCollection assemblyReferences = new StringCollection();
// attempt to resolve assembly reference
string assemblyFile = ResolveAssemblyReference();
if (assemblyFile == null) {
Log(Level.Warning, "Assembly \"{0}\", referenced"
+ " by project \"{1}\", could not be resolved.", Name,
Parent.Name);
return assemblyReferences;
}
// ensure assembly actually exists
if (!File.Exists(assemblyFile)) {
Log(Level.Warning, "Assembly \"{0}\", referenced"
+ " by project \"{1}\", does not exist.", assemblyFile,
Parent.Name);
return assemblyReferences;
}
// add referenced assembly to list of reference assemblies
assemblyReferences.Add(assemblyFile);
return assemblyReferences;
}
///
/// Gets the timestamp of the reference.
///
/// The solution configuration that is built.
///
/// The timestamp of the reference.
///
public override DateTime GetTimestamp(string solutionConfiguration) {
string assemblyFile = ResolveAssemblyReference();
if (assemblyFile == null) {
return DateTime.MaxValue;
}
return GetFileTimestamp(assemblyFile);
}
#endregion Override implementation of ReferenceBase
#region Public Instance Methods
public ProjectReferenceBase CreateProjectReference(ProjectBase project) {
return project.CreateProjectReference(project, IsPrivateSpecified,
IsPrivate);
}
#endregion Public Instance Methods
#region Protected Instance Methods
///
/// Resolves an assembly reference.
///
///
/// The full path to the resolved assembly, or
/// if the assembly reference could not be resolved.
///
protected abstract string ResolveAssemblyReference();
///
/// Searches for the given file in all paths in .
///
/// The folders to search.
/// The file to search for.
///
/// The path of the assembly if was found
/// in ; otherwise, .
///
protected string ResolveFromFolderList(StringCollection folderList, string fileName) {
Log(Level.Debug, "Attempting to resolve \"{0}\" in AssemblyFolders...",
fileName);
foreach (string path in folderList) {
Log(Level.Debug, "Checking \"{0}\"...", path);
try {
string assemblyFile = FileUtils.CombinePaths(path, fileName);
if (File.Exists(assemblyFile)) {
Log(Level.Debug, "Assembly found in \"{0}\".", path);
return assemblyFile;
} else {
Log(Level.Debug, "Assembly not found in \"{0}\".", path);
}
} catch (Exception ex) {
Log(Level.Verbose, "Error resolving reference to \"{0}\""
+ " in directory \"{1}\".", fileName, path);
Log(Level.Debug, ex.ToString());
}
}
return null;
}
///
/// Resolves an assembly reference in the framework assembly directory
/// of the target framework.
///
/// The file to search for.
///
/// The full path of the assembly file if the assembly could be located
/// in the framework assembly directory; otherwise, .
///
protected string ResolveFromFramework(string fileName) {
string systemAssembly = FileUtils.CombinePaths(SolutionTask.Project.TargetFramework.
FrameworkAssemblyDirectory.FullName, fileName);
if (File.Exists(systemAssembly)) {
return systemAssembly;
}
return null;
}
///
/// Resolves an assembly reference using a path relative to the project
/// directory.
///
///
/// The full path of the assembly, or if
/// is or an
/// empty .
///
protected string ResolveFromRelativePath(string relativePath) {
if (!StringUtils.IsNullOrEmpty(relativePath)) {
// TODO: VS.NET seems to be able to handle a project dir / hint
// path combination that is more than 260 characters long
//
// eg. ../Assemblies/..Assemblies/../......
string combinedPath = FileUtils.CombinePaths(Parent.ProjectDirectory.FullName,
relativePath);
try {
return FileUtils.GetFullPath(combinedPath);
} catch (PathTooLongException ex) {
throw new BuildException(string.Format(CultureInfo.InvariantCulture,
"Assembly \"{0}\", referenced by project \"{1}\", could not be"
+ " resolved using path \"{2}\".", Name, Parent.Name, combinedPath),
Location.UnknownLocation, ex);
}
}
return null;
}
protected virtual string ResolveFromAssemblyFolders(XmlElement referenceElement, string fileName) {
return ResolveFromFolderList(SolutionTask.AssemblyFolderList,
fileName);
}
#endregion Protected Instance Methods
}
}