Project model server cleanup

- Removed unused message types
- Removed intermediate ProjectInfo and ProjectState types
- Renamed Snapshot to ProjectSnapshot and ProjectSnapshot to ProjectContextSnapshot
- Exposed Project on ProjectContextCollection
- Removed AllDiagnostics message since it won't be used
- Renamed ProjectContextManager to ProjectManager
- Create project context snapshot in one pass
- Create project contexts lookup inline
- Consistent naming of payloads
This commit is contained in:
David Fowler 2016-01-02 00:44:59 -08:00
parent 41f4c926a7
commit 4b07b2d034
26 changed files with 244 additions and 461 deletions

View file

@ -12,17 +12,17 @@ namespace Microsoft.DotNet.ProjectModel.Server
{ {
private readonly string _hostName; private readonly string _hostName;
private readonly ProcessingQueue _queue; private readonly ProcessingQueue _queue;
private readonly IDictionary<int, ProjectContextManager> _projectContextManagers; private readonly IDictionary<int, ProjectManager> _projects;
public ConnectionContext(Socket acceptedSocket, public ConnectionContext(Socket acceptedSocket,
string hostName, string hostName,
ProtocolManager protocolManager, ProtocolManager protocolManager,
WorkspaceContext workspaceContext, WorkspaceContext workspaceContext,
IDictionary<int, ProjectContextManager> projectContextManagers, IDictionary<int, ProjectManager> projects,
ILoggerFactory loggerFactory) ILoggerFactory loggerFactory)
{ {
_hostName = hostName; _hostName = hostName;
_projectContextManagers = projectContextManagers; _projects = projects;
_queue = new ProcessingQueue(new NetworkStream(acceptedSocket), loggerFactory); _queue = new ProcessingQueue(new NetworkStream(acceptedSocket), loggerFactory);
_queue.OnReceive += message => _queue.OnReceive += message =>
@ -35,18 +35,18 @@ namespace Microsoft.DotNet.ProjectModel.Server
else else
{ {
message.Sender = this; message.Sender = this;
ProjectContextManager keeper; ProjectManager projectManager;
if (!_projectContextManagers.TryGetValue(message.ContextId, out keeper)) if (!_projects.TryGetValue(message.ContextId, out projectManager))
{ {
keeper = new ProjectContextManager(message.ContextId, projectManager = new ProjectManager(message.ContextId,
loggerFactory, loggerFactory,
workspaceContext, workspaceContext,
protocolManager); protocolManager);
_projectContextManagers[message.ContextId] = keeper; _projects[message.ContextId] = projectManager;
} }
keeper.OnReceive(message); projectManager.OnReceive(message);
} }
}; };
} }

View file

@ -8,15 +8,14 @@ namespace Microsoft.DotNet.ProjectModel.Server.Models
{ {
public static class NuGetFrameworkExtensions public static class NuGetFrameworkExtensions
{ {
public static FrameworkData ToPayload(this NuGetFramework framework, public static FrameworkData ToPayload(this NuGetFramework framework)
FrameworkReferenceResolver resolver)
{ {
return new FrameworkData return new FrameworkData
{ {
ShortName = framework.GetShortFolderName(), ShortName = framework.GetShortFolderName(),
FrameworkName = framework.DotNetFrameworkName, FrameworkName = framework.DotNetFrameworkName,
FriendlyName = framework.Framework, FriendlyName = framework.Framework,
RedistListPath = resolver.GetFrameworkRedistListPath(framework) RedistListPath = FrameworkReferenceResolver.Default.GetFrameworkRedistListPath(framework)
}; };
} }
} }

View file

@ -1,13 +0,0 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.Collections.Generic;
using Microsoft.DotNet.ProjectModel.Server.Models;
namespace Microsoft.DotNet.ProjectModel.Server.InternalModels
{
internal class DependencyInfo
{
public Dictionary<string, DependencyDescription> Dependencies { get; set; }
}
}

View file

@ -0,0 +1,69 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.DotNet.ProjectModel.Server.Helpers;
using Microsoft.DotNet.ProjectModel.Server.Models;
using NuGet.Frameworks;
namespace Microsoft.DotNet.ProjectModel.Server
{
internal class ProjectContextSnapshot
{
public string RootDependency { get; set; }
public NuGetFramework TargetFramework { get; set; }
public IReadOnlyList<string> SourceFiles { get; set; }
public CommonCompilerOptions CompilerOptions { get; set; }
public IReadOnlyList<ProjectReferenceDescription> ProjectReferences { get; set; }
public IReadOnlyList<string> FileReferences { get; set; }
public IReadOnlyList<DiagnosticMessage> DependencyDiagnostics { get; set; }
public IDictionary<string, DependencyDescription> Dependencies { get; set; }
public static ProjectContextSnapshot Create(ProjectContext context, string configuration, IEnumerable<string> currentSearchPaths)
{
var snapshot = new ProjectContextSnapshot();
var allDependencyDiagnostics = new List<DiagnosticMessage>();
allDependencyDiagnostics.AddRange(context.LibraryManager.GetAllDiagnostics());
allDependencyDiagnostics.AddRange(DependencyTypeChangeFinder.Diagnose(context, currentSearchPaths));
var diagnosticsLookup = allDependencyDiagnostics.ToLookup(d => d.Source);
var allSourceFiles = new List<string>(context.ProjectFile.Files.SourceFiles);
var allFileReferences = new List<string>();
var allProjectReferences = new List<ProjectReferenceDescription>();
var allDependencies = new Dictionary<string, DependencyDescription>();
foreach (var export in context.CreateExporter(configuration).GetDependencies())
{
allSourceFiles.AddRange(export.SourceReferences);
allFileReferences.AddRange(export.CompilationAssemblies.Select(asset => asset.ResolvedPath));
var library = export.Library;
var diagnostics = diagnosticsLookup[library].ToList();
var description = DependencyDescription.Create(library, diagnostics);
allDependencies[description.Name] = description;
var projectDescription = library as ProjectDescription;
if (projectDescription != null)
{
allProjectReferences.Add(ProjectReferenceDescription.Create(projectDescription));
}
}
snapshot.RootDependency = context.ProjectFile.Name;
snapshot.TargetFramework = context.TargetFramework;
snapshot.SourceFiles = allSourceFiles.Distinct(StringComparer.OrdinalIgnoreCase).OrderBy(path => path).ToList();
snapshot.CompilerOptions = context.ProjectFile.GetCompilerOptions(context.TargetFramework, configuration);
snapshot.ProjectReferences = allProjectReferences.OrderBy(reference => reference.Name).ToList();
snapshot.FileReferences = allFileReferences.Distinct(StringComparer.OrdinalIgnoreCase).OrderBy(path => path).ToList();
snapshot.DependencyDiagnostics = allDependencyDiagnostics;
snapshot.Dependencies = allDependencies;
return snapshot;
}
}
}

View file

@ -1,83 +0,0 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.DotNet.ProjectModel.Server.Helpers;
using Microsoft.DotNet.ProjectModel.Server.Models;
using NuGet.Frameworks;
namespace Microsoft.DotNet.ProjectModel.Server.InternalModels
{
internal class ProjectInfo
{
public ProjectInfo(ProjectContext context,
string configuration,
IEnumerable<string> currentSearchPaths)
{
var allExports = context.CreateExporter(configuration).GetAllExports().ToList();
var allDiagnostics = context.LibraryManager.GetAllDiagnostics();
Context = context;
Configuration = configuration;
var allSourceFiles = new List<string>(context.ProjectFile.Files.SourceFiles);
var allFileReferences = new List<string>();
foreach (var export in allExports)
{
allSourceFiles.AddRange(export.SourceReferences);
allFileReferences.AddRange(export.CompilationAssemblies.Select(asset => asset.ResolvedPath));
}
SourceFiles = allSourceFiles.Distinct(StringComparer.OrdinalIgnoreCase).OrderBy(path => path).ToList();
CompilationAssembiles = allFileReferences.Distinct(StringComparer.OrdinalIgnoreCase).OrderBy(path => path).ToList();
var allProjectReferences = new List<ProjectReferenceDescription>();
var allDependencyDiagnostics = new List<DiagnosticMessage>();
allDependencyDiagnostics.AddRange(context.LibraryManager.GetAllDiagnostics());
allDependencyDiagnostics.AddRange(DependencyTypeChangeFinder.Diagnose(Context, currentSearchPaths));
var diagnosticsLookup = allDependencyDiagnostics.ToLookup(d => d.Source);
Dependencies = new Dictionary<string, DependencyDescription>();
foreach (var library in context.LibraryManager.GetLibraries())
{
var diagnostics = diagnosticsLookup[library].ToList();
var description = DependencyDescription.Create(library, diagnostics);
Dependencies[description.Name] = description;
if (library is ProjectDescription && library.Identity.Name != context.ProjectFile.Name)
{
allProjectReferences.Add(ProjectReferenceDescription.Create((ProjectDescription)library));
}
}
DependencyDiagnostics = allDependencyDiagnostics;
ProjectReferences = allProjectReferences.OrderBy(reference => reference.Name).ToList();
}
public string Configuration { get; }
public ProjectContext Context { get; }
public string RootDependency => Context.ProjectFile.Name;
public NuGetFramework Framework => Context.TargetFramework;
public CommonCompilerOptions CompilerOptions => Context.ProjectFile.GetCompilerOptions(Framework, Configuration);
public IReadOnlyList<string> SourceFiles { get; }
public IReadOnlyList<string> CompilationAssembiles { get; }
public IReadOnlyList<ProjectReferenceDescription> ProjectReferences { get; }
public IReadOnlyList<DiagnosticMessage> DependencyDiagnostics { get; }
public Dictionary<string, DependencyDescription> Dependencies { get; }
}
}

View file

@ -1,21 +1,47 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved. // Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information. // Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using Microsoft.DotNet.ProjectModel.Server.Helpers;
using Microsoft.DotNet.ProjectModel.Server.Models; using Microsoft.DotNet.ProjectModel.Server.Models;
using NuGet.Frameworks; using NuGet.Frameworks;
namespace Microsoft.DotNet.ProjectModel.Server.InternalModels namespace Microsoft.DotNet.ProjectModel.Server
{ {
internal class ProjectSnapshot internal class ProjectSnapshot
{ {
public NuGetFramework TargetFramework { get; set; } public Project Project { get; set; }
public IReadOnlyList<string> SourceFiles { get; set; } public string GlobalJsonPath { get; set; }
public CommonCompilerOptions CompilerOptions { get; set; } public IReadOnlyList<string> ProjectSearchPaths { get; set; }
public IReadOnlyList<ProjectReferenceDescription> ProjectReferences { get; set; } public IReadOnlyList<DiagnosticMessage> ProjectDiagnostics { get; set; }
public IReadOnlyList<string> FileReferences { get; set; } public ErrorMessage GlobalErrorMessage { get; set; }
public IReadOnlyList<DiagnosticMessage> DependencyDiagnostics { get; set; } public Dictionary<NuGetFramework, ProjectContextSnapshot> ProjectContexts { get; } = new Dictionary<NuGetFramework, ProjectContextSnapshot>();
public IDictionary<string, DependencyDescription> Dependencies { get; set; }
public string RootDependency { get; set; } public static ProjectSnapshot Create(string projectDirectory, string configuration, WorkspaceContext workspaceContext, IReadOnlyList<string> projectSearchPaths)
{
var projectContextsCollection = workspaceContext.GetProjectContextCollection(projectDirectory);
if (!projectContextsCollection.ProjectContexts.Any())
{
throw new InvalidOperationException($"Unable to find project.json in '{projectDirectory}'");
}
GlobalSettings globalSettings;
var currentSearchPaths = projectContextsCollection.Project.ResolveSearchPaths(out globalSettings);
var snapshot = new ProjectSnapshot();
snapshot.Project = projectContextsCollection.Project;
snapshot.ProjectDiagnostics = new List<DiagnosticMessage>(projectContextsCollection.ProjectDiagnostics);
snapshot.ProjectSearchPaths = currentSearchPaths.ToList();
snapshot.GlobalJsonPath = globalSettings?.FilePath;
foreach (var projectContext in projectContextsCollection.ProjectContexts)
{
snapshot.ProjectContexts[projectContext.TargetFramework] =
ProjectContextSnapshot.Create(projectContext, configuration, currentSearchPaths);
}
return snapshot;
}
} }
} }

View file

@ -1,51 +0,0 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.Linq;
using System.Collections.Generic;
using System;
namespace Microsoft.DotNet.ProjectModel.Server.InternalModels
{
internal class ProjectState
{
public static ProjectState Create(string appPath,
string configuration,
WorkspaceContext workspaceContext,
IEnumerable<string> currentSearchPaths)
{
var projectContextsCollection = workspaceContext.GetProjectContextCollection(appPath);
if (!projectContextsCollection.ProjectContexts.Any())
{
throw new InvalidOperationException($"Unable to find project.json in '{appPath}'");
}
var project = projectContextsCollection.ProjectContexts.First().ProjectFile;
var projectDiagnostics = new List<DiagnosticMessage>(projectContextsCollection.ProjectDiagnostics);
var projectInfos = new List<ProjectInfo>();
foreach (var projectContext in projectContextsCollection.ProjectContexts)
{
projectInfos.Add(new ProjectInfo(
projectContext,
configuration,
currentSearchPaths));
}
return new ProjectState(project, projectDiagnostics, projectInfos);
}
private ProjectState(Project project, List<DiagnosticMessage> projectDiagnostics, List<ProjectInfo> projectInfos)
{
Project = project;
Projects = projectInfos;
Diagnostics = projectDiagnostics;
}
public Project Project { get; }
public IReadOnlyList<ProjectInfo> Projects { get; }
public IReadOnlyList<DiagnosticMessage> Diagnostics { get; }
}
}

View file

@ -1,43 +0,0 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.Collections.Generic;
using System.Linq;
using Microsoft.DotNet.ProjectModel.Server.Helpers;
using Microsoft.DotNet.ProjectModel.Server.InternalModels;
using Microsoft.DotNet.ProjectModel.Server.Models;
using NuGet.Frameworks;
namespace Microsoft.DotNet.ProjectModel.Server
{
internal class Snapshot
{
public static Snapshot CreateFromProject(Project project)
{
GlobalSettings globalSettings;
var projectSearchPaths = project.ResolveSearchPaths(out globalSettings);
return new Snapshot(project, globalSettings?.FilePath, projectSearchPaths);
}
public Snapshot()
{
Projects = new Dictionary<NuGetFramework, ProjectSnapshot>();
}
public Snapshot(Project project, string globalJsonPath, IEnumerable<string> projectSearchPaths)
: this()
{
Project = project;
GlobalJsonPath = globalJsonPath;
ProjectSearchPaths = projectSearchPaths.ToList();
}
public Project Project { get; set; }
public string GlobalJsonPath { get; set; }
public IReadOnlyList<string> ProjectSearchPaths { get; set; }
public IReadOnlyList<DiagnosticMessage> ProjectDiagnostics { get; set; }
public ErrorMessage GlobalErrorMessage { get; set; }
public Dictionary<NuGetFramework, ProjectSnapshot> Projects { get; }
}
}

View file

@ -6,7 +6,6 @@ namespace Microsoft.DotNet.ProjectModel.Server
public class MessageTypes public class MessageTypes
{ {
// Incoming // Incoming
public const string ProjectContexts = nameof(ProjectContexts);
public const string Initialize = nameof(Initialize); public const string Initialize = nameof(Initialize);
public const string ChangeConfiguration = nameof(ChangeConfiguration); public const string ChangeConfiguration = nameof(ChangeConfiguration);
public const string RefreshDependencies = nameof(RefreshDependencies); public const string RefreshDependencies = nameof(RefreshDependencies);
@ -24,6 +23,5 @@ namespace Microsoft.DotNet.ProjectModel.Server
public const string CompilerOptions = nameof(CompilerOptions); public const string CompilerOptions = nameof(CompilerOptions);
public const string References = nameof(References); public const string References = nameof(References);
public const string Sources = nameof(Sources); public const string Sources = nameof(Sources);
public const string AllDiagnostics = nameof(AllDiagnostics);
} }
} }

View file

@ -2,38 +2,37 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information. // Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System; using System;
using Microsoft.DotNet.ProjectModel.Server.InternalModels;
using Microsoft.DotNet.ProjectModel.Server.Models; using Microsoft.DotNet.ProjectModel.Server.Models;
namespace Microsoft.DotNet.ProjectModel.Server.Messengers namespace Microsoft.DotNet.ProjectModel.Server.Messengers
{ {
internal class CompilerOptionsMessenger : Messenger<ProjectSnapshot> internal class CompilerOptionsMessenger : Messenger<ProjectContextSnapshot>
{ {
public CompilerOptionsMessenger(Action<string, object> transmit) public CompilerOptionsMessenger(Action<string, object> transmit)
: base(MessageTypes.CompilerOptions, transmit) : base(MessageTypes.CompilerOptions, transmit)
{ } { }
protected override bool CheckDifference(ProjectSnapshot local, ProjectSnapshot remote) protected override bool CheckDifference(ProjectContextSnapshot local, ProjectContextSnapshot remote)
{ {
return remote.CompilerOptions != null && return remote.CompilerOptions != null &&
Equals(local.CompilerOptions, remote.CompilerOptions); Equals(local.CompilerOptions, remote.CompilerOptions);
} }
protected override object CreatePayload(ProjectSnapshot local) protected override object CreatePayload(ProjectContextSnapshot local)
{ {
return new CompilationOptionsMessagePayload return new CompilationOptionsMessage
{ {
Framework = local.TargetFramework.ToPayload(_resolver), Framework = local.TargetFramework.ToPayload(),
Options = local.CompilerOptions Options = local.CompilerOptions
}; };
} }
protected override void SetValue(ProjectSnapshot local, ProjectSnapshot remote) protected override void SetValue(ProjectContextSnapshot local, ProjectContextSnapshot remote)
{ {
remote.CompilerOptions = local.CompilerOptions; remote.CompilerOptions = local.CompilerOptions;
} }
private class CompilationOptionsMessagePayload private class CompilationOptionsMessage
{ {
public FrameworkData Framework { get; set; } public FrameworkData Framework { get; set; }

View file

@ -4,18 +4,17 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Microsoft.DotNet.ProjectModel.Server.InternalModels;
using Microsoft.DotNet.ProjectModel.Server.Models; using Microsoft.DotNet.ProjectModel.Server.Models;
namespace Microsoft.DotNet.ProjectModel.Server.Messengers namespace Microsoft.DotNet.ProjectModel.Server.Messengers
{ {
internal class DependenciesMessenger : Messenger<ProjectSnapshot> internal class DependenciesMessenger : Messenger<ProjectContextSnapshot>
{ {
public DependenciesMessenger(Action<string, object> transmit) public DependenciesMessenger(Action<string, object> transmit)
: base(MessageTypes.Dependencies, transmit) : base(MessageTypes.Dependencies, transmit)
{ } { }
protected override bool CheckDifference(ProjectSnapshot local, ProjectSnapshot remote) protected override bool CheckDifference(ProjectContextSnapshot local, ProjectContextSnapshot remote)
{ {
return remote.Dependencies != null && return remote.Dependencies != null &&
string.Equals(local.RootDependency, remote.RootDependency) && string.Equals(local.RootDependency, remote.RootDependency) &&
@ -23,17 +22,17 @@ namespace Microsoft.DotNet.ProjectModel.Server.Messengers
Enumerable.SequenceEqual(local.Dependencies, remote.Dependencies); Enumerable.SequenceEqual(local.Dependencies, remote.Dependencies);
} }
protected override object CreatePayload(ProjectSnapshot local) protected override object CreatePayload(ProjectContextSnapshot local)
{ {
return new DependenciesMessage return new DependenciesMessage
{ {
Framework = local.TargetFramework.ToPayload(_resolver), Framework = local.TargetFramework.ToPayload(),
RootDependency = local.RootDependency, RootDependency = local.RootDependency,
Dependencies = local.Dependencies Dependencies = local.Dependencies
}; };
} }
protected override void SetValue(ProjectSnapshot local, ProjectSnapshot remote) protected override void SetValue(ProjectContextSnapshot local, ProjectContextSnapshot remote)
{ {
remote.Dependencies = local.Dependencies; remote.Dependencies = local.Dependencies;
} }

View file

@ -3,31 +3,30 @@
using System; using System;
using System.Linq; using System.Linq;
using Microsoft.DotNet.ProjectModel.Server.InternalModels;
using Microsoft.DotNet.ProjectModel.Server.Models; using Microsoft.DotNet.ProjectModel.Server.Models;
namespace Microsoft.DotNet.ProjectModel.Server.Messengers namespace Microsoft.DotNet.ProjectModel.Server.Messengers
{ {
internal class DependencyDiagnosticsMessenger : Messenger<ProjectSnapshot> internal class DependencyDiagnosticsMessenger : Messenger<ProjectContextSnapshot>
{ {
public DependencyDiagnosticsMessenger(Action<string, object> transmit) public DependencyDiagnosticsMessenger(Action<string, object> transmit)
: base(MessageTypes.DependencyDiagnostics, transmit) : base(MessageTypes.DependencyDiagnostics, transmit)
{ } { }
protected override bool CheckDifference(ProjectSnapshot local, ProjectSnapshot remote) protected override bool CheckDifference(ProjectContextSnapshot local, ProjectContextSnapshot remote)
{ {
return remote.DependencyDiagnostics != null && return remote.DependencyDiagnostics != null &&
Enumerable.SequenceEqual(local.DependencyDiagnostics, remote.DependencyDiagnostics); Enumerable.SequenceEqual(local.DependencyDiagnostics, remote.DependencyDiagnostics);
} }
protected override object CreatePayload(ProjectSnapshot local) protected override object CreatePayload(ProjectContextSnapshot local)
{ {
return new DiagnosticsListMessage( return new DiagnosticsListMessage(
local.DependencyDiagnostics, local.DependencyDiagnostics,
local.TargetFramework?.ToPayload(_resolver)); local.TargetFramework?.ToPayload());
} }
protected override void SetValue(ProjectSnapshot local, ProjectSnapshot remote) protected override void SetValue(ProjectContextSnapshot local, ProjectContextSnapshot remote)
{ {
remote.DependencyDiagnostics = local.DependencyDiagnostics; remote.DependencyDiagnostics = local.DependencyDiagnostics;
} }

View file

@ -5,23 +5,23 @@ using System;
namespace Microsoft.DotNet.ProjectModel.Server.Messengers namespace Microsoft.DotNet.ProjectModel.Server.Messengers
{ {
internal class GlobalErrorMessenger : Messenger<Snapshot> internal class GlobalErrorMessenger : Messenger<ProjectSnapshot>
{ {
public GlobalErrorMessenger(Action<string, object> transmit) public GlobalErrorMessenger(Action<string, object> transmit)
: base(MessageTypes.Error, transmit) : base(MessageTypes.Error, transmit)
{ } { }
protected override bool CheckDifference(Snapshot local, Snapshot remote) protected override bool CheckDifference(ProjectSnapshot local, ProjectSnapshot remote)
{ {
return remote != null && Equals(local.GlobalErrorMessage, remote.GlobalErrorMessage); return remote != null && Equals(local.GlobalErrorMessage, remote.GlobalErrorMessage);
} }
protected override object CreatePayload(Snapshot local) protected override object CreatePayload(ProjectSnapshot local)
{ {
return local.GlobalErrorMessage; return local.GlobalErrorMessage;
} }
protected override void SetValue(Snapshot local, Snapshot remote) protected override void SetValue(ProjectSnapshot local, ProjectSnapshot remote)
{ {
remote.GlobalErrorMessage = local.GlobalErrorMessage; remote.GlobalErrorMessage = local.GlobalErrorMessage;
} }

View file

@ -2,18 +2,15 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information. // Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System; using System;
using Microsoft.DotNet.ProjectModel.Resolution;
namespace Microsoft.DotNet.ProjectModel.Server.Messengers namespace Microsoft.DotNet.ProjectModel.Server.Messengers
{ {
internal abstract class Messenger<T> where T : class internal abstract class Messenger<T> where T : class
{ {
protected readonly FrameworkReferenceResolver _resolver;
protected readonly Action<string, object> _transmit; protected readonly Action<string, object> _transmit;
public Messenger(string messageType, Action<string, object> transmit) public Messenger(string messageType, Action<string, object> transmit)
{ {
_resolver = FrameworkReferenceResolver.Default;
_transmit = transmit; _transmit = transmit;
MessageType = messageType; MessageType = messageType;

View file

@ -7,24 +7,24 @@ using Microsoft.DotNet.ProjectModel.Server.Models;
namespace Microsoft.DotNet.ProjectModel.Server.Messengers namespace Microsoft.DotNet.ProjectModel.Server.Messengers
{ {
internal class ProjectDiagnosticsMessenger : Messenger<Snapshot> internal class ProjectDiagnosticsMessenger : Messenger<ProjectSnapshot>
{ {
public ProjectDiagnosticsMessenger(Action<string, object> transmit) public ProjectDiagnosticsMessenger(Action<string, object> transmit)
: base(MessageTypes.Diagnostics, transmit) : base(MessageTypes.Diagnostics, transmit)
{ } { }
protected override bool CheckDifference(Snapshot local, Snapshot remote) protected override bool CheckDifference(ProjectSnapshot local, ProjectSnapshot remote)
{ {
return remote.ProjectDiagnostics != null && return remote.ProjectDiagnostics != null &&
Enumerable.SequenceEqual(local.ProjectDiagnostics, remote.ProjectDiagnostics); Enumerable.SequenceEqual(local.ProjectDiagnostics, remote.ProjectDiagnostics);
} }
protected override object CreatePayload(Snapshot local) protected override object CreatePayload(ProjectSnapshot local)
{ {
return new DiagnosticsListMessage(local.ProjectDiagnostics); return new DiagnosticsListMessage(local.ProjectDiagnostics);
} }
protected override void SetValue(Snapshot local, Snapshot remote) protected override void SetValue(ProjectSnapshot local, ProjectSnapshot remote)
{ {
remote.ProjectDiagnostics = local.ProjectDiagnostics; remote.ProjectDiagnostics = local.ProjectDiagnostics;
} }

View file

@ -4,18 +4,17 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Microsoft.DotNet.ProjectModel.Resolution;
using Microsoft.DotNet.ProjectModel.Server.Models; using Microsoft.DotNet.ProjectModel.Server.Models;
namespace Microsoft.DotNet.ProjectModel.Server.Messengers namespace Microsoft.DotNet.ProjectModel.Server.Messengers
{ {
internal class ProjectInformationMessenger : Messenger<Snapshot> internal class ProjectInformationMessenger : Messenger<ProjectSnapshot>
{ {
public ProjectInformationMessenger(Action<string, object> transmit) public ProjectInformationMessenger(Action<string, object> transmit)
: base(MessageTypes.ProjectInformation, transmit) : base(MessageTypes.ProjectInformation, transmit)
{ } { }
protected override bool CheckDifference(Snapshot local, Snapshot remote) protected override bool CheckDifference(ProjectSnapshot local, ProjectSnapshot remote)
{ {
return remote.Project != null && return remote.Project != null &&
string.Equals(local.Project.Name, remote.Project.Name) && string.Equals(local.Project.Name, remote.Project.Name) &&
@ -27,30 +26,29 @@ namespace Microsoft.DotNet.ProjectModel.Server.Messengers
Enumerable.SequenceEqual(local.ProjectSearchPaths, remote.ProjectSearchPaths); Enumerable.SequenceEqual(local.ProjectSearchPaths, remote.ProjectSearchPaths);
} }
protected override object CreatePayload(Snapshot local) protected override object CreatePayload(ProjectSnapshot local)
{ {
return new ProjectInformation(local.Project, local.GlobalJsonPath, local.ProjectSearchPaths, _resolver); return new ProjectInformationMessage(local.Project, local.GlobalJsonPath, local.ProjectSearchPaths);
} }
protected override void SetValue(Snapshot local, Snapshot remote) protected override void SetValue(ProjectSnapshot local, ProjectSnapshot remote)
{ {
remote.Project = local.Project; remote.Project = local.Project;
remote.GlobalJsonPath = local.GlobalJsonPath; remote.GlobalJsonPath = local.GlobalJsonPath;
remote.ProjectSearchPaths = local.ProjectSearchPaths; remote.ProjectSearchPaths = local.ProjectSearchPaths;
} }
private class ProjectInformation private class ProjectInformationMessage
{ {
public ProjectInformation(Project project, public ProjectInformationMessage(Project project,
string gloablJsonPath, string gloablJsonPath,
IEnumerable<string> projectSearchPath, IReadOnlyList<string> projectSearchPaths)
FrameworkReferenceResolver resolver)
{ {
Name = project.Name; Name = project.Name;
Frameworks = project.GetTargetFrameworks().Select(f => f.FrameworkName.ToPayload(resolver)).ToList(); Frameworks = project.GetTargetFrameworks().Select(f => f.FrameworkName.ToPayload()).ToList();
Configurations = project.GetConfigurations().ToList(); Configurations = project.GetConfigurations().ToList();
Commands = project.Commands; Commands = project.Commands;
ProjectSearchPaths = new List<string>(projectSearchPath); ProjectSearchPaths = projectSearchPaths;
GlobalJsonPath = gloablJsonPath; GlobalJsonPath = gloablJsonPath;
} }

View file

@ -4,18 +4,17 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Microsoft.DotNet.ProjectModel.Server.InternalModels;
using Microsoft.DotNet.ProjectModel.Server.Models; using Microsoft.DotNet.ProjectModel.Server.Models;
namespace Microsoft.DotNet.ProjectModel.Server.Messengers namespace Microsoft.DotNet.ProjectModel.Server.Messengers
{ {
internal class ReferencesMessenger : Messenger<ProjectSnapshot> internal class ReferencesMessenger : Messenger<ProjectContextSnapshot>
{ {
public ReferencesMessenger(Action<string, object> transmit) public ReferencesMessenger(Action<string, object> transmit)
: base(MessageTypes.References, transmit) : base(MessageTypes.References, transmit)
{ } { }
protected override bool CheckDifference(ProjectSnapshot local, ProjectSnapshot remote) protected override bool CheckDifference(ProjectContextSnapshot local, ProjectContextSnapshot remote)
{ {
return remote.FileReferences != null && return remote.FileReferences != null &&
remote.ProjectReferences != null && remote.ProjectReferences != null &&
@ -23,17 +22,17 @@ namespace Microsoft.DotNet.ProjectModel.Server.Messengers
Enumerable.SequenceEqual(local.ProjectReferences, remote.ProjectReferences); Enumerable.SequenceEqual(local.ProjectReferences, remote.ProjectReferences);
} }
protected override object CreatePayload(ProjectSnapshot local) protected override object CreatePayload(ProjectContextSnapshot local)
{ {
return new ReferencesMessage return new ReferencesMessage
{ {
Framework = local.TargetFramework.ToPayload(_resolver), Framework = local.TargetFramework.ToPayload(),
ProjectReferences = local.ProjectReferences, ProjectReferences = local.ProjectReferences,
FileReferences = local.FileReferences FileReferences = local.FileReferences
}; };
} }
protected override void SetValue(ProjectSnapshot local, ProjectSnapshot remote) protected override void SetValue(ProjectContextSnapshot local, ProjectContextSnapshot remote)
{ {
remote.FileReferences = local.FileReferences; remote.FileReferences = local.FileReferences;
remote.ProjectReferences = local.ProjectReferences; remote.ProjectReferences = local.ProjectReferences;

View file

@ -4,39 +4,38 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Microsoft.DotNet.ProjectModel.Server.InternalModels;
using Microsoft.DotNet.ProjectModel.Server.Models; using Microsoft.DotNet.ProjectModel.Server.Models;
namespace Microsoft.DotNet.ProjectModel.Server.Messengers namespace Microsoft.DotNet.ProjectModel.Server.Messengers
{ {
internal class SourcesMessenger : Messenger<ProjectSnapshot> internal class SourcesMessenger : Messenger<ProjectContextSnapshot>
{ {
public SourcesMessenger(Action<string, object> transmit) public SourcesMessenger(Action<string, object> transmit)
: base(MessageTypes.Sources, transmit) : base(MessageTypes.Sources, transmit)
{ } { }
protected override bool CheckDifference(ProjectSnapshot local, ProjectSnapshot remote) protected override bool CheckDifference(ProjectContextSnapshot local, ProjectContextSnapshot remote)
{ {
return remote.SourceFiles != null && return remote.SourceFiles != null &&
Enumerable.SequenceEqual(local.SourceFiles, remote.SourceFiles); Enumerable.SequenceEqual(local.SourceFiles, remote.SourceFiles);
} }
protected override object CreatePayload(ProjectSnapshot local) protected override object CreatePayload(ProjectContextSnapshot local)
{ {
return new SourcesMessagePayload return new SourcesMessage
{ {
Framework = local.TargetFramework.ToPayload(_resolver), Framework = local.TargetFramework.ToPayload(),
Files = local.SourceFiles, Files = local.SourceFiles,
GeneratedFiles = new Dictionary<string, string>() GeneratedFiles = new Dictionary<string, string>()
}; };
} }
protected override void SetValue(ProjectSnapshot local, ProjectSnapshot remote) protected override void SetValue(ProjectContextSnapshot local, ProjectContextSnapshot remote)
{ {
remote.SourceFiles = local.SourceFiles; remote.SourceFiles = local.SourceFiles;
} }
private class SourcesMessagePayload private class SourcesMessage
{ {
public FrameworkData Framework { get; set; } public FrameworkData Framework { get; set; }
public IReadOnlyList<string> Files { get; set; } public IReadOnlyList<string> Files { get; set; }

View file

@ -11,28 +11,6 @@ namespace Microsoft.DotNet.ProjectModel.Server.Models
{ {
private DependencyDescription() { } private DependencyDescription() { }
public static DependencyDescription Create(LibraryDescription library, IEnumerable<DiagnosticMessage> diagnostics)
{
return new DependencyDescription
{
Name = library.Identity.Name,
DisplayName = GetLibraryDisplayName(library),
Version = library.Identity.Version?.ToString(),
Type = library.Identity.Type.Value,
Resolved = library.Resolved,
Path = library.Path,
Dependencies = library.Dependencies.Select(dependency => new DependencyItem
{
Name = dependency.Name,
Version = dependency.VersionRange?.ToString() // TODO: review
}),
Errors = diagnostics.Where(d => d.Severity == DiagnosticMessageSeverity.Error)
.Select(d => new DiagnosticMessageView(d)),
Warnings = diagnostics.Where(d => d.Severity == DiagnosticMessageSeverity.Warning)
.Select(d => new DiagnosticMessageView(d))
};
}
public string Name { get; private set; } public string Name { get; private set; }
public string DisplayName { get; private set; } public string DisplayName { get; private set; }
@ -73,6 +51,28 @@ namespace Microsoft.DotNet.ProjectModel.Server.Models
return base.GetHashCode(); return base.GetHashCode();
} }
public static DependencyDescription Create(LibraryDescription library, IEnumerable<DiagnosticMessage> diagnostics)
{
return new DependencyDescription
{
Name = library.Identity.Name,
DisplayName = GetLibraryDisplayName(library),
Version = library.Identity.Version?.ToString(),
Type = library.Identity.Type.Value,
Resolved = library.Resolved,
Path = library.Path,
Dependencies = library.Dependencies.Select(dependency => new DependencyItem
{
Name = dependency.Name,
Version = dependency.VersionRange?.ToString() // TODO: review
}),
Errors = diagnostics.Where(d => d.Severity == DiagnosticMessageSeverity.Error)
.Select(d => new DiagnosticMessageView(d)),
Warnings = diagnostics.Where(d => d.Severity == DiagnosticMessageSeverity.Warning)
.Select(d => new DiagnosticMessageView(d))
};
}
private static string GetLibraryDisplayName(LibraryDescription library) private static string GetLibraryDisplayName(LibraryDescription library)
{ {
var name = library.Identity.Name; var name = library.Identity.Name;

View file

@ -5,7 +5,6 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Microsoft.DotNet.ProjectModel.Server.Models namespace Microsoft.DotNet.ProjectModel.Server.Models
{ {

View file

@ -7,6 +7,24 @@ namespace Microsoft.DotNet.ProjectModel.Server.Models
{ {
private ProjectReferenceDescription() { } private ProjectReferenceDescription() { }
public string Name { get; set; }
public string Path { get; set; }
public string WrappedProjectPath { get; set; }
public override bool Equals(object obj)
{
var other = obj as ProjectReferenceDescription;
return other != null &&
string.Equals(Name, other.Name) &&
string.Equals(Path, other.Path) &&
string.Equals(WrappedProjectPath, other.WrappedProjectPath);
}
public override int GetHashCode()
{
return base.GetHashCode();
}
public static ProjectReferenceDescription Create(ProjectDescription description) public static ProjectReferenceDescription Create(ProjectDescription description)
{ {
var targetFrameworkInformation = description.TargetFrameworkInfo; var targetFrameworkInformation = description.TargetFrameworkInfo;
@ -29,23 +47,5 @@ namespace Microsoft.DotNet.ProjectModel.Server.Models
WrappedProjectPath = wrappedProjectPath, WrappedProjectPath = wrappedProjectPath,
}; };
} }
public string Name { get; set; }
public string Path { get; set; }
public string WrappedProjectPath { get; set; }
public override bool Equals(object obj)
{
var other = obj as ProjectReferenceDescription;
return other != null &&
string.Equals(Name, other.Name) &&
string.Equals(Path, other.Path) &&
string.Equals(WrappedProjectPath, other.WrappedProjectPath);
}
public override int GetHashCode()
{
return base.GetHashCode();
}
} }
} }

View file

@ -6,14 +6,13 @@ using System.Diagnostics;
using System.Net; using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
using Microsoft.Dnx.Runtime.Common.CommandLine; using Microsoft.Dnx.Runtime.Common.CommandLine;
using Microsoft.DotNet.ProjectModel.Resolution;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
namespace Microsoft.DotNet.ProjectModel.Server namespace Microsoft.DotNet.ProjectModel.Server
{ {
public class Program public class Program
{ {
private readonly Dictionary<int, ProjectContextManager> _projectContextManagers; private readonly Dictionary<int, ProjectManager> _projects;
private readonly WorkspaceContext _workspaceContext; private readonly WorkspaceContext _workspaceContext;
private readonly ProtocolManager _protocolManager; private readonly ProtocolManager _protocolManager;
private readonly ILoggerFactory _loggerFactory; private readonly ILoggerFactory _loggerFactory;
@ -21,14 +20,14 @@ namespace Microsoft.DotNet.ProjectModel.Server
private readonly int _port; private readonly int _port;
private Socket _listenSocket; private Socket _listenSocket;
public Program(int intPort, string hostName, ILoggerFactory loggerFactory) public Program(int port, string hostName, ILoggerFactory loggerFactory)
{ {
_port = intPort; _port = port;
_hostName = hostName; _hostName = hostName;
_loggerFactory = loggerFactory; _loggerFactory = loggerFactory;
_protocolManager = new ProtocolManager(maxVersion: 4, loggerFactory: _loggerFactory); _protocolManager = new ProtocolManager(maxVersion: 4, loggerFactory: _loggerFactory);
_workspaceContext = WorkspaceContext.Create(); _workspaceContext = WorkspaceContext.Create();
_projectContextManagers = new Dictionary<int, ProjectContextManager>(); _projects = new Dictionary<int, ProjectManager>();
} }
public static int Main(string[] args) public static int Main(string[] args)
@ -41,8 +40,8 @@ namespace Microsoft.DotNet.ProjectModel.Server
app.HelpOption("-?|-h|--help"); app.HelpOption("-?|-h|--help");
var verbose = app.Option("--verbose", "Verbose ouput", CommandOptionType.NoValue); var verbose = app.Option("--verbose", "Verbose ouput", CommandOptionType.NoValue);
var hostpid = app.Option("--hostPid", "The process id of the host", CommandOptionType.SingleValue); var hostpid = app.Option("--host-pid", "The process id of the host", CommandOptionType.SingleValue);
var hostname = app.Option("--hostName", "The name of the host", CommandOptionType.SingleValue); var hostname = app.Option("--host-name", "The name of the host", CommandOptionType.SingleValue);
var port = app.Option("--port", "The TCP port used for communication", CommandOptionType.SingleValue); var port = app.Option("--port", "The TCP port used for communication", CommandOptionType.SingleValue);
app.OnExecute(() => app.OnExecute(() =>
@ -82,7 +81,6 @@ namespace Microsoft.DotNet.ProjectModel.Server
{ {
var logger = _loggerFactory.CreateLogger($"OpenChannel"); var logger = _loggerFactory.CreateLogger($"OpenChannel");
// This fixes the mono incompatibility but ties it to ipv4 connections
_listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); _listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_listenSocket.Bind(new IPEndPoint(IPAddress.Loopback, _port)); _listenSocket.Bind(new IPEndPoint(IPAddress.Loopback, _port));
_listenSocket.Listen(10); _listenSocket.Listen(10);
@ -99,7 +97,7 @@ namespace Microsoft.DotNet.ProjectModel.Server
_hostName, _hostName,
_protocolManager, _protocolManager,
_workspaceContext, _workspaceContext,
_projectContextManagers, _projects,
_loggerFactory); _loggerFactory);
connection.QueueStart(); connection.QueueStart();

View file

@ -6,25 +6,21 @@ using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using Microsoft.DotNet.ProjectModel.Resolution;
using Microsoft.DotNet.ProjectModel.Server.Helpers; using Microsoft.DotNet.ProjectModel.Server.Helpers;
using Microsoft.DotNet.ProjectModel.Server.InternalModels;
using Microsoft.DotNet.ProjectModel.Server.Messengers; using Microsoft.DotNet.ProjectModel.Server.Messengers;
using Microsoft.DotNet.ProjectModel.Server.Models; using Microsoft.DotNet.ProjectModel.Server.Models;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Newtonsoft.Json.Linq;
using NuGet.Frameworks; using NuGet.Frameworks;
namespace Microsoft.DotNet.ProjectModel.Server namespace Microsoft.DotNet.ProjectModel.Server
{ {
internal class ProjectContextManager internal class ProjectManager
{ {
private readonly ILogger _log; private readonly ILogger _log;
private readonly object _processingLock = new object(); private readonly object _processingLock = new object();
private readonly Queue<Message> _inbox = new Queue<Message>(); private readonly Queue<Message> _inbox = new Queue<Message>();
private readonly ProtocolManager _protocolManager; private readonly ProtocolManager _protocolManager;
private readonly List<ConnectionContext> _waitingForDiagnostics = new List<ConnectionContext>();
private ConnectionContext _initializedContext; private ConnectionContext _initializedContext;
@ -34,29 +30,29 @@ namespace Microsoft.DotNet.ProjectModel.Server
private readonly Trigger<int> _refreshDependencies = new Trigger<int>(); private readonly Trigger<int> _refreshDependencies = new Trigger<int>();
private readonly Trigger<int> _filesChanged = new Trigger<int>(); private readonly Trigger<int> _filesChanged = new Trigger<int>();
private Snapshot _local = new Snapshot(); private ProjectSnapshot _local = new ProjectSnapshot();
private Snapshot _remote = new Snapshot(); private ProjectSnapshot _remote = new ProjectSnapshot();
private readonly WorkspaceContext _workspaceContext; private readonly WorkspaceContext _workspaceContext;
private int? _contextProtocolVersion; private int? _contextProtocolVersion;
private readonly List<Messenger<ProjectSnapshot>> _messengers; private readonly List<Messenger<ProjectContextSnapshot>> _messengers;
private ProjectDiagnosticsMessenger _projectDiagnosticsMessenger; private ProjectDiagnosticsMessenger _projectDiagnosticsMessenger;
private GlobalErrorMessenger _globalErrorMessenger; private GlobalErrorMessenger _globalErrorMessenger;
private ProjectInformationMessenger _projectInforamtionMessenger; private ProjectInformationMessenger _projectInforamtionMessenger;
public ProjectContextManager(int contextId, public ProjectManager(int contextId,
ILoggerFactory loggerFactory, ILoggerFactory loggerFactory,
WorkspaceContext workspaceContext, WorkspaceContext workspaceContext,
ProtocolManager protocolManager) ProtocolManager protocolManager)
{ {
Id = contextId; Id = contextId;
_log = loggerFactory.CreateLogger<ProjectContextManager>(); _log = loggerFactory.CreateLogger<ProjectManager>();
_workspaceContext = workspaceContext; _workspaceContext = workspaceContext;
_protocolManager = protocolManager; _protocolManager = protocolManager;
_messengers = new List<Messenger<ProjectSnapshot>> _messengers = new List<Messenger<ProjectContextSnapshot>>
{ {
new DependencyDiagnosticsMessenger(Transmit), new DependencyDiagnosticsMessenger(Transmit),
new DependenciesMessenger(Transmit), new DependenciesMessenger(Transmit),
@ -66,7 +62,7 @@ namespace Microsoft.DotNet.ProjectModel.Server
}; };
_projectDiagnosticsMessenger = new ProjectDiagnosticsMessenger(Transmit); _projectDiagnosticsMessenger = new ProjectDiagnosticsMessenger(Transmit);
_globalErrorMessenger = new GlobalErrorMessenger(TransmitDiagnostics); _globalErrorMessenger = new GlobalErrorMessenger(Transmit);
_projectInforamtionMessenger = new ProjectInformationMessenger(Transmit); _projectInforamtionMessenger = new ProjectInformationMessenger(Transmit);
} }
@ -96,7 +92,7 @@ namespace Microsoft.DotNet.ProjectModel.Server
_inbox.Enqueue(message); _inbox.Enqueue(message);
} }
ThreadPool.QueueUserWorkItem(state => ((ProjectContextManager)state).ProcessLoop(), this); ThreadPool.QueueUserWorkItem(state => ((ProjectManager)state).ProcessLoop(), this);
} }
private void Transmit(string messageType, object payload) private void Transmit(string messageType, object payload)
@ -105,17 +101,6 @@ namespace Microsoft.DotNet.ProjectModel.Server
_initializedContext.Transmit(message); _initializedContext.Transmit(message);
} }
private void TransmitDiagnostics(string messageType, object payload)
{
var message = Message.FromPayload(messageType, Id, payload);
_initializedContext.Transmit(message);
foreach (var connection in _waitingForDiagnostics)
{
connection.Transmit(message);
}
}
private void ProcessLoop() private void ProcessLoop()
{ {
if (!Monitor.TryEnter(_processingLock)) if (!Monitor.TryEnter(_processingLock))
@ -158,13 +143,6 @@ namespace Microsoft.DotNet.ProjectModel.Server
_initializedContext.Transmit(message); _initializedContext.Transmit(message);
_remote.GlobalErrorMessage = error; _remote.GlobalErrorMessage = error;
foreach (var connection in _waitingForDiagnostics)
{
connection.Transmit(message);
}
_waitingForDiagnostics.Clear();
} }
} }
@ -173,12 +151,9 @@ namespace Microsoft.DotNet.ProjectModel.Server
while (true) while (true)
{ {
DrainInbox(); DrainInbox();
var allDiagnostics = new List<DiagnosticMessageGroup>(); UpdateProject();
SendOutgingMessages();
UpdateProjectStates();
SendOutgingMessages(allDiagnostics);
SendDiagnostics(allDiagnostics);
lock (_inbox) lock (_inbox)
{ {
@ -232,9 +207,6 @@ namespace Microsoft.DotNet.ProjectModel.Server
case MessageTypes.FilesChanged: case MessageTypes.FilesChanged:
_filesChanged.Value = 0; _filesChanged.Value = 0;
break; break;
case MessageTypes.GetDiagnostics:
_waitingForDiagnostics.Add(message.Sender);
break;
} }
return true; return true;
@ -260,9 +232,9 @@ namespace Microsoft.DotNet.ProjectModel.Server
} }
} }
private bool UpdateProjectStates() private bool UpdateProject()
{ {
ProjectState state = null; ProjectSnapshot newSnapshot = null;
if (_appPath.WasAssigned || _configure.WasAssigned || _filesChanged.WasAssigned || _refreshDependencies.WasAssigned) if (_appPath.WasAssigned || _configure.WasAssigned || _filesChanged.WasAssigned || _refreshDependencies.WasAssigned)
{ {
@ -271,71 +243,41 @@ namespace Microsoft.DotNet.ProjectModel.Server
_filesChanged.ClearAssigned(); _filesChanged.ClearAssigned();
_refreshDependencies.ClearAssigned(); _refreshDependencies.ClearAssigned();
state = ProjectState.Create(_appPath.Value, _configure.Value, _workspaceContext, _remote.ProjectSearchPaths); newSnapshot = ProjectSnapshot.Create(_appPath.Value, _configure.Value, _workspaceContext, _remote.ProjectSearchPaths);
} }
if (state == null) if (newSnapshot == null)
{ {
return false; return false;
} }
_local = Snapshot.CreateFromProject(state.Project); _local = newSnapshot;
_local.ProjectDiagnostics = state.Diagnostics;
foreach (var projectInfo in state.Projects)
{
var projectWorkd = new ProjectSnapshot
{
RootDependency = projectInfo.RootDependency,
TargetFramework = projectInfo.Framework,
SourceFiles = new List<string>(projectInfo.SourceFiles),
CompilerOptions = projectInfo.CompilerOptions,
ProjectReferences = projectInfo.ProjectReferences,
FileReferences = projectInfo.CompilationAssembiles,
DependencyDiagnostics = projectInfo.DependencyDiagnostics,
Dependencies = projectInfo.Dependencies
};
_local.Projects[projectInfo.Framework] = projectWorkd;
}
return true; return true;
} }
private void SendOutgingMessages(List<DiagnosticMessageGroup> diagnostics) private void SendOutgingMessages()
{ {
_projectInforamtionMessenger.UpdateRemote(_local, _remote); _projectInforamtionMessenger.UpdateRemote(_local, _remote);
_projectDiagnosticsMessenger.UpdateRemote(_local, _remote); _projectDiagnosticsMessenger.UpdateRemote(_local, _remote);
if (_local.ProjectDiagnostics != null) var unprocessedFrameworks = new HashSet<NuGetFramework>(_remote.ProjectContexts.Keys);
foreach (var pair in _local.ProjectContexts)
{ {
diagnostics.Add(new DiagnosticMessageGroup(_local.ProjectDiagnostics)); ProjectContextSnapshot localProjectSnapshot = pair.Value;
} ProjectContextSnapshot remoteProjectSnapshot;
var unprocessedFrameworks = new HashSet<NuGetFramework>(_remote.Projects.Keys); if (!_remote.ProjectContexts.TryGetValue(pair.Key, out remoteProjectSnapshot))
foreach (var pair in _local.Projects)
{
ProjectSnapshot localProjectSnapshot = pair.Value;
ProjectSnapshot remoteProjectSnapshot;
if (!_remote.Projects.TryGetValue(pair.Key, out remoteProjectSnapshot))
{ {
remoteProjectSnapshot = new ProjectSnapshot(); remoteProjectSnapshot = new ProjectContextSnapshot();
_remote.Projects[pair.Key] = remoteProjectSnapshot; _remote.ProjectContexts[pair.Key] = remoteProjectSnapshot;
}
if (localProjectSnapshot.DependencyDiagnostics != null)
{
diagnostics.Add(new DiagnosticMessageGroup(
localProjectSnapshot.TargetFramework,
localProjectSnapshot.DependencyDiagnostics));
} }
unprocessedFrameworks.Remove(pair.Key); unprocessedFrameworks.Remove(pair.Key);
foreach(var messenger in _messengers) foreach (var messenger in _messengers)
{ {
messenger.UpdateRemote(localProjectSnapshot, messenger.UpdateRemote(localProjectSnapshot,
remoteProjectSnapshot); remoteProjectSnapshot);
} }
} }
@ -343,35 +285,10 @@ namespace Microsoft.DotNet.ProjectModel.Server
// Remove all processed frameworks from the remote view // Remove all processed frameworks from the remote view
foreach (var framework in unprocessedFrameworks) foreach (var framework in unprocessedFrameworks)
{ {
_remote.Projects.Remove(framework); _remote.ProjectContexts.Remove(framework);
} }
}
private void SendDiagnostics(List<DiagnosticMessageGroup> allDiagnostics)
{
_log.LogInformation($"SendDiagnostics, {allDiagnostics.Count()} diagnostics, {_waitingForDiagnostics.Count()} waiting for diagnostics.");
if (!allDiagnostics.Any())
{
return;
}
_globalErrorMessenger.UpdateRemote(_local, _remote); _globalErrorMessenger.UpdateRemote(_local, _remote);
// Group all of the diagnostics into group by target framework
var messages = new List<DiagnosticsListMessage>();
foreach (var g in allDiagnostics.GroupBy(g => g.Framework))
{
var frameworkData = g.Key?.ToPayload(FrameworkReferenceResolver.Default);
var messageGroup = g.SelectMany(d => d.Diagnostics).ToList();
messages.Add(new DiagnosticsListMessage(messageGroup, frameworkData));
}
// Send all diagnostics back
TransmitDiagnostics(
MessageTypes.AllDiagnostics,
messages.Select(d => JToken.FromObject(d)));
_waitingForDiagnostics.Clear();
} }
private class Trigger<TValue> private class Trigger<TValue>

View file

@ -9,6 +9,8 @@ namespace Microsoft.DotNet.ProjectModel
{ {
public class ProjectContextCollection public class ProjectContextCollection
{ {
public Project Project { get; set; }
public List<ProjectContext> ProjectContexts { get; } = new List<ProjectContext>(); public List<ProjectContext> ProjectContexts { get; } = new List<ProjectContext>();
public List<DiagnosticMessage> ProjectDiagnostics { get; } = new List<DiagnosticMessage>(); public List<DiagnosticMessage> ProjectDiagnostics { get; } = new List<DiagnosticMessage>();
@ -51,6 +53,7 @@ namespace Microsoft.DotNet.ProjectModel
public void Reset() public void Reset()
{ {
Project = null;
ProjectContexts.Clear(); ProjectContexts.Clear();
ProjectFilePath = null; ProjectFilePath = null;
LockFilePath = null; LockFilePath = null;

View file

@ -210,7 +210,7 @@ namespace Microsoft.DotNet.ProjectModel
} }
private ProjectContextCollection AddProjectContextEntry(string projectDirectory, private ProjectContextCollection AddProjectContextEntry(string projectDirectory,
ProjectContextCollection currentEntry) ProjectContextCollection currentEntry)
{ {
if (currentEntry == null) if (currentEntry == null)
{ {
@ -241,7 +241,8 @@ namespace Microsoft.DotNet.ProjectModel
currentEntry.ProjectContexts.Add(builder.Build()); currentEntry.ProjectContexts.Add(builder.Build());
} }
currentEntry.Project = project;
currentEntry.ProjectFilePath = project.ProjectFilePath; currentEntry.ProjectFilePath = project.ProjectFilePath;
currentEntry.LastProjectFileWriteTime = File.GetLastWriteTime(currentEntry.ProjectFilePath); currentEntry.LastProjectFileWriteTime = File.GetLastWriteTime(currentEntry.ProjectFilePath);

View file

@ -83,33 +83,6 @@ namespace Microsoft.DotNet.ProjectModel.Server.Tests
} }
} }
[Fact]
public void DthCompilation_GetDiagnostics_OnEmptyConsoleApp()
{
var projectPath = _testHelper.FindSampleProject("EmptyConsoleApp");
Assert.NotNull(projectPath);
using (var server = new DthTestServer(_testHelper.LoggerFactory))
using (var client = new DthTestClient(server))
{
// Drain the inital messages
client.Initialize(projectPath);
client.SendPayLoad(projectPath, "GetDiagnostics");
var diagnosticsGroup = client.DrainTillFirst("AllDiagnostics")
.EnsureSource(server, client)
.RetrievePayloadAs<JArray>()
.AssertJArrayCount(3);
foreach (var group in diagnosticsGroup)
{
group.AsJObject()
.AssertProperty<JArray>("Errors", errorsArray => !errorsArray.Any())
.AssertProperty<JArray>("Warnings", warningsArray => !warningsArray.Any());
}
}
}
[Theory] [Theory]
[InlineData("Project", "UnresolvedProjectSample", "EmptyLibrary", "Project")] [InlineData("Project", "UnresolvedProjectSample", "EmptyLibrary", "Project")]
[InlineData("Package", "UnresolvedPackageSample", "NoSuchPackage", null)] [InlineData("Package", "UnresolvedPackageSample", "NoSuchPackage", null)]