From: Antonius Riha Date: Mon, 30 Dec 2013 20:41:32 +0000 (+0100) Subject: Move internals from Microsoft.Build.Tasks to new dll Mono.XBuild.Tasks X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=commitdiff_plain;h=9ac4fc1b5226be7b5a59535a6201ea852d533b97;p=mono.git Move internals from Microsoft.Build.Tasks to new dll Mono.XBuild.Tasks All internal members (such as PcFileCache) have been made public to make them unit-testable. * mcs/class/Makefile: Add Mono.XBuild.Tasks as build target * mcs/class/Microsoft.Build.Tasks/Makefile: Add Mono.XBuild.Tasks.dll as build reference of Microsoft.Build.Tasks.dll * mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks-net_2_0.csproj: * mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks-net_3_5.csproj: * mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks-net_4_0.csproj: * mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks-net_4_5.csproj: Remove source files, which have been moved to Mono.XBuild.Tasks.dll and add a project reference to Mono.XBuild.Tasks.dll * mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks.dll.sources: Remove files that have been moved to Mono.XBuild.Tasks.dll from Microsoft.Build.Tasks.dll * mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks/PcFileCache.cs: * mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks/LibraryPcFileCache.cs: This file was moved to Mono.XBuild.Tasks.dll * mcs/class/Mono.XBuild.Tasks/Assembly/AssemblyInfo.cs: Moved from Microsoft.Build.Tasks.dll. Signing key is mono.pub. * mcs/class/Mono.XBuild.Tasks/Mono.XBuild.Tasks/PcFileCache.cs: * mcs/class/Mono.XBuild.Tasks/Mono.XBuild.Tasks/LibraryPcFileCache.cs: Moved from Microsoft.Build.Tasks.dll. All internal members have been made public. * mcs/class/Mono.XBuild.Tasks/Test/Mono.XBuild.Tasks/PcFileCacheTest.cs: Create test file stub. --- diff --git a/mcs/class/Makefile b/mcs/class/Makefile index aa37aebd10e..79f1f9d618c 100644 --- a/mcs/class/Makefile +++ b/mcs/class/Makefile @@ -91,6 +91,7 @@ net_2_0_dirs := \ Microsoft.Build.Framework \ Microsoft.Build.Utilities \ Microsoft.Build.Engine \ + Mono.XBuild.Tasks \ Microsoft.Build.Tasks \ System.Xml.Linq \ System.Runtime.Serialization \ @@ -173,6 +174,7 @@ net_3_5_only_dirs := \ Microsoft.Build.Framework \ Microsoft.Build.Utilities \ Microsoft.Build.Engine \ + Mono.XBuild.Tasks \ Microsoft.Build.Tasks net_4_0_dirs := \ diff --git a/mcs/class/Microsoft.Build.Tasks/Makefile b/mcs/class/Microsoft.Build.Tasks/Makefile index 18288e01177..4161a45b51c 100644 --- a/mcs/class/Microsoft.Build.Tasks/Makefile +++ b/mcs/class/Microsoft.Build.Tasks/Makefile @@ -5,11 +5,13 @@ include ../../build/rules.make LIBRARY = Microsoft.Build.Tasks.dll BUILD_FRAMEWORK = Microsoft.Build.Framework.dll BUILD_ENGINE = Microsoft.Build.Engine.dll +XBUILD_TASKS = Mono.XBuild.Tasks.dll ifeq (3.5, $(FRAMEWORK_VERSION)) NAME_SUFFIX = .v3.5 BUILD_FRAMEWORK := $(topdir)/class/lib/$(PROFILE)/$(BUILD_FRAMEWORK) BUILD_ENGINE := $(topdir)/class/lib/$(PROFILE)/$(BUILD_ENGINE) +XBUILD_TASKS := $(topdir)/class/lib/$(PROFILE)/$(XBUILD_TASKS) else ifeq (4, $(FRAMEWORK_VERSION_MAJOR)) NAME_SUFFIX = .v4.0 @@ -29,11 +31,13 @@ LIB_MCS_FLAGS = \ /r:System.Windows.Forms.dll \ /r:Microsoft.Build.Utilities$(NAME_SUFFIX).dll \ /r:$(BUILD_FRAMEWORK) \ - /r:$(BUILD_ENGINE) + /r:$(BUILD_ENGINE) \ + /r:$(XBUILD_TASKS) TEST_MCS_FLAGS = \ /r:$(BUILD_ENGINE) \ /r:$(BUILD_FRAMEWORK) \ + /r:$(XBUILD_TASKS) \ /r:Microsoft.Build.Utilities$(NAME_SUFFIX).dll \ /r:System.Core.dll diff --git a/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks-net_2_0.csproj b/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks-net_2_0.csproj index 6d196e931da..39fdfbca0de 100644 --- a/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks-net_2_0.csproj +++ b/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks-net_2_0.csproj @@ -132,12 +132,10 @@ - - @@ -210,6 +208,10 @@ {E8E948B8-6DCF-48F2-A6BC-04309AED8740} Microsoft.Build.Engine\Microsoft.Build.Engine-net_2_0 + + {F5F84165-0541-4828-A81E-0AA1836E50C1} + Mono.XBuild.Tasks-net_2_0 + diff --git a/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks-net_3_5.csproj b/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks-net_3_5.csproj index 014cf446e04..7f9ae420975 100644 --- a/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks-net_3_5.csproj +++ b/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks-net_3_5.csproj @@ -132,12 +132,10 @@ - - @@ -210,6 +208,10 @@ {874516A3-F5F6-4EAB-B005-4D1A567C5E4D} Microsoft.Build.Engine\Microsoft.Build.Engine-net_3_5 + + {7B888FCD-9064-4F4A-954E-795B43F98127} + Mono.XBuild.Tasks-net_3_5 + diff --git a/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks-net_4_0.csproj b/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks-net_4_0.csproj index b52f6278696..f883f4f7889 100644 --- a/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks-net_4_0.csproj +++ b/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks-net_4_0.csproj @@ -132,12 +132,10 @@ - - @@ -210,6 +208,10 @@ {9B0AC297-CB85-43C1-8C18-12997CF1B78D} Microsoft.Build.Engine\Microsoft.Build.Engine-net_4_0 + + {F7F03F9B-6E7A-43BD-993A-7F197A440150} + Mono.XBuild.Tasks-net_4_0 + diff --git a/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks-net_4_5.csproj b/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks-net_4_5.csproj index 657ee6fc251..7af8b85741e 100644 --- a/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks-net_4_5.csproj +++ b/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks-net_4_5.csproj @@ -132,12 +132,10 @@ - - @@ -210,6 +208,10 @@ {0DA63190-E6E1-41C5-B683-A54FADBE61CB} Microsoft.Build.Engine\Microsoft.Build.Engine-net_4_5 + + {9AC58525-C730-4552-A8FA-332979FCD055} + Mono.XBuild.Tasks-net_4_5 + diff --git a/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks.dll.sources b/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks.dll.sources index fb30b46bc2a..e61c90c6300 100644 --- a/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks.dll.sources +++ b/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks.dll.sources @@ -87,8 +87,6 @@ Microsoft.Build.Tasks/MakeDir.cs 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 diff --git a/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks/LibraryPcFileCache.cs b/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks/LibraryPcFileCache.cs deleted file mode 100644 index f29a591f56a..00000000000 --- a/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks/LibraryPcFileCache.cs +++ /dev/null @@ -1,321 +0,0 @@ -// -// PcFileCacheAssembly.cs -// -// Author: -// Lluis Sanchez Gual -// -// 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; - -// IMPORTANT IMPORTANT IMPORTANT IMPORTANT IMPORTANT IMPORTANT -// This code is shared with xbuild, which has to build with .NET 2.0, -// so no c# 3.0 syntax is allowed here. - -namespace Mono.PkgConfig -{ - internal class LibraryPcFileCache: PcFileCache - { - Dictionary assemblyLocations; - - public LibraryPcFileCache (IPcFileCacheContext 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 searchPaths) - { - lock (SyncRoot) { - if (assemblyLocations == null) { - // Populate on demand - assemblyLocations = new Dictionary (); - 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 ResolveAssemblyName (string name) - { - return ResolveAssemblyName (name, null); - } - - public IEnumerable ResolveAssemblyName (string name, IEnumerable 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 (); - asm.ParentPackage = pinfo; - pinfo.Assemblies.Add (asm); - tr.Read (); - tr.MoveToContent (); - } - } - - protected override void ParsePackageInfo (PcFile file, LibraryPackageInfo pinfo) - { - List 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) { - pinfo.IsGacPackage = - string.Equals (value, "yes", StringComparison.OrdinalIgnoreCase) || - string.Equals (value, "true", StringComparison.OrdinalIgnoreCase); - 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 list = new List (); - 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 GetAssembliesWithLibInfo (string line) - { - List references = new List (); - List libdirs = new List (); - List retval = new List (); - foreach (string piece in line.Split (' ')) { - if (IsReferenceParameter (piece)) { - references.Add (piece.Substring (3).Trim ()); - } else if (piece.TrimStart ().StartsWith ("/lib:", StringComparison.OrdinalIgnoreCase) || - piece.TrimStart ().StartsWith ("-lib:", StringComparison.OrdinalIgnoreCase)) { - 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; - } - - static bool IsReferenceParameter (string value) - { - return value.TrimStart ().StartsWith ("/r:", StringComparison.OrdinalIgnoreCase) || - value.TrimStart ().StartsWith ("-r:", StringComparison.OrdinalIgnoreCase); - } - - List GetAssembliesFromLibrariesVar (string line) - { - List references = new List (); - foreach (string reference in line.Split (' ')) { - if (!string.IsNullOrEmpty (reference)) - references.Add (reference); - } - return references; - } - - private List GetAssembliesWithoutLibInfo (string line) - { - List references = new List (); - foreach (string reference in line.Split (' ')) { - if (IsReferenceParameter (reference)) { - string final_ref = reference.Substring (3).Trim (); - references.Add (final_ref); - } - } - return references; - } - - public static string NormalizeAsmName (string name) - { - int i = name.IndexOf (", publickeytoken=null", StringComparison.OrdinalIgnoreCase); - if (i != -1) - name = name.Substring (0, i).Trim (); - i = name.IndexOf (", processorarchitecture=", StringComparison.OrdinalIgnoreCase); - 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 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.IndexOf (key, StringComparison.OrdinalIgnoreCase) + key.Length; - int j = fn.IndexOf (',', i); - if (j == -1) j = fn.Length; - PublicKeyToken = fn.Substring (i, j - i); - } - } -} diff --git a/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks/PcFileCache.cs b/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks/PcFileCache.cs deleted file mode 100644 index aa96a318fc8..00000000000 --- a/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks/PcFileCache.cs +++ /dev/null @@ -1,646 +0,0 @@ -// -// PcFileCache.cs -// -// Author: -// Lluis Sanchez Gual -// -// 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; - -// IMPORTANT IMPORTANT IMPORTANT IMPORTANT IMPORTANT IMPORTANT -// This code is shared with xbuild, which has to build with .NET 2.0, -// so no c# 3.0 syntax is allowed here. - -namespace Mono.PkgConfig -{ - internal interface IPcFileCacheContext 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, TP pkg); - - // Should return false if the provided package does not have required - // custom data - bool IsCustomDataComplete (string pcfile, TP pkg); - - // Called to report errors - void ReportError (string message, Exception ex); - } - - internal interface IPcFileCacheContext: IPcFileCacheContext - { - } - - internal abstract class PcFileCache: PcFileCache - { - public PcFileCache (IPcFileCacheContext ctx): base (ctx) - { - } - } - - internal abstract class PcFileCache where TP:PackageInfo, new() - { - const string CACHE_VERSION = "2"; - const string MacOSXExternalPkgConfigDir = "/Library/Frameworks/Mono.framework/External/pkgconfig"; - - Dictionary infos = new Dictionary (); - Dictionary> filesByFolder = new Dictionary> (); - - string cacheFile; - bool hasChanges; - IPcFileCacheContext ctx; - IEnumerable defaultPaths; - - public PcFileCache (IPcFileCacheContext ctx) - { - this.ctx = ctx; - try { - string path = CacheDirectory; - if (!Directory.Exists (path)) - Directory.CreateDirectory (path); - cacheFile = Path.Combine (path, "pkgconfig-cache-" + CACHE_VERSION + ".xml"); - - if (File.Exists (cacheFile)) - Load (); - - } catch (Exception ex) { - ctx.ReportError ("pc file cache could not be loaded.", ex); - } - } - - protected abstract string CacheDirectory { get; } - - // Updates the pkg-config index, using the default search directories - public void Update () - { - Update (GetDefaultPaths ()); - } - - // Updates the pkg-config index, looking for .pc files in the provided directories - public void Update (IEnumerable pkgConfigDirs) - { - foreach (string pcdir in pkgConfigDirs) { - foreach (string pcfile in Directory.GetFiles (pcdir, "*.pc")) - GetPackageInfo (pcfile); - } - Save (); - } - - public IEnumerable GetPackages () - { - return GetPackages (null); - } - - public IEnumerable GetPackages (IEnumerable pkgConfigDirs) - { - if (pkgConfigDirs == null) - pkgConfigDirs = GetDefaultPaths (); - - foreach (string sp in pkgConfigDirs) { - List 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 pkgConfigDirs) - { - foreach (TP p in GetPackages (pkgConfigDirs)) - if (p.Name == name) - return p; - return null; - } - - // Returns information about a .pc file - public TP GetPackageInfo (string file) - { - TP info, oldInfo = null; - file = Path.GetFullPath (file); - - DateTime wtime = File.GetLastWriteTime (file); - - lock (infos) { - if (infos.TryGetValue (file, out info)) { - if (info.LastWriteTime == wtime) - return info; - oldInfo = info; - } - } - - try { - info = ParsePackageInfo (file); - } catch (Exception ex) { - ctx.ReportError ("Error while parsing .pc file: " + file, ex); - info = new TP (); - } - - lock (infos) { - if (!info.IsValidPackage) - info = new TP (); // Create a default empty instance - info.LastWriteTime = wtime; - 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 list; - if (!filesByFolder.TryGetValue (dir, out list)) { - list = new List (); - 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; - FileMode mode = access == FileAccess.Read ? FileMode.Open : FileMode.Create; - Exception lastException = null; - - while (retries > 0) { - try { - return new FileStream (cacheFile, mode, access, FileShare.None); - } catch (Exception ex) { - // the file may be locked by another app. Wait a bit and try again - lastException = ex; - System.Threading.Thread.Sleep (200); - retries--; - } - } - ctx.ReportError ("File could not be opened: " + cacheFile, lastException); - return null; - } - - void Load () - { - // The serializer can't be used because this file is reused in xbuild - using (FileStream fs = OpenFile (FileAccess.Read)) { - if (fs == null) - return; - XmlTextReader xr = new XmlTextReader (fs); - xr.MoveToContent (); - xr.ReadStartElement (); - xr.MoveToContent (); - - while (xr.NodeType == XmlNodeType.Element) - ReadPackage (xr); - } - } - - public void Save () - { - // The serializer can't be used because this file is reused in xbuild - lock (infos) { - if (!hasChanges) - return; - - using (FileStream fs = OpenFile (FileAccess.Write)) { - if (fs == null) - return; - XmlTextWriter tw = new XmlTextWriter (new StreamWriter (fs)); - tw.Formatting = Formatting.Indented; - - tw.WriteStartElement ("PcFileCache"); - foreach (KeyValuePair file in infos) { - WritePackage (tw, file.Key, file.Value); - } - tw.WriteEndElement (); // PcFileCache - tw.Flush (); - - hasChanges = false; - } - } - } - - void WritePackage (XmlTextWriter tw, string file, TP pinfo) - { - tw.WriteStartElement ("File"); - tw.WriteAttributeString ("path", file); - tw.WriteAttributeString ("lastWriteTime", XmlConvert.ToString (pinfo.LastWriteTime, XmlDateTimeSerializationMode.Local)); - - if (pinfo.IsValidPackage) { - if (pinfo.Name != null) - tw.WriteAttributeString ("name", pinfo.Name); - if (pinfo.Version != null) - tw.WriteAttributeString ("version", pinfo.Version); - if (!string.IsNullOrEmpty (pinfo.Description)) - tw.WriteAttributeString ("description", pinfo.Description); - if (!string.IsNullOrEmpty (pinfo.Requires)) - tw.WriteAttributeString ("requires", pinfo.Requires); - if (pinfo.CustomData != null) { - foreach (KeyValuePair cd in pinfo.CustomData) - tw.WriteAttributeString (cd.Key, cd.Value); - } - WritePackageContent (tw, file, pinfo); - } - tw.WriteEndElement (); // File - } - - protected virtual void WritePackageContent (XmlTextWriter tw, string file, TP pinfo) - { - } - - void ReadPackage (XmlReader tr) - { - TP pinfo = new TP (); - string file = null; - - tr.MoveToFirstAttribute (); - do { - switch (tr.LocalName) { - case "path": file = tr.Value; break; - case "lastWriteTime": pinfo.LastWriteTime = XmlConvert.ToDateTime (tr.Value, XmlDateTimeSerializationMode.Local); break; - case "name": pinfo.Name = tr.Value; break; - case "version": pinfo.Version = tr.Value; break; - case "description": pinfo.Description = tr.Value; break; - case "requires": pinfo.Requires = tr.Value; break; - default: pinfo.SetData (tr.LocalName, tr.Value); break; - } - } while (tr.MoveToNextAttribute ()); - - tr.MoveToElement (); - - if (!tr.IsEmptyElement) { - tr.ReadStartElement (); - tr.MoveToContent (); - ReadPackageContent (tr, pinfo); - tr.MoveToContent (); - tr.ReadEndElement (); - } else - tr.Read (); - tr.MoveToContent (); - - if (!pinfo.IsValidPackage || ctx.IsCustomDataComplete (file, pinfo)) - Add (file, pinfo, null); - } - - protected virtual void ReadPackageContent (XmlReader tr, TP pinfo) - { - } - - public object SyncRoot { - get { return infos; } - } - - - TP ParsePackageInfo (string pcfile) - { - PcFile file = new PcFile (); - file.Load (pcfile); - - TP pinfo = new TP (); - pinfo.Name = Path.GetFileNameWithoutExtension (file.FilePath); - - if (!file.HasErrors) { - pinfo.Version = file.Version; - pinfo.Description = file.Description; - pinfo.Requires = file.Requires; - ParsePackageInfo (file, pinfo); - if (pinfo.IsValidPackage) - ctx.StoreCustomData (file, pinfo); - } - return pinfo; - } - - protected virtual void ParsePackageInfo (PcFile file, TP pinfo) - { - } - - IEnumerable GetDefaultPaths () - { - if (defaultPaths == null) { - // For mac osx, look in the 'External' dir on macosx, - // see bug #663180 - string pkgConfigPath = String.Format ("{0}:{1}", - Mono.XBuild.Utilities.MSBuildUtils.RunningOnMac ? MacOSXExternalPkgConfigDir : String.Empty, - Environment.GetEnvironmentVariable ("PKG_CONFIG_PATH") ?? String.Empty); - - string pkgConfigDir = Environment.GetEnvironmentVariable ("PKG_CONFIG_LIBDIR"); - defaultPaths = GetPkgconfigPaths (null, pkgConfigPath, pkgConfigDir); - } - return defaultPaths; - } - - public IEnumerable GetPkgconfigPaths (string prefix, string pkgConfigPath, string pkgConfigLibdir) - { - char[] sep = new char[] { Path.PathSeparator }; - - string[] pkgConfigPaths = null; - if (!String.IsNullOrEmpty (pkgConfigPath)) { - pkgConfigPaths = pkgConfigPath.Split (sep, StringSplitOptions.RemoveEmptyEntries); - if (pkgConfigPaths.Length == 0) - pkgConfigPaths = null; - } - - string[] pkgConfigLibdirs = null; - if (!String.IsNullOrEmpty (pkgConfigLibdir)) { - pkgConfigLibdirs = pkgConfigLibdir.Split (sep, StringSplitOptions.RemoveEmptyEntries); - if (pkgConfigLibdirs.Length == 0) - pkgConfigLibdirs = null; - } - - if (prefix == null) - prefix = PathUp (typeof (int).Assembly.Location, 4); - - IEnumerable paths = GetUnfilteredPkgConfigDirs (pkgConfigPaths, pkgConfigLibdirs, new string [] { prefix }); - return NormaliseAndFilterPaths (paths, Environment.CurrentDirectory); - } - - IEnumerable GetUnfilteredPkgConfigDirs (IEnumerable pkgConfigPaths, IEnumerable pkgConfigLibdirs, IEnumerable systemPrefixes) - { - if (pkgConfigPaths != null) { - foreach (string dir in pkgConfigPaths) - yield return dir; - } - - if (pkgConfigLibdirs != null) { - foreach (string dir in pkgConfigLibdirs) - yield return dir; - } else if (systemPrefixes != null) { - string[] suffixes = new string [] { - //FIXME: is this the correct order? share should be before lib but not sure about others. - Path.Combine ("share", "pkgconfig"), - Path.Combine ("lib", "pkgconfig"), - Path.Combine ("lib64", "pkgconfig"), - Path.Combine ("libdata", "pkgconfig"), - }; - foreach (string prefix in systemPrefixes) - foreach (string suffix in suffixes) - yield return Path.Combine (prefix, suffix); - } - } - - IEnumerable NormaliseAndFilterPaths (IEnumerable paths, string workingDirectory) - { - Dictionary filtered = new Dictionary (); - foreach (string p in paths) { - string path = p; - if (!Path.IsPathRooted (path)) - path = Path.Combine (workingDirectory, path); - path = Path.GetFullPath (path); - if (filtered.ContainsKey (path)) - continue; - filtered.Add (path,path); - try { - if (!Directory.Exists (path)) - continue; - } catch (IOException ex) { - ctx.ReportError ("Error checking for directory '" + path + "'.", ex); - } - yield return path; - } - } - - static string PathUp (string path, int up) - { - if (up == 0) - return path; - for (int i = path.Length -1; i >= 0; i--) { - if (path[i] == Path.DirectorySeparatorChar) { - up--; - if (up == 0) - return path.Substring (0, i); - } - } - return null; - } - } - - internal class PcFile - { - Dictionary variables = new Dictionary (); - - string description; - public string Description { - get { return description; } - set { description = value; } - } - - string filePath; - public string FilePath { - get { return filePath; } - set { filePath = value; } - } - - bool hasErrors; - public bool HasErrors { - get { return hasErrors; } - set { hasErrors = value; } - } - - string libs; - public string Libs { - get { return libs; } - set { libs = value; } - } - - string name; - public string Name { - get { return name; } - set { name = value; } - } - - string version; - public string Version { - get { return version; } - set { version = value; } - } - - string requires; - public string Requires { - get { return requires; } - set { requires = value; } - } - - public string GetVariable (string varName) - { - string val; - variables.TryGetValue (varName, out val); - return val; - } - - public void Load (string pcfile) - { - FilePath = pcfile; - variables.Add ("pcfiledir", Path.GetDirectoryName (pcfile)); - using (StreamReader reader = new StreamReader (pcfile)) { - string line; - while ((line = reader.ReadLine ()) != null) { - int i = line.IndexOf (':'); - int j = line.IndexOf ('='); - int k = System.Math.Min (i != -1 ? i : int.MaxValue, j != -1 ? j : int.MaxValue); - if (k == int.MaxValue) - continue; - string var = line.Substring (0, k).Trim (); - string value = line.Substring (k + 1).Trim (); - value = Evaluate (value); - - if (k == j) { - // Is variable - variables [var] = value; - } - else { - switch (var) { - case "Name": Name = value; break; - case "Description": Description = value; break; - case "Version": Version = value; break; - case "Libs": Libs = value; break; - case "Requires": Requires = value; break; - } - } - } - } - } - - string Evaluate (string value) - { - int i = value.IndexOf ("${"); - if (i == -1) - return value; - - StringBuilder sb = new StringBuilder (); - int last = 0; - while (i != -1 && i < value.Length) { - sb.Append (value.Substring (last, i - last)); - if (i == 0 || value [i - 1] != '$') { - // Evaluate if var is not escaped - i += 2; - int n = value.IndexOf ('}', i); - if (n == -1 || n == i) { - // Closing bracket not found or empty name - HasErrors = true; - return value; - } - string rname = value.Substring (i, n - i); - string rval; - if (variables.TryGetValue (rname, out rval)) - sb.Append (rval); - else { - HasErrors = true; - return value; - } - i = n + 1; - last = i; - } else - last = i++; - - if (i < value.Length) - i = value.IndexOf ("${", i); - } - sb.Append (value.Substring (last, value.Length - last)); - return sb.ToString (); - } - } - - internal class PackageInfo - { - Dictionary customData; - DateTime lastWriteTime; - - string name; - public string Name { - get { return name; } - set { name = value; } - } - - string version; - public string Version { - get { return version; } - set { version = value; } - } - - string description; - public string Description { - get { return description; } - set { description = value; } - } - - string requires; - public string Requires { - get { return requires; } - set { requires = value; } - } - - public string GetData (string name) - { - if (customData == null) - return null; - string res; - customData.TryGetValue (name, out res); - return res; - } - - public void SetData (string name, string value) - { - if (customData == null) - customData = new Dictionary (); - customData [name] = value; - } - - public void RemoveData (string name) - { - if (customData != null) - customData.Remove (name); - } - - internal Dictionary CustomData { - get { return customData; } - } - - internal DateTime LastWriteTime { - get { return lastWriteTime; } - set { lastWriteTime = value; } - } - - internal bool HasCustomData { - get { return customData != null && customData.Count > 0; } - } - - internal protected virtual bool IsValidPackage { - get { return HasCustomData; } - } - } -} diff --git a/mcs/class/Mono.XBuild.Tasks/Assembly/AssemblyInfo.cs b/mcs/class/Mono.XBuild.Tasks/Assembly/AssemblyInfo.cs new file mode 100644 index 00000000000..c5543a4af27 --- /dev/null +++ b/mcs/class/Mono.XBuild.Tasks/Assembly/AssemblyInfo.cs @@ -0,0 +1,53 @@ +// +// AssemblyInfo.cs +// +// Author: +// Antonius Riha +// +// Copyright (c) 2013 Antonius Riha +// +// 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.Reflection; +using System.Resources; +using System.Runtime.InteropServices; + +// General Information about the Mono.XBuild.Tasks assembly + +[assembly: AssemblyTitle ("Mono.XBuild.Tasks.dll")] +[assembly: AssemblyDescription ("Mono.XBuild.Tasks.dll")] +[assembly: AssemblyDefaultAlias ("Mono.XBuild.Tasks.dll")] + +[assembly: AssemblyCompany (Consts.MonoCompany)] +[assembly: AssemblyProduct (Consts.MonoProduct)] +[assembly: AssemblyCopyright (Consts.MonoCopyright)] +[assembly: AssemblyVersion (Consts.FxVersion)] +[assembly: SatelliteContractVersion (Consts.FxVersion)] +[assembly: AssemblyInformationalVersion (Consts.FxFileVersion)] + +[assembly: NeutralResourcesLanguage ("en-US")] + +[assembly: ComVisible (false)] +[assembly: CLSCompliant (true)] +[assembly: AssemblyDelaySign (true)] +[assembly: AssemblyKeyFile("../mono.pub")] + +[assembly: AssemblyFileVersion (Consts.FxFileVersion)] diff --git a/mcs/class/Mono.XBuild.Tasks/Makefile b/mcs/class/Mono.XBuild.Tasks/Makefile new file mode 100644 index 00000000000..824eaf70ab4 --- /dev/null +++ b/mcs/class/Mono.XBuild.Tasks/Makefile @@ -0,0 +1,16 @@ +thisdir = class/Mono.XBuild.Tasks +SUBDIRS = +include ../../build/rules.make + +LIBRARY = Mono.XBuild.Tasks.dll + +LIB_MCS_FLAGS = \ + /r:$(corlib) \ + /r:System.dll \ + /r:System.Xml.dll + +export TESTING_MONO=a +XBUILD_DIR=../../tools/xbuild +include $(XBUILD_DIR)/xbuild_targets.make + +include ../../build/library.make diff --git a/mcs/class/Mono.XBuild.Tasks/Mono.XBuild.Tasks-net_2_0.csproj b/mcs/class/Mono.XBuild.Tasks/Mono.XBuild.Tasks-net_2_0.csproj new file mode 100644 index 00000000000..a2ade4abc79 --- /dev/null +++ b/mcs/class/Mono.XBuild.Tasks/Mono.XBuild.Tasks-net_2_0.csproj @@ -0,0 +1,76 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {F5F84165-0541-4828-A81E-0AA1836E50C1} + Library + 1699 + bin\Debug\Mono.XBuild.Tasks-net_2_0 + True + True + Properties + Mono.XBuild.Tasks + v2.0 + 512 + + + true + full + false + DEBUG;TRACE;NET_2_0 + prompt + 4 + + + true + prompt + 4 + NET_2_0 + + + + false + + + + + + + + + + + + + + + + xcopy $(TargetName).* $(ProjectDir)..\lib\net_2_0\ /Y /R /D + + + + + + + + ..\lib\net_2_0\mscorlib.dll + + + ..\lib\net_2_0\System.dll + + + ..\lib\net_2_0\System.Xml.dll + + + diff --git a/mcs/class/Mono.XBuild.Tasks/Mono.XBuild.Tasks-net_3_5.csproj b/mcs/class/Mono.XBuild.Tasks/Mono.XBuild.Tasks-net_3_5.csproj new file mode 100644 index 00000000000..f162637d51f --- /dev/null +++ b/mcs/class/Mono.XBuild.Tasks/Mono.XBuild.Tasks-net_3_5.csproj @@ -0,0 +1,74 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {7B888FCD-9064-4F4A-954E-795B43F98127} + Library + 1699 + bin\Debug\Mono.XBuild.Tasks-net_3_5 + True + True + Properties + Mono.XBuild.Tasks.v3.5 + v3.5 + 512 + + + true + full + false + DEBUG;TRACE;NET_2_0;NET_3_5 + prompt + 4 + + + pdbonly + true + NET_2_0;NET_3_5 + prompt + 4 + + + + false + + + + + + + + + + + + + + + + xcopy $(TargetName).* $(ProjectDir)..\lib\net_3_5\ /Y /R /D + + + + + ..\lib\net_3_5\mscorlib.dll + + + ..\lib\net_3_5\System.dll + + + ..\lib\net_3_5\System.Xml.dll + + + diff --git a/mcs/class/Mono.XBuild.Tasks/Mono.XBuild.Tasks-net_4_0.csproj b/mcs/class/Mono.XBuild.Tasks/Mono.XBuild.Tasks-net_4_0.csproj new file mode 100644 index 00000000000..e5560345655 --- /dev/null +++ b/mcs/class/Mono.XBuild.Tasks/Mono.XBuild.Tasks-net_4_0.csproj @@ -0,0 +1,74 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {F7F03F9B-6E7A-43BD-993A-7F197A440150} + Library + 1699 + bin\Debug\Mono.XBuild.Tasks-net_4_0 + True + True + Properties + Mono.XBuild.Tasks.v4.0 + v4.0 + 512 + + + true + full + false + DEBUG;TRACE;NET_2_0;NET_3_0;NET_3_5;NET_4_0 + prompt + 4 + + + pdbonly + true + NET_2_0;NET_3_0;NET_3_5;NET_4_0 + prompt + 4 + + + + false + + + + + + + + + + + + + + + + xcopy $(TargetName).* $(ProjectDir)..\lib\net_4_0\ /Y /R /D + + + + + ..\lib\net_4_0\mscorlib.dll + + + ..\lib\net_4_0\System.dll + + + ..\lib\net_4_0\System.Xml.dll + + + diff --git a/mcs/class/Mono.XBuild.Tasks/Mono.XBuild.Tasks-net_4_5.csproj b/mcs/class/Mono.XBuild.Tasks/Mono.XBuild.Tasks-net_4_5.csproj new file mode 100644 index 00000000000..9bf6342e1af --- /dev/null +++ b/mcs/class/Mono.XBuild.Tasks/Mono.XBuild.Tasks-net_4_5.csproj @@ -0,0 +1,74 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {9AC58525-C730-4552-A8FA-332979FCD055} + Library + 1699 + bin\Debug\Mono.XBuild.Tasks-net_4_5 + True + True + Properties + Mono.XBuild.Tasks.v4.0 + v4.5 + 512 + + + true + full + false + DEBUG;TRACE;NET_2_0;NET_3_0;NET_3_5;NET_4_0;NET_4_5 + prompt + 4 + + + pdbonly + true + NET_2_0;NET_3_0;NET_3_5;NET_4_0;NET_4_5 + prompt + 4 + + + + false + + + + + + + + + + + + + + + + xcopy $(TargetName).* $(ProjectDir)..\lib\net_4_5\ /Y /R /D + + + + + ..\lib\net_4_5\mscorlib.dll + + + ..\lib\net_4_5\System.dll + + + ..\lib\net_4_5\System.Xml.dll + + + diff --git a/mcs/class/Mono.XBuild.Tasks/Mono.XBuild.Tasks-tests-net_2_0.csproj b/mcs/class/Mono.XBuild.Tasks/Mono.XBuild.Tasks-tests-net_2_0.csproj new file mode 100644 index 00000000000..0412ea86e4e --- /dev/null +++ b/mcs/class/Mono.XBuild.Tasks/Mono.XBuild.Tasks-tests-net_2_0.csproj @@ -0,0 +1,75 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {0E03221E-BC2B-4C7C-AA7B-F26B8FFA3014} + Library + 1699 + bin\Debug\Mono.XBuild.Tasks-tests-net_2_0 + True + False + Properties + Mono.XBuild.Tasks_test_net_2_0 + v2.0 + 512 + + + true + full + false + DEBUG;TRACE;NET_2_0 + prompt + 4 + + + pdbonly + true + NET_2_0 + prompt + 4 + + + + false + + + + + + + + + + + xcopy $(TargetName).* $(ProjectDir)..\lib\net_2_0\ /Y /R /D + + + + + ..\lib\net_2_0\mscorlib.dll + + + ..\lib\net_2_0\System.Core.dll + + + ..\lib\net_2_0\nunit.framework.dll + + + + + {F5F84165-0541-4828-A81E-0AA1836E50C1} + Mono.XBuild.Tasks-net_2_0 + + + diff --git a/mcs/class/Mono.XBuild.Tasks/Mono.XBuild.Tasks-tests-net_3_5.csproj b/mcs/class/Mono.XBuild.Tasks/Mono.XBuild.Tasks-tests-net_3_5.csproj new file mode 100644 index 00000000000..77ffd647277 --- /dev/null +++ b/mcs/class/Mono.XBuild.Tasks/Mono.XBuild.Tasks-tests-net_3_5.csproj @@ -0,0 +1,75 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {B1C8C446-5C28-4352-BA7A-A30171FEA614} + Library + 1699 + bin\Debug\Mono.XBuild.Tasks-tests-net_3_5 + True + False + Properties + Mono.XBuild.Tasks_test_net_3_5 + v3.5 + 512 + + + true + full + false + DEBUG;TRACE;NET_2_0;NET_3_5 + prompt + 4 + + + pdbonly + true + NET_2_0;NET_3_5 + prompt + 4 + + + + false + + + + + + + + + + + xcopy $(TargetName).* $(ProjectDir)..\lib\net_3_5\ /Y /R /D + + + + + ..\lib\net_3_5\mscorlib.dll + + + ..\lib\net_3_5\System.Core.dll + + + ..\lib\net_3_5\nunit.framework.dll + + + + + {7B888FCD-9064-4F4A-954E-795B43F98127} + Mono.XBuild.Tasks-net_3_5 + + + diff --git a/mcs/class/Mono.XBuild.Tasks/Mono.XBuild.Tasks-tests-net_4_0.csproj b/mcs/class/Mono.XBuild.Tasks/Mono.XBuild.Tasks-tests-net_4_0.csproj new file mode 100644 index 00000000000..0e005df2bc5 --- /dev/null +++ b/mcs/class/Mono.XBuild.Tasks/Mono.XBuild.Tasks-tests-net_4_0.csproj @@ -0,0 +1,75 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {0C851F1F-CF06-4440-8E69-F33FBF07D605} + Library + 1699 + bin\Debug\Mono.XBuild.Tasks-tests-net_4_0 + True + False + Properties + Mono.XBuild.Tasks_test_net_4_0 + v4.0 + 512 + + + true + full + false + DEBUG;TRACE;NET_2_0;NET_3_0;NET_3_5;NET_4_0 + prompt + 4 + + + pdbonly + true + NET_2_0;NET_3_0;NET_3_5;NET_4_0 + prompt + 4 + + + + false + + + + + + + + + + + xcopy $(TargetName).* $(ProjectDir)..\lib\net_4_0\ /Y /R /D + + + + + ..\lib\net_4_0\mscorlib.dll + + + ..\lib\net_4_0\System.Core.dll + + + ..\lib\net_4_0\nunit.framework.dll + + + + + {F7F03F9B-6E7A-43BD-993A-7F197A440150} + Mono.XBuild.Tasks-net_4_0 + + + diff --git a/mcs/class/Mono.XBuild.Tasks/Mono.XBuild.Tasks-tests-net_4_5.csproj b/mcs/class/Mono.XBuild.Tasks/Mono.XBuild.Tasks-tests-net_4_5.csproj new file mode 100644 index 00000000000..e1c568b4579 --- /dev/null +++ b/mcs/class/Mono.XBuild.Tasks/Mono.XBuild.Tasks-tests-net_4_5.csproj @@ -0,0 +1,75 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {74FC4C23-BF2E-4514-82D2-E99561BF352C} + Library + 1699 + bin\Debug\Mono.XBuild.Tasks-tests-net_4_5 + True + False + Properties + Mono.XBuild.Tasks_test_net_4_5 + v4.5 + 512 + + + true + full + false + DEBUG;TRACE;NET_2_0;NET_3_0;NET_3_5;NET_4_0;NET_4_5 + prompt + 4 + + + pdbonly + true + NET_2_0;NET_3_0;NET_3_5;NET_4_0;NET_4_5 + prompt + 4 + + + + false + + + + + + + + + + + xcopy $(TargetName).* $(ProjectDir)..\lib\net_4_5\ /Y /R /D + + + + + ..\lib\net_4_5\mscorlib.dll + + + ..\lib\net_4_5\System.Core.dll + + + ..\lib\net_4_5\nunit.framework.dll + + + + + {9AC58525-C730-4552-A8FA-332979FCD055} + Mono.XBuild.Tasks-net_4_5 + + + diff --git a/mcs/class/Mono.XBuild.Tasks/Mono.XBuild.Tasks.dll.sources b/mcs/class/Mono.XBuild.Tasks/Mono.XBuild.Tasks.dll.sources new file mode 100644 index 00000000000..60955c07e07 --- /dev/null +++ b/mcs/class/Mono.XBuild.Tasks/Mono.XBuild.Tasks.dll.sources @@ -0,0 +1,6 @@ +Assembly/AssemblyInfo.cs +../../build/common/Consts.cs +../../build/common/MonoTODOAttribute.cs +Mono.XBuild.Tasks/PcFileCache.cs +Mono.XBuild.Tasks/LibraryPcFileCache.cs +../Microsoft.Build.Utilities/Mono.XBuild.Utilities/MSBuildUtils.cs diff --git a/mcs/class/Mono.XBuild.Tasks/Mono.XBuild.Tasks/LibraryPcFileCache.cs b/mcs/class/Mono.XBuild.Tasks/Mono.XBuild.Tasks/LibraryPcFileCache.cs new file mode 100644 index 00000000000..c89cba9a95f --- /dev/null +++ b/mcs/class/Mono.XBuild.Tasks/Mono.XBuild.Tasks/LibraryPcFileCache.cs @@ -0,0 +1,321 @@ +// +// PcFileCacheAssembly.cs +// +// Author: +// Lluis Sanchez Gual +// +// 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; + +// IMPORTANT IMPORTANT IMPORTANT IMPORTANT IMPORTANT IMPORTANT +// This code is shared with xbuild, which has to build with .NET 2.0, +// so no c# 3.0 syntax is allowed here. + +namespace Mono.PkgConfig +{ + public class LibraryPcFileCache: PcFileCache + { + Dictionary assemblyLocations; + + public LibraryPcFileCache (IPcFileCacheContext 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 searchPaths) + { + lock (SyncRoot) { + if (assemblyLocations == null) { + // Populate on demand + assemblyLocations = new Dictionary (); + 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 ResolveAssemblyName (string name) + { + return ResolveAssemblyName (name, null); + } + + public IEnumerable ResolveAssemblyName (string name, IEnumerable 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 (); + asm.ParentPackage = pinfo; + pinfo.Assemblies.Add (asm); + tr.Read (); + tr.MoveToContent (); + } + } + + protected override void ParsePackageInfo (PcFile file, LibraryPackageInfo pinfo) + { + List 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) { + pinfo.IsGacPackage = + string.Equals (value, "yes", StringComparison.OrdinalIgnoreCase) || + string.Equals (value, "true", StringComparison.OrdinalIgnoreCase); + 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 list = new List (); + 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 GetAssembliesWithLibInfo (string line) + { + List references = new List (); + List libdirs = new List (); + List retval = new List (); + foreach (string piece in line.Split (' ')) { + if (IsReferenceParameter (piece)) { + references.Add (piece.Substring (3).Trim ()); + } else if (piece.TrimStart ().StartsWith ("/lib:", StringComparison.OrdinalIgnoreCase) || + piece.TrimStart ().StartsWith ("-lib:", StringComparison.OrdinalIgnoreCase)) { + 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; + } + + static bool IsReferenceParameter (string value) + { + return value.TrimStart ().StartsWith ("/r:", StringComparison.OrdinalIgnoreCase) || + value.TrimStart ().StartsWith ("-r:", StringComparison.OrdinalIgnoreCase); + } + + List GetAssembliesFromLibrariesVar (string line) + { + List references = new List (); + foreach (string reference in line.Split (' ')) { + if (!string.IsNullOrEmpty (reference)) + references.Add (reference); + } + return references; + } + + private List GetAssembliesWithoutLibInfo (string line) + { + List references = new List (); + foreach (string reference in line.Split (' ')) { + if (IsReferenceParameter (reference)) { + string final_ref = reference.Substring (3).Trim (); + references.Add (final_ref); + } + } + return references; + } + + public static string NormalizeAsmName (string name) + { + int i = name.IndexOf (", publickeytoken=null", StringComparison.OrdinalIgnoreCase); + if (i != -1) + name = name.Substring (0, i).Trim (); + i = name.IndexOf (", processorarchitecture=", StringComparison.OrdinalIgnoreCase); + if (i != -1) + name = name.Substring (0, i).Trim (); + return name; + } + } + + public class LibraryPackageInfo: PackageInfo + { + public bool IsGacPackage { + get { return GetData ("gacPackage") != "false"; } + set { + if (value) + RemoveData ("gacPackage"); + else + SetData ("gacPackage", "false"); + } + } + + internal List Assemblies { get; set; } + + internal protected override bool IsValidPackage { + get { return Assemblies != null && Assemblies.Count > 0; } + } + } + + public 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.IndexOf (key, StringComparison.OrdinalIgnoreCase) + key.Length; + int j = fn.IndexOf (',', i); + if (j == -1) j = fn.Length; + PublicKeyToken = fn.Substring (i, j - i); + } + } +} diff --git a/mcs/class/Mono.XBuild.Tasks/Mono.XBuild.Tasks/PcFileCache.cs b/mcs/class/Mono.XBuild.Tasks/Mono.XBuild.Tasks/PcFileCache.cs new file mode 100644 index 00000000000..515f463ae86 --- /dev/null +++ b/mcs/class/Mono.XBuild.Tasks/Mono.XBuild.Tasks/PcFileCache.cs @@ -0,0 +1,646 @@ +// +// PcFileCache.cs +// +// Author: +// Lluis Sanchez Gual +// +// 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; + +// IMPORTANT IMPORTANT IMPORTANT IMPORTANT IMPORTANT IMPORTANT +// This code is shared with xbuild, which has to build with .NET 2.0, +// so no c# 3.0 syntax is allowed here. + +namespace Mono.PkgConfig +{ + public interface IPcFileCacheContext 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, TP pkg); + + // Should return false if the provided package does not have required + // custom data + bool IsCustomDataComplete (string pcfile, TP pkg); + + // Called to report errors + void ReportError (string message, Exception ex); + } + + public interface IPcFileCacheContext: IPcFileCacheContext + { + } + + public abstract class PcFileCache: PcFileCache + { + public PcFileCache (IPcFileCacheContext ctx): base (ctx) + { + } + } + + public abstract class PcFileCache where TP:PackageInfo, new() + { + const string CACHE_VERSION = "2"; + const string MacOSXExternalPkgConfigDir = "/Library/Frameworks/Mono.framework/External/pkgconfig"; + + Dictionary infos = new Dictionary (); + Dictionary> filesByFolder = new Dictionary> (); + + string cacheFile; + bool hasChanges; + IPcFileCacheContext ctx; + IEnumerable defaultPaths; + + public PcFileCache (IPcFileCacheContext ctx) + { + this.ctx = ctx; + try { + string path = CacheDirectory; + if (!Directory.Exists (path)) + Directory.CreateDirectory (path); + cacheFile = Path.Combine (path, "pkgconfig-cache-" + CACHE_VERSION + ".xml"); + + if (File.Exists (cacheFile)) + Load (); + + } catch (Exception ex) { + ctx.ReportError ("pc file cache could not be loaded.", ex); + } + } + + protected abstract string CacheDirectory { get; } + + // Updates the pkg-config index, using the default search directories + public void Update () + { + Update (GetDefaultPaths ()); + } + + // Updates the pkg-config index, looking for .pc files in the provided directories + public void Update (IEnumerable pkgConfigDirs) + { + foreach (string pcdir in pkgConfigDirs) { + foreach (string pcfile in Directory.GetFiles (pcdir, "*.pc")) + GetPackageInfo (pcfile); + } + Save (); + } + + public IEnumerable GetPackages () + { + return GetPackages (null); + } + + public IEnumerable GetPackages (IEnumerable pkgConfigDirs) + { + if (pkgConfigDirs == null) + pkgConfigDirs = GetDefaultPaths (); + + foreach (string sp in pkgConfigDirs) { + List 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 pkgConfigDirs) + { + foreach (TP p in GetPackages (pkgConfigDirs)) + if (p.Name == name) + return p; + return null; + } + + // Returns information about a .pc file + public TP GetPackageInfo (string file) + { + TP info, oldInfo = null; + file = Path.GetFullPath (file); + + DateTime wtime = File.GetLastWriteTime (file); + + lock (infos) { + if (infos.TryGetValue (file, out info)) { + if (info.LastWriteTime == wtime) + return info; + oldInfo = info; + } + } + + try { + info = ParsePackageInfo (file); + } catch (Exception ex) { + ctx.ReportError ("Error while parsing .pc file: " + file, ex); + info = new TP (); + } + + lock (infos) { + if (!info.IsValidPackage) + info = new TP (); // Create a default empty instance + info.LastWriteTime = wtime; + 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 list; + if (!filesByFolder.TryGetValue (dir, out list)) { + list = new List (); + 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; + FileMode mode = access == FileAccess.Read ? FileMode.Open : FileMode.Create; + Exception lastException = null; + + while (retries > 0) { + try { + return new FileStream (cacheFile, mode, access, FileShare.None); + } catch (Exception ex) { + // the file may be locked by another app. Wait a bit and try again + lastException = ex; + System.Threading.Thread.Sleep (200); + retries--; + } + } + ctx.ReportError ("File could not be opened: " + cacheFile, lastException); + return null; + } + + void Load () + { + // The serializer can't be used because this file is reused in xbuild + using (FileStream fs = OpenFile (FileAccess.Read)) { + if (fs == null) + return; + XmlTextReader xr = new XmlTextReader (fs); + xr.MoveToContent (); + xr.ReadStartElement (); + xr.MoveToContent (); + + while (xr.NodeType == XmlNodeType.Element) + ReadPackage (xr); + } + } + + public void Save () + { + // The serializer can't be used because this file is reused in xbuild + lock (infos) { + if (!hasChanges) + return; + + using (FileStream fs = OpenFile (FileAccess.Write)) { + if (fs == null) + return; + XmlTextWriter tw = new XmlTextWriter (new StreamWriter (fs)); + tw.Formatting = Formatting.Indented; + + tw.WriteStartElement ("PcFileCache"); + foreach (KeyValuePair file in infos) { + WritePackage (tw, file.Key, file.Value); + } + tw.WriteEndElement (); // PcFileCache + tw.Flush (); + + hasChanges = false; + } + } + } + + void WritePackage (XmlTextWriter tw, string file, TP pinfo) + { + tw.WriteStartElement ("File"); + tw.WriteAttributeString ("path", file); + tw.WriteAttributeString ("lastWriteTime", XmlConvert.ToString (pinfo.LastWriteTime, XmlDateTimeSerializationMode.Local)); + + if (pinfo.IsValidPackage) { + if (pinfo.Name != null) + tw.WriteAttributeString ("name", pinfo.Name); + if (pinfo.Version != null) + tw.WriteAttributeString ("version", pinfo.Version); + if (!string.IsNullOrEmpty (pinfo.Description)) + tw.WriteAttributeString ("description", pinfo.Description); + if (!string.IsNullOrEmpty (pinfo.Requires)) + tw.WriteAttributeString ("requires", pinfo.Requires); + if (pinfo.CustomData != null) { + foreach (KeyValuePair cd in pinfo.CustomData) + tw.WriteAttributeString (cd.Key, cd.Value); + } + WritePackageContent (tw, file, pinfo); + } + tw.WriteEndElement (); // File + } + + protected virtual void WritePackageContent (XmlTextWriter tw, string file, TP pinfo) + { + } + + void ReadPackage (XmlReader tr) + { + TP pinfo = new TP (); + string file = null; + + tr.MoveToFirstAttribute (); + do { + switch (tr.LocalName) { + case "path": file = tr.Value; break; + case "lastWriteTime": pinfo.LastWriteTime = XmlConvert.ToDateTime (tr.Value, XmlDateTimeSerializationMode.Local); break; + case "name": pinfo.Name = tr.Value; break; + case "version": pinfo.Version = tr.Value; break; + case "description": pinfo.Description = tr.Value; break; + case "requires": pinfo.Requires = tr.Value; break; + default: pinfo.SetData (tr.LocalName, tr.Value); break; + } + } while (tr.MoveToNextAttribute ()); + + tr.MoveToElement (); + + if (!tr.IsEmptyElement) { + tr.ReadStartElement (); + tr.MoveToContent (); + ReadPackageContent (tr, pinfo); + tr.MoveToContent (); + tr.ReadEndElement (); + } else + tr.Read (); + tr.MoveToContent (); + + if (!pinfo.IsValidPackage || ctx.IsCustomDataComplete (file, pinfo)) + Add (file, pinfo, null); + } + + protected virtual void ReadPackageContent (XmlReader tr, TP pinfo) + { + } + + public object SyncRoot { + get { return infos; } + } + + + TP ParsePackageInfo (string pcfile) + { + PcFile file = new PcFile (); + file.Load (pcfile); + + TP pinfo = new TP (); + pinfo.Name = Path.GetFileNameWithoutExtension (file.FilePath); + + if (!file.HasErrors) { + pinfo.Version = file.Version; + pinfo.Description = file.Description; + pinfo.Requires = file.Requires; + ParsePackageInfo (file, pinfo); + if (pinfo.IsValidPackage) + ctx.StoreCustomData (file, pinfo); + } + return pinfo; + } + + protected virtual void ParsePackageInfo (PcFile file, TP pinfo) + { + } + + IEnumerable GetDefaultPaths () + { + if (defaultPaths == null) { + // For mac osx, look in the 'External' dir on macosx, + // see bug #663180 + string pkgConfigPath = String.Format ("{0}:{1}", + Mono.XBuild.Utilities.MSBuildUtils.RunningOnMac ? MacOSXExternalPkgConfigDir : String.Empty, + Environment.GetEnvironmentVariable ("PKG_CONFIG_PATH") ?? String.Empty); + + string pkgConfigDir = Environment.GetEnvironmentVariable ("PKG_CONFIG_LIBDIR"); + defaultPaths = GetPkgconfigPaths (null, pkgConfigPath, pkgConfigDir); + } + return defaultPaths; + } + + public IEnumerable GetPkgconfigPaths (string prefix, string pkgConfigPath, string pkgConfigLibdir) + { + char[] sep = new char[] { Path.PathSeparator }; + + string[] pkgConfigPaths = null; + if (!String.IsNullOrEmpty (pkgConfigPath)) { + pkgConfigPaths = pkgConfigPath.Split (sep, StringSplitOptions.RemoveEmptyEntries); + if (pkgConfigPaths.Length == 0) + pkgConfigPaths = null; + } + + string[] pkgConfigLibdirs = null; + if (!String.IsNullOrEmpty (pkgConfigLibdir)) { + pkgConfigLibdirs = pkgConfigLibdir.Split (sep, StringSplitOptions.RemoveEmptyEntries); + if (pkgConfigLibdirs.Length == 0) + pkgConfigLibdirs = null; + } + + if (prefix == null) + prefix = PathUp (typeof (int).Assembly.Location, 4); + + IEnumerable paths = GetUnfilteredPkgConfigDirs (pkgConfigPaths, pkgConfigLibdirs, new string [] { prefix }); + return NormaliseAndFilterPaths (paths, Environment.CurrentDirectory); + } + + IEnumerable GetUnfilteredPkgConfigDirs (IEnumerable pkgConfigPaths, IEnumerable pkgConfigLibdirs, IEnumerable systemPrefixes) + { + if (pkgConfigPaths != null) { + foreach (string dir in pkgConfigPaths) + yield return dir; + } + + if (pkgConfigLibdirs != null) { + foreach (string dir in pkgConfigLibdirs) + yield return dir; + } else if (systemPrefixes != null) { + string[] suffixes = new string [] { + //FIXME: is this the correct order? share should be before lib but not sure about others. + Path.Combine ("share", "pkgconfig"), + Path.Combine ("lib", "pkgconfig"), + Path.Combine ("lib64", "pkgconfig"), + Path.Combine ("libdata", "pkgconfig"), + }; + foreach (string prefix in systemPrefixes) + foreach (string suffix in suffixes) + yield return Path.Combine (prefix, suffix); + } + } + + IEnumerable NormaliseAndFilterPaths (IEnumerable paths, string workingDirectory) + { + Dictionary filtered = new Dictionary (); + foreach (string p in paths) { + string path = p; + if (!Path.IsPathRooted (path)) + path = Path.Combine (workingDirectory, path); + path = Path.GetFullPath (path); + if (filtered.ContainsKey (path)) + continue; + filtered.Add (path,path); + try { + if (!Directory.Exists (path)) + continue; + } catch (IOException ex) { + ctx.ReportError ("Error checking for directory '" + path + "'.", ex); + } + yield return path; + } + } + + static string PathUp (string path, int up) + { + if (up == 0) + return path; + for (int i = path.Length -1; i >= 0; i--) { + if (path[i] == Path.DirectorySeparatorChar) { + up--; + if (up == 0) + return path.Substring (0, i); + } + } + return null; + } + } + + public class PcFile + { + Dictionary variables = new Dictionary (); + + string description; + public string Description { + get { return description; } + set { description = value; } + } + + string filePath; + public string FilePath { + get { return filePath; } + set { filePath = value; } + } + + bool hasErrors; + public bool HasErrors { + get { return hasErrors; } + set { hasErrors = value; } + } + + string libs; + public string Libs { + get { return libs; } + set { libs = value; } + } + + string name; + public string Name { + get { return name; } + set { name = value; } + } + + string version; + public string Version { + get { return version; } + set { version = value; } + } + + string requires; + public string Requires { + get { return requires; } + set { requires = value; } + } + + public string GetVariable (string varName) + { + string val; + variables.TryGetValue (varName, out val); + return val; + } + + public void Load (string pcfile) + { + FilePath = pcfile; + variables.Add ("pcfiledir", Path.GetDirectoryName (pcfile)); + using (StreamReader reader = new StreamReader (pcfile)) { + string line; + while ((line = reader.ReadLine ()) != null) { + int i = line.IndexOf (':'); + int j = line.IndexOf ('='); + int k = System.Math.Min (i != -1 ? i : int.MaxValue, j != -1 ? j : int.MaxValue); + if (k == int.MaxValue) + continue; + string var = line.Substring (0, k).Trim (); + string value = line.Substring (k + 1).Trim (); + value = Evaluate (value); + + if (k == j) { + // Is variable + variables [var] = value; + } + else { + switch (var) { + case "Name": Name = value; break; + case "Description": Description = value; break; + case "Version": Version = value; break; + case "Libs": Libs = value; break; + case "Requires": Requires = value; break; + } + } + } + } + } + + string Evaluate (string value) + { + int i = value.IndexOf ("${"); + if (i == -1) + return value; + + StringBuilder sb = new StringBuilder (); + int last = 0; + while (i != -1 && i < value.Length) { + sb.Append (value.Substring (last, i - last)); + if (i == 0 || value [i - 1] != '$') { + // Evaluate if var is not escaped + i += 2; + int n = value.IndexOf ('}', i); + if (n == -1 || n == i) { + // Closing bracket not found or empty name + HasErrors = true; + return value; + } + string rname = value.Substring (i, n - i); + string rval; + if (variables.TryGetValue (rname, out rval)) + sb.Append (rval); + else { + HasErrors = true; + return value; + } + i = n + 1; + last = i; + } else + last = i++; + + if (i < value.Length) + i = value.IndexOf ("${", i); + } + sb.Append (value.Substring (last, value.Length - last)); + return sb.ToString (); + } + } + + public class PackageInfo + { + Dictionary customData; + DateTime lastWriteTime; + + string name; + public string Name { + get { return name; } + set { name = value; } + } + + string version; + public string Version { + get { return version; } + set { version = value; } + } + + string description; + public string Description { + get { return description; } + set { description = value; } + } + + string requires; + public string Requires { + get { return requires; } + set { requires = value; } + } + + public string GetData (string name) + { + if (customData == null) + return null; + string res; + customData.TryGetValue (name, out res); + return res; + } + + public void SetData (string name, string value) + { + if (customData == null) + customData = new Dictionary (); + customData [name] = value; + } + + public void RemoveData (string name) + { + if (customData != null) + customData.Remove (name); + } + + internal Dictionary CustomData { + get { return customData; } + } + + internal DateTime LastWriteTime { + get { return lastWriteTime; } + set { lastWriteTime = value; } + } + + internal bool HasCustomData { + get { return customData != null && customData.Count > 0; } + } + + internal protected virtual bool IsValidPackage { + get { return HasCustomData; } + } + } +} diff --git a/mcs/class/Mono.XBuild.Tasks/Mono.XBuild.Tasks_test.dll.sources b/mcs/class/Mono.XBuild.Tasks/Mono.XBuild.Tasks_test.dll.sources new file mode 100644 index 00000000000..0dbb1260ba9 --- /dev/null +++ b/mcs/class/Mono.XBuild.Tasks/Mono.XBuild.Tasks_test.dll.sources @@ -0,0 +1 @@ +Mono.XBuild.Tasks/PcFileCacheTest.cs diff --git a/mcs/class/Mono.XBuild.Tasks/Test/Mono.XBuild.Tasks/PcFileCacheTest.cs b/mcs/class/Mono.XBuild.Tasks/Test/Mono.XBuild.Tasks/PcFileCacheTest.cs new file mode 100644 index 00000000000..2c3b3ab1443 --- /dev/null +++ b/mcs/class/Mono.XBuild.Tasks/Test/Mono.XBuild.Tasks/PcFileCacheTest.cs @@ -0,0 +1,34 @@ +// +// PcFileCacheTest.cs +// +// Author: +// Antonius Riha +// +// Copyright (c) 2013 Antonius Riha +// +// 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 NUnit.Framework; + +namespace MonoTests.Microsoft.Build.Tasks +{ + [TestFixture] + public class PcFileCacheTest + { + } +}