This repository has been archived by the owner on Dec 18, 2017. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 223
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adding ILibraryManager to Runtime assembly
- Loading branch information
Showing
8 changed files
with
322 additions
and
6 deletions.
There are no files selected for viewing
12 changes: 12 additions & 0 deletions
12
src/Microsoft.Net.Runtime.Interfaces/ILibraryInformation.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
using System.Collections.Generic; | ||
|
||
namespace Microsoft.Net.Runtime | ||
{ | ||
[AssemblyNeutral] | ||
public interface ILibraryInformation | ||
{ | ||
string Name { get; } | ||
|
||
IEnumerable<string> Dependencies { get; } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
using System.Collections.Generic; | ||
|
||
namespace Microsoft.Net.Runtime | ||
{ | ||
[AssemblyNeutral] | ||
public interface ILibraryManager | ||
{ | ||
ILibraryExport GetLibraryExport(string name); | ||
|
||
IEnumerable<ILibraryInformation> GetReferencingLibraries(string name); | ||
|
||
ILibraryInformation GetLibraryInformation(string name); | ||
|
||
IEnumerable<ILibraryInformation> GetLibraries(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
32 changes: 32 additions & 0 deletions
32
src/Microsoft.Net.Runtime/DependencyManagement/LibraryInformation.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
|
||
namespace Microsoft.Net.Runtime | ||
{ | ||
public sealed class LibraryInformation : ILibraryInformation | ||
{ | ||
public LibraryInformation(LibraryDescription description) | ||
{ | ||
Name = description.Identity.Name; | ||
Dependencies = description.Dependencies.Select(d => d.Name); | ||
} | ||
|
||
public LibraryInformation(string name, IEnumerable<string> dependencies) | ||
{ | ||
Name = name; | ||
Dependencies = dependencies; | ||
} | ||
|
||
public string Name | ||
{ | ||
get; | ||
private set; | ||
} | ||
|
||
public IEnumerable<string> Dependencies | ||
{ | ||
get; | ||
private set; | ||
} | ||
} | ||
} |
189 changes: 189 additions & 0 deletions
189
src/Microsoft.Net.Runtime/DependencyManagement/LibraryManager.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,189 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Runtime.Versioning; | ||
|
||
namespace Microsoft.Net.Runtime | ||
{ | ||
public class LibraryManager : ILibraryManager | ||
{ | ||
private readonly FrameworkName _targetFramework; | ||
private readonly ILibraryExportProvider _libraryExportProvider; | ||
private readonly Func<IEnumerable<ILibraryInformation>> _libraryInfoThunk; | ||
private readonly object _initializeLock = new object(); | ||
private Dictionary<string, IEnumerable<ILibraryInformation>> _inverse; | ||
private Dictionary<string, ILibraryInformation> _graph; | ||
private bool _initialized; | ||
|
||
public LibraryManager(FrameworkName targetFramework, | ||
DependencyWalker dependencyWalker, | ||
IEnumerable<ILibraryExportProvider> libraryExportProviders) | ||
: this(targetFramework, | ||
GetLibraryInfoThunk(dependencyWalker), | ||
libraryExportProviders) | ||
{ | ||
} | ||
|
||
public LibraryManager(FrameworkName targetFramework, | ||
Func<IEnumerable<ILibraryInformation>> libraryInfoThunk, | ||
IEnumerable<ILibraryExportProvider> libraryExportProviders) | ||
{ | ||
_targetFramework = targetFramework; | ||
_libraryInfoThunk = libraryInfoThunk; | ||
_libraryExportProvider = new CompositeLibraryExportProvider(libraryExportProviders); | ||
} | ||
|
||
private Dictionary<string, ILibraryInformation> LibraryLookup | ||
{ | ||
get | ||
{ | ||
EnsureInitialized(); | ||
return _graph; | ||
} | ||
} | ||
|
||
private Dictionary<string, IEnumerable<ILibraryInformation>> InverseGraph | ||
{ | ||
get | ||
{ | ||
EnsureInitialized(); | ||
return _inverse; | ||
} | ||
} | ||
|
||
public ILibraryInformation GetLibraryInformation(string name) | ||
{ | ||
ILibraryInformation information; | ||
if (LibraryLookup.TryGetValue(name, out information)) | ||
{ | ||
return information; | ||
} | ||
|
||
return null; | ||
} | ||
|
||
public IEnumerable<ILibraryInformation> GetReferencingLibraries(string name) | ||
{ | ||
IEnumerable<ILibraryInformation> libraries; | ||
if (InverseGraph.TryGetValue(name, out libraries)) | ||
{ | ||
return libraries; | ||
} | ||
|
||
return Enumerable.Empty<ILibraryInformation>(); | ||
} | ||
|
||
public ILibraryExport GetLibraryExport(string name) | ||
{ | ||
return _libraryExportProvider.GetLibraryExport(name, _targetFramework); | ||
} | ||
|
||
public IEnumerable<ILibraryInformation> GetLibraries() | ||
{ | ||
EnsureInitialized(); | ||
return _graph.Values; | ||
} | ||
|
||
private void EnsureInitialized() | ||
{ | ||
lock (_initializeLock) | ||
{ | ||
if (!_initialized) | ||
{ | ||
_initialized = true; | ||
_graph = _libraryInfoThunk().ToDictionary(ld => ld.Name, | ||
StringComparer.Ordinal); | ||
|
||
BuildInverseGraph(); | ||
} | ||
} | ||
} | ||
|
||
public void BuildInverseGraph() | ||
{ | ||
var firstLevelLookups = new Dictionary<string, List<ILibraryInformation>>(StringComparer.Ordinal); | ||
var visited = new HashSet<string>(StringComparer.Ordinal); | ||
foreach (var item in _graph.Values) | ||
{ | ||
Visit(item, firstLevelLookups, visited); | ||
} | ||
|
||
_inverse = new Dictionary<string, IEnumerable<ILibraryInformation>>(); | ||
|
||
// Flatten the graph | ||
foreach (var item in _graph.Values) | ||
{ | ||
Flatten(item, firstLevelLookups: firstLevelLookups); | ||
} | ||
} | ||
|
||
private void Visit(ILibraryInformation item, | ||
Dictionary<string, List<ILibraryInformation>> inverse, | ||
HashSet<string> visited) | ||
{ | ||
if (!visited.Add(item.Name)) | ||
{ | ||
return; | ||
} | ||
|
||
foreach (var dependency in item.Dependencies) | ||
{ | ||
List<ILibraryInformation> dependents; | ||
if (!inverse.TryGetValue(dependency, out dependents)) | ||
{ | ||
dependents = new List<ILibraryInformation>(); | ||
inverse[dependency] = dependents; | ||
} | ||
|
||
dependents.Add(item); | ||
Visit(_graph[dependency], inverse, visited); | ||
} | ||
} | ||
|
||
private void Flatten(ILibraryInformation info, | ||
Dictionary<string, List<ILibraryInformation>> firstLevelLookups, | ||
HashSet<ILibraryInformation> parentDependents = null) | ||
{ | ||
IEnumerable<ILibraryInformation> libraryDependents; | ||
if (!_inverse.TryGetValue(info.Name, out libraryDependents)) | ||
{ | ||
List<ILibraryInformation> firstLevelDependents; | ||
if (firstLevelLookups.TryGetValue(info.Name, out firstLevelDependents)) | ||
{ | ||
var allDependents = new HashSet<ILibraryInformation>(); | ||
foreach (var dependent in firstLevelDependents) | ||
{ | ||
allDependents.Add(dependent); | ||
Flatten(dependent, firstLevelLookups, allDependents); | ||
} | ||
libraryDependents = allDependents; | ||
} | ||
else | ||
{ | ||
libraryDependents = Enumerable.Empty<ILibraryInformation>(); | ||
} | ||
_inverse[info.Name] = libraryDependents; | ||
|
||
} | ||
AddRange(parentDependents, libraryDependents); | ||
} | ||
|
||
|
||
private static Func<IEnumerable<ILibraryInformation>> GetLibraryInfoThunk(DependencyWalker dependencyWalker) | ||
{ | ||
return () => dependencyWalker.Libraries | ||
.Select(library => new LibraryInformation(library)); | ||
} | ||
|
||
private static void AddRange(HashSet<ILibraryInformation> source, IEnumerable<ILibraryInformation> values) | ||
{ | ||
if (source != null) | ||
{ | ||
foreach (var value in values) | ||
{ | ||
source.Add(value); | ||
} | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Runtime.Versioning; | ||
using Xunit; | ||
|
||
namespace Microsoft.Net.Runtime.Tests | ||
{ | ||
public class LibraryManagerFacts | ||
{ | ||
[Fact] | ||
public void GetReferencingLibraries_ReturnsFirstLevelReferences() | ||
{ | ||
// Arrange | ||
var manager = CreateManager(); | ||
|
||
// Act | ||
var referencingLibraries = manager.GetReferencingLibraries("Hosting"); | ||
|
||
// Assert | ||
Assert.Equal(new[] { "MyApp" }, | ||
referencingLibraries.Select(y => y.Name)); | ||
} | ||
|
||
[Theory] | ||
[InlineData("Mvc.Core", new[] { "Mvc", "Mvc.Rendering", "Mvc.RenderingExtensions", "MyApp" })] | ||
[InlineData("Config", new[] { "DI", "Hosting", "Mvc", "Mvc.Core", "Mvc.ModelBinding", "Mvc.Rendering", "Mvc.RenderingExtensions", "MyApp" })] | ||
public void GetReferencingLibraries_ReturnsFullListOfReferences(string library, string[] expectedReferences) | ||
{ | ||
// Arrange | ||
var manager = CreateManager(); | ||
|
||
// Act | ||
var referencingLibraries = manager.GetReferencingLibraries(library); | ||
|
||
// Assert | ||
Assert.Equal(expectedReferences, referencingLibraries.Select(y => y.Name).OrderBy(y => y)); | ||
} | ||
|
||
private static LibraryManager CreateManager(IEnumerable<ILibraryInformation> libraryInfo = null) | ||
{ | ||
var frameworkName = new FrameworkName("Net45", new Version(4, 5, 1)); | ||
libraryInfo = libraryInfo ?? new[] | ||
{ | ||
new LibraryInformation("Mvc.RenderingExtensions", new[] { "Mvc.Rendering" }), | ||
new LibraryInformation("Mvc.Rendering", new[] { "DI", "Mvc.Core", "HttpAbstractions" }), | ||
new LibraryInformation("DI", new[] { "Config" }), | ||
new LibraryInformation("Mvc", new[] { "DI", "Mvc.Core", "HttpAbstractions", "Mvc.RenderingExtensions", "Mvc.ModelBinding" }), | ||
new LibraryInformation("Mvc.Core", new[] { "DI", "HttpAbstractions", "Mvc.ModelBinding" }), | ||
new LibraryInformation("Mvc.ModelBinding", new[] { "DI", "HttpAbstractions" }), | ||
new LibraryInformation("HttpAbstractions", Enumerable.Empty<String>()), | ||
new LibraryInformation("Hosting", new[] { "DI"}), | ||
new LibraryInformation("Config", Enumerable.Empty<String>()), | ||
new LibraryInformation("MyApp", new[] { "DI", "Hosting", "Mvc", "HttpAbstractions" }) | ||
|
||
}; | ||
return new LibraryManager(frameworkName, () => libraryInfo, Enumerable.Empty<ILibraryExportProvider>()); | ||
} | ||
} | ||
} |