1 // Copyright (c) Microsoft. All rights reserved.
2 // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 
4 using System;
5 using System.Reflection;
6 using System.Collections;
7 using Microsoft.Build.Shared;
8 using System.Diagnostics;
9 
10 namespace Microsoft.Build.Tasks
11 {
12     /// <summary>
13     /// Resolve searchpath type {CandidateAssemblyFiles}
14     /// </summary>
15     internal class CandidateAssemblyFilesResolver : Resolver
16     {
17         /// <summary>
18         /// The candidate assembly files.
19         /// </summary>
20         private string[] _candidateAssemblyFiles;
21 
22         /// <summary>
23         /// Construct.
24         /// </summary>
25         /// <param name="candidateAssemblyFiles">List of literal assembly file names to be considered when SearchPaths has {CandidateAssemblyFiles}.</param>
26         /// <param name="searchPathElement"></param>
27         /// <param name="getAssemblyName"></param>
28         /// <param name="fileExists"></param>
CandidateAssemblyFilesResolver(string[] candidateAssemblyFiles, string searchPathElement, GetAssemblyName getAssemblyName, FileExists fileExists, GetAssemblyRuntimeVersion getRuntimeVersion, Version targetedRuntimeVesion)29         public CandidateAssemblyFilesResolver(string[] candidateAssemblyFiles, string searchPathElement, GetAssemblyName getAssemblyName, FileExists fileExists, GetAssemblyRuntimeVersion getRuntimeVersion, Version targetedRuntimeVesion)
30             : base(searchPathElement, getAssemblyName, fileExists, getRuntimeVersion, targetedRuntimeVesion, ProcessorArchitecture.None, false)
31         {
32             _candidateAssemblyFiles = candidateAssemblyFiles;
33         }
34 
35         /// <summary>
36         /// Resolve a reference to a specific file name.
37         /// </summary>
38         /// <param name="assemblyName">The assemblyname of the reference.</param>
39         /// <param name="rawFileNameCandidate">The reference's 'include' treated as a raw file name.</param>
40         /// <param name="isPrimaryProjectReference">Whether or not this reference was directly from the project file (and therefore not a dependency)</param>
41         /// <param name="wantSpecificVersion">Whether an exact version match is requested.</param>
42         /// <param name="executableExtensions">Allowed executable extensions.</param>
43         /// <param name="hintPath">The item's hintpath value.</param>
44         /// <param name="assemblyFolderKey">Like "hklm\Vendor RegKey" as provided to a reference by the &lt;AssemblyFolderKey&gt; on the reference in the project.</param>
45         /// <param name="assembliesConsideredAndRejected">Receives the list of locations that this function tried to find the assembly. May be "null".</param>
46         /// <param name="foundPath">The path where the file was found.</param>
47         /// <param name="userRequestedSpecificFile">Whether or not the user wanted a specific file (for example, HintPath is a request for a specific file)</param>
48         /// <returns>True if the file was resolved.</returns>
Resolve( AssemblyNameExtension assemblyName, string sdkName, string rawFileNameCandidate, bool isPrimaryProjectReference, bool wantSpecificVersion, string[] executableExtensions, string hintPath, string assemblyFolderKey, ArrayList assembliesConsideredAndRejected, out string foundPath, out bool userRequestedSpecificFile )49         public override bool Resolve
50         (
51             AssemblyNameExtension assemblyName,
52             string sdkName,
53             string rawFileNameCandidate,
54             bool isPrimaryProjectReference,
55             bool wantSpecificVersion,
56             string[] executableExtensions,
57             string hintPath,
58             string assemblyFolderKey,
59             ArrayList assembliesConsideredAndRejected,
60 
61             out string foundPath,
62             out bool userRequestedSpecificFile
63         )
64         {
65             foundPath = null;
66             userRequestedSpecificFile = false;
67 
68             if (assemblyName != null)
69             {
70                 // {CandidateAssemblyFiles} was passed in.
71                 foreach (string candidateAssemblyFile in _candidateAssemblyFiles)
72                 {
73                     // Filter out disallowed extensions. We don't even want to log them.
74                     bool allowedExtension = FileUtilities.HasExtension(candidateAssemblyFile, executableExtensions);
75                     if (allowedExtension)
76                     {
77                         // The file has an allowed extension, so give it a shot.
78                         bool matched = false;
79 
80                         ResolutionSearchLocation considered = null;
81                         if (assembliesConsideredAndRejected != null)
82                         {
83                             considered = new ResolutionSearchLocation();
84                             considered.FileNameAttempted = candidateAssemblyFile;
85                             considered.SearchPath = searchPathElement;
86                         }
87 
88                         if (FileMatchesAssemblyName(assemblyName, isPrimaryProjectReference, wantSpecificVersion, false, candidateAssemblyFile, considered))
89                         {
90                             matched = true;
91                         }
92                         else
93                         {
94                             // Record this as a location that was considered.
95                             if (assembliesConsideredAndRejected != null)
96                             {
97                                 Debug.Assert(considered.Reason != NoMatchReason.Unknown, "Expected a no match reason here.");
98                                 assembliesConsideredAndRejected.Add(considered);
99                             }
100                         }
101 
102                         if (matched)
103                         {
104                             foundPath = candidateAssemblyFile;
105                             return true;
106                         }
107                     }
108                 }
109             }
110 
111 
112 
113             return false;
114         }
115     }
116 }
117