Improve assembly resolution when hintpath is specified and when searching
authorAnkit Jain <radical@corewars.org>
Fri, 28 May 2010 21:35:10 +0000 (21:35 -0000)
committerAnkit Jain <radical@corewars.org>
Fri, 28 May 2010 21:35:10 +0000 (21:35 -0000)
in a directory.

* AssemblyResolver.cs (FindInDirectory): Add a 'specific_version'
parameter. Look for reference.{dll|exe} instead of checking all
files in the directory. Compare assembly names only if
specific_version is true.
(ResolveHintPathReference): Extract code to check and compare assembly
names to ..
(ResolvedReferenceFromPath): .. this.
(AssemblyNamesCompatible): Change default value of @specificVersion to
true.
Track api changes.
* ResolveAssemblyReference.cs (ResolveReference): Specify
'specific_version' in case of SearchPath.Directory.
(TryGetSpecificVersionValue): msbuild seems to look only for ',' in
the reference, instead of checking whether the assembly is strong
named.
(TryGetResolvedReferenceByAssemblyName): Track api changes.

svn path=/trunk/mcs/; revision=158123

mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks/AssemblyResolver.cs
mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks/ChangeLog
mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks/ResolveAssemblyReference.cs

index 9298ba06891dae1ae2b120c2acc759f923d2f105..74f50332ac7d58eacb3284717a69387199157e61 100644 (file)
@@ -130,7 +130,7 @@ namespace Microsoft.Build.Tasks {
 
                        KeyValuePair<AssemblyName, string> pair;
                        if (gac_asm.NameToAssemblyNameCache.TryGetValue (key_aname.Name, out pair)) {
-                               if (AssemblyNamesCompatible (key_aname, pair.Key, specific_version, true)) {
+                               if (AssemblyNamesCompatible (key_aname, pair.Key, specific_version)) {
                                        // gac and tgt frmwk refs are not copied private
                                        return GetResolvedReference (reference, pair.Value, pair.Key, false,
                                                        SearchPath.TargetFrameworkDirectory);
@@ -146,40 +146,50 @@ namespace Microsoft.Build.Tasks {
                        return null;
                }
 
-               public ResolvedReference FindInDirectory (ITaskItem reference, string directory, string [] file_extensions)
+               public ResolvedReference FindInDirectory (ITaskItem reference, string directory, string [] file_extensions, bool specific_version)
                {
-                       if (reference.ItemSpec.IndexOf (',') < 0) {
-                               // Try as a filename
-                               string path = Path.Combine (directory, reference.ItemSpec);
-                               AssemblyName aname = GetAssemblyNameFromFile (path);
-                               if (aname != null)
-                                       return GetResolvedReference (reference, path, aname, true, SearchPath.Directory);
-
-                               foreach (string extn in file_extensions) {
-                                       string path_with_extn = path + extn;
-                                       aname = GetAssemblyNameFromFile (path_with_extn);
-                                       if (aname != null)
-                                               return GetResolvedReference (reference, path_with_extn, aname, true,
-                                                               SearchPath.Directory);
-                               }
-                       }
+                       string filename = reference.ItemSpec;
+                       int comma_pos = filename.IndexOf (',');
+                       if (comma_pos >= 0)
+                               filename = filename.Substring (0, comma_pos);
 
-                       // Probably an assembly name
-                       AssemblyName key_aname = new AssemblyName (reference.ItemSpec);
+                       // Try as a filename
+                       string path = Path.GetFullPath (Path.Combine (directory, filename));
+                       AssemblyName aname = specific_version ? new AssemblyName (reference.ItemSpec) : null;
+
+                       ResolvedReference resolved_ref = ResolveReferenceForPath (path, reference, aname, null, SearchPath.Directory, specific_version);
+                       if (resolved_ref != null)
+                               return resolved_ref;
+
+                       // try path + Include + {.dll|.exe|..}
                        foreach (string extn in file_extensions) {
-                               foreach (string file in Directory.GetFiles (directory, "*" + extn)) {
-                                       AssemblyName found_aname = GetAssemblyNameFromFile (file);
-                                       if (found_aname == null)
-                                               // error already logged
-                                               continue;
-
-                                       //FIXME: Extract 'name' and look only for name.dll name.exe ?
-                                       if (AssemblyNamesCompatible (key_aname, found_aname, false))
-                                               return GetResolvedReference (reference, file, found_aname, true,
-                                                               SearchPath.Directory);
-
-                                       LogSearchMessage ("Considered {0}, but assembly name wasn't compatible.", file);
-                               }
+                               resolved_ref = ResolveReferenceForPath (path + extn, reference, aname, null, SearchPath.Directory, specific_version);
+                               if (resolved_ref != null)
+                                       return resolved_ref;
+                       }
+
+                       return null;
+               }
+
+               // tries to resolve reference from the given file path, and compares assembly names
+               // if @specific_version == true, and logs accordingly
+               ResolvedReference ResolveReferenceForPath (string filename, ITaskItem reference, AssemblyName aname,
+                                       string error_message, SearchPath spath, bool specific_version)
+               {
+                       AssemblyName found_aname = GetAssemblyNameFromFile (filename);
+                       if (found_aname == null) {
+                               if (error_message != null)
+                                       log.LogMessage (MessageImportance.Low, error_message);
+                               return null;
+                       }
+
+                       if (!specific_version || AssemblyNamesCompatible (aname, found_aname, specific_version)) {
+                               // Check compatibility only if specific_version == true
+                               return GetResolvedReference (reference, filename, found_aname, true, spath);
+                       } else {
+                               LogSearchMessage ("Considered '{0}', but assembly name '{1}' did not match the " +
+                                               "expected '{2}' (SpecificVersion={3})", filename, found_aname, aname, specific_version);
+                               log.LogMessage (MessageImportance.Low, "Assembly names are not compatible.");
                        }
 
                        return null;
@@ -259,9 +269,6 @@ namespace Microsoft.Build.Tasks {
 
                public ResolvedReference ResolveHintPathReference (ITaskItem reference, bool specific_version)
                {
-                       AssemblyName name = new AssemblyName (reference.ItemSpec);
-                       ResolvedReference resolved = null;
-
                        string hintpath = reference.GetMetadata ("HintPath");
                        if (String.IsNullOrEmpty (hintpath)) {
                                LogSearchMessage ("HintPath attribute not found");
@@ -274,21 +281,9 @@ namespace Microsoft.Build.Tasks {
                                return null;
                        }
 
-                       AssemblyName found = GetAssemblyNameFromFile (hintpath);
-                       if (found == null) {
-                               log.LogMessage (MessageImportance.Low, "File at HintPath {0}, is either an invalid assembly or the file does not exist.", hintpath);
-                               return null;
-                       }
-
-                       if (AssemblyNamesCompatible (name, found, specific_version)) {
-                               resolved = GetResolvedReference (reference, hintpath, found, true, SearchPath.HintPath);
-                       } else {
-                               LogSearchMessage ("Considered {0}, but assembly name '{1}' did not match the " +
-                                               "expected '{2}' (SpecificVersion={3})", hintpath, found, name, specific_version);
-                               log.LogMessage (MessageImportance.Low, "Assembly names are not compatible.");
-                       }
-
-                       return resolved;
+                       return ResolveReferenceForPath (hintpath, reference, new AssemblyName (reference.ItemSpec),
+                                               String.Format ("File at HintPath {0}, is either an invalid assembly or the file does not exist.", hintpath),
+                                               SearchPath.HintPath, specific_version);
                }
 
                public AssemblyName GetAssemblyNameFromFile (string filename)
@@ -310,7 +305,7 @@ namespace Microsoft.Build.Tasks {
 
                internal static bool AssemblyNamesCompatible (AssemblyName a, AssemblyName b, bool specificVersion)
                {
-                       return AssemblyNamesCompatible (a, b, specificVersion, false);
+                       return AssemblyNamesCompatible (a, b, specificVersion, true);
                }
 
                // if @specificVersion is true then match full name, else just the simple name
index d74f25d7c972a3d884230ff7cc4a51224b867613..ab95556951d760ade0962038c7c68349659a03b6 100644 (file)
@@ -1,3 +1,22 @@
+2010-05-28  Ankit Jain  <jankit@novell.com>
+
+       * AssemblyResolver.cs (FindInDirectory): Add a 'specific_version'
+       parameter. Look for reference.{dll|exe} instead of checking all
+       files in the directory. Compare assembly names only if
+       specific_version is true.
+       (ResolveHintPathReference): Extract code to check and compare assembly
+       names to ..
+       (ResolvedReferenceFromPath): .. this.
+       (AssemblyNamesCompatible): Change default value of @specificVersion to
+       true.
+       Track api changes.
+       * ResolveAssemblyReference.cs (ResolveReference): Specify
+       'specific_version' in case of SearchPath.Directory.
+       (TryGetSpecificVersionValue): msbuild seems to look only for ',' in
+       the reference, instead of checking whether the assembly is strong
+       named.
+       (TryGetResolvedReferenceByAssemblyName): Track api changes.
+
 2010-05-28  Ankit Jain  <jankit@novell.com>
 
        * AssemblyResolver.cs (PopulateTargetFrameworkAssemblies):
index 4f7665d7dde7efb491f27fbb7f50d3dbca711f2b..ee39d771589665062ed17a256e62bd66b180b67a 100644 (file)
@@ -221,7 +221,8 @@ namespace Microsoft.Build.Tasks {
                                } else {
                                        resolved = assembly_resolver.FindInDirectory (
                                                        item, spath,
-                                                       allowedAssemblyExtensions ?? default_assembly_extensions);
+                                                       allowedAssemblyExtensions ?? default_assembly_extensions,
+                                                       specific_version);
                                }
 
                                if (resolved != null)
@@ -239,10 +240,13 @@ namespace Microsoft.Build.Tasks {
                        specific_version = true;
                        string value = item.GetMetadata ("SpecificVersion");
                        if (String.IsNullOrEmpty (value)) {
-                               AssemblyName name = new AssemblyName (item.ItemSpec);
+                               //AssemblyName name = new AssemblyName (item.ItemSpec);
                                // If SpecificVersion is not specified, then
                                // it is true if the Include is a strong name else false
-                               specific_version = assembly_resolver.IsStrongNamed (name);
+                               //specific_version = assembly_resolver.IsStrongNamed (name);
+
+                               // msbuild seems to just look for a ',' in the name :/
+                               specific_version = item.ItemSpec.IndexOf (',') >= 0;
                                return true;
                        }
 
@@ -460,7 +464,7 @@ namespace Microsoft.Build.Tasks {
                                return false;
 
                        // match for full name
-                       if (AssemblyResolver.AssemblyNamesCompatible (key_aname, found_ref.AssemblyName, true))
+                       if (AssemblyResolver.AssemblyNamesCompatible (key_aname, found_ref.AssemblyName, true, false))
                                // exact match, so its already there, dont add anything
                                return true;