Skip to content
This repository has been archived by the owner on Dec 18, 2017. It is now read-only.

Commit

Permalink
Adding ILibraryManager to Runtime assembly
Browse files Browse the repository at this point in the history
  • Loading branch information
pranavkm committed Mar 20, 2014
1 parent 321e3f6 commit 6f839d6
Show file tree
Hide file tree
Showing 8 changed files with 322 additions and 6 deletions.
12 changes: 12 additions & 0 deletions src/Microsoft.Net.Runtime.Interfaces/ILibraryInformation.cs
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; }
}
}
16 changes: 16 additions & 0 deletions src/Microsoft.Net.Runtime.Interfaces/ILibraryManager.cs
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();
}
}
8 changes: 4 additions & 4 deletions src/Microsoft.Net.Runtime/DefaultHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -157,11 +157,11 @@ private void Initialize(DefaultHostOptions options)

_dependencyWalker = new DependencyWalker(dependencyProviders);
_loader = new AssemblyLoader(loaders);

_serviceProvider.Add(typeof(IFileMonitor), _watcher);
_serviceProvider.Add(typeof(ILibraryExportProvider),
new CompositeLibraryExportProvider(
libraryExporters.Concat(new[] { roslynLoader })));
_serviceProvider.Add(typeof(ILibraryManager),
new LibraryManager(_targetFramework,
_dependencyWalker,
libraryExporters.Concat(new[] { roslynLoader })));
}

public static string ResolveRootDirectory(string projectDir)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,18 @@ namespace Microsoft.Net.Runtime
public class DependencyWalker
{
private readonly IEnumerable<IDependencyProvider> _dependencyProviders;
private readonly List<LibraryDescription> _libraries = new List<LibraryDescription>();

public DependencyWalker(IEnumerable<IDependencyProvider> dependencyProviders)
{
_dependencyProviders = dependencyProviders;
}

public IList<LibraryDescription> Libraries
{
get { return _libraries; }
}

public void Walk(string name, SemanticVersion version, FrameworkName targetFramework)
{
var sw = Stopwatch.StartNew();
Expand All @@ -27,7 +33,7 @@ public void Walk(string name, SemanticVersion version, FrameworkName targetFrame
version,
targetFramework);

context.Populate(targetFramework);
context.Populate(targetFramework, Libraries);

sw.Stop();
Trace.TraceInformation("Resolved dependencies for {0} in {1}ms", name, sw.ElapsedMilliseconds);
Expand Down
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 src/Microsoft.Net.Runtime/DependencyManagement/LibraryManager.cs
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);
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ public enum Disposition
};
}

public void Populate(FrameworkName frameworkName)
public void Populate(FrameworkName frameworkName, IList<LibraryDescription> libraries)
{
foreach (var groupByResolver in _usedItems.GroupBy(x => x.Value.Resolver))
{
Expand All @@ -253,6 +253,7 @@ public void Populate(FrameworkName frameworkName)
}).ToList();

resolver.Initialize(descriptions, frameworkName);
libraries.AddRange(descriptions);
}
}

Expand Down
60 changes: 60 additions & 0 deletions test/Microsoft.Net.Runtime.Tests/LibraryManagerFacts.cs
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>());
}
}
}

0 comments on commit 6f839d6

Please sign in to comment.