From d118448cba85ddf83456602498bf286c9e03e1a8 Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Mon, 11 Jul 2016 14:06:33 -0700 Subject: [PATCH 01/16] fix conflicts --- .../Tracing/PerfTraceOutput.cs | 3 +- .../Compilation/LibraryExporter.cs | 24 +++++-- .../Files/PatternGroup.cs | 64 +++++++++++++------ .../ProjectContext.cs | 7 +- 4 files changed, 70 insertions(+), 28 deletions(-) diff --git a/src/Microsoft.DotNet.Cli.Utils/Tracing/PerfTraceOutput.cs b/src/Microsoft.DotNet.Cli.Utils/Tracing/PerfTraceOutput.cs index 2212efb14e..099ff8afd4 100644 --- a/src/Microsoft.DotNet.Cli.Utils/Tracing/PerfTraceOutput.cs +++ b/src/Microsoft.DotNet.Cli.Utils/Tracing/PerfTraceOutput.cs @@ -50,7 +50,8 @@ private static void FormatEventTimeStat(StringBuilder builder, PerfTraceEvent e, AppendTime(builder, e.Duration.TotalSeconds / root.Duration.TotalSeconds, 0.2); } AppendTime(builder, e.Duration.TotalSeconds / parent?.Duration.TotalSeconds, 0.5); - builder.Append($"{e.Duration.ToString("ss\\.fff\\s").Blue()}]"); + builder.Append($"{(int)e.Duration.TotalSeconds}.{e.Duration.Milliseconds:000}s".Blue()); + builder.Append("]"); } private static void AppendTime(StringBuilder builder, double? percent, double treshold) diff --git a/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExporter.cs b/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExporter.cs index f5682ef29c..d7a77a9517 100644 --- a/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExporter.cs +++ b/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExporter.cs @@ -24,6 +24,7 @@ public class LibraryExporter private readonly ProjectDescription _rootProject; private readonly string _buildBasePath; private readonly string _solutionRootPath; + private IEnumerable _cachedExports; public LibraryExporter(ProjectDescription rootProject, LibraryManager manager, @@ -84,16 +85,29 @@ public IEnumerable GetDependencies(LibraryType type) /// private IEnumerable ExportLibraries(Func condition) { - var seenMetadataReferences = new HashSet(); - - // Iterate over libraries in the library manager - foreach (var library in LibraryManager.GetLibraries()) + if (_cachedExports == null) { - if (!condition(library)) + _cachedExports = GetAllExportsImpl().ToArray(); + } + foreach (var export in _cachedExports) + { + if (!condition(export.Library)) { continue; } + yield return export; + } + } + private IEnumerable GetAllExportsImpl() + { + using (PerfTrace.Current.CaptureTiming()) + { + var seenMetadataReferences = new HashSet(); + + // Iterate over libraries in the library manager + foreach (var library in LibraryManager.GetLibraries()) + { var compilationAssemblies = new List(); var sourceReferences = new List(); var analyzerReferences = new List(); diff --git a/src/Microsoft.DotNet.ProjectModel/Files/PatternGroup.cs b/src/Microsoft.DotNet.ProjectModel/Files/PatternGroup.cs index 80c8e81577..cea9cdadd0 100644 --- a/src/Microsoft.DotNet.ProjectModel/Files/PatternGroup.cs +++ b/src/Microsoft.DotNet.ProjectModel/Files/PatternGroup.cs @@ -14,6 +14,7 @@ public class PatternGroup { private readonly List _excludeGroups = new List(); private readonly Matcher _matcher = new Matcher(); + static readonly Dictionary> Cache = new Dictionary>(); internal PatternGroup(IEnumerable includePatterns) { @@ -82,37 +83,58 @@ public PatternGroup ExcludeGroup(PatternGroup group) public IEnumerable SearchFiles(string rootPath) { - // literal included files are added at the last, but the search happens early - // so as to make the process fail early in case there is missing file. fail early - // helps to avoid unnecessary globing for performance optimization - var literalIncludedFiles = new List(); - foreach (var literalRelativePath in IncludeLiterals) + var key = rootPath + + (IncludePatterns.Any() ? " ++ " + string.Join(", ", IncludePatterns): "") + + (IncludeLiterals.Any() ? " + " + string.Join(", ", IncludeLiterals) : "") + + (ExcludePatterns.Any() ? " -- " + string.Join(", ", ExcludePatterns) : ""); + IEnumerable result; + lock (Cache) { - var fullPath = Path.GetFullPath(Path.Combine(rootPath, literalRelativePath)); + if (Cache.TryGetValue(key, out result)) + { + return result; + } + } - if (!File.Exists(fullPath)) + using (PerfTrace.Current.CaptureTiming(key)) + { + // literal included files are added at the last, but the search happens early + // so as to make the process fail early in case there is missing file. fail early + // helps to avoid unnecessary globing for performance optimization + var literalIncludedFiles = new List(); + foreach (var literalRelativePath in IncludeLiterals) { - throw new InvalidOperationException(string.Format("Can't find file {0}", literalRelativePath)); + var fullPath = Path.GetFullPath(Path.Combine(rootPath, literalRelativePath)); + + if (!File.Exists(fullPath)) + { + throw new InvalidOperationException(string.Format("Can't find file {0}", literalRelativePath)); + } + + // TODO: extract utility like NuGet.PathUtility.GetPathWithForwardSlashes() + literalIncludedFiles.Add(fullPath.Replace('\\', '/')); } - // TODO: extract utility like NuGet.PathUtility.GetPathWithForwardSlashes() - literalIncludedFiles.Add(fullPath.Replace('\\', '/')); - } + // globing files + var globbingResults = _matcher.GetResultsInFullPath(rootPath); - // globing files - var globbingResults = _matcher.GetResultsInFullPath(rootPath); + // if there is no results generated in globing, skip excluding other groups + // for performance optimization. + if (globbingResults.Any()) + { + foreach (var group in _excludeGroups) + { + globbingResults = globbingResults.Except(group.SearchFiles(rootPath)); + } + } - // if there is no results generated in globing, skip excluding other groups - // for performance optimization. - if (globbingResults.Any()) - { - foreach (var group in _excludeGroups) + result = globbingResults.Concat(literalIncludedFiles).Distinct(); + lock (Cache) { - globbingResults = globbingResults.Except(group.SearchFiles(rootPath)); + Cache.Add(key, result); } } - - return globbingResults.Concat(literalIncludedFiles).Distinct(); + return result; } public override string ToString() diff --git a/src/Microsoft.DotNet.ProjectModel/ProjectContext.cs b/src/Microsoft.DotNet.ProjectModel/ProjectContext.cs index 14a6d17f9f..bf24b914c8 100644 --- a/src/Microsoft.DotNet.ProjectModel/ProjectContext.cs +++ b/src/Microsoft.DotNet.ProjectModel/ProjectContext.cs @@ -15,6 +15,7 @@ namespace Microsoft.DotNet.ProjectModel public class ProjectContext { private string[] _runtimeFallbacks; + private LibraryExporter _exporter; public ProjectContextIdentity Identity { get; } @@ -71,12 +72,16 @@ internal ProjectContext( public LibraryExporter CreateExporter(string configuration, string buildBasePath = null) { + if (_exporter != null) + { + return _exporter; + } if (IsPortable && RuntimeIdentifier != null && _runtimeFallbacks == null) { var graph = RuntimeGraphCollector.Collect(LibraryManager.GetLibraries()); _runtimeFallbacks = graph.ExpandRuntime(RuntimeIdentifier).ToArray(); } - return new LibraryExporter(RootProject, + return _exporter = new LibraryExporter(RootProject, LibraryManager, configuration, RuntimeIdentifier, From eb02a34bbcab36aba63f7892c25d9434bedad366 Mon Sep 17 00:00:00 2001 From: Bryan Thornbury Date: Fri, 22 Jul 2016 19:11:35 -0700 Subject: [PATCH 02/16] Fix bug with libraryexporter caching, add test for libraryexporter caching, general refactor of changes --- .../Compilation/LibraryExporter.cs | 15 ++-- .../Files/PatternGroup.cs | 83 +++++++++++-------- .../ProjectContext.cs | 18 +++- .../GivenAProjectContext.cs | 72 ++++++++++++++++ .../project.json | 3 +- 5 files changed, 142 insertions(+), 49 deletions(-) create mode 100644 test/Microsoft.DotNet.ProjectModel.Tests/GivenAProjectContext.cs diff --git a/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExporter.cs b/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExporter.cs index d7a77a9517..804f3ac324 100644 --- a/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExporter.cs +++ b/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExporter.cs @@ -24,6 +24,7 @@ public class LibraryExporter private readonly ProjectDescription _rootProject; private readonly string _buildBasePath; private readonly string _solutionRootPath; + private IEnumerable _cachedExports; public LibraryExporter(ProjectDescription rootProject, @@ -85,11 +86,9 @@ public IEnumerable GetDependencies(LibraryType type) /// private IEnumerable ExportLibraries(Func condition) { - if (_cachedExports == null) - { - _cachedExports = GetAllExportsImpl().ToArray(); - } - foreach (var export in _cachedExports) + IEnumerable exports = _cachedExports ?? (_cachedExports = CalculateAllExports().ToArray()); + + foreach (var export in exports) { if (!condition(export.Library)) { @@ -99,11 +98,9 @@ private IEnumerable ExportLibraries(Func GetAllExportsImpl() + private IEnumerable CalculateAllExports() { - using (PerfTrace.Current.CaptureTiming()) - { - var seenMetadataReferences = new HashSet(); + var seenMetadataReferences = new HashSet(); // Iterate over libraries in the library manager foreach (var library in LibraryManager.GetLibraries()) diff --git a/src/Microsoft.DotNet.ProjectModel/Files/PatternGroup.cs b/src/Microsoft.DotNet.ProjectModel/Files/PatternGroup.cs index cea9cdadd0..c59277f048 100644 --- a/src/Microsoft.DotNet.ProjectModel/Files/PatternGroup.cs +++ b/src/Microsoft.DotNet.ProjectModel/Files/PatternGroup.cs @@ -12,9 +12,10 @@ namespace Microsoft.DotNet.ProjectModel.Files { public class PatternGroup { + private static readonly Dictionary> s_resolvedFilesCache = new Dictionary>(); + private readonly List _excludeGroups = new List(); private readonly Matcher _matcher = new Matcher(); - static readonly Dictionary> Cache = new Dictionary>(); internal PatternGroup(IEnumerable includePatterns) { @@ -81,60 +82,72 @@ public PatternGroup ExcludeGroup(PatternGroup group) return this; } - public IEnumerable SearchFiles(string rootPath) + public IEnumerable SearchFiles(string rootDirectory) { - var key = rootPath + var patternUnionKey = rootDirectory + (IncludePatterns.Any() ? " ++ " + string.Join(", ", IncludePatterns): "") + (IncludeLiterals.Any() ? " + " + string.Join(", ", IncludeLiterals) : "") + (ExcludePatterns.Any() ? " -- " + string.Join(", ", ExcludePatterns) : ""); - IEnumerable result; - lock (Cache) + + IEnumerable resolvedFiles; + lock (s_resolvedFilesCache) { - if (Cache.TryGetValue(key, out result)) + if (s_resolvedFilesCache.TryGetValue(patternUnionKey, out resolvedFiles)) { - return result; + return resolvedFiles; } } - using (PerfTrace.Current.CaptureTiming(key)) + resolvedFiles = ResolveFilesFromPatterns(rootDirectory, IncludePatterns, IncludeLiterals, ExcludePatterns); + + lock (s_resolvedFilesCache) { - // literal included files are added at the last, but the search happens early - // so as to make the process fail early in case there is missing file. fail early - // helps to avoid unnecessary globing for performance optimization - var literalIncludedFiles = new List(); - foreach (var literalRelativePath in IncludeLiterals) - { - var fullPath = Path.GetFullPath(Path.Combine(rootPath, literalRelativePath)); + s_resolvedFilesCache.Add(patternUnionKey, resolvedFiles); + } - if (!File.Exists(fullPath)) - { - throw new InvalidOperationException(string.Format("Can't find file {0}", literalRelativePath)); - } + return resolvedFiles; + } - // TODO: extract utility like NuGet.PathUtility.GetPathWithForwardSlashes() - literalIncludedFiles.Add(fullPath.Replace('\\', '/')); - } + private IEnumerable ResolveFilesFromPatterns( + string rootDirectory, + IEnumerable includePatterns, + IEnumerable includeLiterals, + IEnumerable excludePatterns) + { + IEnumerable resolvedFiles; - // globing files - var globbingResults = _matcher.GetResultsInFullPath(rootPath); + // literal included files are added at the last, but the search happens early + // so as to make the process fail early in case there is missing file. fail early + // helps to avoid unnecessary globing for performance optimization + var literalIncludedFiles = new List(); + foreach (var literalRelativePath in IncludeLiterals) + { + var fullPath = Path.GetFullPath(Path.Combine(rootDirectory, literalRelativePath)); - // if there is no results generated in globing, skip excluding other groups - // for performance optimization. - if (globbingResults.Any()) + if (!File.Exists(fullPath)) { - foreach (var group in _excludeGroups) - { - globbingResults = globbingResults.Except(group.SearchFiles(rootPath)); - } + throw new InvalidOperationException(string.Format("Can't find file {0}", literalRelativePath)); } - result = globbingResults.Concat(literalIncludedFiles).Distinct(); - lock (Cache) + // TODO: extract utility like NuGet.PathUtility.GetPathWithForwardSlashes() + literalIncludedFiles.Add(fullPath.Replace('\\', '/')); + } + + // globing files + var globbingResults = _matcher.GetResultsInFullPath(rootDirectory); + + // if there is no results generated in globing, skip excluding other groups + // for performance optimization. + if (globbingResults.Any()) + { + foreach (var group in _excludeGroups) { - Cache.Add(key, result); + globbingResults = globbingResults.Except(group.SearchFiles(rootDirectory)); } } - return result; + + resolvedFiles = globbingResults.Concat(literalIncludedFiles).Distinct(); + return resolvedFiles; } public override string ToString() diff --git a/src/Microsoft.DotNet.ProjectModel/ProjectContext.cs b/src/Microsoft.DotNet.ProjectModel/ProjectContext.cs index bf24b914c8..30b452f44d 100644 --- a/src/Microsoft.DotNet.ProjectModel/ProjectContext.cs +++ b/src/Microsoft.DotNet.ProjectModel/ProjectContext.cs @@ -14,8 +14,9 @@ namespace Microsoft.DotNet.ProjectModel { public class ProjectContext { + private readonly Dictionary _cachedExporters = new Dictionary(); + private string[] _runtimeFallbacks; - private LibraryExporter _exporter; public ProjectContextIdentity Identity { get; } @@ -72,22 +73,31 @@ internal ProjectContext( public LibraryExporter CreateExporter(string configuration, string buildBasePath = null) { - if (_exporter != null) + LibraryExporter exporter; + var libraryExporterCacheKey = "+ " + (configuration ?? "") + " - " + (buildBasePath ?? ""); + + if (_cachedExporters.TryGetValue(libraryExporterCacheKey, out exporter)) { - return _exporter; + return exporter; } + if (IsPortable && RuntimeIdentifier != null && _runtimeFallbacks == null) { var graph = RuntimeGraphCollector.Collect(LibraryManager.GetLibraries()); _runtimeFallbacks = graph.ExpandRuntime(RuntimeIdentifier).ToArray(); } - return _exporter = new LibraryExporter(RootProject, + + exporter = new LibraryExporter(RootProject, LibraryManager, configuration, RuntimeIdentifier, _runtimeFallbacks, buildBasePath, RootDirectory); + + _cachedExporters[libraryExporterCacheKey] = exporter; + + return exporter; } /// diff --git a/test/Microsoft.DotNet.ProjectModel.Tests/GivenAProjectContext.cs b/test/Microsoft.DotNet.ProjectModel.Tests/GivenAProjectContext.cs new file mode 100644 index 0000000000..77c15abdac --- /dev/null +++ b/test/Microsoft.DotNet.ProjectModel.Tests/GivenAProjectContext.cs @@ -0,0 +1,72 @@ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using Microsoft.DotNet.ProjectModel; +using Microsoft.DotNet.ProjectModel.Compilation; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Xunit; +using System.Linq; +using FluentAssertions; +using Microsoft.DotNet.Tools.Test.Utilities; +using NuGet.Frameworks; + +namespace Microsoft.DotNet.ProjectModel.Tests +{ + public class GivenAProjectContext : TestBase + { + [Fact] + public void It_caches_library_exporter_when_configuration_and_buildBasePath_keep_value() + { + var projectContext = GetProjectContext(); + + var configurations = new string[] { "TestConfig", "TestConfig", "TestConfig2", "TestConfig2" }; + var buildBasePaths = new string[] { null, AppContext.BaseDirectory, null, AppContext.BaseDirectory }; + + for(int i=0; i(); + + for(int i=0; i Date: Mon, 25 Jul 2016 16:17:34 -0700 Subject: [PATCH 03/16] GetTypeBuildExclusionList Optimization. GetPlatformExclusionList Optimization. --- .../ProjectModelPlatformExtensions.cs | 71 ++++++++++++++----- 1 file changed, 53 insertions(+), 18 deletions(-) diff --git a/src/Microsoft.DotNet.ProjectModel/ProjectModelPlatformExtensions.cs b/src/Microsoft.DotNet.ProjectModel/ProjectModelPlatformExtensions.cs index 5f6ea1b94e..2694316ae5 100644 --- a/src/Microsoft.DotNet.ProjectModel/ProjectModelPlatformExtensions.cs +++ b/src/Microsoft.DotNet.ProjectModel/ProjectModelPlatformExtensions.cs @@ -2,6 +2,8 @@ using System.Linq; using Microsoft.DotNet.ProjectModel.Compilation; using Microsoft.DotNet.ProjectModel.Graph; +using Microsoft.DotNet.Cli.Utils; +using System; namespace Microsoft.DotNet.ProjectModel { @@ -28,7 +30,8 @@ private static void CollectDependencies(IDictionary expor foreach (var dependency in dependencies) { var export = exports[dependency.Name]; - if (export.Library.Identity.Version.Equals(dependency.VersionRange.MinVersion)) + if (export.Library.Identity.Version.Equals(dependency.VersionRange.MinVersion) + && !exclusionList.Contains(dependency.Name)) { exclusionList.Add(export.Library.Identity.Name); CollectDependencies(exports, export.Library.Dependencies, exclusionList); @@ -38,31 +41,63 @@ private static void CollectDependencies(IDictionary expor public static HashSet GetTypeBuildExclusionList(this ProjectContext context, IDictionary exports) { - var acceptedExports = new HashSet(); + var rootProject = context.RootProject; + var buildExports = new HashSet(); + var nonBuildExports = new HashSet(); - // Accept the root project, obviously :) - acceptedExports.Add(context.RootProject.Identity.Name); + var nonBuildExportsToSearch = new Stack(); + var buildExportsToSearch = new Stack(); - // Walk all dependencies, tagging exports. But don't walk through Build dependencies. - CollectNonBuildDependencies(exports, context.RootProject.Dependencies, acceptedExports); + LibraryExport export; + string exportName; - // Whatever is left in exports was brought in ONLY by a build dependency - var exclusionList = new HashSet(exports.Keys); - exclusionList.ExceptWith(acceptedExports); - return exclusionList; - } + // Root project is non-build + nonBuildExportsToSearch.Push(rootProject.Identity.Name); + nonBuildExports.Add(rootProject.Identity.Name); - private static void CollectNonBuildDependencies(IDictionary exports, IEnumerable dependencies, HashSet acceptedExports) - { - foreach (var dependency in dependencies) + // Mark down all nonbuild exports and all of their dependencies + // Mark down build exports to come back to them later + while (nonBuildExportsToSearch.Count > 0) { - var export = exports[dependency.Name]; - if (!dependency.Type.Equals(LibraryDependencyType.Build)) + exportName = nonBuildExportsToSearch.Pop(); + export = exports[exportName]; + + foreach (var dependency in export.Library.Dependencies) + { + if (!dependency.Type.Equals(LibraryDependencyType.Build)) + { + if (!nonBuildExports.Contains(dependency.Name)) + { + nonBuildExportsToSearch.Push(dependency.Name); + nonBuildExports.Add(dependency.Name); + } + } + else + { + buildExportsToSearch.Push(dependency.Name); + } + } + } + + // Go through exports marked build and their dependencies + // For Exports not marked as non-build, mark them down as build + while (buildExportsToSearch.Count > 0) + { + exportName = buildExportsToSearch.Pop(); + export = exports[exportName]; + + buildExports.Add(exportName); + + foreach (var dependency in export.Library.Dependencies) { - acceptedExports.Add(export.Library.Identity.Name); - CollectNonBuildDependencies(exports, export.Library.Dependencies, acceptedExports); + if (!nonBuildExports.Contains(dependency.Name)) + { + buildExportsToSearch.Push(dependency.Name); + } } } + + return buildExports; } public static IEnumerable FilterExports(this IEnumerable exports, HashSet exclusionList) From b6080bfa42943ccd1dcfe5715018e5710200c924 Mon Sep 17 00:00:00 2001 From: Bryan Thornbury Date: Tue, 26 Jul 2016 14:16:13 -0700 Subject: [PATCH 04/16] fix unused using --- .../ProjectModelPlatformExtensions.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Microsoft.DotNet.ProjectModel/ProjectModelPlatformExtensions.cs b/src/Microsoft.DotNet.ProjectModel/ProjectModelPlatformExtensions.cs index 2694316ae5..305b23649a 100644 --- a/src/Microsoft.DotNet.ProjectModel/ProjectModelPlatformExtensions.cs +++ b/src/Microsoft.DotNet.ProjectModel/ProjectModelPlatformExtensions.cs @@ -2,7 +2,6 @@ using System.Linq; using Microsoft.DotNet.ProjectModel.Compilation; using Microsoft.DotNet.ProjectModel.Graph; -using Microsoft.DotNet.Cli.Utils; using System; namespace Microsoft.DotNet.ProjectModel From 5f2dd29b7348730849cf362fac427a3dc60ed052 Mon Sep 17 00:00:00 2001 From: Bryan Thornbury Date: Mon, 1 Aug 2016 17:15:52 -0700 Subject: [PATCH 05/16] Clear PatternGroup Cache, PR Feedback --- .../Compilation/LibraryExporter.cs | 4 ++-- .../Files/PatternGroup.cs | 21 ++++++++++++++----- .../ProjectContext.cs | 5 +++-- .../ProjectModelPlatformExtensions.cs | 10 ++++----- .../InternalModels/ProjectContextSnapshot.cs | 6 ++++++ 5 files changed, 32 insertions(+), 14 deletions(-) diff --git a/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExporter.cs b/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExporter.cs index 804f3ac324..805d82b8ea 100644 --- a/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExporter.cs +++ b/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExporter.cs @@ -86,9 +86,9 @@ public IEnumerable GetDependencies(LibraryType type) /// private IEnumerable ExportLibraries(Func condition) { - IEnumerable exports = _cachedExports ?? (_cachedExports = CalculateAllExports().ToArray()); + _cachedExports = _cachedExports ?? CalculateAllExports().ToArray(); - foreach (var export in exports) + foreach (var export in _cachedExports) { if (!condition(export.Library)) { diff --git a/src/Microsoft.DotNet.ProjectModel/Files/PatternGroup.cs b/src/Microsoft.DotNet.ProjectModel/Files/PatternGroup.cs index c59277f048..b821be3485 100644 --- a/src/Microsoft.DotNet.ProjectModel/Files/PatternGroup.cs +++ b/src/Microsoft.DotNet.ProjectModel/Files/PatternGroup.cs @@ -8,11 +8,14 @@ using Microsoft.DotNet.ProjectModel.FileSystemGlobbing; using Newtonsoft.Json.Linq; +using FourStringTuple = System.Tuple; + namespace Microsoft.DotNet.ProjectModel.Files { public class PatternGroup { - private static readonly Dictionary> s_resolvedFilesCache = new Dictionary>(); + private static readonly Dictionary> s_resolvedFilesCache = + new Dictionary>(); private readonly List _excludeGroups = new List(); private readonly Matcher _matcher = new Matcher(); @@ -84,10 +87,10 @@ public PatternGroup ExcludeGroup(PatternGroup group) public IEnumerable SearchFiles(string rootDirectory) { - var patternUnionKey = rootDirectory - + (IncludePatterns.Any() ? " ++ " + string.Join(", ", IncludePatterns): "") - + (IncludeLiterals.Any() ? " + " + string.Join(", ", IncludeLiterals) : "") - + (ExcludePatterns.Any() ? " -- " + string.Join(", ", ExcludePatterns) : ""); + var patternUnionKey = new FourStringTuple(rootDirectory, + (IncludePatterns.Any() ? string.Join(", ", IncludePatterns): ""), + (IncludeLiterals.Any() ? string.Join(", ", IncludeLiterals) : ""), + (ExcludePatterns.Any() ? string.Join(", ", ExcludePatterns) : "")); IEnumerable resolvedFiles; lock (s_resolvedFilesCache) @@ -154,5 +157,13 @@ public override string ToString() { return string.Format("Pattern group: Literals [{0}] Includes [{1}] Excludes [{2}]", string.Join(", ", IncludeLiterals), string.Join(", ", IncludePatterns), string.Join(", ", ExcludePatterns)); } + + public static void ClearCache() + { + if (s_resolvedFilesCache != null) + { + s_resolvedFilesCache.Clear(); + } + } } } diff --git a/src/Microsoft.DotNet.ProjectModel/ProjectContext.cs b/src/Microsoft.DotNet.ProjectModel/ProjectContext.cs index 30b452f44d..6465fda1f1 100644 --- a/src/Microsoft.DotNet.ProjectModel/ProjectContext.cs +++ b/src/Microsoft.DotNet.ProjectModel/ProjectContext.cs @@ -14,7 +14,8 @@ namespace Microsoft.DotNet.ProjectModel { public class ProjectContext { - private readonly Dictionary _cachedExporters = new Dictionary(); + private readonly Dictionary, LibraryExporter> _cachedExporters = + new Dictionary, LibraryExporter>(); private string[] _runtimeFallbacks; @@ -74,7 +75,7 @@ internal ProjectContext( public LibraryExporter CreateExporter(string configuration, string buildBasePath = null) { LibraryExporter exporter; - var libraryExporterCacheKey = "+ " + (configuration ?? "") + " - " + (buildBasePath ?? ""); + var libraryExporterCacheKey = Tuple.Create(configuration ?? "" , buildBasePath ?? ""); if (_cachedExporters.TryGetValue(libraryExporterCacheKey, out exporter)) { diff --git a/src/Microsoft.DotNet.ProjectModel/ProjectModelPlatformExtensions.cs b/src/Microsoft.DotNet.ProjectModel/ProjectModelPlatformExtensions.cs index 305b23649a..dd407e1fee 100644 --- a/src/Microsoft.DotNet.ProjectModel/ProjectModelPlatformExtensions.cs +++ b/src/Microsoft.DotNet.ProjectModel/ProjectModelPlatformExtensions.cs @@ -2,7 +2,6 @@ using System.Linq; using Microsoft.DotNet.ProjectModel.Compilation; using Microsoft.DotNet.ProjectModel.Graph; -using System; namespace Microsoft.DotNet.ProjectModel { @@ -29,11 +28,12 @@ private static void CollectDependencies(IDictionary expor foreach (var dependency in dependencies) { var export = exports[dependency.Name]; - if (export.Library.Identity.Version.Equals(dependency.VersionRange.MinVersion) - && !exclusionList.Contains(dependency.Name)) + if (export.Library.Identity.Version.Equals(dependency.VersionRange.MinVersion)) { - exclusionList.Add(export.Library.Identity.Name); - CollectDependencies(exports, export.Library.Dependencies, exclusionList); + if (exclusionList.Add(export.Library.Identity.Name)) + { + CollectDependencies(exports, export.Library.Dependencies, exclusionList); + } } } } diff --git a/src/dotnet/commands/dotnet-projectmodel-server/InternalModels/ProjectContextSnapshot.cs b/src/dotnet/commands/dotnet-projectmodel-server/InternalModels/ProjectContextSnapshot.cs index 1307714d0e..4ce798fc6a 100644 --- a/src/dotnet/commands/dotnet-projectmodel-server/InternalModels/ProjectContextSnapshot.cs +++ b/src/dotnet/commands/dotnet-projectmodel-server/InternalModels/ProjectContextSnapshot.cs @@ -26,6 +26,9 @@ internal class ProjectContextSnapshot public static ProjectContextSnapshot Create(ProjectContext context, string configuration, IEnumerable previousSearchPaths) { + // Clear cached file glob results + PatternGroup.ClearCache(); + var snapshot = new ProjectContextSnapshot(); var allDependencyDiagnostics = new List(); @@ -78,6 +81,9 @@ public static ProjectContextSnapshot Create(ProjectContext context, string confi private static IEnumerable GetSourceFiles(ProjectContext context, string configuration) { + // Clear cached glob results + PatternGroup.ClearCache(); + var compilerOptions = context.ProjectFile.GetCompilerOptions(context.TargetFramework, configuration); if (compilerOptions.CompileInclude == null) From a8dc2b0e24eda03c0a58274ef713dfee6fa12fe6 Mon Sep 17 00:00:00 2001 From: Bryan Thornbury Date: Mon, 1 Aug 2016 18:34:38 -0700 Subject: [PATCH 06/16] Slight tweak on project context cache --- src/Microsoft.DotNet.ProjectModel/ProjectContext.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.DotNet.ProjectModel/ProjectContext.cs b/src/Microsoft.DotNet.ProjectModel/ProjectContext.cs index 6465fda1f1..a6c8acf840 100644 --- a/src/Microsoft.DotNet.ProjectModel/ProjectContext.cs +++ b/src/Microsoft.DotNet.ProjectModel/ProjectContext.cs @@ -14,8 +14,8 @@ namespace Microsoft.DotNet.ProjectModel { public class ProjectContext { - private readonly Dictionary, LibraryExporter> _cachedExporters = - new Dictionary, LibraryExporter>(); + private readonly Dictionary, LibraryExporter> _cachedExporters = + new Dictionary, LibraryExporter>(); private string[] _runtimeFallbacks; @@ -75,7 +75,10 @@ internal ProjectContext( public LibraryExporter CreateExporter(string configuration, string buildBasePath = null) { LibraryExporter exporter; - var libraryExporterCacheKey = Tuple.Create(configuration ?? "" , buildBasePath ?? ""); + var libraryExporterCacheKey = Tuple.Create( + configuration ?? "", + buildBasePath ?? "", + RootDirectory); if (_cachedExporters.TryGetValue(libraryExporterCacheKey, out exporter)) { From 3871b9a60a40a077aae68f141df0f96ec183eebd Mon Sep 17 00:00:00 2001 From: Bryan Thornbury Date: Mon, 1 Aug 2016 20:26:07 -0700 Subject: [PATCH 07/16] Fix Binding redirects! --- .../Compilation/LibraryExporter.cs | 110 +++++++++++------- 1 file changed, 66 insertions(+), 44 deletions(-) diff --git a/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExporter.cs b/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExporter.cs index 805d82b8ea..d2782c082c 100644 --- a/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExporter.cs +++ b/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExporter.cs @@ -24,8 +24,9 @@ public class LibraryExporter private readonly ProjectDescription _rootProject; private readonly string _buildBasePath; private readonly string _solutionRootPath; + private HashSet _seenMetadataReferences; - private IEnumerable _cachedExports; + private List _cachedExports; public LibraryExporter(ProjectDescription rootProject, LibraryManager manager, @@ -86,9 +87,9 @@ public IEnumerable GetDependencies(LibraryType type) /// private IEnumerable ExportLibraries(Func condition) { - _cachedExports = _cachedExports ?? CalculateAllExports().ToArray(); + var cache = GetCacheWithRefreshedProjectExports(); - foreach (var export in _cachedExports) + foreach (var export in cache) { if (!condition(export.Library)) { @@ -98,59 +99,80 @@ private IEnumerable ExportLibraries(Func GetCacheWithRefreshedProjectExports() + { + if (_cachedExports == null) + { + return (_cachedExports = CalculateAllExports().ToList()); + } + + var nonProjectExports = _cachedExports.Where(export => !Equals(export.Library.Identity.Type, LibraryType.Project)); + var projectExports = _cachedExports.Where(export => Equals(export.Library.Identity.Type, LibraryType.Project)); + var refreshedProjectExports = projectExports.Select(export => GenerateExportFromLibrary(_seenMetadataReferences, export.Library)); + + return nonProjectExports.Concat(refreshedProjectExports); + } + private IEnumerable CalculateAllExports() { - var seenMetadataReferences = new HashSet(); + _seenMetadataReferences = new HashSet(); // Iterate over libraries in the library manager foreach (var library in LibraryManager.GetLibraries()) { - var compilationAssemblies = new List(); - var sourceReferences = new List(); - var analyzerReferences = new List(); - var libraryExport = GetExport(library); - - // We need to filter out source references from non-root libraries, - // so we rebuild the library export - foreach (var reference in libraryExport.CompilationAssemblies) - { - if (seenMetadataReferences.Add(reference.Name)) - { - compilationAssemblies.Add(reference); - } - } + yield return GenerateExportFromLibrary(_seenMetadataReferences, library); + } + } - // Source and analyzer references are not transitive - if (library.Parents.Contains(_rootProject)) + private LibraryExport GenerateExportFromLibrary( + HashSet seenMetadataReferences, + LibraryDescription library) + { + var compilationAssemblies = new List(); + var sourceReferences = new List(); + var analyzerReferences = new List(); + var libraryExport = GetExport(library); + + // We need to filter out source references from non-root libraries, + // so we rebuild the library export + foreach (var reference in libraryExport.CompilationAssemblies) + { + if (seenMetadataReferences.Add(reference.Name)) { - sourceReferences.AddRange(libraryExport.SourceReferences); - analyzerReferences.AddRange(libraryExport.AnalyzerReferences); + compilationAssemblies.Add(reference); } + } - var builder = LibraryExportBuilder.Create(library); - if (_runtime != null && _runtimeFallbacks != null) - { - // For portable apps that are built with runtime trimming we replace RuntimeAssemblyGroups and NativeLibraryGroups - // with single default group that contains asset specific to runtime we are trimming for - // based on runtime fallback list - builder.WithRuntimeAssemblyGroups(TrimAssetGroups(libraryExport.RuntimeAssemblyGroups, _runtimeFallbacks)); - builder.WithNativeLibraryGroups(TrimAssetGroups(libraryExport.NativeLibraryGroups, _runtimeFallbacks)); - } - else - { - builder.WithRuntimeAssemblyGroups(libraryExport.RuntimeAssemblyGroups); - builder.WithNativeLibraryGroups(libraryExport.NativeLibraryGroups); - } + // Source and analyzer references are not transitive + if (library.Parents.Contains(_rootProject)) + { + sourceReferences.AddRange(libraryExport.SourceReferences); + analyzerReferences.AddRange(libraryExport.AnalyzerReferences); + } - yield return builder - .WithCompilationAssemblies(compilationAssemblies) - .WithSourceReferences(sourceReferences) - .WithRuntimeAssets(libraryExport.RuntimeAssets) - .WithEmbedddedResources(libraryExport.EmbeddedResources) - .WithAnalyzerReference(analyzerReferences) - .WithResourceAssemblies(libraryExport.ResourceAssemblies) - .Build(); + var builder = LibraryExportBuilder.Create(library); + if (_runtime != null && _runtimeFallbacks != null) + { + // For portable apps that are built with runtime trimming we replace RuntimeAssemblyGroups and NativeLibraryGroups + // with single default group that contains asset specific to runtime we are trimming for + // based on runtime fallback list + builder.WithRuntimeAssemblyGroups(TrimAssetGroups(libraryExport.RuntimeAssemblyGroups, _runtimeFallbacks)); + builder.WithNativeLibraryGroups(TrimAssetGroups(libraryExport.NativeLibraryGroups, _runtimeFallbacks)); } + else + { + builder.WithRuntimeAssemblyGroups(libraryExport.RuntimeAssemblyGroups); + builder.WithNativeLibraryGroups(libraryExport.NativeLibraryGroups); + } + + return builder + .WithCompilationAssemblies(compilationAssemblies) + .WithSourceReferences(sourceReferences) + .WithRuntimeAssets(libraryExport.RuntimeAssets) + .WithEmbedddedResources(libraryExport.EmbeddedResources) + .WithAnalyzerReference(analyzerReferences) + .WithResourceAssemblies(libraryExport.ResourceAssemblies) + .Build(); } private IEnumerable TrimAssetGroups(IEnumerable runtimeAssemblyGroups, From 55bddff449da30ffb94fcd71ec643535d66883f0 Mon Sep 17 00:00:00 2001 From: Bryan Thornbury Date: Mon, 1 Aug 2016 23:21:23 -0700 Subject: [PATCH 08/16] clean bin/obj in dependencycontextvalidator tests --- .../FunctionalTests.cs | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/test/Microsoft.Extensions.DependencyModel.Tests/FunctionalTests.cs b/test/Microsoft.Extensions.DependencyModel.Tests/FunctionalTests.cs index 476671ebbe..3931a846ee 100644 --- a/test/Microsoft.Extensions.DependencyModel.Tests/FunctionalTests.cs +++ b/test/Microsoft.Extensions.DependencyModel.Tests/FunctionalTests.cs @@ -30,6 +30,8 @@ public void RunTest(string appname, bool checkCompilation) var testProjectPath = Path.Combine(RepoRoot, "TestAssets", "TestProjects", "DependencyContextValidator", appname); var testProject = Path.Combine(testProjectPath, "project.json"); + CleanBinObj(testProjectPath); + var runCommand = new RunCommand(testProject); var result = runCommand.ExecuteWithCapturedOutput(); result.Should().Pass(); @@ -50,6 +52,8 @@ public void PublishTest(string appname, bool portable, bool checkCompilation) var testProjectPath = Path.Combine(RepoRoot, "TestAssets", "TestProjects", "DependencyContextValidator", appname); var testProject = Path.Combine(testProjectPath, "project.json"); + CleanBinObj(testProjectPath); + var publishCommand = new PublishCommand(testProject); publishCommand.Execute().Should().Pass(); @@ -69,6 +73,8 @@ public void RunTestFullClr() var testProjectPath = Path.Combine(RepoRoot, "TestAssets", "TestProjects", "DependencyContextValidator", "TestAppFullClr"); var testProject = Path.Combine(testProjectPath, "project.json"); + CleanBinObj(testProjectPath); + var runCommand = new RunCommand(testProject); var result = runCommand.ExecuteWithCapturedOutput(); result.Should().Pass(); @@ -82,6 +88,8 @@ public void PublishTestFullClr() var testProjectPath = Path.Combine(RepoRoot, "TestAssets", "TestProjects", "DependencyContextValidator", "TestAppFullClr"); var testProject = Path.Combine(testProjectPath, "project.json"); + CleanBinObj(testProjectPath); + var publishCommand = new PublishCommand(testProject); publishCommand.Execute().Should().Pass(); @@ -90,6 +98,19 @@ public void PublishTestFullClr() ValidateCompilationLibrariesFullClr(result, "TestAppFullClr"); } + private void CleanBinObj(string rootPath) + { + var dirs = new string{} ["bin", "obj"]; + + foreach (var dir in dirs) + { + if (Directory.Exists(Path.Combine(rootPath, dir))) + { + Directory.Delete(Path.Combine(rootPath, dir)); + } + } + } + private void ValidateRuntimeLibrariesFullClr(CommandResult result, string appname) { // entry assembly From ec04a52d869c0c6b2da1a25929e25191c9a462fb Mon Sep 17 00:00:00 2001 From: Bryan Thornbury Date: Mon, 1 Aug 2016 23:39:19 -0700 Subject: [PATCH 09/16] More performant and consistently ordered project dependency cache refresh --- .../Compilation/LibraryExporter.cs | 19 +++++++++++++++---- .../FunctionalTests.cs | 2 +- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExporter.cs b/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExporter.cs index d2782c082c..970ee77a1c 100644 --- a/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExporter.cs +++ b/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExporter.cs @@ -103,13 +103,24 @@ private IEnumerable GetCacheWithRefreshedProjectExports() { if (_cachedExports == null) { - return (_cachedExports = CalculateAllExports().ToList()); + _cachedExports = CalculateAllExports().ToList(); } - var nonProjectExports = _cachedExports.Where(export => !Equals(export.Library.Identity.Type, LibraryType.Project)); - var projectExports = _cachedExports.Where(export => Equals(export.Library.Identity.Type, LibraryType.Project)); - var refreshedProjectExports = projectExports.Select(export => GenerateExportFromLibrary(_seenMetadataReferences, export.Library)); + var refreshedExports = new string[_cachedExports.Count()]; + int index = 0; + foreach (var export in _cachedExports) + { + if (Equals(export.Library.Identity.Type, LibraryType.Project)) + { + refreshedExports[index++] = export; + } + else + { + refreshedExports[index++] = GenerateExportFromLibrary(_seenMetadataReferences, export.Library); + } + } + return nonProjectExports.Concat(refreshedProjectExports); } diff --git a/test/Microsoft.Extensions.DependencyModel.Tests/FunctionalTests.cs b/test/Microsoft.Extensions.DependencyModel.Tests/FunctionalTests.cs index 3931a846ee..2bc7e02657 100644 --- a/test/Microsoft.Extensions.DependencyModel.Tests/FunctionalTests.cs +++ b/test/Microsoft.Extensions.DependencyModel.Tests/FunctionalTests.cs @@ -100,7 +100,7 @@ public void PublishTestFullClr() private void CleanBinObj(string rootPath) { - var dirs = new string{} ["bin", "obj"]; + var dirs = new string[] {"bin", "obj"}; foreach (var dir in dirs) { From 729b0425f0b2f1e2e70fabd019bc62f0a1e2e2b2 Mon Sep 17 00:00:00 2001 From: Bryan Thornbury Date: Tue, 2 Aug 2016 00:06:51 -0700 Subject: [PATCH 10/16] fix errors --- .../Compilation/LibraryExporter.cs | 9 ++++++--- .../FunctionalTests.cs | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExporter.cs b/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExporter.cs index 970ee77a1c..80b1ee8f27 100644 --- a/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExporter.cs +++ b/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExporter.cs @@ -87,6 +87,9 @@ public IEnumerable GetDependencies(LibraryType type) /// private IEnumerable ExportLibraries(Func condition) { + // Project Exports cannot be cached because the binding redirect file + // for desktop apps is not added to runtimeassets of the project + // until after the project is built. var cache = GetCacheWithRefreshedProjectExports(); foreach (var export in cache) @@ -106,7 +109,7 @@ private IEnumerable GetCacheWithRefreshedProjectExports() _cachedExports = CalculateAllExports().ToList(); } - var refreshedExports = new string[_cachedExports.Count()]; + var refreshedExports = new LibraryExport[_cachedExports.Count()]; int index = 0; foreach (var export in _cachedExports) @@ -120,8 +123,8 @@ private IEnumerable GetCacheWithRefreshedProjectExports() refreshedExports[index++] = GenerateExportFromLibrary(_seenMetadataReferences, export.Library); } } - - return nonProjectExports.Concat(refreshedProjectExports); + + return refreshedExports; } private IEnumerable CalculateAllExports() diff --git a/test/Microsoft.Extensions.DependencyModel.Tests/FunctionalTests.cs b/test/Microsoft.Extensions.DependencyModel.Tests/FunctionalTests.cs index 2bc7e02657..950a2943db 100644 --- a/test/Microsoft.Extensions.DependencyModel.Tests/FunctionalTests.cs +++ b/test/Microsoft.Extensions.DependencyModel.Tests/FunctionalTests.cs @@ -106,7 +106,7 @@ private void CleanBinObj(string rootPath) { if (Directory.Exists(Path.Combine(rootPath, dir))) { - Directory.Delete(Path.Combine(rootPath, dir)); + Directory.Delete(Path.Combine(rootPath, dir), true); } } } From 874f512ae7d9e6cba7353da98463b2d518fa3a21 Mon Sep 17 00:00:00 2001 From: Bryan Thornbury Date: Tue, 2 Aug 2016 00:36:21 -0700 Subject: [PATCH 11/16] fix library exporter --- .../Compilation/LibraryExporter.cs | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExporter.cs b/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExporter.cs index 80b1ee8f27..f654f10848 100644 --- a/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExporter.cs +++ b/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExporter.cs @@ -27,6 +27,7 @@ public class LibraryExporter private HashSet _seenMetadataReferences; private List _cachedExports; + private List _projectExportIndices; public LibraryExporter(ProjectDescription rootProject, LibraryManager manager, @@ -107,21 +108,17 @@ private IEnumerable GetCacheWithRefreshedProjectExports() if (_cachedExports == null) { _cachedExports = CalculateAllExports().ToList(); - } - var refreshedExports = new LibraryExport[_cachedExports.Count()]; + _cachedProjectExportIndices = _cachedExports + .Where(export => Equals(export.Library.Identity.Type, LibraryType.Project)) + .Select((export, index) => index); + } - int index = 0; - foreach (var export in _cachedExports) + foreach(var index in _cachedProjectExportIndices) { - if (Equals(export.Library.Identity.Type, LibraryType.Project)) - { - refreshedExports[index++] = export; - } - else - { - refreshedExports[index++] = GenerateExportFromLibrary(_seenMetadataReferences, export.Library); - } + var export = _cachedExports[index]; + + _cachedExports[index] = GenerateExportFromLibrary(_seenMetadataReferences, export.Library); } return refreshedExports; From 854824f5ca46c8c4b462849528846fb55ea23313 Mon Sep 17 00:00:00 2001 From: Bryan Thornbury Date: Tue, 2 Aug 2016 00:38:06 -0700 Subject: [PATCH 12/16] fix --- .../Compilation/LibraryExporter.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExporter.cs b/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExporter.cs index f654f10848..016e96a551 100644 --- a/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExporter.cs +++ b/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExporter.cs @@ -27,7 +27,7 @@ public class LibraryExporter private HashSet _seenMetadataReferences; private List _cachedExports; - private List _projectExportIndices; + private IEnumerable _cachedProjectExportIndices; public LibraryExporter(ProjectDescription rootProject, LibraryManager manager, @@ -121,7 +121,7 @@ private IEnumerable GetCacheWithRefreshedProjectExports() _cachedExports[index] = GenerateExportFromLibrary(_seenMetadataReferences, export.Library); } - return refreshedExports; + return _cachedExports; } private IEnumerable CalculateAllExports() From f1f7f1128a772bb1beb53bd59c63163d2184772e Mon Sep 17 00:00:00 2001 From: Bryan Thornbury Date: Tue, 2 Aug 2016 11:38:53 -0700 Subject: [PATCH 13/16] changes --- .../Compilation/LibraryExporter.cs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExporter.cs b/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExporter.cs index 016e96a551..11d37cac9b 100644 --- a/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExporter.cs +++ b/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExporter.cs @@ -114,14 +114,12 @@ private IEnumerable GetCacheWithRefreshedProjectExports() .Select((export, index) => index); } - foreach(var index in _cachedProjectExportIndices) - { - var export = _cachedExports[index]; - - _cachedExports[index] = GenerateExportFromLibrary(_seenMetadataReferences, export.Library); - } - - return _cachedExports; + return _cachedExports.Select(export => + { + return Equals(export.Library.Identity.Type, LibraryType.Project) + ? GenerateExportFromLibrary(_seenMetadataReferences, export.Library) + : export; + }); } private IEnumerable CalculateAllExports() From 13a7c9092819826d3afbdad60ad044aada528cc5 Mon Sep 17 00:00:00 2001 From: Bryan Thornbury Date: Tue, 2 Aug 2016 11:58:38 -0700 Subject: [PATCH 14/16] try again, this time do seen metadata right --- .../Compilation/LibraryExporter.cs | 36 ++++++++++++------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExporter.cs b/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExporter.cs index 11d37cac9b..3c97243c3c 100644 --- a/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExporter.cs +++ b/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExporter.cs @@ -24,7 +24,6 @@ public class LibraryExporter private readonly ProjectDescription _rootProject; private readonly string _buildBasePath; private readonly string _solutionRootPath; - private HashSet _seenMetadataReferences; private List _cachedExports; private IEnumerable _cachedProjectExportIndices; @@ -108,28 +107,41 @@ private IEnumerable GetCacheWithRefreshedProjectExports() if (_cachedExports == null) { _cachedExports = CalculateAllExports().ToList(); - - _cachedProjectExportIndices = _cachedExports - .Where(export => Equals(export.Library.Identity.Type, LibraryType.Project)) - .Select((export, index) => index); } - return _cachedExports.Select(export => + var seenMetadataReferences = new HashSet(); + var refreshedCache = new LibraryExport[_cachedExports.Count()]; + + int index = 0; + foreach (var export in _cachedExports) + { + foreach (var reference in export.CompilationAssemblies) { - return Equals(export.Library.Identity.Type, LibraryType.Project) - ? GenerateExportFromLibrary(_seenMetadataReferences, export.Library) - : export; - }); + seenMetadataReferences.Add(reference.Name); + } + + if (Equals(export.Library.Identity.Type, LibraryType.Project)) + { + refreshedCache[index++] = GenerateExportFromLibrary(seenMetadataReferences, export.Library); + } + else + { + refreshedCache[index++] = export; + } + + } + + return refreshedCache; } private IEnumerable CalculateAllExports() { - _seenMetadataReferences = new HashSet(); + var seenMetadataReferences = new HashSet(); // Iterate over libraries in the library manager foreach (var library in LibraryManager.GetLibraries()) { - yield return GenerateExportFromLibrary(_seenMetadataReferences, library); + yield return GenerateExportFromLibrary(seenMetadataReferences, library); } } From 36ca46d5c36dc4027814438fd0697279ce9c74b5 Mon Sep 17 00:00:00 2001 From: Bryan Thornbury Date: Tue, 2 Aug 2016 11:59:21 -0700 Subject: [PATCH 15/16] tweak metadata --- .../Compilation/LibraryExporter.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExporter.cs b/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExporter.cs index 3c97243c3c..e8937f17ee 100644 --- a/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExporter.cs +++ b/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExporter.cs @@ -115,11 +115,6 @@ private IEnumerable GetCacheWithRefreshedProjectExports() int index = 0; foreach (var export in _cachedExports) { - foreach (var reference in export.CompilationAssemblies) - { - seenMetadataReferences.Add(reference.Name); - } - if (Equals(export.Library.Identity.Type, LibraryType.Project)) { refreshedCache[index++] = GenerateExportFromLibrary(seenMetadataReferences, export.Library); @@ -129,6 +124,10 @@ private IEnumerable GetCacheWithRefreshedProjectExports() refreshedCache[index++] = export; } + foreach (var reference in export.CompilationAssemblies) + { + seenMetadataReferences.Add(reference.Name); + } } return refreshedCache; From 601c8f3a5c909650a0c7994c39807fb67b4522e5 Mon Sep 17 00:00:00 2001 From: Bryan Thornbury Date: Tue, 2 Aug 2016 12:39:19 -0700 Subject: [PATCH 16/16] fix build warnings --- src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExporter.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExporter.cs b/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExporter.cs index e8937f17ee..66dfcbea9a 100644 --- a/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExporter.cs +++ b/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExporter.cs @@ -26,7 +26,6 @@ public class LibraryExporter private readonly string _solutionRootPath; private List _cachedExports; - private IEnumerable _cachedProjectExportIndices; public LibraryExporter(ProjectDescription rootProject, LibraryManager manager,