diff options
author | Mikayla Hutchinson <m.j.hutchinson@gmail.com> | 2018-04-24 01:49:51 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-04-24 01:49:51 +0300 |
commit | e665ba6c0d378907891338d12411ac235c75bf25 (patch) | |
tree | 6a4ae1f19635e2ef2f91853235184dd4d3e42cbe | |
parent | 6aba0c4e88d85d30613cd606200873f255981f22 (diff) | |
parent | 1ee3fbeaa449b83e9a0007668de423bec7537cab (diff) |
Merge pull request #4648 from mono/assemblyservice-caching
Improve SystemAssemblyService initialization time
9 files changed, 410 insertions, 334 deletions
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/FrameworkInfo.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/FrameworkInfo.cs new file mode 100644 index 0000000000..6bdbc01b5d --- /dev/null +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/FrameworkInfo.cs @@ -0,0 +1,152 @@ +// +// Copyright (c) 2008 Novell, Inc (http://www.novell.com) +// Copyright (c) Microsoft Corp. +// +// 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.Collections.Generic; +using System.IO; +using System.Xml; +using System.Reflection; +using System.Text; + +namespace MonoDevelop.Core.Assemblies +{ + class FrameworkInfo + { + public TargetFrameworkMoniker Id { get; set; } + public string Name { get; set; } + public string IncludeFramework { get; set; } + public string TargetFrameworkDirectory { get; set; } + public List<AssemblyInfo> Assemblies { get; set; } + public List<SupportedFramework> SupportedFrameworks { get; set; } + + public static FrameworkInfo Load (TargetFrameworkMoniker moniker, FilePath frameworkListFile) + { + var info = new FrameworkInfo { Id = moniker }; + + //for non-cached files, this file is in the RedistList subdir of the assembly dir + info.TargetFrameworkDirectory = frameworkListFile.ParentDirectory.ParentDirectory; + + using (var reader = XmlReader.Create (frameworkListFile)) { + if (!reader.ReadToDescendant ("FileList")) + throw new Exception ("Missing FileList element"); + + if (reader.MoveToAttribute ("Name") && reader.ReadAttributeValue ()) + info.Name = reader.ReadContentAsString (); + + if (reader.MoveToAttribute ("IncludeFramework") && reader.ReadAttributeValue ()) { + string include = reader.ReadContentAsString (); + if (!string.IsNullOrEmpty (include)) + info.IncludeFramework = include; + } + + //this is a Mono-specific extension + if (reader.MoveToAttribute ("TargetFrameworkDirectory") && reader.ReadAttributeValue ()) { + string targetDir = reader.ReadContentAsString (); + if (!string.IsNullOrEmpty (targetDir)) { + targetDir = targetDir.Replace ('\\', Path.DirectorySeparatorChar); + info.TargetFrameworkDirectory = frameworkListFile.ParentDirectory.Combine (targetDir).FullPath; + } + } + + info.Assemblies = new List<AssemblyInfo> (); + info.SupportedFrameworks = new List<SupportedFramework> (); + + while (reader.Read ()) { + if (reader.IsStartElement ()) { + switch (reader.LocalName) { + case "File": + info.Assemblies.Add (ReadFileElement (reader)); + break; + case "SupportedFramework": + info.SupportedFrameworks.Add (SupportedFramework.LoadFromAttributes (reader)); + break; + } + } + } + } + return info; + } + + static AssemblyInfo ReadFileElement (XmlReader reader) + { + var ainfo = new AssemblyInfo (); + if (reader.MoveToAttribute ("AssemblyName") && reader.ReadAttributeValue ()) + ainfo.Name = reader.ReadContentAsString (); + if (string.IsNullOrEmpty (ainfo.Name)) + throw new Exception ("Missing AssemblyName attribute"); + if (reader.MoveToAttribute ("Version") && reader.ReadAttributeValue ()) + ainfo.Version = reader.ReadContentAsString (); + if (reader.MoveToAttribute ("PublicKeyToken") && reader.ReadAttributeValue ()) + ainfo.PublicKeyToken = reader.ReadContentAsString (); + if (reader.MoveToAttribute ("Culture") && reader.ReadAttributeValue ()) + ainfo.Culture = reader.ReadContentAsString (); + if (reader.MoveToAttribute ("ProcessorArchitecture") && reader.ReadAttributeValue ()) + ainfo.ProcessorArchitecture = (ProcessorArchitecture) + Enum.Parse (typeof (ProcessorArchitecture), reader.ReadContentAsString (), true); + if (reader.MoveToAttribute ("InGac") && reader.ReadAttributeValue ()) + ainfo.InGac = reader.ReadContentAsBoolean (); + return ainfo; + } + + public void Save (string path) + { + using (var writer = XmlWriter.Create (path, new XmlWriterSettings { Encoding = Encoding.UTF8 })) { + writer.WriteStartDocument (); + writer.WriteStartElement ("FileList"); + WriteNonEmptyAttribute ("Name", Name); + WriteNonEmptyAttribute ("IncludeFramework", IncludeFramework); + WriteNonEmptyAttribute ("TargetFrameworkDirectory", TargetFrameworkDirectory); + if (Assemblies.Count > 0) { + foreach (var asm in Assemblies) { + writer.WriteStartElement ("File"); + writer.WriteAttributeString ("AssemblyName", asm.Name); + WriteNonEmptyAttribute ("Version", asm.Version); + WriteNonEmptyAttribute ("PublicKeyToken", asm.PublicKeyToken); + WriteNonEmptyAttribute ("Culture", asm.Culture); + if (asm.ProcessorArchitecture != ProcessorArchitecture.None) { + writer.WriteAttributeString ("ProcessorArchitecture", asm.ProcessorArchitecture.ToString ()); + } + if (asm.InGac) { + writer.WriteAttributeString ("InGac", "true"); + } + writer.WriteEndElement (); + } + } + if (SupportedFrameworks.Count > 0) { + foreach (var sf in SupportedFrameworks) { + sf.SaveAsElement (writer); + } + } + writer.WriteEndDocument (); + + void WriteNonEmptyAttribute (string name, string val) + { + if (!string.IsNullOrEmpty (val)) { + writer.WriteAttributeString (name, val); + } + } + } + } + } +} diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/MonoFrameworkBackend.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/MonoFrameworkBackend.cs index 13a67e6608..924cfc39f2 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/MonoFrameworkBackend.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/MonoFrameworkBackend.cs @@ -32,18 +32,11 @@ namespace MonoDevelop.Core.Assemblies { public class MonoFrameworkBackend: TargetFrameworkBackend<MonoTargetRuntime> { - string ref_assemblies_folder; - - string GetReferenceAssembliesFolder () + protected override string OnGetReferenceAssembliesFolder () { - if (ref_assemblies_folder != null) - return ref_assemblies_folder; - var fxDir = framework.Id.GetAssemblyDirectoryName (); - foreach (var rootDir in ((MonoTargetRuntime)runtime).GetReferenceFrameworkDirectories ()) { - var dir = rootDir.Combine (fxDir); + FilePath dir = base.OnGetReferenceAssembliesFolder (); + if (dir != null) { var frameworkList = dir.Combine ("RedistList", "FrameworkList.xml"); - if (!File.Exists (frameworkList)) - continue; //check for the Mono-specific TargetFrameworkDirectory extension using (var reader = System.Xml.XmlReader.Create (frameworkList)) { if (reader.ReadToDescendant ("FileList") && reader.MoveToAttribute ("TargetFrameworkDirectory") && reader.ReadAttributeValue ()) { @@ -54,62 +47,11 @@ namespace MonoDevelop.Core.Assemblies } } } - ref_assemblies_folder = dir; return dir; } return null; } - - public override IEnumerable<string> GetFrameworkFolders () - { - var dir = GetReferenceAssembliesFolder (); - if (dir != null) - yield return dir; - - if (framework.Id.Identifier != TargetFrameworkMoniker.ID_NET_FRAMEWORK) - yield break; - - string subdir; - switch (framework.Id.Version) { - case "1.1": - subdir = "1.0"; break; - case "3.0": - // WCF is installed in the 2.0 directory. Others (olive) in 3.0. - yield return Path.Combine (targetRuntime.MonoDirectory, "2.0"); - yield return Path.Combine (targetRuntime.MonoDirectory, "3.0"); - yield break; - case "3.5": - yield return Path.Combine (targetRuntime.MonoDirectory, "3.5"); - subdir = "2.0"; break; - default: - subdir = framework.Id.Version; break; - } - yield return Path.Combine (targetRuntime.MonoDirectory, subdir); - } - - public override bool IsInstalled { - get { - if (framework.Id.Identifier == TargetFrameworkMoniker.ID_NET_FRAMEWORK && - framework.Id.Version == "3.0") - { - // This is a special case. The WCF assemblies are installed in the 2.0 directory. - // There are other 3.0 assemblies which belong to the olive package (WCF doesn't) - // and which are installed in the 3.0 directory. We consider 3.0 to be installed - // if any of those assemblies are installed. - if (base.IsInstalled) - return true; - string dir = Path.Combine (targetRuntime.MonoDirectory, "2.0"); - if (Directory.Exists (dir)) { - string firstAsm = Path.Combine (dir, "System.ServiceModel.dll"); - return File.Exists (firstAsm); - } - return false; - } - return base.IsInstalled; - } - } - - + string GetOldMcsName (TargetFrameworkMoniker fx) { //old compilers for specific frameworks diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/MsNetFrameworkBackend.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/MsNetFrameworkBackend.cs index c92ddaf68b..75344ca43f 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/MsNetFrameworkBackend.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/MsNetFrameworkBackend.cs @@ -25,39 +25,12 @@ // THE SOFTWARE. using System; -using Microsoft.Win32; -using System.IO; using System.Collections.Generic; namespace MonoDevelop.Core.Assemblies { public class MsNetFrameworkBackend: TargetFrameworkBackend<MsNetTargetRuntime> { - string ref_assemblies_folder; - - string GetReferenceAssembliesFolder () - { - if (ref_assemblies_folder != null) - return ref_assemblies_folder; - - var fxDir = framework.Id.GetAssemblyDirectoryName (); - foreach (var rootDir in runtime.GetReferenceFrameworkDirectories ()) { - var dir = rootDir.Combine (fxDir); - var frameworkList = dir.Combine ("RedistList", "FrameworkList.xml"); - if (File.Exists (frameworkList)) - return ref_assemblies_folder = dir; - } - return null; - } - - public override IEnumerable<string> GetFrameworkFolders () - { - var dir = GetReferenceAssembliesFolder (); - if (dir != null) { - yield return dir; - } - } - public override Dictionary<string, string> GetToolsEnvironmentVariables () { var vars = new Dictionary<string, string> (); diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/SupportedFramework.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/SupportedFramework.cs index 28c1c14924..c6f22ef554 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/SupportedFramework.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/SupportedFramework.cs @@ -24,7 +24,6 @@ // THE SOFTWARE. using System; -using System.IO; using System.Xml; using System.Collections.Generic; @@ -33,9 +32,18 @@ namespace MonoDevelop.Core.Assemblies public class SupportedFramework { public static readonly Version NoMaximumVersion = new Version (int.MaxValue, int.MaxValue, int.MaxValue, int.MaxValue); - public static readonly Version NoMinumumVersion = new Version (0, 0, 0, 0); + public static readonly Version NoMinimumVersion = new Version (0, 0, 0, 0); + [Obsolete("This was misspelled, use NoMinimumVersion")] + public static readonly Version NoMinumumVersion = NoMinimumVersion; + + [Obsolete("Use the overload without a TargetFramework parameter")] public SupportedFramework (TargetFramework target, string identifier, string display, string profile, Version minVersion, string minDisplayVersion) + : this (identifier, display, profile, minVersion, minDisplayVersion) + { + } + + public SupportedFramework (string identifier, string display, string profile, Version minVersion, string minDisplayVersion) { MinimumVersionDisplayName = minDisplayVersion; MinimumVersion = minVersion; @@ -43,20 +51,16 @@ namespace MonoDevelop.Core.Assemblies DisplayName = display; Identifier = identifier; Profile = profile; - - TargetFramework = target; } - internal SupportedFramework (TargetFramework target) + internal SupportedFramework () { MinimumVersionDisplayName = string.Empty; - MinimumVersion = NoMinumumVersion; + MinimumVersion = NoMinimumVersion; MaximumVersion = NoMaximumVersion; DisplayName = string.Empty; Identifier = string.Empty; Profile = string.Empty; - - TargetFramework = target; } public string DisplayName { @@ -90,10 +94,10 @@ namespace MonoDevelop.Core.Assemblies public string MonoSpecificVersionDisplayName { get; internal set; } - - public TargetFramework TargetFramework { - get; private set; - } + + //this referred to the "parent" rather than framework decsribed by this instance + [Obsolete ("This property was misleading and is no longer supported")] + public TargetFramework TargetFramework => TargetFramework.Default; static Version ParseVersion (string version, Version wildcard) { @@ -103,55 +107,85 @@ namespace MonoDevelop.Core.Assemblies return Version.Parse (version); } - internal static SupportedFramework Load (TargetFramework target, FilePath path) + internal static SupportedFramework Load (FilePath path) { - SupportedFramework fx = new SupportedFramework (target); - - fx.DisplayName = path.FileNameWithoutExtension; - using (var reader = XmlReader.Create (path)) { if (!reader.ReadToDescendant ("Framework")) throw new Exception ("Missing Framework element"); - - if (!reader.HasAttributes) - throw new Exception ("Framework element does not contain any attributes"); - - while (reader.MoveToNextAttribute ()) { - switch (reader.Name) { - case "MaximumVersion": - fx.MaximumVersion = ParseVersion (reader.Value, NoMaximumVersion); - break; - case "MinimumVersion": - fx.MinimumVersion = ParseVersion (reader.Value, NoMinumumVersion); - break; - case "Profile": - fx.Profile = reader.Value; - break; - case "Identifier": - fx.Identifier = reader.Value; - break; - case "MinimumVersionDisplayName": - fx.MinimumVersionDisplayName = reader.Value; - break; - case "DisplayName": - fx.DisplayName = reader.Value; - break; - case "MonoSpecificVersion": - fx.MonoSpecificVersion = reader.Value; - break; - case "MonoSpecificVersionDisplayName": - fx.MonoSpecificVersionDisplayName = reader.Value; - break; - } + var fx = LoadFromAttributes (reader); + if (string.IsNullOrEmpty (fx.DisplayName)) { + fx.DisplayName = path.FileNameWithoutExtension; + } + return fx; + } + + } + internal static SupportedFramework LoadFromAttributes (XmlReader reader) + { + var fx = new SupportedFramework (); + if (!reader.HasAttributes) + throw new Exception ("Framework element does not contain any attributes"); + + while (reader.MoveToNextAttribute ()) { + switch (reader.Name) { + case "MaximumVersion": + fx.MaximumVersion = ParseVersion (reader.Value, NoMaximumVersion); + break; + case "MinimumVersion": + fx.MinimumVersion = ParseVersion (reader.Value, NoMinimumVersion); + break; + case "Profile": + fx.Profile = reader.Value; + break; + case "Identifier": + fx.Identifier = reader.Value; + break; + case "MinimumVersionDisplayName": + fx.MinimumVersionDisplayName = reader.Value; + break; + case "DisplayName": + fx.DisplayName = reader.Value; + break; + case "MonoSpecificVersion": + fx.MonoSpecificVersion = reader.Value; + break; + case "MonoSpecificVersionDisplayName": + fx.MonoSpecificVersionDisplayName = reader.Value; + break; } } if (string.IsNullOrEmpty (fx.Identifier)) throw new Exception ("Framework element did not specify an Identifier attribute"); - + return fx; } + internal void SaveAsElement (XmlWriter writer) + { + writer.WriteStartElement ("SupportedFramework"); + if (MaximumVersion != NoMaximumVersion) { + writer.WriteAttributeString ("MaximumVersion", MaximumVersion.ToString ()); + } + if (MinimumVersion != NoMinimumVersion) { + writer.WriteAttributeString ("MinimumVersion", MinimumVersion.ToString ()); + } + WriteNonEmptyAttribute ("Profile", Profile); + WriteNonEmptyAttribute ("Identifier", Identifier); + WriteNonEmptyAttribute ("MinimumVersionDisplayName", MinimumVersionDisplayName); + WriteNonEmptyAttribute ("MonoSpecificVersion", MonoSpecificVersion); + WriteNonEmptyAttribute ("MonoSpecificVersionDisplayName", MonoSpecificVersionDisplayName); + + writer.WriteEndElement (); + + void WriteNonEmptyAttribute (string name, string val) + { + if (!string.IsNullOrEmpty (val)) { + writer.WriteAttributeString (name, val); + } + } + } + public override int GetHashCode () { return DisplayName != null ? DisplayName.GetHashCode () : 0; diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/TargetFramework.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/TargetFramework.cs index c9c6a32d5b..9c78def14b 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/TargetFramework.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/TargetFramework.cs @@ -29,9 +29,7 @@ using System; using System.IO; using System.Collections.Generic; -using Mono.Addins; using Mono.PkgConfig; -using MonoDevelop.Core.AddIns; using MonoDevelop.Core.Serialization; using System.Reflection; @@ -46,7 +44,7 @@ namespace MonoDevelop.Core.Assemblies List<SupportedFramework> supportedFrameworks = new List<SupportedFramework> (); internal bool RelationsBuilt; - + string corlibVersion; public static TargetFramework Default { @@ -63,9 +61,9 @@ namespace MonoDevelop.Core.Assemblies this.name = id.Profile == null ? string.Format ("{0} {1}", id.Identifier, id.Version) : string.Format ("{0} {1} {2} Profile", id.Identifier, id.Version, id.Profile); - Assemblies = new AssemblyInfo[0]; + Assemblies = new AssemblyInfo [0]; } - + public string Name { get { if (string.IsNullOrEmpty (name)) { @@ -76,19 +74,19 @@ namespace MonoDevelop.Core.Assemblies return name; } } - + public TargetFrameworkMoniker Id { get { return id; } } - [Obsolete("It is no longer possible to define a hidden framework")] + [Obsolete ("It is no longer possible to define a hidden framework")] public bool Hidden { get; } = false; - - [Obsolete("This value is no longer meaningful")] + + [Obsolete ("This value is no longer meaningful")] public ClrVersion ClrVersion { get; } = ClrVersion.Net_4_0; - + static bool ProfileMatchesPattern (string profile, string pattern) { if (string.IsNullOrEmpty (pattern)) @@ -163,12 +161,12 @@ namespace MonoDevelop.Core.Assemblies return fx.Id.Identifier == id.Identifier && new Version (fx.Id.Version).CompareTo (new Version (id.Version)) <= 0; } - + internal string GetCorlibVersion () { if (corlibVersion != null) return corlibVersion; - + foreach (AssemblyInfo asm in Assemblies) { if (asm.Name == "mscorlib") return corlibVersion = asm.Version; @@ -185,121 +183,102 @@ namespace MonoDevelop.Core.Assemblies get { return includedFrameworks; } } - #pragma warning disable 649 +#pragma warning disable 649 string includesFramework; - #pragma warning restore 649 +#pragma warning restore 649 internal TargetFrameworkMoniker GetIncludesFramework () { if (string.IsNullOrEmpty (includesFramework)) return null; - string version = includesFramework[0] == 'v'? + string version = includesFramework [0] == 'v' ? includesFramework.Substring (1) : includesFramework; if (version.Length == 0) throw new InvalidOperationException ("Invalid include version in framework " + id); - - return new TargetFrameworkMoniker (id.Identifier, version); + + return new TargetFrameworkMoniker (id.Identifier, version); } - + public List<SupportedFramework> SupportedFrameworks { get { return supportedFrameworks; } } - - internal AssemblyInfo[] Assemblies { + + internal AssemblyInfo [] Assemblies { get; set; } - + + internal string FrameworkAssembliesDirectory { get; set; } + public override string ToString () { return $"[TargetFramework: Name={Name}, Id={Id}]"; } - + public static TargetFramework FromFrameworkDirectory (TargetFrameworkMoniker moniker, FilePath dir) { - var fxList = dir.Combine ("RedistList", "FrameworkList.xml"); - if (!File.Exists (fxList)) + var fxListFile = dir.Combine ("RedistList", "FrameworkList.xml"); + var fxListInfo = new FileInfo (fxListFile); + if (!fxListInfo.Exists) return null; - - var fx = new TargetFramework (moniker); - - using (var reader = System.Xml.XmlReader.Create (fxList)) { - if (!reader.ReadToDescendant ("FileList")) - throw new Exception ("Missing FileList element"); - - //not sure what this is for - //if (reader.MoveToAttribute ("Redist") && reader.ReadAttributeValue ()) - // redist = reader.ReadContentAsString (); - - if (reader.MoveToAttribute ("Name") && reader.ReadAttributeValue ()) - fx.name = reader.ReadContentAsString (); - - if (reader.MoveToAttribute ("IncludeFramework") && reader.ReadAttributeValue ()) { - string include = reader.ReadContentAsString (); - if (!string.IsNullOrEmpty (include)) - fx.includesFramework = include; - } - - //this is a Mono-specific extension - if (reader.MoveToAttribute ("TargetFrameworkDirectory") && reader.ReadAttributeValue ()) { - string targetDir = reader.ReadContentAsString (); - if (!string.IsNullOrEmpty (targetDir)) { - targetDir = targetDir.Replace ('\\', System.IO.Path.DirectorySeparatorChar); - dir = fxList.ParentDirectory.Combine (targetDir).FullPath; - } + + var fxCacheDir = UserProfile.Current.CacheDir.Combine ("FrameworkInfo"); + + var cacheKey = moniker.Identifier + "_" + moniker.Version; + if (!string.IsNullOrEmpty (moniker.Profile)) { + cacheKey += "_" + moniker.Profile; + } + + FrameworkInfo fxInfo; + + var cachedListFile = fxCacheDir.Combine (cacheKey + ".xml"); + var cachedListInfo = new FileInfo (cachedListFile); + if (cachedListInfo.Exists && cachedListInfo.LastWriteTime == fxListInfo.LastWriteTime) { + fxInfo = FrameworkInfo.Load (moniker, cachedListFile); + } else { + fxInfo = FrameworkInfo.Load (moniker, fxListFile); + var supportedFrameworksDir = dir.Combine ("SupportedFrameworks"); + if (Directory.Exists (supportedFrameworksDir)) { + foreach (var sfx in Directory.EnumerateFiles (supportedFrameworksDir)) + fxInfo.SupportedFrameworks.Add (SupportedFramework.Load (sfx)); } - - var assemblies = new List<AssemblyInfo> (); - if (reader.ReadToFollowing ("File")) { - do { - var ainfo = new AssemblyInfo (); - assemblies.Add (ainfo); - if (reader.MoveToAttribute ("AssemblyName") && reader.ReadAttributeValue ()) - ainfo.Name = reader.ReadContentAsString (); - if (string.IsNullOrEmpty (ainfo.Name)) - throw new Exception ("Missing AssemblyName attribute"); - if (reader.MoveToAttribute ("Version") && reader.ReadAttributeValue ()) - ainfo.Version = reader.ReadContentAsString (); - if (reader.MoveToAttribute ("PublicKeyToken") && reader.ReadAttributeValue ()) - ainfo.PublicKeyToken = reader.ReadContentAsString (); - if (reader.MoveToAttribute ("Culture") && reader.ReadAttributeValue ()) - ainfo.Culture = reader.ReadContentAsString (); - if (reader.MoveToAttribute ("ProcessorArchitecture") && reader.ReadAttributeValue ()) - ainfo.ProcessorArchitecture = (ProcessorArchitecture) - Enum.Parse (typeof (ProcessorArchitecture), reader.ReadContentAsString (), true); - if (reader.MoveToAttribute ("InGac") && reader.ReadAttributeValue ()) - ainfo.InGac = reader.ReadContentAsBoolean (); - } while (reader.ReadToFollowing ("File")); - } else if (Directory.Exists (dir)) { - - foreach (var f in Directory.EnumerateFiles (dir, "*.dll")) { - try { - var an = SystemAssemblyService.GetAssemblyNameObj (dir.Combine (f)); - var ainfo = new AssemblyInfo (); - ainfo.Update (an); - assemblies.Add (ainfo); - } catch (BadImageFormatException ex) { - LoggingService.LogError ("Invalid assembly in framework '{0}': {1}{2}{3}", fx.Id, f, Environment.NewLine, ex.ToString ()); - } catch (Exception ex) { - LoggingService.LogError ("Error reading assembly '{0}' in framework '{1}':{2}{3}", - f, fx.Id, Environment.NewLine, ex.ToString ()); - } - } + if (fxInfo.Assemblies.Count == 0) { + fxInfo.Assemblies = ScanAssemblyDirectory (moniker, fxInfo.TargetFrameworkDirectory); } - - fx.Assemblies = assemblies.ToArray (); + Directory.CreateDirectory (fxCacheDir); + fxInfo.Save (cachedListFile); + File.SetLastWriteTime (cachedListFile, fxListInfo.LastWriteTime); } - - var supportedFrameworksDir = dir.Combine ("SupportedFrameworks"); - if (Directory.Exists (supportedFrameworksDir)) { - foreach (var sfx in Directory.GetFiles (supportedFrameworksDir)) - fx.SupportedFrameworks.Add (SupportedFramework.Load (fx, sfx)); + + return new TargetFramework (moniker) { + name = fxInfo.Name, + includesFramework = fxInfo.IncludeFramework, + Assemblies = fxInfo.Assemblies.ToArray (), + supportedFrameworks = fxInfo.SupportedFrameworks, + FrameworkAssembliesDirectory = fxInfo.TargetFrameworkDirectory + }; + } + + static List<AssemblyInfo> ScanAssemblyDirectory (TargetFrameworkMoniker tfm, FilePath dir) + { + var assemblies = new List<AssemblyInfo> (); + foreach (var f in Directory.EnumerateFiles (dir, "*.dll")) { + try { + var an = SystemAssemblyService.GetAssemblyNameObj (dir.Combine (f)); + var ainfo = new AssemblyInfo (); + ainfo.Update (an); + assemblies.Add (ainfo); + } catch (BadImageFormatException ex) { + LoggingService.LogError ("Invalid assembly in framework '{0}': {1}{2}{3}", tfm, f, Environment.NewLine, ex.ToString ()); + } catch (Exception ex) { + LoggingService.LogError ("Error reading assembly '{0}' in framework '{1}':{2}{3}", + f, tfm, Environment.NewLine, ex.ToString ()); + } } - - return fx; + return assemblies; } } - + class AssemblyInfo { [ItemProperty ("name")] diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/TargetFrameworkBackend.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/TargetFrameworkBackend.cs index 1e93638b32..9c69d7e490 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/TargetFrameworkBackend.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/TargetFrameworkBackend.cs @@ -27,6 +27,7 @@ using System; using System.IO; using System.Collections.Generic; +using System.Linq; namespace MonoDevelop.Core.Assemblies { @@ -46,32 +47,41 @@ namespace MonoDevelop.Core.Assemblies bool? isInstalled; public virtual bool IsInstalled { get { - if (isInstalled != null) - return isInstalled.Value; - - foreach (string dir in GetFrameworkFolders ()) { - if (Directory.Exists (dir)) { - string manifest = Path.Combine (dir, "RedistList", "FrameworkList.xml"); - if (File.Exists (manifest)) { - isInstalled = true; - return true; - } - if (framework.Assemblies.Length > 0) { - string firstAsm = Path.Combine (dir, framework.Assemblies [0].Name) + ".dll"; - if (File.Exists (firstAsm)) { - isInstalled = true; - return true; - } - } - } + if (isInstalled == null) + isInstalled = GetFrameworkFolders ().Any (); + return isInstalled.Value; + } + internal set { + isInstalled = value; + } + } + + internal string ReferenceAssembliesFolder { get; set; } + + protected virtual string OnGetReferenceAssembliesFolder () + { + var fxDir = framework.Id.GetAssemblyDirectoryName (); + foreach (var rootDir in runtime.GetReferenceFrameworkDirectories ()) { + var dir = rootDir.Combine (fxDir); + var frameworkList = dir.Combine ("RedistList", "FrameworkList.xml"); + if (File.Exists (frameworkList)) + return dir; + } + return null; + } + + public virtual IEnumerable<string> GetFrameworkFolders () + { + if (!string.IsNullOrEmpty (ReferenceAssembliesFolder)) { + yield return ReferenceAssembliesFolder; + } else { + ReferenceAssembliesFolder = OnGetReferenceAssembliesFolder () ?? ""; + if (!string.IsNullOrEmpty (ReferenceAssembliesFolder)) { + yield return ReferenceAssembliesFolder; } - isInstalled = false; - return false; } } - public abstract IEnumerable<string> GetFrameworkFolders (); - public virtual Dictionary<string, string> GetToolsEnvironmentVariables () { return new Dictionary<string,string> (); @@ -151,7 +161,7 @@ namespace MonoDevelop.Core.Assemblies public override IEnumerable<string> GetFrameworkFolders () { - return null; + yield break; } public override bool IsInstalled { diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/TargetRuntime.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/TargetRuntime.cs index dd5a651d23..6ec1e3b665 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/TargetRuntime.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/TargetRuntime.cs @@ -27,21 +27,16 @@ // THE SOFTWARE. using System; -using System.Threading; -using System.IO; -using System.Xml; -using System.Collections; using System.Collections.Generic; using System.Diagnostics; -using System.Reflection; -using System.Collections.Specialized; -using MonoDevelop.Core.Execution; -using MonoDevelop.Core.AddIns; -using MonoDevelop.Core.Serialization; +using System.IO; +using System.Linq; +using System.Threading; using Mono.Addins; -using Mono.PkgConfig; +using MonoDevelop.Core.AddIns; +using MonoDevelop.Core.Execution; using MonoDevelop.Core.Instrumentation; -using System.Linq; +using System.Runtime.CompilerServices; namespace MonoDevelop.Core.Assemblies { @@ -244,19 +239,23 @@ namespace MonoDevelop.Core.Assemblies protected virtual void ConvertAssemblyProcessStartInfo (ProcessStartInfo pinfo) { } - + + NotSupportedFrameworkBackend NotSupportedBackend = new NotSupportedFrameworkBackend (); + protected TargetFrameworkBackend GetBackend (TargetFramework fx) { EnsureInitialized (); - lock (frameworkBackends) { - TargetFrameworkBackend backend; - if (frameworkBackends.TryGetValue (fx.Id, out backend)) - return backend; - backend = CreateBackend (fx) ?? new NotSupportedFrameworkBackend (); - backend.Initialize (this, fx); - frameworkBackends[fx.Id] = backend; + if (frameworkBackends.TryGetValue (fx.Id, out TargetFrameworkBackend backend)) return backend; - } + return NotSupportedBackend; + } + + TargetFrameworkBackend CreateAndInitializeBackend (TargetFramework fx) + { + var backend = CreateBackend (fx); + backend.Initialize (this, fx); + frameworkBackends [fx.Id] = backend; + return backend; } protected virtual TargetFrameworkBackend CreateBackend (TargetFramework fx) @@ -385,9 +384,19 @@ namespace MonoDevelop.Core.Assemblies } } } - + + //runtimes can't get deinitialized, so add an inlinable fast path + [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void EnsureInitialized () { + if (initialized) { + return; + } + EnsureInitializedSlow (); + } + + void EnsureInitializedSlow() + { lock (initLock) { if (!initialized && !initializing) { if (!backgroundInitialize) { @@ -542,20 +551,27 @@ namespace MonoDevelop.Core.Assemblies void CreateFrameworks () { var frameworks = new HashSet<TargetFrameworkMoniker> (); - - foreach (TargetFramework fx in Runtime.SystemAssemblyService.GetKnownFrameworks ()) { - // A framework is installed if the assemblies directory exists and the first - // assembly of the list exists. - if (frameworks.Add (fx.Id) && IsInstalled (fx)) { - timer.Trace ("Registering assemblies for framework " + fx.Id); + + //register custom frameworks first. they may have been found by another runtime + //already, but we want to use this runtime's version so path info is correct + foreach (TargetFramework fx in CustomFrameworks) { + if (frameworks.Add (fx.Id)) { + //if the framework was discovered in this runtime, we know it's installed + var backend = CreateAndInitializeBackend (fx); + backend.IsInstalled = true; + backend.ReferenceAssembliesFolder = fx.FrameworkAssembliesDirectory; RegisterSystemAssemblies (fx); } } - - foreach (TargetFramework fx in CustomFrameworks) { - if (frameworks.Add (fx.Id) && IsInstalled (fx)) { - timer.Trace ("Registering assemblies for framework " + fx.Id); - RegisterSystemAssemblies (fx); + + foreach (TargetFramework fx in Runtime.SystemAssemblyService.GetKnownFrameworks ()) { + // A framework is installed if the assemblies directory exists and the first + // assembly of the list exists. + if (frameworks.Add (fx.Id)) { + var backend = CreateAndInitializeBackend (fx); + if (backend.IsInstalled) { + RegisterSystemAssemblies (fx); + } } } } @@ -567,45 +583,18 @@ namespace MonoDevelop.Core.Assemblies void RegisterSystemAssemblies (TargetFramework fx) { - Dictionary<string,List<SystemAssembly>> assemblies = new Dictionary<string, List<SystemAssembly>> (); - Dictionary<string,SystemPackage> packs = new Dictionary<string, SystemPackage> (); - - IEnumerable<string> dirs = GetFrameworkFolders (fx); - + var assemblies = new List<SystemAssembly> (); + var package = new SystemPackage (); foreach (AssemblyInfo assembly in fx.Assemblies) { - foreach (string dir in dirs) { - string file = Path.Combine (dir, assembly.Name) + ".dll"; - if (File.Exists (file)) { - if (assembly.Version == null && IsRunning) { - try { - AssemblyName aname = SystemAssemblyService.GetAssemblyNameObj (file); - assembly.Update (aname); - } catch { - // If something goes wrong when getting the name, just ignore the assembly - } - } - string pkg = assembly.Package ?? string.Empty; - SystemPackage package; - if (!packs.TryGetValue (pkg, out package)) { - packs [pkg] = package = new SystemPackage (); - assemblies [pkg] = new List<SystemAssembly> (); - } - List<SystemAssembly> list = assemblies [pkg]; - list.Add (assemblyContext.AddAssembly (file, assembly, package)); - break; - } - } - } - - foreach (string pkg in packs.Keys) { - SystemPackage package = packs [pkg]; - List<SystemAssembly> list = assemblies [pkg]; - SystemPackageInfo info = GetFrameworkPackageInfo (fx, pkg); - if (!info.IsCorePackage) - corePackages.Add (info.Name); - package.Initialize (info, list.ToArray (), false); - assemblyContext.InternalAddPackage (package); + var file = Path.Combine (fx.FrameworkAssembliesDirectory, assembly.Name + ".dll"); + assemblies.Add (assemblyContext.AddAssembly (file, assembly, package)); } + + SystemPackageInfo info = GetFrameworkPackageInfo (fx, ""); + package.Initialize (info, assemblies, false); + if (!info.IsCorePackage) + corePackages.Add (info.Name); + assemblyContext.InternalAddPackage (package); } protected virtual SystemPackageInfo GetFrameworkPackageInfo (TargetFramework fx, string packageName) diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.csproj b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.csproj index 4692af099b..ee14abcc69 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.csproj +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.csproj @@ -763,6 +763,7 @@ <Compile Include="MonoDevelop.Core\ObjectPool.cs" /> <Compile Include="MonoDevelop.Core\SharedPools.cs" /> <Compile Include="MonoDevelop.Core.Collections\LookupTable.cs" /> + <Compile Include="MonoDevelop.Core.Assemblies\FrameworkInfo.cs" /> </ItemGroup> <ItemGroup> <None Include="Makefile.am" /> diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Projects.OptionPanels/PortableRuntimeSelectorDialog.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Projects.OptionPanels/PortableRuntimeSelectorDialog.cs index d56604b2cb..8d7bb8fa2d 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Projects.OptionPanels/PortableRuntimeSelectorDialog.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Projects.OptionPanels/PortableRuntimeSelectorDialog.cs @@ -59,13 +59,11 @@ namespace MonoDevelop.Ide.Projects.OptionPanels { public readonly string Name; public readonly SupportedFramework Framework; - public readonly List<TargetFramework> Targets; public OptionComboItem (string name, SupportedFramework sfx) { this.Name = name; this.Framework = sfx; - this.Targets = new List<TargetFramework> (); } } @@ -138,8 +136,6 @@ namespace MonoDevelop.Ide.Projects.OptionPanels item = new OptionComboItem (label, sfx); dict.Add (label, item); } - - item.Targets.Add (sfx.TargetFramework); } combo.Items = dict.Values.ToList (); @@ -277,7 +273,7 @@ namespace MonoDevelop.Ide.Projects.OptionPanels void AddTopSelectorCombo () { - var model = new ListStore (new Type[] { typeof (string), typeof (object) }); + var model = new ListStore (new Type[] { typeof (string) }); var renderer = new CellRendererText (); var combo = selectorCombo = new ComboBox (model); @@ -337,7 +333,7 @@ namespace MonoDevelop.Ide.Projects.OptionPanels if (hasOtherVersions && string.IsNullOrEmpty (sfx.MonoSpecificVersionDisplayName)) label += " or later"; - model.AppendValues (label, item.Targets); + model.AppendValues (label); } option.Combo = new ComboBox (model); |