Fix projectmodel-server regression

1. Address the null reference exception when a project dependency is
broken.
2. Address the duplicate key issues after the logic of redirecting
System pacage to reference assembly was added

Update projectmodel-server and tests

1. Fix test timeout caused by undisconnected socket;
2. Update project model server
This commit is contained in:
Troy Dai 2016-01-29 01:49:56 -08:00
parent c4b3925e46
commit b9f2d8fe3d
12 changed files with 81 additions and 48 deletions

View file

@ -156,6 +156,18 @@ namespace Microsoft.DotNet.ProjectModel.Compilation
private LibraryExport ExportProject(ProjectDescription project) private LibraryExport ExportProject(ProjectDescription project)
{ {
if (!project.Resolved)
{
// For a unresolved project reference returns a export with empty asset.
return new LibraryExport(library: project,
compileAssemblies: Enumerable.Empty<LibraryAsset>(),
sourceReferences: Enumerable.Empty<string>(),
nativeLibraries: Enumerable.Empty<LibraryAsset>(),
runtimeAssets: Enumerable.Empty<string>(),
runtimeAssemblies: Array.Empty<LibraryAsset>(),
analyzers: Array.Empty<AnalyzerReference>());
}
var compileAssemblies = new List<LibraryAsset>(); var compileAssemblies = new List<LibraryAsset>();
var runtimeAssets = new List<string>(); var runtimeAssets = new List<string>();
var sourceReferences = new List<string>(); var sourceReferences = new List<string>();

View file

@ -41,7 +41,7 @@ namespace Microsoft.DotNet.ProjectModel.Graph
public override string ToString() public override string ToString()
{ {
return Value; return Value ?? nameof(Unspecified);
} }
public bool CanSatisfyConstraint(LibraryType constraint) public bool CanSatisfyConstraint(LibraryType constraint)

View file

@ -267,6 +267,7 @@ namespace Microsoft.DotNet.ProjectModel
ReferenceAssemblyDependencyResolver referenceAssemblyDependencyResolver, ReferenceAssemblyDependencyResolver referenceAssemblyDependencyResolver,
out bool requiresFrameworkAssemblies) out bool requiresFrameworkAssemblies)
{ {
// Remark: the LibraryType in the key of the given dictionary are all "Unspecified" at the beginning.
requiresFrameworkAssemblies = false; requiresFrameworkAssemblies = false;
foreach (var pair in libraries.ToList()) foreach (var pair in libraries.ToList())
@ -294,41 +295,50 @@ namespace Microsoft.DotNet.ProjectModel
// Remove the original package reference // Remove the original package reference
libraries.Remove(pair.Key); libraries.Remove(pair.Key);
// Add the reference to the refernce assembly. // Insert a reference assembly key if there isn't one
libraries[new LibraryKey(replacement.Identity.Name)] = replacement; var key = new LibraryKey(replacement.Identity.Name, LibraryType.ReferenceAssembly);
if (!libraries.ContainsKey(key))
continue; {
libraries[key] = replacement;
}
}
} }
} }
foreach (var pair in libraries.ToList())
{
var library = pair.Value;
library.Framework = library.Framework ?? TargetFramework; library.Framework = library.Framework ?? TargetFramework;
foreach (var dependency in library.Dependencies) foreach (var dependency in library.Dependencies)
{ {
var keyType = dependency.Target == LibraryType.ReferenceAssembly ? LibraryType.ReferenceAssembly : LibraryType.Unspecified; var keyType = dependency.Target == LibraryType.ReferenceAssembly ?
LibraryType.ReferenceAssembly :
LibraryType.Unspecified;
var key = new LibraryKey(dependency.Name, keyType); var key = new LibraryKey(dependency.Name, keyType);
LibraryDescription dep; LibraryDescription dependencyDescription;
if (!libraries.TryGetValue(key, out dep)) if (!libraries.TryGetValue(key, out dependencyDescription))
{ {
if (Equals(LibraryType.ReferenceAssembly, dependency.Target)) if (keyType == LibraryType.ReferenceAssembly)
{ {
requiresFrameworkAssemblies = true; // a dependency is specified to be reference assembly but fail to match
// then add a unresolved dependency
dep = referenceAssemblyDependencyResolver.GetDescription(dependency, TargetFramework) ?? dependencyDescription = referenceAssemblyDependencyResolver.GetDescription(dependency, TargetFramework) ??
UnresolvedDependencyProvider.GetDescription(dependency, TargetFramework); UnresolvedDependencyProvider.GetDescription(dependency, TargetFramework);
libraries[key] = dependencyDescription;
dep.Framework = TargetFramework;
libraries[key] = dep;
} }
else else if (!libraries.TryGetValue(new LibraryKey(dependency.Name, LibraryType.ReferenceAssembly), out dependencyDescription))
{ {
dep = UnresolvedDependencyProvider.GetDescription(dependency, TargetFramework); // a dependency which type is unspecified fails to match, then try to find a
libraries[key] = dep; // reference assembly type dependency
dependencyDescription = UnresolvedDependencyProvider.GetDescription(dependency, TargetFramework);
libraries[key] = dependencyDescription;
} }
} }
dep.RequestedRanges.Add(dependency); dependencyDescription.RequestedRanges.Add(dependency);
dep.Parents.Add(library); dependencyDescription.Parents.Add(library);
} }
} }
} }

View file

@ -63,7 +63,7 @@ namespace Microsoft.DotNet.ProjectModel.Resolution
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{ {
// There is no reference assemblies path outside of windows // There is no reference assemblies path outside of windows
// The enviorment variable can be used to specify one // The environment variable can be used to specify one
return null; return null;
} }

View file

@ -34,7 +34,8 @@ namespace Microsoft.DotNet.ProjectModel.Server
var allExports = context.CreateExporter(configuration) var allExports = context.CreateExporter(configuration)
.GetAllExports() .GetAllExports()
.ToDictionary(export => export.Library.GetUniqueName()); .ToDictionary(export => export.Library.Identity.Name);
var allSourceFiles = new List<string>(context.ProjectFile.Files.SourceFiles); var allSourceFiles = new List<string>(context.ProjectFile.Files.SourceFiles);
var allFileReferences = new List<string>(); var allFileReferences = new List<string>();
var allProjectReferences = new List<ProjectReferenceDescription>(); var allProjectReferences = new List<ProjectReferenceDescription>();
@ -42,10 +43,8 @@ namespace Microsoft.DotNet.ProjectModel.Server
// All exports are returned. When the same library name have a ReferenceAssembly type export and a Package type export // All exports are returned. When the same library name have a ReferenceAssembly type export and a Package type export
// both will be listed as dependencies. Prefix "fx/" will be added to ReferenceAssembly type dependency. // both will be listed as dependencies. Prefix "fx/" will be added to ReferenceAssembly type dependency.
foreach (var pair in allExports) foreach (var export in allExports.Values)
{ {
var export = pair.Value;
allSourceFiles.AddRange(export.SourceReferences); allSourceFiles.AddRange(export.SourceReferences);
allFileReferences.AddRange(export.CompilationAssemblies.Select(asset => asset.ResolvedPath)); allFileReferences.AddRange(export.CompilationAssemblies.Select(asset => asset.ResolvedPath));

View file

@ -4,6 +4,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Microsoft.DotNet.ProjectModel.Compilation; using Microsoft.DotNet.ProjectModel.Compilation;
using Microsoft.DotNet.ProjectModel.Graph;
using Microsoft.DotNet.ProjectModel.Server.Helpers; using Microsoft.DotNet.ProjectModel.Server.Helpers;
namespace Microsoft.DotNet.ProjectModel.Server.Models namespace Microsoft.DotNet.ProjectModel.Server.Models
@ -54,27 +55,32 @@ namespace Microsoft.DotNet.ProjectModel.Server.Models
public static DependencyDescription Create(LibraryDescription library, public static DependencyDescription Create(LibraryDescription library,
List<DiagnosticMessage> diagnostics, List<DiagnosticMessage> diagnostics,
Dictionary<string, LibraryExport> allExports) IDictionary<string, LibraryExport> exportsLookup)
{ {
var name = library.GetUniqueName();
return new DependencyDescription return new DependencyDescription
{ {
Name = name, Name = library.Identity.Name,
DisplayName = library.Identity.Name, DisplayName = library.Identity.Name,
Version = library.Identity.Version?.ToNormalizedString(), Version = library.Identity.Version?.ToNormalizedString(),
Type = library.Identity.Type.Value, Type = library.Identity.Type.Value,
Resolved = library.Resolved, Resolved = library.Resolved,
Path = library.Path, Path = library.Path,
Dependencies = library.Dependencies.Select(dependency => new DependencyItem Dependencies = library.Dependencies.Select(dependency => GetDependencyItem(dependency, exportsLookup)),
{
Name = dependency.GetUniqueName(),
Version = allExports[dependency.GetUniqueName()].Library.Identity.Version?.ToNormalizedString()
}),
Errors = diagnostics.Where(d => d.Severity == DiagnosticMessageSeverity.Error) Errors = diagnostics.Where(d => d.Severity == DiagnosticMessageSeverity.Error)
.Select(d => new DiagnosticMessageView(d)), .Select(d => new DiagnosticMessageView(d)),
Warnings = diagnostics.Where(d => d.Severity == DiagnosticMessageSeverity.Warning) Warnings = diagnostics.Where(d => d.Severity == DiagnosticMessageSeverity.Warning)
.Select(d => new DiagnosticMessageView(d)) .Select(d => new DiagnosticMessageView(d))
}; };
} }
private static DependencyItem GetDependencyItem(LibraryRange dependency,
IDictionary<string, LibraryExport> exportsLookup)
{
return new DependencyItem
{
Name = dependency.Name,
Version = exportsLookup[dependency.Name].Library.Identity.Version?.ToNormalizedString()
};
}
} }
} }

View file

@ -43,7 +43,7 @@ namespace Microsoft.DotNet.ProjectModel.Server
catch (IOException ex) catch (IOException ex)
{ {
// swallow // swallow
_log.LogWarning($"Ignore {nameof(IOException)} during sending message: \"{ex.Message}\"."); _log.LogInformation($"Ignore {nameof(IOException)} during sending message: \"{ex.Message}\".");
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -79,7 +79,7 @@ namespace Microsoft.DotNet.ProjectModel.Server
} }
catch (IOException ex) catch (IOException ex)
{ {
_log.LogWarning($"Ignore {nameof(IOException)} during receiving messages: \"{ex}\"."); _log.LogInformation($"Ignore {nameof(IOException)} during receiving messages: \"{ex}\".");
} }
catch (Exception ex) catch (Exception ex)
{ {

View file

@ -9,6 +9,7 @@ using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json; using Newtonsoft.Json;
using Xunit; using Xunit;
@ -29,18 +30,19 @@ namespace Microsoft.DotNet.ProjectModel.Server.Tests
// works in visual studio // works in visual studio
private readonly Dictionary<string, int> _projectContexts = new Dictionary<string, int>(); private readonly Dictionary<string, int> _projectContexts = new Dictionary<string, int>();
private int _nextContextId; private int _nextContextId;
private readonly Socket _socket;
public DthTestClient(DthTestServer server) public DthTestClient(DthTestServer server)
{ {
var socket = new Socket(AddressFamily.InterNetwork, _socket = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, SocketType.Stream,
ProtocolType.Tcp); ProtocolType.Tcp);
socket.Connect(new IPEndPoint(IPAddress.Loopback, server.Port)); _socket.Connect(new IPEndPoint(IPAddress.Loopback, server.Port));
_hostId = server.HostId; _hostId = server.HostId;
_networkStream = new NetworkStream(socket); _networkStream = new NetworkStream(_socket);
_reader = new BinaryReader(_networkStream); _reader = new BinaryReader(_networkStream);
_writer = new BinaryWriter(_networkStream); _writer = new BinaryWriter(_networkStream);
@ -221,6 +223,7 @@ namespace Microsoft.DotNet.ProjectModel.Server.Tests
_writer.Dispose(); _writer.Dispose();
_networkStream.Dispose(); _networkStream.Dispose();
_readCancellationToken.Cancel(); _readCancellationToken.Cancel();
_socket.Shutdown(SocketShutdown.Both);
} }
private void ReadMessage(CancellationToken cancellationToken) private void ReadMessage(CancellationToken cancellationToken)

View file

@ -5,13 +5,14 @@ using System;
using System.Net; using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
using System.Threading; using System.Threading;
using Microsoft.DotNet.ProjectModel.Server;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
namespace Microsoft.DotNet.ProjectModel.Server.Tests namespace Microsoft.DotNet.ProjectModel.Server.Tests
{ {
public class DthTestServer : IDisposable public class DthTestServer : IDisposable
{ {
private readonly Program _program; private readonly ProjectModelServerCommand _program;
private readonly Thread _thread; private readonly Thread _thread;
public DthTestServer(ILoggerFactory loggerFactory) public DthTestServer(ILoggerFactory loggerFactory)
@ -21,9 +22,9 @@ namespace Microsoft.DotNet.ProjectModel.Server.Tests
Port = FindFreePort(); Port = FindFreePort();
HostId = Guid.NewGuid().ToString(); HostId = Guid.NewGuid().ToString();
_program = new Program(Port, HostId, LoggerFactory); _program = new ProjectModelServerCommand(Port, HostId, LoggerFactory);
_thread = new Thread(() => { _program.OpenChannel(); }); _thread = new Thread(() => { _program.OpenChannel(); }) { IsBackground = true };
_thread.Start(); _thread.Start();
} }

View file

@ -86,7 +86,7 @@ namespace Microsoft.DotNet.ProjectModel.Server.Tests
[Theory] [Theory]
[InlineData("Project", "UnresolvedProjectSample", "EmptyLibrary", "Project")] [InlineData("Project", "UnresolvedProjectSample", "EmptyLibrary", "Project")]
[InlineData("Package", "UnresolvedPackageSample", "NoSuchPackage", null)] [InlineData("Package", "UnresolvedPackageSample", "NoSuchPackage", null)]
[InlineData("Package", "IncompatiblePackageSample", "Newtonsoft.Json", "Package")] [InlineData("Package", "IncompatiblePackageSample", "Microsoft.Web.Administration", "Package")]
public void DthCompilation_Initialize_UnresolvedDependency(string referenceType, public void DthCompilation_Initialize_UnresolvedDependency(string referenceType,
string testProjectName, string testProjectName,
string expectedUnresolvedDependency, string expectedUnresolvedDependency,

View file

@ -1,5 +1,6 @@
{ {
"dependencies": { "dependencies": {
"NETStandard.Library": "1.0.0-rc2-23728",
"EmptyLibrary": "" "EmptyLibrary": ""
}, },
"frameworks": { "frameworks": {

View file

@ -1,6 +1,7 @@
{ {
"dependencies": { "dependencies": {
"Newtonsoft.Json": "4.5.11" "NETStandard.Library": "1.0.0-rc2-23728",
"Microsoft.Web.Administration": "7.0.0"
}, },
"frameworks": { "frameworks": {
"dnxcore50": { "dnxcore50": {