* ResolveAssemblyReference.cs: Log only unique conflict warnings.
[mono.git] / mcs / class / Microsoft.Build.Tasks / Microsoft.Build.Tasks / ResolveAssemblyReference.cs
1 //
2 // ResolveAssemblyReference.cs: Searches for assembly files.
3 //
4 // Author:
5 //   Marek Sieradzki (marek.sieradzki@gmail.com)
6 //   Ankit Jain (jankit@novell.com)
7 // 
8 // (C) 2006 Marek Sieradzki
9 // Copyright 2009 Novell, Inc (http://www.novell.com)
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 //
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 //
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29
30 #if NET_2_0
31
32 using System;
33 using System.Collections.Generic;
34 using System.Globalization;
35 using System.IO;
36 using System.Linq;
37 using System.Reflection;
38 using System.Security;
39 using Microsoft.Build.Framework;
40 using Microsoft.Build.Utilities;
41
42 namespace Microsoft.Build.Tasks {
43         public class ResolveAssemblyReference : TaskExtension {
44         
45                 bool            autoUnify;
46                 ITaskItem[]     assemblyFiles;
47                 ITaskItem[]     assemblies;
48                 string          appConfigFile;
49                 string[]        allowedAssemblyExtensions;
50                 string[]        allowedRelatedFileExtensions;
51                 string[]        candidateAssemblyFiles;
52                 ITaskItem[]     copyLocalFiles;
53                 ITaskItem[]     filesWritten;
54                 bool            findDependencies;
55                 bool            findRelatedFiles;
56                 bool            findSatellites;
57                 bool            findSerializationAssemblies;
58                 string[]        installedAssemblyTables;
59                 ITaskItem[]     relatedFiles;
60                 ITaskItem[]     resolvedDependencyFiles;
61                 ITaskItem[]     resolvedFiles;
62                 ITaskItem[]     satelliteFiles;
63                 ITaskItem[]     scatterFiles;
64                 string[]        searchPaths;
65                 ITaskItem[]     serializationAssemblyFiles;
66                 bool            silent;
67                 string          stateFile;
68                 ITaskItem[]     suggestedRedirects;
69                 string[]        targetFrameworkDirectories;
70                 string          targetProcessorArchitecture;
71                 static string []        default_assembly_extensions;
72
73                 AssemblyResolver        assembly_resolver;
74                 List<string> dependency_search_paths;
75                 Dictionary<string, ResolvedReference> assemblyNameToResolvedRef;
76                 Dictionary<string, ITaskItem>   tempSatelliteFiles, tempRelatedFiles,
77                         tempResolvedDepFiles, tempCopyLocalFiles;
78                 List<ITaskItem> tempResolvedFiles;
79                 List<PrimaryReference> primaryReferences;
80                 Dictionary<string, string> alreadyScannedAssemblyNames;
81                 Dictionary<string, string> conflictWarningsCache;
82
83                 //FIXME: construct and use a graph of the dependencies, useful across projects
84
85                 static ResolveAssemblyReference ()
86                 {
87                         default_assembly_extensions = new string [] { ".dll", ".exe" };
88                 }
89
90                 public ResolveAssemblyReference ()
91                 {
92                         assembly_resolver = new AssemblyResolver ();
93                 }
94
95                 //FIXME: make this reusable
96                 public override bool Execute ()
97                 {
98                         if (assemblies == null && assemblyFiles == null)
99                                 // nothing to resolve
100                                 return true;
101
102                         assembly_resolver.Log = Log;
103                         tempResolvedFiles = new List<ITaskItem> ();
104                         tempCopyLocalFiles = new Dictionary<string, ITaskItem> ();
105                         tempSatelliteFiles = new Dictionary<string, ITaskItem> ();
106                         tempRelatedFiles = new Dictionary<string, ITaskItem> ();
107                         tempResolvedDepFiles = new Dictionary<string, ITaskItem> ();
108
109                         primaryReferences = new List<PrimaryReference> ();
110                         assemblyNameToResolvedRef = new Dictionary<string, ResolvedReference> ();
111                         conflictWarningsCache = new Dictionary<string, string> ();
112
113                         ResolveAssemblies ();
114                         ResolveAssemblyFiles ();
115
116                         alreadyScannedAssemblyNames = new Dictionary<string, string> ();
117
118                         // the first element is place holder for parent assembly's dir
119                         dependency_search_paths = new List<string> () { String.Empty };
120                         dependency_search_paths.AddRange (searchPaths);
121
122                         // resolve dependencies
123                         foreach (PrimaryReference pref in primaryReferences)
124                                 ResolveAssemblyFileDependencies (pref.TaskItem, pref.ParentCopyLocal);
125
126                         resolvedFiles = tempResolvedFiles.ToArray ();
127                         copyLocalFiles = tempCopyLocalFiles.Values.ToArray ();
128                         satelliteFiles = tempSatelliteFiles.Values.ToArray ();
129                         relatedFiles = tempRelatedFiles.Values.ToArray ();
130                         resolvedDependencyFiles = tempResolvedDepFiles.Values.ToArray ();
131
132                         tempResolvedFiles.Clear ();
133                         tempCopyLocalFiles.Clear ();
134                         tempSatelliteFiles.Clear ();
135                         tempRelatedFiles.Clear ();
136                         tempResolvedDepFiles.Clear ();
137                         alreadyScannedAssemblyNames.Clear ();
138                         primaryReferences.Clear ();
139                         assemblyNameToResolvedRef.Clear ();
140                         conflictWarningsCache.Clear ();
141                         dependency_search_paths = null;
142
143                         return true;
144                 }
145
146                 void ResolveAssemblies ()
147                 {
148                         if (assemblies == null || assemblies.Length == 0)
149                                 return;
150
151                         foreach (ITaskItem item in assemblies) {
152                                 if (!String.IsNullOrEmpty (item.GetMetadata ("SubType"))) {
153                                         Log.LogWarning ("Reference '{0}' has non-empty SubType. Ignoring.", item.ItemSpec);
154                                         continue;
155                                 }
156
157                                 Log.LogMessage (MessageImportance.Low, "Primary Reference {0}", item.ItemSpec);
158                                 ResolvedReference resolved_ref = ResolveReference (item, searchPaths, true);
159                                 if (resolved_ref == null) {
160                                         Log.LogWarning ("Reference '{0}' not resolved", item.ItemSpec);
161                                         assembly_resolver.LogSearchLoggerMessages ();
162                                 } else {
163                                         Log.LogMessage (MessageImportance.Low,
164                                                         "\tReference {0} resolved to {1}. CopyLocal = {2}",
165                                                         item.ItemSpec, resolved_ref.TaskItem,
166                                                         resolved_ref.TaskItem.GetMetadata ("CopyLocal"));
167
168                                         Log.LogMessage (MessageImportance.Low,
169                                                         "\tReference found at search path {0}",
170                                                         resolved_ref.FoundInSearchPathAsString);
171
172                                         if (TryAddNewReference (tempResolvedFiles, resolved_ref) &&
173                                                 !IsFromGacOrTargetFramework (resolved_ref) &&
174                                                 resolved_ref.FoundInSearchPath != SearchPath.PkgConfig) {
175                                                 primaryReferences.Add (new PrimaryReference (
176                                                                 resolved_ref.TaskItem,
177                                                                 resolved_ref.TaskItem.GetMetadata ("CopyLocal")));
178                                         }
179                                 }
180                         }
181                 }
182
183                 // Use @search_paths to resolve the reference
184                 ResolvedReference ResolveReference (ITaskItem item, IEnumerable<string> search_paths, bool set_copy_local)
185                 {
186                         ResolvedReference resolved = null;
187                         bool specific_version;
188
189                         assembly_resolver.ResetSearchLogger ();
190
191                         if (!TryGetSpecificVersionValue (item, out specific_version))
192                                 return null;
193
194                         foreach (string spath in search_paths) {
195                                 assembly_resolver.LogSearchMessage ("For searchpath {0}", spath);
196
197                                 if (String.Compare (spath, "{HintPathFromItem}") == 0) {
198                                         resolved = assembly_resolver.ResolveHintPathReference (item, specific_version);
199                                 } else if (String.Compare (spath, "{TargetFrameworkDirectory}") == 0) {
200                                         if (targetFrameworkDirectories == null)
201                                                 continue;
202                                         foreach (string fpath in targetFrameworkDirectories) {
203                                                 resolved = assembly_resolver.FindInTargetFramework (item,
204                                                                 fpath, specific_version);
205                                                 if (resolved != null)
206                                                         break;
207                                         }
208                                 } else if (String.Compare (spath, "{GAC}") == 0) {
209                                         resolved = assembly_resolver.ResolveGacReference (item, specific_version);
210                                 } else if (String.Compare (spath, "{RawFileName}") == 0) {
211                                         //FIXME: identify assembly names, as extract the name, and try with that?
212                                         AssemblyName aname = assembly_resolver.GetAssemblyNameFromFile (item.ItemSpec);
213                                         if (aname != null)
214                                                 resolved = assembly_resolver.GetResolvedReference (item, item.ItemSpec, aname, true,
215                                                                 SearchPath.RawFileName);
216                                 } else if (String.Compare (spath, "{CandidateAssemblyFiles}") == 0) {
217                                         assembly_resolver.LogSearchMessage (
218                                                         "Warning: {{CandidateAssemblyFiles}} not supported currently");
219                                 } else if (String.Compare (spath, "{PkgConfig}") == 0) {
220                                         resolved = assembly_resolver.ResolvePkgConfigReference (item, specific_version);
221                                 } else {
222                                         resolved = assembly_resolver.FindInDirectory (
223                                                         item, spath,
224                                                         allowedAssemblyExtensions ?? default_assembly_extensions);
225                                 }
226
227                                 if (resolved != null)
228                                         break;
229                         }
230
231                         if (resolved != null && set_copy_local)
232                                 SetCopyLocal (resolved.TaskItem, resolved.CopyLocal.ToString ());
233
234                         return resolved;
235                 }
236
237                 bool TryGetSpecificVersionValue (ITaskItem item, out bool specific_version)
238                 {
239                         specific_version = true;
240                         string value = item.GetMetadata ("SpecificVersion");
241                         if (String.IsNullOrEmpty (value)) {
242                                 AssemblyName name = new AssemblyName (item.ItemSpec);
243                                 // If SpecificVersion is not specified, then
244                                 // it is true if the Include is a strong name else false
245                                 specific_version = assembly_resolver.IsStrongNamed (name);
246                                 return true;
247                         }
248
249                         if (Boolean.TryParse (value, out specific_version))
250                                 return true;
251
252                         Log.LogError ("Item '{0}' has attribute SpecificVersion with invalid value '{1}' " +
253                                         "which could not be converted to a boolean.", item.ItemSpec, value);
254                         return false;
255                 }
256
257                 //FIXME: Consider CandidateAssemblyFiles also here
258                 void ResolveAssemblyFiles ()
259                 {
260                         if (assemblyFiles == null)
261                                 return;
262
263                         foreach (ITaskItem item in assemblyFiles) {
264                                 assembly_resolver.ResetSearchLogger ();
265
266                                 if (!File.Exists (item.ItemSpec)) {
267                                         Log.LogMessage (MessageImportance.Low,
268                                                         "Primary Reference from AssemblyFiles {0}, file not found. Ignoring",
269                                                         item.ItemSpec);
270                                         continue;
271                                 }
272
273                                 Log.LogMessage (MessageImportance.Low, "Primary Reference from AssemblyFiles {0}", item.ItemSpec);
274                                 string copy_local;
275
276                                 AssemblyName aname = assembly_resolver.GetAssemblyNameFromFile (item.ItemSpec);
277                                 if (aname == null) {
278                                         Log.LogWarning ("Reference '{0}' not resolved", item.ItemSpec);
279                                         assembly_resolver.LogSearchLoggerMessages ();
280                                         continue;
281                                 }
282
283                                 ResolvedReference rr = assembly_resolver.GetResolvedReference (item, item.ItemSpec, aname, true,
284                                                 SearchPath.RawFileName);
285                                 copy_local = rr.CopyLocal.ToString ();
286
287                                 if (!TryAddNewReference (tempResolvedFiles, rr))
288                                         // already resolved
289                                         continue;
290
291                                 SetCopyLocal (rr.TaskItem, copy_local);
292
293                                 FindAndAddRelatedFiles (item.ItemSpec, copy_local);
294                                 FindAndAddSatellites (item.ItemSpec, copy_local);
295
296                                 if (FindDependencies && !IsFromGacOrTargetFramework (rr) &&
297                                                 rr.FoundInSearchPath != SearchPath.PkgConfig)
298                                         primaryReferences.Add (new PrimaryReference (item, copy_local));
299                         }
300                 }
301
302                 // Tries to resolve assemblies referenced by @item
303                 // Skips gac references
304                 // @item : filename
305                 void ResolveAssemblyFileDependencies (ITaskItem item, string parent_copy_local)
306                 {
307                         Queue<string> dependencies = new Queue<string> ();
308                         dependencies.Enqueue (item.ItemSpec);
309
310                         while (dependencies.Count > 0) {
311                                 string filename = Path.GetFullPath (dependencies.Dequeue ());
312                                 Assembly asm = Assembly.ReflectionOnlyLoadFrom (filename);
313                                 if (alreadyScannedAssemblyNames.ContainsKey (asm.FullName))
314                                         continue;
315
316                                 // set the 1st search path to this ref's base path
317                                 // Will be used for resolving the dependencies
318                                 dependency_search_paths [0] = Path.GetDirectoryName (filename);
319
320                                 foreach (AssemblyName aname in asm.GetReferencedAssemblies ()) {
321                                         if (alreadyScannedAssemblyNames.ContainsKey (aname.FullName))
322                                                 continue;
323
324                                         ResolvedReference resolved_ref = ResolveDependencyByAssemblyName (
325                                                         aname, asm.FullName, parent_copy_local);
326
327                                         if (resolved_ref != null && !IsFromGacOrTargetFramework (resolved_ref)
328                                                         && resolved_ref.FoundInSearchPath != SearchPath.PkgConfig)
329                                                 dependencies.Enqueue (resolved_ref.TaskItem.ItemSpec);
330                                 }
331                                 alreadyScannedAssemblyNames.Add (asm.FullName, String.Empty);
332                         }
333                 }
334
335                 // Resolves by looking dependency_search_paths
336                 // which is dir of parent reference file, and
337                 // SearchPaths
338                 ResolvedReference ResolveDependencyByAssemblyName (AssemblyName aname, string parent_asm_name,
339                                 string parent_copy_local)
340                 {
341                         // This will check for compatible assembly name/version
342                         ResolvedReference resolved_ref;
343                         if (TryGetResolvedReferenceByAssemblyName (aname, false, out resolved_ref))
344                                 return resolved_ref;
345
346                         Log.LogMessage (MessageImportance.Low, "Dependency {0}", aname);
347                         Log.LogMessage (MessageImportance.Low, "\tRequired by {0}", parent_asm_name);
348
349                         ITaskItem item = new TaskItem (aname.FullName);
350                         item.SetMetadata ("SpecificVersion", "false");
351                         resolved_ref = ResolveReference (item, dependency_search_paths, false);
352
353                         if (resolved_ref != null) {
354                                 Log.LogMessage (MessageImportance.Low, "\tReference {0} resolved to {1}.",
355                                         aname, resolved_ref.TaskItem.ItemSpec);
356
357                                 Log.LogMessage (MessageImportance.Low,
358                                                 "\tReference found at search path {0}",
359                                                 resolved_ref.FoundInSearchPathAsString);
360
361                                 if (resolved_ref.FoundInSearchPath == SearchPath.Directory) {
362                                         // override CopyLocal with parent's val
363                                         SetCopyLocal (resolved_ref.TaskItem, parent_copy_local);
364
365                                         Log.LogMessage (MessageImportance.Low,
366                                                         "\tThis is CopyLocal {0} as parent item has this value",
367                                                         parent_copy_local);
368
369                                         if (TryAddNewReference (tempResolvedFiles, resolved_ref)) {
370                                                 FindAndAddRelatedFiles (resolved_ref.TaskItem.ItemSpec, parent_copy_local);
371                                                 FindAndAddSatellites (resolved_ref.TaskItem.ItemSpec, parent_copy_local);
372                                         }
373                                 } else {
374                                         //gac or tgtfmwk
375                                         Log.LogMessage (MessageImportance.Low,
376                                                         "\tThis is CopyLocal false as it is in the gac," +
377                                                         "target framework directory or provided by a package.");
378
379                                         TryAddNewReference (tempResolvedFiles, resolved_ref);
380                                 }
381                         } else {
382                                 Log.LogWarning ("Reference '{0}' not resolved", aname);
383                                 assembly_resolver.LogSearchLoggerMessages ();
384                         }
385
386                         return resolved_ref;
387                 }
388
389                 void FindAndAddRelatedFiles (string filename, string parent_copy_local)
390                 {
391                         if (!findRelatedFiles || allowedRelatedFileExtensions == null)
392                                 return;
393
394                         foreach (string ext in allowedRelatedFileExtensions) {
395                                 string rfile = filename + ext;
396                                 if (File.Exists (rfile)) {
397                                         ITaskItem item = new TaskItem (rfile);
398                                         SetCopyLocal (item, parent_copy_local);
399
400                                         tempRelatedFiles.AddUniqueFile (item);
401                                 }
402                         }
403                 }
404
405                 void FindAndAddSatellites (string filename, string parent_copy_local)
406                 {
407                         if (!FindSatellites)
408                                 return;
409
410                         string basepath = Path.GetDirectoryName (filename);
411                         string resource = String.Format ("{0}{1}{2}",
412                                         Path.GetFileNameWithoutExtension (filename),
413                                         ".resources",
414                                         Path.GetExtension (filename));
415
416                         string dir_sep = Path.DirectorySeparatorChar.ToString ();
417                         foreach (string dir in Directory.GetDirectories (basepath)) {
418                                 string culture = Path.GetFileName (dir);
419                                 if (!CultureNamesTable.ContainsKey (culture))
420                                         continue;
421
422                                 string res_path = Path.Combine (dir, resource);
423                                 if (File.Exists (res_path)) {
424                                         ITaskItem item = new TaskItem (res_path);
425                                         SetCopyLocal (item, parent_copy_local);
426                                         item.SetMetadata ("DestinationSubdirectory", culture + dir_sep);
427                                         tempSatelliteFiles.AddUniqueFile (item);
428                                 }
429                         }
430                 }
431
432                 // returns true is it was new
433                 bool TryAddNewReference (List<ITaskItem> file_list, ResolvedReference key_ref)
434                 {
435                         ResolvedReference found_ref;
436                         if (!TryGetResolvedReferenceByAssemblyName (key_ref.AssemblyName, key_ref.IsPrimary, out found_ref)) {
437                                 assemblyNameToResolvedRef [key_ref.AssemblyName.Name] = key_ref;
438                                 file_list.Add (key_ref.TaskItem);
439
440                                 return true;
441                         }
442                         return false;
443                 }
444
445                 void SetCopyLocal (ITaskItem item, string copy_local)
446                 {
447                         item.SetMetadata ("CopyLocal", copy_local);
448
449                         // Assumed to be valid value
450                         if (Boolean.Parse (copy_local))
451                                 tempCopyLocalFiles.AddUniqueFile (item);
452                 }
453
454                 bool TryGetResolvedReferenceByAssemblyName (AssemblyName key_aname, bool is_primary, out ResolvedReference found_ref)
455                 {
456                         found_ref = null;
457                         // Match by just name
458                         if (!assemblyNameToResolvedRef.TryGetValue (key_aname.Name, out found_ref))
459                                 // not there
460                                 return false;
461
462                         // match for full name
463                         if (AssemblyResolver.AssemblyNamesCompatible (key_aname, found_ref.AssemblyName, true))
464                                 // exact match, so its already there, dont add anything
465                                 return true;
466
467                         // we have a name match, but version mismatch!
468                         assembly_resolver.LogSearchMessage ("A conflict was detected between '{0}' and '{1}'",
469                                         key_aname.FullName, found_ref.AssemblyName.FullName);
470
471                         if (is_primary == found_ref.IsPrimary) {
472                                 assembly_resolver.LogSearchMessage ("Unable to choose between the two. " +
473                                                 "Choosing '{0}' arbitrarily.", found_ref.AssemblyName.FullName);
474                                 return true;
475                         }
476
477                         // since all dependencies are processed after
478                         // all primary refererences, the one in the cache
479                         // has to be a primary
480                         // Prefer a primary reference over a dependency
481
482                         assembly_resolver.LogSearchMessage ("Choosing '{0}' as it is a primary reference.",
483                                         found_ref.AssemblyName.FullName);
484
485                         LogConflictWarning (found_ref.AssemblyName.FullName, key_aname.FullName);
486
487                         return true;
488                 }
489
490                 // conflict b/w @main and @conflicting, picking @main
491                 void LogConflictWarning (string main, string conflicting)
492                 {
493                         string key = main + ":" + conflicting;
494                         if (!conflictWarningsCache.ContainsKey (key)) {
495                                 Log.LogWarning ("Found a conflict between : '{0}' and '{1}'. Using '{0}' reference.",
496                                                 main, conflicting);
497                                 conflictWarningsCache [key] = key;
498                         }
499                 }
500
501                 bool IsCopyLocal (ITaskItem item)
502                 {
503                         return Boolean.Parse (item.GetMetadata ("CopyLocal"));
504                 }
505
506                 bool IsFromTargetFramework (string filename)
507                 {
508                         foreach (string fpath in targetFrameworkDirectories)
509                                 if (filename.StartsWith (fpath))
510                                         return true;
511
512                         return false;
513                 }
514
515                 bool IsFromGacOrTargetFramework (ResolvedReference rr)
516                 {
517                         return rr.FoundInSearchPath == SearchPath.Gac ||
518                                 rr.FoundInSearchPath == SearchPath.TargetFrameworkDirectory;
519                 }
520
521                 public bool AutoUnify {
522                         get { return autoUnify; }
523                         set { autoUnify = value; }
524                 }
525                 
526                 public ITaskItem[] AssemblyFiles {
527                         get { return assemblyFiles; }
528                         set { assemblyFiles = value; }
529                 }
530                 
531                 public ITaskItem[] Assemblies {
532                         get { return assemblies; }
533                         set { assemblies = value; }
534                 }
535                 
536                 public string AppConfigFile {
537                         get { return appConfigFile; }
538                         set { appConfigFile = value; }
539                 }
540                 
541                 public string[] AllowedAssemblyExtensions {
542                         get { return allowedAssemblyExtensions; }
543                         set { allowedAssemblyExtensions = value; }
544                 }
545
546                 public string[] AllowedRelatedFileExtensions {
547                         get { return allowedRelatedFileExtensions; }
548                         set { allowedRelatedFileExtensions = value; }
549                 }
550                 
551                 public string[] CandidateAssemblyFiles {
552                         get { return candidateAssemblyFiles; }
553                         set { candidateAssemblyFiles = value; }
554                 }
555                 
556                 [Output]
557                 public ITaskItem[] CopyLocalFiles {
558                         get { return copyLocalFiles; }
559                 }
560                 
561                 [Output]
562                 public ITaskItem[] FilesWritten {
563                         get { return filesWritten; }
564                         set { filesWritten = value; }
565                 }
566                 
567                 public bool FindDependencies {
568                         get { return findDependencies; }
569                         set { findDependencies = value; }
570                 }
571                 
572                 public bool FindRelatedFiles {
573                         get { return findRelatedFiles; }
574                         set { findRelatedFiles = value; }
575                 }
576                 
577                 public bool FindSatellites {
578                         get { return findSatellites; }
579                         set { findSatellites = value; }
580                 }
581                 
582                 public bool FindSerializationAssemblies {
583                         get { return findSerializationAssemblies; }
584                         set { findSerializationAssemblies = value; }
585                 }
586                 
587                 public string[] InstalledAssemblyTables {
588                         get { return installedAssemblyTables; }
589                         set { installedAssemblyTables = value; }
590                 }
591                 
592                 [Output]
593                 public ITaskItem[] RelatedFiles {
594                         get { return relatedFiles; }
595                 }
596                 
597                 [Output]
598                 public ITaskItem[] ResolvedDependencyFiles {
599                         get { return resolvedDependencyFiles; }
600                 }
601                 
602                 [Output]
603                 public ITaskItem[] ResolvedFiles {
604                         get { return resolvedFiles; }
605                 }
606                 
607                 [Output]
608                 public ITaskItem[] SatelliteFiles {
609                         get { return satelliteFiles; }
610                 }
611                 
612                 [Output]
613                 public ITaskItem[] ScatterFiles {
614                         get { return scatterFiles; }
615                 }
616                 
617                 [Required]
618                 public string[] SearchPaths {
619                         get { return searchPaths; }
620                         set { searchPaths = value; }
621                 }
622                 
623                 [Output]
624                 public ITaskItem[] SerializationAssemblyFiles {
625                         get { return serializationAssemblyFiles; }
626                 }
627                 
628                 public bool Silent {
629                         get { return silent; }
630                         set { silent = value; }
631                 }
632                 
633                 public string StateFile {
634                         get { return stateFile; }
635                         set { stateFile = value; }
636                 }
637                 
638                 [Output]
639                 public ITaskItem[] SuggestedRedirects {
640                         get { return suggestedRedirects; }
641                 }
642                 
643                 public string[] TargetFrameworkDirectories {
644                         get { return targetFrameworkDirectories; }
645                         set { targetFrameworkDirectories = value; }
646                 }
647                 
648                 public string TargetProcessorArchitecture {
649                         get { return targetProcessorArchitecture; }
650                         set { targetProcessorArchitecture = value; }
651                 }
652
653                 static Dictionary<string, string> cultureNamesTable;
654                 static Dictionary<string, string> CultureNamesTable {
655                         get {
656                                 if (cultureNamesTable == null) {
657                                         cultureNamesTable = new Dictionary<string, string> ();
658                                         foreach (CultureInfo ci in CultureInfo.GetCultures (CultureTypes.AllCultures))
659                                                 cultureNamesTable [ci.Name] = ci.Name;
660                                 }
661
662                                 return cultureNamesTable;
663                         }
664                 }
665         }
666
667         static class ResolveAssemblyReferenceHelper {
668                 public static void AddUniqueFile (this Dictionary<string, ITaskItem> dic, ITaskItem item)
669                 {
670                         if (dic == null)
671                                 throw new ArgumentNullException ("dic");
672                         if (item == null)
673                                 throw new ArgumentNullException ("item");
674
675                         string fullpath = Path.GetFullPath (item.ItemSpec);
676                         if (!dic.ContainsKey (fullpath))
677                                 dic [fullpath] = item;
678                 }
679         }
680
681         struct PrimaryReference {
682                 public ITaskItem TaskItem;
683                 public string ParentCopyLocal;
684
685                 public PrimaryReference (ITaskItem item, string parent_copy_local)
686                 {
687                         TaskItem = item;
688                         ParentCopyLocal = parent_copy_local;
689                 }
690         }
691
692 }
693
694 #endif