Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Separate project-system-tools into a frontend and backend structure #346

Closed
wants to merge 48 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
232e1d9
starting interface with Codespaces
eric62369 Jul 20, 2020
d6b58cd
more changes to initial interface (add Task return types)
eric62369 Jul 20, 2020
20601a9
Add basic documentation and remove unnecessary APIs
eric62369 Jul 21, 2020
13baf9f
Small API changes
eric62369 Jul 24, 2020
fb04787
Placeholder service implementation
eric62369 Jul 24, 2020
3d2b515
Builds currently not tracked, but ready to start introducing new inte…
eric62369 Jul 24, 2020
b483b2c
starting separation for BuildTableDataSource.cs
eric62369 Jul 27, 2020
dea31e8
placeholder connections on UI to Codespaces API
eric62369 Jul 28, 2020
569c223
temporary remove BuildHandle type definition
eric62369 Jul 28, 2020
7cb43b4
temporary remove log providers
eric62369 Jul 28, 2020
62c2786
remove extra file
eric62369 Jul 28, 2020
2ba90f3
Merge branch 'master' into t-eriyoo/codespace-interface
eric62369 Jul 28, 2020
3bc45a7
address messages in visual studio
eric62369 Jul 28, 2020
a078cdf
Remove most commented out code
eric62369 Jul 28, 2020
6fa8c08
fix unused expression warnings
eric62369 Jul 28, 2020
6e0a162
basic construction for buildloggingservice
eric62369 Jul 28, 2020
dcb7eab
Interface changes and introducing UI async interface
eric62369 Jul 29, 2020
1401c40
Testing async changes
eric62369 Jul 29, 2020
bd2478c
Adding async to basic UI to API connections
eric62369 Jul 29, 2020
12c9c0e
temporarily remove async code, separate log file level code
eric62369 Jul 30, 2020
e98cacf
Current progress on splitting Builds into a client and server side
eric62369 Jul 30, 2020
0f66003
Testing end to end local retrieve all builds
eric62369 Jul 30, 2020
1d61442
temporary log file transfer (local only), context menu commands seem …
eric62369 Jul 30, 2020
451b150
Temporary callback to implement the notifyChange method accross serve…
eric62369 Jul 31, 2020
ef1613f
Support Roslyn Logging now passed from server side
eric62369 Jul 31, 2020
4d41b88
remove unnecessary TODO comments
eric62369 Jul 31, 2020
5d1290f
Created IBuildSummary interface
eric62369 Jul 31, 2020
8dc9d8d
Merge branch 'master' into t-eriyoo/codespace-interface
eric62369 Jul 31, 2020
0774a22
update namespaces for modified code
eric62369 Jul 31, 2020
fd5d9a7
update using statements to use new namespaces
eric62369 Jul 31, 2020
6ec205e
Removing outdated comments and remove extra whitespace
eric62369 Jul 31, 2020
e4a3c7b
Fix documentation comment on IBuildLoggerService.cs
eric62369 Jul 31, 2020
2eeb38f
renaming classes and namespaces
eric62369 Aug 1, 2020
c6a31d4
Address more PR comments
eric62369 Aug 1, 2020
a17a850
More PR comments addressed, new SDK workaround added
eric62369 Aug 3, 2020
82145b4
Add in UI side NotifyChange to update the UI
eric62369 Aug 3, 2020
ed43497
Now using interlocked increment
eric62369 Aug 3, 2020
b94450f
Change SharedBuildID to SharedBuildId
eric62369 Aug 3, 2020
ae9a0b1
Cleaning up unnecessary comments
eric62369 Aug 3, 2020
a14924b
fix build errors
eric62369 Aug 3, 2020
3247514
IBuildSummary removed
eric62369 Aug 3, 2020
d84a0b8
Reworking how BuildSummary types work
eric62369 Aug 3, 2020
d490290
Simplifying UIBuildSummary
eric62369 Aug 4, 2020
52e0b06
Edits to Build Summary and interface structure
eric62369 Aug 4, 2020
49c952e
rename backend frontend namespaces
eric62369 Aug 4, 2020
6a3646a
move namespaces around for BuildSummary related types
eric62369 Aug 4, 2020
92addef
Remove unnecessary using statements, and add documentation comments t…
eric62369 Aug 4, 2020
a63f26e
Renaming Frontend to FrontEnd
eric62369 Aug 4, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,7 @@
<CheckForOverflowUnderflow>false</CheckForOverflowUnderflow>
<VSSDKTargetPlatformRegRootSuffix Condition="'$(RootSuffix)' != ''">$(RootSuffix)</VSSDKTargetPlatformRegRootSuffix>
<VSSDKTargetPlatformRegRootSuffix Condition="'$(VSSDKTargetPlatformRegRootSuffix)' == ''">Exp</VSSDKTargetPlatformRegRootSuffix>
<!-- Workaround: https://github.com/dotnet/sdk/issues/12739 -->
<ImportFrameworkWinFXTargets>true</ImportFrameworkWinFXTargets>
</PropertyGroup>
</Project>
12 changes: 6 additions & 6 deletions src/LogProviders/BuildLoggerProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@ namespace Microsoft.VisualStudio.ProjectSystem.Tools.Providers
[Export(typeof(IVsBuildLoggerProvider))]
internal sealed class BuildLoggerProvider : IBuildLoggerProviderAsync, IVsBuildLoggerProvider
{
private readonly IBuildTableDataSource _dataSource;
private readonly ILoggingController _loggingController;

[ImportingConstructor]
public BuildLoggerProvider(IBuildTableDataSource dataSource)
public BuildLoggerProvider(ILoggingController loggingController)
{
_dataSource = dataSource;
_loggingController = loggingController;
}

public LoggerVerbosity Verbosity => LoggerVerbosity.Diagnostic;
Expand All @@ -47,18 +47,18 @@ public BuildLoggerProvider(IBuildTableDataSource dataSource)
BuildLoggerEvents.CustomEvent;

public ILogger GetLogger(string projectPath, IEnumerable<string> targets, IDictionary<string, string> properties, bool isDesignTimeBuild) =>
_dataSource.IsLogging ? _dataSource.CreateLogger(isDesignTimeBuild) : null;
_loggingController.IsLogging ? _loggingController.CreateLogger(isDesignTimeBuild) : null;

public Task<IImmutableSet<ILogger>> GetLoggersAsync(IReadOnlyList<string> targets, IImmutableDictionary<string, string> properties, CancellationToken cancellationToken)
{
var loggers = (IImmutableSet<ILogger>)ImmutableHashSet<ILogger>.Empty;

if (_dataSource.IsLogging)
if (_loggingController.IsLogging)
{
var isDesignTime = properties.TryGetValue("DesignTimeBuild", out var value) &&
string.Equals(value, "true", StringComparison.OrdinalIgnoreCase);

loggers = loggers.Add(_dataSource.CreateLogger(isDesignTime));
loggers = loggers.Add(_loggingController.CreateLogger(isDesignTime));
}

return Task.FromResult(loggers);
Expand Down
22 changes: 0 additions & 22 deletions src/LogProviders/IBuildTableDataSource.cs

This file was deleted.

22 changes: 22 additions & 0 deletions src/LogProviders/ILoggingController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using Microsoft.Build.Framework;

namespace Microsoft.VisualStudio.ProjectSystem.Tools.Providers
{
public interface ILoggingController
{
/// <summary>
/// Is this logging controller currently collecting logs?
/// true if yes, false if no.
/// </summary>
bool IsLogging { get; }

/// <summary>
/// Creates a new logger to collect builds and their logs
/// </summary>
/// <param name="isDesignTime">Is this for DesignTime build logging?</param>
/// <returns>Return newly created logger</returns>
ILogger CreateLogger(bool isDesignTime);
}
}
20 changes: 12 additions & 8 deletions src/ProjectSystemTools/BuildLogging/BuildLoggingToolWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
using Microsoft.VisualStudio.OLE.Interop;
using Microsoft.VisualStudio.PlatformUI;
using Microsoft.VisualStudio.ProjectSystem.Tools.BuildLogging.Model;
using Microsoft.VisualStudio.ProjectSystem.Tools.Providers;
using Microsoft.VisualStudio.ProjectSystem.Tools.BuildLogging.Model.FrontEnd;
using Microsoft.VisualStudio.ProjectSystem.Tools.TableControl;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.Shell.TableControl;
Expand All @@ -27,7 +27,7 @@ internal sealed class BuildLoggingToolWindow : TableToolWindow
public const string BuildLogging = "BuildLogging";
public const string BuildLoggingToolWindowGuidString = "391238ea-dad7-488c-94d1-e2b6b5172bf3";

private readonly IBuildTableDataSource _dataSource;
private readonly IFrontEndBuildTableDataSource _dataSource;
private readonly IVsUIShellOpenDocument _openDocument;

private BuildType _filterType = BuildType.All;
Expand All @@ -43,7 +43,7 @@ internal sealed class BuildLoggingToolWindow : TableToolWindow
public BuildLoggingToolWindow()
{
var componentModel = (IComponentModel)GetService(typeof(SComponentModel));
_dataSource = componentModel.GetService<IBuildTableDataSource>();
_dataSource = componentModel.GetService<IFrontEndBuildTableDataSource>();

_openDocument = (IVsUIShellOpenDocument)GetService(typeof(SVsUIShellOpenDocument));

Expand Down Expand Up @@ -194,11 +194,12 @@ private void SaveLogs()

foreach (var entry in TableControl.SelectedEntries)
{
if (!entry.TryGetValue(TableKeyNames.LogPath, out string logPath))
if (!entry.TryGetValue(TableKeyNames.BuildID, out int buildID))
{
continue;
}

string logPath = _dataSource.GetLogForBuild(buildID);
var filename = Path.GetFileName(logPath);

if (filename == null)
Expand Down Expand Up @@ -246,12 +247,13 @@ private void OpenLogs()

public void OpenLog(ITableEntryHandle tableEntry)
{
if (!tableEntry.TryGetValue(TableKeyNames.LogPath, out string logPath))
if (!tableEntry.TryGetValue(TableKeyNames.BuildID, out int buildID))
{
return;
}

var guid = VSConstants.LOGVIEWID_Primary;
string logPath = _dataSource.GetLogForBuild(buildID);
_openDocument.OpenDocumentViaProject(logPath, ref guid, out _, out _, out _, out var frame);
frame?.Show();
}
Expand All @@ -260,11 +262,12 @@ private void OpenLogsExternal()
{
foreach (var entry in TableControl.SelectedEntries)
{
if (!entry.TryGetValue(TableKeyNames.LogPath, out string logPath))
if (!entry.TryGetValue(TableKeyNames.BuildID, out int buildID))
{
continue;
}

string logPath = _dataSource.GetLogForBuild(buildID);
try
{
Process.Start(logPath);
Expand Down Expand Up @@ -301,7 +304,6 @@ protected override int InnerQueryStatus(ref Guid commandGroupGuid, uint commandC
var enabled = false;
var visible = false;
var latched = false;

switch (cmd.cmdID)
{
case ProjectSystemToolsPackage.StartLoggingCommandId:
Expand Down Expand Up @@ -350,7 +352,7 @@ protected override int InnerQueryStatus(ref Guid commandGroupGuid, uint commandC
}

private string[] GetBuildFilterComboItems() =>
(_dataSource as BuildTableDataSource)?.SupportRoslynLogging ?? false
(_dataSource as FrontEndBuildTableDataSource)?.SupportRoslynLogging ?? false
? new[]
{
BuildLoggingResources.FilterBuildAll, BuildLoggingResources.FilterBuildEvaluations,
Expand Down Expand Up @@ -380,10 +382,12 @@ protected override int InnerExec(ref Guid commandGroupGuid, uint commandId, uint
{
case ProjectSystemToolsPackage.StartLoggingCommandId:
_dataSource.Start();

break;

case ProjectSystemToolsPackage.StopLoggingCommandId:
_dataSource.Stop();

break;

case ProjectSystemToolsPackage.ClearCommandId:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Collections.Immutable;
using System.ComponentModel.Composition;
using System.Linq;
using Microsoft.Build.Evaluation;
using Microsoft.Build.Framework;
using Microsoft.VisualStudio.ProjectSystem.Tools.Providers;

namespace Microsoft.VisualStudio.ProjectSystem.Tools.BuildLogging.Model.BackEnd
{
[Export(typeof(ILoggingController))]
[Export(typeof(ILoggingDataSource))]
internal sealed class BackEndBuildTableDataSource : ILoggingController, ILoggingDataSource
{
private const string BuildDataSourceDisplayName = "Build Data Source";
private const string BuildTableDataSourceIdentifier = nameof(BuildTableDataSourceIdentifier);
private const string BuildTableDataSourceSourceTypeIdentifier = nameof(BuildTableDataSourceSourceTypeIdentifier);

private readonly EvaluationLogger _evaluationLogger;
private readonly RoslynLogger _roslynLogger;

private ImmutableList<Build> _entries = ImmutableList<Build>.Empty;

public string SourceTypeIdentifier => BuildTableDataSourceSourceTypeIdentifier;

public string Identifier => BuildTableDataSourceIdentifier;

public string DisplayName => BuildDataSourceDisplayName;

public bool SupportRoslynLogging => _roslynLogger.Supported;

public bool IsLogging { get; private set; }

public bool SupportsRoslynLogging => _roslynLogger.Supported;

private Action NotifyUI { get; set; }

public BackEndBuildTableDataSource()
{
_evaluationLogger = new EvaluationLogger(this);
_roslynLogger = new RoslynLogger(this);
}

public void Start(Action notifyCallback)
{
NotifyUI = notifyCallback;

IsLogging = true;
ProjectCollection.GlobalProjectCollection.RegisterLogger(_evaluationLogger);
_roslynLogger.Start();
}

public void Stop()
{
NotifyUI = null;

IsLogging = false;
ProjectCollection.GlobalProjectCollection.UnregisterAllLoggers();
_roslynLogger.Stop();
}

public void Clear()
{
foreach (var build in _entries)
{
build.Dispose();
}
_entries = ImmutableList<Build>.Empty;
}

public ILogger CreateLogger(bool isDesignTime) => new ProjectLogger(this, isDesignTime);

/// <summary>
/// return log path on server for a given build
/// If buildID cannot be found, will return null
/// </summary>
/// <param name="buildID">ID to return build for</param>
/// <returns> returns filepath to log path (on server)</returns>
public string GetLogForBuild(int buildID)
{
return _entries.Find(x => x.BuildId == buildID).LogPath;
}

ImmutableList<BuildSummary> ILoggingDataSource.GetAllBuilds()
{
return _entries.Select(build => build.BuildSummary).ToImmutableList();
}

public void NotifyChange()
{
NotifyUI?.Invoke();
}

public void AddEntry(Build build)
{
_entries = _entries.Add(build);
NotifyChange();
}
}
}
76 changes: 76 additions & 0 deletions src/ProjectSystemTools/BuildLogging/Model/Backend/Build.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
using System.Threading;

namespace Microsoft.VisualStudio.ProjectSystem.Tools.BuildLogging.Model.BackEnd
{
/// <summary>
/// Represents a build collected by the loggers
/// Deals with data needed by the client as well as data related to log files
/// and the file system on the server.
///
/// Build should only be used on the server side,
/// where BuildSummary type (a subset of this type)
/// can be sent to the client side
/// </summary>
internal sealed class Build : IDisposable
{
public BuildSummary BuildSummary { get; set; }
public string ProjectPath { get; }
public string LogPath { get; private set; }
public int BuildId => BuildSummary.BuildId;
public BuildType BuildType => BuildSummary.BuildType;
public ImmutableArray<string> Dimensions => BuildSummary.Dimensions;
public ImmutableArray<string> Targets => BuildSummary.Targets;
public DateTime StartTime => BuildSummary.StartTime;
public TimeSpan Elapsed => BuildSummary.Elapsed;
public BuildStatus Status => BuildSummary.Status;
public string ProjectName => BuildSummary.ProjectName;
private static int SharedBuildId;
public Build(string projectPath, IEnumerable<string> dimensions, IEnumerable<string> targets, BuildType buildType, DateTime startTime)
{
int nextId = Interlocked.Increment(ref SharedBuildId);
BuildSummary = new BuildSummary(nextId, projectPath, dimensions, targets, buildType, startTime);
}

public void Finish(bool succeeded, DateTime time)
{
if (Status != BuildStatus.Running)
{
throw new InvalidOperationException();
}

BuildStatus newStatus = succeeded ? BuildStatus.Finished : BuildStatus.Failed;
var elapsedTime = time - StartTime;
BuildSummary = new BuildSummary(BuildSummary, newStatus, elapsedTime);
}

public void SetLogPath(string logPath)
{
LogPath = logPath;
}

public void Dispose()
{
if (LogPath == null)
{
return;
}

var logPath = LogPath;
LogPath = null;
try
{
File.Delete(logPath);
}
catch
{
// If it fails, it fails...
}
}
}
}
Loading