* LibraryPcFileCache.cs: New. From monodevelop.
authorAnkit Jain <radical@corewars.org>
Mon, 24 Aug 2009 18:13:42 +0000 (18:13 -0000)
committerAnkit Jain <radical@corewars.org>
Mon, 24 Aug 2009 18:13:42 +0000 (18:13 -0000)
* PcFileCache.cs: Update from monodevelop, see r140528.
* AssemblyResolver.cs: Track api changes.

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

mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks.dll.sources
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/LibraryPcFileCache.cs [new file with mode: 0644]
mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks/PcFileCache.cs

index 3fcfd02c95f9ca758d4b88c688c039bdfce74ba2..2000633ab5bd76c8f45dc466b3e1fabc54d872bc 100644 (file)
@@ -85,6 +85,7 @@ Microsoft.Build.Tasks/ManagedCompiler.cs
 Microsoft.Build.Tasks/Message.cs
 Microsoft.Build.Tasks/MSBuild.cs
 Microsoft.Build.Tasks/PcFileCache.cs
+Microsoft.Build.Tasks/LibraryPcFileCache.cs
 Microsoft.Build.Tasks/ReadLinesFromFile.cs
 Microsoft.Build.Tasks/RegisterAssembly.cs
 Microsoft.Build.Tasks/RemoveDir.cs
index a3ebe27d1bed14425196f3fbc925feb521290864..93ad81648905efc0eb597b4b85e87a3fcd513222 100644 (file)
@@ -48,7 +48,7 @@ namespace Microsoft.Build.Tasks {
                TaskLoggingHelper log;
                StringWriter sw;
 
-               static PcFileCache cache;
+               static LibraryPcFileCache cache;
 
                public AssemblyResolver ()
                {
@@ -378,11 +378,11 @@ namespace Microsoft.Build.Tasks {
                        }
                }
 
-               static PcFileCache PcCache  {
+               static LibraryPcFileCache PcCache  {
                        get {
                                if (cache == null) {
-                                       PcFileCacheContext context = new PcFileCacheContext ();
-                                       cache = new PcFileCache (context);
+                                       var context = new PcFileCacheContext ();
+                                       cache = new LibraryPcFileCache (context);
                                        cache.Update ();
                                }
 
@@ -405,19 +405,19 @@ namespace Microsoft.Build.Tasks {
                }
        }
 
-       class PcFileCacheContext : IPcFileCacheContext
+       class PcFileCacheContext : IPcFileCacheContext<LibraryPackageInfo>
        {
                public static TaskLoggingHelper Log;
 
                // In the implementation of this method, the host application can extract
                // information from the pc file and store it in the PackageInfo object
-               public void StoreCustomData (PcFile pcfile, PackageInfo pkg)
+               public void StoreCustomData (PcFile pcfile, LibraryPackageInfo pkg)
                {
                }
 
                // Should return false if the provided package does not have required
                // custom data
-               public bool IsCustomDataComplete (string pcfile, PackageInfo pkg)
+               public bool IsCustomDataComplete (string pcfile, LibraryPackageInfo pkg)
                {
                        return true;
                }
index 7e308e3affce96a6bf9bcba0dbfb4ede2cc323bf..8a325f573c4545dad4994d0a96042338c551925e 100644 (file)
@@ -1,3 +1,9 @@
+2009-08-24  Ankit Jain  <jankit@novell.com>
+
+       * LibraryPcFileCache.cs: New. From monodevelop.
+       * PcFileCache.cs: Update from monodevelop, see r140528.
+       * AssemblyResolver.cs: Track api changes.
+
 2009-08-24  Ankit Jain  <jankit@novell.com>
 
        * CreateManifestResourceName.cs (GetResourceIdFromFileName): Spaces
diff --git a/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks/LibraryPcFileCache.cs b/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks/LibraryPcFileCache.cs
new file mode 100644 (file)
index 0000000..3eaa214
--- /dev/null
@@ -0,0 +1,309 @@
+// 
+// PcFileCacheAssembly.cs
+//  
+// Author:
+//       Lluis Sanchez Gual <lluis@novell.com>
+// 
+// Copyright (c) 2009 Novell, Inc (http://www.novell.com)
+// 
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+// 
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+using System.Text;
+using System.Xml;
+using System.IO;
+using System.Collections.Generic;
+
+namespace Mono.PkgConfig
+{
+       internal class LibraryPcFileCache: PcFileCache<LibraryPackageInfo>
+       {
+               Dictionary<string, PackageAssemblyInfo> assemblyLocations;
+               
+               public LibraryPcFileCache (IPcFileCacheContext<LibraryPackageInfo> ctx): base (ctx)
+               {
+               }
+               
+               protected override string CacheDirectory {
+                       get {
+                               string path = Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData);
+                               path = Path.Combine (path, "xbuild");
+                               return path;
+                       }
+               }
+               
+               // Returns the location of an assembly, given the full name
+               public PackageAssemblyInfo GetAssemblyLocation (string fullName)
+               {
+                       return GetAssemblyLocation (fullName, null);
+               }
+               
+               public PackageAssemblyInfo GetAssemblyLocation (string fullName, IEnumerable<string> searchPaths)
+               {
+                       lock (SyncRoot) {
+                               if (assemblyLocations == null) {
+                                       // Populate on demand
+                                       assemblyLocations = new Dictionary<string, PackageAssemblyInfo> ();
+                                       foreach (LibraryPackageInfo info in GetPackages (searchPaths)) {
+                                               if (info.IsValidPackage) {
+                                                       foreach (PackageAssemblyInfo asm in info.Assemblies)
+                                                               assemblyLocations [NormalizeAsmName (asm.FullName)] = asm;
+                                               }
+                                       }
+                               }
+                       }
+                       // This collection is read-only once built, so there is no need for a lock
+                       PackageAssemblyInfo pasm;
+                       assemblyLocations.TryGetValue (NormalizeAsmName (fullName), out pasm);
+                       return pasm;
+               }
+               
+               public IEnumerable<PackageAssemblyInfo> ResolveAssemblyName (string name)
+               {
+                       return ResolveAssemblyName (name, null);
+               }
+               
+               public IEnumerable<PackageAssemblyInfo> ResolveAssemblyName (string name, IEnumerable<string> searchPaths)
+               {
+                       foreach (LibraryPackageInfo pinfo in GetPackages (searchPaths)) {
+                               if (pinfo.IsValidPackage) {
+                                       foreach (PackageAssemblyInfo asm in pinfo.Assemblies) {
+                                               if (asm.Name == name)
+                                                       yield return asm;
+                                       }
+                               }
+                       }
+               }
+               
+               protected override void WritePackageContent (XmlTextWriter tw, string file, LibraryPackageInfo pinfo)
+               {
+                       foreach (PackageAssemblyInfo asm in pinfo.Assemblies) {
+                               tw.WriteStartElement ("Assembly");
+                               tw.WriteAttributeString ("name", asm.Name);
+                               tw.WriteAttributeString ("version", asm.Version);
+                               tw.WriteAttributeString ("culture", asm.Culture);
+                               tw.WriteAttributeString ("publicKeyToken", asm.PublicKeyToken);
+                               tw.WriteAttributeString ("file", asm.File);
+                               tw.WriteEndElement (); // Assembly
+                       }
+               }
+               
+               protected override void ReadPackageContent (XmlReader tr, LibraryPackageInfo pinfo)
+               {
+                       while (tr.NodeType == XmlNodeType.Element) {
+                               PackageAssemblyInfo asm = new PackageAssemblyInfo ();
+                               asm.Name = tr.GetAttribute ("name");
+                               asm.Version = tr.GetAttribute ("version");
+                               asm.Culture = tr.GetAttribute ("culture");
+                               asm.PublicKeyToken = tr.GetAttribute ("publicKeyToken");
+                               asm.File = tr.GetAttribute ("file");
+                               if (pinfo.Assemblies == null)
+                                       pinfo.Assemblies = new List<PackageAssemblyInfo> ();
+                               asm.ParentPackage = pinfo;
+                               pinfo.Assemblies.Add (asm);
+                               tr.Read ();
+                               tr.MoveToContent ();
+                       }
+               }
+               
+               protected override void ParsePackageInfo (PcFile file, LibraryPackageInfo pinfo)
+               {
+                       List<string> fullassemblies = null;
+                       bool gacPackageSet = false;
+                       
+                       if (file.Libs != null && file.Libs.IndexOf (".dll") != -1) {
+                               if (file.Libs.IndexOf ("-lib:") != -1 || file.Libs.IndexOf ("/lib:") != -1) {
+                                       fullassemblies = GetAssembliesWithLibInfo (file.Libs);
+                               } else {
+                                       fullassemblies = GetAssembliesWithoutLibInfo (file.Libs);
+                               }
+                       }
+                       
+                       string value = file.GetVariable ("Libraries");
+                       if (!string.IsNullOrEmpty (value))
+                               fullassemblies = GetAssembliesFromLibrariesVar (value);
+                       
+                       value = file.GetVariable ("GacPackage");
+                       if (value != null) {
+                               value = value.ToLower ();
+                               pinfo.IsGacPackage = value == "yes" || value == "true";
+                               gacPackageSet = true;
+                       }
+       
+                       if (fullassemblies == null)
+                               return;
+                       
+                       string pcDir = Path.GetDirectoryName (file.FilePath);
+                       string monoPrefix = Path.GetDirectoryName (Path.GetDirectoryName (pcDir));
+                       monoPrefix = Path.GetFullPath (monoPrefix + Path.DirectorySeparatorChar + "lib" + Path.DirectorySeparatorChar + "mono" + Path.DirectorySeparatorChar);
+
+                       List<PackageAssemblyInfo> list = new List<PackageAssemblyInfo> ();
+                       foreach (string assembly in fullassemblies) {
+                               string asm;
+                               if (Path.IsPathRooted (assembly))
+                                       asm = Path.GetFullPath (assembly);
+                               else {
+                                       if (Path.GetDirectoryName (assembly).Length == 0) {
+                                               asm = assembly;
+                                       } else {
+                                               asm = Path.GetFullPath (Path.Combine (pcDir, assembly));
+                                       }
+                               }
+                               if (File.Exists (asm)) {
+                                       PackageAssemblyInfo pi = new PackageAssemblyInfo ();
+                                       pi.File = asm;
+                                       pi.ParentPackage = pinfo;
+                                       pi.UpdateFromFile (pi.File);
+                                       list.Add (pi);
+                                       if (!gacPackageSet && !asm.StartsWith (monoPrefix) && Path.IsPathRooted (asm)) {
+                                               // Assembly installed outside $(prefix)/lib/mono. It is most likely not a gac package.
+                                               gacPackageSet = true;
+                                               pinfo.IsGacPackage = false;
+                                       }
+                               }
+                       }
+                       pinfo.Assemblies = list;
+               }
+               
+               private List<string> GetAssembliesWithLibInfo (string line)
+               {
+                       List<string> references = new List<string> ();
+                       List<string> libdirs = new List<string> ();
+                       List<string> retval = new List<string> ();
+                       foreach (string piece in line.Split (' ')) {
+                               if (piece.ToLower ().Trim ().StartsWith ("/r:") || piece.ToLower ().Trim ().StartsWith ("-r:")) {
+                                       references.Add (piece.Substring (3).Trim ());
+                               } else if (piece.ToLower ().Trim ().StartsWith ("/lib:") || piece.ToLower ().Trim ().StartsWith ("-lib:")) {
+                                       libdirs.Add (piece.Substring (5).Trim ());
+                               }
+                       }
+       
+                       foreach (string refrnc in references) {
+                               foreach (string libdir in libdirs) {
+                                       if (File.Exists (libdir + Path.DirectorySeparatorChar + refrnc)) {
+                                               retval.Add (libdir + Path.DirectorySeparatorChar + refrnc);
+                                       }
+                               }
+                       }
+       
+                       return retval;
+               }
+               
+               List<string> GetAssembliesFromLibrariesVar (string line)
+               {
+                       List<string> references = new List<string> ();
+                       foreach (string reference in line.Split (' ')) {
+                               if (!string.IsNullOrEmpty (reference))
+                                       references.Add (reference);
+                       }
+                       return references;
+               }
+       
+               private List<string> GetAssembliesWithoutLibInfo (string line)
+               {
+                       List<string> references = new List<string> ();
+                       foreach (string reference in line.Split (' ')) {
+                               if (reference.ToLower ().Trim ().StartsWith ("/r:") || reference.ToLower ().Trim ().StartsWith ("-r:")) {
+                                       string final_ref = reference.Substring (3).Trim ();
+                                       references.Add (final_ref);
+                               }
+                       }
+                       return references;
+               }
+               
+               public static string NormalizeAsmName (string name)
+               {
+                       int i = name.ToLower ().IndexOf (", publickeytoken=null");
+                       if (i != -1)
+                               name = name.Substring (0, i).Trim ();
+                       i = name.ToLower ().IndexOf (", processorarchitecture=");
+                       if (i != -1)
+                               name = name.Substring (0, i).Trim ();
+                       return name;
+               }
+       }
+       
+       internal class LibraryPackageInfo: PackageInfo
+       {
+               public bool IsGacPackage {
+                       get { return GetData ("gacPackage") != "false"; }
+                       set {
+                               if (value)
+                                       RemoveData ("gacPackage");
+                               else
+                                       SetData ("gacPackage", "false");
+                       }
+               }
+               
+               internal List<PackageAssemblyInfo> Assemblies { get; set; }
+               
+               internal protected override bool IsValidPackage {
+                       get { return Assemblies != null && Assemblies.Count > 0; }
+               }
+       }
+       
+       internal class PackageAssemblyInfo
+       {
+               public string File { get; set; }
+               
+               public string Name;
+               
+               public string Version;
+               
+               public string Culture;
+               
+               public string PublicKeyToken;
+               
+               public string FullName {
+                       get {
+                               string fn = Name + ", Version=" + Version;
+                               if (!string.IsNullOrEmpty (Culture))
+                                       fn += ", Culture=" + Culture;
+                               if (!string.IsNullOrEmpty (PublicKeyToken))
+                                       fn += ", PublicKeyToken=" + PublicKeyToken;
+                               return fn;
+                       }
+               }
+               
+               public LibraryPackageInfo ParentPackage { get; set; }
+               
+               public void UpdateFromFile (string file)
+               {
+                       Update (System.Reflection.AssemblyName.GetAssemblyName (file));
+               }
+               
+               public void Update (System.Reflection.AssemblyName aname)
+               {
+                       Name = aname.Name;
+                       Version = aname.Version.ToString ();
+                       if (aname.CultureInfo != null) {
+                               if (aname.CultureInfo.LCID == System.Globalization.CultureInfo.InvariantCulture.LCID)
+                                       Culture = "neutral";
+                               else
+                                       Culture = aname.CultureInfo.Name;
+                       }
+                       string fn = aname.ToString ();
+                       string key = "publickeytoken=";
+                       int i = fn.ToLower().IndexOf (key) + key.Length;
+                       int j = fn.IndexOf (',', i);
+                       if (j == -1) j = fn.Length;
+                       PublicKeyToken = fn.Substring (i, j - i);
+               }
+       }
+}
index 63cda26392300991632b72887b181acbc8a029a3..f77a5ae80726f4fc34b33816a6de13956c8817d4 100644 (file)
@@ -32,36 +32,48 @@ using System.Collections.Generic;
 
 namespace Mono.PkgConfig
 {
-       internal interface IPcFileCacheContext
+       internal interface IPcFileCacheContext<TP> where TP:PackageInfo, new()
        {
                // In the implementation of this method, the host application can extract
                // information from the pc file and store it in the PackageInfo object
-               void StoreCustomData (PcFile pcfile, PackageInfo pkg);
+               void StoreCustomData (PcFile pcfile, TP pkg);
                
                // Should return false if the provided package does not have required
                // custom data
-               bool IsCustomDataComplete (string pcfile, PackageInfo pkg);
+               bool IsCustomDataComplete (string pcfile, TP pkg);
                
                // Called to report errors
                void ReportError (string message, Exception ex);
        }
        
-       internal class PcFileCache
+       internal interface IPcFileCacheContext: IPcFileCacheContext<PackageInfo>
+       {
+       }
+       
+       internal abstract class PcFileCache: PcFileCache<PackageInfo>
+       {
+               public PcFileCache (IPcFileCacheContext ctx): base (ctx)
+               {
+               }
+       }
+       
+       internal abstract class PcFileCache<TP> where TP:PackageInfo, new()
        {
                const string CACHE_VERSION = "2";
                
-               Dictionary<string, PackageInfo> infos = new Dictionary<string, PackageInfo> ();
-               Dictionary<string, PackageAssemblyInfo> assemblyLocations;
+               Dictionary<string, TP> infos = new Dictionary<string, TP> ();
+               Dictionary<string, List<TP>> filesByFolder = new Dictionary<string, List<TP>> ();
+               
                string cacheFile;
                bool hasChanges;
-               IPcFileCacheContext ctx;
+               IPcFileCacheContext<TP> ctx;
+               IEnumerable<string> defaultPaths;
                
-               public PcFileCache (IPcFileCacheContext ctx)
+               public PcFileCache (IPcFileCacheContext<TP> ctx)
                {
                        this.ctx = ctx;
                        try {
-                               string path = Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData);
-                               path = Path.Combine (path, "xbuild");
+                               string path = CacheDirectory;
                                if (!Directory.Exists (path))
                                        Directory.CreateDirectory (path);
                                cacheFile = Path.Combine (path, "pkgconfig-cache-" + CACHE_VERSION + ".xml");
@@ -74,12 +86,12 @@ namespace Mono.PkgConfig
                        }
                }
                
+               protected abstract string CacheDirectory { get; }
+               
                // Updates the pkg-config index, using the default search directories
                public void Update ()
                {
-                       string pkgConfigPath = Environment.GetEnvironmentVariable ("PKG_CONFIG_PATH");
-                       string pkgConfigDir = Environment.GetEnvironmentVariable ("PKG_CONFIG_LIBDIR");
-                       Update (GetPkgconfigPaths (null, pkgConfigPath, pkgConfigDir));
+                       Update (GetDefaultPaths ());
                }
 
                // Updates the pkg-config index, looking for .pc files in the provided directories
@@ -92,43 +104,42 @@ namespace Mono.PkgConfig
                        Save ();
                }
                
-               // Returns the location of an assembly, given the full name
-               public PackageAssemblyInfo GetAssemblyLocation (string fullName)
+               public IEnumerable<TP> GetPackages ()
                {
-                       lock (infos) {
-                               if (assemblyLocations == null) {
-                                       // Populate on demand
-                                       assemblyLocations = new Dictionary<string, PackageAssemblyInfo> ();
-                                       foreach (PackageInfo info in infos.Values) {
-                                               if (info.IsValidPackage) {
-                                                       foreach (PackageAssemblyInfo asm in info.Assemblies)
-                                                               assemblyLocations [NormalizeAsmName (asm.FullName)] = asm;
-                                               }
-                                       }
-                               }
-                       }
-                       // This collection is read-only once built, so there is no need for a lock
-                       PackageAssemblyInfo pasm;
-                       assemblyLocations.TryGetValue (NormalizeAsmName (fullName), out pasm);
-                       return pasm;
+                       return GetPackages (null);
                }
                
-               public IEnumerable<PackageAssemblyInfo> ResolveAssemblyName (string name)
+               public IEnumerable<TP> GetPackages (IEnumerable<string> pkgConfigDirs)
                {
-                       foreach (PackageInfo pinfo in infos.Values) {
-                               if (pinfo.IsValidPackage) {
-                                       foreach (PackageAssemblyInfo asm in pinfo.Assemblies) {
-                                               if (asm.Name == name)
-                                                       yield return asm;
-                                       }
+                       if (pkgConfigDirs == null)
+                               pkgConfigDirs = GetDefaultPaths ();
+
+                       foreach (string sp in pkgConfigDirs) {
+                               List<TP> list;
+                               if (filesByFolder.TryGetValue (Path.GetFullPath (sp), out list)) {
+                                       foreach (TP p in list)
+                                               yield return p;
                                }
                        }
                }
                
+               public TP GetPackageInfoByName (string name)
+               {
+                       return GetPackageInfoByName (name, null);
+               }
+               
+               public TP GetPackageInfoByName (string name, IEnumerable<string> pkgConfigDirs)
+               {
+                       foreach (TP p in GetPackages (pkgConfigDirs))
+                               if (p.Name == name)
+                                       return p;
+                       return null;
+               }
+               
                // Returns information about a .pc file
-               public PackageInfo GetPackageInfo (string file)
+               public TP GetPackageInfo (string file)
                {
-                       PackageInfo info;
+                       TP info, oldInfo = null;
                        file = Path.GetFullPath (file);
                        
                        DateTime wtime = File.GetLastWriteTime (file);
@@ -137,6 +148,7 @@ namespace Mono.PkgConfig
                                if (infos.TryGetValue (file, out info)) {
                                        if (info.LastWriteTime == wtime)
                                                return info;
+                                       oldInfo = info;
                                }
                        }
 
@@ -144,20 +156,39 @@ namespace Mono.PkgConfig
                                info = ParsePackageInfo (file);
                        } catch (Exception ex) {
                                ctx.ReportError ("Error while parsing .pc file", ex);
-                               info = new PackageInfo ();
+                               info = new TP ();
                        }
                        
                        lock (infos) {
                                if (!info.IsValidPackage)
-                                       info = new PackageInfo (); // Create a default empty instance
+                                       info = new TP (); // Create a default empty instance
                                info.LastWriteTime = wtime;
-                               infos [file] = info;
+                               Add (file, info, oldInfo);
                                hasChanges = true;
                        }
                        
                        return info;
                }
                
+               void Add (string file, TP info, TP replacedInfo)
+               {
+                       infos [file] = info;
+                       string dir = Path.GetFullPath (Path.GetDirectoryName (file));
+                       List<TP> list;
+                       if (!filesByFolder.TryGetValue (dir, out list)) {
+                               list = new List<TP> ();
+                               filesByFolder [dir] = list;
+                       }
+                       if (replacedInfo != null) {
+                               int i = list.IndexOf (replacedInfo);
+                               if (i != -1) {
+                                       list [i] = info;
+                                       return;
+                               }
+                       }
+                       list.Add (info);
+               }
+               
                FileStream OpenFile (FileAccess access)
                {
                        int retries = 6;
@@ -208,7 +239,7 @@ namespace Mono.PkgConfig
                                        tw.Formatting = Formatting.Indented;
                                        
                                        tw.WriteStartElement ("PcFileCache");
-                                       foreach (KeyValuePair<string,PackageInfo> file in infos) {
+                                       foreach (KeyValuePair<string,TP> file in infos) {
                                                WritePackage (tw, file.Key, file.Value);
                                        }
                                        tw.WriteEndElement (); // PcFileCache
@@ -219,7 +250,7 @@ namespace Mono.PkgConfig
                        }
                }
                
-               void WritePackage (XmlTextWriter tw, string file, PackageInfo pinfo)
+               void WritePackage (XmlTextWriter tw, string file, TP pinfo)
                {
                        tw.WriteStartElement ("File");
                        tw.WriteAttributeString ("path", file);
@@ -232,28 +263,22 @@ namespace Mono.PkgConfig
                                        tw.WriteAttributeString ("version", pinfo.Version);
                                if (!string.IsNullOrEmpty (pinfo.Description))
                                        tw.WriteAttributeString ("description", pinfo.Description);
-                               if (!pinfo.IsGacPackage)
-                                       tw.WriteAttributeString ("gacPackage", "false");
                                if (pinfo.CustomData != null) {
                                        foreach (KeyValuePair<string,string> cd in pinfo.CustomData)
                                                tw.WriteAttributeString (cd.Key, cd.Value);
                                }
-                               foreach (PackageAssemblyInfo asm in pinfo.Assemblies) {
-                                       tw.WriteStartElement ("Assembly");
-                                       tw.WriteAttributeString ("name", asm.Name);
-                                       tw.WriteAttributeString ("version", asm.Version);
-                                       tw.WriteAttributeString ("culture", asm.Culture);
-                                       tw.WriteAttributeString ("publicKeyToken", asm.PublicKeyToken);
-                                       tw.WriteAttributeString ("file", asm.File);
-                                       tw.WriteEndElement (); // Assembly
-                               }
+                               WritePackageContent (tw, file, pinfo);
                        }
                        tw.WriteEndElement (); // File
                }
                
+               protected virtual void WritePackageContent (XmlTextWriter tw, string file, TP pinfo)
+               {
+               }
+               
                void ReadPackage (XmlReader tr)
                {
-                       PackageInfo pinfo = new PackageInfo ();
+                       TP pinfo = new TP ();
                        string file = null;
                        
                        tr.MoveToFirstAttribute ();
@@ -264,7 +289,6 @@ namespace Mono.PkgConfig
                                        case "name": pinfo.Name = tr.Value; break;
                                        case "version": pinfo.Version = tr.Value; break;
                                        case "description": pinfo.Description = tr.Value; break;
-                                       case "gacPackage": pinfo.IsGacPackage = tr.Value != "false"; break;
                                        default: pinfo.SetData (tr.LocalName, tr.Value); break;
                                }
                        } while (tr.MoveToNextAttribute ());
@@ -274,20 +298,7 @@ namespace Mono.PkgConfig
                        if (!tr.IsEmptyElement) {
                                tr.ReadStartElement ();
                                tr.MoveToContent ();
-                               while (tr.NodeType == XmlNodeType.Element) {
-                                       PackageAssemblyInfo asm = new PackageAssemblyInfo ();
-                                       asm.Name = tr.GetAttribute ("name");
-                                       asm.Version = tr.GetAttribute ("version");
-                                       asm.Culture = tr.GetAttribute ("culture");
-                                       asm.PublicKeyToken = tr.GetAttribute ("publicKeyToken");
-                                       asm.File = tr.GetAttribute ("file");
-                                       if (pinfo.Assemblies == null)
-                                               pinfo.Assemblies = new List<PackageAssemblyInfo> ();
-                                       asm.ParentPackage = pinfo;
-                                       pinfo.Assemblies.Add (asm);
-                                       tr.Read ();
-                                       tr.MoveToContent ();
-                               }
+                               ReadPackageContent (tr, pinfo);
                                tr.MoveToContent ();
                                tr.ReadEndElement ();
                        } else
@@ -295,7 +306,11 @@ namespace Mono.PkgConfig
                        tr.MoveToContent ();
                        
                        if (!pinfo.IsValidPackage || ctx.IsCustomDataComplete (file, pinfo))
-                               infos [file] = pinfo;
+                               Add (file, pinfo, null);
+               }
+               
+               protected virtual void ReadPackageContent (XmlReader tr, TP pinfo)
+               {
                }
                
                public object SyncRoot {
@@ -303,123 +318,35 @@ namespace Mono.PkgConfig
                }
                
                
-               PackageInfo ParsePackageInfo (string pcfile)
+               TP ParsePackageInfo (string pcfile)
                {
-                       PackageInfo pinfo = new PackageInfo ();
-                       pinfo.Name = Path.GetFileNameWithoutExtension (pcfile);
-                       List<string> fullassemblies = null;
-                       bool gacPackageSet = false;
-                       
                        PcFile file = new PcFile ();
                        file.Load (pcfile);
                        
-                       if (file.HasErrors)
-                               return pinfo;
-                       
-                       if (file.Libs != null && file.Libs.IndexOf (".dll") != -1) {
-                               if (file.Libs.IndexOf ("-lib:") != -1 || file.Libs.IndexOf ("/lib:") != -1) {
-                                       fullassemblies = GetAssembliesWithLibInfo (file.Libs);
-                               } else {
-                                       fullassemblies = GetAssembliesWithoutLibInfo (file.Libs);
-                               }
-                       }
-                       
-                       string value = file.GetVariable ("Libraries");
-                       if (!string.IsNullOrEmpty (value))
-                               fullassemblies = GetAssembliesFromLibrariesVar (value);
+                       TP pinfo = new TP ();
+                       pinfo.Name = Path.GetFileNameWithoutExtension (file.FilePath);
                        
-                       pinfo.Version = file.Version;
-                       pinfo.Description = file.Description;
-
-                       value = file.GetVariable ("GacPackage");
-                       if (value != null) {
-                               value = value.ToLower ();
-                               pinfo.IsGacPackage = value == "yes" || value == "true";
-                               gacPackageSet = true;
+                       if (!file.HasErrors) {
+                               pinfo.Version = file.Version;
+                               pinfo.Description = file.Description;
+                               ParsePackageInfo (file, pinfo);
+                               ctx.StoreCustomData (file, pinfo);
                        }
-       
-                       if (fullassemblies == null)
-                               return pinfo;
-                       
-                       string pcDir = Path.GetDirectoryName (pcfile);
-                       string monoPrefix = Path.GetDirectoryName (Path.GetDirectoryName (pcDir));
-                       monoPrefix = Path.GetFullPath (monoPrefix + Path.DirectorySeparatorChar + "lib" + Path.DirectorySeparatorChar + "mono" + Path.DirectorySeparatorChar);
-
-                       List<PackageAssemblyInfo> list = new List<PackageAssemblyInfo> ();
-                       foreach (string assembly in fullassemblies) {
-                               string asm;
-                               if (Path.IsPathRooted (assembly))
-                                       asm = Path.GetFullPath (assembly);
-                               else {
-                                       if (Path.GetDirectoryName (assembly).Length == 0) {
-                                               asm = assembly;
-                                       } else {
-                                               asm = Path.GetFullPath (Path.Combine (pcDir, assembly));
-                                       }
-                               }
-                               if (File.Exists (asm)) {
-                                       PackageAssemblyInfo pi = new PackageAssemblyInfo ();
-                                       pi.File = asm;
-                                       pi.ParentPackage = pinfo;
-                                       pi.UpdateFromFile (pi.File);
-                                       list.Add (pi);
-                                       if (!gacPackageSet && !asm.StartsWith (monoPrefix) && Path.IsPathRooted (asm)) {
-                                               // Assembly installed outside $(prefix)/lib/mono. It is most likely not a gac package.
-                                               gacPackageSet = true;
-                                               pinfo.IsGacPackage = false;
-                                       }
-                               }
-                       }
-                       pinfo.Assemblies = list;
-                       ctx.StoreCustomData (file, pinfo);
-                       
                        return pinfo;
                }
                
-               private List<string> GetAssembliesWithLibInfo (string line)
+               protected virtual void ParsePackageInfo (PcFile file, TP pinfo)
                {
-                       List<string> references = new List<string> ();
-                       List<string> libdirs = new List<string> ();
-                       List<string> retval = new List<string> ();
-                       foreach (string piece in line.Split (' ')) {
-                               if (piece.ToLower ().Trim ().StartsWith ("/r:") || piece.ToLower ().Trim ().StartsWith ("-r:")) {
-                                       references.Add (piece.Substring (3).Trim ());
-                               } else if (piece.ToLower ().Trim ().StartsWith ("/lib:") || piece.ToLower ().Trim ().StartsWith ("-lib:")) {
-                                       libdirs.Add (piece.Substring (5).Trim ());
-                               }
-                       }
-       
-                       foreach (string refrnc in references) {
-                               foreach (string libdir in libdirs) {
-                                       if (File.Exists (libdir + Path.DirectorySeparatorChar + refrnc)) {
-                                               retval.Add (libdir + Path.DirectorySeparatorChar + refrnc);
-                                       }
-                               }
-                       }
-       
-                       return retval;
                }
                
-               List<string> GetAssembliesFromLibrariesVar (string line)
-               {
-                       List<string> references = new List<string> ();
-                       foreach (string reference in line.Split (' ')) {
-                               if (!string.IsNullOrEmpty (reference))
-                                       references.Add (reference);
-                       }
-                       return references;
-               }
-       
-               private List<string> GetAssembliesWithoutLibInfo (string line)
+               IEnumerable<string> GetDefaultPaths ()
                {
-                       List<string> references = new List<string> ();
-                       foreach (string reference in line.Split (' ')) {
-                               if (reference.ToLower ().Trim ().StartsWith ("/r:") || reference.ToLower ().Trim ().StartsWith ("-r:")) {
-                                       string final_ref = reference.Substring (3).Trim ();
-                                       references.Add (final_ref);
-                               }
+                       if (defaultPaths == null) {
+                               string pkgConfigPath = Environment.GetEnvironmentVariable ("PKG_CONFIG_PATH");
+                               string pkgConfigDir = Environment.GetEnvironmentVariable ("PKG_CONFIG_LIBDIR");
+                               defaultPaths = GetPkgconfigPaths (null, pkgConfigPath, pkgConfigDir);
                        }
-                       return references;
+                       return defaultPaths;
                }
                
                public IEnumerable<string> GetPkgconfigPaths (string prefix, string pkgConfigPath, string pkgConfigLibdir)
@@ -472,14 +399,15 @@ namespace Mono.PkgConfig
                
                IEnumerable<string> NormaliseAndFilterPaths (IEnumerable<string> paths, string workingDirectory)
                {
-                       HashSet<string> filtered = new HashSet<string> ();
+                       Dictionary<string,string> filtered = new Dictionary<string,string> ();
                        foreach (string p in paths) {
                                string path = p;
                                if (!Path.IsPathRooted (path))
                                        path = Path.Combine (workingDirectory, path);
                                path = Path.GetFullPath (path);
-                               if (!filtered.Add (path))
+                               if (filtered.ContainsKey (path))
                                        continue;
+                               filtered.Add (path,path);
                                try {
                                        if (!Directory.Exists (path))
                                                continue;
@@ -503,17 +431,6 @@ namespace Mono.PkgConfig
                        }
                        return null;
                }
-               
-               public static string NormalizeAsmName (string name)
-               {
-                       int i = name.ToLower ().IndexOf (", publickeytoken=null");
-                       if (i != -1)
-                               name = name.Substring (0, i).Trim ();
-                       i = name.ToLower ().IndexOf (", processorarchitecture=");
-                       if (i != -1)
-                               name = name.Substring (0, i).Trim ();
-                       return name;
-               }
        }
 
        internal class PcFile
@@ -609,22 +526,13 @@ namespace Mono.PkgConfig
        internal class PackageInfo
        {
                Dictionary<string,string> customData;
-               
-               public PackageInfo ()
-               {
-                       IsGacPackage = true;
-               }
 
                public string Name { get; set; }
                
-               public bool IsGacPackage { get; set; }
-               
                public string Version { get; set; }
                
                public string Description { get; set; }
                
-               internal List<PackageAssemblyInfo> Assemblies { get; set; }
-               
                public string GetData (string name)
                {
                        if (customData == null)
@@ -641,67 +549,24 @@ namespace Mono.PkgConfig
                        customData [name] = value;
                }
                
+               public void RemoveData (string name)
+               {
+                       if (customData != null)
+                               customData.Remove (name);
+               }
+               
                internal Dictionary<string,string> CustomData {
                        get { return customData; }
                }
                
                internal DateTime LastWriteTime { get; set; }
                
-               internal bool IsValidPackage {
-                       get { return Assemblies != null && Assemblies.Count > 0; }
-               }
-               
                internal bool HasCustomData {
                        get { return customData != null && customData.Count > 0; }
                }
-       }
-       
-       class PackageAssemblyInfo
-       {
-               public string File { get; set; }
-               
-               public string Name;
-               
-               public string Version;
                
-               public string Culture;
-               
-               public string PublicKeyToken;
-               
-               public string FullName {
-                       get {
-                               string fn = Name + ", Version=" + Version;
-                               if (!string.IsNullOrEmpty (Culture))
-                                       fn += ", Culture=" + Culture;
-                               if (!string.IsNullOrEmpty (PublicKeyToken))
-                                       fn += ", PublicKeyToken=" + PublicKeyToken;
-                               return fn;
-                       }
-               }
-               
-               public PackageInfo ParentPackage { get; set; }
-               
-               public void UpdateFromFile (string file)
-               {
-                       Update (System.Reflection.AssemblyName.GetAssemblyName (file));
-               }
-               
-               public void Update (System.Reflection.AssemblyName aname)
-               {
-                       Name = aname.Name;
-                       Version = aname.Version.ToString ();
-                       if (aname.CultureInfo != null) {
-                               if (aname.CultureInfo.LCID == System.Globalization.CultureInfo.InvariantCulture.LCID)
-                                       Culture = "neutral";
-                               else
-                                       Culture = aname.CultureInfo.Name;
-                       }
-                       string fn = aname.ToString ();
-                       string key = "publickeytoken=";
-                       int i = fn.ToLower().IndexOf (key) + key.Length;
-                       int j = fn.IndexOf (',', i);
-                       if (j == -1) j = fn.Length;
-                       PublicKeyToken = fn.Substring (i, j - i);
+               internal protected virtual bool IsValidPackage {
+                       get { return HasCustomData; }
                }
        }
 }