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 ProcessingQueue _queue;
private readonly IDictionary<int, ProjectContextManager> _projectContextManagers;
private readonly IDictionary<int, ProjectManager> _projects;
public ConnectionContext(Socket acceptedSocket,
string hostName,
ProtocolManager protocolManager,
WorkspaceContext workspaceContext,
IDictionary<int, ProjectContextManager> projectContextManagers,
IDictionary<int, ProjectManager> projects,
ILoggerFactory loggerFactory)
{
_hostName = hostName;
_projectContextManagers = projectContextManagers;
_projects = projects;
_queue = new ProcessingQueue(new NetworkStream(acceptedSocket), loggerFactory);
_queue.OnReceive += message =>
@ -35,18 +35,18 @@ namespace Microsoft.DotNet.ProjectModel.Server
else
{
message.Sender = this;
ProjectContextManager keeper;
if (!_projectContextManagers.TryGetValue(message.ContextId, out keeper))
ProjectManager projectManager;
if (!_projects.TryGetValue(message.ContextId, out projectManager))
{
keeper = new ProjectContextManager(message.ContextId,
projectManager = new ProjectManager(message.ContextId,
loggerFactory,
workspaceContext,
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 FrameworkData ToPayload(this NuGetFramework framework,
FrameworkReferenceResolver resolver)
public static FrameworkData ToPayload(this NuGetFramework framework)
{
return new FrameworkData
{
ShortName = framework.GetShortFolderName(),
FrameworkName = framework.DotNetFrameworkName,
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.
// 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
namespace Microsoft.DotNet.ProjectModel.Server
{
internal class ProjectSnapshot
{
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 string RootDependency { get; set; }
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, ProjectContextSnapshot> ProjectContexts { get; } = new Dictionary<NuGetFramework, ProjectContextSnapshot>();
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
{
// Incoming
public const string ProjectContexts = nameof(ProjectContexts);
public const string Initialize = nameof(Initialize);
public const string ChangeConfiguration = nameof(ChangeConfiguration);
public const string RefreshDependencies = nameof(RefreshDependencies);
@ -24,6 +23,5 @@ namespace Microsoft.DotNet.ProjectModel.Server
public const string CompilerOptions = nameof(CompilerOptions);
public const string References = nameof(References);
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.
using System;
using Microsoft.DotNet.ProjectModel.Server.InternalModels;
using Microsoft.DotNet.ProjectModel.Server.Models;
namespace Microsoft.DotNet.ProjectModel.Server.Messengers
{
internal class CompilerOptionsMessenger : Messenger<ProjectSnapshot>
internal class CompilerOptionsMessenger : Messenger<ProjectContextSnapshot>
{
public CompilerOptionsMessenger(Action<string, object> 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 &&
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
};
}
protected override void SetValue(ProjectSnapshot local, ProjectSnapshot remote)
protected override void SetValue(ProjectContextSnapshot local, ProjectContextSnapshot remote)
{
remote.CompilerOptions = local.CompilerOptions;
}
private class CompilationOptionsMessagePayload
private class CompilationOptionsMessage
{
public FrameworkData Framework { get; set; }

View file

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

View file

@ -3,31 +3,30 @@
using System;
using System.Linq;
using Microsoft.DotNet.ProjectModel.Server.InternalModels;
using Microsoft.DotNet.ProjectModel.Server.Models;
namespace Microsoft.DotNet.ProjectModel.Server.Messengers
{
internal class DependencyDiagnosticsMessenger : Messenger<ProjectSnapshot>
internal class DependencyDiagnosticsMessenger : Messenger<ProjectContextSnapshot>
{
public DependencyDiagnosticsMessenger(Action<string, object> 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 &&
Enumerable.SequenceEqual(local.DependencyDiagnostics, remote.DependencyDiagnostics);
}
protected override object CreatePayload(ProjectSnapshot local)
protected override object CreatePayload(ProjectContextSnapshot local)
{
return new DiagnosticsListMessage(
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;
}

View file

@ -5,23 +5,23 @@ using System;
namespace Microsoft.DotNet.ProjectModel.Server.Messengers
{
internal class GlobalErrorMessenger : Messenger<Snapshot>
internal class GlobalErrorMessenger : Messenger<ProjectSnapshot>
{
public GlobalErrorMessenger(Action<string, object> 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);
}
protected override object CreatePayload(Snapshot local)
protected override object CreatePayload(ProjectSnapshot local)
{
return local.GlobalErrorMessage;
}
protected override void SetValue(Snapshot local, Snapshot remote)
protected override void SetValue(ProjectSnapshot local, ProjectSnapshot remote)
{
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.
using System;
using Microsoft.DotNet.ProjectModel.Resolution;
namespace Microsoft.DotNet.ProjectModel.Server.Messengers
{
internal abstract class Messenger<T> where T : class
{
protected readonly FrameworkReferenceResolver _resolver;
protected readonly Action<string, object> _transmit;
public Messenger(string messageType, Action<string, object> transmit)
{
_resolver = FrameworkReferenceResolver.Default;
_transmit = transmit;
MessageType = messageType;

View file

@ -7,24 +7,24 @@ using Microsoft.DotNet.ProjectModel.Server.Models;
namespace Microsoft.DotNet.ProjectModel.Server.Messengers
{
internal class ProjectDiagnosticsMessenger : Messenger<Snapshot>
internal class ProjectDiagnosticsMessenger : Messenger<ProjectSnapshot>
{
public ProjectDiagnosticsMessenger(Action<string, object> 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 &&
Enumerable.SequenceEqual(local.ProjectDiagnostics, remote.ProjectDiagnostics);
}
protected override object CreatePayload(Snapshot local)
protected override object CreatePayload(ProjectSnapshot local)
{
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;
}

View file

@ -4,18 +4,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.DotNet.ProjectModel.Resolution;
using Microsoft.DotNet.ProjectModel.Server.Models;
namespace Microsoft.DotNet.ProjectModel.Server.Messengers
{
internal class ProjectInformationMessenger : Messenger<Snapshot>
internal class ProjectInformationMessenger : Messenger<ProjectSnapshot>
{
public ProjectInformationMessenger(Action<string, object> 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 &&
string.Equals(local.Project.Name, remote.Project.Name) &&
@ -27,30 +26,29 @@ namespace Microsoft.DotNet.ProjectModel.Server.Messengers
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.GlobalJsonPath = local.GlobalJsonPath;
remote.ProjectSearchPaths = local.ProjectSearchPaths;
}
private class ProjectInformation
private class ProjectInformationMessage
{
public ProjectInformation(Project project,
string gloablJsonPath,
IEnumerable<string> projectSearchPath,
FrameworkReferenceResolver resolver)
public ProjectInformationMessage(Project project,
string gloablJsonPath,
IReadOnlyList<string> projectSearchPaths)
{
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();
Commands = project.Commands;
ProjectSearchPaths = new List<string>(projectSearchPath);
ProjectSearchPaths = projectSearchPaths;
GlobalJsonPath = gloablJsonPath;
}

View file

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

View file

@ -4,39 +4,38 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.DotNet.ProjectModel.Server.InternalModels;
using Microsoft.DotNet.ProjectModel.Server.Models;
namespace Microsoft.DotNet.ProjectModel.Server.Messengers
{
internal class SourcesMessenger : Messenger<ProjectSnapshot>
internal class SourcesMessenger : Messenger<ProjectContextSnapshot>
{
public SourcesMessenger(Action<string, object> 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 &&
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,
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;
}
private class SourcesMessagePayload
private class SourcesMessage
{
public FrameworkData Framework { get; set; }
public IReadOnlyList<string> Files { get; set; }

View file

@ -11,28 +11,6 @@ namespace Microsoft.DotNet.ProjectModel.Server.Models
{
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 DisplayName { get; private set; }
@ -73,6 +51,28 @@ namespace Microsoft.DotNet.ProjectModel.Server.Models
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)
{
var name = library.Identity.Name;

View file

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

View file

@ -7,6 +7,24 @@ namespace Microsoft.DotNet.ProjectModel.Server.Models
{
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)
{
var targetFrameworkInformation = description.TargetFrameworkInfo;
@ -29,23 +47,5 @@ namespace Microsoft.DotNet.ProjectModel.Server.Models
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.Sockets;
using Microsoft.Dnx.Runtime.Common.CommandLine;
using Microsoft.DotNet.ProjectModel.Resolution;
using Microsoft.Extensions.Logging;
namespace Microsoft.DotNet.ProjectModel.Server
{
public class Program
{
private readonly Dictionary<int, ProjectContextManager> _projectContextManagers;
private readonly Dictionary<int, ProjectManager> _projects;
private readonly WorkspaceContext _workspaceContext;
private readonly ProtocolManager _protocolManager;
private readonly ILoggerFactory _loggerFactory;
@ -21,14 +20,14 @@ namespace Microsoft.DotNet.ProjectModel.Server
private readonly int _port;
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;
_loggerFactory = loggerFactory;
_protocolManager = new ProtocolManager(maxVersion: 4, loggerFactory: _loggerFactory);
_workspaceContext = WorkspaceContext.Create();
_projectContextManagers = new Dictionary<int, ProjectContextManager>();
_projects = new Dictionary<int, ProjectManager>();
}
public static int Main(string[] args)
@ -41,8 +40,8 @@ namespace Microsoft.DotNet.ProjectModel.Server
app.HelpOption("-?|-h|--help");
var verbose = app.Option("--verbose", "Verbose ouput", CommandOptionType.NoValue);
var hostpid = app.Option("--hostPid", "The process id of the host", CommandOptionType.SingleValue);
var hostname = app.Option("--hostName", "The name of the host", CommandOptionType.SingleValue);
var hostpid = app.Option("--host-pid", "The process id 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);
app.OnExecute(() =>
@ -82,7 +81,6 @@ namespace Microsoft.DotNet.ProjectModel.Server
{
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.Bind(new IPEndPoint(IPAddress.Loopback, _port));
_listenSocket.Listen(10);
@ -99,7 +97,7 @@ namespace Microsoft.DotNet.ProjectModel.Server
_hostName,
_protocolManager,
_workspaceContext,
_projectContextManagers,
_projects,
_loggerFactory);
connection.QueueStart();

View file

@ -6,25 +6,21 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using Microsoft.DotNet.ProjectModel.Resolution;
using Microsoft.DotNet.ProjectModel.Server.Helpers;
using Microsoft.DotNet.ProjectModel.Server.InternalModels;
using Microsoft.DotNet.ProjectModel.Server.Messengers;
using Microsoft.DotNet.ProjectModel.Server.Models;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json.Linq;
using NuGet.Frameworks;
namespace Microsoft.DotNet.ProjectModel.Server
{
internal class ProjectContextManager
internal class ProjectManager
{
private readonly ILogger _log;
private readonly object _processingLock = new object();
private readonly Queue<Message> _inbox = new Queue<Message>();
private readonly ProtocolManager _protocolManager;
private readonly List<ConnectionContext> _waitingForDiagnostics = new List<ConnectionContext>();
private ConnectionContext _initializedContext;
@ -34,29 +30,29 @@ namespace Microsoft.DotNet.ProjectModel.Server
private readonly Trigger<int> _refreshDependencies = new Trigger<int>();
private readonly Trigger<int> _filesChanged = new Trigger<int>();
private Snapshot _local = new Snapshot();
private Snapshot _remote = new Snapshot();
private ProjectSnapshot _local = new ProjectSnapshot();
private ProjectSnapshot _remote = new ProjectSnapshot();
private readonly WorkspaceContext _workspaceContext;
private int? _contextProtocolVersion;
private readonly List<Messenger<ProjectSnapshot>> _messengers;
private readonly List<Messenger<ProjectContextSnapshot>> _messengers;
private ProjectDiagnosticsMessenger _projectDiagnosticsMessenger;
private GlobalErrorMessenger _globalErrorMessenger;
private ProjectInformationMessenger _projectInforamtionMessenger;
public ProjectContextManager(int contextId,
public ProjectManager(int contextId,
ILoggerFactory loggerFactory,
WorkspaceContext workspaceContext,
ProtocolManager protocolManager)
{
Id = contextId;
_log = loggerFactory.CreateLogger<ProjectContextManager>();
_log = loggerFactory.CreateLogger<ProjectManager>();
_workspaceContext = workspaceContext;
_protocolManager = protocolManager;
_messengers = new List<Messenger<ProjectSnapshot>>
_messengers = new List<Messenger<ProjectContextSnapshot>>
{
new DependencyDiagnosticsMessenger(Transmit),
new DependenciesMessenger(Transmit),
@ -66,7 +62,7 @@ namespace Microsoft.DotNet.ProjectModel.Server
};
_projectDiagnosticsMessenger = new ProjectDiagnosticsMessenger(Transmit);
_globalErrorMessenger = new GlobalErrorMessenger(TransmitDiagnostics);
_globalErrorMessenger = new GlobalErrorMessenger(Transmit);
_projectInforamtionMessenger = new ProjectInformationMessenger(Transmit);
}
@ -96,7 +92,7 @@ namespace Microsoft.DotNet.ProjectModel.Server
_inbox.Enqueue(message);
}
ThreadPool.QueueUserWorkItem(state => ((ProjectContextManager)state).ProcessLoop(), this);
ThreadPool.QueueUserWorkItem(state => ((ProjectManager)state).ProcessLoop(), this);
}
private void Transmit(string messageType, object payload)
@ -105,17 +101,6 @@ namespace Microsoft.DotNet.ProjectModel.Server
_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()
{
if (!Monitor.TryEnter(_processingLock))
@ -158,13 +143,6 @@ namespace Microsoft.DotNet.ProjectModel.Server
_initializedContext.Transmit(message);
_remote.GlobalErrorMessage = error;
foreach (var connection in _waitingForDiagnostics)
{
connection.Transmit(message);
}
_waitingForDiagnostics.Clear();
}
}
@ -173,12 +151,9 @@ namespace Microsoft.DotNet.ProjectModel.Server
while (true)
{
DrainInbox();
var allDiagnostics = new List<DiagnosticMessageGroup>();
UpdateProjectStates();
SendOutgingMessages(allDiagnostics);
SendDiagnostics(allDiagnostics);
UpdateProject();
SendOutgingMessages();
lock (_inbox)
{
@ -232,9 +207,6 @@ namespace Microsoft.DotNet.ProjectModel.Server
case MessageTypes.FilesChanged:
_filesChanged.Value = 0;
break;
case MessageTypes.GetDiagnostics:
_waitingForDiagnostics.Add(message.Sender);
break;
}
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)
{
@ -271,71 +243,41 @@ namespace Microsoft.DotNet.ProjectModel.Server
_filesChanged.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;
}
_local = Snapshot.CreateFromProject(state.Project);
_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;
}
_local = newSnapshot;
return true;
}
private void SendOutgingMessages(List<DiagnosticMessageGroup> diagnostics)
private void SendOutgingMessages()
{
_projectInforamtionMessenger.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);
foreach (var pair in _local.Projects)
{
ProjectSnapshot localProjectSnapshot = pair.Value;
ProjectSnapshot remoteProjectSnapshot;
if (!_remote.Projects.TryGetValue(pair.Key, out remoteProjectSnapshot))
if (!_remote.ProjectContexts.TryGetValue(pair.Key, out remoteProjectSnapshot))
{
remoteProjectSnapshot = new ProjectSnapshot();
_remote.Projects[pair.Key] = remoteProjectSnapshot;
}
if (localProjectSnapshot.DependencyDiagnostics != null)
{
diagnostics.Add(new DiagnosticMessageGroup(
localProjectSnapshot.TargetFramework,
localProjectSnapshot.DependencyDiagnostics));
remoteProjectSnapshot = new ProjectContextSnapshot();
_remote.ProjectContexts[pair.Key] = remoteProjectSnapshot;
}
unprocessedFrameworks.Remove(pair.Key);
foreach(var messenger in _messengers)
foreach (var messenger in _messengers)
{
messenger.UpdateRemote(localProjectSnapshot,
messenger.UpdateRemote(localProjectSnapshot,
remoteProjectSnapshot);
}
}
@ -343,35 +285,10 @@ namespace Microsoft.DotNet.ProjectModel.Server
// Remove all processed frameworks from the remote view
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);
// 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>

View file

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

View file

@ -210,7 +210,7 @@ namespace Microsoft.DotNet.ProjectModel
}
private ProjectContextCollection AddProjectContextEntry(string projectDirectory,
ProjectContextCollection currentEntry)
ProjectContextCollection currentEntry)
{
if (currentEntry == null)
{
@ -241,7 +241,8 @@ namespace Microsoft.DotNet.ProjectModel
currentEntry.ProjectContexts.Add(builder.Build());
}
currentEntry.Project = project;
currentEntry.ProjectFilePath = project.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]
[InlineData("Project", "UnresolvedProjectSample", "EmptyLibrary", "Project")]
[InlineData("Package", "UnresolvedPackageSample", "NoSuchPackage", null)]