copied mono-api-diff.cs from mono-2-2 branch so new patch can be applied and history...
[mono.git] / mcs / class / Microsoft.Build.Tasks / Microsoft.Build.Tasks / LibraryPcFileCache.cs
1 // 
2 // PcFileCacheAssembly.cs
3 //  
4 // Author:
5 //       Lluis Sanchez Gual <lluis@novell.com>
6 // 
7 // Copyright (c) 2009 Novell, Inc (http://www.novell.com)
8 // 
9 // Permission is hereby granted, free of charge, to any person obtaining a copy
10 // of this software and associated documentation files (the "Software"), to deal
11 // in the Software without restriction, including without limitation the rights
12 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 // copies of the Software, and to permit persons to whom the Software is
14 // furnished to do so, subject to the following conditions:
15 // 
16 // The above copyright notice and this permission notice shall be included in
17 // all copies or substantial portions of the Software.
18 // 
19 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 // THE SOFTWARE.
26
27 using System;
28 using System.Text;
29 using System.Xml;
30 using System.IO;
31 using System.Collections.Generic;
32
33 namespace Mono.PkgConfig
34 {
35         internal class LibraryPcFileCache: PcFileCache<LibraryPackageInfo>
36         {
37                 Dictionary<string, PackageAssemblyInfo> assemblyLocations;
38                 
39                 public LibraryPcFileCache (IPcFileCacheContext<LibraryPackageInfo> ctx): base (ctx)
40                 {
41                 }
42                 
43                 protected override string CacheDirectory {
44                         get {
45                                 string path = Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData);
46                                 path = Path.Combine (path, "xbuild");
47                                 return path;
48                         }
49                 }
50                 
51                 // Returns the location of an assembly, given the full name
52                 public PackageAssemblyInfo GetAssemblyLocation (string fullName)
53                 {
54                         return GetAssemblyLocation (fullName, null);
55                 }
56                 
57                 public PackageAssemblyInfo GetAssemblyLocation (string fullName, IEnumerable<string> searchPaths)
58                 {
59                         lock (SyncRoot) {
60                                 if (assemblyLocations == null) {
61                                         // Populate on demand
62                                         assemblyLocations = new Dictionary<string, PackageAssemblyInfo> ();
63                                         foreach (LibraryPackageInfo info in GetPackages (searchPaths)) {
64                                                 if (info.IsValidPackage) {
65                                                         foreach (PackageAssemblyInfo asm in info.Assemblies)
66                                                                 assemblyLocations [NormalizeAsmName (asm.FullName)] = asm;
67                                                 }
68                                         }
69                                 }
70                         }
71                         // This collection is read-only once built, so there is no need for a lock
72                         PackageAssemblyInfo pasm;
73                         assemblyLocations.TryGetValue (NormalizeAsmName (fullName), out pasm);
74                         return pasm;
75                 }
76                 
77                 public IEnumerable<PackageAssemblyInfo> ResolveAssemblyName (string name)
78                 {
79                         return ResolveAssemblyName (name, null);
80                 }
81                 
82                 public IEnumerable<PackageAssemblyInfo> ResolveAssemblyName (string name, IEnumerable<string> searchPaths)
83                 {
84                         foreach (LibraryPackageInfo pinfo in GetPackages (searchPaths)) {
85                                 if (pinfo.IsValidPackage) {
86                                         foreach (PackageAssemblyInfo asm in pinfo.Assemblies) {
87                                                 if (asm.Name == name)
88                                                         yield return asm;
89                                         }
90                                 }
91                         }
92                 }
93                 
94                 protected override void WritePackageContent (XmlTextWriter tw, string file, LibraryPackageInfo pinfo)
95                 {
96                         foreach (PackageAssemblyInfo asm in pinfo.Assemblies) {
97                                 tw.WriteStartElement ("Assembly");
98                                 tw.WriteAttributeString ("name", asm.Name);
99                                 tw.WriteAttributeString ("version", asm.Version);
100                                 tw.WriteAttributeString ("culture", asm.Culture);
101                                 tw.WriteAttributeString ("publicKeyToken", asm.PublicKeyToken);
102                                 tw.WriteAttributeString ("file", asm.File);
103                                 tw.WriteEndElement (); // Assembly
104                         }
105                 }
106                 
107                 protected override void ReadPackageContent (XmlReader tr, LibraryPackageInfo pinfo)
108                 {
109                         while (tr.NodeType == XmlNodeType.Element) {
110                                 PackageAssemblyInfo asm = new PackageAssemblyInfo ();
111                                 asm.Name = tr.GetAttribute ("name");
112                                 asm.Version = tr.GetAttribute ("version");
113                                 asm.Culture = tr.GetAttribute ("culture");
114                                 asm.PublicKeyToken = tr.GetAttribute ("publicKeyToken");
115                                 asm.File = tr.GetAttribute ("file");
116                                 if (pinfo.Assemblies == null)
117                                         pinfo.Assemblies = new List<PackageAssemblyInfo> ();
118                                 asm.ParentPackage = pinfo;
119                                 pinfo.Assemblies.Add (asm);
120                                 tr.Read ();
121                                 tr.MoveToContent ();
122                         }
123                 }
124                 
125                 protected override void ParsePackageInfo (PcFile file, LibraryPackageInfo pinfo)
126                 {
127                         List<string> fullassemblies = null;
128                         bool gacPackageSet = false;
129                         
130                         if (file.Libs != null && file.Libs.IndexOf (".dll") != -1) {
131                                 if (file.Libs.IndexOf ("-lib:") != -1 || file.Libs.IndexOf ("/lib:") != -1) {
132                                         fullassemblies = GetAssembliesWithLibInfo (file.Libs);
133                                 } else {
134                                         fullassemblies = GetAssembliesWithoutLibInfo (file.Libs);
135                                 }
136                         }
137                         
138                         string value = file.GetVariable ("Libraries");
139                         if (!string.IsNullOrEmpty (value))
140                                 fullassemblies = GetAssembliesFromLibrariesVar (value);
141                         
142                         value = file.GetVariable ("GacPackage");
143                         if (value != null) {
144                                 value = value.ToLower ();
145                                 pinfo.IsGacPackage = value == "yes" || value == "true";
146                                 gacPackageSet = true;
147                         }
148         
149                         if (fullassemblies == null)
150                                 return;
151                         
152                         string pcDir = Path.GetDirectoryName (file.FilePath);
153                         string monoPrefix = Path.GetDirectoryName (Path.GetDirectoryName (pcDir));
154                         monoPrefix = Path.GetFullPath (monoPrefix + Path.DirectorySeparatorChar + "lib" + Path.DirectorySeparatorChar + "mono" + Path.DirectorySeparatorChar);
155
156                         List<PackageAssemblyInfo> list = new List<PackageAssemblyInfo> ();
157                         foreach (string assembly in fullassemblies) {
158                                 string asm;
159                                 if (Path.IsPathRooted (assembly))
160                                         asm = Path.GetFullPath (assembly);
161                                 else {
162                                         if (Path.GetDirectoryName (assembly).Length == 0) {
163                                                 asm = assembly;
164                                         } else {
165                                                 asm = Path.GetFullPath (Path.Combine (pcDir, assembly));
166                                         }
167                                 }
168                                 if (File.Exists (asm)) {
169                                         PackageAssemblyInfo pi = new PackageAssemblyInfo ();
170                                         pi.File = asm;
171                                         pi.ParentPackage = pinfo;
172                                         pi.UpdateFromFile (pi.File);
173                                         list.Add (pi);
174                                         if (!gacPackageSet && !asm.StartsWith (monoPrefix) && Path.IsPathRooted (asm)) {
175                                                 // Assembly installed outside $(prefix)/lib/mono. It is most likely not a gac package.
176                                                 gacPackageSet = true;
177                                                 pinfo.IsGacPackage = false;
178                                         }
179                                 }
180                         }
181                         pinfo.Assemblies = list;
182                 }
183                 
184                 private List<string> GetAssembliesWithLibInfo (string line)
185                 {
186                         List<string> references = new List<string> ();
187                         List<string> libdirs = new List<string> ();
188                         List<string> retval = new List<string> ();
189                         foreach (string piece in line.Split (' ')) {
190                                 if (piece.ToLower ().Trim ().StartsWith ("/r:") || piece.ToLower ().Trim ().StartsWith ("-r:")) {
191                                         references.Add (piece.Substring (3).Trim ());
192                                 } else if (piece.ToLower ().Trim ().StartsWith ("/lib:") || piece.ToLower ().Trim ().StartsWith ("-lib:")) {
193                                         libdirs.Add (piece.Substring (5).Trim ());
194                                 }
195                         }
196         
197                         foreach (string refrnc in references) {
198                                 foreach (string libdir in libdirs) {
199                                         if (File.Exists (libdir + Path.DirectorySeparatorChar + refrnc)) {
200                                                 retval.Add (libdir + Path.DirectorySeparatorChar + refrnc);
201                                         }
202                                 }
203                         }
204         
205                         return retval;
206                 }
207                 
208                 List<string> GetAssembliesFromLibrariesVar (string line)
209                 {
210                         List<string> references = new List<string> ();
211                         foreach (string reference in line.Split (' ')) {
212                                 if (!string.IsNullOrEmpty (reference))
213                                         references.Add (reference);
214                         }
215                         return references;
216                 }
217         
218                 private List<string> GetAssembliesWithoutLibInfo (string line)
219                 {
220                         List<string> references = new List<string> ();
221                         foreach (string reference in line.Split (' ')) {
222                                 if (reference.ToLower ().Trim ().StartsWith ("/r:") || reference.ToLower ().Trim ().StartsWith ("-r:")) {
223                                         string final_ref = reference.Substring (3).Trim ();
224                                         references.Add (final_ref);
225                                 }
226                         }
227                         return references;
228                 }
229                 
230                 public static string NormalizeAsmName (string name)
231                 {
232                         int i = name.ToLower ().IndexOf (", publickeytoken=null");
233                         if (i != -1)
234                                 name = name.Substring (0, i).Trim ();
235                         i = name.ToLower ().IndexOf (", processorarchitecture=");
236                         if (i != -1)
237                                 name = name.Substring (0, i).Trim ();
238                         return name;
239                 }
240         }
241         
242         internal class LibraryPackageInfo: PackageInfo
243         {
244                 public bool IsGacPackage {
245                         get { return GetData ("gacPackage") != "false"; }
246                         set {
247                                 if (value)
248                                         RemoveData ("gacPackage");
249                                 else
250                                         SetData ("gacPackage", "false");
251                         }
252                 }
253                 
254                 internal List<PackageAssemblyInfo> Assemblies { get; set; }
255                 
256                 internal protected override bool IsValidPackage {
257                         get { return Assemblies != null && Assemblies.Count > 0; }
258                 }
259         }
260         
261         internal class PackageAssemblyInfo
262         {
263                 public string File { get; set; }
264                 
265                 public string Name;
266                 
267                 public string Version;
268                 
269                 public string Culture;
270                 
271                 public string PublicKeyToken;
272                 
273                 public string FullName {
274                         get {
275                                 string fn = Name + ", Version=" + Version;
276                                 if (!string.IsNullOrEmpty (Culture))
277                                         fn += ", Culture=" + Culture;
278                                 if (!string.IsNullOrEmpty (PublicKeyToken))
279                                         fn += ", PublicKeyToken=" + PublicKeyToken;
280                                 return fn;
281                         }
282                 }
283                 
284                 public LibraryPackageInfo ParentPackage { get; set; }
285                 
286                 public void UpdateFromFile (string file)
287                 {
288                         Update (System.Reflection.AssemblyName.GetAssemblyName (file));
289                 }
290                 
291                 public void Update (System.Reflection.AssemblyName aname)
292                 {
293                         Name = aname.Name;
294                         Version = aname.Version.ToString ();
295                         if (aname.CultureInfo != null) {
296                                 if (aname.CultureInfo.LCID == System.Globalization.CultureInfo.InvariantCulture.LCID)
297                                         Culture = "neutral";
298                                 else
299                                         Culture = aname.CultureInfo.Name;
300                         }
301                         string fn = aname.ToString ();
302                         string key = "publickeytoken=";
303                         int i = fn.ToLower().IndexOf (key) + key.Length;
304                         int j = fn.IndexOf (',', i);
305                         if (j == -1) j = fn.Length;
306                         PublicKeyToken = fn.Substring (i, j - i);
307                 }
308         }
309 }