From 00d158ef1a138a43db1a79f994d331027e0eeae8 Mon Sep 17 00:00:00 2001 From: StefanKert Date: Sun, 23 Dec 2018 13:57:41 +0100 Subject: [PATCH 001/100] Starting development for 3.0.0 --- version.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.json b/version.json index 287468c3..0d623d7a 100644 --- a/version.json +++ b/version.json @@ -1,6 +1,6 @@ { "$schema": "https://raw.githubusercontent.com/AArnott/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", - "version": "2.2.0-preview-1.{height}", + "version": "3.0.0-preview-1.{height}", "publicReleaseRefSpec": [ "^refs/heads/master$", "^refs/tags/v\\d+\\.\\d+\\.\\d+" From 7b68ef60ad5177881b3f013c873d78c7249c5cfc Mon Sep 17 00:00:00 2001 From: StefanKert Date: Sun, 23 Dec 2018 13:57:56 +0100 Subject: [PATCH 002/100] Dropping support for vs2013 --- src/BuildVision/source.extension.vsixmanifest | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/BuildVision/source.extension.vsixmanifest b/src/BuildVision/source.extension.vsixmanifest index 6dcfcbc8..4e624fd4 100644 --- a/src/BuildVision/source.extension.vsixmanifest +++ b/src/BuildVision/source.extension.vsixmanifest @@ -11,12 +11,12 @@ Resources\PreviewImage.png - - - + + + - + From 55c7f2d3197035b1189aba8d68de8d1629ebc80f Mon Sep 17 00:00:00 2001 From: StefanKert Date: Sun, 23 Dec 2018 13:58:29 +0100 Subject: [PATCH 003/100] Removing third party nuget packages and replace with Microsoft packages --- src/BuildVision.UI/BuildVision.UI.csproj | 7 +- .../Resources/BuildState.Resources.xaml | 4 +- .../Resources/CommonResources.xaml | 4 +- .../Resources/ValueIndicator.Resources.xaml | 2 +- src/BuildVision.UI/Styles/ExtensionStyle.xaml | 4 +- .../Styles/ScrollViewerStyle.xaml | 4 +- src/BuildVision/BuildVision.csproj | 98 ++++--------------- src/BuildVision/Helpers/ProjectExtensions.cs | 11 ++- .../Helpers/SolutionProjectsExtensions.cs | 14 ++- .../PackageTests.cs | 78 +++++++-------- 10 files changed, 87 insertions(+), 139 deletions(-) diff --git a/src/BuildVision.UI/BuildVision.UI.csproj b/src/BuildVision.UI/BuildVision.UI.csproj index de0f3ae3..5cf92708 100644 --- a/src/BuildVision.UI/BuildVision.UI.csproj +++ b/src/BuildVision.UI/BuildVision.UI.csproj @@ -362,11 +362,8 @@ - - 12.0.4 - - - 12.0.4 + + 14.3.25407 diff --git a/src/BuildVision.UI/Resources/BuildState.Resources.xaml b/src/BuildVision.UI/Resources/BuildState.Resources.xaml index 797363c8..d68cf636 100644 --- a/src/BuildVision.UI/Resources/BuildState.Resources.xaml +++ b/src/BuildVision.UI/Resources/BuildState.Resources.xaml @@ -1,6 +1,6 @@  + xmlns:vsfx="clr-namespace:Microsoft.VisualStudio.Shell;assembly=Microsoft.VisualStudio.Shell.14.0"> @@ -74,4 +74,4 @@ - \ No newline at end of file + diff --git a/src/BuildVision.UI/Resources/CommonResources.xaml b/src/BuildVision.UI/Resources/CommonResources.xaml index 1a63dec2..e9c29ba0 100644 --- a/src/BuildVision.UI/Resources/CommonResources.xaml +++ b/src/BuildVision.UI/Resources/CommonResources.xaml @@ -1,6 +1,6 @@  + xmlns:vsfx="clr-namespace:Microsoft.VisualStudio.Shell;assembly=Microsoft.VisualStudio.Shell.14.0"> - \ No newline at end of file + diff --git a/src/BuildVision.UI/Resources/ValueIndicator.Resources.xaml b/src/BuildVision.UI/Resources/ValueIndicator.Resources.xaml index 5ac0f110..1a90fdbf 100644 --- a/src/BuildVision.UI/Resources/ValueIndicator.Resources.xaml +++ b/src/BuildVision.UI/Resources/ValueIndicator.Resources.xaml @@ -1,6 +1,6 @@  + xmlns:vsfx="clr-namespace:Microsoft.VisualStudio.Shell;assembly=Microsoft.VisualStudio.Shell.14.0"> diff --git a/src/BuildVision.UI/Styles/ExtensionStyle.xaml b/src/BuildVision.UI/Styles/ExtensionStyle.xaml index b5ec6f2d..dcbec3ba 100644 --- a/src/BuildVision.UI/Styles/ExtensionStyle.xaml +++ b/src/BuildVision.UI/Styles/ExtensionStyle.xaml @@ -1,6 +1,6 @@  + xmlns:environment="clr-namespace:Microsoft.VisualStudio.PlatformUI;assembly=Microsoft.VisualStudio.Shell.14.0"> @@ -23,4 +23,4 @@ - \ No newline at end of file + diff --git a/src/BuildVision.UI/Styles/ScrollViewerStyle.xaml b/src/BuildVision.UI/Styles/ScrollViewerStyle.xaml index d989460d..de31d19b 100644 --- a/src/BuildVision.UI/Styles/ScrollViewerStyle.xaml +++ b/src/BuildVision.UI/Styles/ScrollViewerStyle.xaml @@ -1,6 +1,6 @@  @@ -236,4 +236,4 @@ - \ No newline at end of file + diff --git a/src/BuildVision/BuildVision.csproj b/src/BuildVision/BuildVision.csproj index 91770805..54253341 100644 --- a/src/BuildVision/BuildVision.csproj +++ b/src/BuildVision/BuildVision.csproj @@ -60,28 +60,12 @@ False - - False - - - False - - - False - - - True - - - True - - @@ -105,17 +89,6 @@ - - - {00020430-0000-0000-C000-000000000046} - 2 - 0 - 0 - primary - False - False - - @@ -229,65 +202,34 @@ - - 7.0.4 - - - 12.0.4 - - - 7.0.4 - - - 10.0.4 - - - 11.0.4 - - - 12.0.4 - - - 8.0.4 - - - 9.0.4 - - - 7.0.4 - - - 12.0.4 - - - 10.0.4 - - - 11.0.4 + + 8.0.2 - - 12.0.4 + + 10.0.3 - - 7.0.4 + + 8.0.3 - - 8.0.4 + + 9.0.3 - - 9.0.4 + + 9.0.3 - - 7.0.4 + + 14.3.25407 - - 8.0.4 + + 12.0.30111 - - 12.0.4 + + 15.9.3032 + runtime; build; native; contentfiles; analyzers + all - - 12.0.4 + + 7.0.3303 diff --git a/src/BuildVision/Helpers/ProjectExtensions.cs b/src/BuildVision/Helpers/ProjectExtensions.cs index 45904238..16df3532 100644 --- a/src/BuildVision/Helpers/ProjectExtensions.cs +++ b/src/BuildVision/Helpers/ProjectExtensions.cs @@ -18,6 +18,11 @@ namespace BuildVision.Helpers { + public class EnvDTECodeModelLanguageConstants2 + { + public const string CMLanguageJSharp = "{E6FDF8BF-F3D1-11D4-8576-0002A516ECE8}"; + } + public static class ProjectExtensions { private static readonly HashSet _hiddenProjectsUniqueNames = new HashSet @@ -84,7 +89,7 @@ public static class ProjectExtensions { CodeModelLanguageConstants.vsCMLanguageMC, "MC++" }, // Managed C++ { CodeModelLanguageConstants.vsCMLanguageVB, "VB.NET" }, { CodeModelLanguageConstants.vsCMLanguageVC, "VC++" }, // Visual C++ - { CodeModelLanguageConstants2.vsCMLanguageJSharp, "J#" }, + { EnvDTECodeModelLanguageConstants2.CMLanguageJSharp, "J#" }, { "{F2A71F9B-5D33-465A-A702-920D77279786}", "F#" }, }; @@ -608,7 +613,7 @@ public static Project GetSubProject(this Project solutionFolder, Func GetSubProjects(this Project solutionFolder) continue; // If this is another solution folder, do a recursive call, otherwise add - if (subProject.Kind == ProjectKinds.vsProjectKindSolutionFolder) + if (subProject.Kind == EnvDTEProjectKinds.ProjectKindSolutionFolder) list.AddRange(GetSubProjects(subProject)); else if (!subProject.IsHidden()) list.Add(subProject); diff --git a/src/BuildVision/Helpers/SolutionProjectsExtensions.cs b/src/BuildVision/Helpers/SolutionProjectsExtensions.cs index 1957cfdf..de225fd7 100644 --- a/src/BuildVision/Helpers/SolutionProjectsExtensions.cs +++ b/src/BuildVision/Helpers/SolutionProjectsExtensions.cs @@ -1,13 +1,17 @@ using System; using System.Collections.Generic; - using EnvDTE; -using EnvDTE80; using IServiceProvider = Microsoft.VisualStudio.OLE.Interop.IServiceProvider; using System.Runtime.InteropServices; +using EnvDTE80; namespace BuildVision.Helpers { + public class EnvDTEProjectKinds + { + public const string ProjectKindSolutionFolder = "{66A26720-8FB5-11D2-AA7E-00C04F688DDE}"; + } + public static class SolutionProjectsExtensions { public static IList GetProjects(this Solution solution) @@ -19,7 +23,7 @@ public static IList GetProjects(this Solution solution) if (project == null) continue; - if (project.Kind == ProjectKinds.vsProjectKindSolutionFolder) + if (project.Kind == EnvDTEProjectKinds.ProjectKindSolutionFolder) list.AddRange(project.GetSubProjects()); else if (!project.IsHidden()) list.Add(project); @@ -37,7 +41,7 @@ public static Project GetProject(this Solution solution, Func con if (project == null) continue; - if (project.Kind == ProjectKinds.vsProjectKindSolutionFolder) + if (project.Kind == EnvDTEProjectKinds.ProjectKindSolutionFolder) { Project sub = project.GetSubProject(cond); if (sub != null) @@ -76,4 +80,4 @@ public static object GetService(object serviceProviderObject, Type type) return service; } } -} \ No newline at end of file +} diff --git a/test/BuildVision.IntegrationTests/PackageTests.cs b/test/BuildVision.IntegrationTests/PackageTests.cs index 04eaaa2d..3f590412 100644 --- a/test/BuildVision.IntegrationTests/PackageTests.cs +++ b/test/BuildVision.IntegrationTests/PackageTests.cs @@ -1,7 +1,7 @@ using System; using Microsoft.VisualStudio.Shell.Interop; using Microsoft.VisualStudio.TestTools.UnitTesting; -using Microsoft.VSSDK.Tools.VsIdeTesting; +//using Microsoft.VSSDK.Tools.VsIdeTesting; using System.ComponentModel.Design; using EnvDTE; using Microsoft.VisualStudio; @@ -12,47 +12,47 @@ namespace BuildVision.IntegrationTests [TestClass] public class PackageTests { - private static IVsShell ShellService => VsIdeTestHostContext.ServiceProvider.GetService(typeof(SVsShell)) as IVsShell; - private static IVsUIShell UiShellService => VsIdeTestHostContext.ServiceProvider.GetService(typeof(SVsUIShell)) as IVsUIShell; + //private static IVsShell ShellService => VsIdeTestHostContext.ServiceProvider.GetService(typeof(SVsShell)) as IVsShell; + //private static IVsUIShell UiShellService => VsIdeTestHostContext.ServiceProvider.GetService(typeof(SVsUIShell)) as IVsUIShell; - [Ignore] - [TestMethod] - [HostType("VS IDE")] - public void PackageLoad_Should_Succeed() - { - UIThreadInvoker.Invoke(new Action(() => - { - var guid = PackageGuids.GuidBuildVisionPackage; - Assert.IsTrue(0 == ShellService.LoadPackage(ref guid, out var package)); - Assert.IsNotNull(package, "Package failed to load"); - })); - } + //[Ignore] + //[TestMethod] + //[HostType("VS IDE")] + //public void PackageLoad_Should_Succeed() + //{ + // UIThreadInvoker.Invoke(new Action(() => + // { + // var guid = PackageGuids.GuidBuildVisionPackage; + // Assert.IsTrue(0 == ShellService.LoadPackage(ref guid, out var package)); + // Assert.IsNotNull(package, "Package failed to load"); + // })); + //} - [Ignore] - [TestMethod] - [HostType("VS IDE")] - public void ClickOnBuildVisionMenuItem_Should_ShowBuildVision() - { - UIThreadInvoker.Invoke(new Action(() => - { - var toolwndCommandId = new CommandID(PackageGuids.GuidBuildVisionCmdSet, (int) PackageIds.CmdIdBuildVisionToolWindow); - ExecuteCommand(toolwndCommandId); - Assert.IsTrue(CanFindToolwindow(PackageGuids.GuidBuildVisionToolWindow)); - })); - } + //[Ignore] + //[TestMethod] + //[HostType("VS IDE")] + //public void ClickOnBuildVisionMenuItem_Should_ShowBuildVision() + //{ + // UIThreadInvoker.Invoke(new Action(() => + // { + // var toolwndCommandId = new CommandID(PackageGuids.GuidBuildVisionCmdSet, (int) PackageIds.CmdIdBuildVisionToolWindow); + // ExecuteCommand(toolwndCommandId); + // Assert.IsTrue(CanFindToolwindow(PackageGuids.GuidBuildVisionToolWindow)); + // })); + //} - public static void ExecuteCommand(CommandID cmd) - { - object customin = null; - object customout = null; - VsIdeTestHostContext.Dte.Commands.Raise(cmd.Guid.ToString("B").ToUpper(), cmd.ID, ref customin, ref customout); - } + //public static void ExecuteCommand(CommandID cmd) + //{ + // object customin = null; + // object customout = null; + // VsIdeTestHostContext.Dte.Commands.Raise(cmd.Guid.ToString("B").ToUpper(), cmd.ID, ref customin, ref customout); + //} - public static bool CanFindToolwindow(Guid persistenceGuid) - { - var hr = UiShellService.FindToolWindow((uint) __VSFINDTOOLWIN.FTW_fFindFirst, ref persistenceGuid, out var windowFrame); - Assert.IsTrue(hr == VSConstants.S_OK); - return (windowFrame != null); - } + //public static bool CanFindToolwindow(Guid persistenceGuid) + //{ + // //var hr = UiShellService.FindToolWindow((uint) __VSFINDTOOLWIN.FTW_fFindFirst, ref persistenceGuid, out var windowFrame); + // //Assert.IsTrue(hr == VSConstants.S_OK); + // //return (windowFrame != null); + //} } } From 3bb9a5de915aa2ca0e94f91707330fca71ee2800 Mon Sep 17 00:00:00 2001 From: StefanKert Date: Thu, 27 Dec 2018 18:54:41 +0100 Subject: [PATCH 004/100] update to make use of asyncpackage --- .../Contracts/IBuildDistributor.cs | 3 +- src/BuildVision/BuildVision.csproj | 6 +- .../Core/BuildVisionPackage.Package.cs | 98 ---------------- src/BuildVision/Core/BuildVisionPackage.cs | 108 +++++++++++++----- src/BuildVision/Core/IPackageContext.cs | 17 +-- src/BuildVision/Helpers/ToolWindowManager.cs | 9 +- src/BuildVision/Tool/Building/BuildContext.cs | 25 ++-- src/BuildVision/Tool/Tool.cs | 58 +++++----- .../Views/Settings/GridSettingsDialogPage.cs | 9 +- 9 files changed, 139 insertions(+), 194 deletions(-) delete mode 100644 src/BuildVision/Core/BuildVisionPackage.Package.cs diff --git a/src/BuildVision.UI/Contracts/IBuildDistributor.cs b/src/BuildVision.UI/Contracts/IBuildDistributor.cs index e2d7ea6e..832861a2 100644 --- a/src/BuildVision.UI/Contracts/IBuildDistributor.cs +++ b/src/BuildVision.UI/Contracts/IBuildDistributor.cs @@ -1,5 +1,6 @@ using BuildVision.Contracts; using System; +using System.Threading.Tasks; namespace BuildVision.UI.Contracts { @@ -13,6 +14,6 @@ public interface IBuildDistributor event EventHandler OnBuildProjectDone; event EventHandler OnErrorRaised; - void CancelBuild(); + Task CancelBuildAsync(); } } diff --git a/src/BuildVision/BuildVision.csproj b/src/BuildVision/BuildVision.csproj index 54253341..eb2d1262 100644 --- a/src/BuildVision/BuildVision.csproj +++ b/src/BuildVision/BuildVision.csproj @@ -90,7 +90,7 @@ - + @@ -121,7 +121,6 @@ - @@ -223,6 +222,9 @@ 12.0.30111 + + 14.3.26929 + 15.9.3032 runtime; build; native; contentfiles; analyzers diff --git a/src/BuildVision/Core/BuildVisionPackage.Package.cs b/src/BuildVision/Core/BuildVisionPackage.Package.cs deleted file mode 100644 index 84893827..00000000 --- a/src/BuildVision/Core/BuildVisionPackage.Package.cs +++ /dev/null @@ -1,98 +0,0 @@ -using System; -using System.ComponentModel.Design; -using System.Diagnostics; -using System.Runtime.InteropServices; - -using Microsoft.VisualStudio; -using Microsoft.VisualStudio.Shell; -using Microsoft.VisualStudio.Shell.Interop; -using BuildVision.UI; -using BuildVision.Views.Settings; -using BuildVision.Tool; -using BuildVision.UI.Common.Logging; - -namespace BuildVision.Core -{ - // This attribute tells the PkgDef creation utility (CreatePkgDef.exe) that this class is - // a package. - [PackageRegistration(UseManagedResourcesOnly = true)] - // This attribute is used to register the informations needed to show the this package - // in the Help/About dialog of Visual Studio. Resources are defined in VSPackage.resx. - //[InstalledProductRegistration("#110", "#112", BuildVisionVersion.PackageVersion, IconResourceID = 400)] - // This attribute is needed to let the shell know that this package exposes some menus. - [ProvideMenuResource("Menus.ctmenu", 1)] - // This attribute registers a tool window exposed by this package. - [ProvideToolWindow(typeof(ToolWindow))] - [Guid(PackageGuids.GuidBuildVisionPackageString)] - [ProvideAutoLoad(UIContextGuids80.SolutionExists)] - [ProvideBindingPath] - [ProvideBindingPath(SubPath = "Lib")] - // TODO: Add ProvideProfileAttribute for each DialogPage and implement IVsUserSettings, IVsUserSettingsQuery. - //// [ProvideProfile(typeof(GeneralSettingsDialogPage), SettingsCategoryName, "General Options", 0, 0, true)] - // TODO: ProvideOptionPage keywords. - [ProvideOptionPage(typeof(GeneralSettingsDialogPage), settingsCategoryName, "General", 0, 0, true)] - [ProvideOptionPage(typeof(WindowSettingsDialogPage), settingsCategoryName, "Tool Window", 0, 0, true)] - [ProvideOptionPage(typeof(GridSettingsDialogPage), settingsCategoryName, "Projects Grid", 0, 0, true)] - [ProvideOptionPage(typeof(BuildMessagesSettingsDialogPage), settingsCategoryName, "Build Messages", 0, 0, true)] - [ProvideOptionPage(typeof(ProjectItemSettingsDialogPage), settingsCategoryName, "Project Item", 0, 0, true)] - public sealed partial class BuildVisionPackage : Package - { - /// - /// Default constructor of the package. - /// Inside this method you can place any initialization code that does not require - /// any Visual Studio service because at this point the package object is created but - /// not sited yet inside Visual Studio environment. The place to do all the other - /// initialization is the Initialize method. - /// - public BuildVisionPackage() - { - string hello = string.Format("{0} {1}", Resources.ProductName, "BuildVisionVersion.PackageVersion"); - TraceManager.Trace(hello, EventLogEntryType.Information); - } - - /// - /// Initialization of the package; this method is called right after the package is sited, so this is the place - /// where you can put all the initilaization code that rely on services provided by VisualStudio. - /// - protected override void Initialize() - { - base.Initialize(); - - // Add our command handlers for menu (commands must exist in the .vsct file) - if (GetService(typeof(IMenuCommandService)) is OleMenuCommandService mcs) - { - // Create the command for the tool window - var toolwndCommandId = new CommandID(PackageGuids.GuidBuildVisionCmdSet, (int) PackageIds.CmdIdBuildVisionToolWindow); - var menuToolWin = new MenuCommand(ShowToolWindow, toolwndCommandId); - mcs.AddCommand(menuToolWin); - } - - ToolInitialize(); - } - - /// - /// This function is called when the user clicks the menu item that shows the - /// tool window. See the Initialize method to see how the menu item is associated to - /// this function using the OleMenuCommandService service and the MenuCommand class. - /// - private void ShowToolWindow(object sender, EventArgs e) - { - try - { - // Get the instance number 0 of this tool window. This window is single instance so this instance - // is actually the only one. - // The last flag is set to true so that if the tool window does not exists it will be created. - var window = FindToolWindow(typeof(ToolWindow), 0, true); - if (window == null || window.Frame == null) - throw new InvalidOperationException(Resources.CanNotCreateWindow); - - var windowFrame = (IVsWindowFrame)window.Frame; - ErrorHandler.ThrowOnFailure(windowFrame.Show()); - } - catch (Exception ex) - { - ex.TraceUnknownException(); - } - } - } -} diff --git a/src/BuildVision/Core/BuildVisionPackage.cs b/src/BuildVision/Core/BuildVisionPackage.cs index 3f9d1859..b6c49b8c 100644 --- a/src/BuildVision/Core/BuildVisionPackage.cs +++ b/src/BuildVision/Core/BuildVisionPackage.cs @@ -1,50 +1,97 @@ using System; - +using System.ComponentModel.Design; +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Threading; +using System.Windows; +using BuildVision.Common; +using BuildVision.Tool; +using BuildVision.Tool.Building; +using BuildVision.UI; +using BuildVision.UI.Common.Logging; +using BuildVision.UI.Settings.Models; +using BuildVision.Views.Settings; using EnvDTE; -using EnvDTE80; +using Microsoft.VisualStudio; using Microsoft.VisualStudio.Settings; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; using Microsoft.VisualStudio.Shell.Settings; -using BuildVision.Common; -using BuildVision.Tool.Building; -using BuildVision.UI.Settings.Models; -using BuildVision.UI.ViewModels; -using BuildVision.Tool; -using BuildVision.UI.Common.Logging; -using System.Windows; +using Task = System.Threading.Tasks.Task; namespace BuildVision.Core { - public partial class BuildVisionPackage : IPackageContext + // This attribute tells the PkgDef creation utility (CreatePkgDef.exe) that this class is + // a package. + [PackageRegistration(UseManagedResourcesOnly = true, AllowsBackgroundLoading = true)] + // This attribute is used to register the informations needed to show the this package + // in the Help/About dialog of Visual Studio. Resources are defined in VSPackage.resx. + //[InstalledProductRegistration("#110", "#112", BuildVisionVersion.PackageVersion, IconResourceID = 400)] + // This attribute is needed to let the shell know that this package exposes some menus. + [ProvideMenuResource("Menus.ctmenu", 1)] + // This attribute registers a tool window exposed by this package. + [ProvideToolWindow(typeof(ToolWindow))] + [Guid(PackageGuids.GuidBuildVisionPackageString)] + [ProvideAutoLoad(VSConstants.UICONTEXT.SolutionOpening_string, PackageAutoLoadFlags.BackgroundLoad)] + [ProvideBindingPath] + [ProvideBindingPath(SubPath = "Lib")] + // TODO: Add ProvideProfileAttribute for each DialogPage and implement IVsUserSettings, IVsUserSettingsQuery. + //// [ProvideProfile(typeof(GeneralSettingsDialogPage), SettingsCategoryName, "General Options", 0, 0, true)] + // TODO: ProvideOptionPage keywords. + [ProvideOptionPage(typeof(GeneralSettingsDialogPage), settingsCategoryName, "General", 0, 0, true)] + [ProvideOptionPage(typeof(WindowSettingsDialogPage), settingsCategoryName, "Tool Window", 0, 0, true)] + [ProvideOptionPage(typeof(GridSettingsDialogPage), settingsCategoryName, "Projects Grid", 0, 0, true)] + [ProvideOptionPage(typeof(BuildMessagesSettingsDialogPage), settingsCategoryName, "Build Messages", 0, 0, true)] + [ProvideOptionPage(typeof(ProjectItemSettingsDialogPage), settingsCategoryName, "Project Item", 0, 0, true)] + public sealed partial class BuildVisionPackage : AsyncPackage, IPackageContext { private const string settingsCategoryName = "BuildVision"; private const string settingsPropertyName = "Settings"; + private DTE _dte; public ControlSettings ControlSettings { get; set; } - public DTE2 GetDTE2() => (DTE2)GetService(typeof(DTE)); - - public DTE GetDTE() => (DTE)GetService(typeof(DTE)); + public BuildVisionPackage() + { + string hello = string.Format("{0} {1}", Resources.ProductName, "BuildVisionVersion.PackageVersion"); + TraceManager.Trace(hello, EventLogEntryType.Information); + } - public IVsUIShell GetUIShell() => (IVsUIShell)GetService(typeof(IVsUIShell)); + public event Action ControlSettingsChanged = delegate { }; - public IVsSolution GetSolution() => (IVsSolution)GetService(typeof(IVsSolution)); + protected override async Task InitializeAsync(CancellationToken cancellationToken, IProgress progress) + { + await JoinableTaskFactory.SwitchToMainThreadAsync(DisposalToken); - public IVsStatusbar GetStatusBar() => (IVsStatusbar)GetService(typeof(SVsStatusbar)); + _dte = await GetServiceAsync(typeof(DTE)) as DTE; + if (await GetServiceAsync(typeof(IMenuCommandService)) is OleMenuCommandService mcs) + { + var toolwndCommandId = new CommandID(PackageGuids.GuidBuildVisionCmdSet, (int) PackageIds.CmdIdBuildVisionToolWindow); + var menuToolWin = new MenuCommand(ShowToolWindow, toolwndCommandId); + mcs.AddCommand(menuToolWin); + } - public ToolWindowPane GetToolWindow() => GetWindowPane(typeof(ToolWindow)); + ControlSettings = LoadSettings(this); + var toolWindow = GetWindowPane(typeof(ToolWindow)); + IPackageContext packageContext = this; + var viewModel = ToolWindow.GetViewModel(toolWindow); + var buildContext = new BuildContext(packageContext, _dte, _dte.Events.BuildEvents, _dte.Events.WindowEvents, _dte.Events.CommandEvents, viewModel); + var tool = new Tool.Tool(packageContext, _dte, (IVsWindowFrame) toolWindow.Frame, buildContext, buildContext, viewModel); + } - private void ToolInitialize() + private void ShowToolWindow(object sender, EventArgs e) { try { - ControlSettings = LoadSettings(this); - var toolWindow = GetToolWindow(); - IPackageContext packageContext = this; - var viewModel = ToolWindow.GetViewModel(toolWindow); - var buildContext = new BuildContext(packageContext, viewModel); - var tool = new Tool.Tool(packageContext, buildContext, buildContext, viewModel); + // Get the instance number 0 of this tool window. This window is single instance so this instance + // is actually the only one. + // The last flag is set to true so that if the tool window does not exists it will be created. + var window = FindToolWindow(typeof(ToolWindow), 0, true); + if (window == null || window.Frame == null) + throw new InvalidOperationException(Resources.CanNotCreateWindow); + + var windowFrame = (IVsWindowFrame)window.Frame; + ErrorHandler.ThrowOnFailure(windowFrame.Show()); } catch (Exception ex) { @@ -81,16 +128,13 @@ private static ControlSettings LoadSettings(IServiceProvider serviceProvider) } catch (Exception ex) { - ex.Trace("Error when trying to load settings: " + ex.Message, System.Diagnostics.EventLogEntryType.Error); + ex.Trace("Error when trying to load settings: " + ex.Message, EventLogEntryType.Error); MessageBox.Show("An error occurred when trying to load current settings. To make sure everything is still working the settings are set to default."); } return new ControlSettings(); } - /// - /// Settings are stored under "HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\[12.0Exp]\BuildVision\". - /// private static void SaveSettings(ControlSettings settings, IServiceProvider serviceProvider) { var store = GetWritableSettingsStore(serviceProvider); @@ -102,13 +146,17 @@ private static void SaveSettings(ControlSettings settings, IServiceProvider serv store.SetString(settingsCategoryName, settingsPropertyName, value); } + public async Task ExecuteCommandAsync(string commandName) + { + await JoinableTaskFactory.SwitchToMainThreadAsync(DisposalToken); + _dte.ExecuteCommand(commandName); + } + private static WritableSettingsStore GetWritableSettingsStore(IServiceProvider serviceProvider) { var shellSettingsManager = new ShellSettingsManager(serviceProvider); var writableSettingsStore = shellSettingsManager.GetWritableSettingsStore(SettingsScope.UserSettings); return writableSettingsStore; } - - public event Action ControlSettingsChanged = delegate { }; } } diff --git a/src/BuildVision/Core/IPackageContext.cs b/src/BuildVision/Core/IPackageContext.cs index 50d3f05d..53587218 100644 --- a/src/BuildVision/Core/IPackageContext.cs +++ b/src/BuildVision/Core/IPackageContext.cs @@ -1,12 +1,9 @@ using System; - -using EnvDTE; - using Microsoft.VisualStudio.Shell; -using Microsoft.VisualStudio.Shell.Interop; -using EnvDTE80; using BuildVision.UI.Settings.Models; +using Task = System.Threading.Tasks.Task; + namespace BuildVision.Core { public interface IPackageContext @@ -15,13 +12,7 @@ public interface IPackageContext void SaveSettings(); event Action ControlSettingsChanged; void NotifyControlSettingsChanged(); - - DTE GetDTE(); - DTE2 GetDTE2(); - ToolWindowPane GetToolWindow(); - IVsUIShell GetUIShell(); - IVsSolution GetSolution(); - IVsStatusbar GetStatusBar(); void ShowOptionPage(Type optionsPageType); + Task ExecuteCommandAsync(string command); } -} \ No newline at end of file +} diff --git a/src/BuildVision/Helpers/ToolWindowManager.cs b/src/BuildVision/Helpers/ToolWindowManager.cs index 98cc256d..1cddc3e2 100644 --- a/src/BuildVision/Helpers/ToolWindowManager.cs +++ b/src/BuildVision/Helpers/ToolWindowManager.cs @@ -14,17 +14,16 @@ public class ToolWindowManager private readonly IVsWindowFrame _windowFrame; private readonly Window _window; - public ToolWindowManager(IPackageContext packageContext) + public ToolWindowManager(DTE dte, IVsWindowFrame windowFrame) { - _dte = packageContext.GetDTE(); if (_dte == null) throw new InvalidOperationException("Unable to get DTE instance."); - _windowFrame = (IVsWindowFrame)packageContext.GetToolWindow().Frame; + _windowFrame = windowFrame; if (_windowFrame == null) throw new InvalidOperationException("Unable to get IVsWindowFrame instance."); - _window = GetWindowInstance(packageContext.GetDTE(), typeof(ToolWindow).GUID); + _window = GetWindowInstance(_dte, typeof(ToolWindow).GUID); if (_window == null) throw new InvalidOperationException("Unable to get Window instance."); } @@ -113,4 +112,4 @@ private static Window GetWindowInstance(DTE dte, Guid windowGuid) return null; } } -} \ No newline at end of file +} diff --git a/src/BuildVision/Tool/Building/BuildContext.cs b/src/BuildVision/Tool/Building/BuildContext.cs index d7531218..5d1f3231 100644 --- a/src/BuildVision/Tool/Building/BuildContext.cs +++ b/src/BuildVision/Tool/Building/BuildContext.cs @@ -30,6 +30,8 @@ public class BuildContext : IBuildInfo, IBuildDistributor private readonly object _buildProcessLockObject = new object(); private readonly IPackageContext _packageContext; + private readonly DTE _dte; + private readonly Solution _solution; private readonly Guid _parsingErrorsLoggerId = new Guid("{64822131-DC4D-4087-B292-61F7E06A7B39}"); private BuildOutputLogger _buildLogger; private CancellationTokenSource _buildProcessCancellationToken; @@ -63,19 +65,17 @@ public class BuildContext : IBuildInfo, IBuildDistributor public ProjectItem BuildScopeProject { get; private set; } - public BuildContext(IPackageContext packageContext, ControlViewModel viewModel) + public BuildContext(IPackageContext packageContext, DTE dte, BuildEvents buildEvents, WindowEvents windowEvents, CommandEvents commandEvents, ControlViewModel viewModel) { _viewModel = viewModel; BuildedProjects = new BuildedProjectsCollection(); BuildingProjects = new List(); _buildingProjectsLockObject = ((ICollection)BuildingProjects).SyncRoot; - _packageContext = packageContext; - - var dteEvents = packageContext.GetDTE().Events; - _buildEvents = dteEvents.BuildEvents; - _windowEvents = dteEvents.WindowEvents; - _commandEvents = dteEvents.CommandEvents; + _dte = dte; + _buildEvents = buildEvents; + _windowEvents = windowEvents; + _commandEvents = commandEvents; _buildEvents.OnBuildBegin += BuildEvents_OnBuildBegin; _buildEvents.OnBuildDone += (s, e) => BuildEvents_OnBuildDone(); @@ -93,7 +93,7 @@ public void OverrideBuildProperties(BuildActions? buildAction = null, BuildScope BuildScope = buildScope ?? BuildScope; } - public void CancelBuild() + public async Task CancelBuildAsync() { if(BuildAction == BuildActions.BuildActionClean) return; @@ -105,8 +105,7 @@ public void CancelBuild() // We need to create a separate task here because of some weird things that are going on // when calling ExecuteCommand directly. Directly calling it leads to a freeze. No need // for that! - var cancelBuildTask = Task.Run(() => _packageContext.GetDTE().ExecuteCommand(CancelBuildCommand)); - cancelBuildTask.Wait(10000); + await _packageContext.ExecuteCommandAsync(CancelBuildCommand); _buildCancelledInternally = true; } catch (Exception ex) @@ -242,7 +241,7 @@ private void EventSource_ErrorRaised(BuildOutputLogger loggerSender, LazyFormatt BuildedProject buildedProject = BuildedProjects[projectItem]; var errorItem = new ErrorItem(errorLevel, (eI) => { - _packageContext.GetDTE().Solution.GetProject(x => x.UniqueName == projectItem.UniqueName).NavigateToErrorItem(eI); + _dte.Solution.GetProject(x => x.UniqueName == projectItem.UniqueName).NavigateToErrorItem(eI); }); switch (errorLevel) @@ -553,7 +552,7 @@ private void BuildEvents_OnBuildBegin(vsBuildScope scope, vsBuildAction action) if (scope == vsBuildScope.vsBuildScopeProject) { - var selectedProjects = _packageContext.GetDTE().ActiveSolutionProjects as object[]; + var selectedProjects = _dte.ActiveSolutionProjects as object[]; if (selectedProjects?.Length == 1) { var projectItem = new ProjectItem(); @@ -572,7 +571,7 @@ private void BuildEvents_OnBuildBegin(vsBuildScope scope, vsBuildAction action) } BuildedSolution = null; - var solution = _packageContext.GetDTE().Solution; + var solution = _dte.Solution; BuildingSolution = new BuildedSolution(solution.FullName, solution.FileName); OnBuildBegin(this, EventArgs.Empty); diff --git a/src/BuildVision/Tool/Tool.cs b/src/BuildVision/Tool/Tool.cs index 823f63cc..56ea5672 100644 --- a/src/BuildVision/Tool/Tool.cs +++ b/src/BuildVision/Tool/Tool.cs @@ -7,9 +7,7 @@ using EnvDTE; using Microsoft.VisualStudio.Shell.Interop; -using ProjectItem = BuildVision.UI.Models.ProjectItem; -using ErrorItem = BuildVision.Contracts.ErrorItem; -using WindowState = BuildVision.UI.Models.WindowState; + using Microsoft.VisualStudio; using System.Windows; using System.ComponentModel; @@ -33,49 +31,53 @@ using BuildVision.UI.Models; using BuildVision.UI.Settings.Models.ToolWindow; using System.Collections.Specialized; +using Microsoft.VisualStudio.Shell; +using System.Threading; + +using ProjectItem = BuildVision.UI.Models.ProjectItem; +using ErrorItem = BuildVision.Contracts.ErrorItem; +using WindowState = BuildVision.UI.Models.WindowState; +using Task = System.Threading.Tasks.Task; namespace BuildVision.Tool { public class Tool { - private readonly DTE _dte; - private readonly DTE2 _dte2; - private readonly IVsStatusbar _dteStatusBar; + private DTE _dte; + private DTE2 _dte2; + private IVsStatusbar _dteStatusBar; + private SolutionEvents _solutionEvents; + private readonly ToolWindowManager _toolWindowManager; + private readonly IPackageContext _packageContext; private readonly IBuildInfo _buildContext; private readonly IBuildDistributor _buildDistributor; private readonly ControlViewModel _viewModel; - private readonly SolutionEvents _solutionEvents; private bool _buildErrorIsNavigated; private string _origTextCurrentState; - private readonly IPackageContext _packageContext; - public Tool(IPackageContext packageContext, IBuildInfo buildContext, IBuildDistributor buildDistributor, ControlViewModel viewModel) + public Tool(IPackageContext packageContext, DTE _dte, IVsWindowFrame frame, IBuildInfo buildContext, IBuildDistributor buildDistributor, ControlViewModel viewModel) { + _toolWindowManager = new ToolWindowManager(_dte, frame); _packageContext = packageContext; - _dte = packageContext.GetDTE(); - _dte2 = packageContext.GetDTE2(); + _buildContext = buildContext; + _buildDistributor = buildDistributor; + _viewModel = viewModel; + } + + public async Task InitializeAsync(Microsoft.VisualStudio.Shell.IAsyncServiceProvider provider, CancellationToken cancellationToken) + { + _dte = await provider.GetServiceAsync(typeof(DTE)) as DTE; if (_dte == null) throw new InvalidOperationException("Unable to get DTE instance."); - - _dteStatusBar = packageContext.GetStatusBar(); + _dte2 = await provider.GetServiceAsync(typeof(DTE2)) as DTE2; + _dteStatusBar = await provider.GetServiceAsync(typeof(IVsStatusbar)) as IVsStatusbar; if (_dteStatusBar == null) TraceManager.TraceError("Unable to get IVsStatusbar instance."); - _toolWindowManager = new ToolWindowManager(packageContext); - - _buildContext = buildContext; - _buildDistributor = buildDistributor; - - _viewModel = viewModel; _solutionEvents = _dte.Events.SolutionEvents; - Initialize(); - } - - private void Initialize() - { _buildDistributor.OnBuildBegin += (s, e) => BuildEvents_OnBuildBegin(); _buildDistributor.OnBuildDone += (s, e) => BuildEvents_OnBuildDone(); _buildDistributor.OnBuildProcess += (s, e) => BuildEvents_OnBuildProcess(); @@ -87,9 +89,9 @@ private void Initialize() _solutionEvents.AfterClosing += SolutionEvents_AfterClosing; _solutionEvents.Opened += SolutionEvents_Opened; - _viewModel.CancelBuildSolution += () => RaiseCommand(VSConstants.VSStd97CmdID.CancelBuild); + _viewModel.CancelBuildSolution += () => RaiseCommand(VSConstants.VSStd97CmdID.CancelBuild); _viewModel.CleanSolution += () => RaiseCommand(VSConstants.VSStd97CmdID.CleanSln); - _viewModel.RebuildSolution += () => RaiseCommand(VSConstants.VSStd97CmdID.RebuildSln); + _viewModel.RebuildSolution += () => RaiseCommand(VSConstants.VSStd97CmdID.RebuildSln); _viewModel.BuildSolution += () => RaiseCommand(VSConstants.VSStd97CmdID.BuildSln); _viewModel.RaiseCommandForSelectedProject += RaiseCommandForSelectedProject; _viewModel.ProjectCopyBuildOutputFilesToClipBoard += ProjectCopyBuildOutputFilesToClipBoard; @@ -296,7 +298,7 @@ private void BuildEvents_OnBuildProjectBegin(object sender, BuildProjectEventArg private void BuildEvents_OnBuildProjectDone(object sender, BuildProjectEventArgs e) { if (e.ProjectState == ProjectState.BuildError && _viewModel.ControlSettings.GeneralSettings.StopBuildAfterFirstError) - _buildDistributor.CancelBuild(); + _buildDistributor.CancelBuildAsync(); try { @@ -489,7 +491,7 @@ private void BuildEvents_OnErrorRaised(object sender, BuildErrorRaisedEventArgs { bool buildNeedToCancel = (args.ErrorLevel == ErrorLevel.Error && _viewModel.ControlSettings.GeneralSettings.StopBuildAfterFirstError); if (buildNeedToCancel) - _buildDistributor.CancelBuild(); + _buildDistributor.CancelBuildAsync(); bool navigateToBuildFailureReason = (!_buildErrorIsNavigated && args.ErrorLevel == ErrorLevel.Error diff --git a/src/BuildVision/Tool/Views/Settings/GridSettingsDialogPage.cs b/src/BuildVision/Tool/Views/Settings/GridSettingsDialogPage.cs index 8ceb4681..82ce3b00 100644 --- a/src/BuildVision/Tool/Views/Settings/GridSettingsDialogPage.cs +++ b/src/BuildVision/Tool/Views/Settings/GridSettingsDialogPage.cs @@ -21,11 +21,12 @@ protected override GridSettings Settings protected override void OnActivate(CancelEventArgs e) { - ToolWindowPane toolWindow = Package.GetToolWindow(); - ControlViewModel viewModel = ToolWindow.GetViewModel(toolWindow); - viewModel.SyncColumnSettings(); + //TODO FIx + //ToolWindowPane toolWindow = Package.GetToolWindow(); + //ControlViewModel viewModel = ToolWindow.GetViewModel(toolWindow); + //viewModel.SyncColumnSettings(); base.OnActivate(e); } } -} \ No newline at end of file +} From 70932b187bb0e439464f282ebb5271787a1c7379 Mon Sep 17 00:00:00 2001 From: Stefan Kert Date: Fri, 4 Jan 2019 13:46:22 +0100 Subject: [PATCH 005/100] Further major refactorings. Using MFC for loading services. Added basic DI concepts --- src/BuildVision.UI/BuildVision.UI.csproj | 4 +- .../Components/ControlView.xaml | 2 +- .../Components/ControlView.xaml.cs | 4 +- .../Contracts/IBuildDistributor.cs | 8 - .../IBuildVisionPaneViewModel.cs | 17 + src/BuildVision.UI/MainWindow.xaml.cs | 2 +- .../Settings/Models/ControlSettings.cs | 2 +- ...ewModel.cs => BuildVisionPaneViewModel.cs} | 27 +- src/BuildVision/BuildVision.csproj | 20 +- src/BuildVision/Core/BuildVisionPackage.cs | 105 ++-- src/BuildVision/Core/IPackageContext.cs | 2 - .../Core/IStatusBarNotificationService.cs | 8 + src/BuildVision/Core/PackageGuids.cs | 2 + .../Core/ServiceProviderExports.cs | 23 + .../Core/ServiceProviderPackage.cs | 36 ++ src/BuildVision/Core/Services.cs | 35 ++ .../Core/StatusBarNotificationService.cs | 50 ++ src/BuildVision/Helpers/ToolWindowManager.cs | 2 +- src/BuildVision/Helpers/ViewModelHelper.cs | 1 + .../{ToolWindow.cs => BuildVisionPane.cs} | 14 +- src/BuildVision/Tool/Building/BuildContext.cs | 591 +++++++++++------- src/BuildVision/Tool/Building/BuildManager.cs | 206 ++++++ .../Tool/Building/IVsItemLocatorService.cs | 18 + .../Tool/Building/VsItemLocatorService.cs | 132 ++++ src/BuildVision/Tool/Tool.cs | 553 ---------------- .../Settings/IPackageSettingsProvider.cs | 12 + .../Views/Settings/PackageSettingsProvider.cs | 64 ++ .../Tool/Views/Settings/SettingsDialogPage.cs | 27 +- src/BuildVision/source.extension.vsixmanifest | 1 + 29 files changed, 1078 insertions(+), 890 deletions(-) create mode 100644 src/BuildVision.UI/IBuildVisionPaneViewModel.cs rename src/BuildVision.UI/ViewModels/{ControlViewModel.cs => BuildVisionPaneViewModel.cs} (94%) create mode 100644 src/BuildVision/Core/IStatusBarNotificationService.cs create mode 100644 src/BuildVision/Core/ServiceProviderExports.cs create mode 100644 src/BuildVision/Core/ServiceProviderPackage.cs create mode 100644 src/BuildVision/Core/Services.cs create mode 100644 src/BuildVision/Core/StatusBarNotificationService.cs rename src/BuildVision/Tool/{ToolWindow.cs => BuildVisionPane.cs} (89%) create mode 100644 src/BuildVision/Tool/Building/BuildManager.cs create mode 100644 src/BuildVision/Tool/Building/IVsItemLocatorService.cs create mode 100644 src/BuildVision/Tool/Building/VsItemLocatorService.cs delete mode 100644 src/BuildVision/Tool/Tool.cs create mode 100644 src/BuildVision/Tool/Views/Settings/IPackageSettingsProvider.cs create mode 100644 src/BuildVision/Tool/Views/Settings/PackageSettingsProvider.cs diff --git a/src/BuildVision.UI/BuildVision.UI.csproj b/src/BuildVision.UI/BuildVision.UI.csproj index 5cf92708..f2359dce 100644 --- a/src/BuildVision.UI/BuildVision.UI.csproj +++ b/src/BuildVision.UI/BuildVision.UI.csproj @@ -43,6 +43,7 @@ + @@ -106,6 +107,7 @@ + MainWindow.xaml @@ -167,7 +169,7 @@ WindowSettingsControl.xaml - + diff --git a/src/BuildVision.UI/Components/ControlView.xaml b/src/BuildVision.UI/Components/ControlView.xaml index 01c02f0b..17759e95 100644 --- a/src/BuildVision.UI/Components/ControlView.xaml +++ b/src/BuildVision.UI/Components/ControlView.xaml @@ -31,7 +31,7 @@ - + diff --git a/src/BuildVision.UI/Components/ControlView.xaml.cs b/src/BuildVision.UI/Components/ControlView.xaml.cs index 5a764caf..be494324 100644 --- a/src/BuildVision.UI/Components/ControlView.xaml.cs +++ b/src/BuildVision.UI/Components/ControlView.xaml.cs @@ -24,7 +24,7 @@ namespace BuildVision.UI /// public partial class ControlView : UserControl { - private ControlViewModel _viewModel; + private BuildVisionPaneViewModel _viewModel; public ControlView() { @@ -60,7 +60,7 @@ private void OnDataContextChanged(object sender, DependencyPropertyChangedEventA { Debug.Assert(DataContext != null); - _viewModel = (ControlViewModel)DataContext; + _viewModel = (BuildVisionPaneViewModel)DataContext; _viewModel.SetGridColumnsRef(Grid.Columns); _viewModel.PropertyChanged += ViewModelOnPropertyChanged; } diff --git a/src/BuildVision.UI/Contracts/IBuildDistributor.cs b/src/BuildVision.UI/Contracts/IBuildDistributor.cs index 832861a2..e5bcd8ed 100644 --- a/src/BuildVision.UI/Contracts/IBuildDistributor.cs +++ b/src/BuildVision.UI/Contracts/IBuildDistributor.cs @@ -6,14 +6,6 @@ namespace BuildVision.UI.Contracts { public interface IBuildDistributor { - event EventHandler OnBuildBegin; - event EventHandler OnBuildProcess; - event EventHandler OnBuildDone; - event EventHandler OnBuildCancelled; - event EventHandler OnBuildProjectBegin; - event EventHandler OnBuildProjectDone; - event EventHandler OnErrorRaised; - Task CancelBuildAsync(); } } diff --git a/src/BuildVision.UI/IBuildVisionPaneViewModel.cs b/src/BuildVision.UI/IBuildVisionPaneViewModel.cs new file mode 100644 index 00000000..5e30ae7c --- /dev/null +++ b/src/BuildVision.UI/IBuildVisionPaneViewModel.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using BuildVision.UI.Models; + +namespace BuildVision.UI +{ + public interface IBuildVisionPaneViewModel + { + SolutionItem SolutionItem { get; } + + ObservableCollection ProjectsList { get;} + } +} diff --git a/src/BuildVision.UI/MainWindow.xaml.cs b/src/BuildVision.UI/MainWindow.xaml.cs index 33a10faf..ee39079a 100644 --- a/src/BuildVision.UI/MainWindow.xaml.cs +++ b/src/BuildVision.UI/MainWindow.xaml.cs @@ -16,7 +16,7 @@ public MainWindow() { InitializeComponent(); - var controlViewModel = new ControlViewModel(); + var controlViewModel = new BuildVisionPaneViewModel(); ControlView.DataContext = controlViewModel; } diff --git a/src/BuildVision.UI/Settings/Models/ControlSettings.cs b/src/BuildVision.UI/Settings/Models/ControlSettings.cs index 3c47195a..8a1067a8 100644 --- a/src/BuildVision.UI/Settings/Models/ControlSettings.cs +++ b/src/BuildVision.UI/Settings/Models/ControlSettings.cs @@ -44,4 +44,4 @@ private void Init() ProjectItemSettings = new ProjectItemSettings(); } } -} \ No newline at end of file +} diff --git a/src/BuildVision.UI/ViewModels/ControlViewModel.cs b/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs similarity index 94% rename from src/BuildVision.UI/ViewModels/ControlViewModel.cs rename to src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs index 057d6a20..cc52cb5c 100644 --- a/src/BuildVision.UI/ViewModels/ControlViewModel.cs +++ b/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs @@ -22,10 +22,13 @@ using SortDescription = BuildVision.UI.Settings.Models.Sorting.SortDescription; using BuildVision.UI.Settings.Models; using BuildVision.Helpers; +using System.ComponentModel.Composition; +using System.Text; namespace BuildVision.UI.ViewModels { - public class ControlViewModel : BindableBase + [Export(typeof(IBuildVisionPaneViewModel))] + public class BuildVisionPaneViewModel : BindableBase, IBuildVisionPaneViewModel { private BuildState _buildState; private IBuildInfo _buildInfo; @@ -211,7 +214,7 @@ public ProjectItem SelectedProjectItem set => SetProperty(ref _selectedProjectItem, value); } - public ControlViewModel(ControlModel model, ControlSettings controlSettings) + public BuildVisionPaneViewModel(ControlModel model, ControlSettings controlSettings) { Model = model; ControlSettings = controlSettings; @@ -221,7 +224,7 @@ public ControlViewModel(ControlModel model, ControlSettings controlSettings) /// /// Uses as design-time ViewModel. /// - internal ControlViewModel() + internal BuildVisionPaneViewModel() { Model = new ControlModel(); ControlSettings = new ControlSettings(); @@ -383,6 +386,23 @@ private bool IsProjectItemEnabledForActions() return (SelectedProjectItem != null && !string.IsNullOrEmpty(SelectedProjectItem.UniqueName) && !SelectedProjectItem.IsBatchBuildProject); } + private void CopyErrorMessageToClipboard(ProjectItem projectItem) + { + try + { + var errors = new StringBuilder(); + foreach (var errorItem in projectItem.ErrorsBox.Errors) + { + errors.AppendLine(string.Format("{0}({1},{2},{3},{4}): error {5}: {6}", errorItem.File, errorItem.LineNumber, errorItem.ColumnNumber, errorItem.EndLineNumber, errorItem.EndColumnNumber, errorItem.Code, errorItem.Message)); + } + Clipboard.SetText(errors.ToString()); + } + catch (Exception ex) + { + ex.TraceUnknownException(); + } + } + #region Commands public ICommand ReportIssues => new RelayCommand(obj => GithubHelper.OpenBrowserWithPrefilledIssue()); @@ -436,6 +456,5 @@ private bool IsProjectItemEnabledForActions() public event Action CancelBuildSolution; public event Action ProjectCopyBuildOutputFilesToClipBoard; public event Action RaiseCommandForSelectedProject; - public event Action CopyErrorMessageToClipboard; } } diff --git a/src/BuildVision/BuildVision.csproj b/src/BuildVision/BuildVision.csproj index eb2d1262..db62b6ee 100644 --- a/src/BuildVision/BuildVision.csproj +++ b/src/BuildVision/BuildVision.csproj @@ -68,6 +68,7 @@ + @@ -91,6 +92,11 @@ + + + + + @@ -98,8 +104,11 @@ + + + Component @@ -109,6 +118,8 @@ Component + + Component @@ -118,8 +129,7 @@ Component - - + @@ -216,6 +226,12 @@ 9.0.3 + + 15.8.525 + + + 15.8.36 + 14.3.25407 diff --git a/src/BuildVision/Core/BuildVisionPackage.cs b/src/BuildVision/Core/BuildVisionPackage.cs index b6c49b8c..acd181c0 100644 --- a/src/BuildVision/Core/BuildVisionPackage.cs +++ b/src/BuildVision/Core/BuildVisionPackage.cs @@ -7,9 +7,14 @@ using BuildVision.Common; using BuildVision.Tool; using BuildVision.Tool.Building; +using BuildVision.Tool.Models; using BuildVision.UI; using BuildVision.UI.Common.Logging; +using BuildVision.UI.Extensions; +using BuildVision.UI.Helpers; +using BuildVision.UI.Models.Indicators.Core; using BuildVision.UI.Settings.Models; +using BuildVision.UI.ViewModels; using BuildVision.Views.Settings; using EnvDTE; using Microsoft.VisualStudio; @@ -21,6 +26,7 @@ namespace BuildVision.Core { + // This attribute tells the PkgDef creation utility (CreatePkgDef.exe) that this class is // a package. [PackageRegistration(UseManagedResourcesOnly = true, AllowsBackgroundLoading = true)] @@ -30,7 +36,7 @@ namespace BuildVision.Core // This attribute is needed to let the shell know that this package exposes some menus. [ProvideMenuResource("Menus.ctmenu", 1)] // This attribute registers a tool window exposed by this package. - [ProvideToolWindow(typeof(ToolWindow))] + [ProvideToolWindow(typeof(BuildVisionPane))] [Guid(PackageGuids.GuidBuildVisionPackageString)] [ProvideAutoLoad(VSConstants.UICONTEXT.SolutionOpening_string, PackageAutoLoadFlags.BackgroundLoad)] [ProvideBindingPath] @@ -38,16 +44,16 @@ namespace BuildVision.Core // TODO: Add ProvideProfileAttribute for each DialogPage and implement IVsUserSettings, IVsUserSettingsQuery. //// [ProvideProfile(typeof(GeneralSettingsDialogPage), SettingsCategoryName, "General Options", 0, 0, true)] // TODO: ProvideOptionPage keywords. - [ProvideOptionPage(typeof(GeneralSettingsDialogPage), settingsCategoryName, "General", 0, 0, true)] - [ProvideOptionPage(typeof(WindowSettingsDialogPage), settingsCategoryName, "Tool Window", 0, 0, true)] - [ProvideOptionPage(typeof(GridSettingsDialogPage), settingsCategoryName, "Projects Grid", 0, 0, true)] - [ProvideOptionPage(typeof(BuildMessagesSettingsDialogPage), settingsCategoryName, "Build Messages", 0, 0, true)] - [ProvideOptionPage(typeof(ProjectItemSettingsDialogPage), settingsCategoryName, "Project Item", 0, 0, true)] + [ProvideOptionPage(typeof(GeneralSettingsDialogPage), "BuildVision", "General", 0, 0, true)] + [ProvideOptionPage(typeof(WindowSettingsDialogPage), "BuildVision", "Tool Window", 0, 0, true)] + [ProvideOptionPage(typeof(GridSettingsDialogPage), "BuildVision", "Projects Grid", 0, 0, true)] + [ProvideOptionPage(typeof(BuildMessagesSettingsDialogPage), "BuildVision", "Build Messages", 0, 0, true)] + [ProvideOptionPage(typeof(ProjectItemSettingsDialogPage), "BuildVision", "Project Item", 0, 0, true)] public sealed partial class BuildVisionPackage : AsyncPackage, IPackageContext { - private const string settingsCategoryName = "BuildVision"; - private const string settingsPropertyName = "Settings"; private DTE _dte; + private SolutionEvents _solutionEvents; + private BuildVisionPaneViewModel _viewModel; public ControlSettings ControlSettings { get; set; } @@ -62,34 +68,55 @@ public BuildVisionPackage() protected override async Task InitializeAsync(CancellationToken cancellationToken, IProgress progress) { await JoinableTaskFactory.SwitchToMainThreadAsync(DisposalToken); - _dte = await GetServiceAsync(typeof(DTE)) as DTE; if (await GetServiceAsync(typeof(IMenuCommandService)) is OleMenuCommandService mcs) { var toolwndCommandId = new CommandID(PackageGuids.GuidBuildVisionCmdSet, (int) PackageIds.CmdIdBuildVisionToolWindow); - var menuToolWin = new MenuCommand(ShowToolWindow, toolwndCommandId); + var menuToolWin = new OleMenuCommand(ShowToolWindowAsync, toolwndCommandId); mcs.AddCommand(menuToolWin); } - ControlSettings = LoadSettings(this); - var toolWindow = GetWindowPane(typeof(ToolWindow)); + _solutionEvents = _dte.Events.SolutionEvents; + _solutionEvents.AfterClosing += SolutionEvents_AfterClosing; + _solutionEvents.Opened += SolutionEvents_Opened; + + var toolWindow = GetWindowPane(typeof(BuildVisionPane)); IPackageContext packageContext = this; - var viewModel = ToolWindow.GetViewModel(toolWindow); - var buildContext = new BuildContext(packageContext, _dte, _dte.Events.BuildEvents, _dte.Events.WindowEvents, _dte.Events.CommandEvents, viewModel); - var tool = new Tool.Tool(packageContext, _dte, (IVsWindowFrame) toolWindow.Frame, buildContext, buildContext, viewModel); + _viewModel = BuildVisionPane.GetViewModel(toolWindow); + ViewModelHelper.UpdateSolution(_dte.Solution, _viewModel.SolutionItem); + //var buildContext = new BuildContext(packageContext, _dte, _dte.Events.BuildEvents, _dte.Events.WindowEvents, _dte.Events.CommandEvents, viewModel); + } + + private void SolutionEvents_Opened() + { + ViewModelHelper.UpdateSolution(_dte.Solution, _viewModel.SolutionItem); + _viewModel.ResetIndicators(ResetIndicatorMode.ResetValue); } - private void ShowToolWindow(object sender, EventArgs e) + private void SolutionEvents_AfterClosing() + { + _viewModel.TextCurrentState = Resources.BuildDoneText_BuildNotStarted; + _viewModel.ImageCurrentState = VectorResources.TryGet(BuildImages.BuildActionResourcesUri, "StandBy"); + _viewModel.ImageCurrentStateResult = null; + + ViewModelHelper.UpdateSolution(_dte.Solution, _viewModel.SolutionItem); + _viewModel.ProjectsList.Clear(); + _viewModel.ResetIndicators(ResetIndicatorMode.Disable); + _viewModel.BuildProgressViewModel.ResetTaskBarInfo(); + } + + private async void ShowToolWindowAsync(object sender, EventArgs e) { try { // Get the instance number 0 of this tool window. This window is single instance so this instance // is actually the only one. // The last flag is set to true so that if the tool window does not exists it will be created. - var window = FindToolWindow(typeof(ToolWindow), 0, true); + var window = FindToolWindow(typeof(BuildVisionPane), 0, true); if (window == null || window.Frame == null) throw new InvalidOperationException(Resources.CanNotCreateWindow); + await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); var windowFrame = (IVsWindowFrame)window.Frame; ErrorHandler.ThrowOnFailure(windowFrame.Show()); } @@ -99,11 +126,6 @@ private void ShowToolWindow(object sender, EventArgs e) } } - public void SaveSettings() - { - SaveSettings(ControlSettings, this); - } - public void NotifyControlSettingsChanged() { ControlSettingsChanged(ControlSettings); @@ -114,49 +136,10 @@ private ToolWindowPane GetWindowPane(Type windowType) return FindToolWindow(windowType, 0, false) ?? FindToolWindow(windowType, 0, true); } - private static ControlSettings LoadSettings(IServiceProvider serviceProvider) - { - try - { - var store = GetWritableSettingsStore(serviceProvider); - if (store.PropertyExists(settingsCategoryName, settingsPropertyName)) - { - var legacySerialized = new LegacyConfigurationSerializer(); - var value = store.GetString(settingsCategoryName, settingsPropertyName); - return legacySerialized.Deserialize(value); - } - } - catch (Exception ex) - { - ex.Trace("Error when trying to load settings: " + ex.Message, EventLogEntryType.Error); - MessageBox.Show("An error occurred when trying to load current settings. To make sure everything is still working the settings are set to default."); - } - - return new ControlSettings(); - } - - private static void SaveSettings(ControlSettings settings, IServiceProvider serviceProvider) - { - var store = GetWritableSettingsStore(serviceProvider); - if (!store.CollectionExists(settingsCategoryName)) - store.CreateCollection(settingsCategoryName); - - var legacySerializer = new LegacyConfigurationSerializer(); - var value = legacySerializer.Serialize(settings); - store.SetString(settingsCategoryName, settingsPropertyName, value); - } - public async Task ExecuteCommandAsync(string commandName) { await JoinableTaskFactory.SwitchToMainThreadAsync(DisposalToken); _dte.ExecuteCommand(commandName); } - - private static WritableSettingsStore GetWritableSettingsStore(IServiceProvider serviceProvider) - { - var shellSettingsManager = new ShellSettingsManager(serviceProvider); - var writableSettingsStore = shellSettingsManager.GetWritableSettingsStore(SettingsScope.UserSettings); - return writableSettingsStore; - } } } diff --git a/src/BuildVision/Core/IPackageContext.cs b/src/BuildVision/Core/IPackageContext.cs index 53587218..21c7c078 100644 --- a/src/BuildVision/Core/IPackageContext.cs +++ b/src/BuildVision/Core/IPackageContext.cs @@ -8,8 +8,6 @@ namespace BuildVision.Core { public interface IPackageContext { - ControlSettings ControlSettings { get; } - void SaveSettings(); event Action ControlSettingsChanged; void NotifyControlSettingsChanged(); void ShowOptionPage(Type optionsPageType); diff --git a/src/BuildVision/Core/IStatusBarNotificationService.cs b/src/BuildVision/Core/IStatusBarNotificationService.cs new file mode 100644 index 00000000..98068091 --- /dev/null +++ b/src/BuildVision/Core/IStatusBarNotificationService.cs @@ -0,0 +1,8 @@ +namespace BuildVision.Core +{ + public interface IStatusBarNotificationService + { + void ShowText(string str); + void ShowTextWithFreeze(string str); + } +} \ No newline at end of file diff --git a/src/BuildVision/Core/PackageGuids.cs b/src/BuildVision/Core/PackageGuids.cs index 77329509..23ec63d1 100644 --- a/src/BuildVision/Core/PackageGuids.cs +++ b/src/BuildVision/Core/PackageGuids.cs @@ -10,6 +10,8 @@ public static class PackageGuids public const string GuidBuildVisionCmdSetString = "caca30de-6571-483c-b8a1-b6a067964af1"; public const string GuidBuildVisionToolWindowString = "e1d4b2b5-934e-4b0e-96cc-1c0449764501"; + public const string GuidBuildVisionServiceProvider = "6671760c-72c3-49c4-a5c2-c97221bf88fc"; + public static readonly Guid GuidBuildVisionPackage = new Guid(GuidBuildVisionPackageString); public static readonly Guid GuidBuildVisionCmdSet = new Guid(GuidBuildVisionCmdSetString); public static readonly Guid GuidBuildVisionToolWindow = new Guid(GuidBuildVisionToolWindowString); diff --git a/src/BuildVision/Core/ServiceProviderExports.cs b/src/BuildVision/Core/ServiceProviderExports.cs new file mode 100644 index 00000000..48021e07 --- /dev/null +++ b/src/BuildVision/Core/ServiceProviderExports.cs @@ -0,0 +1,23 @@ +using System; +using System.ComponentModel.Composition; +using BuildVision.Views.Settings; +using Microsoft.VisualStudio.Shell; + +namespace BuildVision.Core +{ + [PartCreationPolicy(CreationPolicy.Shared)] + public class ServiceProviderExports + { + private readonly IServiceProvider _serviceProvider; + + [ImportingConstructor] + public ServiceProviderExports([Import(typeof(SVsServiceProvider))] IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + } + + [Export] + public IPackageSettingsProvider PackageSettingsProvider => (IPackageSettingsProvider) _serviceProvider.GetService(typeof(IPackageSettingsProvider)); + + } +} diff --git a/src/BuildVision/Core/ServiceProviderPackage.cs b/src/BuildVision/Core/ServiceProviderPackage.cs new file mode 100644 index 00000000..85c48306 --- /dev/null +++ b/src/BuildVision/Core/ServiceProviderPackage.cs @@ -0,0 +1,36 @@ +using System; +using System.Runtime.InteropServices; +using System.Threading; +using System.Threading.Tasks; +using BuildVision.Views.Settings; +using Microsoft.VisualStudio.Shell; +using Task = System.Threading.Tasks.Task; + +namespace BuildVision.Core +{ + [PackageRegistration(UseManagedResourcesOnly = true, AllowsBackgroundLoading = true)] + [Guid(PackageGuids.GuidBuildVisionServiceProvider)] + [ProvideService(typeof(IPackageSettingsProvider), IsAsyncQueryable = true)] + public sealed class ServiceProviderPackage : AsyncPackage + { + protected override async Task InitializeAsync(CancellationToken cancellationToken, IProgress progress) + { + await Task.CompletedTask; + AddService(typeof(IPackageSettingsProvider), CreateServiceAsync, true); + } + + async Task CreateServiceAsync(IAsyncServiceContainer container, CancellationToken cancellation, Type serviceType) + { + if (serviceType == typeof(IPackageSettingsProvider)) + { + await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(cancellation); + var sp = new ServiceProvider(Services.Dte as Microsoft.VisualStudio.OLE.Interop.IServiceProvider); + return new PackageSettingsProvider(sp); + } + else + { + throw new Exception("Not found"); + } + } + } +} diff --git a/src/BuildVision/Core/Services.cs b/src/BuildVision/Core/Services.cs new file mode 100644 index 00000000..732e9be8 --- /dev/null +++ b/src/BuildVision/Core/Services.cs @@ -0,0 +1,35 @@ +using System; +using System.ComponentModel.Composition.Hosting; +using EnvDTE; +using EnvDTE80; +using Microsoft.VisualStudio.ComponentModelHost; +using Microsoft.VisualStudio.Shell; +using Microsoft.VisualStudio.Shell.Interop; + +namespace BuildVision.Core +{ + + public static class Services + { + static TResult GetGlobalService(IServiceProvider provider = null) where T : class where TResult : class + { + + if(provider != null) + return provider.GetService(typeof(T)) as TResult; + return Package.GetGlobalService(typeof(T)) as TResult; + } + + public static DTE Dte => GetGlobalService(); + + public static DTE2 Dte2 => Dte as DTE2; + + public static ExportProvider DefaultExportProvider => ComponentModel.DefaultExportProvider; + + public static IComponentModel ComponentModel => GetGlobalService(); + + public static IVsSolution GetSolution(this IServiceProvider provider) + { + return GetGlobalService(provider); + } + } +} diff --git a/src/BuildVision/Core/StatusBarNotificationService.cs b/src/BuildVision/Core/StatusBarNotificationService.cs new file mode 100644 index 00000000..24967361 --- /dev/null +++ b/src/BuildVision/Core/StatusBarNotificationService.cs @@ -0,0 +1,50 @@ +using System; +using System.ComponentModel.Composition; +using BuildVision.Views.Settings; +using Microsoft.VisualStudio.Shell; +using Microsoft.VisualStudio.Shell.Interop; + +namespace BuildVision.Core +{ + [Export(typeof(IStatusBarNotificationService))] + [PartCreationPolicy(CreationPolicy.Shared)] + public class StatusBarNotificationService : IStatusBarNotificationService + { + private readonly IServiceProvider _serviceProvider; + + [ImportingConstructor] + public StatusBarNotificationService([Import(typeof(SVsServiceProvider))] IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + } + + public void ShowText(string str) + { + ThreadHelper.ThrowIfNotOnUIThread(); + var statusBar = _serviceProvider.GetService(typeof(IVsStatusbar)) as IVsStatusbar; + var settings = _serviceProvider.GetService(typeof(IPackageSettingsProvider)) as IPackageSettingsProvider; + if (settings == null || statusBar == null) + return; + + if (!settings.Settings.GeneralSettings.EnableStatusBarOutput) + return; + statusBar.FreezeOutput(0); + statusBar.SetText(str); + } + + public void ShowTextWithFreeze(string str) + { + ThreadHelper.ThrowIfNotOnUIThread(); + var statusBar = _serviceProvider.GetService(typeof(IVsStatusbar)) as IVsStatusbar; + var settings = _serviceProvider.GetService(typeof(IPackageSettingsProvider)) as IPackageSettingsProvider; + if (settings == null || statusBar == null) + return; + + if (!settings.Settings.GeneralSettings.EnableStatusBarOutput) + return; + statusBar.FreezeOutput(0); + statusBar.SetText(str); + statusBar.FreezeOutput(1); + } + } +} diff --git a/src/BuildVision/Helpers/ToolWindowManager.cs b/src/BuildVision/Helpers/ToolWindowManager.cs index 1cddc3e2..fc1b0eeb 100644 --- a/src/BuildVision/Helpers/ToolWindowManager.cs +++ b/src/BuildVision/Helpers/ToolWindowManager.cs @@ -23,7 +23,7 @@ public ToolWindowManager(DTE dte, IVsWindowFrame windowFrame) if (_windowFrame == null) throw new InvalidOperationException("Unable to get IVsWindowFrame instance."); - _window = GetWindowInstance(_dte, typeof(ToolWindow).GUID); + _window = GetWindowInstance(_dte, typeof(BuildVisionPane).GUID); if (_window == null) throw new InvalidOperationException("Unable to get Window instance."); } diff --git a/src/BuildVision/Helpers/ViewModelHelper.cs b/src/BuildVision/Helpers/ViewModelHelper.cs index ff3903f0..102843c7 100644 --- a/src/BuildVision/Helpers/ViewModelHelper.cs +++ b/src/BuildVision/Helpers/ViewModelHelper.cs @@ -10,6 +10,7 @@ using ProjectItem = BuildVision.UI.Models.ProjectItem; using BuildVision.UI.Models; +using Microsoft.VisualStudio.Shell.Interop; namespace BuildVision.Tool.Models { diff --git a/src/BuildVision/Tool/ToolWindow.cs b/src/BuildVision/Tool/BuildVisionPane.cs similarity index 89% rename from src/BuildVision/Tool/ToolWindow.cs rename to src/BuildVision/Tool/BuildVisionPane.cs index dc60a73a..433fedf9 100644 --- a/src/BuildVision/Tool/ToolWindow.cs +++ b/src/BuildVision/Tool/BuildVisionPane.cs @@ -28,11 +28,11 @@ namespace BuildVision.Tool /// in order to use its implementation of the IVsUIElementPane interface. /// [Guid(PackageGuids.GuidBuildVisionToolWindowString)] - public sealed class ToolWindow : ToolWindowPane + public sealed class BuildVisionPane : ToolWindowPane { private bool _controlCreatedSuccessfully; - public ToolWindow() + public BuildVisionPane() :base(null) { Caption = Resources.ToolWindowTitle; @@ -50,8 +50,6 @@ public ToolWindow() FrameworkElement.LanguageProperty.OverrideMetadata( typeof(FrameworkElement), new FrameworkPropertyMetadata(XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag))); - - // Content has been set in Initialize(), because Package == null now. } protected override void Initialize() @@ -76,7 +74,7 @@ protected override void OnClose() private ControlView CreateControlView() { var packageContext = (IPackageContext)Package; - var viewModel = new ControlViewModel(new ControlModel(), packageContext.ControlSettings); + var viewModel = new BuildVisionPaneViewModel(new ControlModel(), null);//packageContext.ControlSettings); packageContext.ControlSettingsChanged += (settings) => { viewModel.OnControlSettingsChanged(settings, buildInfo => BuildMessages.GetBuildDoneMessage(viewModel.SolutionItem, buildInfo, viewModel.ControlSettings.BuildMessagesSettings)); @@ -95,13 +93,13 @@ private void SaveControlSettings() viewModel.SyncColumnSettings(); var packageContext = (IPackageContext)Package; - packageContext.SaveSettings(); + //packageContext.SaveSettings(); } - public static ControlViewModel GetViewModel(ToolWindowPane toolWindow) + public static BuildVisionPaneViewModel GetViewModel(ToolWindowPane toolWindow) { var controlView = (ControlView)toolWindow.Content; - return (ControlViewModel)controlView.DataContext; + return (BuildVisionPaneViewModel)controlView.DataContext; } } } diff --git a/src/BuildVision/Tool/Building/BuildContext.cs b/src/BuildVision/Tool/Building/BuildContext.cs index 5d1f3231..ef85b630 100644 --- a/src/BuildVision/Tool/Building/BuildContext.cs +++ b/src/BuildVision/Tool/Building/BuildContext.cs @@ -3,20 +3,31 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using System.Text; using System.Threading; using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using BuildVision.Common; using BuildVision.Contracts; using BuildVision.Core; using BuildVision.Helpers; using BuildVision.Tool.Models; using BuildVision.UI.Common.Logging; using BuildVision.UI.Contracts; +using BuildVision.UI.Extensions; +using BuildVision.UI.Helpers; +using BuildVision.UI.Models; +using BuildVision.UI.Models.Indicators.Core; +using BuildVision.UI.Settings.Models.ToolWindow; using BuildVision.UI.ViewModels; using EnvDTE; using Microsoft.Build.Framework; using Microsoft.VisualStudio; +using Microsoft.VisualStudio.Shell.Interop; using ErrorItem = BuildVision.Contracts.ErrorItem; using ProjectItem = BuildVision.UI.Models.ProjectItem; +using WindowState = BuildVision.UI.Models.WindowState; namespace BuildVision.Tool.Building { @@ -26,9 +37,12 @@ public class BuildContext : IBuildInfo, IBuildDistributor private const int BuildInProcessQuantumSleep = 50; private const string CancelBuildCommand = "Build.Cancel"; + private IVsStatusbar _dteStatusBar; private readonly object _buildingProjectsLockObject; private readonly object _buildProcessLockObject = new object(); - + private readonly IVsItemLocatorService _locatorService; + private readonly IStatusBarNotificationService _statusBarNotificationService; + private readonly IStatusBarNotificationService statusBarNotificationService; private readonly IPackageContext _packageContext; private readonly DTE _dte; private readonly Solution _solution; @@ -36,12 +50,13 @@ public class BuildContext : IBuildInfo, IBuildDistributor private BuildOutputLogger _buildLogger; private CancellationTokenSource _buildProcessCancellationToken; private bool _buildCancelledInternally; - private Window _activeProjectContext; - private readonly ControlViewModel _viewModel; + private readonly BuildVisionPaneViewModel _viewModel; private bool _buildCancelled; private readonly BuildEvents _buildEvents; - private readonly WindowEvents _windowEvents; private readonly CommandEvents _commandEvents; + private readonly ToolWindowManager _toolWindowManager; + private bool _buildErrorIsNavigated; + private string _origTextCurrentState; public bool BuildIsCancelled => _buildCancelled && !_buildCancelledInternally; @@ -65,28 +80,34 @@ public class BuildContext : IBuildInfo, IBuildDistributor public ProjectItem BuildScopeProject { get; private set; } - public BuildContext(IPackageContext packageContext, DTE dte, BuildEvents buildEvents, WindowEvents windowEvents, CommandEvents commandEvents, ControlViewModel viewModel) + public BuildContext(IVsItemLocatorService locatorService, IStatusBarNotificationService statusBarNotificationService, IPackageContext packageContext, DTE dte, BuildVisionPaneViewModel viewModel) { _viewModel = viewModel; BuildedProjects = new BuildedProjectsCollection(); BuildingProjects = new List(); _buildingProjectsLockObject = ((ICollection)BuildingProjects).SyncRoot; + _locatorService = locatorService; + _statusBarNotificationService = statusBarNotificationService; _packageContext = packageContext; _dte = dte; - _buildEvents = buildEvents; - _windowEvents = windowEvents; - _commandEvents = commandEvents; + _buildEvents = dte.Events.BuildEvents; + _commandEvents = dte.Events.CommandEvents; _buildEvents.OnBuildBegin += BuildEvents_OnBuildBegin; _buildEvents.OnBuildDone += (s, e) => BuildEvents_OnBuildDone(); _buildEvents.OnBuildProjConfigBegin += BuildEvents_OnBuildProjectBegin; _buildEvents.OnBuildProjConfigDone += BuildEvents_OnBuildProjectDone; - _windowEvents.WindowActivated += WindowEvents_WindowActivated; - _commandEvents.AfterExecute += CommandEvents_AfterExecute; } + public async Task InitializeAsync(Microsoft.VisualStudio.Shell.IAsyncServiceProvider provider, CancellationToken cancellationToken) + { + _dteStatusBar = await provider.GetServiceAsync(typeof(IVsStatusbar)) as IVsStatusbar; + if (_dteStatusBar == null) + TraceManager.TraceError("Unable to get IVsStatusbar instance."); + } + public void OverrideBuildProperties(BuildActions? buildAction = null, BuildScopes? buildScope = null) { BuildAction = buildAction ?? BuildAction; @@ -114,59 +135,6 @@ public async Task CancelBuildAsync() } } - public ProjectItem FindProjectItemInProjectsByUniqueName(string uniqueName, string configuration, string platform) - { - return _viewModel.ProjectsList.FirstOrDefault(item => item.UniqueName == uniqueName && item.Configuration == configuration && PlatformsIsEquals(item.Platform, platform)); - } - - public ProjectItem FindProjectItemInProjectsByUniqueName(string uniqueName) - { - return _viewModel.ProjectsList.FirstOrDefault(item => item.UniqueName == uniqueName); - } - - public ProjectItem AddProjectToVisibleProjectsByUniqueName(string uniqueName) - { - var proj = _viewModel.SolutionItem.AllProjects.FirstOrDefault(x => x.UniqueName == uniqueName); - if (proj == null) - throw new InvalidOperationException(); - _viewModel.ProjectsList.Add(proj); - return proj; - } - - public ProjectItem AddProjectToVisibleProjectsByUniqueName(string uniqueName, string configuration, string platform) - { - ProjectItem currentProject = _viewModel.SolutionItem.AllProjects.FirstOrDefault(item => item.UniqueName == uniqueName - && item.Configuration == configuration - && PlatformsIsEquals(item.Platform, platform)); - if (currentProject == null) - { - currentProject = _viewModel.SolutionItem.AllProjects.FirstOrDefault(x => x.UniqueName == uniqueName); - if (currentProject == null) - throw new InvalidOperationException(); - currentProject = currentProject.GetBatchBuildCopy(configuration, platform); - _viewModel.SolutionItem.AllProjects.Add(currentProject); - } - - _viewModel.ProjectsList.Add(currentProject); - return currentProject; - } - - private bool PlatformsIsEquals(string platformName1, string platformName2) - { - if (string.Compare(platformName1, platformName2, StringComparison.InvariantCultureIgnoreCase) == 0) - return true; - - // The ambiguity between Project.ActiveConfiguration.PlatformName and - // ProjectStartedEventArgs.ProjectPlatform in Microsoft.Build.Utilities.Logger - // (see BuildOutputLogger). - bool isAnyCpu1 = (platformName1 == "Any CPU" || platformName1 == "AnyCPU"); - bool isAnyCpu2 = (platformName2 == "Any CPU" || platformName2 == "AnyCPU"); - if (isAnyCpu1 && isAnyCpu2) - return true; - - return false; - } - private void RegisterLogger() { _buildLogger = null; @@ -232,7 +200,7 @@ private void EventSource_ErrorRaised(BuildOutputLogger loggerSender, LazyFormatt if (projectEntry.IsInvalid) return; - if (!GetProjectItem(projectEntry, out var projectItem)) + if (!_locatorService.GetProjectItem(_viewModel, BuildScope, projectEntry, out var projectItem)) { projectEntry.IsInvalid = true; return; @@ -310,82 +278,99 @@ private void Init(ErrorItem item, BuildMessageEventArgs e) item.Message = e.Message; } - private bool GetProjectItem(BuildProjectContextEntry projectEntry, out ProjectItem projectItem) + private void CommandEvents_AfterExecute(string guid, int id, object customIn, object customOut) { - projectItem = projectEntry.ProjectItem; - if (projectItem != null) - return true; + if (id == (int)VSConstants.VSStd97CmdID.CancelBuild + && Guid.Parse(guid) == VSConstants.GUID_VSStandardCommandSet97) + { + _buildCancelled = true; + if (!_buildCancelledInternally) + OnBuildCancelled(); + } + } - string projectFile = projectEntry.FileName; - if (ProjectExtensions.IsProjectHidden(projectFile)) - return false; + private ProjectState GetProjectState() + { + ProjectState projectState; + switch (BuildAction) + { + case BuildActions.BuildActionBuild: + case BuildActions.BuildActionRebuildAll: + projectState = ProjectState.Building; + break; - IDictionary projectProperties = projectEntry.Properties; - var project = _viewModel.ProjectsList.FirstOrDefault(x => x.FullName == projectFile); + case BuildActions.BuildActionClean: + projectState = ProjectState.Cleaning; + break; + case BuildActions.BuildActionDeploy: + throw new InvalidOperationException("vsBuildActionDeploy not supported"); - if (BuildScope == BuildScopes.BuildScopeBatch && projectProperties.ContainsKey("Configuration") && projectProperties.ContainsKey("Platform")) - { - string projectConfiguration = projectProperties["Configuration"]; - string projectPlatform = projectProperties["Platform"]; - projectItem = FindProjectItemInProjectsByUniqueName(project.UniqueName, projectConfiguration, projectPlatform); - if (projectItem == null) - { - TraceManager.Trace( - string.Format("Project Item not found by: UniqueName='{0}', Configuration='{1}, Platform='{2}'.", - project.UniqueName, - projectConfiguration, - projectPlatform), - EventLogEntryType.Warning); - return false; - } - } - else - { - projectItem = FindProjectItemInProjectsByUniqueName(project.UniqueName); - if (projectItem == null) - { - TraceManager.Trace(string.Format("Project Item not found by FullName='{0}'.", projectFile), EventLogEntryType.Warning); - return false; - } + default: + throw new ArgumentOutOfRangeException(nameof(BuildAction)); } - projectEntry.ProjectItem = projectItem; - return true; + return projectState; } - private void WindowEvents_WindowActivated(Window gotFocus, Window lostFocus) + private void BuildEvents_OnBuildBegin(vsBuildScope scope, vsBuildAction action) { - if (gotFocus == null) + if (action == vsBuildAction.vsBuildActionDeploy) return; - switch (gotFocus.Type) + RegisterLogger(); + + CurrentBuildState = BuildState.InProgress; + + BuildStartTime = DateTime.Now; + BuildFinishTime = null; + BuildAction = (BuildActions) action; + + switch (scope) { - case vsWindowType.vsWindowTypeSolutionExplorer: - _activeProjectContext = gotFocus; + case vsBuildScope.vsBuildScopeSolution: + case vsBuildScope.vsBuildScopeBatch: + case vsBuildScope.vsBuildScopeProject: + BuildScope = (BuildScopes) scope; break; - case vsWindowType.vsWindowTypeDocument: - case vsWindowType.vsWindowTypeDesigner: - case vsWindowType.vsWindowTypeCodeWindow: - if (gotFocus.Project != null && !gotFocus.Project.IsHidden()) - _activeProjectContext = gotFocus; + case 0: + // Scope may be 0 in case of Clean solution, then Start (F5). + BuildScope = (BuildScopes) vsBuildScope.vsBuildScopeSolution; break; default: - return; + throw new ArgumentOutOfRangeException("scope"); } - } - private void CommandEvents_AfterExecute(string guid, int id, object customIn, object customOut) - { - if (id == (int)VSConstants.VSStd97CmdID.CancelBuild - && Guid.Parse(guid) == VSConstants.GUID_VSStandardCommandSet97) + if (scope == vsBuildScope.vsBuildScopeProject) { - _buildCancelled = true; - if (!_buildCancelledInternally) - OnBuildCancelled(this, EventArgs.Empty); + var selectedProjects = _dte.ActiveSolutionProjects as object[]; + if (selectedProjects?.Length == 1) + { + var projectItem = new ProjectItem(); + ViewModelHelper.UpdateProperties((Project) selectedProjects[0], projectItem); + BuildScopeProject = projectItem; + } } + + _buildCancelled = false; + _buildCancelledInternally = false; + + BuildedProjects.Clear(); + lock (_buildingProjectsLockObject) + { + BuildingProjects.Clear(); + } + + BuildedSolution = null; + var solution = _dte.Solution; + BuildingSolution = new BuildedSolution(solution.FullName, solution.FileName); + + OnBuildBegin(); + + _buildProcessCancellationToken = new CancellationTokenSource(); + Task.Factory.StartNew(BuildEvents_BuildInProcess, _buildProcessCancellationToken.Token, _buildProcessCancellationToken.Token); } private void BuildEvents_OnBuildProjectBegin(string project, string projectconfig, string platform, string solutionconfig) @@ -398,15 +383,15 @@ private void BuildEvents_OnBuildProjectBegin(string project, string projectconfi ProjectItem currentProject; if (BuildScope == BuildScopes.BuildScopeBatch) { - currentProject = FindProjectItemInProjectsByUniqueName(project, projectconfig, platform); + currentProject = _locatorService.FindProjectItemInProjectsByUniqueName(_viewModel, project, projectconfig, platform); if (currentProject == null) - currentProject = AddProjectToVisibleProjectsByUniqueName(project, projectconfig, platform); + currentProject = _locatorService.AddProjectToVisibleProjectsByUniqueName(_viewModel, project, projectconfig, platform); } else { - currentProject = FindProjectItemInProjectsByUniqueName(project); + currentProject = _locatorService.FindProjectItemInProjectsByUniqueName(_viewModel, project); if (currentProject == null) - currentProject = AddProjectToVisibleProjectsByUniqueName(project); + currentProject = _locatorService.AddProjectToVisibleProjectsByUniqueName(_viewModel, project); } lock (_buildingProjectsLockObject) @@ -415,31 +400,30 @@ private void BuildEvents_OnBuildProjectBegin(string project, string projectconfi } var projectState = GetProjectState(); - OnBuildProjectBegin(this, new BuildProjectEventArgs(currentProject, projectState, eventTime, null)); + OnBuildProjectBegin(new BuildProjectEventArgs(currentProject, projectState, eventTime, null)); } - private ProjectState GetProjectState() + private void BuildEvents_BuildInProcess(object state) { - ProjectState projectState; - switch (BuildAction) + lock (_buildProcessLockObject) { - case BuildActions.BuildActionBuild: - case BuildActions.BuildActionRebuildAll: - projectState = ProjectState.Building; - break; + if (BuildAction == BuildActions.BuildActionDeploy) + return; - case BuildActions.BuildActionClean: - projectState = ProjectState.Cleaning; - break; + var token = (CancellationToken) state; + while (!token.IsCancellationRequested) + { + OnBuildProcess(); - case BuildActions.BuildActionDeploy: - throw new InvalidOperationException("vsBuildActionDeploy not supported"); + for (int i = 0; i < BuildInProcessQuantumSleep * BuildInProcessCountOfQuantumSleep; i += BuildInProcessQuantumSleep) + { + if (token.IsCancellationRequested) + break; - default: - throw new ArgumentOutOfRangeException(nameof(BuildAction)); + System.Threading.Thread.Sleep(BuildInProcessQuantumSleep); + } + } } - - return projectState; } private void BuildEvents_OnBuildProjectDone(string project, string projectconfig, string platform, string solutionconfig, bool success) @@ -448,7 +432,7 @@ private void BuildEvents_OnBuildProjectDone(string project, string projectconfig return; var eventTime = DateTime.Now; - var currentProject = GetCurrentProject(project, projectconfig, platform); + var currentProject = _locatorService.GetCurrentProject(_viewModel, BuildScope, project, projectconfig, platform); lock (_buildingProjectsLockObject) { @@ -498,144 +482,297 @@ private void BuildEvents_OnBuildProjectDone(string project, string projectconfig } buildedProject.ProjectState = projectState; - OnBuildProjectDone(this, new BuildProjectEventArgs(currentProject, projectState, eventTime, buildedProject)); + OnBuildProjectDone(new BuildProjectEventArgs(currentProject, projectState, eventTime, buildedProject)); } - private ProjectItem GetCurrentProject(string project, string projectconfig, string platform) + private void BuildEvents_OnBuildDone() { - ProjectItem currentProject; - if (BuildScope == BuildScopes.BuildScopeBatch) + if (BuildAction == BuildActions.BuildActionDeploy) + return; + + if (CurrentBuildState != BuildState.InProgress) { - currentProject = FindProjectItemInProjectsByUniqueName(project, projectconfig, platform); - if (currentProject == null) - throw new InvalidOperationException(); + // Start command (F5), when Build is not required. + return; } - else + + _buildProcessCancellationToken.Cancel(); + + BuildedSolution = BuildingSolution; + BuildingSolution = null; + + lock (_buildingProjectsLockObject) { - currentProject = FindProjectItemInProjectsByUniqueName(project); - if (currentProject == null) - throw new InvalidOperationException(); + BuildingProjects.Clear(); } - return currentProject; + BuildFinishTime = DateTime.Now; + CurrentBuildState = BuildState.Done; + + OnBuildDone(); } - private void BuildEvents_OnBuildBegin(vsBuildScope scope, vsBuildAction action) + private void OnBuildProjectBegin(BuildProjectEventArgs e) { - if (action == vsBuildAction.vsBuildActionDeploy) - return; + try + { + ProjectItem currentProject = e.ProjectItem; + currentProject.State = e.ProjectState; + currentProject.BuildFinishTime = null; + currentProject.BuildStartTime = e.EventTime; + + _viewModel.OnBuildProjectBegin(); + if (BuildScope == BuildScopes.BuildScopeSolution && + (BuildAction == BuildActions.BuildActionBuild || + BuildAction == BuildActions.BuildActionRebuildAll)) + { + currentProject.BuildOrder = _viewModel.BuildProgressViewModel.CurrentQueuePosOfBuildingProject; + } - RegisterLogger(); + if (!_viewModel.ProjectsList.Contains(currentProject)) + _viewModel.ProjectsList.Add(currentProject); + else if (_viewModel.ControlSettings.GeneralSettings.FillProjectListOnBuildBegin) + _viewModel.OnPropertyChanged(nameof(BuildVisionPaneViewModel.GroupedProjectsList)); + _viewModel.CurrentProject = currentProject; + } + catch (Exception ex) + { + ex.TraceUnknownException(); + } + } - CurrentBuildState = BuildState.InProgress; + private void OnBuildProjectDone(BuildProjectEventArgs e) + { + if (e.ProjectState == ProjectState.BuildError && _viewModel.ControlSettings.GeneralSettings.StopBuildAfterFirstError) + CancelBuildAsync(); - BuildStartTime = DateTime.Now; - BuildFinishTime = null; - BuildAction = (BuildActions) action; + try + { + ProjectItem currentProject = e.ProjectItem; + currentProject.State = e.ProjectState; + currentProject.BuildFinishTime = DateTime.Now; + currentProject.UpdatePostBuildProperties(e.BuildedProjectInfo); - switch (scope) + if (!_viewModel.ProjectsList.Contains(currentProject)) + _viewModel.ProjectsList.Add(currentProject); + + if (ReferenceEquals(_viewModel.CurrentProject, e.ProjectItem) && BuildingProjects.Any()) + _viewModel.CurrentProject = BuildingProjects.Last(); + } + catch (Exception ex) { - case vsBuildScope.vsBuildScopeSolution: - case vsBuildScope.vsBuildScopeBatch: - case vsBuildScope.vsBuildScopeProject: - BuildScope = (BuildScopes) scope; - break; + ex.TraceUnknownException(); + } - case 0: - // Scope may be 0 in case of Clean solution, then Start (F5). - BuildScope = (BuildScopes)vsBuildScope.vsBuildScopeSolution; - break; + _viewModel.UpdateIndicators(this); - default: - throw new ArgumentOutOfRangeException("scope"); + try + { + _viewModel.OnBuildProjectDone(e.BuildedProjectInfo); + } + catch (Exception ex) + { + ex.TraceUnknownException(); } + } - if (scope == vsBuildScope.vsBuildScopeProject) + private void OnBuildBegin() + { + try { - var selectedProjects = _dte.ActiveSolutionProjects as object[]; - if (selectedProjects?.Length == 1) + _buildErrorIsNavigated = false; + + ApplyToolWindowStateAction(_viewModel.ControlSettings.WindowSettings.WindowActionOnBuildBegin); + + ViewModelHelper.UpdateSolution(_dte.Solution, _viewModel.SolutionItem); + + string message = BuildMessages.GetBuildBeginMajorMessage(_viewModel.SolutionItem, this, _viewModel.ControlSettings.BuildMessagesSettings); + + _statusBarNotificationService.ShowTextWithFreeze(message); + _viewModel.TextCurrentState = message; + _origTextCurrentState = message; + _viewModel.ImageCurrentState = BuildImages.GetBuildBeginImage(this); + _viewModel.ImageCurrentStateResult = null; + + ViewModelHelper.UpdateProjects(_viewModel.SolutionItem, Services.Dte.Solution); + _viewModel.ProjectsList.Clear(); + + if (_viewModel.ControlSettings.GeneralSettings.FillProjectListOnBuildBegin) + _viewModel.ProjectsList.AddRange(_viewModel.SolutionItem.AllProjects); + + _viewModel.ResetIndicators(ResetIndicatorMode.ResetValue); + + int projectsCount = -1; + switch (BuildScope) { - var projectItem = new ProjectItem(); - ViewModelHelper.UpdateProperties((Project)selectedProjects[0], projectItem); - BuildScopeProject = projectItem; - } - } + case BuildScopes.BuildScopeSolution: + if (_viewModel.ControlSettings.GeneralSettings.FillProjectListOnBuildBegin) + { + projectsCount = _viewModel.ProjectsList.Count; + } + else + { + try + { + Solution solution = _dte.Solution; + if (solution != null) + projectsCount = solution.GetProjects().Count; + } + catch (Exception ex) + { + ex.Trace("Unable to count projects in solution."); + } + } + break; - _buildCancelled = false; - _buildCancelledInternally = false; + case BuildScopes.BuildScopeBatch: + case BuildScopes.BuildScopeProject: + break; - BuildedProjects.Clear(); - lock (_buildingProjectsLockObject) + default: + throw new ArgumentOutOfRangeException(nameof(BuildScope)); + } + + _viewModel.OnBuildBegin(projectsCount, this); + } + catch (Exception ex) { - BuildingProjects.Clear(); + ex.TraceUnknownException(); } + } - BuildedSolution = null; - var solution = _dte.Solution; - BuildingSolution = new BuildedSolution(solution.FullName, solution.FileName); + private void OnBuildProcess() + { + try + { + var labelsSettings = _viewModel.ControlSettings.BuildMessagesSettings; + string msg = _origTextCurrentState + BuildMessages.GetBuildBeginExtraMessage(this, labelsSettings); - OnBuildBegin(this, EventArgs.Empty); + _viewModel.TextCurrentState = msg; + _statusBarNotificationService.ShowTextWithFreeze(msg); - _buildProcessCancellationToken = new CancellationTokenSource(); - Task.Factory.StartNew(BuildEvents_BuildInProcess, _buildProcessCancellationToken.Token, _buildProcessCancellationToken.Token); + var buildingProjects = BuildingProjects; + for (int i = 0; i < buildingProjects.Count; i++) + buildingProjects[i].RaiseBuildElapsedTimeChanged(); + } + catch (Exception ex) + { + ex.TraceUnknownException(); + } } - private void BuildEvents_BuildInProcess(object state) + private void OnBuildDone() { - lock (_buildProcessLockObject) + try { - if (BuildAction == BuildActions.BuildActionDeploy) - return; + var settings = _viewModel.ControlSettings; - var token = (CancellationToken)state; - while (!token.IsCancellationRequested) + if (BuildScope == BuildScopes.BuildScopeSolution) { - OnBuildProcess(this, EventArgs.Empty); - - for (int i = 0; i < BuildInProcessQuantumSleep * BuildInProcessCountOfQuantumSleep; i += BuildInProcessQuantumSleep) + foreach (var projectItem in _viewModel.ProjectsList) { - if (token.IsCancellationRequested) - break; - - System.Threading.Thread.Sleep(BuildInProcessQuantumSleep); + if (projectItem.State == ProjectState.Pending) + projectItem.State = ProjectState.Skipped; } } + + _viewModel.UpdateIndicators(this); + + var message = BuildMessages.GetBuildDoneMessage(_viewModel.SolutionItem, this, settings.BuildMessagesSettings); + var buildDoneImage = BuildImages.GetBuildDoneImage(this, _viewModel.ProjectsList, out ControlTemplate stateImage); + + _statusBarNotificationService.ShowText(message); + _viewModel.TextCurrentState = message; + _viewModel.ImageCurrentState = buildDoneImage; + _viewModel.ImageCurrentStateResult = stateImage; + _viewModel.CurrentProject = null; + _viewModel.OnBuildDone(this); + + int errorProjectsCount = _viewModel.ProjectsList.Count(item => item.State.IsErrorState()); + if (errorProjectsCount > 0 || BuildIsCancelled) + ApplyToolWindowStateAction(settings.WindowSettings.WindowActionOnBuildError); + else + ApplyToolWindowStateAction(settings.WindowSettings.WindowActionOnBuildSuccess); + + bool navigateToBuildFailureReason = (!BuildedProjects.BuildWithoutErrors + && settings.GeneralSettings.NavigateToBuildFailureReason == NavigateToBuildFailureReasonCondition.OnBuildDone); + if (navigateToBuildFailureReason && BuildedProjects.Any(p => p.ErrorsBox.Errors.Any(NavigateToErrorItem))) + { + _buildErrorIsNavigated = true; + } + } + catch (Exception ex) + { + ex.TraceUnknownException(); } } - private void BuildEvents_OnBuildDone() + private void OnBuildCancelled() { - if (BuildAction == BuildActions.BuildActionDeploy) - return; + _viewModel.OnBuildCancelled(this); + } - if (CurrentBuildState != BuildState.InProgress) + private async void OnErrorRaised(object sender, BuildErrorRaisedEventArgs args) + { + bool buildNeedToCancel = (args.ErrorLevel == ErrorLevel.Error && _viewModel.ControlSettings.GeneralSettings.StopBuildAfterFirstError); + if (buildNeedToCancel) + await CancelBuildAsync(); + + bool navigateToBuildFailureReason = (!_buildErrorIsNavigated + && args.ErrorLevel == ErrorLevel.Error + && _viewModel.ControlSettings.GeneralSettings.NavigateToBuildFailureReason == NavigateToBuildFailureReasonCondition.OnErrorRaised); + if (navigateToBuildFailureReason && args.ProjectInfo.ErrorsBox.Errors.Any(NavigateToErrorItem)) { - // Start command (F5), when Build is not required. - return; + _buildErrorIsNavigated = true; } + } - _buildProcessCancellationToken.Cancel(); - - BuildedSolution = BuildingSolution; - BuildingSolution = null; + private bool NavigateToErrorItem(ErrorItem errorItem) + { + if (string.IsNullOrEmpty(errorItem?.File) || string.IsNullOrEmpty(errorItem?.ProjectFile)) + return false; - lock (_buildingProjectsLockObject) + try { - BuildingProjects.Clear(); - } + var projectItem = _viewModel.ProjectsList.FirstOrDefault(x => x.FullName == errorItem.ProjectFile); + if (projectItem == null) + return false; - BuildFinishTime = DateTime.Now; - CurrentBuildState = BuildState.Done; - OnBuildDone(this, EventArgs.Empty); + var project = _dte.Solution.GetProject(x => x.UniqueName == projectItem.UniqueName); + if (project == null) + return false; + + return project.NavigateToErrorItem(errorItem); + } + catch (Exception ex) + { + ex.Trace("Navigate to error item exception"); + return true; + } } - public event EventHandler OnBuildBegin = delegate { }; - public event EventHandler OnBuildProcess = delegate { }; - public event EventHandler OnBuildDone = delegate { }; - public event EventHandler OnBuildCancelled = delegate { }; - public event EventHandler OnBuildProjectBegin = delegate { }; - public event EventHandler OnBuildProjectDone = delegate { }; - public event EventHandler OnErrorRaised = delegate { }; + private void ApplyToolWindowStateAction(WindowStateAction windowStateAction) + { + switch (windowStateAction.State) + { + case WindowState.Nothing: + break; + case WindowState.Show: + _toolWindowManager.Show(); + break; + case WindowState.ShowNoActivate: + _toolWindowManager.ShowNoActivate(); + break; + case WindowState.Hide: + _toolWindowManager.Hide(); + break; + case WindowState.Close: + _toolWindowManager.Close(); + break; + default: + throw new ArgumentOutOfRangeException(nameof(windowStateAction)); + } + } } } diff --git a/src/BuildVision/Tool/Building/BuildManager.cs b/src/BuildVision/Tool/Building/BuildManager.cs new file mode 100644 index 00000000..c290cc6b --- /dev/null +++ b/src/BuildVision/Tool/Building/BuildManager.cs @@ -0,0 +1,206 @@ +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.ComponentModel; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using System.Windows; +using BuildVision.Common; +using BuildVision.Contracts; +using BuildVision.Core; +using BuildVision.Helpers; +using BuildVision.UI; +using BuildVision.UI.Common.Logging; +using BuildVision.UI.Models; +using EnvDTE; +using Microsoft.VisualStudio; + +namespace BuildVision.Tool.Building +{ + public class BuildManager + { + public BuildActions? BuildAction { get; private set; } + + public BuildScopes? BuildScope { get; private set; } + + public BuildState CurrentBuildState { get; private set; } + + private bool _buildCancelled; + private bool _buildCancelledInternally; + + public BuildManager() + { + //_viewModel.RaiseCommandForSelectedProject += RaiseCommandForSelectedProject; + //_viewModel.ProjectCopyBuildOutputFilesToClipBoard += ProjectCopyBuildOutputFilesToClipBoard; + //_viewModel.ShowGeneralSettingsPage += () => _packageContext.ShowOptionPage(typeof(GeneralSettingsDialogPage)); + //_viewModel.ShowGridColumnsSettingsPage += () => _packageContext.ShowOptionPage(typeof(GridSettingsDialogPage)); + //_viewModel.CopyErrorMessageToClipboard += CopyErrorMessageToClipboard; + } + + public void CancelBuildSolution() + { + RaiseCommand(VSConstants.VSStd97CmdID.CancelBuild); + } + + public void CleanSolution() + { + RaiseCommand(VSConstants.VSStd97CmdID.CleanSln); + } + + public void RebuildSolution() + { + RaiseCommand(VSConstants.VSStd97CmdID.RebuildSln); + } + + public void BuildSolution() + { + RaiseCommand(VSConstants.VSStd97CmdID.BuildSln); + } + + public async Task CancelBuildAsync() + { + if (BuildAction == BuildActions.BuildActionClean) + return; + if (CurrentBuildState != BuildState.InProgress || _buildCancelled || _buildCancelledInternally) + return; + + try + { + // We need to create a separate task here because of some weird things that are going on + // when calling ExecuteCommand directly. Directly calling it leads to a freeze. No need + // for that! + //await _packageContext.ExecuteCommandAsync(CancelBuildCommand); + _buildCancelledInternally = true; + } + catch (Exception ex) + { + ex.Trace("Cancel build failed."); + } + } + + public void RaiseCommandForSelectedProject(UI.Models.ProjectItem selectedProjectItem, int commandId) + { + try + { + SelectProjectInSolutionExplorer(selectedProjectItem); + RaiseCommand((VSConstants.VSStd97CmdID) commandId); + } + catch (Exception ex) + { + ex.TraceUnknownException(); + } + } + + private void SelectProjectInSolutionExplorer(UI.Models.ProjectItem projectItem) + { + var solutionExplorer = Services.Dte2.ToolWindows.SolutionExplorer; + var project = Services.Dte2.Solution.GetProject(x => x.UniqueName == projectItem.UniqueName); + var item = solutionExplorer.FindHierarchyItem(project); + if (item == null) + throw new ProjectNotFoundException($"Project '{projectItem.UniqueName}' not found in SolutionExplorer."); + solutionExplorer.Parent.Activate(); + item.Select(vsUISelectionType.vsUISelectionTypeSelect); + } + + private void ProjectCopyBuildOutputFilesToClipBoard(UI.Models.ProjectItem projItem) + { + try + { + Project project = Services.Dte.Solution.GetProject(x => x.UniqueName == projItem.UniqueName); + BuildOutputFileTypes fileTypes = null; //_packageContext.ControlSettings.ProjectItemSettings.CopyBuildOutputFileTypesToClipboard; + if (fileTypes.IsEmpty) + { + MessageBox.Show(@"Nothing to copy: all file types unchecked.", Resources.ProductName, MessageBoxButton.OK, MessageBoxImage.Error); + return; + } + + string[] filePaths = project.GetBuildOutputFilePaths(fileTypes, projItem.Configuration, projItem.Platform).ToArray(); + if (filePaths.Length == 0) + { + MessageBox.Show(@"Nothing copied: selected build output groups are empty.", Resources.ProductName, MessageBoxButton.OK, MessageBoxImage.Information); + return; + } + + string[] existFilePaths = filePaths.Where(File.Exists).ToArray(); + if (existFilePaths.Length == 0) + { + string msg = GetCopyBuildOutputFilesToClipboardActionMessage("Nothing copied. {0} wasn't found{1}", filePaths); + MessageBox.Show(msg, Resources.ProductName, MessageBoxButton.OK, MessageBoxImage.Warning); + return; + } + + CopyFiles(existFilePaths); + + if (existFilePaths.Length == filePaths.Length) + { + string msg = GetCopyBuildOutputFilesToClipboardActionMessage("Copied {0}{1}", existFilePaths); + MessageBox.Show(msg, Resources.ProductName, MessageBoxButton.OK, MessageBoxImage.Information); + } + else + { + string[] notExistFilePaths = filePaths.Except(existFilePaths).ToArray(); + string copiedMsg = GetCopyBuildOutputFilesToClipboardActionMessage("Copied {0}{1}", existFilePaths); + string notFoundMsg = GetCopyBuildOutputFilesToClipboardActionMessage("{0} wasn't found{1}", notExistFilePaths); + string msg = string.Concat(copiedMsg, Environment.NewLine, Environment.NewLine, notFoundMsg); + MessageBox.Show(msg, Resources.ProductName, MessageBoxButton.OK, MessageBoxImage.Warning); + } + } + catch (Win32Exception ex) + { + string msg = string.Format("Error copying files to the Clipboard: 0x{0:X} ({1})", ex.ErrorCode, ex.Message); + ex.Trace(msg); + MessageBox.Show(msg, Resources.ProductName, MessageBoxButton.OK, MessageBoxImage.Error); + } + catch (Exception ex) + { + ex.TraceUnknownException(); + MessageBox.Show(ex.Message, Resources.ProductName, MessageBoxButton.OK, MessageBoxImage.Error); + } + } + + private void CopyFiles(string[] files) + { + var fileCollection = new StringCollection(); + fileCollection.AddRange(files); + Clipboard.Clear(); + Clipboard.SetFileDropList(fileCollection); + } + + private string GetCopyBuildOutputFilesToClipboardActionMessage(string template, string[] filePaths) + { + const int MaxFilePathLinesInMessage = 30; + const int MaxFilePathLengthInMessage = 60; + + string filesCountArg = string.Concat(filePaths.Length, " file", filePaths.Length == 1 ? string.Empty : "s"); + string filesListArg; + if (filePaths.Length < MaxFilePathLinesInMessage) + { + IEnumerable shortenedFilePaths = FilePathHelper.ShortenPaths(filePaths, MaxFilePathLengthInMessage); + filesListArg = string.Concat(":", Environment.NewLine, string.Join(Environment.NewLine, shortenedFilePaths)); + } + else + { + filesListArg = "."; + } + + string msg = string.Format(template, filesCountArg, filesListArg); + return msg; + } + + private void RaiseCommand(VSConstants.VSStd97CmdID command) + { + Microsoft.VisualStudio.Shell.ThreadHelper.ThrowIfNotOnUIThread(); + try + { + object customIn = null; + object customOut = null; + Services.Dte.Commands.Raise(VSConstants.GUID_VSStandardCommandSet97.ToString(), (int) command, ref customIn, ref customOut); + } + catch (Exception ex) + { + ex.TraceUnknownException(); + } + } + } +} diff --git a/src/BuildVision/Tool/Building/IVsItemLocatorService.cs b/src/BuildVision/Tool/Building/IVsItemLocatorService.cs new file mode 100644 index 00000000..26b1dd07 --- /dev/null +++ b/src/BuildVision/Tool/Building/IVsItemLocatorService.cs @@ -0,0 +1,18 @@ +using BuildVision.Contracts; +using BuildVision.UI; +using BuildVision.UI.Contracts; +using BuildVision.UI.Models; + +namespace BuildVision.Tool.Building +{ + public interface IVsItemLocatorService + { + ProjectItem AddProjectToVisibleProjectsByUniqueName(IBuildVisionPaneViewModel viewModel, string uniqueName); + ProjectItem AddProjectToVisibleProjectsByUniqueName(IBuildVisionPaneViewModel viewModel, string uniqueName, string configuration, string platform); + ProjectItem FindProjectItemInProjectsByUniqueName(IBuildVisionPaneViewModel viewModel, string uniqueName); + ProjectItem FindProjectItemInProjectsByUniqueName(IBuildVisionPaneViewModel viewModel, string uniqueName, string configuration, string platform); + + ProjectItem GetCurrentProject(IBuildVisionPaneViewModel viewModel, BuildScopes? buildScope, string project, string projectconfig, string platform); + bool GetProjectItem(IBuildVisionPaneViewModel viewModel, BuildScopes? buildScope, BuildProjectContextEntry projectEntry, out ProjectItem projectItem); + } +} diff --git a/src/BuildVision/Tool/Building/VsItemLocatorService.cs b/src/BuildVision/Tool/Building/VsItemLocatorService.cs new file mode 100644 index 00000000..6e63a657 --- /dev/null +++ b/src/BuildVision/Tool/Building/VsItemLocatorService.cs @@ -0,0 +1,132 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using BuildVision.Contracts; +using BuildVision.Helpers; +using BuildVision.UI; +using BuildVision.UI.Common.Logging; +using BuildVision.UI.Contracts; +using ProjectItem = BuildVision.UI.Models.ProjectItem; + +namespace BuildVision.Tool.Building +{ + public class VsItemLocatorService : IVsItemLocatorService + { + public ProjectItem FindProjectItemInProjectsByUniqueName(IBuildVisionPaneViewModel viewModel, string uniqueName, string configuration, string platform) + { + return viewModel.ProjectsList.FirstOrDefault(item => item.UniqueName == uniqueName && item.Configuration == configuration && PlatformsIsEquals(item.Platform, platform)); + } + + public ProjectItem FindProjectItemInProjectsByUniqueName(IBuildVisionPaneViewModel viewModel, string uniqueName) + { + return viewModel.ProjectsList.FirstOrDefault(item => item.UniqueName == uniqueName); + } + + public ProjectItem AddProjectToVisibleProjectsByUniqueName(IBuildVisionPaneViewModel viewModel, string uniqueName) + { + var proj = viewModel.SolutionItem.AllProjects.FirstOrDefault(x => x.UniqueName == uniqueName); + if (proj == null) + throw new InvalidOperationException(); + viewModel.ProjectsList.Add(proj); + return proj; + } + + public ProjectItem AddProjectToVisibleProjectsByUniqueName(IBuildVisionPaneViewModel viewModel, string uniqueName, string configuration, string platform) + { + var currentProject = viewModel.SolutionItem.AllProjects.FirstOrDefault(item => item.UniqueName == uniqueName + && item.Configuration == configuration + && PlatformsIsEquals(item.Platform, platform)); + if (currentProject == null) + { + currentProject = viewModel.SolutionItem.AllProjects.FirstOrDefault(x => x.UniqueName == uniqueName); + if (currentProject == null) + throw new InvalidOperationException(); + currentProject = currentProject.GetBatchBuildCopy(configuration, platform); + viewModel.SolutionItem.AllProjects.Add(currentProject); + } + + viewModel.ProjectsList.Add(currentProject); + return currentProject; + } + + private bool PlatformsIsEquals(string platformName1, string platformName2) + { + if (string.Compare(platformName1, platformName2, StringComparison.InvariantCultureIgnoreCase) == 0) + return true; + + // The ambiguity between Project.ActiveConfiguration.PlatformName and + // ProjectStartedEventArgs.ProjectPlatform in Microsoft.Build.Utilities.Logger + // (see BuildOutputLogger). + bool isAnyCpu1 = (platformName1 == "Any CPU" || platformName1 == "AnyCPU"); + bool isAnyCpu2 = (platformName2 == "Any CPU" || platformName2 == "AnyCPU"); + if (isAnyCpu1 && isAnyCpu2) + return true; + + return false; + } + + public ProjectItem GetCurrentProject(IBuildVisionPaneViewModel viewModel, BuildScopes? buildScope, string project, string projectconfig, string platform) + { + ProjectItem currentProject; + if (buildScope == BuildScopes.BuildScopeBatch) + { + currentProject = FindProjectItemInProjectsByUniqueName(viewModel, project, projectconfig, platform); + if (currentProject == null) + throw new InvalidOperationException(); + } + else + { + currentProject = FindProjectItemInProjectsByUniqueName(viewModel, project); + if (currentProject == null) + throw new InvalidOperationException(); + } + + return currentProject; + } + + public bool GetProjectItem(IBuildVisionPaneViewModel viewModel, BuildScopes? buildScope, BuildProjectContextEntry projectEntry, out ProjectItem projectItem) + { + projectItem = projectEntry.ProjectItem; + if (projectItem != null) + return true; + + string projectFile = projectEntry.FileName; + if (ProjectExtensions.IsProjectHidden(projectFile)) + return false; + + var projectProperties = projectEntry.Properties; + var project = viewModel.ProjectsList.FirstOrDefault(x => x.FullName == projectFile); + + + if (buildScope == BuildScopes.BuildScopeBatch && projectProperties.ContainsKey("Configuration") && projectProperties.ContainsKey("Platform")) + { + string projectConfiguration = projectProperties["Configuration"]; + string projectPlatform = projectProperties["Platform"]; + projectItem = FindProjectItemInProjectsByUniqueName(viewModel, project.UniqueName, projectConfiguration, projectPlatform); + if (projectItem == null) + { + TraceManager.Trace( + string.Format("Project Item not found by: UniqueName='{0}', Configuration='{1}, Platform='{2}'.", + project.UniqueName, + projectConfiguration, + projectPlatform), + EventLogEntryType.Warning); + return false; + } + } + else + { + projectItem = FindProjectItemInProjectsByUniqueName(viewModel, project.UniqueName); + if (projectItem == null) + { + TraceManager.Trace(string.Format("Project Item not found by FullName='{0}'.", projectFile), EventLogEntryType.Warning); + return false; + } + } + + projectEntry.ProjectItem = projectItem; + return true; + } + } +} diff --git a/src/BuildVision/Tool/Tool.cs b/src/BuildVision/Tool/Tool.cs deleted file mode 100644 index 56ea5672..00000000 --- a/src/BuildVision/Tool/Tool.cs +++ /dev/null @@ -1,553 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Windows.Controls; - -using EnvDTE; -using Microsoft.VisualStudio.Shell.Interop; - - -using Microsoft.VisualStudio; -using System.Windows; -using System.ComponentModel; -using System.IO; -using BuildVision.Contracts; -using EnvDTE80; -using BuildVision.Common; -using BuildVision.UI; - -using System.Text; -using BuildVision.Core; -using BuildVision.Helpers; -using BuildVision.Views.Settings; -using BuildVision.Tool.Models; -using BuildVision.UI.Contracts; -using BuildVision.UI.ViewModels; -using BuildVision.UI.Common.Logging; -using BuildVision.UI.Models.Indicators.Core; -using BuildVision.UI.Extensions; -using BuildVision.UI.Helpers; -using BuildVision.UI.Models; -using BuildVision.UI.Settings.Models.ToolWindow; -using System.Collections.Specialized; -using Microsoft.VisualStudio.Shell; -using System.Threading; - -using ProjectItem = BuildVision.UI.Models.ProjectItem; -using ErrorItem = BuildVision.Contracts.ErrorItem; -using WindowState = BuildVision.UI.Models.WindowState; -using Task = System.Threading.Tasks.Task; - -namespace BuildVision.Tool -{ - public class Tool - { - private DTE _dte; - private DTE2 _dte2; - private IVsStatusbar _dteStatusBar; - private SolutionEvents _solutionEvents; - - private readonly ToolWindowManager _toolWindowManager; - private readonly IPackageContext _packageContext; - private readonly IBuildInfo _buildContext; - private readonly IBuildDistributor _buildDistributor; - private readonly ControlViewModel _viewModel; - - private bool _buildErrorIsNavigated; - private string _origTextCurrentState; - - public Tool(IPackageContext packageContext, DTE _dte, IVsWindowFrame frame, IBuildInfo buildContext, IBuildDistributor buildDistributor, ControlViewModel viewModel) - { - _toolWindowManager = new ToolWindowManager(_dte, frame); - _packageContext = packageContext; - _buildContext = buildContext; - _buildDistributor = buildDistributor; - _viewModel = viewModel; - } - - public async Task InitializeAsync(Microsoft.VisualStudio.Shell.IAsyncServiceProvider provider, CancellationToken cancellationToken) - { - _dte = await provider.GetServiceAsync(typeof(DTE)) as DTE; - if (_dte == null) - throw new InvalidOperationException("Unable to get DTE instance."); - _dte2 = await provider.GetServiceAsync(typeof(DTE2)) as DTE2; - _dteStatusBar = await provider.GetServiceAsync(typeof(IVsStatusbar)) as IVsStatusbar; - if (_dteStatusBar == null) - TraceManager.TraceError("Unable to get IVsStatusbar instance."); - - _solutionEvents = _dte.Events.SolutionEvents; - - _buildDistributor.OnBuildBegin += (s, e) => BuildEvents_OnBuildBegin(); - _buildDistributor.OnBuildDone += (s, e) => BuildEvents_OnBuildDone(); - _buildDistributor.OnBuildProcess += (s, e) => BuildEvents_OnBuildProcess(); - _buildDistributor.OnBuildCancelled += (s, e) => BuildEvents_OnBuildCancelled(); - _buildDistributor.OnBuildProjectBegin += BuildEvents_OnBuildProjectBegin; - _buildDistributor.OnBuildProjectDone += BuildEvents_OnBuildProjectDone; - _buildDistributor.OnErrorRaised += BuildEvents_OnErrorRaised; - - _solutionEvents.AfterClosing += SolutionEvents_AfterClosing; - _solutionEvents.Opened += SolutionEvents_Opened; - - _viewModel.CancelBuildSolution += () => RaiseCommand(VSConstants.VSStd97CmdID.CancelBuild); - _viewModel.CleanSolution += () => RaiseCommand(VSConstants.VSStd97CmdID.CleanSln); - _viewModel.RebuildSolution += () => RaiseCommand(VSConstants.VSStd97CmdID.RebuildSln); - _viewModel.BuildSolution += () => RaiseCommand(VSConstants.VSStd97CmdID.BuildSln); - _viewModel.RaiseCommandForSelectedProject += RaiseCommandForSelectedProject; - _viewModel.ProjectCopyBuildOutputFilesToClipBoard += ProjectCopyBuildOutputFilesToClipBoard; - _viewModel.ShowGeneralSettingsPage += () => _packageContext.ShowOptionPage(typeof(GeneralSettingsDialogPage)); - _viewModel.ShowGridColumnsSettingsPage += () => _packageContext.ShowOptionPage(typeof(GridSettingsDialogPage)); - _viewModel.CopyErrorMessageToClipboard += CopyErrorMessageToClipboard; - - UpdateSolutionItem(); - } - - private void CopyErrorMessageToClipboard(ProjectItem projectItem) - { - try - { - var errors = new StringBuilder(); - foreach(var errorItem in projectItem.ErrorsBox.Errors) - { - errors.AppendLine(string.Format("{0}({1},{2},{3},{4}): error {5}: {6}", errorItem.File, errorItem.LineNumber, errorItem.ColumnNumber, errorItem.EndLineNumber, errorItem.EndColumnNumber, errorItem.Code, errorItem.Message)); - } - Clipboard.SetText(errors.ToString()); - } - catch (Exception ex) - { - ex.TraceUnknownException(); - } - } - - private void SolutionEvents_Opened() - { - UpdateSolutionItem(); - _viewModel.ResetIndicators(ResetIndicatorMode.ResetValue); - } - - private void SolutionEvents_AfterClosing() - { - _viewModel.TextCurrentState = Resources.BuildDoneText_BuildNotStarted; - _viewModel.ImageCurrentState = VectorResources.TryGet(BuildImages.BuildActionResourcesUri, "StandBy"); - _viewModel.ImageCurrentStateResult = null; - - UpdateSolutionItem(); - _viewModel.ProjectsList.Clear(); - _viewModel.ResetIndicators(ResetIndicatorMode.Disable); - _viewModel.BuildProgressViewModel.ResetTaskBarInfo(); - } - - private void RaiseCommandForSelectedProject(ProjectItem selectedProjectItem, int commandId) - { - try - { - SelectProjectInSolutionExplorer(selectedProjectItem); - RaiseCommand((VSConstants.VSStd97CmdID) commandId); - } - catch (Exception ex) - { - ex.TraceUnknownException(); - } - } - - private void SelectProjectInSolutionExplorer(ProjectItem projectItem) - { - var solutionExplorer = _dte2.ToolWindows.SolutionExplorer; - var project = _dte.Solution.GetProject(x => x.UniqueName == projectItem.UniqueName); - var item = solutionExplorer.FindHierarchyItem(project); - if (item == null) - throw new ProjectNotFoundException($"Project '{projectItem.UniqueName}' not found in SolutionExplorer."); - solutionExplorer.Parent.Activate(); - item.Select(vsUISelectionType.vsUISelectionTypeSelect); - } - - private void ProjectCopyBuildOutputFilesToClipBoard(ProjectItem projItem) - { - try - { - Project project = _dte.Solution.GetProject(x => x.UniqueName == projItem.UniqueName); - BuildOutputFileTypes fileTypes = _packageContext.ControlSettings.ProjectItemSettings.CopyBuildOutputFileTypesToClipboard; - if (fileTypes.IsEmpty) - { - MessageBox.Show(@"Nothing to copy: all file types unchecked.", Resources.ProductName, MessageBoxButton.OK, MessageBoxImage.Error); - return; - } - - string[] filePaths = project.GetBuildOutputFilePaths(fileTypes, projItem.Configuration, projItem.Platform).ToArray(); - if (filePaths.Length == 0) - { - MessageBox.Show(@"Nothing copied: selected build output groups are empty.", Resources.ProductName, MessageBoxButton.OK, MessageBoxImage.Information); - return; - } - - string[] existFilePaths = filePaths.Where(File.Exists).ToArray(); - if (existFilePaths.Length == 0) - { - string msg = GetCopyBuildOutputFilesToClipboardActionMessage("Nothing copied. {0} wasn't found{1}", filePaths); - MessageBox.Show(msg, Resources.ProductName, MessageBoxButton.OK, MessageBoxImage.Warning); - return; - } - - CopyFiles(existFilePaths); - - if (existFilePaths.Length == filePaths.Length) - { - string msg = GetCopyBuildOutputFilesToClipboardActionMessage("Copied {0}{1}", existFilePaths); - MessageBox.Show(msg, Resources.ProductName, MessageBoxButton.OK, MessageBoxImage.Information); - } - else - { - string[] notExistFilePaths = filePaths.Except(existFilePaths).ToArray(); - string copiedMsg = GetCopyBuildOutputFilesToClipboardActionMessage("Copied {0}{1}", existFilePaths); - string notFoundMsg = GetCopyBuildOutputFilesToClipboardActionMessage("{0} wasn't found{1}", notExistFilePaths); - string msg = string.Concat(copiedMsg, Environment.NewLine, Environment.NewLine, notFoundMsg); - MessageBox.Show(msg, Resources.ProductName, MessageBoxButton.OK, MessageBoxImage.Warning); - } - } - catch (Win32Exception ex) - { - string msg = string.Format("Error copying files to the Clipboard: 0x{0:X} ({1})", ex.ErrorCode, ex.Message); - ex.Trace(msg); - MessageBox.Show(msg, Resources.ProductName, MessageBoxButton.OK, MessageBoxImage.Error); - } - catch (Exception ex) - { - ex.TraceUnknownException(); - MessageBox.Show(ex.Message, Resources.ProductName, MessageBoxButton.OK, MessageBoxImage.Error); - } - } - - - private void CopyFiles(string[] files) - { - var fileCollection = new StringCollection(); - fileCollection.AddRange(files); - Clipboard.Clear(); - Clipboard.SetFileDropList(fileCollection); - } - - private string GetCopyBuildOutputFilesToClipboardActionMessage(string template, string[] filePaths) - { - const int MaxFilePathLinesInMessage = 30; - const int MaxFilePathLengthInMessage = 60; - - string filesCountArg = string.Concat(filePaths.Length, " file", filePaths.Length == 1 ? string.Empty : "s"); - string filesListArg; - if (filePaths.Length < MaxFilePathLinesInMessage) - { - IEnumerable shortenedFilePaths = FilePathHelper.ShortenPaths(filePaths, MaxFilePathLengthInMessage); - filesListArg = string.Concat(":", Environment.NewLine, string.Join(Environment.NewLine, shortenedFilePaths)); - } - else - { - filesListArg = "."; - } - - string msg = string.Format(template, filesCountArg, filesListArg); - return msg; - } - - private void RaiseCommand(VSConstants.VSStd97CmdID command) - { - try - { - object customIn = null; - object customOut = null; - _dte.Commands.Raise(VSConstants.GUID_VSStandardCommandSet97.ToString(), (int)command, ref customIn, ref customOut); - } - catch (Exception ex) - { - ex.TraceUnknownException(); - } - } - - private void UpdateSolutionItem() - { - ViewModelHelper.UpdateSolution(_dte.Solution, _viewModel.SolutionItem); - } - - private void BuildEvents_OnBuildProjectBegin(object sender, BuildProjectEventArgs e) - { - try - { - ProjectItem currentProject = e.ProjectItem; - currentProject.State = e.ProjectState; - currentProject.BuildFinishTime = null; - currentProject.BuildStartTime = e.EventTime; - - _viewModel.OnBuildProjectBegin(); - if (_buildContext.BuildScope == BuildScopes.BuildScopeSolution && - (_buildContext.BuildAction == BuildActions.BuildActionBuild || - _buildContext.BuildAction == BuildActions.BuildActionRebuildAll)) - { - currentProject.BuildOrder = _viewModel.BuildProgressViewModel.CurrentQueuePosOfBuildingProject; - } - - if (!_viewModel.ProjectsList.Contains(currentProject)) - _viewModel.ProjectsList.Add(currentProject); - else if (_viewModel.ControlSettings.GeneralSettings.FillProjectListOnBuildBegin) - _viewModel.OnPropertyChanged(nameof(ControlViewModel.GroupedProjectsList)); - _viewModel.CurrentProject = currentProject; - } - catch (Exception ex) - { - ex.TraceUnknownException(); - } - } - - private void BuildEvents_OnBuildProjectDone(object sender, BuildProjectEventArgs e) - { - if (e.ProjectState == ProjectState.BuildError && _viewModel.ControlSettings.GeneralSettings.StopBuildAfterFirstError) - _buildDistributor.CancelBuildAsync(); - - try - { - ProjectItem currentProject = e.ProjectItem; - currentProject.State = e.ProjectState; - currentProject.BuildFinishTime = DateTime.Now; - currentProject.UpdatePostBuildProperties(e.BuildedProjectInfo); - - if (!_viewModel.ProjectsList.Contains(currentProject)) - _viewModel.ProjectsList.Add(currentProject); - - var buildInfo = (IBuildInfo)sender; - if (ReferenceEquals(_viewModel.CurrentProject, e.ProjectItem) && buildInfo.BuildingProjects.Any()) - _viewModel.CurrentProject = buildInfo.BuildingProjects.Last(); - } - catch (Exception ex) - { - ex.TraceUnknownException(); - } - - _viewModel.UpdateIndicators(_buildContext); - - try - { - _viewModel.OnBuildProjectDone(e.BuildedProjectInfo); - } - catch (Exception ex) - { - ex.TraceUnknownException(); - } - } - - private void BuildEvents_OnBuildBegin() - { - try - { - _buildErrorIsNavigated = false; - - ApplyToolWindowStateAction(_viewModel.ControlSettings.WindowSettings.WindowActionOnBuildBegin); - - UpdateSolutionItem(); - - string message = BuildMessages.GetBuildBeginMajorMessage(_viewModel.SolutionItem, _buildContext, _viewModel.ControlSettings.BuildMessagesSettings); - - OutputInStatusBar(message, true); - _viewModel.TextCurrentState = message; - _origTextCurrentState = message; - _viewModel.ImageCurrentState = BuildImages.GetBuildBeginImage(_buildContext); - _viewModel.ImageCurrentStateResult = null; - - ViewModelHelper.UpdateProjects(_viewModel.SolutionItem, _dte.Solution); - _viewModel.ProjectsList.Clear(); - - if (_viewModel.ControlSettings.GeneralSettings.FillProjectListOnBuildBegin) - _viewModel.ProjectsList.AddRange(_viewModel.SolutionItem.AllProjects); - - _viewModel.ResetIndicators(ResetIndicatorMode.ResetValue); - - OnBuildBegin(_buildContext.BuildScope); - } - catch (Exception ex) - { - ex.TraceUnknownException(); - } - } - - public void OnBuildBegin(BuildScopes? buildScope) - { - int projectsCount = -1; - switch (buildScope) - { - case BuildScopes.BuildScopeSolution: - if (_viewModel.ControlSettings.GeneralSettings.FillProjectListOnBuildBegin) - { - projectsCount = _viewModel.ProjectsList.Count; - } - else - { - try - { - Solution solution = _dte.Solution; - if (solution != null) - projectsCount = solution.GetProjects().Count; - } - catch (Exception ex) - { - ex.Trace("Unable to count projects in solution."); - } - } - break; - - case BuildScopes.BuildScopeBatch: - case BuildScopes.BuildScopeProject: - break; - - default: - throw new ArgumentOutOfRangeException(nameof(buildScope)); - } - - _viewModel.OnBuildBegin(projectsCount, _buildContext); - } - - - private void OutputInStatusBar(string str, bool freeze) - { - if (!_viewModel.ControlSettings.GeneralSettings.EnableStatusBarOutput) - return; - - if (_dteStatusBar == null) - return; - - _dteStatusBar.FreezeOutput(0); - _dteStatusBar.SetText(str); - if (freeze) - _dteStatusBar.FreezeOutput(1); - } - - private void BuildEvents_OnBuildProcess() - { - try - { - var labelsSettings = _viewModel.ControlSettings.BuildMessagesSettings; - string msg = _origTextCurrentState + BuildMessages.GetBuildBeginExtraMessage(_buildContext, labelsSettings); - - _viewModel.TextCurrentState = msg; - OutputInStatusBar(msg, true); - - var buildingProjects = _buildContext.BuildingProjects; - for (int i = 0; i < buildingProjects.Count; i++) - buildingProjects[i].RaiseBuildElapsedTimeChanged(); - } - catch (Exception ex) - { - ex.TraceUnknownException(); - } - } - - private void BuildEvents_OnBuildDone() - { - try - { - var settings = _viewModel.ControlSettings; - - if (_buildContext.BuildScope == BuildScopes.BuildScopeSolution) - { - foreach (var projectItem in _viewModel.ProjectsList) - { - if (projectItem.State == ProjectState.Pending) - projectItem.State = ProjectState.Skipped; - } - } - - _viewModel.UpdateIndicators(_buildContext); - - var message = BuildMessages.GetBuildDoneMessage(_viewModel.SolutionItem, _buildContext, settings.BuildMessagesSettings); - var buildDoneImage = BuildImages.GetBuildDoneImage(_buildContext, _viewModel.ProjectsList, out ControlTemplate stateImage); - - OutputInStatusBar(message, false); - _viewModel.TextCurrentState = message; - _viewModel.ImageCurrentState = buildDoneImage; - _viewModel.ImageCurrentStateResult = stateImage; - _viewModel.CurrentProject = null; - _viewModel.OnBuildDone(_buildContext); - - int errorProjectsCount = _viewModel.ProjectsList.Count(item => item.State.IsErrorState()); - if (errorProjectsCount > 0 || _buildContext.BuildIsCancelled) - ApplyToolWindowStateAction(settings.WindowSettings.WindowActionOnBuildError); - else - ApplyToolWindowStateAction(settings.WindowSettings.WindowActionOnBuildSuccess); - - bool navigateToBuildFailureReason = (!_buildContext.BuildedProjects.BuildWithoutErrors - && settings.GeneralSettings.NavigateToBuildFailureReason == NavigateToBuildFailureReasonCondition.OnBuildDone); - if (navigateToBuildFailureReason && _buildContext.BuildedProjects.Any(p => p.ErrorsBox.Errors.Any(NavigateToErrorItem))) - { - _buildErrorIsNavigated = true; - } - } - catch (Exception ex) - { - ex.TraceUnknownException(); - } - } - - private void BuildEvents_OnBuildCancelled() - { - _viewModel.OnBuildCancelled(_buildContext); - } - - private void BuildEvents_OnErrorRaised(object sender, BuildErrorRaisedEventArgs args) - { - bool buildNeedToCancel = (args.ErrorLevel == ErrorLevel.Error && _viewModel.ControlSettings.GeneralSettings.StopBuildAfterFirstError); - if (buildNeedToCancel) - _buildDistributor.CancelBuildAsync(); - - bool navigateToBuildFailureReason = (!_buildErrorIsNavigated - && args.ErrorLevel == ErrorLevel.Error - && _viewModel.ControlSettings.GeneralSettings.NavigateToBuildFailureReason == NavigateToBuildFailureReasonCondition.OnErrorRaised); - if (navigateToBuildFailureReason && args.ProjectInfo.ErrorsBox.Errors.Any(NavigateToErrorItem)) - { - _buildErrorIsNavigated = true; - } - } - - private bool NavigateToErrorItem(ErrorItem errorItem) - { - if (string.IsNullOrEmpty(errorItem?.File) || string.IsNullOrEmpty(errorItem?.ProjectFile)) - return false; - - try - { - var projectItem = _viewModel.ProjectsList.FirstOrDefault(x => x.FullName == errorItem.ProjectFile); - if (projectItem == null) - return false; - - - var project = _dte.Solution.GetProject(x => x.UniqueName == projectItem.UniqueName); - if (project == null) - return false; - - return project.NavigateToErrorItem(errorItem); - } - catch (Exception ex) - { - ex.Trace("Navigate to error item exception"); - return true; - } - } - - private void ApplyToolWindowStateAction(WindowStateAction windowStateAction) - { - switch (windowStateAction.State) - { - case WindowState.Nothing: - break; - case WindowState.Show: - _toolWindowManager.Show(); - break; - case WindowState.ShowNoActivate: - _toolWindowManager.ShowNoActivate(); - break; - case WindowState.Hide: - _toolWindowManager.Hide(); - break; - case WindowState.Close: - _toolWindowManager.Close(); - break; - default: - throw new ArgumentOutOfRangeException(nameof(windowStateAction)); - } - } - } -} diff --git a/src/BuildVision/Tool/Views/Settings/IPackageSettingsProvider.cs b/src/BuildVision/Tool/Views/Settings/IPackageSettingsProvider.cs new file mode 100644 index 00000000..6ea186a1 --- /dev/null +++ b/src/BuildVision/Tool/Views/Settings/IPackageSettingsProvider.cs @@ -0,0 +1,12 @@ +using System.ComponentModel; +using BuildVision.UI.Settings.Models; + +namespace BuildVision.Views.Settings +{ + public interface IPackageSettingsProvider : INotifyPropertyChanged + { + void Save(); + + ControlSettings Settings { get; } + } +} diff --git a/src/BuildVision/Tool/Views/Settings/PackageSettingsProvider.cs b/src/BuildVision/Tool/Views/Settings/PackageSettingsProvider.cs new file mode 100644 index 00000000..d1eb6106 --- /dev/null +++ b/src/BuildVision/Tool/Views/Settings/PackageSettingsProvider.cs @@ -0,0 +1,64 @@ +using System; +using System.ComponentModel; +using System.Diagnostics; +using System.Windows; +using BuildVision.Common; +using BuildVision.UI.Settings.Models; +using Microsoft.VisualStudio.Settings; +using Microsoft.VisualStudio.Shell.Settings; +using BuildVision.UI.Common.Logging; +using BuildVision.Core; + +namespace BuildVision.Views.Settings +{ + public class PackageSettingsProvider : BindableBase, IPackageSettingsProvider + { + private const string settingsCategoryName = "BuildVision"; + private const string settingsPropertyName = "Settings"; + + readonly WritableSettingsStore _settingsStore; + + public ControlSettings Settings { get; set; } + + public PackageSettingsProvider(IServiceProvider serviceProvider) + { + var shellSettingsManager = new ShellSettingsManager(serviceProvider); + _settingsStore = shellSettingsManager.GetWritableSettingsStore(SettingsScope.UserSettings); + + LoadSettings(); + } + + public void Save() + { + SaveSettings(); + } + + private void SaveSettings() + { + if (!_settingsStore.CollectionExists(settingsCategoryName)) + _settingsStore.CreateCollection(settingsCategoryName); + + var legacySerializer = new LegacyConfigurationSerializer(); + var value = legacySerializer.Serialize(Settings); + _settingsStore.SetString(settingsCategoryName, settingsPropertyName, value); + } + + private void LoadSettings() + { + try + { + if (_settingsStore.PropertyExists(settingsCategoryName, settingsPropertyName)) + { + var legacySerialized = new LegacyConfigurationSerializer(); + var value = _settingsStore.GetString(settingsCategoryName, settingsPropertyName); + Settings = legacySerialized.Deserialize(value); + } + } + catch (Exception ex) + { + ex.Trace("Error when trying to load settings: " + ex.Message, EventLogEntryType.Error); + MessageBox.Show("An error occurred when trying to load current settings. To make sure everything is still working the settings are set to default."); + } + } + } +} diff --git a/src/BuildVision/Tool/Views/Settings/SettingsDialogPage.cs b/src/BuildVision/Tool/Views/Settings/SettingsDialogPage.cs index c1982693..809f3fb4 100644 --- a/src/BuildVision/Tool/Views/Settings/SettingsDialogPage.cs +++ b/src/BuildVision/Tool/Views/Settings/SettingsDialogPage.cs @@ -10,14 +10,15 @@ namespace BuildVision.Views.Settings { public abstract class SettingsDialogPage : UIElementDialogPage - where TControl : FrameworkElement, new() + where TControl : FrameworkElement, new() where TSettings : SettingsBase, new() - { + { private static bool _notifySettingsChangedOnce; private TSettings _editSettings; private FrameworkElement _ctrl; + private IPackageSettingsProvider _packageSettingsProvider; protected abstract TSettings Settings { get; set; } @@ -37,6 +38,7 @@ protected override void OnActivate(CancelEventArgs e) if (_ctrl.DataContext == null) _ctrl.DataContext = _editSettings; + _packageSettingsProvider = Services.DefaultExportProvider.GetExportedValue(); base.OnActivate(e); } @@ -46,7 +48,7 @@ protected override void OnApply(PageApplyEventArgs args) { _notifySettingsChangedOnce = true; Settings = _editSettings; - Package.SaveSettings(); + _packageSettingsProvider.Save(); } base.OnApply(args); @@ -55,13 +57,13 @@ protected override void OnApply(PageApplyEventArgs args) protected override void OnClosed(EventArgs e) { _editSettings = null; - if(_ctrl != null) + if (_ctrl != null) _ctrl.DataContext = null; if (_notifySettingsChangedOnce) { _notifySettingsChangedOnce = false; - Package.NotifyControlSettingsChanged(); + //Package.NotifyControlSettingsChanged(); } base.OnClosed(e); @@ -70,22 +72,11 @@ protected override void OnClosed(EventArgs e) public override void ResetSettings() { Settings = new TSettings(); - Package.SaveSettings(); - Package.NotifyControlSettingsChanged(); + _packageSettingsProvider.Save(); base.ResetSettings(); } - protected ControlSettings ControlSettings => Package.ControlSettings; - - protected IPackageContext Package - { - get - { - var package = (IPackageContext)GetService(typeof(BuildVisionPackage)); - Debug.Assert(package != null); - return package; - } - } + protected ControlSettings ControlSettings => _packageSettingsProvider.Settings; } } diff --git a/src/BuildVision/source.extension.vsixmanifest b/src/BuildVision/source.extension.vsixmanifest index 4e624fd4..5b5c8004 100644 --- a/src/BuildVision/source.extension.vsixmanifest +++ b/src/BuildVision/source.extension.vsixmanifest @@ -20,5 +20,6 @@ + From 3a680f86bfc549543df2acf434ea03d8ab86aeeb Mon Sep 17 00:00:00 2001 From: Stefan Kert Date: Mon, 7 Jan 2019 07:10:04 +0100 Subject: [PATCH 006/100] Added further extension methods to make them more readable. Preparing for 3.0 -> IVsUpdateSolutionEvents --- src/BuildVision/BuildVision.csproj | 2 + src/BuildVision/Core/BuildVisionPackage.cs | 83 +++++++++++++++++-- .../Helpers/BuildEventContextExtensions.cs | 15 ++++ .../BuildMessageEventArgsExtensions.cs | 15 ++++ .../Helpers/SolutionProjectsExtensions.cs | 1 + src/BuildVision/Tool/BuildVisionPane.cs | 2 +- src/BuildVision/Tool/Building/BuildContext.cs | 21 +---- .../Tool/Building/BuildOutputLogger.cs | 4 +- 8 files changed, 115 insertions(+), 28 deletions(-) create mode 100644 src/BuildVision/Helpers/BuildEventContextExtensions.cs create mode 100644 src/BuildVision/Helpers/BuildMessageEventArgsExtensions.cs diff --git a/src/BuildVision/BuildVision.csproj b/src/BuildVision/BuildVision.csproj index db62b6ee..8023631c 100644 --- a/src/BuildVision/BuildVision.csproj +++ b/src/BuildVision/BuildVision.csproj @@ -97,6 +97,8 @@ + + diff --git a/src/BuildVision/Core/BuildVisionPackage.cs b/src/BuildVision/Core/BuildVisionPackage.cs index acd181c0..a078ffb9 100644 --- a/src/BuildVision/Core/BuildVisionPackage.cs +++ b/src/BuildVision/Core/BuildVisionPackage.cs @@ -22,6 +22,7 @@ using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; using Microsoft.VisualStudio.Shell.Settings; +using VSLangProj; using Task = System.Threading.Tasks.Task; namespace BuildVision.Core @@ -38,22 +39,26 @@ namespace BuildVision.Core // This attribute registers a tool window exposed by this package. [ProvideToolWindow(typeof(BuildVisionPane))] [Guid(PackageGuids.GuidBuildVisionPackageString)] - [ProvideAutoLoad(VSConstants.UICONTEXT.SolutionOpening_string, PackageAutoLoadFlags.BackgroundLoad)] + //[ProvideAutoLoad(VSConstants.UICONTEXT.SolutionOpening_string, PackageAutoLoadFlags.BackgroundLoad)] [ProvideBindingPath] [ProvideBindingPath(SubPath = "Lib")] // TODO: Add ProvideProfileAttribute for each DialogPage and implement IVsUserSettings, IVsUserSettingsQuery. - //// [ProvideProfile(typeof(GeneralSettingsDialogPage), SettingsCategoryName, "General Options", 0, 0, true)] + [ProvideProfile(typeof(GeneralSettingsDialogPage), SettingsCategoryName, "General Options", 0, 0, true)] // TODO: ProvideOptionPage keywords. [ProvideOptionPage(typeof(GeneralSettingsDialogPage), "BuildVision", "General", 0, 0, true)] [ProvideOptionPage(typeof(WindowSettingsDialogPage), "BuildVision", "Tool Window", 0, 0, true)] [ProvideOptionPage(typeof(GridSettingsDialogPage), "BuildVision", "Projects Grid", 0, 0, true)] [ProvideOptionPage(typeof(BuildMessagesSettingsDialogPage), "BuildVision", "Build Messages", 0, 0, true)] [ProvideOptionPage(typeof(ProjectItemSettingsDialogPage), "BuildVision", "Project Item", 0, 0, true)] - public sealed partial class BuildVisionPackage : AsyncPackage, IPackageContext + public sealed partial class BuildVisionPackage : AsyncPackage, IPackageContext, IVsUpdateSolutionEvents2 { private DTE _dte; private SolutionEvents _solutionEvents; private BuildVisionPaneViewModel _viewModel; + private IVsSolutionBuildManager2 _solutionBuildManager; + private uint _updateSolutionEventsCookie; + + private IVsSolution2 _vsSolution; public ControlSettings ControlSettings { get; set; } @@ -76,23 +81,44 @@ protected override async Task InitializeAsync(CancellationToken cancellationToke mcs.AddCommand(menuToolWin); } + _solutionBuildManager = ServiceProvider.GlobalProvider.GetService(typeof(SVsSolutionBuildManager)) as IVsSolutionBuildManager2; + if (_solutionBuildManager != null) + { + _solutionBuildManager.AdviseUpdateSolutionEvents(this, out _updateSolutionEventsCookie); + } + _solutionEvents = _dte.Events.SolutionEvents; _solutionEvents.AfterClosing += SolutionEvents_AfterClosing; _solutionEvents.Opened += SolutionEvents_Opened; - var toolWindow = GetWindowPane(typeof(BuildVisionPane)); + //var toolWindow = GetWindowPane(typeof(BuildVisionPane)); IPackageContext packageContext = this; - _viewModel = BuildVisionPane.GetViewModel(toolWindow); - ViewModelHelper.UpdateSolution(_dte.Solution, _viewModel.SolutionItem); + //_viewModel = BuildVisionPane.GetViewModel(toolWindow); + //ViewModelHelper.UpdateSolution(_dte.Solution, _viewModel.SolutionItem); //var buildContext = new BuildContext(packageContext, _dte, _dte.Events.BuildEvents, _dte.Events.WindowEvents, _dte.Events.CommandEvents, viewModel); } private void SolutionEvents_Opened() { + SetVsSolution(); + ViewModelHelper.UpdateSolution(_dte.Solution, _viewModel.SolutionItem); _viewModel.ResetIndicators(ResetIndicatorMode.ResetValue); } + private void SetVsSolution() + { + if (_vsSolution == null) + _vsSolution = ServiceProvider.GlobalProvider.GetService(typeof(SVsSolution)) as IVsSolution2; + } + + private Project GetProject(IVsHierarchy pHierProj) + { + object objProj; + pHierProj.GetProperty(VSConstants.VSITEMID_ROOT, (int) __VSHPROPID.VSHPROPID_ExtObject, out objProj); + return objProj as Project; + } + private void SolutionEvents_AfterClosing() { _viewModel.TextCurrentState = Resources.BuildDoneText_BuildNotStarted; @@ -141,5 +167,50 @@ public async Task ExecuteCommandAsync(string commandName) await JoinableTaskFactory.SwitchToMainThreadAsync(DisposalToken); _dte.ExecuteCommand(commandName); } + + public int UpdateSolution_Begin(ref int pfCancelUpdate) + { + Console.WriteLine($"UpdateSolution_Begin"); + return 0; + } + + public int UpdateSolution_Done(int fSucceeded, int fModified, int fCancelCommand) + { + Console.WriteLine($"UpdateSolution_Done: fSucceeded {fSucceeded}, fModified {fModified}, fCancelCommand {fCancelCommand}"); + return 0; + } + + public int UpdateSolution_StartUpdate(ref int pfCancelUpdate) + { + Console.WriteLine($"UpdateSolution_StartUpdate"); + return 0; + } + + public int UpdateSolution_Cancel() + { + Console.WriteLine($"UpdateSolution_Cancel"); + return 0; + } + + public int OnActiveProjectCfgChange(IVsHierarchy pIVsHierarchy) + { + var proj = GetProject(pIVsHierarchy); + Console.WriteLine($"OnActiveProjectCfgChange {proj.UniqueName}"); + return 0; + } + + public int UpdateProjectCfg_Begin(IVsHierarchy pHierProj, IVsCfg pCfgProj, IVsCfg pCfgSln, uint dwAction, ref int pfCancel) + { + var proj = GetProject(pHierProj); + Console.WriteLine($"UpdateProjectCfg_Begin {proj.UniqueName}"); + return 0; + } + + public int UpdateProjectCfg_Done(IVsHierarchy pHierProj, IVsCfg pCfgProj, IVsCfg pCfgSln, uint dwAction, int fSuccess, int fCancel) + { + var proj = GetProject(pHierProj); + Console.WriteLine($"UpdateProjectCfg_Done {proj.UniqueName}: dwAction {dwAction}, fSuccess {fSuccess}, fCancel {fCancel}"); + return 0; + } } } diff --git a/src/BuildVision/Helpers/BuildEventContextExtensions.cs b/src/BuildVision/Helpers/BuildEventContextExtensions.cs new file mode 100644 index 00000000..a709ddd4 --- /dev/null +++ b/src/BuildVision/Helpers/BuildEventContextExtensions.cs @@ -0,0 +1,15 @@ +using Microsoft.Build.Framework; + +namespace BuildVision.Helpers +{ + public static class BuildEventContextExtensions + { + public static bool IsBuildEventContextInvalid(this BuildEventContext bec) + { + return (bec == null + || bec == BuildEventContext.Invalid + || bec.ProjectContextId == BuildEventContext.InvalidProjectContextId + || bec.ProjectInstanceId == BuildEventContext.InvalidProjectInstanceId); + } + } +} diff --git a/src/BuildVision/Helpers/BuildMessageEventArgsExtensions.cs b/src/BuildVision/Helpers/BuildMessageEventArgsExtensions.cs new file mode 100644 index 00000000..5882e5d6 --- /dev/null +++ b/src/BuildVision/Helpers/BuildMessageEventArgsExtensions.cs @@ -0,0 +1,15 @@ +using BuildVision.Tool.Building; +using Microsoft.Build.Framework; + +namespace BuildVision.Helpers +{ + public static class BuildMessageEventArgsExtensions + { + public static bool IsUserMessage(this BuildMessageEventArgs message, BuildOutputLogger loggerSender) + { + return (message.Importance == MessageImportance.High && loggerSender.IsVerbosityAtLeast(LoggerVerbosity.Minimal)) + || (message.Importance == MessageImportance.Normal && loggerSender.IsVerbosityAtLeast(LoggerVerbosity.Normal)) + || (message.Importance == MessageImportance.Low && loggerSender.IsVerbosityAtLeast(LoggerVerbosity.Detailed)); + } + } +} diff --git a/src/BuildVision/Helpers/SolutionProjectsExtensions.cs b/src/BuildVision/Helpers/SolutionProjectsExtensions.cs index de225fd7..4c199fcf 100644 --- a/src/BuildVision/Helpers/SolutionProjectsExtensions.cs +++ b/src/BuildVision/Helpers/SolutionProjectsExtensions.cs @@ -4,6 +4,7 @@ using IServiceProvider = Microsoft.VisualStudio.OLE.Interop.IServiceProvider; using System.Runtime.InteropServices; using EnvDTE80; +using BuildVision.UI.Helpers; namespace BuildVision.Helpers { diff --git a/src/BuildVision/Tool/BuildVisionPane.cs b/src/BuildVision/Tool/BuildVisionPane.cs index 433fedf9..52094631 100644 --- a/src/BuildVision/Tool/BuildVisionPane.cs +++ b/src/BuildVision/Tool/BuildVisionPane.cs @@ -74,7 +74,7 @@ protected override void OnClose() private ControlView CreateControlView() { var packageContext = (IPackageContext)Package; - var viewModel = new BuildVisionPaneViewModel(new ControlModel(), null);//packageContext.ControlSettings); + var viewModel = new BuildVisionPaneViewModel(new ControlModel(), new UI.Settings.Models.ControlSettings());//packageContext.ControlSettings); packageContext.ControlSettingsChanged += (settings) => { viewModel.OnControlSettingsChanged(settings, buildInfo => BuildMessages.GetBuildDoneMessage(viewModel.SolutionItem, buildInfo, viewModel.ControlSettings.BuildMessagesSettings)); diff --git a/src/BuildVision/Tool/Building/BuildContext.cs b/src/BuildVision/Tool/Building/BuildContext.cs index ef85b630..8f4b1762 100644 --- a/src/BuildVision/Tool/Building/BuildContext.cs +++ b/src/BuildVision/Tool/Building/BuildContext.cs @@ -37,7 +37,6 @@ public class BuildContext : IBuildInfo, IBuildDistributor private const int BuildInProcessQuantumSleep = 50; private const string CancelBuildCommand = "Build.Cancel"; - private IVsStatusbar _dteStatusBar; private readonly object _buildingProjectsLockObject; private readonly object _buildProcessLockObject = new object(); private readonly IVsItemLocatorService _locatorService; @@ -101,13 +100,6 @@ public BuildContext(IVsItemLocatorService locatorService, IStatusBarNotification _commandEvents.AfterExecute += CommandEvents_AfterExecute; } - public async Task InitializeAsync(Microsoft.VisualStudio.Shell.IAsyncServiceProvider provider, CancellationToken cancellationToken) - { - _dteStatusBar = await provider.GetServiceAsync(typeof(IVsStatusbar)) as IVsStatusbar; - if (_dteStatusBar == null) - TraceManager.TraceError("Unable to get IVsStatusbar instance."); - } - public void OverrideBuildProperties(BuildActions? buildAction = null, BuildScopes? buildScope = null) { BuildAction = buildAction ?? BuildAction; @@ -158,22 +150,13 @@ private void RegisterLogger() private bool VerifyLoggerBuildEvent(BuildOutputLogger loggerSender, BuildEventArgs eventArgs, ErrorLevel errorLevel) { - var bec = eventArgs.BuildEventContext; - bool becIsInvalid = (bec == null - || bec == BuildEventContext.Invalid - || bec.ProjectContextId == BuildEventContext.InvalidProjectContextId - || bec.ProjectInstanceId == BuildEventContext.InvalidProjectInstanceId); - if (becIsInvalid) + if (eventArgs.BuildEventContext.IsBuildEventContextInvalid()) return false; if (errorLevel == ErrorLevel.Message) { var messageEventArgs = (BuildMessageEventArgs)eventArgs; - bool isUserMessage = (messageEventArgs.Importance == MessageImportance.High && loggerSender.IsVerbosityAtLeast(LoggerVerbosity.Minimal)) - || (messageEventArgs.Importance == MessageImportance.Normal && loggerSender.IsVerbosityAtLeast(LoggerVerbosity.Normal)) - || (messageEventArgs.Importance == MessageImportance.Low && loggerSender.IsVerbosityAtLeast(LoggerVerbosity.Detailed)); - - if (!isUserMessage) + if (!messageEventArgs.IsUserMessage(loggerSender)) return false; } diff --git a/src/BuildVision/Tool/Building/BuildOutputLogger.cs b/src/BuildVision/Tool/Building/BuildOutputLogger.cs index 6dad77f2..2b700d00 100644 --- a/src/BuildVision/Tool/Building/BuildOutputLogger.cs +++ b/src/BuildVision/Tool/Building/BuildOutputLogger.cs @@ -56,7 +56,7 @@ public static RegisterLoggerResult Register(Guid loggerId, LoggerVerbosity logge | BindingFlags.Public | BindingFlags.Instance; - BuildManager buildManager = BuildManager.DefaultBuildManager; + var buildManager = Microsoft.Build.Execution.BuildManager.DefaultBuildManager; Type buildHostType = buildManager.GetType().Assembly.GetType("Microsoft.Build.BackEnd.IBuildComponentHost"); PropertyInfo loggingSeviceProperty = buildHostType.GetProperty("LoggingService", InterfacePropertyFlags); @@ -98,4 +98,4 @@ public static RegisterLoggerResult Register(Guid loggerId, LoggerVerbosity logge } } } -} \ No newline at end of file +} From 0b1f15d1b5f2f8a2c24239ee815b4798963bb1e8 Mon Sep 17 00:00:00 2001 From: Stefan Kert Date: Mon, 14 Jan 2019 06:09:40 +0100 Subject: [PATCH 007/100] Further improvement for several entities. Starting to move to IVsUpdateSolutionEvents --- .../BuildVision.Contracts.csproj | 1 + src/BuildVision.Contracts/ErrorItem.cs | 154 +++++++++++------- src/BuildVision/BuildVision.csproj | 1 + src/BuildVision/Core/BuildVisionPackage.cs | 78 +++------ src/BuildVision/Core/SolutionBuildEvents.cs | 85 ++++++++++ src/BuildVision/Tool/Building/BuildContext.cs | 123 +------------- .../Tool/Building/BuildOutputLogger.cs | 100 ++++++++++-- .../Views/Settings/PackageSettingsProvider.cs | 4 +- 8 files changed, 298 insertions(+), 248 deletions(-) create mode 100644 src/BuildVision/Core/SolutionBuildEvents.cs diff --git a/src/BuildVision.Contracts/BuildVision.Contracts.csproj b/src/BuildVision.Contracts/BuildVision.Contracts.csproj index ae2b2b0f..40096121 100644 --- a/src/BuildVision.Contracts/BuildVision.Contracts.csproj +++ b/src/BuildVision.Contracts/BuildVision.Contracts.csproj @@ -37,6 +37,7 @@ Key.snk + diff --git a/src/BuildVision.Contracts/ErrorItem.cs b/src/BuildVision.Contracts/ErrorItem.cs index 9b95c7f2..8625dd97 100644 --- a/src/BuildVision.Contracts/ErrorItem.cs +++ b/src/BuildVision.Contracts/ErrorItem.cs @@ -1,87 +1,127 @@ using System; using System.Collections.Generic; using System.IO; +using Microsoft.Build.Framework; namespace BuildVision.Contracts { - public class ErrorItem - { - public const string DefaultSortPropertyName = "Number"; - private readonly List _invalidFileNames = new List { "CSC", "MSBUILD", "LINK" }; + public class ErrorItem + { + public const string DefaultSortPropertyName = "Number"; + private readonly List _invalidFileNames = new List { "CSC", "MSBUILD", "LINK" }; - public bool CanNavigateTo { get; set; } + public bool CanNavigateTo { get; set; } - public int? Number { get; set; } + public int? Number { get; set; } - public ErrorLevel Level { get; set; } + public ErrorLevel Level { get; set; } - public string Code { get; set; } + public string Code { get; set; } - public string File { get; set; } + public string File { get; set; } - public string FileName - { - get - { - try - { - return Path.GetFileName(File); - } - catch (ArgumentException) + public string FileName { - return File; + get + { + try + { + return Path.GetFileName(File); + } + catch (ArgumentException) + { + return File; + } + } } - } - } - public string ProjectFile { get; set; } + public string ProjectFile { get; set; } - public int LineNumber { get; set; } - public int ColumnNumber { get; set; } + public int LineNumber { get; set; } + public int ColumnNumber { get; set; } - public int EndLineNumber { get; set; } + public int EndLineNumber { get; set; } - public int EndColumnNumber { get; set; } + public int EndColumnNumber { get; set; } - public string Subcategory { get; set; } + public string Subcategory { get; set; } - public string Message { get; set; } + public string Message { get; set; } - public Action GoToError { get; } + public Action GoToError { get; } - public ErrorItem(ErrorLevel errorLevel, Action goToError) - { - Level = errorLevel; - GoToError = () => goToError(this); - } + public ErrorItem(ErrorLevel errorLevel, Action goToError) + { + Level = errorLevel; + GoToError = () => goToError(this); + } - public ErrorItem() { } + public ErrorItem() { } - // 1. EnvDTE.TextSelection.MoveToLineAndOffset requires line and offset numbers beginning at one. - // BuildErrorEventArgs.LineNumber and BuildErrorEventArgs.ColumnNumber may be uninitialized. - // 2. BuildErrorEventArgs.EndLineNumber and BuildErrorEventArgs.EndColumnNumber may be uninitialized, - // regardless of BuildErrorEventArgs.LineNumber and BuildErrorEventArgs.ColumnNumber. - public void VerifyValues() - { - if (_invalidFileNames.Contains(File) && LineNumber == 0 && ColumnNumber == 0) - { - CanNavigateTo = false; - return; - } - if (LineNumber < 1) - LineNumber = 1; + public void Init(BuildErrorEventArgs e) + { + Code = e.Code; + File = e.File; + ProjectFile = e.ProjectFile; + LineNumber = e.LineNumber; + ColumnNumber = e.ColumnNumber; + EndLineNumber = e.EndLineNumber; + EndColumnNumber = e.EndColumnNumber; + Subcategory = e.Subcategory; + Message = e.Message; + } + + public void Init(BuildWarningEventArgs e) + { + Code = e.Code; + File = e.File; + ProjectFile = e.ProjectFile; + LineNumber = e.LineNumber; + ColumnNumber = e.ColumnNumber; + EndLineNumber = e.EndLineNumber; + EndColumnNumber = e.EndColumnNumber; + Subcategory = e.Subcategory; + Message = e.Message; + } + + public void Init(BuildMessageEventArgs e) + { + Code = e.Code; + File = e.File; + ProjectFile = e.ProjectFile; + LineNumber = e.LineNumber; + ColumnNumber = e.ColumnNumber; + EndLineNumber = e.EndLineNumber; + EndColumnNumber = e.EndColumnNumber; + Subcategory = e.Subcategory; + Message = e.Message; + } + // 1. EnvDTE.TextSelection.MoveToLineAndOffset requires line and offset numbers beginning at one. + // BuildErrorEventArgs.LineNumber and BuildErrorEventArgs.ColumnNumber may be uninitialized. + // 2. BuildErrorEventArgs.EndLineNumber and BuildErrorEventArgs.EndColumnNumber may be uninitialized, + // regardless of BuildErrorEventArgs.LineNumber and BuildErrorEventArgs.ColumnNumber. + public void VerifyValues() + { + if (_invalidFileNames.Contains(File) && LineNumber == 0 && ColumnNumber == 0) + { + CanNavigateTo = false; + return; + } - if (ColumnNumber < 1) - ColumnNumber = 1; + if (LineNumber < 1) + LineNumber = 1; - if (EndLineNumber == 0 && EndColumnNumber == 0) - { - EndLineNumber = LineNumber; - EndColumnNumber = ColumnNumber; - } + if (ColumnNumber < 1) + ColumnNumber = 1; - CanNavigateTo = true; + if (EndLineNumber == 0 && EndColumnNumber == 0) + { + EndLineNumber = LineNumber; + EndColumnNumber = ColumnNumber; + } + + CanNavigateTo = true; + } } - } } diff --git a/src/BuildVision/BuildVision.csproj b/src/BuildVision/BuildVision.csproj index 8023631c..16ea8712 100644 --- a/src/BuildVision/BuildVision.csproj +++ b/src/BuildVision/BuildVision.csproj @@ -96,6 +96,7 @@ + diff --git a/src/BuildVision/Core/BuildVisionPackage.cs b/src/BuildVision/Core/BuildVisionPackage.cs index a078ffb9..405015af 100644 --- a/src/BuildVision/Core/BuildVisionPackage.cs +++ b/src/BuildVision/Core/BuildVisionPackage.cs @@ -5,6 +5,7 @@ using System.Threading; using System.Windows; using BuildVision.Common; +using BuildVision.Contracts; using BuildVision.Tool; using BuildVision.Tool.Building; using BuildVision.Tool.Models; @@ -43,21 +44,22 @@ namespace BuildVision.Core [ProvideBindingPath] [ProvideBindingPath(SubPath = "Lib")] // TODO: Add ProvideProfileAttribute for each DialogPage and implement IVsUserSettings, IVsUserSettingsQuery. - [ProvideProfile(typeof(GeneralSettingsDialogPage), SettingsCategoryName, "General Options", 0, 0, true)] + [ProvideProfile(typeof(GeneralSettingsDialogPage), PackageSettingsProvider.settingsCategoryName, "General Options", 0, 0, true)] // TODO: ProvideOptionPage keywords. [ProvideOptionPage(typeof(GeneralSettingsDialogPage), "BuildVision", "General", 0, 0, true)] [ProvideOptionPage(typeof(WindowSettingsDialogPage), "BuildVision", "Tool Window", 0, 0, true)] [ProvideOptionPage(typeof(GridSettingsDialogPage), "BuildVision", "Projects Grid", 0, 0, true)] [ProvideOptionPage(typeof(BuildMessagesSettingsDialogPage), "BuildVision", "Build Messages", 0, 0, true)] [ProvideOptionPage(typeof(ProjectItemSettingsDialogPage), "BuildVision", "Project Item", 0, 0, true)] - public sealed partial class BuildVisionPackage : AsyncPackage, IPackageContext, IVsUpdateSolutionEvents2 + public sealed partial class BuildVisionPackage : AsyncPackage, IPackageContext { private DTE _dte; private SolutionEvents _solutionEvents; private BuildVisionPaneViewModel _viewModel; private IVsSolutionBuildManager2 _solutionBuildManager; private uint _updateSolutionEventsCookie; - + private readonly Guid _parsingErrorsLoggerId = new Guid("{64822131-DC4D-4087-B292-61F7E06A7B39}"); + private BuildOutputLogger _buildLogger; private IVsSolution2 _vsSolution; public ControlSettings ControlSettings { get; set; } @@ -84,7 +86,7 @@ protected override async Task InitializeAsync(CancellationToken cancellationToke _solutionBuildManager = ServiceProvider.GlobalProvider.GetService(typeof(SVsSolutionBuildManager)) as IVsSolutionBuildManager2; if (_solutionBuildManager != null) { - _solutionBuildManager.AdviseUpdateSolutionEvents(this, out _updateSolutionEventsCookie); + _solutionBuildManager.AdviseUpdateSolutionEvents(new SolutionBuildEvents(), out _updateSolutionEventsCookie); } _solutionEvents = _dte.Events.SolutionEvents; @@ -96,10 +98,22 @@ protected override async Task InitializeAsync(CancellationToken cancellationToke //_viewModel = BuildVisionPane.GetViewModel(toolWindow); //ViewModelHelper.UpdateSolution(_dte.Solution, _viewModel.SolutionItem); //var buildContext = new BuildContext(packageContext, _dte, _dte.Events.BuildEvents, _dte.Events.WindowEvents, _dte.Events.CommandEvents, viewModel); + + _dte.Events.BuildEvents.OnBuildBegin += (scope, args) => { RegisterLogger(); }; + } + + private void RegisterLogger() + { + var result = BuildOutputLogger.Register(_parsingErrorsLoggerId, Microsoft.Build.Framework.LoggerVerbosity.Quiet, out _buildLogger); + if (result == RegisterLoggerResult.AlreadyExists) + { + _buildLogger.Projects?.Clear(); + } } private void SolutionEvents_Opened() { + ThreadHelper.ThrowIfNotOnUIThread(); SetVsSolution(); ViewModelHelper.UpdateSolution(_dte.Solution, _viewModel.SolutionItem); @@ -108,19 +122,16 @@ private void SolutionEvents_Opened() private void SetVsSolution() { + ThreadHelper.ThrowIfNotOnUIThread(); if (_vsSolution == null) _vsSolution = ServiceProvider.GlobalProvider.GetService(typeof(SVsSolution)) as IVsSolution2; } - private Project GetProject(IVsHierarchy pHierProj) - { - object objProj; - pHierProj.GetProperty(VSConstants.VSITEMID_ROOT, (int) __VSHPROPID.VSHPROPID_ExtObject, out objProj); - return objProj as Project; - } - private void SolutionEvents_AfterClosing() { + ThreadHelper.ThrowIfNotOnUIThread(); + SetVsSolution(); + _viewModel.TextCurrentState = Resources.BuildDoneText_BuildNotStarted; _viewModel.ImageCurrentState = VectorResources.TryGet(BuildImages.BuildActionResourcesUri, "StandBy"); _viewModel.ImageCurrentStateResult = null; @@ -167,50 +178,5 @@ public async Task ExecuteCommandAsync(string commandName) await JoinableTaskFactory.SwitchToMainThreadAsync(DisposalToken); _dte.ExecuteCommand(commandName); } - - public int UpdateSolution_Begin(ref int pfCancelUpdate) - { - Console.WriteLine($"UpdateSolution_Begin"); - return 0; - } - - public int UpdateSolution_Done(int fSucceeded, int fModified, int fCancelCommand) - { - Console.WriteLine($"UpdateSolution_Done: fSucceeded {fSucceeded}, fModified {fModified}, fCancelCommand {fCancelCommand}"); - return 0; - } - - public int UpdateSolution_StartUpdate(ref int pfCancelUpdate) - { - Console.WriteLine($"UpdateSolution_StartUpdate"); - return 0; - } - - public int UpdateSolution_Cancel() - { - Console.WriteLine($"UpdateSolution_Cancel"); - return 0; - } - - public int OnActiveProjectCfgChange(IVsHierarchy pIVsHierarchy) - { - var proj = GetProject(pIVsHierarchy); - Console.WriteLine($"OnActiveProjectCfgChange {proj.UniqueName}"); - return 0; - } - - public int UpdateProjectCfg_Begin(IVsHierarchy pHierProj, IVsCfg pCfgProj, IVsCfg pCfgSln, uint dwAction, ref int pfCancel) - { - var proj = GetProject(pHierProj); - Console.WriteLine($"UpdateProjectCfg_Begin {proj.UniqueName}"); - return 0; - } - - public int UpdateProjectCfg_Done(IVsHierarchy pHierProj, IVsCfg pCfgProj, IVsCfg pCfgSln, uint dwAction, int fSuccess, int fCancel) - { - var proj = GetProject(pHierProj); - Console.WriteLine($"UpdateProjectCfg_Done {proj.UniqueName}: dwAction {dwAction}, fSuccess {fSuccess}, fCancel {fCancel}"); - return 0; - } } } diff --git a/src/BuildVision/Core/SolutionBuildEvents.cs b/src/BuildVision/Core/SolutionBuildEvents.cs new file mode 100644 index 00000000..5979ee6a --- /dev/null +++ b/src/BuildVision/Core/SolutionBuildEvents.cs @@ -0,0 +1,85 @@ +using System; +using System.Diagnostics; +using System.Threading; +using BuildVision.Contracts; +using BuildVision.Tool.Building; +using BuildVision.UI.Common.Logging; +using BuildVision.UI.Contracts; +using BuildVision.UI.ViewModels; +using EnvDTE; +using Microsoft.VisualStudio; +using Microsoft.VisualStudio.Shell; +using Microsoft.VisualStudio.Shell.Interop; + +namespace BuildVision.Core +{ + public class SolutionBuildEvents : IVsUpdateSolutionEvents2 + { + private bool _buildCancelled; + private bool _buildCancelledInternally; + private CancellationTokenSource _buildProcessCancellationToken; + private BuildOutputLogger _buildLogger; + private readonly Guid _parsingErrorsLoggerId = new Guid("{64822131-DC4D-4087-B292-61F7E06A7B39}"); + + public BuildState CurrentBuildState { get; private set; } + public DateTime BuildStartTime { get; private set; } + public DateTime BuildFinishTime { get; private set; } + public BuildActions BuildAction { get; private set; } + public BuildScopes BuildScope { get; private set; } + + private Project GetProject(IVsHierarchy pHierProj) + { + ThreadHelper.ThrowIfNotOnUIThread(); + pHierProj.GetProperty(VSConstants.VSITEMID_ROOT, (int) __VSHPROPID.VSHPROPID_ExtObject, out var objProj); + return objProj as Project; + } + + public int UpdateSolution_Begin(ref int pfCancelUpdate) + { + Debug.WriteLine($"UpdateSolution_Begin"); + return 0; + } + + public int UpdateSolution_Done(int fSucceeded, int fModified, int fCancelCommand) + { + Console.WriteLine($"UpdateSolution_Done: fSucceeded {fSucceeded}, fModified {fModified}, fCancelCommand {fCancelCommand}"); + return 0; + } + + public int UpdateSolution_StartUpdate(ref int pfCancelUpdate) + { + + Debug.WriteLine($"UpdateSolution_StartUpdate"); + return 0; + } + + public int UpdateSolution_Cancel() + { + Debug.WriteLine($"UpdateSolution_Cancel"); + return 0; + } + + public int OnActiveProjectCfgChange(IVsHierarchy pIVsHierarchy) + { + var proj = GetProject(pIVsHierarchy); + Debug.WriteLine($"OnActiveProjectCfgChange {proj.UniqueName}"); + + return 0; + } + + public int UpdateProjectCfg_Begin(IVsHierarchy pHierProj, IVsCfg pCfgProj, IVsCfg pCfgSln, uint dwAction, ref int pfCancel) + { + var proj = GetProject(pHierProj); + Debug.WriteLine($"UpdateProjectCfg_Begin {proj.UniqueName} (IsDirty: {proj.IsDirty}): dwAction {(VSSOLNBUILDUPDATEFLAGS) dwAction} ({dwAction})"); + return 0; + } + + public int UpdateProjectCfg_Done(IVsHierarchy pHierProj, IVsCfg pCfgProj, IVsCfg pCfgSln, uint dwAction, int fSuccess, int fCancel) + { + var projects = _buildLogger.Projects; + var proj = GetProject(pHierProj); + Debug.WriteLine($"UpdateProjectCfg_Done {proj.UniqueName} (IsDirty: {proj.IsDirty}): dwAction {(VSSOLNBUILDUPDATEFLAGS)dwAction} ({dwAction}), fSuccess {fSuccess}, fCancel {fCancel}"); + return 0; + } + } +} diff --git a/src/BuildVision/Tool/Building/BuildContext.cs b/src/BuildVision/Tool/Building/BuildContext.cs index 8f4b1762..a17521a5 100644 --- a/src/BuildVision/Tool/Building/BuildContext.cs +++ b/src/BuildVision/Tool/Building/BuildContext.cs @@ -41,7 +41,6 @@ public class BuildContext : IBuildInfo, IBuildDistributor private readonly object _buildProcessLockObject = new object(); private readonly IVsItemLocatorService _locatorService; private readonly IStatusBarNotificationService _statusBarNotificationService; - private readonly IStatusBarNotificationService statusBarNotificationService; private readonly IPackageContext _packageContext; private readonly DTE _dte; private readonly Solution _solution; @@ -135,132 +134,12 @@ private void RegisterLogger() const LoggerVerbosity LoggerVerbosity = LoggerVerbosity.Quiet; RegisterLoggerResult result = BuildOutputLogger.Register(_parsingErrorsLoggerId, LoggerVerbosity, out _buildLogger); - if (result == RegisterLoggerResult.RegisterSuccess) - { - var eventSource = _buildLogger.EventSource; - eventSource.MessageRaised += (s, e) => EventSource_ErrorRaised(_buildLogger, e, ErrorLevel.Message); - eventSource.WarningRaised += (s, e) => EventSource_ErrorRaised(_buildLogger, e, ErrorLevel.Warning); - eventSource.ErrorRaised += (s, e) => EventSource_ErrorRaised(_buildLogger, e, ErrorLevel.Error); - } - else if (result == RegisterLoggerResult.AlreadyExists) + if (result == RegisterLoggerResult.AlreadyExists) { _buildLogger.Projects?.Clear(); } } - private bool VerifyLoggerBuildEvent(BuildOutputLogger loggerSender, BuildEventArgs eventArgs, ErrorLevel errorLevel) - { - if (eventArgs.BuildEventContext.IsBuildEventContextInvalid()) - return false; - - if (errorLevel == ErrorLevel.Message) - { - var messageEventArgs = (BuildMessageEventArgs)eventArgs; - if (!messageEventArgs.IsUserMessage(loggerSender)) - return false; - } - - return true; - } - - private void EventSource_ErrorRaised(BuildOutputLogger loggerSender, LazyFormattedBuildEventArgs e, ErrorLevel errorLevel) - { - try - { - bool verified = VerifyLoggerBuildEvent(loggerSender, e, errorLevel); - if (!verified) - return; - - int projectInstanceId = e.BuildEventContext.ProjectInstanceId; - int projectContextId = e.BuildEventContext.ProjectContextId; - - var projectEntry = loggerSender.Projects.Find(t => t.InstanceId == projectInstanceId && t.ContextId == projectContextId); - if (projectEntry == null) - { - TraceManager.Trace(string.Format("Project entry not found by ProjectInstanceId='{0}' and ProjectContextId='{1}'.", projectInstanceId, projectContextId), EventLogEntryType.Warning); - return; - } - if (projectEntry.IsInvalid) - return; - - if (!_locatorService.GetProjectItem(_viewModel, BuildScope, projectEntry, out var projectItem)) - { - projectEntry.IsInvalid = true; - return; - } - - BuildedProject buildedProject = BuildedProjects[projectItem]; - var errorItem = new ErrorItem(errorLevel, (eI) => - { - _dte.Solution.GetProject(x => x.UniqueName == projectItem.UniqueName).NavigateToErrorItem(eI); - }); - - switch (errorLevel) - { - case ErrorLevel.Message: - Init(errorItem, (BuildMessageEventArgs)e); - break; - - case ErrorLevel.Warning: - Init(errorItem, (BuildWarningEventArgs)e); - break; - - case ErrorLevel.Error: - Init(errorItem, (BuildErrorEventArgs)e); - break; - - default: - throw new ArgumentOutOfRangeException("errorLevel"); - } - errorItem.VerifyValues(); - buildedProject.ErrorsBox.Add(errorItem); - OnErrorRaised(this, new BuildErrorRaisedEventArgs(errorLevel, buildedProject)); - } - catch (Exception ex) - { - ex.TraceUnknownException(); - } - } - - private void Init(ErrorItem item, BuildErrorEventArgs e) - { - item.Code = e.Code; - item.File = e.File; - item.ProjectFile = e.ProjectFile; - item.LineNumber = e.LineNumber; - item.ColumnNumber = e.ColumnNumber; - item.EndLineNumber = e.EndLineNumber; - item.EndColumnNumber = e.EndColumnNumber; - item.Subcategory = e.Subcategory; - item.Message = e.Message; - } - - private void Init(ErrorItem item, BuildWarningEventArgs e) - { - item.Code = e.Code; - item.File = e.File; - item.ProjectFile = e.ProjectFile; - item.LineNumber = e.LineNumber; - item.ColumnNumber = e.ColumnNumber; - item.EndLineNumber = e.EndLineNumber; - item.EndColumnNumber = e.EndColumnNumber; - item.Subcategory = e.Subcategory; - item.Message = e.Message; - } - - private void Init(ErrorItem item, BuildMessageEventArgs e) - { - item.Code = e.Code; - item.File = e.File; - item.ProjectFile = e.ProjectFile; - item.LineNumber = e.LineNumber; - item.ColumnNumber = e.ColumnNumber; - item.EndLineNumber = e.EndLineNumber; - item.EndColumnNumber = e.EndColumnNumber; - item.Subcategory = e.Subcategory; - item.Message = e.Message; - } - private void CommandEvents_AfterExecute(string guid, int id, object customIn, object customOut) { if (id == (int)VSConstants.VSStd97CmdID.CancelBuild diff --git a/src/BuildVision/Tool/Building/BuildOutputLogger.cs b/src/BuildVision/Tool/Building/BuildOutputLogger.cs index 2b700d00..1dce08ea 100644 --- a/src/BuildVision/Tool/Building/BuildOutputLogger.cs +++ b/src/BuildVision/Tool/Building/BuildOutputLogger.cs @@ -9,34 +9,36 @@ using BuildVision.Contracts; using BuildVision.UI.Contracts; using BuildVision.UI.Common.Logging; +using BuildVision.Helpers; +using BuildVision.UI.ViewModels; +using BuildVision.Core; namespace BuildVision.Tool.Building { public class BuildOutputLogger : Logger { - private IEventSource _eventSource; + private List _projects; private readonly Guid _id; + private readonly IVsItemLocatorService _locatorService; + private readonly BuildVisionPaneViewModel _viewModel; - private BuildOutputLogger(Guid id) + private BuildOutputLogger(Guid id, IVsItemLocatorService locatorService = null, BuildVisionPaneViewModel viewModel = null) { _id = id; + _locatorService = locatorService; + _viewModel = viewModel; } - public IEventSource EventSource => _eventSource; public List Projects => _projects; public override void Initialize(IEventSource eventSource) { - _eventSource = eventSource; - if (_eventSource == null) - { - TraceManager.TraceError("Unexpected value of BuildOutputLogger.EventSource: null"); - return; - } - _projects = new List(); - _eventSource.ProjectStarted += OnProjectStarted; + eventSource.ProjectStarted += OnProjectStarted; + eventSource.MessageRaised += (s, e) => EventSource_ErrorRaised(s, e, ErrorLevel.Message); + eventSource.WarningRaised += (s, e) => EventSource_ErrorRaised(s, e, ErrorLevel.Warning); + eventSource.ErrorRaised += (s, e) => EventSource_ErrorRaised(s, e, ErrorLevel.Error); } private void OnProjectStarted(object sender, ProjectStartedEventArgs e) @@ -60,6 +62,8 @@ public static RegisterLoggerResult Register(Guid loggerId, LoggerVerbosity logge Type buildHostType = buildManager.GetType().Assembly.GetType("Microsoft.Build.BackEnd.IBuildComponentHost"); PropertyInfo loggingSeviceProperty = buildHostType.GetProperty("LoggingService", InterfacePropertyFlags); + + object loggingServiceObj; try { @@ -97,5 +101,79 @@ public static RegisterLoggerResult Register(Guid loggerId, LoggerVerbosity logge return RegisterLoggerResult.FatalError; } } + + private void EventSource_ErrorRaised(object sender, BuildEventArgs e, ErrorLevel errorLevel) + { + try + { + bool verified = VerifyLoggerBuildEvent(e, errorLevel); + if (!verified) + return; + + int projectInstanceId = e.BuildEventContext.ProjectInstanceId; + int projectContextId = e.BuildEventContext.ProjectContextId; + + var projectEntry = Projects.Find(t => t.InstanceId == projectInstanceId && t.ContextId == projectContextId); + if (projectEntry == null) + { + //TraceManager.Trace(string.Format("Project entry not found by ProjectInstanceId='{0}' and ProjectContextId='{1}'.", projectInstanceId, projectContextId), EventLogEntryType.Warning); + return; + } + if (projectEntry.IsInvalid) + return; + + //if (!_locatorService.GetProjectItem(_viewModel, BuildScope, projectEntry, out var projectItem)) + //{ + // projectEntry.IsInvalid = true; + // return; + //} + + //BuildedProject buildedProject = BuildedProjects[projectItem]; + //var errorItem = new ErrorItem(errorLevel, (eI) => + //{ + // Services.Dte.Solution.GetProject(x => x.UniqueName == projectItem.UniqueName).NavigateToErrorItem(eI); + //}); + + //switch (errorLevel) + //{ + // case ErrorLevel.Message: + // errorItem.Init((BuildMessageEventArgs) e); + // break; + + // case ErrorLevel.Warning: + // errorItem.Init((BuildWarningEventArgs) e); + // break; + + // case ErrorLevel.Error: + // errorItem.Init((BuildErrorEventArgs) e); + // break; + + // default: + // throw new ArgumentOutOfRangeException("errorLevel"); + //} + //errorItem.VerifyValues(); + //buildedProject.ErrorsBox.Add(errorItem); + //OnErrorRaised(this, new BuildErrorRaisedEventArgs(errorLevel, buildedProject)); + } + catch (Exception ex) + { + ex.TraceUnknownException(); + } + } + + private bool VerifyLoggerBuildEvent(BuildEventArgs eventArgs, ErrorLevel errorLevel) + { + if (eventArgs.BuildEventContext.IsBuildEventContextInvalid()) + return false; + + if (errorLevel == ErrorLevel.Message) + { + var messageEventArgs = (BuildMessageEventArgs) eventArgs; + if (!messageEventArgs.IsUserMessage(this)) + return false; + } + + return true; + } } } diff --git a/src/BuildVision/Tool/Views/Settings/PackageSettingsProvider.cs b/src/BuildVision/Tool/Views/Settings/PackageSettingsProvider.cs index d1eb6106..0a6b9f65 100644 --- a/src/BuildVision/Tool/Views/Settings/PackageSettingsProvider.cs +++ b/src/BuildVision/Tool/Views/Settings/PackageSettingsProvider.cs @@ -13,8 +13,8 @@ namespace BuildVision.Views.Settings { public class PackageSettingsProvider : BindableBase, IPackageSettingsProvider { - private const string settingsCategoryName = "BuildVision"; - private const string settingsPropertyName = "Settings"; + public const string settingsCategoryName = "BuildVision"; + public const string settingsPropertyName = "Settings"; readonly WritableSettingsStore _settingsStore; From f227aa986c3a929c4c939e1a93e96745bb227b64 Mon Sep 17 00:00:00 2001 From: Stefan Kert Date: Fri, 8 Mar 2019 11:41:02 +0100 Subject: [PATCH 008/100] Fixed integrationtests --- .../Microsoft.VSSDK.TestHostFramework.dll | Bin 0 -> 26672 bytes ...lStudio.QualityTools.UnitTestFramework.dll | Bin 0 -> 98344 bytes ...soft.VisualStudioTools.VSTestHost.15.0.dll | Bin 0 -> 63280 bytes .../Core/ServiceProviderExports.cs | 1 - src/BuildVision/Core/Services.cs | 1 - .../Tool/Building/BuildOutputLogger.cs | 6 +- .../BuildVision.IntegrationTests.csproj | 112 ++++++------------ .../PackageTests.cs | 82 ++++++------- .../Properties/AssemblyInfo.cs | 16 --- tools/PrepareMachine.ps1 | 1 + tools/VSTestHost.VS2017/InstallInVS2017.ps1 | 75 ++++++++++++ ...soft.VisualStudioTools.VSTestHost.15.0.dll | Bin 0 -> 63280 bytes ...t.VisualStudioTools.VSTestHost.15.0.pkgdef | Bin 0 -> 3586 bytes .../vs2017.testsettings.template | 55 +++++++++ 14 files changed, 207 insertions(+), 142 deletions(-) create mode 100644 libs/2017/Microsoft.VSSDK.TestHostFramework.dll create mode 100644 libs/2017/Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll create mode 100644 libs/2017/Microsoft.VisualStudioTools.VSTestHost.15.0.dll delete mode 100644 test/BuildVision.IntegrationTests/Properties/AssemblyInfo.cs create mode 100644 tools/PrepareMachine.ps1 create mode 100644 tools/VSTestHost.VS2017/InstallInVS2017.ps1 create mode 100644 tools/VSTestHost.VS2017/Microsoft.VisualStudioTools.VSTestHost.15.0.dll create mode 100644 tools/VSTestHost.VS2017/Microsoft.VisualStudioTools.VSTestHost.15.0.pkgdef create mode 100644 tools/VSTestHost.VS2017/vs2017.testsettings.template diff --git a/libs/2017/Microsoft.VSSDK.TestHostFramework.dll b/libs/2017/Microsoft.VSSDK.TestHostFramework.dll new file mode 100644 index 0000000000000000000000000000000000000000..9ad0b1819002ae828ea3989f0a8e4f62c3402ee5 GIT binary patch literal 26672 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 KP$0%ttj{5kU!rCCVN^P%DIFfJl;uGl>cc4T`8= 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�d=eE&~R=3NFxnFb48%%8*5u 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 literal 0 HcmV?d00001 diff --git a/libs/2017/Microsoft.VisualStudioTools.VSTestHost.15.0.dll b/libs/2017/Microsoft.VisualStudioTools.VSTestHost.15.0.dll new file mode 100644 index 0000000000000000000000000000000000000000..03fdd0437baab34ecb1557e672fcd301bbae0af2 GIT binary patch literal 63280 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 literal 0 HcmV?d00001 diff --git a/src/BuildVision/Core/ServiceProviderExports.cs b/src/BuildVision/Core/ServiceProviderExports.cs index 48021e07..ea3bacb1 100644 --- a/src/BuildVision/Core/ServiceProviderExports.cs +++ b/src/BuildVision/Core/ServiceProviderExports.cs @@ -18,6 +18,5 @@ public ServiceProviderExports([Import(typeof(SVsServiceProvider))] IServiceProvi [Export] public IPackageSettingsProvider PackageSettingsProvider => (IPackageSettingsProvider) _serviceProvider.GetService(typeof(IPackageSettingsProvider)); - } } diff --git a/src/BuildVision/Core/Services.cs b/src/BuildVision/Core/Services.cs index 732e9be8..3aa95827 100644 --- a/src/BuildVision/Core/Services.cs +++ b/src/BuildVision/Core/Services.cs @@ -8,7 +8,6 @@ namespace BuildVision.Core { - public static class Services { static TResult GetGlobalService(IServiceProvider provider = null) where T : class where TResult : class diff --git a/src/BuildVision/Tool/Building/BuildOutputLogger.cs b/src/BuildVision/Tool/Building/BuildOutputLogger.cs index 1dce08ea..a2024d48 100644 --- a/src/BuildVision/Tool/Building/BuildOutputLogger.cs +++ b/src/BuildVision/Tool/Building/BuildOutputLogger.cs @@ -142,6 +142,9 @@ private void EventSource_ErrorRaised(object sender, BuildEventArgs e, ErrorLevel // case ErrorLevel.Warning: // errorItem.Init((BuildWarningEventArgs) e); + // throw new ArgumentOutOfRangeException("errorLevel"); + //} + //errorItem.VerifyValues(); // break; // case ErrorLevel.Error: @@ -149,9 +152,6 @@ private void EventSource_ErrorRaised(object sender, BuildEventArgs e, ErrorLevel // break; // default: - // throw new ArgumentOutOfRangeException("errorLevel"); - //} - //errorItem.VerifyValues(); //buildedProject.ErrorsBox.Add(errorItem); //OnErrorRaised(this, new BuildErrorRaisedEventArgs(errorLevel, buildedProject)); } diff --git a/test/BuildVision.IntegrationTests/BuildVision.IntegrationTests.csproj b/test/BuildVision.IntegrationTests/BuildVision.IntegrationTests.csproj index daf81711..beee67a3 100644 --- a/test/BuildVision.IntegrationTests/BuildVision.IntegrationTests.csproj +++ b/test/BuildVision.IntegrationTests/BuildVision.IntegrationTests.csproj @@ -1,82 +1,38 @@ - - - + - Debug - AnyCPU - {FBB4F3ED-B1B8-4401-8667-5180194BAA54} - Library - Properties - BuildVision.IntegrationTests - BuildVision.IntegrationTests - v4.7.2 - 512 - {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - 15.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages - False - UnitTest - - - + net472 + true - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - - - - - - - - - - - - - - - - {9925a635-1827-4bb4-9c31-fe0fc87a6265} - BuildVision - - - - - 8.0.2 - - - 8.0.3 - - - 15.0.27 - - - 1.4.0 - - - 7.0.3303 - + + + + + + + + + + - - + + + + + + + + + + + + ..\..\libs\2017\Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll + + + ..\..\libs\2017\Microsoft.VisualStudioTools.VSTestHost.15.0.dll + + + ..\..\libs\2017\Microsoft.VSSDK.TestHostFramework.dll + + + \ No newline at end of file diff --git a/test/BuildVision.IntegrationTests/PackageTests.cs b/test/BuildVision.IntegrationTests/PackageTests.cs index 3f590412..737dbb11 100644 --- a/test/BuildVision.IntegrationTests/PackageTests.cs +++ b/test/BuildVision.IntegrationTests/PackageTests.cs @@ -1,58 +1,54 @@ using System; using Microsoft.VisualStudio.Shell.Interop; -using Microsoft.VisualStudio.TestTools.UnitTesting; -//using Microsoft.VSSDK.Tools.VsIdeTesting; using System.ComponentModel.Design; -using EnvDTE; -using Microsoft.VisualStudio; using BuildVision.Core; +using Microsoft.VSSDK.Tools.VsIdeTesting; +using Microsoft.VisualStudio; +using Xunit; +using System.Linq; +using System.Diagnostics; +using EnvDTE; +[assembly: VsixRunner(TraceLevel = SourceLevels.All)] namespace BuildVision.IntegrationTests { - [TestClass] public class PackageTests { - //private static IVsShell ShellService => VsIdeTestHostContext.ServiceProvider.GetService(typeof(SVsShell)) as IVsShell; - //private static IVsUIShell UiShellService => VsIdeTestHostContext.ServiceProvider.GetService(typeof(SVsUIShell)) as IVsUIShell; + private static IVsShell ShellService => GlobalServices.GetService() as IVsShell; + private static IVsUIShell UiShellService => GlobalServices.GetService() as IVsUIShell; + private static DTE DTE => GlobalServices.GetService() as DTE; + + [VsixFact(VisualStudioVersion.Current, RootSuffix = "Exp")] + public void PackageLoad_Should_Succeed() + { + IVsPackage package; + var packageGuid = PackageGuids.GuidBuildVisionPackage; + var packageLoaded = ShellService.LoadPackage(ref packageGuid, out package); - //[Ignore] - //[TestMethod] - //[HostType("VS IDE")] - //public void PackageLoad_Should_Succeed() - //{ - // UIThreadInvoker.Invoke(new Action(() => - // { - // var guid = PackageGuids.GuidBuildVisionPackage; - // Assert.IsTrue(0 == ShellService.LoadPackage(ref guid, out var package)); - // Assert.IsNotNull(package, "Package failed to load"); - // })); - //} + Assert.Equal(0, packageLoaded); + Assert.NotNull(package); + } - //[Ignore] - //[TestMethod] - //[HostType("VS IDE")] - //public void ClickOnBuildVisionMenuItem_Should_ShowBuildVision() - //{ - // UIThreadInvoker.Invoke(new Action(() => - // { - // var toolwndCommandId = new CommandID(PackageGuids.GuidBuildVisionCmdSet, (int) PackageIds.CmdIdBuildVisionToolWindow); - // ExecuteCommand(toolwndCommandId); - // Assert.IsTrue(CanFindToolwindow(PackageGuids.GuidBuildVisionToolWindow)); - // })); - //} + [VsixFact(VisualStudioVersion.Current, RootSuffix = "Exp")] + public void ClickOnBuildVisionMenuItem_Should_ShowBuildVision() + { + var toolwndCommandId = new CommandID(PackageGuids.GuidBuildVisionCmdSet, (int) PackageIds.CmdIdBuildVisionToolWindow); + ExecuteCommand(toolwndCommandId); + Assert.True(CanFindToolwindow(PackageGuids.GuidBuildVisionToolWindow)); + } - //public static void ExecuteCommand(CommandID cmd) - //{ - // object customin = null; - // object customout = null; - // VsIdeTestHostContext.Dte.Commands.Raise(cmd.Guid.ToString("B").ToUpper(), cmd.ID, ref customin, ref customout); - //} + private static void ExecuteCommand(CommandID cmd) + { + object customin = null; + object customout = null; + DTE.Commands.Raise(cmd.Guid.ToString("B").ToUpper(), cmd.ID, ref customin, ref customout); + } - //public static bool CanFindToolwindow(Guid persistenceGuid) - //{ - // //var hr = UiShellService.FindToolWindow((uint) __VSFINDTOOLWIN.FTW_fFindFirst, ref persistenceGuid, out var windowFrame); - // //Assert.IsTrue(hr == VSConstants.S_OK); - // //return (windowFrame != null); - //} + private static bool CanFindToolwindow(Guid persistenceGuid) + { + var hr = UiShellService.FindToolWindow((uint) __VSFINDTOOLWIN.FTW_fFindFirst, ref persistenceGuid, out var windowFrame); + Assert.True(hr == VSConstants.S_OK); + return (windowFrame != null); + } } } diff --git a/test/BuildVision.IntegrationTests/Properties/AssemblyInfo.cs b/test/BuildVision.IntegrationTests/Properties/AssemblyInfo.cs deleted file mode 100644 index 7f2fa353..00000000 --- a/test/BuildVision.IntegrationTests/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -[assembly: AssemblyTitle("BuildVision.IntegrationTests")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("BuildVision.IntegrationTests")] -[assembly: AssemblyCopyright("Copyright © 2018")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -[assembly: ComVisible(false)] - -[assembly: Guid("fbb4f3ed-b1b8-4401-8667-5180194baa54")] diff --git a/tools/PrepareMachine.ps1 b/tools/PrepareMachine.ps1 new file mode 100644 index 00000000..9cf25ae2 --- /dev/null +++ b/tools/PrepareMachine.ps1 @@ -0,0 +1 @@ +.\VSTestHost.VS2017\InstallInVS2017.ps1 -vs "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise" \ No newline at end of file diff --git a/tools/VSTestHost.VS2017/InstallInVS2017.ps1 b/tools/VSTestHost.VS2017/InstallInVS2017.ps1 new file mode 100644 index 00000000..f8960dac --- /dev/null +++ b/tools/VSTestHost.VS2017/InstallInVS2017.ps1 @@ -0,0 +1,75 @@ +param($vs) + +$source = $MyInvocation.MyCommand.Definition | Split-Path -Parent + +if (-not $vs) { + $vs = [Environment]::GetEnvironmentVariable("VisualStudio_15.0") +} +if (-not $vs) { + throw "-vs option must be specified" +} +if (-not (Test-Path $vs)) { + throw "specified path -vs $vs does not exist" +} +if (-not (Test-Path "$vs\Common7\IDE\devenv.exe")) { + throw "specified path -vs $vs does not contain a Visual Studio installation" +} + +if (-not (Test-Path "$source\Microsoft.VisualStudioTools.VSTestHost.15.0.dll") -or + -not (Test-Path "$source\Microsoft.VisualStudioTools.VSTestHost.15.0.pkgdef")) { + throw "expected VSTestHost files in $source" +} + +"Installing VSTestHost from $source" +copy "$source\Microsoft.VisualStudioTools.VSTestHost.15.0.dll" "$vs\Common7\IDE\CommonExtensions\Platform" -Force +copy "$source\Microsoft.VisualStudioTools.VSTestHost.15.0.pkgdef" "$vs\Common7\IDE\CommonExtensions\Platform" -Force + +"Updating *.exe.config files" +gci @( + "$vs\Common7\IDE\MSTest.exe.config", + "$vs\Common7\IDE\QTAgent*.exe.config", + "$vs\Common7\IDE\CommonExtensions\Microsoft\TestWindow\vstest.*.exe.config" +) | ?{ Test-Path $_ } | %{ + $conf = [xml](gc $_); + if (-not $conf.configuration.runtime.assemblyBinding.probing.privatePath.Contains("CommonExtensions\Microsoft\Editor")) { + $conf.configuration.runtime.assemblyBinding.probing.privatePath += ";CommonExtensions\Platform;CommonExtensions\Microsoft\Editor"; + + $n = $conf.configuration.runtime.assemblyBinding.AppendChild($conf.ImportNode(([xml]' + + + + ').dependentAssembly, $true)); + + $conf.Save("$_"); + " - $($_.Name)" + } +} + +"Executing devenv /setup" +Start-Process -Wait -NoNewWindow "$vs\Common7\IDE\devenv.exe" "/setup" + +"Generating testsettings files" +$ts = [xml](gc "$source\vs2017.testsettings.template") +foreach ($n in $ts.TestSettings.Execution.TestTypeSpecific.UnitTestRunConfig.AssemblyResolution.RuntimeResolution.Directory) { + $n.path = $n.path -replace '\$VSPath', "$vs"; + $n.path = $n.path -replace '\$VSVersion', "15.0"; +} +foreach ($n in $ts.TestSettings.Execution.TestTypeSpecific.UnitTestRunConfig.AssemblyResolution.DiscoveryResolution.Directory) { + $n.path = $n.path -replace '\$VSPath', "$vs"; + $n.path = $n.path -replace '\$VSVersion', "15.0"; +} +foreach ($n in $ts.TestSettings.Properties.Property) { + $n.value = $n.value -replace '\$VSPath', "$vs"; + $n.value = $n.value -replace '\$VSVersion', "15.0"; +} +$ts.Save("$vs\vstesthost.testsettings") +" - $vs\vstesthost.testsettings" + +foreach ($n in $ts.TestSettings.Properties.Property) { + if ($n.name -eq "VSHive") { + $n.value = "Exp"; + } +} +$ts.Save("$vs\vstesthost.exp.testsettings") +" - $vs\vstesthost.exp.testsettings" +"" diff --git a/tools/VSTestHost.VS2017/Microsoft.VisualStudioTools.VSTestHost.15.0.dll b/tools/VSTestHost.VS2017/Microsoft.VisualStudioTools.VSTestHost.15.0.dll new file mode 100644 index 0000000000000000000000000000000000000000..03fdd0437baab34ecb1557e672fcd301bbae0af2 GIT binary patch literal 63280 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 literal 0 HcmV?d00001 diff --git a/tools/VSTestHost.VS2017/Microsoft.VisualStudioTools.VSTestHost.15.0.pkgdef b/tools/VSTestHost.VS2017/Microsoft.VisualStudioTools.VSTestHost.15.0.pkgdef new file mode 100644 index 0000000000000000000000000000000000000000..eae6598d65240836b68cc404cbe7695c3b248cf5 GIT binary patch literal 3586 zcmd^?ZBG+H5Xa}WiQl0)cxjuqTq$QlVl5B}5D`#gtS@NqN*Ze0(4rxRude?7yKJ8< zXh2kn}+_(m! z9p)dp9NQ=7^=&%<=`t$^eAn$QF|^H7fOnrK=%|C_DOd(H57?>YbPmC= z4cZ0br~~~HzAk%>n5C@ri7iE?JRzPxW3Aw#bmY$5bJC0XX0Z<^tGQEU_LXSr67}BV z<(^NGsEB)EIV=#uLuXl!Xbdz(W8kS{d)Faw0rw`zXRM5n6E@oAkZ+w=DEe#_O6Txt z&nCLoK()eKf^gUoXYpOFZg}wv`b@nRCn%gyUFUhQd^SE*#9p^ys|8T1AmR!Y3U2RUOTY30XZV>fcs?qAG@{FqP zsiP*;z6$&;s4eCx98K40skeHM#}#k6vDUk8oBN{@@_J&Eda31Evk1rADqW~)i@Fov zPlz%>BscDpb2eL-?!xK_zbczL^eP#>mU64j*BR^T3`Egd1CL~`w)WgiGV@(d1J9|8 z&+Ijls`b7Tt=kS2qt3gSkYJ@@KdhqZ%Wy3RAc S(|(wWSwMsS(fPBfBl-;nDN0rV literal 0 HcmV?d00001 diff --git a/tools/VSTestHost.VS2017/vs2017.testsettings.template b/tools/VSTestHost.VS2017/vs2017.testsettings.template new file mode 100644 index 00000000..74b406ea --- /dev/null +++ b/tools/VSTestHost.VS2017/vs2017.testsettings.template @@ -0,0 +1,55 @@ + + + Local test runs with Visual Studio 2017 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 645cf64b469b19414f371792e2da538ee7cd32c7 Mon Sep 17 00:00:00 2001 From: Stefan Kert Date: Sat, 9 Mar 2019 11:29:51 +0100 Subject: [PATCH 009/100] Next steps to a cleaner structure --- BuildVision.sln | 9 +- .../BuildVision.Contracts.csproj | 3 +- src/BuildVision.Contracts/BuildedSolution.cs | 17 - .../Enums/BuildResultState.cs | 22 + src/BuildVision.Contracts/Enums/BuildState.cs | 5 +- .../PropertyNotFoundException.cs | 2 +- .../BuildVision.Exports.csproj | 9 + src/BuildVision.Exports/Key.snk | Bin 0 -> 596 bytes .../Sevices/IBuildService.cs | 14 + .../Sevices}/IStatusBarNotificationService.cs | 4 +- .../ViewModels/IBuildVisionPaneViewModel.cs | 14 + .../ViewModels/IViewModel.cs | 9 + src/BuildVision.UI/BuildVision.UI.csproj | 69 +- .../Components/ControlHeader.xaml | 316 ++++---- .../Components/ControlView.xaml.cs | 17 +- src/BuildVision.UI/Contracts/BuildInfo.cs | 32 - .../Contracts/BuildedProjectsCollection.cs | 24 +- .../Contracts/IBuildDistributor.cs | 11 - .../IndicatorVectorIconConverter.cs | 26 - .../IsErrorToBorderThicknessConverter.cs | 22 - .../IsSeparatorIndicatorConverter.cs | 22 - src/BuildVision.UI/Helpers/BuildImages.cs | 82 --- src/BuildVision.UI/Helpers/BuildMessages.cs | 204 +++--- .../ResetTaskBarItemInfoCondition.cs | 2 +- .../Sorting => Helpers}/SortDescription.cs | 0 .../{Models => Helpers}/SortOrder.cs | 0 .../{Models => Helpers}/WindowState.cs | 0 .../WindowStateAction.cs | 0 .../IBuildVisionPaneViewModel.cs | 17 - .../IPackageSettingsProvider.cs | 0 .../Models}/BaseGridColumnSettings.cs | 0 .../Models/BuildMessagesSettings.cs | 0 .../BuildProgressSettings.cs | 0 src/BuildVision.UI/Models/ControlModel.cs | 32 - src/BuildVision.UI/Models/ControlSettings.cs | 46 ++ .../{Settings => }/Models/GeneralSettings.cs | 0 .../Columns => Models}/GridColumnSettings.cs | 0 .../GridColumnSettingsCollection.cs | 0 .../{Settings => }/Models/GridSettings.cs | 0 .../Indicators/Core/ResetIndicatorMode.cs | 8 - .../Models/Indicators/Core/ValueIndicator.cs | 130 ---- .../Indicators/Core/ValueIndicatorsFactory.cs | 24 - .../Indicators/ErrorProjectsIndicator.cs | 26 - .../Models/Indicators/ErrorsIndicator.cs | 19 - .../Models/Indicators/MessagesIndicator.cs | 19 - .../Models/Indicators/SeparatorIndicator.cs | 21 - .../Indicators/SuccessProjectsIndicator.cs | 27 - .../Indicators/UpToDateProjectsIndicator.cs | 24 - .../Indicators/WarningProjectsIndicator.cs | 24 - .../Models/Indicators/WarningsIndicator.cs | 18 - src/BuildVision.UI/Models/ProjectItem.cs | 436 +++++------ .../Models/ProjectItemSettings.cs | 7 +- .../{Settings => }/Models/WindowSettings.cs | 2 +- .../Resources/BuildAction.Resources.Test.xaml | 36 +- .../Resources/BuildAction.Resources.xaml | 40 +- .../Resources/BuildResult.Resources.Test.xaml | 126 ++++ .../Resources/BuildResult.Resources.xaml | 333 +++++++++ .../Resources/BuildState.Resources.Test.xaml | 44 +- .../Resources/BuildState.Resources.xaml | 8 +- .../Settings/Models/ControlSettings.cs | 47 -- .../Styles/ControlViewStyle.xaml | 15 +- .../ViewModels/BuildProgressViewModel.cs | 2 +- .../ViewModels/BuildVisionPaneViewModel.cs | 137 +--- .../ViewModels/SolutionModel.cs | 93 +++ .../ViewModels/VisualStudioSolution.cs | 101 +++ src/BuildVision/BuildVision.csproj | 15 +- src/BuildVision/Core/BuildVisionPackage.cs | 71 +- src/BuildVision/Core/SolutionBuildEvents.cs | 361 ++++++++- .../Core/StatusBarNotificationService.cs | 1 + src/BuildVision/Helpers/EnvDTEProjectKinds.cs | 7 + .../Helpers/ProjectIdentifierGenerator.cs | 22 + .../Helpers/SolutionProjectsExtensions.cs | 227 +++++- .../Helpers/StateConverterHelper.cs | 30 + src/BuildVision/Helpers/ViewModelHelper.cs | 234 ------ src/BuildVision/Helpers/VsCfgExtensions.cs | 16 + .../Helpers/VsHierarchyExtensions.cs | 17 + src/BuildVision/Tool/BuildVisionPane.cs | 9 +- .../Building/BackgroundBuildProcessUpdater.cs | 59 ++ src/BuildVision/Tool/Building/BuildContext.cs | 684 ++++-------------- src/BuildVision/Tool/Building/BuildManager.cs | 71 +- .../Tool/Building/BuildOutputLogger.cs | 20 +- .../Tool/Building/IVsItemLocatorService.cs | 18 - .../Tool/Building/VsItemLocatorService.cs | 132 ---- .../PackageTests.cs | 4 +- 84 files changed, 2316 insertions(+), 2479 deletions(-) delete mode 100644 src/BuildVision.Contracts/BuildedSolution.cs create mode 100644 src/BuildVision.Contracts/Enums/BuildResultState.cs create mode 100644 src/BuildVision.Exports/BuildVision.Exports.csproj create mode 100644 src/BuildVision.Exports/Key.snk create mode 100644 src/BuildVision.Exports/Sevices/IBuildService.cs rename src/{BuildVision/Core => BuildVision.Exports/Sevices}/IStatusBarNotificationService.cs (76%) create mode 100644 src/BuildVision.Exports/ViewModels/IBuildVisionPaneViewModel.cs create mode 100644 src/BuildVision.Exports/ViewModels/IViewModel.cs delete mode 100644 src/BuildVision.UI/Contracts/BuildInfo.cs delete mode 100644 src/BuildVision.UI/Contracts/IBuildDistributor.cs delete mode 100644 src/BuildVision.UI/Converters/IndicatorVectorIconConverter.cs delete mode 100644 src/BuildVision.UI/Converters/IsErrorToBorderThicknessConverter.cs delete mode 100644 src/BuildVision.UI/Converters/IsSeparatorIndicatorConverter.cs delete mode 100644 src/BuildVision.UI/Helpers/BuildImages.cs rename src/BuildVision.UI/{Models => Helpers}/ResetTaskBarItemInfoCondition.cs (99%) rename src/BuildVision.UI/{Settings/Models/Sorting => Helpers}/SortDescription.cs (100%) rename src/BuildVision.UI/{Models => Helpers}/SortOrder.cs (100%) rename src/BuildVision.UI/{Models => Helpers}/WindowState.cs (100%) rename src/BuildVision.UI/{Settings/Models/ToolWindow => Helpers}/WindowStateAction.cs (100%) delete mode 100644 src/BuildVision.UI/IBuildVisionPaneViewModel.cs rename src/{BuildVision/Tool/Views/Settings => BuildVision.UI}/IPackageSettingsProvider.cs (100%) rename src/{BuildVision.Contracts => BuildVision.UI/Models}/BaseGridColumnSettings.cs (100%) rename src/BuildVision.UI/{Settings => }/Models/BuildMessagesSettings.cs (100%) rename src/BuildVision.UI/{Settings/Models/BuildProgress => Models}/BuildProgressSettings.cs (100%) delete mode 100644 src/BuildVision.UI/Models/ControlModel.cs create mode 100644 src/BuildVision.UI/Models/ControlSettings.cs rename src/BuildVision.UI/{Settings => }/Models/GeneralSettings.cs (100%) rename src/BuildVision.UI/{Settings/Models/Columns => Models}/GridColumnSettings.cs (100%) rename src/BuildVision.UI/{Settings/Models/Columns => Models}/GridColumnSettingsCollection.cs (100%) rename src/BuildVision.UI/{Settings => }/Models/GridSettings.cs (100%) delete mode 100644 src/BuildVision.UI/Models/Indicators/Core/ResetIndicatorMode.cs delete mode 100644 src/BuildVision.UI/Models/Indicators/Core/ValueIndicator.cs delete mode 100644 src/BuildVision.UI/Models/Indicators/Core/ValueIndicatorsFactory.cs delete mode 100644 src/BuildVision.UI/Models/Indicators/ErrorProjectsIndicator.cs delete mode 100644 src/BuildVision.UI/Models/Indicators/ErrorsIndicator.cs delete mode 100644 src/BuildVision.UI/Models/Indicators/MessagesIndicator.cs delete mode 100644 src/BuildVision.UI/Models/Indicators/SeparatorIndicator.cs delete mode 100644 src/BuildVision.UI/Models/Indicators/SuccessProjectsIndicator.cs delete mode 100644 src/BuildVision.UI/Models/Indicators/UpToDateProjectsIndicator.cs delete mode 100644 src/BuildVision.UI/Models/Indicators/WarningProjectsIndicator.cs delete mode 100644 src/BuildVision.UI/Models/Indicators/WarningsIndicator.cs rename src/BuildVision.UI/{Settings => }/Models/ProjectItemSettings.cs (84%) rename src/BuildVision.UI/{Settings => }/Models/WindowSettings.cs (99%) create mode 100644 src/BuildVision.UI/Resources/BuildResult.Resources.Test.xaml create mode 100644 src/BuildVision.UI/Resources/BuildResult.Resources.xaml delete mode 100644 src/BuildVision.UI/Settings/Models/ControlSettings.cs create mode 100644 src/BuildVision.UI/ViewModels/SolutionModel.cs create mode 100644 src/BuildVision.UI/ViewModels/VisualStudioSolution.cs create mode 100644 src/BuildVision/Helpers/EnvDTEProjectKinds.cs create mode 100644 src/BuildVision/Helpers/ProjectIdentifierGenerator.cs create mode 100644 src/BuildVision/Helpers/StateConverterHelper.cs delete mode 100644 src/BuildVision/Helpers/ViewModelHelper.cs create mode 100644 src/BuildVision/Helpers/VsCfgExtensions.cs create mode 100644 src/BuildVision/Helpers/VsHierarchyExtensions.cs create mode 100644 src/BuildVision/Tool/Building/BackgroundBuildProcessUpdater.cs delete mode 100644 src/BuildVision/Tool/Building/IVsItemLocatorService.cs delete mode 100644 src/BuildVision/Tool/Building/VsItemLocatorService.cs diff --git a/BuildVision.sln b/BuildVision.sln index d7427501..2e4cbd62 100644 --- a/BuildVision.sln +++ b/BuildVision.sln @@ -27,10 +27,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BuildVision.UI", "src\Build EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{1DE272AA-D641-45F2-AEB9-934B3BAA6FBD}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BuildVision.IntegrationTests", "test\BuildVision.IntegrationTests\BuildVision.IntegrationTests.csproj", "{FBB4F3ED-B1B8-4401-8667-5180194BAA54}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BuildVision.IntegrationTests", "test\BuildVision.IntegrationTests\BuildVision.IntegrationTests.csproj", "{FBB4F3ED-B1B8-4401-8667-5180194BAA54}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BuildVision.UnitTests", "test\BuildVision.UnitTests\BuildVision.UnitTests.csproj", "{2A7DE186-A1FA-4BA8-B393-3CA9ECBF444F}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BuildVision.Exports", "src\BuildVision.Exports\BuildVision.Exports.csproj", "{F16E6593-DDF9-4E9E-A2F8-56A3C43A643E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -61,6 +63,10 @@ Global {2A7DE186-A1FA-4BA8-B393-3CA9ECBF444F}.Debug|Any CPU.Build.0 = Debug|Any CPU {2A7DE186-A1FA-4BA8-B393-3CA9ECBF444F}.Release|Any CPU.ActiveCfg = Release|Any CPU {2A7DE186-A1FA-4BA8-B393-3CA9ECBF444F}.Release|Any CPU.Build.0 = Release|Any CPU + {F16E6593-DDF9-4E9E-A2F8-56A3C43A643E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F16E6593-DDF9-4E9E-A2F8-56A3C43A643E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F16E6593-DDF9-4E9E-A2F8-56A3C43A643E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F16E6593-DDF9-4E9E-A2F8-56A3C43A643E}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -72,6 +78,7 @@ Global {84E8BA65-9A4B-4C50-A115-6EF3208E4058} = {AE904AFF-1B2B-4D8F-9826-57BC13DC4AC5} {FBB4F3ED-B1B8-4401-8667-5180194BAA54} = {1DE272AA-D641-45F2-AEB9-934B3BAA6FBD} {2A7DE186-A1FA-4BA8-B393-3CA9ECBF444F} = {1DE272AA-D641-45F2-AEB9-934B3BAA6FBD} + {F16E6593-DDF9-4E9E-A2F8-56A3C43A643E} = {AE904AFF-1B2B-4D8F-9826-57BC13DC4AC5} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {1485240E-4A28-4FA4-8D69-3D8151C3E1F6} diff --git a/src/BuildVision.Contracts/BuildVision.Contracts.csproj b/src/BuildVision.Contracts/BuildVision.Contracts.csproj index 40096121..37f38f4b 100644 --- a/src/BuildVision.Contracts/BuildVision.Contracts.csproj +++ b/src/BuildVision.Contracts/BuildVision.Contracts.csproj @@ -49,10 +49,9 @@ - + - diff --git a/src/BuildVision.Contracts/BuildedSolution.cs b/src/BuildVision.Contracts/BuildedSolution.cs deleted file mode 100644 index 6c31ffac..00000000 --- a/src/BuildVision.Contracts/BuildedSolution.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System.IO; - -namespace BuildVision.Contracts -{ - public class BuildedSolution - { - public string FullName { get; set; } - - public string Name { get; set; } - - public BuildedSolution(string fullName, string fileName) - { - FullName = fullName; - Name = Path.GetFileNameWithoutExtension(fileName); - } - } -} \ No newline at end of file diff --git a/src/BuildVision.Contracts/Enums/BuildResultState.cs b/src/BuildVision.Contracts/Enums/BuildResultState.cs new file mode 100644 index 00000000..6e2d1f57 --- /dev/null +++ b/src/BuildVision.Contracts/Enums/BuildResultState.cs @@ -0,0 +1,22 @@ +namespace BuildVision.Contracts +{ + public enum BuildResultState + { + Unknown, + + RebuildSucceeded, + RebuildSucceededWithErrors, + RebuildFailed, + RebuildCancelled, + + BuildSucceeded, + BuildSucceededWithErrors, + BuildFailed, + BuildCancelled, + + CleanSucceeded, + CleanSucceededWithErrors, + CleanFailed, + CleanCancelled + } +} diff --git a/src/BuildVision.Contracts/Enums/BuildState.cs b/src/BuildVision.Contracts/Enums/BuildState.cs index cda71fff..9d58869c 100644 --- a/src/BuildVision.Contracts/Enums/BuildState.cs +++ b/src/BuildVision.Contracts/Enums/BuildState.cs @@ -4,6 +4,7 @@ public enum BuildState { NotStarted = 0, InProgress = 1, - Done = 2 + Done = 2, + Cancelled = 3 } -} \ No newline at end of file +} diff --git a/src/BuildVision.Contracts/PropertyNotFoundException.cs b/src/BuildVision.Contracts/PropertyNotFoundException.cs index 5d43f387..041a0d59 100644 --- a/src/BuildVision.Contracts/PropertyNotFoundException.cs +++ b/src/BuildVision.Contracts/PropertyNotFoundException.cs @@ -28,4 +28,4 @@ public override string Message get { return string.Format("Property '{0}' not found in '{1}' type.", _propertyName, _type); } } } -} \ No newline at end of file +} diff --git a/src/BuildVision.Exports/BuildVision.Exports.csproj b/src/BuildVision.Exports/BuildVision.Exports.csproj new file mode 100644 index 00000000..2095a5ba --- /dev/null +++ b/src/BuildVision.Exports/BuildVision.Exports.csproj @@ -0,0 +1,9 @@ + + + + net472 + true + Key.snk + + + diff --git a/src/BuildVision.Exports/Key.snk b/src/BuildVision.Exports/Key.snk new file mode 100644 index 0000000000000000000000000000000000000000..8bf0d5578f282dc1f6ebe6cfc6e9e9b4b2e0b0d2 GIT binary patch literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50097djXR6X9J~grV+EGhnX%hfv3m$dZu8&Q zHb7iZGdB#C#hqz>3Bo`RKEQH5;GT6cQ8uqLw0VTm~du)7NMQK%3x%a?d~Q8 zh-iq=DfuUs0_NM!_LSc5R*V>sg%VkvLVg(pnBZj zg~P!v%m^IdYt9Mz2Dn~HA+cvAENL~R%?p>oMS~-jxRBn0jwC5@w5IV<7Mirj z#12JWv9&nJLS+5r)4~IIbWyzn%<9F@G!-oe;81{tnEs^COtx(6k27wr2|Hgd~ z(WM5tdZW%la(t_@hOR$>RwP8|qQBl*;p0_}NupSJ*;&Z8p3eAos?~lO7hG0P)mi6_ zP9*_p3@#Oqg{`pZ__je+2AYVvD(pB<>LBNQLC*Ul6{aaE^94I(pH5GlpZM*;WF|bq z!`L~wD-qEELkM{G<*t?sXpC^`3~v3cfMQM8sN)hZ5fguo>)}*x@pF52gy@6$hiH%i z=0Tm1gxv%KX-XlAYI-_q2{CFNEKN?vW~-}&o#S~8DuAEhp$V{DQgvpv>clBx+H{hQ zjPw}SR;g{_FKR^C`vk-bO5;qF24(HS3&rZ5Z1>;mG;^m^+?>jZGf?nNCD} i6TP9RXLZc2>YS=2)aJr`6KyjYP!Iox$=ws)In3GlmLvfH literal 0 HcmV?d00001 diff --git a/src/BuildVision.Exports/Sevices/IBuildService.cs b/src/BuildVision.Exports/Sevices/IBuildService.cs new file mode 100644 index 00000000..42789b89 --- /dev/null +++ b/src/BuildVision.Exports/Sevices/IBuildService.cs @@ -0,0 +1,14 @@ +namespace BuildVision.Exports.Services +{ + public interface IBuildService + { + void ShowGridColumnsSettingsPage(); + void ShowGeneralSettingsPage(); + void BuildSolution(); + void CleanSolution(); + void RebuildSolution(); + void CancelBuildSolution(); + void ProjectCopyBuildOutputFilesToClipBoard(); + void RaiseCommandForSelectedProject(); + } +} diff --git a/src/BuildVision/Core/IStatusBarNotificationService.cs b/src/BuildVision.Exports/Sevices/IStatusBarNotificationService.cs similarity index 76% rename from src/BuildVision/Core/IStatusBarNotificationService.cs rename to src/BuildVision.Exports/Sevices/IStatusBarNotificationService.cs index 98068091..a2d5ab6d 100644 --- a/src/BuildVision/Core/IStatusBarNotificationService.cs +++ b/src/BuildVision.Exports/Sevices/IStatusBarNotificationService.cs @@ -1,8 +1,8 @@ -namespace BuildVision.Core +namespace BuildVision.Exports.Services { public interface IStatusBarNotificationService { void ShowText(string str); void ShowTextWithFreeze(string str); } -} \ No newline at end of file +} diff --git a/src/BuildVision.Exports/ViewModels/IBuildVisionPaneViewModel.cs b/src/BuildVision.Exports/ViewModels/IBuildVisionPaneViewModel.cs new file mode 100644 index 00000000..d417c5ba --- /dev/null +++ b/src/BuildVision.Exports/ViewModels/IBuildVisionPaneViewModel.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using BuildVision.Exports.ViewModels; + +namespace BuildVision.Exports.ViewModels +{ + public interface IBuildVisionPaneViewModel : IViewModel + { + } +} diff --git a/src/BuildVision.Exports/ViewModels/IViewModel.cs b/src/BuildVision.Exports/ViewModels/IViewModel.cs new file mode 100644 index 00000000..2a41720b --- /dev/null +++ b/src/BuildVision.Exports/ViewModels/IViewModel.cs @@ -0,0 +1,9 @@ +using System; +using System.ComponentModel; + +namespace BuildVision.Exports.ViewModels +{ + public interface IViewModel : INotifyPropertyChanged + { + } +} diff --git a/src/BuildVision.UI/BuildVision.UI.csproj b/src/BuildVision.UI/BuildVision.UI.csproj index f2359dce..12b18850 100644 --- a/src/BuildVision.UI/BuildVision.UI.csproj +++ b/src/BuildVision.UI/BuildVision.UI.csproj @@ -73,6 +73,15 @@ App.xaml Code + + + + + + + + + @@ -83,10 +92,12 @@ - + + + + + - - @@ -107,44 +118,18 @@ - MainWindow.xaml - - - - - - - - - - - - - - - - - - - - - - - - - - + Resources.resx True @@ -168,8 +153,11 @@ WindowSettingsControl.xaml + + + @@ -180,11 +168,8 @@ - - - @@ -251,12 +236,22 @@ Designer MSBuild:Compile + + MSBuild:Compile + Designer + Always + + + MSBuild:Compile + Designer + Always + MSBuild:Compile Designer Always - + MSBuild:Compile Designer Always @@ -285,7 +280,7 @@ Designer Always - + MSBuild:Compile Designer Always @@ -362,6 +357,10 @@ {13d64a57-5db3-4cc7-ac2b-9034e767d754} BuildVision.Contracts + + {F16E6593-DDF9-4E9E-A2F8-56A3C43A643E} + BuildVision.Exports + diff --git a/src/BuildVision.UI/Components/ControlHeader.xaml b/src/BuildVision.UI/Components/ControlHeader.xaml index 23caf0ad..bde829d0 100644 --- a/src/BuildVision.UI/Components/ControlHeader.xaml +++ b/src/BuildVision.UI/Components/ControlHeader.xaml @@ -1,9 +1,11 @@  + - - - - - + - - - - + @@ -145,10 +110,11 @@ - + + @@ -246,114 +212,180 @@ Background="Transparent" BorderThickness="0" ScrollViewer.HorizontalScrollBarVisibility="Auto" - UseLayoutRounding="False" - ItemsSource="{Binding ValueIndicators}"> - - - + UseLayoutRounding="False"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + diff --git a/src/BuildVision.UI/Components/ControlView.xaml.cs b/src/BuildVision.UI/Components/ControlView.xaml.cs index be494324..6d1f27af 100644 --- a/src/BuildVision.UI/Components/ControlView.xaml.cs +++ b/src/BuildVision.UI/Components/ControlView.xaml.cs @@ -67,14 +67,15 @@ private void OnDataContextChanged(object sender, DependencyPropertyChangedEventA private void ViewModelOnPropertyChanged(object sender, PropertyChangedEventArgs e) { - if (_viewModel.CurrentProject != null && e.PropertyName == "CurrentProject") - { - // TODO: Remove SelectedIndex = -1 and implement Unselect row feature by clicking on selected row. - Grid.SelectedIndex = -1; - - if (Grid.SelectedIndex == -1) - Grid.ScrollIntoView(_viewModel.CurrentProject); - } + //TODO implement logic for scrolling tu currentproject + //if (_viewModel.CurrentProject != null && e.PropertyName == "CurrentProject") + //{ + // // TODO: Remove SelectedIndex = -1 and implement Unselect row feature by clicking on selected row. + // Grid.SelectedIndex = -1; + + // if (Grid.SelectedIndex == -1) + // Grid.ScrollIntoView(_viewModel.CurrentProject); + //} } private void DataGridExpanderOnExpanded(object sender, RoutedEventArgs e) diff --git a/src/BuildVision.UI/Contracts/BuildInfo.cs b/src/BuildVision.UI/Contracts/BuildInfo.cs deleted file mode 100644 index 159a449e..00000000 --- a/src/BuildVision.UI/Contracts/BuildInfo.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System; -using System.Collections.Generic; -using BuildVision.Contracts; -using BuildVision.UI.Models; - -namespace BuildVision.UI.Contracts -{ - public interface IBuildInfo - { - BuildActions? BuildAction { get; } - - BuildScopes? BuildScope { get; } - - BuildState CurrentBuildState { get; } - - bool BuildIsCancelled { get; } - - DateTime? BuildStartTime { get; } - - DateTime? BuildFinishTime { get; } - - BuildedProjectsCollection BuildedProjects { get; } - - IList BuildingProjects { get; } - - BuildedSolution BuildedSolution { get; } - - void OverrideBuildProperties(BuildActions? buildAction = null, BuildScopes? buildScope = null); - - ProjectItem BuildScopeProject { get; } - } -} \ No newline at end of file diff --git a/src/BuildVision.UI/Contracts/BuildedProjectsCollection.cs b/src/BuildVision.UI/Contracts/BuildedProjectsCollection.cs index f6406220..450ecdee 100644 --- a/src/BuildVision.UI/Contracts/BuildedProjectsCollection.cs +++ b/src/BuildVision.UI/Contracts/BuildedProjectsCollection.cs @@ -6,33 +6,21 @@ namespace BuildVision.UI.Contracts { - // TODO: thread-safety. - public class BuildedProjectsCollection : List + public class BuildedProjectsCollection : List { - public int BuildSuccessCount => this.Count(p => p.Success == true && p.ProjectState != ProjectState.BuildWarning && p.ProjectState != ProjectState.UpToDate); + public int BuildSuccessCount => this.Count(p => p.Success == true && p.State != ProjectState.BuildWarning && p.State != ProjectState.UpToDate); public int BuildErrorCount => this.Count(p => p.Success == false); - public int BuildWarningsCount => this.Count(p => p.ProjectState == ProjectState.BuildWarning); + public int BuildWarningsCount => this.Count(p => p.State == ProjectState.BuildWarning); - public int BuildUpToDateCount => this.Count(p => p.ProjectState == ProjectState.UpToDate); + public int BuildUpToDateCount => this.Count(p => p.State == ProjectState.UpToDate); public bool BuildWithoutErrors => this.All(p => p.Success == null || p.Success == true); - /// - /// Get by . - /// If not exists, it has been created and added to the collection. - /// - public BuildedProject this[ProjectItem pi] + public ProjectItem this[ProjectItem pi] { get { - var proj = Find(p => p.UniqueName == pi.UniqueName && p.Configuration == pi.Configuration && p.Platform == pi.Platform); - if (proj == null) - { - proj = new BuildedProject(pi.UniqueName, pi.FullName, pi.Configuration, pi.Platform); - Add(proj); - } - - return proj; + return Find(p => p.UniqueName == pi.UniqueName && p.Configuration == pi.Configuration && p.Platform == pi.Platform); } } } diff --git a/src/BuildVision.UI/Contracts/IBuildDistributor.cs b/src/BuildVision.UI/Contracts/IBuildDistributor.cs deleted file mode 100644 index e5bcd8ed..00000000 --- a/src/BuildVision.UI/Contracts/IBuildDistributor.cs +++ /dev/null @@ -1,11 +0,0 @@ -using BuildVision.Contracts; -using System; -using System.Threading.Tasks; - -namespace BuildVision.UI.Contracts -{ - public interface IBuildDistributor - { - Task CancelBuildAsync(); - } -} diff --git a/src/BuildVision.UI/Converters/IndicatorVectorIconConverter.cs b/src/BuildVision.UI/Converters/IndicatorVectorIconConverter.cs deleted file mode 100644 index bd5f289b..00000000 --- a/src/BuildVision.UI/Converters/IndicatorVectorIconConverter.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using System.Diagnostics; -using System.Globalization; -using System.Windows.Controls; -using System.Windows.Data; - -using BuildVision.UI.Models.Indicators.Core; -using BuildVision.UI.Extensions; - -namespace BuildVision.UI.Converters -{ - [ValueConversion(typeof(ValueIndicator), typeof(ControlTemplate))] - public class IndicatorVectorIconConverter : IValueConverter - { - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) - { - Debug.Assert(value is ValueIndicator); - return VectorResources.TryGet(ValueIndicator.ResourcesUri, value.GetType().Name); - } - - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) - { - throw new NotSupportedException(); - } - } -} \ No newline at end of file diff --git a/src/BuildVision.UI/Converters/IsErrorToBorderThicknessConverter.cs b/src/BuildVision.UI/Converters/IsErrorToBorderThicknessConverter.cs deleted file mode 100644 index 8d5bba32..00000000 --- a/src/BuildVision.UI/Converters/IsErrorToBorderThicknessConverter.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; -using System.Globalization; -using System.Windows; -using System.Windows.Data; - -namespace BuildVision.UI.Converters -{ - [ValueConversion(typeof(bool), typeof(Thickness))] - public class IsErrorToBorderThicknessConverter : IValueConverter - { - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) - { - var isError = (bool)value; - return isError ? new Thickness(1) : new Thickness(0); - } - - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) - { - throw new NotImplementedException(); - } - } -} \ No newline at end of file diff --git a/src/BuildVision.UI/Converters/IsSeparatorIndicatorConverter.cs b/src/BuildVision.UI/Converters/IsSeparatorIndicatorConverter.cs deleted file mode 100644 index 82829877..00000000 --- a/src/BuildVision.UI/Converters/IsSeparatorIndicatorConverter.cs +++ /dev/null @@ -1,22 +0,0 @@ -using BuildVision.UI.Models.Indicators; -using BuildVision.UI.Models.Indicators.Core; -using System; -using System.Globalization; -using System.Windows.Data; - -namespace BuildVision.UI.Converters -{ - [ValueConversion(typeof(ValueIndicator), typeof(bool))] - public class IsSeparatorIndicatorConverter : IValueConverter - { - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) - { - return (value is SeparatorIndicator); - } - - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) - { - throw new InvalidOperationException(); - } - } -} \ No newline at end of file diff --git a/src/BuildVision.UI/Helpers/BuildImages.cs b/src/BuildVision.UI/Helpers/BuildImages.cs deleted file mode 100644 index 618910d0..00000000 --- a/src/BuildVision.UI/Helpers/BuildImages.cs +++ /dev/null @@ -1,82 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Windows.Controls; - -using ProjectItem = BuildVision.UI.Models.ProjectItem; -using BuildVision.Contracts; -using BuildVision.UI.Contracts; -using BuildVision.UI.Extensions; - -namespace BuildVision.UI.Helpers -{ - public static class BuildImages - { - public const string BuildActionResourcesUri = @"Resources/BuildAction.Resources.xaml"; - public const string BuildStateResourcesUri = @"Resources/BuildState.Resources.xaml"; - - public static ControlTemplate GetBuildBeginImage(IBuildInfo buildInfo) - { - var buildAction = buildInfo.BuildAction; - var buildScope = buildInfo.BuildScope; - - if (buildAction == null || buildScope == null) - return null; - - string actionKey = GetBuildActionResourceKey(buildAction.Value); - return VectorResources.TryGet(BuildActionResourcesUri, actionKey); - } - - public static ControlTemplate GetBuildDoneImage(IBuildInfo buildInfo, IEnumerable allProjects, out ControlTemplate stateImage) - { - if (buildInfo?.BuildAction == null || buildInfo?.BuildScope == null) - throw new ArgumentNullException(nameof(buildInfo)); - - if (allProjects == null) - throw new InvalidOperationException(); - - int errorProjectsCount = allProjects.Count(item => item.State.IsErrorState()); - bool buildedProjectsSuccess = buildInfo.BuildedProjects.BuildWithoutErrors; - - string stateKey; - - if (buildedProjectsSuccess) - { - if (errorProjectsCount == 0) - stateKey = "BuildDone"; - else - stateKey = "BuildErrorDone"; - } - else if (buildInfo.BuildIsCancelled) - stateKey = "BuildCancelled"; - else - stateKey = "BuildError"; - - stateImage = VectorResources.TryGet(BuildStateResourcesUri, stateKey); - - string actionKey = GetBuildActionResourceKey(buildInfo.BuildAction.Value); - return VectorResources.TryGet(BuildActionResourcesUri, actionKey); - } - - private static string GetBuildActionResourceKey(BuildActions buildAction) - { - switch (buildAction) - { - case BuildActions.BuildActionBuild: - return "Build"; - - case BuildActions.BuildActionRebuildAll: - return "Rebuild"; - - case BuildActions.BuildActionClean: - return "Clean"; - - case BuildActions.BuildActionDeploy: - throw new InvalidOperationException(); - - default: - throw new ArgumentOutOfRangeException(nameof(buildAction)); - } - } - } -} diff --git a/src/BuildVision.UI/Helpers/BuildMessages.cs b/src/BuildVision.UI/Helpers/BuildMessages.cs index 6aa3c0bf..d5311c14 100644 --- a/src/BuildVision.UI/Helpers/BuildMessages.cs +++ b/src/BuildVision.UI/Helpers/BuildMessages.cs @@ -1,36 +1,37 @@ using System; -using System.Diagnostics; using System.Linq; using BuildVision.Contracts; -using BuildVision.UI.Contracts; using BuildVision.UI.Models; -using BuildVision.UI.Extensions; using BuildVision.UI.Settings.Models; +using BuildVision.Core; namespace BuildVision.UI.Helpers { - public static class BuildMessages + public class BuildMessagesFactory { - public static string GetBuildBeginMajorMessage(SolutionItem solutionItem, IBuildInfo buildInfo, BuildMessagesSettings labelsSettings) - { - if (buildInfo.BuildAction == null || buildInfo.BuildScope == null || buildInfo.BuildAction.Value == BuildActions.BuildActionDeploy) - return Resources.UnknownBuildActionOrScope_BuildBeginText; + private readonly BuildMessagesSettings _labelSettings; - if (buildInfo.BuildStartTime == null) - throw new InvalidOperationException(); + public BuildMessagesFactory(BuildMessagesSettings labelsSettings) + { + _labelSettings = labelsSettings; + } - var mainString = GetMainString(solutionItem, buildInfo, labelsSettings); - return string.Format(labelsSettings.BuildBeginMajorMessageStringFormat, mainString); + public string GetBuildBeginMajorMessage(VisualStudioSolution solutionItem) + { + var mainString = GetMainString(solutionItem); + return string.Format(_labelSettings.BuildBeginMajorMessageStringFormat, mainString); } - private static string GetMainString(SolutionItem solutionItem, IBuildInfo buildInfo, BuildMessagesSettings labelsSettings) + private string GetMainString(VisualStudioSolution solutionItem) { - var unitName = GetUnitName(solutionItem, buildInfo, labelsSettings); - var actionName = GetActionName(buildInfo.BuildAction.Value); - var beginAtString = GetBeginAtString(buildInfo.BuildAction.Value); - var timeString = GetTimeString(buildInfo, labelsSettings); + var buildAction = BuildActions.BuildActionBuild; //TOdo replace + + var unitName = GetUnitName(solutionItem); + var actionName = GetActionName(solutionItem.BuildAction); + var beginAtString = GetBeginAtString(solutionItem.BuildAction); + var timeString = GetTimeString(solutionItem); string mainString; - switch (labelsSettings.MajorMessageFormat) + switch (_labelSettings.MajorMessageFormat) { case BuildMajorMessageFormat.Entire: mainString = string.Format(Resources.BuildBeginStateLabelTemplate_Default, actionName, unitName, beginAtString, timeString); @@ -41,18 +42,18 @@ private static string GetMainString(SolutionItem solutionItem, IBuildInfo buildI break; default: - throw new ArgumentOutOfRangeException(nameof(labelsSettings.MajorMessageFormat)); + throw new ArgumentOutOfRangeException(nameof(_labelSettings.MajorMessageFormat)); } return mainString; } - private static string GetTimeString(IBuildInfo buildInfo, BuildMessagesSettings labelsSettings) + private string GetTimeString(VisualStudioSolution solution) { - string timeString; + string timeString = ""; try { - timeString = buildInfo.BuildStartTime.Value.ToString(labelsSettings.DateTimeFormat); + timeString = solution.BuildStartTime.Value.ToString(_labelSettings.DateTimeFormat); } catch (FormatException) { @@ -62,7 +63,7 @@ private static string GetTimeString(IBuildInfo buildInfo, BuildMessagesSettings return timeString; } - private static string GetBeginAtString(BuildActions? buildAction) + private string GetBeginAtString(BuildActions? buildAction) { switch (buildAction.Value) { @@ -79,7 +80,7 @@ private static string GetBeginAtString(BuildActions? buildAction) } } - private static string GetActionName(BuildActions buildAction) + private string GetActionName(BuildActions buildAction) { switch (buildAction) { @@ -96,15 +97,15 @@ private static string GetActionName(BuildActions buildAction) } } - private static string GetUnitName(SolutionItem solutionItem, IBuildInfo buildInfo, BuildMessagesSettings labelsSettings) + private string GetUnitName(VisualStudioSolution solutionItem) { - string unitName; - switch (buildInfo.BuildScope.Value) + string unitName = ""; + switch (solutionItem.BuildScope) { case BuildScopes.BuildScopeSolution: unitName = Resources.BuildScopeSolution_UnitName; - if (labelsSettings.ShowSolutionName) - unitName += string.Format(Resources.BuildScopeSolution_SolutionNameTemplate, solutionItem.Name); + //if (_labelSettings.ShowSolutionName) + //unitName += string.Format(Resources.BuildScopeSolution_SolutionNameTemplate, solutionItem.Name); break; case BuildScopes.BuildScopeBatch: @@ -113,80 +114,62 @@ private static string GetUnitName(SolutionItem solutionItem, IBuildInfo buildInf case BuildScopes.BuildScopeProject: unitName = Resources.BuildScopeProject_UnitName; - if (labelsSettings.ShowProjectName) - { - var proj = buildInfo.BuildScopeProject; - if (proj != null) - { - unitName += string.Format(Resources.BuildScopeProject_ProjectNameTemplate, proj.Name); - } - else - { - unitName = Resources.BuildScopeBatch_UnitName; - buildInfo.OverrideBuildProperties(buildScope: BuildScopes.BuildScopeBatch); - } - } + // TODO specify name for project? break; default: - throw new ArgumentOutOfRangeException(nameof(buildInfo.BuildScope)); + throw new ArgumentOutOfRangeException(nameof(solutionItem.BuildScope)); } return unitName; } - public static string GetBuildBeginExtraMessage(IBuildInfo buildInfo, BuildMessagesSettings labelsSettings) + public string GetBuildBeginExtraMessage(VisualStudioSolution solutionItem) { - if (buildInfo == null || buildInfo.BuildStartTime == null || !labelsSettings.ShowExtraMessage || labelsSettings.ExtraMessageDelay < 0) + if (solutionItem.BuildStartTime == null || !_labelSettings.ShowExtraMessage || _labelSettings.ExtraMessageDelay < 0) { return string.Empty; } - TimeSpan timeSpan = DateTime.Now.Subtract(buildInfo.BuildStartTime.Value); - if (timeSpan.TotalSeconds > labelsSettings.ExtraMessageDelay) + TimeSpan timeSpan = DateTime.Now.Subtract(solutionItem.BuildStartTime.Value); + if (timeSpan.TotalSeconds > _labelSettings.ExtraMessageDelay) { - return GetExtraTimePartString(labelsSettings, timeSpan); + return GetExtraTimePartString( timeSpan); } return string.Empty; } - public static string GetBuildDoneMessage(SolutionItem solutionItem, IBuildInfo buildInfo, BuildMessagesSettings labelsSettings) + public string GetBuildDoneMessage(VisualStudioSolution solutionItem) { - return GetBuildDoneMajorMessage(solutionItem, buildInfo, labelsSettings) + GetBuildDoneExtraMessage(buildInfo, labelsSettings); + return GetBuildDoneMajorMessage(solutionItem) + GetBuildDoneExtraMessage(solutionItem); } - private static string GetBuildDoneMajorMessage(SolutionItem solutionItem, IBuildInfo buildInfo, BuildMessagesSettings labelsSettings) + private string GetBuildDoneMajorMessage(VisualStudioSolution solutionItem) { - if (buildInfo == null) - return Resources.BuildDoneText_BuildNotStarted; - - var buildAction = buildInfo.BuildAction; - var buildScope = buildInfo.BuildScope; + var buildAction = solutionItem.BuildAction; + var buildScope = solutionItem.BuildScope; - if (buildInfo.BuildFinishTime == null) + if (solutionItem.BuildFinishTime == null) throw new InvalidOperationException(); string timeString; try { - timeString = buildInfo.BuildFinishTime.Value.ToString(labelsSettings.DateTimeFormat); + timeString = solutionItem.BuildFinishTime.Value.ToString(_labelSettings.DateTimeFormat); } catch (FormatException) { timeString = Resources.InvalidTimeStringFormat; } - if (buildAction == null || buildScope == null) - return string.Format(Resources.BuildDoneText_NotSupported_BuildActionOrScopeIsNull_CompletedAtTemplate, timeString); //? WTF??? - string unitName; - switch (buildScope.Value) + switch (buildScope) { case BuildScopes.BuildScopeSolution: unitName = Resources.BuildScopeSolution_UnitName; - if (labelsSettings.ShowSolutionName) - unitName += string.Format(Resources.BuildScopeSolution_SolutionNameTemplate, solutionItem.Name); + //if (_labelSettings.ShowSolutionName) + //unitName += string.Format(Resources.BuildScopeSolution_SolutionNameTemplate, solutionItem.Name); break; case BuildScopes.BuildScopeBatch: @@ -195,13 +178,11 @@ private static string GetBuildDoneMajorMessage(SolutionItem solutionItem, IBuild case BuildScopes.BuildScopeProject: unitName = Resources.BuildScopeProject_UnitName; - if (labelsSettings.ShowProjectName) + if (_labelSettings.ShowProjectName) { - // Skip dependent projects. The last project in the list is the target project. - string uniqProjName = buildInfo.BuildedProjects[buildInfo.BuildedProjects.Count - 1].UniqueName; - ProjectItem projItem = solutionItem.AllProjects.FirstOrDefault(item => item.UniqueName == uniqProjName); - Debug.Assert(projItem != null); - + // Todo this is probably wrong. maybe we should go the extra mile and check which projects are selected? + var uniqProjName = solutionItem.Projects.LastOrDefault(x => x.State == ProjectState.BuildDone)?.UniqueName; + var projItem = solutionItem.Projects.FirstOrDefault(item => item.UniqueName == uniqProjName); unitName += string.Format(Resources.BuildScopeProject_ProjectNameTemplate, projItem.Name); } break; @@ -210,11 +191,11 @@ private static string GetBuildDoneMajorMessage(SolutionItem solutionItem, IBuild throw new ArgumentOutOfRangeException(nameof(buildScope)); } - var actionName = GetActionName(buildInfo); - var resultName = GetResultName(solutionItem, buildInfo); + var actionName = GetActionName(solutionItem.BuildAction); + var resultName = GetResultName(solutionItem.ResultState); string mainString; - switch (labelsSettings.MajorMessageFormat) + switch (_labelSettings.MajorMessageFormat) { case BuildMajorMessageFormat.Entire: mainString = string.Format(Resources.BuildDoneStateLabelTemplate_Default, actionName, unitName, resultName, timeString); @@ -225,71 +206,58 @@ private static string GetBuildDoneMajorMessage(SolutionItem solutionItem, IBuild break; default: - throw new ArgumentOutOfRangeException(nameof(labelsSettings.MajorMessageFormat)); + throw new ArgumentOutOfRangeException(nameof(_labelSettings.MajorMessageFormat)); } - string resultMainString = string.Format(labelsSettings.BuildDoneMajorMessageStringFormat, mainString); + string resultMainString = string.Format(_labelSettings.BuildDoneMajorMessageStringFormat, mainString); return resultMainString; } - private static string GetActionName(IBuildInfo buildInfo) + private string GetResultName(BuildResultState resultState) { - if (buildInfo.BuildAction == null) - throw new InvalidOperationException(); - - switch (buildInfo.BuildAction.Value) + switch (resultState) { - case BuildActions.BuildActionBuild: - return Resources.BuildActionBuild; - - case BuildActions.BuildActionRebuildAll: - return Resources.BuildActionRebuildAll; - - case BuildActions.BuildActionClean: - return Resources.BuildActionClean; - - case BuildActions.BuildActionDeploy: - throw new InvalidOperationException(); - + case BuildResultState.BuildCancelled: + case BuildResultState.RebuildCancelled: + return Resources.BuildActionCancelled; + case BuildResultState.BuildFailed: + case BuildResultState.RebuildFailed: + return Resources.BuildActionFailed; + case BuildResultState.BuildSucceeded: + case BuildResultState.RebuildSucceeded: + return Resources.BuildActionFinishedSuccessfully; + case BuildResultState.CleanCancelled: + return Resources.BuildActionCancelled_Clean; + case BuildResultState.CleanFailed: + return Resources.BuildActionFailed_Clean; + case BuildResultState.CleanSucceeded: + return Resources.BuildActionFinishedSuccessfully_Clean; + case BuildResultState.Unknown: // Check if this is right + return Resources.BuildActionFinished_Clean; default: - throw new ArgumentOutOfRangeException(nameof(buildInfo.BuildAction)); + return Resources.BuildActionFinished; } } - private static string GetResultName(SolutionItem solutionItem, IBuildInfo buildInfo) - { - var buildAction = buildInfo.BuildAction; - int errorStateProjectsCount = solutionItem.AllProjects.Count(item => item.State.IsErrorState()); - - if (buildInfo.BuildIsCancelled) - return buildAction.Value == BuildActions.BuildActionClean ? Resources.BuildActionCancelled_Clean : Resources.BuildActionCancelled; - else if (!buildInfo.BuildedProjects.BuildWithoutErrors) - return buildAction.Value == BuildActions.BuildActionClean ? Resources.BuildActionFailed_Clean : Resources.BuildActionFailed; - else if (errorStateProjectsCount == 0) - return buildAction.Value == BuildActions.BuildActionClean ? Resources.BuildActionFinishedSuccessfully_Clean : Resources.BuildActionFinishedSuccessfully; - else - return buildAction.Value == BuildActions.BuildActionClean ? Resources.BuildActionFinished_Clean : Resources.BuildActionFinished; - } - - private static string GetBuildDoneExtraMessage(IBuildInfo buildInfo, BuildMessagesSettings labelsSettings) + private string GetBuildDoneExtraMessage(VisualStudioSolution solutionItem) { - if (buildInfo?.BuildStartTime == null || buildInfo?.BuildFinishTime == null || !labelsSettings.ShowExtraMessage) + if (solutionItem.BuildStartTime == null || solutionItem.BuildFinishTime == null || !_labelSettings.ShowExtraMessage) return string.Empty; - TimeSpan timeSpan = buildInfo.BuildFinishTime.Value.Subtract(buildInfo.BuildStartTime.Value); - string extraTimePartString = GetExtraTimePartString(labelsSettings, timeSpan); - return string.Format(labelsSettings.ExtraMessageStringFormat, extraTimePartString); + TimeSpan timeSpan = solutionItem.BuildFinishTime.Value.Subtract(solutionItem.BuildStartTime.Value); + string extraTimePartString = GetExtraTimePartString(timeSpan); + return string.Format(_labelSettings.ExtraMessageStringFormat, extraTimePartString); } - private static string GetExtraTimePartString(BuildMessagesSettings labelsSettings, TimeSpan timeSpan) + private string GetExtraTimePartString(TimeSpan timeSpan) { string extraTimePartString; - switch (labelsSettings.ExtraMessageFormat) + switch (_labelSettings.ExtraMessageFormat) { case BuildExtraMessageFormat.Custom: try { - extraTimePartString = timeSpan.ToString(labelsSettings.TimeSpanFormat); + extraTimePartString = timeSpan.ToString(_labelSettings.TimeSpanFormat); } catch (FormatException) { @@ -310,10 +278,10 @@ private static string GetExtraTimePartString(BuildMessagesSettings labelsSetting break; default: - throw new ArgumentOutOfRangeException(nameof(labelsSettings.ExtraMessageFormat)); + throw new ArgumentOutOfRangeException(nameof(_labelSettings.ExtraMessageFormat)); } - return string.Format(labelsSettings.ExtraMessageStringFormat, extraTimePartString); + return string.Format(_labelSettings.ExtraMessageStringFormat, extraTimePartString); } } } diff --git a/src/BuildVision.UI/Models/ResetTaskBarItemInfoCondition.cs b/src/BuildVision.UI/Helpers/ResetTaskBarItemInfoCondition.cs similarity index 99% rename from src/BuildVision.UI/Models/ResetTaskBarItemInfoCondition.cs rename to src/BuildVision.UI/Helpers/ResetTaskBarItemInfoCondition.cs index 4cc63b53..2af5da3f 100644 --- a/src/BuildVision.UI/Models/ResetTaskBarItemInfoCondition.cs +++ b/src/BuildVision.UI/Helpers/ResetTaskBarItemInfoCondition.cs @@ -16,4 +16,4 @@ public enum ResetTaskBarItemInfoCondition [DisplayString(ResourceName = nameof(Resources.ResetTaskBarItemInfoCondition_ByMouseClick))] ByMouseClick } -} \ No newline at end of file +} diff --git a/src/BuildVision.UI/Settings/Models/Sorting/SortDescription.cs b/src/BuildVision.UI/Helpers/SortDescription.cs similarity index 100% rename from src/BuildVision.UI/Settings/Models/Sorting/SortDescription.cs rename to src/BuildVision.UI/Helpers/SortDescription.cs diff --git a/src/BuildVision.UI/Models/SortOrder.cs b/src/BuildVision.UI/Helpers/SortOrder.cs similarity index 100% rename from src/BuildVision.UI/Models/SortOrder.cs rename to src/BuildVision.UI/Helpers/SortOrder.cs diff --git a/src/BuildVision.UI/Models/WindowState.cs b/src/BuildVision.UI/Helpers/WindowState.cs similarity index 100% rename from src/BuildVision.UI/Models/WindowState.cs rename to src/BuildVision.UI/Helpers/WindowState.cs diff --git a/src/BuildVision.UI/Settings/Models/ToolWindow/WindowStateAction.cs b/src/BuildVision.UI/Helpers/WindowStateAction.cs similarity index 100% rename from src/BuildVision.UI/Settings/Models/ToolWindow/WindowStateAction.cs rename to src/BuildVision.UI/Helpers/WindowStateAction.cs diff --git a/src/BuildVision.UI/IBuildVisionPaneViewModel.cs b/src/BuildVision.UI/IBuildVisionPaneViewModel.cs deleted file mode 100644 index 5e30ae7c..00000000 --- a/src/BuildVision.UI/IBuildVisionPaneViewModel.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using BuildVision.UI.Models; - -namespace BuildVision.UI -{ - public interface IBuildVisionPaneViewModel - { - SolutionItem SolutionItem { get; } - - ObservableCollection ProjectsList { get;} - } -} diff --git a/src/BuildVision/Tool/Views/Settings/IPackageSettingsProvider.cs b/src/BuildVision.UI/IPackageSettingsProvider.cs similarity index 100% rename from src/BuildVision/Tool/Views/Settings/IPackageSettingsProvider.cs rename to src/BuildVision.UI/IPackageSettingsProvider.cs diff --git a/src/BuildVision.Contracts/BaseGridColumnSettings.cs b/src/BuildVision.UI/Models/BaseGridColumnSettings.cs similarity index 100% rename from src/BuildVision.Contracts/BaseGridColumnSettings.cs rename to src/BuildVision.UI/Models/BaseGridColumnSettings.cs diff --git a/src/BuildVision.UI/Settings/Models/BuildMessagesSettings.cs b/src/BuildVision.UI/Models/BuildMessagesSettings.cs similarity index 100% rename from src/BuildVision.UI/Settings/Models/BuildMessagesSettings.cs rename to src/BuildVision.UI/Models/BuildMessagesSettings.cs diff --git a/src/BuildVision.UI/Settings/Models/BuildProgress/BuildProgressSettings.cs b/src/BuildVision.UI/Models/BuildProgressSettings.cs similarity index 100% rename from src/BuildVision.UI/Settings/Models/BuildProgress/BuildProgressSettings.cs rename to src/BuildVision.UI/Models/BuildProgressSettings.cs diff --git a/src/BuildVision.UI/Models/ControlModel.cs b/src/BuildVision.UI/Models/ControlModel.cs deleted file mode 100644 index 6e28a4ae..00000000 --- a/src/BuildVision.UI/Models/ControlModel.cs +++ /dev/null @@ -1,32 +0,0 @@ -using BuildVision.UI.Extensions; -using BuildVision.UI.Helpers; -using BuildVision.UI.Models.Indicators.Core; -using System.Collections.ObjectModel; -using System.Windows.Controls; - -namespace BuildVision.UI.Models -{ - public class ControlModel - { - public ProjectItem CurrentProject { get; set; } - - public ControlTemplate ImageCurrentState { get; set; } - - public ControlTemplate ImageCurrentStateResult { get; set; } - - public string TextCurrentState { get; set; } - - public SolutionItem SolutionItem { get; set; } - - public ObservableCollection ValueIndicators { get; set; } - - public ControlModel() - { - ValueIndicators = ValueIndicatorsFactory.CreateCollection(); - SolutionItem = new SolutionItem(); - TextCurrentState = Resources.BuildDoneText_BuildNotStarted; - ImageCurrentState = VectorResources.TryGet(BuildImages.BuildActionResourcesUri, "StandBy"); - ImageCurrentStateResult = null; - } - } -} diff --git a/src/BuildVision.UI/Models/ControlSettings.cs b/src/BuildVision.UI/Models/ControlSettings.cs new file mode 100644 index 00000000..db7c7527 --- /dev/null +++ b/src/BuildVision.UI/Models/ControlSettings.cs @@ -0,0 +1,46 @@ +using System.Runtime.Serialization; +using BuildVision.Common; + +namespace BuildVision.UI.Settings.Models +{ + public class ControlSettings : SettingsBase + { + public BuildMessagesSettings BuildMessagesSettings { get; set; } + + public GeneralSettings GeneralSettings { get; set; } + + public GridSettings GridSettings { get; set; } + + public ProjectItemSettings ProjectItemSettings { get; set; } + + public WindowSettings WindowSettings { get; set; } + + public ControlSettings() + { + Init(); + } + + private void OnDeserialized(StreamingContext context) + { + Init(); + } + + private void Init() + { + if (GeneralSettings == null) + GeneralSettings = new GeneralSettings(); + + if (WindowSettings == null) + WindowSettings = new WindowSettings(); + + if (GridSettings == null) + GridSettings = new GridSettings(); + + if (BuildMessagesSettings == null) + BuildMessagesSettings = new BuildMessagesSettings(); + + if (ProjectItemSettings == null) + ProjectItemSettings = new ProjectItemSettings(); + } + } +} diff --git a/src/BuildVision.UI/Settings/Models/GeneralSettings.cs b/src/BuildVision.UI/Models/GeneralSettings.cs similarity index 100% rename from src/BuildVision.UI/Settings/Models/GeneralSettings.cs rename to src/BuildVision.UI/Models/GeneralSettings.cs diff --git a/src/BuildVision.UI/Settings/Models/Columns/GridColumnSettings.cs b/src/BuildVision.UI/Models/GridColumnSettings.cs similarity index 100% rename from src/BuildVision.UI/Settings/Models/Columns/GridColumnSettings.cs rename to src/BuildVision.UI/Models/GridColumnSettings.cs diff --git a/src/BuildVision.UI/Settings/Models/Columns/GridColumnSettingsCollection.cs b/src/BuildVision.UI/Models/GridColumnSettingsCollection.cs similarity index 100% rename from src/BuildVision.UI/Settings/Models/Columns/GridColumnSettingsCollection.cs rename to src/BuildVision.UI/Models/GridColumnSettingsCollection.cs diff --git a/src/BuildVision.UI/Settings/Models/GridSettings.cs b/src/BuildVision.UI/Models/GridSettings.cs similarity index 100% rename from src/BuildVision.UI/Settings/Models/GridSettings.cs rename to src/BuildVision.UI/Models/GridSettings.cs diff --git a/src/BuildVision.UI/Models/Indicators/Core/ResetIndicatorMode.cs b/src/BuildVision.UI/Models/Indicators/Core/ResetIndicatorMode.cs deleted file mode 100644 index 0bba806a..00000000 --- a/src/BuildVision.UI/Models/Indicators/Core/ResetIndicatorMode.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace BuildVision.UI.Models.Indicators.Core -{ - public enum ResetIndicatorMode - { - ResetValue, - Disable - } -} \ No newline at end of file diff --git a/src/BuildVision.UI/Models/Indicators/Core/ValueIndicator.cs b/src/BuildVision.UI/Models/Indicators/Core/ValueIndicator.cs deleted file mode 100644 index 6536e2de..00000000 --- a/src/BuildVision.UI/Models/Indicators/Core/ValueIndicator.cs +++ /dev/null @@ -1,130 +0,0 @@ -using System; -using BuildVision.Common; -using BuildVision.UI; -using BuildVision.UI.Contracts; -using BuildVision.UI.Common.Logging; - -namespace BuildVision.UI.Models.Indicators.Core -{ - public abstract class ValueIndicator : BindableBase - { - private int? _value; - private bool _isEnabled; - private bool _isUpdateError; - private string _lastErrorMessage; - - public const string ResourcesUri = @"Resources/ValueIndicator.Resources.xaml"; - - public abstract string Header { get; } - - public abstract string Description { get; } - - protected abstract int? GetValue(IBuildInfo buildContext); - - public int? Value => _value; - public bool IsEnabled => _isEnabled; - - public virtual string StringValue - { - get - { - if (_isUpdateError) - return Resources.GridCellNAText; - - return Value != null ? Value.ToString() : "0"; - } - } - - public bool IsUpdateError - { - get { return _isUpdateError; } - set => SetProperty(ref _isUpdateError, value); - } - - public string LastErrorMessage - { - get { return _lastErrorMessage; } - set - { - SetProperty(ref _lastErrorMessage, value); - OnPropertyChanged(nameof(ToolTip)); - } - } - - public string ToolTip - { - get - { - if (!IsUpdateError) - return Header; - - return string.Format("{0}{1}{2}", - Header, - Environment.NewLine, - string.IsNullOrEmpty(LastErrorMessage) ? "Unknown error" : LastErrorMessage); - } - } - - public virtual double Width - { - get { return double.NaN; } - } - - public void UpdateValue(IBuildInfo buildContext) - { - UpdateValueAction(buildContext); - } - - public void ResetValue(ResetIndicatorMode resetMode) - { - switch (resetMode) - { - case ResetIndicatorMode.ResetValue: - IsUpdateError = false; - _value = null; - _isEnabled = true; - break; - - case ResetIndicatorMode.Disable: - IsUpdateError = false; - _value = null; - _isEnabled = false; - break; - - default: - throw new ArgumentOutOfRangeException(nameof(resetMode)); - } - - RaiseValueChanged(); - } - - private void UpdateValueAction(IBuildInfo buildContext) - { - IsUpdateError = false; - _isEnabled = true; - - try - { - var currentValue = GetValue(buildContext); - _value = currentValue; - LastErrorMessage = null; - } - catch (Exception ex) - { - _value = null; - IsUpdateError = true; - LastErrorMessage = ex.Message; - ex.TraceUnknownException(); - } - - RaiseValueChanged(); - } - - private void RaiseValueChanged() - { - OnPropertyChanged(nameof(Value)); - OnPropertyChanged(nameof(StringValue)); - OnPropertyChanged(nameof(IsEnabled)); - } - } -} diff --git a/src/BuildVision.UI/Models/Indicators/Core/ValueIndicatorsFactory.cs b/src/BuildVision.UI/Models/Indicators/Core/ValueIndicatorsFactory.cs deleted file mode 100644 index 2e961f6f..00000000 --- a/src/BuildVision.UI/Models/Indicators/Core/ValueIndicatorsFactory.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System.Collections.ObjectModel; - -namespace BuildVision.UI.Models.Indicators.Core -{ - public static class ValueIndicatorsFactory - { - public static ObservableCollection CreateCollection() - { - return new ObservableCollection - { - new ErrorsIndicator(), - new WarningsIndicator(), - new MessagesIndicator(), - - new SeparatorIndicator(), - - new SuccessProjectsIndicator(), - new UpToDateProjectsIndicator(), - new WarningProjectsIndicator(), - new ErrorProjectsIndicator() - }; - } - } -} diff --git a/src/BuildVision.UI/Models/Indicators/ErrorProjectsIndicator.cs b/src/BuildVision.UI/Models/Indicators/ErrorProjectsIndicator.cs deleted file mode 100644 index 720bcaab..00000000 --- a/src/BuildVision.UI/Models/Indicators/ErrorProjectsIndicator.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; - -using BuildVision.UI; -using BuildVision.UI.Models.Indicators.Core; -using BuildVision.UI.Contracts; - -namespace BuildVision.UI.Models.Indicators -{ - public class ErrorProjectsIndicator : ValueIndicator - { - public override string Header => Resources.ErrorProjectsIndicator_Header; - public override string Description => Resources.ErrorProjectsIndicator_Description; - - protected override int? GetValue(IBuildInfo buildContext) - { - try - { - return buildContext.BuildedProjects.BuildErrorCount; - } - catch (NullReferenceException) - { - return null; - } - } - } -} diff --git a/src/BuildVision.UI/Models/Indicators/ErrorsIndicator.cs b/src/BuildVision.UI/Models/Indicators/ErrorsIndicator.cs deleted file mode 100644 index 08446ea3..00000000 --- a/src/BuildVision.UI/Models/Indicators/ErrorsIndicator.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System.Linq; - -using BuildVision.UI; -using BuildVision.UI.Models.Indicators.Core; -using BuildVision.UI.Contracts; - -namespace BuildVision.UI.Models.Indicators -{ - public class ErrorsIndicator : ValueIndicator - { - public override string Header => Resources.ErrorsIndicator_Header; - public override string Description => Resources.ErrorsIndicator_Description; - - protected override int? GetValue( IBuildInfo buildContext) - { - return buildContext.BuildedProjects.Sum(proj => proj.ErrorsBox.ErrorsCount); - } - } -} \ No newline at end of file diff --git a/src/BuildVision.UI/Models/Indicators/MessagesIndicator.cs b/src/BuildVision.UI/Models/Indicators/MessagesIndicator.cs deleted file mode 100644 index 450576bd..00000000 --- a/src/BuildVision.UI/Models/Indicators/MessagesIndicator.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System.Linq; - -using BuildVision.UI; -using BuildVision.UI.Models.Indicators.Core; -using BuildVision.UI.Contracts; - -namespace BuildVision.UI.Models.Indicators -{ - public class MessagesIndicator : ValueIndicator - { - public override string Header => Resources.MessagesIndicator_Header; - public override string Description => Resources.MessagesIndicator_Description; - - protected override int? GetValue(IBuildInfo buildContext) - { - return buildContext.BuildedProjects.Sum(proj => proj.ErrorsBox.MessagesCount); - } - } -} \ No newline at end of file diff --git a/src/BuildVision.UI/Models/Indicators/SeparatorIndicator.cs b/src/BuildVision.UI/Models/Indicators/SeparatorIndicator.cs deleted file mode 100644 index 8691c5b6..00000000 --- a/src/BuildVision.UI/Models/Indicators/SeparatorIndicator.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System.Linq; - -using BuildVision.UI; -using BuildVision.UI.Models.Indicators.Core; -using BuildVision.UI.Contracts; - -namespace BuildVision.UI.Models.Indicators -{ - public class SeparatorIndicator : ValueIndicator - { - public override string Header => Resources.SeparatorIndicator_Header; - public override string Description => null; - public override string StringValue => string.Empty; - public override double Width => 20; - - protected override int? GetValue(IBuildInfo buildContext) - { - return null; - } - } -} \ No newline at end of file diff --git a/src/BuildVision.UI/Models/Indicators/SuccessProjectsIndicator.cs b/src/BuildVision.UI/Models/Indicators/SuccessProjectsIndicator.cs deleted file mode 100644 index 87bbe666..00000000 --- a/src/BuildVision.UI/Models/Indicators/SuccessProjectsIndicator.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System.Linq; - -using BuildVision.UI; -using BuildVision.UI.Models.Indicators.Core; -using BuildVision.UI.Contracts; -using System; - -namespace BuildVision.UI.Models.Indicators -{ - public class SuccessProjectsIndicator : ValueIndicator - { - public override string Header => Resources.SuccessProjectsIndicator_Header; - public override string Description => Resources.SuccessProjectsIndicator_Description; - - protected override int? GetValue(IBuildInfo buildContext) - { - try - { - return buildContext.BuildedProjects.BuildSuccessCount; - } - catch (NullReferenceException) - { - return null; - } - } - } -} \ No newline at end of file diff --git a/src/BuildVision.UI/Models/Indicators/UpToDateProjectsIndicator.cs b/src/BuildVision.UI/Models/Indicators/UpToDateProjectsIndicator.cs deleted file mode 100644 index 01a4b84f..00000000 --- a/src/BuildVision.UI/Models/Indicators/UpToDateProjectsIndicator.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; -using BuildVision.UI.Models.Indicators.Core; -using BuildVision.UI.Contracts; - -namespace BuildVision.UI.Models.Indicators -{ - public class UpToDateProjectsIndicator : ValueIndicator - { - public override string Header => Resources.UpToDateProjectsIndicator_Header; - public override string Description => Resources.UpToDateProjectsIndicator_Description; - - protected override int? GetValue(IBuildInfo buildContext) - { - try - { - return buildContext.BuildedProjects.BuildUpToDateCount; - } - catch (NullReferenceException) - { - return null; - } - } - } -} diff --git a/src/BuildVision.UI/Models/Indicators/WarningProjectsIndicator.cs b/src/BuildVision.UI/Models/Indicators/WarningProjectsIndicator.cs deleted file mode 100644 index aa609d28..00000000 --- a/src/BuildVision.UI/Models/Indicators/WarningProjectsIndicator.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; -using BuildVision.UI.Models.Indicators.Core; -using BuildVision.UI.Contracts; - -namespace BuildVision.UI.Models.Indicators -{ - public class WarningProjectsIndicator : ValueIndicator - { - public override string Header => Resources.WarningProjectsIndicator_Header; - public override string Description => Resources.WarningProjectsIndicator_Description; - - protected override int? GetValue(IBuildInfo buildContext) - { - try - { - return buildContext.BuildedProjects.BuildWarningsCount; - } - catch (NullReferenceException) - { - return null; - } - } - } -} diff --git a/src/BuildVision.UI/Models/Indicators/WarningsIndicator.cs b/src/BuildVision.UI/Models/Indicators/WarningsIndicator.cs deleted file mode 100644 index 83e55861..00000000 --- a/src/BuildVision.UI/Models/Indicators/WarningsIndicator.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System.Linq; - -using BuildVision.UI.Models.Indicators.Core; -using BuildVision.UI.Contracts; - -namespace BuildVision.UI.Models.Indicators -{ - public class WarningsIndicator : ValueIndicator - { - public override string Header => Resources.WarningsIndicator_Header; - public override string Description => Resources.WarningsIndicator_Description; - - protected override int? GetValue(IBuildInfo buildContext) - { - return buildContext.BuildedProjects.Sum(proj => proj.ErrorsBox.WarningsCount); - } - } -} \ No newline at end of file diff --git a/src/BuildVision.UI/Models/ProjectItem.cs b/src/BuildVision.UI/Models/ProjectItem.cs index 959949fc..fa5539f6 100644 --- a/src/BuildVision.UI/Models/ProjectItem.cs +++ b/src/BuildVision.UI/Models/ProjectItem.cs @@ -5,278 +5,278 @@ using BuildVision.Contracts; using BuildVision.UI.Modelss; using BuildVision.UI.Extensions; -using BuildVision.UI.Models.Indicators.Core; namespace BuildVision.UI.Models { - public class ProjectItem : BindableBase - { - private const string ResourcesUri = @"Resources/ProjectItem.Resources.xaml"; - - public ProjectItem() + public class ProjectItem : BindableBase { - State = ProjectState.Pending; - } + private const string ResourcesUri = @"Resources/ProjectItem.Resources.xaml"; - public bool IsBatchBuildProject { get; set; } + public ProjectItem() + { + State = ProjectState.Pending; + } - private string _uniqueName; + public bool IsBatchBuildProject { get; set; } - [GridColumn("ProjectItemHeader_UniqueName", ColumnsOrder.UniqueName, false, ExampleValue = @"ConsoleApplication1\ConsoleApplication1.csproj")] - public string UniqueName - { - get => _uniqueName; - set => SetProperty(ref _uniqueName, value); - } + private string _uniqueName; - private string _name; + [GridColumn("ProjectItemHeader_UniqueName", ColumnsOrder.UniqueName, false, ExampleValue = @"ConsoleApplication1\ConsoleApplication1.csproj")] + public string UniqueName + { + get => _uniqueName; + set => SetProperty(ref _uniqueName, value); + } - [GridColumn("ProjectItemHeader_Name", ColumnsOrder.Name, true, ExampleValue = @"ConsoleApplication1")] - public string Name - { - get => _name; - set => SetProperty(ref _name, value); - } + private string _name; - private string _fullName; + [GridColumn("ProjectItemHeader_Name", ColumnsOrder.Name, true, ExampleValue = @"ConsoleApplication1")] + public string Name + { + get => _name; + set => SetProperty(ref _name, value); + } - [GridColumn("ProjectItemHeader_FullName", ColumnsOrder.FullName, false, ExampleValue = @"D:\Projects\ConsoleApplication1\ConsoleApplication1.csproj")] - public string FullName - { - get => _fullName; - set => SetProperty(ref _fullName, value); - } + private string _fullName; - private string _fullPath; + [GridColumn("ProjectItemHeader_FullName", ColumnsOrder.FullName, false, ExampleValue = @"D:\Projects\ConsoleApplication1\ConsoleApplication1.csproj")] + public string FullName + { + get => _fullName; + set => SetProperty(ref _fullName, value); + } - [GridColumn("ProjectItemHeader_FullPath", ColumnsOrder.FullPath, false, ExampleValue = @"D:\Projects\ConsoleApplication1")] - public string FullPath - { - get => _fullPath; - set => SetProperty(ref _fullPath, value); - } + private string _fullPath; - private string _language; + [GridColumn("ProjectItemHeader_FullPath", ColumnsOrder.FullPath, false, ExampleValue = @"D:\Projects\ConsoleApplication1")] + public string FullPath + { + get => _fullPath; + set => SetProperty(ref _fullPath, value); + } - [GridColumn("ProjectItemHeader_Language", ColumnsOrder.Language, true, ExampleValue = @"C#")] - public string Language - { - get => _language; - set => SetProperty(ref _language, value); - } + private string _language; - private string _commonType; + [GridColumn("ProjectItemHeader_Language", ColumnsOrder.Language, true, ExampleValue = @"C#")] + public string Language + { + get => _language; + set => SetProperty(ref _language, value); + } - /// - /// See registered types in HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\[Version "11.0"]\Projects. - /// - [GridColumn("ProjectItemHeader_CommonType", ColumnsOrder.CommonType, false, ExampleValue = @"Windows")] - public string CommonType - { - get => _commonType; - set => SetProperty(ref _commonType, value); - } + private string _commonType; - private string _configuration; + /// + /// See registered types in HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\[Version "11.0"]\Projects. + /// + [GridColumn("ProjectItemHeader_CommonType", ColumnsOrder.CommonType, false, ExampleValue = @"Windows")] + public string CommonType + { + get => _commonType; + set => SetProperty(ref _commonType, value); + } - [GridColumn("ProjectItemHeader_Configuration", ColumnsOrder.Configuration, true, ExampleValue = @"Debug")] - public string Configuration - { - get => _configuration; - set => SetProperty(ref _configuration, value); - } + private string _configuration; - private string _platform; + [GridColumn("ProjectItemHeader_Configuration", ColumnsOrder.Configuration, true, ExampleValue = @"Debug")] + public string Configuration + { + get => _configuration; + set => SetProperty(ref _configuration, value); + } - [GridColumn("ProjectItemHeader_Platform", ColumnsOrder.Platform, true, ExampleValue = @"x86")] - public string Platform - { - get => _platform; - set => SetProperty(ref _platform, value); - } + private string _platform; - private ProjectState _state; + [GridColumn("ProjectItemHeader_Platform", ColumnsOrder.Platform, true, ExampleValue = @"x86")] + public string Platform + { + get => _platform; + set => SetProperty(ref _platform, value); + } - [GridColumn("ProjectItemHeader_State", ColumnsOrder.State, true, ExampleValue = @"BuildDone")] - public ProjectState State - { - get => _state; - set - { - SetProperty(ref _state, value); - OnPropertyChanged(nameof(StateBitmap)); - } - } + private ProjectState _state; - [GridColumn("ProjectItemHeader_StateBitmap", ColumnsOrder.StateBitmap, true, ImageKey = GridColumnAttribute.EmptyHeaderImageKey)] - public ControlTemplate StateBitmap => _state.GetAssociatedContent(); + [GridColumn("ProjectItemHeader_State", ColumnsOrder.State, true, ExampleValue = @"BuildDone")] + public ProjectState State + { + get => _state; + set + { + SetProperty(ref _state, value); + OnPropertyChanged(nameof(StateBitmap)); + } + } - private DateTime? _buildStartTime; + [GridColumn("ProjectItemHeader_StateBitmap", ColumnsOrder.StateBitmap, true, ImageKey = GridColumnAttribute.EmptyHeaderImageKey)] + public ControlTemplate StateBitmap => _state.GetAssociatedContent(); - [GridColumn("ProjectItemHeader_BuildStartTime", ColumnsOrder.BuildStartTime, true, ValueStringFormat = @"HH:mm:ss", DateTimeExampleValue = @"2012-07-27T20:06:12.3691406+06:00")] - public DateTime? BuildStartTime - { - get => _buildStartTime; - set - { - SetProperty(ref _buildStartTime, value); - OnPropertyChanged(nameof(BuildStartTime)); - OnPropertyChanged(nameof(BuildElapsedTime)); - } - } + private DateTime? _buildStartTime; - private DateTime? _buildFinishTime; + [GridColumn("ProjectItemHeader_BuildStartTime", ColumnsOrder.BuildStartTime, true, ValueStringFormat = @"HH:mm:ss", DateTimeExampleValue = @"2012-07-27T20:06:12.3691406+06:00")] + public DateTime? BuildStartTime + { + get => _buildStartTime; + set + { + SetProperty(ref _buildStartTime, value); + OnPropertyChanged(nameof(BuildStartTime)); + OnPropertyChanged(nameof(BuildElapsedTime)); + } + } - [GridColumn("ProjectItemHeader_BuildFinishTime", ColumnsOrder.BuildFinishTime, true, ValueStringFormat = @"HH:mm:ss", DateTimeExampleValue = @"2012-07-27T20:06:12.3691406+06:00")] - public DateTime? BuildFinishTime - { - get => _buildFinishTime; - set - { - SetProperty(ref _buildFinishTime, value); - OnPropertyChanged(nameof(BuildFinishTime)); - OnPropertyChanged(nameof(BuildElapsedTime)); - } - } + private DateTime? _buildFinishTime; - [GridColumn("ProjectItemHeader_BuildElapsedTime", ColumnsOrder.BuildElapsedTime, true, ValueStringFormat = @"mm\:ss", TimeSpanExampleValue = @"00:09:21.60")] - public TimeSpan? BuildElapsedTime - { - get - { - if (_buildStartTime == null) - return null; + [GridColumn("ProjectItemHeader_BuildFinishTime", ColumnsOrder.BuildFinishTime, true, ValueStringFormat = @"HH:mm:ss", DateTimeExampleValue = @"2012-07-27T20:06:12.3691406+06:00")] + public DateTime? BuildFinishTime + { + get => _buildFinishTime; + set + { + SetProperty(ref _buildFinishTime, value); + OnPropertyChanged(nameof(BuildFinishTime)); + OnPropertyChanged(nameof(BuildElapsedTime)); + } + } - if (_buildFinishTime == null) - return DateTime.Now.Subtract(_buildStartTime.Value); + [GridColumn("ProjectItemHeader_BuildElapsedTime", ColumnsOrder.BuildElapsedTime, true, ValueStringFormat = @"mm\:ss", TimeSpanExampleValue = @"00:09:21.60")] + public TimeSpan? BuildElapsedTime + { + get + { + if (_buildStartTime == null) + return null; - return _buildFinishTime.Value.Truncate(TimeSpan.FromSeconds(1)) - .Subtract(_buildStartTime.Value.Truncate(TimeSpan.FromSeconds(1))); - } - } + if (_buildFinishTime == null) + return DateTime.Now.Subtract(_buildStartTime.Value); - private ErrorsBox _errorsBox; + return _buildFinishTime.Value.Truncate(TimeSpan.FromSeconds(1)) + .Subtract(_buildStartTime.Value.Truncate(TimeSpan.FromSeconds(1))); + } + } - public ErrorsBox ErrorsBox - { - get { return _errorsBox ?? (_errorsBox = new ErrorsBox()); } - set - { - if (_errorsBox != value) + private ErrorsBox _errorsBox; + + public ErrorsBox ErrorsBox { - _errorsBox = value; - OnPropertyChanged("ErrorsBox"); - OnPropertyChanged("ErrorsCount"); - OnPropertyChanged("WarningsCount"); - OnPropertyChanged("MessagesCount"); + get { return _errorsBox ?? (_errorsBox = new ErrorsBox()); } + set + { + if (_errorsBox != value) + { + _errorsBox = value; + OnPropertyChanged("ErrorsBox"); + OnPropertyChanged("ErrorsCount"); + OnPropertyChanged("WarningsCount"); + OnPropertyChanged("MessagesCount"); + } + } } - } - } - [GridColumn("ProjectItemHeader_ErrorsCount", ColumnsOrder.ErrorsCount, true, ImageDictionaryUri = ValueIndicator.ResourcesUri, ImageKey = "ErrorsIndicator", ExampleValue = 4)] - public int ErrorsCount => ErrorsBox.ErrorsCount; - [GridColumn("ProjectItemHeader_WarningsCount", ColumnsOrder.WarningsCount, true, ImageDictionaryUri = ValueIndicator.ResourcesUri, ImageKey = "WarningsIndicator", ExampleValue = 1253)] - public int WarningsCount => ErrorsBox.WarningsCount; - [GridColumn("ProjectItemHeader_MessagesCount", ColumnsOrder.MessagesCount, false, ImageDictionaryUri = ValueIndicator.ResourcesUri, ImageKey = "MessagesIndicator", ExampleValue = 2)] - public int MessagesCount => ErrorsBox.MessagesCount; + [GridColumn("ProjectItemHeader_ErrorsCount", ColumnsOrder.ErrorsCount, true, ImageDictionaryUri = "Resources/ValueIndicator.Resources.xaml", ImageKey = "ErrorsIndicator", ExampleValue = 4)] + public int ErrorsCount => ErrorsBox.ErrorsCount; + [GridColumn("ProjectItemHeader_WarningsCount", ColumnsOrder.WarningsCount, true, ImageDictionaryUri = "Resources/ValueIndicator.Resources.xaml", ImageKey = "WarningsIndicator", ExampleValue = 1253)] + public int WarningsCount => ErrorsBox.WarningsCount; + [GridColumn("ProjectItemHeader_MessagesCount", ColumnsOrder.MessagesCount, false, ImageDictionaryUri = "Resources/ValueIndicator.Resources.xaml", ImageKey = "MessagesIndicator", ExampleValue = 2)] + public int MessagesCount => ErrorsBox.MessagesCount; - private string _framework; + private string _framework; - [GridColumn("ProjectItemHeader_Framework", ColumnsOrder.Framework, false, ExampleValue = @"3.5")] - public string Framework - { - get => _framework; - set => SetProperty(ref _framework, value); - } + [GridColumn("ProjectItemHeader_Framework", ColumnsOrder.Framework, false, ExampleValue = @"3.5")] + public string Framework + { + get => _framework; + set => SetProperty(ref _framework, value); + } - private string _flavourType; + private string _flavourType; - [GridColumn("ProjectItemHeader_FlavourType", ColumnsOrder.FlavourType, true, ExampleValue = @"Windows; VSTA")] - public string FlavourType - { - get => _flavourType; - set => SetProperty(ref _flavourType, value); - } + [GridColumn("ProjectItemHeader_FlavourType", ColumnsOrder.FlavourType, true, ExampleValue = @"Windows; VSTA")] + public string FlavourType + { + get => _flavourType; + set => SetProperty(ref _flavourType, value); + } - private string _mainFlavourType; + private string _mainFlavourType; - [GridColumn("ProjectItemHeader_MainFlavourType", ColumnsOrder.MainFlavourType, false, ExampleValue = @"VSTA")] - public string MainFlavourType - { - get => _mainFlavourType; - set => SetProperty(ref _mainFlavourType, value); - } + [GridColumn("ProjectItemHeader_MainFlavourType", ColumnsOrder.MainFlavourType, false, ExampleValue = @"VSTA")] + public string MainFlavourType + { + get => _mainFlavourType; + set => SetProperty(ref _mainFlavourType, value); + } - private string _outputType; + private string _outputType; - [GridColumn("ProjectItemHeader_OutputType", ColumnsOrder.OutputType, false, ExampleValue = @"Library")] - public string OutputType - { - get => _outputType; - set => SetProperty(ref _outputType, value); - } + [GridColumn("ProjectItemHeader_OutputType", ColumnsOrder.OutputType, false, ExampleValue = @"Library")] + public string OutputType + { + get => _outputType; + set => SetProperty(ref _outputType, value); + } - private string _extenderNames; + private string _extenderNames; - [GridColumn("ProjectItemHeader_ExtenderNames", ColumnsOrder.ExtenderNames, false, ExampleValue = @"VST")] - public string ExtenderNames - { - get => _extenderNames; - set => SetProperty(ref _extenderNames, value); - } + [GridColumn("ProjectItemHeader_ExtenderNames", ColumnsOrder.ExtenderNames, false, ExampleValue = @"VST")] + public string ExtenderNames + { + get => _extenderNames; + set => SetProperty(ref _extenderNames, value); + } - private int? _buildOrder; + private int? _buildOrder; - [GridColumn("ProjectItemHeader_BuildOrder", ColumnsOrder.BuildOrder, false, ImageDictionaryUri = ResourcesUri, ImageKey = "BuildOrder", Width = 23, ExampleValue = 4)] - public int? BuildOrder - { - get => _buildOrder; - set => SetProperty(ref _buildOrder, value); - } + [GridColumn("ProjectItemHeader_BuildOrder", ColumnsOrder.BuildOrder, false, ImageDictionaryUri = ResourcesUri, ImageKey = "BuildOrder", Width = 23, ExampleValue = 4)] + public int? BuildOrder + { + get => _buildOrder; + set => SetProperty(ref _buildOrder, value); + } - private string _rootNamespace; + private string _rootNamespace; - [GridColumn("ProjectItemHeader_RootNamespace", ColumnsOrder.RootNamespace, false, ExampleValue = @"MyApplication")] - public string RootNamespace - { - get => _rootNamespace; - set => SetProperty(ref _rootNamespace, value); - } + [GridColumn("ProjectItemHeader_RootNamespace", ColumnsOrder.RootNamespace, false, ExampleValue = @"MyApplication")] + public string RootNamespace + { + get => _rootNamespace; + set => SetProperty(ref _rootNamespace, value); + } - private string _solutionFolder; + private string _solutionFolder; - [GridColumn("ProjectItemHeader_SolutionFolder", ColumnsOrder.SolutionFolder, false, ExampleValue = @"SolutionFolder1\SolutionFolder2")] - public string SolutionFolder - { - get => _solutionFolder; - set => SetProperty(ref _solutionFolder, value); - } + [GridColumn("ProjectItemHeader_SolutionFolder", ColumnsOrder.SolutionFolder, false, ExampleValue = @"SolutionFolder1\SolutionFolder2")] + public string SolutionFolder + { + get => _solutionFolder; + set => SetProperty(ref _solutionFolder, value); + } + public bool Success { get; set; } - public ProjectItem GetBatchBuildCopy(string configuration, string platform) - { - var pi = Clone(); - pi.Configuration = configuration; - pi.Platform = platform; - pi.ErrorsBox = new ErrorsBox(); - pi.IsBatchBuildProject = true; - return pi; - } + public ProjectItem GetBatchBuildCopy(string configuration, string platform) + { + var pi = Clone(); + pi.Configuration = configuration; + pi.Platform = platform; + pi.ErrorsBox = new ErrorsBox(); + pi.IsBatchBuildProject = true; + return pi; + } - private ProjectItem Clone() - { - var xmlSerializer = new GenericXmlSerializer(); - return xmlSerializer.Deserialize(xmlSerializer.Serialize(this)); - } + private ProjectItem Clone() + { + var xmlSerializer = new GenericXmlSerializer(); + return xmlSerializer.Deserialize(xmlSerializer.Serialize(this)); + } - public void UpdatePostBuildProperties(BuildedProject buildedProjectInfo) - { - if (buildedProjectInfo != null) - ErrorsBox = buildedProjectInfo.ErrorsBox; - } + public void UpdatePostBuildProperties(BuildedProject buildedProjectInfo) + { + if (buildedProjectInfo != null) + ErrorsBox = buildedProjectInfo.ErrorsBox; + } - public void RaiseBuildElapsedTimeChanged() - { - OnPropertyChanged(nameof(BuildElapsedTime)); + public void RaiseBuildElapsedTimeChanged() + { + OnPropertyChanged(nameof(BuildElapsedTime)); + } } - } -} \ No newline at end of file +} diff --git a/src/BuildVision.UI/Settings/Models/ProjectItemSettings.cs b/src/BuildVision.UI/Models/ProjectItemSettings.cs similarity index 84% rename from src/BuildVision.UI/Settings/Models/ProjectItemSettings.cs rename to src/BuildVision.UI/Models/ProjectItemSettings.cs index 2d171cd6..93108f5d 100644 --- a/src/BuildVision.UI/Settings/Models/ProjectItemSettings.cs +++ b/src/BuildVision.UI/Models/ProjectItemSettings.cs @@ -1,6 +1,5 @@ -using BuildVision.Contracts; -using BuildVision.Common; - +using BuildVision.Common; +using BuildVision.Contracts; namespace BuildVision.UI.Settings.Models { public class ProjectItemSettings : SettingsBase @@ -12,4 +11,4 @@ public ProjectItemSettings() CopyBuildOutputFileTypesToClipboard = new BuildOutputFileTypes(); } } -} \ No newline at end of file +} diff --git a/src/BuildVision.UI/Settings/Models/WindowSettings.cs b/src/BuildVision.UI/Models/WindowSettings.cs similarity index 99% rename from src/BuildVision.UI/Settings/Models/WindowSettings.cs rename to src/BuildVision.UI/Models/WindowSettings.cs index bef48610..d23a0da9 100644 --- a/src/BuildVision.UI/Settings/Models/WindowSettings.cs +++ b/src/BuildVision.UI/Models/WindowSettings.cs @@ -19,4 +19,4 @@ public WindowSettings() WindowActionOnBuildError = new WindowStateAction(WindowState.Show); } } -} \ No newline at end of file +} diff --git a/src/BuildVision.UI/Resources/BuildAction.Resources.Test.xaml b/src/BuildVision.UI/Resources/BuildAction.Resources.Test.xaml index 221e5321..f8987deb 100644 --- a/src/BuildVision.UI/Resources/BuildAction.Resources.Test.xaml +++ b/src/BuildVision.UI/Resources/BuildAction.Resources.Test.xaml @@ -6,7 +6,7 @@ - + @@ -23,7 +23,7 @@ SnapsToDevicePixels="True" ClipToBounds="True" UseLayoutRounding="False" - Template="{StaticResource BuildError}" /> + Template="{StaticResource RebuildSolutionButton}" /> @@ -32,7 +32,7 @@ SnapsToDevicePixels="True" ClipToBounds="True" UseLayoutRounding="False" - Template="{StaticResource BuildDone}" /> + Template="{StaticResource BuildSolutionButton}" /> @@ -41,7 +41,7 @@ SnapsToDevicePixels="True" ClipToBounds="True" UseLayoutRounding="False" - Template="{StaticResource BuildCancelled}" /> + Template="{StaticResource CancelBuildSolutionButton}" /> @@ -50,7 +50,33 @@ SnapsToDevicePixels="True" ClipToBounds="True" UseLayoutRounding="False" - Template="{StaticResource BuildErrorDone}" /> + Template="{StaticResource CleanSolutionButton}" /> + + + + + + + + + + + diff --git a/src/BuildVision.UI/Resources/BuildAction.Resources.xaml b/src/BuildVision.UI/Resources/BuildAction.Resources.xaml index 5ce9a519..6127957e 100644 --- a/src/BuildVision.UI/Resources/BuildAction.Resources.xaml +++ b/src/BuildVision.UI/Resources/BuildAction.Resources.xaml @@ -127,44 +127,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -245,4 +207,4 @@ - \ No newline at end of file + diff --git a/src/BuildVision.UI/Resources/BuildResult.Resources.Test.xaml b/src/BuildVision.UI/Resources/BuildResult.Resources.Test.xaml new file mode 100644 index 00000000..3cd4fd27 --- /dev/null +++ b/src/BuildVision.UI/Resources/BuildResult.Resources.Test.xaml @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/BuildVision.UI/Resources/BuildResult.Resources.xaml b/src/BuildVision.UI/Resources/BuildResult.Resources.xaml new file mode 100644 index 00000000..2062b805 --- /dev/null +++ b/src/BuildVision.UI/Resources/BuildResult.Resources.xaml @@ -0,0 +1,333 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/BuildVision.UI/Resources/BuildState.Resources.Test.xaml b/src/BuildVision.UI/Resources/BuildState.Resources.Test.xaml index 5cc2130a..59c4d01e 100644 --- a/src/BuildVision.UI/Resources/BuildState.Resources.Test.xaml +++ b/src/BuildVision.UI/Resources/BuildState.Resources.Test.xaml @@ -6,7 +6,7 @@ - + @@ -23,7 +23,7 @@ SnapsToDevicePixels="True" ClipToBounds="True" UseLayoutRounding="False" - Template="{StaticResource RebuildSolutionButton}" /> + Template="{StaticResource Failed}" /> @@ -32,7 +32,7 @@ SnapsToDevicePixels="True" ClipToBounds="True" UseLayoutRounding="False" - Template="{StaticResource BuildSolutionButton}" /> + Template="{StaticResource Done}" /> @@ -41,7 +41,7 @@ SnapsToDevicePixels="True" ClipToBounds="True" UseLayoutRounding="False" - Template="{StaticResource CancelBuildSolutionButton}" /> + Template="{StaticResource Cancelled}" /> @@ -50,41 +50,7 @@ SnapsToDevicePixels="True" ClipToBounds="True" UseLayoutRounding="False" - Template="{StaticResource CleanSolutionButton}" /> - - - - - - - - - - - - - - + Template="{StaticResource FailedWithErrors}" /> diff --git a/src/BuildVision.UI/Resources/BuildState.Resources.xaml b/src/BuildVision.UI/Resources/BuildState.Resources.xaml index d68cf636..9f5d0c19 100644 --- a/src/BuildVision.UI/Resources/BuildState.Resources.xaml +++ b/src/BuildVision.UI/Resources/BuildState.Resources.xaml @@ -2,7 +2,7 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:vsfx="clr-namespace:Microsoft.VisualStudio.Shell;assembly=Microsoft.VisualStudio.Shell.14.0"> - + - + - + - + - - @@ -71,20 +69,9 @@ - - - - - - - - - - - - \ No newline at end of file + diff --git a/src/BuildVision.UI/ViewModels/BuildProgressViewModel.cs b/src/BuildVision.UI/ViewModels/BuildProgressViewModel.cs index 6de83487..779e7c47 100644 --- a/src/BuildVision.UI/ViewModels/BuildProgressViewModel.cs +++ b/src/BuildVision.UI/ViewModels/BuildProgressViewModel.cs @@ -10,7 +10,7 @@ using BuildVision.UI.Settings.Models.BuildProgress; namespace BuildVision.UI.ViewModels -{ +{ public class BuildProgressViewModel : BindableBase { private readonly ControlSettings _settings; diff --git a/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs b/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs index cc52cb5c..4ea77a04 100644 --- a/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs +++ b/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs @@ -17,21 +17,23 @@ using BuildVision.UI.Common.Logging; using BuildVision.UI.Helpers; using BuildVision.UI.Models; -using BuildVision.UI.Models.Indicators.Core; using BuildVision.UI.Settings.Models.Columns; using SortDescription = BuildVision.UI.Settings.Models.Sorting.SortDescription; using BuildVision.UI.Settings.Models; using BuildVision.Helpers; using System.ComponentModel.Composition; using System.Text; +using System.Collections.Generic; +using BuildVision.Core; +using BuildVision.Views.Settings; +using BuildVision.Exports.Services; +using BuildVision.Exports.ViewModels; namespace BuildVision.UI.ViewModels { [Export(typeof(IBuildVisionPaneViewModel))] public class BuildVisionPaneViewModel : BindableBase, IBuildVisionPaneViewModel { - private BuildState _buildState; - private IBuildInfo _buildInfo; private ObservableCollection _gridColumnsRef; public bool HideUpToDateTargets @@ -40,42 +42,10 @@ public bool HideUpToDateTargets set => SetProperty(() => ControlSettings.GeneralSettings.HideUpToDateTargets, val => ControlSettings.GeneralSettings.HideUpToDateTargets = val, value); } - public ControlModel Model { get; } - public BuildProgressViewModel BuildProgressViewModel { get; } public ControlSettings ControlSettings { get; } - public ControlTemplate ImageCurrentState - { - get => Model.ImageCurrentState; - set => SetProperty(() => Model.ImageCurrentState, val => Model.ImageCurrentState = val, value); - } - - public ControlTemplate ImageCurrentStateResult - { - get => Model.ImageCurrentStateResult; - set => SetProperty(() => Model.ImageCurrentStateResult, val => Model.ImageCurrentStateResult = val, value); - } - - public string TextCurrentState - { - get => Model.TextCurrentState; - set => SetProperty(() => Model.TextCurrentState, val => Model.TextCurrentState = val, value); - } - - public ProjectItem CurrentProject - { - get => Model.CurrentProject; - set => SetProperty(() => Model.CurrentProject, val => Model.CurrentProject = val, value); - } - - public ObservableCollection ValueIndicators => Model.ValueIndicators; - - public SolutionItem SolutionItem => Model.SolutionItem; - - public ObservableCollection ProjectsList => Model.SolutionItem.Projects; - public string GridGroupPropertyName { get { return ControlSettings.GridSettings.GroupName; } @@ -173,7 +143,7 @@ public ListCollectionView GroupedProjectsList { get { - var groupedList = new ListCollectionView(ProjectsList); + var groupedList = new ListCollectionView(new List()); // todo use projects here ProjectsList); if (!string.IsNullOrWhiteSpace(GridGroupPropertyName)) { @@ -208,16 +178,19 @@ public DataGridHeadersVisibility GridHeadersVisibility } private ProjectItem _selectedProjectItem; + private readonly IBuildService _buildManager; + public ProjectItem SelectedProjectItem { get => _selectedProjectItem; set => SetProperty(ref _selectedProjectItem, value); } - public BuildVisionPaneViewModel(ControlModel model, ControlSettings controlSettings) + [ImportingConstructor] + public BuildVisionPaneViewModel(IBuildService buildManager, VisualStudioSolution solution, IPackageSettingsProvider settingsProvider) { - Model = model; - ControlSettings = controlSettings; + _buildManager = buildManager; + ControlSettings = settingsProvider.Settings; BuildProgressViewModel = new BuildProgressViewModel(ControlSettings); } @@ -226,7 +199,6 @@ public BuildVisionPaneViewModel(ControlModel model, ControlSettings controlSetti /// internal BuildVisionPaneViewModel() { - Model = new ControlModel(); ControlSettings = new ControlSettings(); BuildProgressViewModel = new BuildProgressViewModel(ControlSettings); } @@ -305,22 +277,6 @@ private static ProjectItemColumnSorter GetProjectItemSorter(SortDescription sort return null; } - public void ResetIndicators(ResetIndicatorMode resetMode) - { - foreach (ValueIndicator indicator in ValueIndicators) - indicator.ResetValue(resetMode); - - OnPropertyChanged(nameof(ValueIndicators)); - } - - public void UpdateIndicators(IBuildInfo buildContext) - { - foreach (ValueIndicator indicator in ValueIndicators) - indicator.UpdateValue(buildContext); - - OnPropertyChanged(nameof(ValueIndicators)); - } - public void GenerateColumns() { Debug.Assert(_gridColumnsRef != null); @@ -333,16 +289,17 @@ public void SyncColumnSettings() ColumnsManager.SyncColumnSettings(_gridColumnsRef, ControlSettings.GridSettings); } - public void OnControlSettingsChanged(ControlSettings settings, Func getBuildMessage) + public void OnControlSettingsChanged(ControlSettings settings) { - ControlSettings.InitFrom(settings); + //ControlSettings.InitFrom(settings); GenerateColumns(); - if (_buildState == BuildState.Done) - { - Model.TextCurrentState = getBuildMessage(_buildInfo); - } + // Refresh build message + //if (_buildState == BuildState.Done) + //{ + // Model.TextCurrentState = getBuildMessage(_buildInfo); + //} // Raise all properties have changed. OnPropertyChanged(null); @@ -361,23 +318,18 @@ public void OnBuildProjectDone(BuildedProject buildedProjectInfo) BuildProgressViewModel.OnBuildProjectDone(success); } - public void OnBuildBegin(int projectsCount, IBuildInfo buildContext) + public void OnBuildBegin(int projectsCount) { - _buildState = BuildState.InProgress; - _buildInfo = buildContext; BuildProgressViewModel.OnBuildBegin(projectsCount); } - public void OnBuildDone(IBuildInfo buildInfo) + public void OnBuildDone() { - _buildInfo = buildInfo; - _buildState = BuildState.Done; BuildProgressViewModel.OnBuildDone(); } - public void OnBuildCancelled(IBuildInfo buildInfo) + public void OnBuildCancelled() { - _buildInfo = buildInfo; BuildProgressViewModel.OnBuildCancelled(); } @@ -414,47 +366,38 @@ private void CopyErrorMessageToClipboard(ProjectItem projectItem) public ICommand SelectedProjectOpenContainingFolderAction => new RelayCommand(obj => OpenContainingFolder(), canExecute: obj => (SelectedProjectItem != null && !string.IsNullOrEmpty(SelectedProjectItem.FullName))); - public ICommand SelectedProjectCopyBuildOutputFilesToClipboardAction => new RelayCommand( - obj => ProjectCopyBuildOutputFilesToClipBoard(SelectedProjectItem), - canExecute: obj => (SelectedProjectItem != null && !string.IsNullOrEmpty(SelectedProjectItem.UniqueName) && !ControlSettings.ProjectItemSettings.CopyBuildOutputFileTypesToClipboard.IsEmpty)); + //public ICommand SelectedProjectCopyBuildOutputFilesToClipboardAction => new RelayCommand( + // obj => _buildManager.ProjectCopyBuildOutputFilesToClipBoard(SelectedProjectItem), + // canExecute: obj => (SelectedProjectItem != null && !string.IsNullOrEmpty(SelectedProjectItem.UniqueName) && !ControlSettings.ProjectItemSettings.CopyBuildOutputFileTypesToClipboard.IsEmpty)); - public ICommand SelectedProjectBuildAction => new RelayCommand( - obj => RaiseCommandForSelectedProject(SelectedProjectItem, (int)VSConstants.VSStd97CmdID.BuildCtx), - canExecute: obj => IsProjectItemEnabledForActions()); + //public ICommand SelectedProjectBuildAction => new RelayCommand( + // obj => _buildManager.RaiseCommandForSelectedProject(SelectedProjectItem, (int)VSConstants.VSStd97CmdID.BuildCtx), + // canExecute: obj => IsProjectItemEnabledForActions()); - public ICommand SelectedProjectRebuildAction => new RelayCommand( - obj => RaiseCommandForSelectedProject(SelectedProjectItem, (int)VSConstants.VSStd97CmdID.RebuildCtx), - canExecute: obj => IsProjectItemEnabledForActions()); + //public ICommand SelectedProjectRebuildAction => new RelayCommand( + // obj => _buildManager.RaiseCommandForSelectedProject(SelectedProjectItem, (int)VSConstants.VSStd97CmdID.RebuildCtx), + // canExecute: obj => IsProjectItemEnabledForActions()); - public ICommand SelectedProjectCleanAction => new RelayCommand( - obj => RaiseCommandForSelectedProject(SelectedProjectItem, (int)VSConstants.VSStd97CmdID.CleanCtx), - canExecute: obj => IsProjectItemEnabledForActions()); + //public ICommand SelectedProjectCleanAction => new RelayCommand( + // obj => _buildManager.RaiseCommandForSelectedProject(SelectedProjectItem, (int)VSConstants.VSStd97CmdID.CleanCtx), + // canExecute: obj => IsProjectItemEnabledForActions()); public ICommand SelectedProjectCopyErrorMessagesAction => new RelayCommand(obj => CopyErrorMessageToClipboard(SelectedProjectItem), canExecute: obj => SelectedProjectItem?.ErrorsCount > 0); - public ICommand BuildSolutionAction => new RelayCommand(obj => BuildSolution()); + public ICommand BuildSolutionAction => new RelayCommand(obj => _buildManager.BuildSolution()); - public ICommand RebuildSolutionAction => new RelayCommand(obj => RebuildSolution()); + public ICommand RebuildSolutionAction => new RelayCommand(obj => _buildManager.RebuildSolution()); - public ICommand CleanSolutionAction => new RelayCommand(obj => CleanSolution()); + public ICommand CleanSolutionAction => new RelayCommand(obj => _buildManager.CleanSolution()); - public ICommand CancelBuildSolutionAction => new RelayCommand(obj => CancelBuildSolution()); + public ICommand CancelBuildSolutionAction => new RelayCommand(obj => _buildManager.CancelBuildSolution()); - public ICommand OpenGridColumnsSettingsAction => new RelayCommand(obj => ShowGridColumnsSettingsPage()); + public ICommand OpenGridColumnsSettingsAction => new RelayCommand(obj => _buildManager.ShowGridColumnsSettingsPage()); - public ICommand OpenGeneralSettingsAction => new RelayCommand(obj => ShowGeneralSettingsPage()); + public ICommand OpenGeneralSettingsAction => new RelayCommand(obj => _buildManager.ShowGeneralSettingsPage()); #endregion - - public event Action ShowGridColumnsSettingsPage; - public event Action ShowGeneralSettingsPage; - public event Action BuildSolution; - public event Action CleanSolution; - public event Action RebuildSolution; - public event Action CancelBuildSolution; - public event Action ProjectCopyBuildOutputFilesToClipBoard; - public event Action RaiseCommandForSelectedProject; } } diff --git a/src/BuildVision.UI/ViewModels/SolutionModel.cs b/src/BuildVision.UI/ViewModels/SolutionModel.cs new file mode 100644 index 00000000..ce8ae774 --- /dev/null +++ b/src/BuildVision.UI/ViewModels/SolutionModel.cs @@ -0,0 +1,93 @@ +using BuildVision.Common; + +namespace BuildVision.Core +{ + public class SolutionModel : BindableBase + { + public string State { get; set; } = "StandBy"; + + private int _errorCount = -1; + public int ErrorCount + { + get => _errorCount; + set => SetProperty(ref _errorCount, value); + } + + private int _warningsCount = -1; + public int WarningsCount + { + get => _warningsCount; + set => SetProperty(ref _warningsCount, value); + } + + private int _messagesCount = -1; + public int MessagesCount + { + get => _messagesCount; + set => SetProperty(ref _messagesCount, value); + } + + private int _succeededProjectsCount = -1; + public int SucceededProjectsCount + { + get => _warningsCount; + set => SetProperty(ref _succeededProjectsCount, value); + } + + private int _upToDateProjectsCount = -1; + public int UpToDateProjectsCount + { + get => _warningsCount; + set => SetProperty(ref _upToDateProjectsCount, value); + } + + private int _failedProjectsCount = -1; + public int FailedProjectsCount + { + get => _warningsCount; + set => SetProperty(ref _failedProjectsCount, value); + } + + private int _warnedProjectsCount = -1; + public int WarnedProjectsCount + { + get => _warningsCount; + set => SetProperty(ref _warnedProjectsCount, value); + } + + private string _stateMessage = ""; + public string StateMessage + { + get => _stateMessage; + set => SetProperty(ref _stateMessage, value); + } + + private string _fileName; + public string FileName + { + get => _fileName; + set => SetProperty(ref _fileName, value); + } + + private string _name; + public string Name + { + get => _name; + set => SetProperty(ref _name, value); + } + + private string _fullName; + public string FullName + { + get => _fullName; + set => SetProperty(ref _fullName, value); + } + + private bool _isEmpty = true; + public bool IsEmpty + { + get => _isEmpty; + set => SetProperty(ref _isEmpty, value); + } + } +} diff --git a/src/BuildVision.UI/ViewModels/VisualStudioSolution.cs b/src/BuildVision.UI/ViewModels/VisualStudioSolution.cs new file mode 100644 index 00000000..bab610c8 --- /dev/null +++ b/src/BuildVision.UI/ViewModels/VisualStudioSolution.cs @@ -0,0 +1,101 @@ +using System; +using System.Collections.ObjectModel; +using BuildVision.Common; +using BuildVision.Contracts; +using BuildVision.UI.Contracts; +using BuildVision.UI.Models; + +namespace BuildVision.Core +{ + + public class VisualStudioSolution : BindableBase + { + public BuildState CurrentBuildState { get; set; } + public BuildResultState ResultState => GetBuildState(); + public BuildActions BuildAction { get; set; } + public BuildScopes BuildScope { get; set; } + public DateTime? BuildStartTime { get; set; } + public DateTime? BuildFinishTime { get; set; } + + public ObservableCollection Projects { get; } + + public VisualStudioSolution() + { + Projects = new ObservableCollection(); + } + + public BuildResultState GetBuildState() + { + if (CurrentBuildState == BuildState.InProgress) + { + return BuildResultState.Unknown; + } + else if (CurrentBuildState == BuildState.Done) + { + //TODO Decied what happened + if (BuildAction == BuildActions.BuildActionRebuildAll) + return BuildResultState.RebuildCancelled; + if (BuildAction == BuildActions.BuildActionClean) + return BuildResultState.CleanCancelled; + if (BuildAction == BuildActions.BuildActionBuild) + return BuildResultState.BuildCancelled; + else + return BuildResultState.Unknown; + + if (BuildAction == BuildActions.BuildActionRebuildAll) + return BuildResultState.RebuildFailed; + if (BuildAction == BuildActions.BuildActionClean) + return BuildResultState.CleanFailed; + if (BuildAction == BuildActions.BuildActionBuild) + return BuildResultState.BuildFailed; + else + return BuildResultState.Unknown; + + if (BuildAction == BuildActions.BuildActionRebuildAll) + return BuildResultState.RebuildSucceeded; + if (BuildAction == BuildActions.BuildActionClean) + return BuildResultState.CleanSucceeded; + if (BuildAction == BuildActions.BuildActionBuild) + return BuildResultState.BuildSucceeded; + else + return BuildResultState.Unknown; + + if (BuildAction == BuildActions.BuildActionRebuildAll) + return BuildResultState.RebuildSucceededWithErrors; + if (BuildAction == BuildActions.BuildActionClean) + return BuildResultState.CleanSucceededWithErrors; + if (BuildAction == BuildActions.BuildActionBuild) + return BuildResultState.BuildSucceededWithErrors; + else + return BuildResultState.Unknown; + } + else + { + return BuildResultState.Unknown; + } + } + } + + + /* + * General + * - BuildState / ResultState + * - StateMessage + * - ErrorsCount + * - WarningsCount + * - InformationCount + * - SucceededProjects + * - UpToDateProjects + * - WarningProjects + * - FailedProjects + * + * Projects + * + * Actions + * - Build Solution + * - Rebuild Solution + * - Clean Solution + * - Cancel + * * + * */ +} diff --git a/src/BuildVision/BuildVision.csproj b/src/BuildVision/BuildVision.csproj index 16ea8712..bc863a08 100644 --- a/src/BuildVision/BuildVision.csproj +++ b/src/BuildVision/BuildVision.csproj @@ -91,8 +91,8 @@ + - @@ -100,18 +100,21 @@ + + + + + - - Component @@ -121,7 +124,6 @@ Component - Component @@ -137,7 +139,6 @@ - @@ -208,6 +209,10 @@ {13d64a57-5db3-4cc7-ac2b-9034e767d754} BuildVision.Contracts + + {F16E6593-DDF9-4E9E-A2F8-56A3C43A643E} + BuildVision.Exports + {84e8ba65-9a4b-4c50-a115-6ef3208e4058} BuildVision.UI diff --git a/src/BuildVision/Core/BuildVisionPackage.cs b/src/BuildVision/Core/BuildVisionPackage.cs index 405015af..5882d334 100644 --- a/src/BuildVision/Core/BuildVisionPackage.cs +++ b/src/BuildVision/Core/BuildVisionPackage.cs @@ -6,6 +6,7 @@ using System.Windows; using BuildVision.Common; using BuildVision.Contracts; +using BuildVision.Helpers; using BuildVision.Tool; using BuildVision.Tool.Building; using BuildVision.Tool.Models; @@ -13,11 +14,11 @@ using BuildVision.UI.Common.Logging; using BuildVision.UI.Extensions; using BuildVision.UI.Helpers; -using BuildVision.UI.Models.Indicators.Core; using BuildVision.UI.Settings.Models; using BuildVision.UI.ViewModels; using BuildVision.Views.Settings; using EnvDTE; +using EnvDTE80; using Microsoft.VisualStudio; using Microsoft.VisualStudio.Settings; using Microsoft.VisualStudio.Shell; @@ -54,13 +55,17 @@ namespace BuildVision.Core public sealed partial class BuildVisionPackage : AsyncPackage, IPackageContext { private DTE _dte; + private DTE2 _dte2; private SolutionEvents _solutionEvents; private BuildVisionPaneViewModel _viewModel; private IVsSolutionBuildManager2 _solutionBuildManager; - private uint _updateSolutionEventsCookie; + private uint _updateSolutionEvents4Cookie; private readonly Guid _parsingErrorsLoggerId = new Guid("{64822131-DC4D-4087-B292-61F7E06A7B39}"); private BuildOutputLogger _buildLogger; - private IVsSolution2 _vsSolution; + private Solution _vsSolution; + private IVsSolutionBuildManager5 _solutionBuildManager4; + private SolutionModel _solutionState; + private SolutionBuildEvents _solutionBuildEvents; public ControlSettings ControlSettings { get; set; } @@ -76,69 +81,57 @@ protected override async Task InitializeAsync(CancellationToken cancellationToke { await JoinableTaskFactory.SwitchToMainThreadAsync(DisposalToken); _dte = await GetServiceAsync(typeof(DTE)) as DTE; + _dte2 = await GetServiceAsync(typeof(DTE)) as DTE2; if (await GetServiceAsync(typeof(IMenuCommandService)) is OleMenuCommandService mcs) { var toolwndCommandId = new CommandID(PackageGuids.GuidBuildVisionCmdSet, (int) PackageIds.CmdIdBuildVisionToolWindow); var menuToolWin = new OleMenuCommand(ShowToolWindowAsync, toolwndCommandId); mcs.AddCommand(menuToolWin); } - _solutionBuildManager = ServiceProvider.GlobalProvider.GetService(typeof(SVsSolutionBuildManager)) as IVsSolutionBuildManager2; - if (_solutionBuildManager != null) - { - _solutionBuildManager.AdviseUpdateSolutionEvents(new SolutionBuildEvents(), out _updateSolutionEventsCookie); - } + _solutionBuildManager4 = ServiceProvider.GlobalProvider.GetService(typeof(SVsSolutionBuildManager)) as IVsSolutionBuildManager5; + + IPackageContext packageContext = this; _solutionEvents = _dte.Events.SolutionEvents; + _solutionEvents.BeforeClosing += SolutionEvents_BeforeClosing; _solutionEvents.AfterClosing += SolutionEvents_AfterClosing; _solutionEvents.Opened += SolutionEvents_Opened; - //var toolWindow = GetWindowPane(typeof(BuildVisionPane)); - IPackageContext packageContext = this; - //_viewModel = BuildVisionPane.GetViewModel(toolWindow); - //ViewModelHelper.UpdateSolution(_dte.Solution, _viewModel.SolutionItem); - //var buildContext = new BuildContext(packageContext, _dte, _dte.Events.BuildEvents, _dte.Events.WindowEvents, _dte.Events.CommandEvents, viewModel); - - _dte.Events.BuildEvents.OnBuildBegin += (scope, args) => { RegisterLogger(); }; - } - - private void RegisterLogger() - { - var result = BuildOutputLogger.Register(_parsingErrorsLoggerId, Microsoft.Build.Framework.LoggerVerbosity.Quiet, out _buildLogger); - if (result == RegisterLoggerResult.AlreadyExists) + if (_dte2.Solution?.IsOpen == true) { - _buildLogger.Projects?.Clear(); + SolutionEvents_Opened(); } + + var toolWindow = GetWindowPane(typeof(BuildVisionPane)); + _viewModel = BuildVisionPane.GetViewModel(toolWindow); } - private void SolutionEvents_Opened() + private void SolutionEvents_BeforeClosing() { ThreadHelper.ThrowIfNotOnUIThread(); - SetVsSolution(); - - ViewModelHelper.UpdateSolution(_dte.Solution, _viewModel.SolutionItem); - _viewModel.ResetIndicators(ResetIndicatorMode.ResetValue); + _solutionBuildManager.UnadviseUpdateSolutionEvents(_updateSolutionEvents4Cookie); + _solutionBuildManager4.UnadviseUpdateSolutionEvents4(_updateSolutionEvents4Cookie); } - private void SetVsSolution() + private void SolutionEvents_Opened() { ThreadHelper.ThrowIfNotOnUIThread(); - if (_vsSolution == null) - _vsSolution = ServiceProvider.GlobalProvider.GetService(typeof(SVsSolution)) as IVsSolution2; + _vsSolution = Services.Dte2.Solution; + _solutionState = _vsSolution.ToSolutionBuildState(); + //_solutionBuildEvents = new SolutionBuildEvents(_solutionState); + _solutionBuildManager.AdviseUpdateSolutionEvents(_solutionBuildEvents, out _updateSolutionEvents4Cookie); + _solutionBuildManager4.AdviseUpdateSolutionEvents4(_solutionBuildEvents, out _updateSolutionEvents4Cookie); + //_viewModel.ResetIndicators(ResetIndicatorMode.ResetValue); } private void SolutionEvents_AfterClosing() { ThreadHelper.ThrowIfNotOnUIThread(); - SetVsSolution(); - - _viewModel.TextCurrentState = Resources.BuildDoneText_BuildNotStarted; - _viewModel.ImageCurrentState = VectorResources.TryGet(BuildImages.BuildActionResourcesUri, "StandBy"); - _viewModel.ImageCurrentStateResult = null; - - ViewModelHelper.UpdateSolution(_dte.Solution, _viewModel.SolutionItem); - _viewModel.ProjectsList.Clear(); - _viewModel.ResetIndicators(ResetIndicatorMode.Disable); + //_viewModel.TextCurrentState = Resources.BuildDoneText_BuildNotStarted; + ////_viewModel.ImageCurrentState = "TODO SET IMAGE"//VectorResources.TryGet(BuildImages.BuildActionResourcesUri, "StandBy"); + //_viewModel.ProjectsList.Clear(); + //_viewModel.ResetIndicators(ResetIndicatorMode.Disable); _viewModel.BuildProgressViewModel.ResetTaskBarInfo(); } diff --git a/src/BuildVision/Core/SolutionBuildEvents.cs b/src/BuildVision/Core/SolutionBuildEvents.cs index 5979ee6a..07fc7d4b 100644 --- a/src/BuildVision/Core/SolutionBuildEvents.cs +++ b/src/BuildVision/Core/SolutionBuildEvents.cs @@ -1,85 +1,374 @@ using System; using System.Diagnostics; +using System.Linq; using System.Threading; +using BuildVision.Common; using BuildVision.Contracts; +using BuildVision.Helpers; using BuildVision.Tool.Building; +using BuildVision.Tool.Models; using BuildVision.UI.Common.Logging; using BuildVision.UI.Contracts; +using BuildVision.UI.Helpers; using BuildVision.UI.ViewModels; using EnvDTE; using Microsoft.VisualStudio; -using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; namespace BuildVision.Core { - public class SolutionBuildEvents : IVsUpdateSolutionEvents2 + + public class SolutionBuildEvents : IVsUpdateSolutionEvents2, IVsUpdateSolutionEvents4 { + private readonly Guid _parsingErrorsLoggerId = new Guid("{64822131-DC4D-4087-B292-61F7E06A7B39}"); + public BuildOutputLogger _buildLogger; // This needs to be static because it is shared accross multiple instances + + public VisualStudioSolution VisualStudioSolution { get; } + + private BuildEvents _buildEvents; private bool _buildCancelled; private bool _buildCancelledInternally; - private CancellationTokenSource _buildProcessCancellationToken; - private BuildOutputLogger _buildLogger; - private readonly Guid _parsingErrorsLoggerId = new Guid("{64822131-DC4D-4087-B292-61F7E06A7B39}"); + private bool _buildErrorIsNavigated; + private string _origTextCurrentState; - public BuildState CurrentBuildState { get; private set; } - public DateTime BuildStartTime { get; private set; } - public DateTime BuildFinishTime { get; private set; } - public BuildActions BuildAction { get; private set; } - public BuildScopes BuildScope { get; private set; } + public SolutionBuildEvents(VisualStudioSolution solutionBuildState) + { + VisualStudioSolution = solutionBuildState; + } - private Project GetProject(IVsHierarchy pHierProj) + public void UpdateSolution_BeginUpdateAction(uint dwAction) { - ThreadHelper.ThrowIfNotOnUIThread(); - pHierProj.GetProperty(VSConstants.VSITEMID_ROOT, (int) __VSHPROPID.VSHPROPID_ExtObject, out var objProj); - return objProj as Project; + _buildCancelled = false; + _buildCancelledInternally = false; + _buildErrorIsNavigated = false; + + RegisterLogger(); + + VisualStudioSolution.Projects.Clear(); + VisualStudioSolution.Projects.AddRange(Services.Dte2.Solution.GetProjectItems()); + VisualStudioSolution.BuildStartTime = DateTime.Now; + VisualStudioSolution.BuildFinishTime = null; + VisualStudioSolution.CurrentBuildState = BuildState.InProgress; + VisualStudioSolution.BuildAction = StateConverterHelper.ConvertSolutionBuildFlagsToBuildAction(dwAction, (VSSOLNBUILDUPDATEFLAGS) dwAction); + + //TODO use settings + string message = new BuildMessagesFactory(new UI.Settings.Models.BuildMessagesSettings()).GetBuildBeginMajorMessage(VisualStudioSolution); + //_statusBarNotificationService.ShowTextWithFreeze(message); + _origTextCurrentState = message; + //VisualStudioSolution.StateMessage = _origTextCurrentState; // Set message + try + { + //ApplyToolWindowStateAction(_viewModel.ControlSettings.WindowSettings.WindowActionOnBuildBegin); + //if (_viewModel.ControlSettings.GeneralSettings.FillProjectListOnBuildBegin) + // _viewModel.ProjectsList.AddRange(_viewModel.SolutionItem.AllProjects); + + // Reset HeaderViewModel + //_viewModel.ResetIndicators(ResetIndicatorMode.ResetValue); + //int projectsCount = -1; + //projectsCount = GetProjectsCount(projectsCount); + //_viewModel.OnBuildBegin(projectsCount, this); + } + catch (Exception ex) + { + ex.TraceUnknownException(); + } + + //_buildProcessCancellationToken = new CancellationTokenSource(); + //// Startbackground process + ////Task.Factory.StartNew(BuildEvents_BuildInProcess, _buildProcessCancellationToken.Token, _buildProcessCancellationToken.Token); } - public int UpdateSolution_Begin(ref int pfCancelUpdate) + public int UpdateProjectCfg_Begin(IVsHierarchy pHierProj, IVsCfg pCfgProj, IVsCfg pCfgSln, uint dwAction, ref int pfCancel) { - Debug.WriteLine($"UpdateSolution_Begin"); - return 0; + try + { + var projectItem = VisualStudioSolution.Projects.FirstOrDefault(item => ProjectIdentifierGenerator.GetIdentifierForProjectItem(item) == ProjectIdentifierGenerator.GetIdentifierForInteropTypes(pHierProj, pCfgProj)); + if (projectItem == null) + { + // In this case we are executing a batch build so we need to add the projectitem manually + projectItem = new UI.Models.ProjectItem(); + var configPair = pCfgProj.ToConfigurationTuple(); + SolutionProjectsExtensions.UpdateProperties(pHierProj.ToProject(), projectItem, configPair.Item1, configPair.Item2); + VisualStudioSolution.Projects.Add(projectItem); + } + + projectItem.State = GetProjectState(VisualStudioSolution.BuildAction); + projectItem.BuildFinishTime = null; + projectItem.BuildStartTime = DateTime.Now; + + // _viewModel.OnBuildProjectBegin(); + //if (BuildScope == BuildScopes.BuildScopeSolution && + // (BuildAction == BuildActions.BuildActionBuild || + // BuildAction == BuildActions.BuildActionRebuildAll)) + //{ + // currentProject.BuildOrder = _viewModel.BuildProgressViewModel.CurrentQueuePosOfBuildingProject; + //} + //if (!_viewModel.ProjectsList.Contains(currentProject)) + // _viewModel.ProjectsList.Add(currentProject); + //else if (_viewModel.ControlSettings.GeneralSettings.FillProjectListOnBuildBegin) + // _viewModel.OnPropertyChanged(nameof(BuildVisionPaneViewModel.GroupedProjectsList)); + //_viewModel.CurrentProject = currentProject; + } + catch (Exception ex) + { + ex.TraceUnknownException(); + } + return VSConstants.S_OK; + } + + public int UpdateProjectCfg_Done(IVsHierarchy pHierProj, IVsCfg pCfgProj, IVsCfg pCfgSln, uint dwAction, int fSuccess, int fCancel) + { + var currentProject = VisualStudioSolution.Projects.First(item => ProjectIdentifierGenerator.GetIdentifierForProjectItem(item) == ProjectIdentifierGenerator.GetIdentifierForInteropTypes(pHierProj, pCfgProj)); + Debug.WriteLine($"UpdateProjectCfg_Done {currentProject.UniqueName} ({currentProject.Configuration}|{currentProject.Platform})"); + //currentProject.Success = fSuccess == 1; + //ProjectState projectState; + //switch (SolutionBuildState.BuildAction) + //{ + // case BuildActions.BuildActionBuild: + // case BuildActions.BuildActionRebuildAll: + // if (currentProject.Success) + // { + // if (_viewModel.ControlSettings.GeneralSettings.ShowWarningSignForBuilds && buildedProject.ErrorsBox.WarningsCount > 0) + // projectState = ProjectState.BuildWarning; + // else + // { + // bool upToDate = (_buildLogger != null && _buildLogger.Projects != null + // && !_buildLogger.Projects.Exists(t => t.FileName == buildedProject.FileName)); + // if (upToDate) + // { + // // Because ErrorBox will be empty if project is UpToDate. + // buildedProject.ErrorsBox = currentProject.ErrorsBox; + // } + // projectState = upToDate ? ProjectState.UpToDate : ProjectState.BuildDone; + // } + // } + // else + // { + // bool canceled = (_buildCancelled && buildedProject.ErrorsBox.ErrorsCount == 0); + // projectState = canceled ? ProjectState.BuildCancelled : ProjectState.BuildError; + // } + // break; + + // case BuildActions.BuildActionClean: + // projectState = fSuccess == 1 ? ProjectState.CleanDone : ProjectState.CleanError; + // break; + + // case BuildActions.BuildActionDeploy: + // throw new InvalidOperationException("vsBuildActionDeploy not supported"); + + // default: + // throw new ArgumentOutOfRangeException(nameof(SolutionBuildState.BuildAction)); + //} + + //buildedProject.ProjectState = projectState; + //OnBuildProjectDone(new BuildProjectEventArgs(currentProject, projectState, eventTime, buildedProject)); + + //Debug.WriteLine($"UpdateProjectCfg_Done {proj.UniqueName} ({projConfiguration}) ({slnConfiguration}"); + + //if (e.ProjectState == ProjectState.BuildError && _viewModel.ControlSettings.GeneralSettings.StopBuildAfterFirstError) + // CancelBuildAsync(); + + //try + //{ + // ProjectItem currentProject = e.ProjectItem; + // currentProject.State = e.ProjectState; + // currentProject.BuildFinishTime = DateTime.Now; + // currentProject.UpdatePostBuildProperties(e.BuildedProjectInfo); + + // if (!_viewModel.ProjectsList.Contains(currentProject)) + // _viewModel.ProjectsList.Add(currentProject); + + // if (ReferenceEquals(_viewModel.CurrentProject, e.ProjectItem) && BuildingProjects.Any()) + // _viewModel.CurrentProject = BuildingProjects.Last(); + //} + //catch (Exception ex) + //{ + // ex.TraceUnknownException(); + //} + + //_viewModel.UpdateIndicators(this); + + //try + //{ + // _viewModel.OnBuildProjectDone(e.BuildedProjectInfo); + //} + //catch (Exception ex) + //{ + // ex.TraceUnknownException(); + //} + return VSConstants.S_OK; } public int UpdateSolution_Done(int fSucceeded, int fModified, int fCancelCommand) { - Console.WriteLine($"UpdateSolution_Done: fSucceeded {fSucceeded}, fModified {fModified}, fCancelCommand {fCancelCommand}"); - return 0; + if (VisualStudioSolution.CurrentBuildState == BuildState.InProgress) + { + // Start command (F5), when Build is not required. + return VSConstants.S_OK; + } + + //try + //{ + // var settings = _viewModel.ControlSettings; + + // SetFinalStateForUnfinishedProjects(); + + // // Update header? This might be happening impliclty when updating solution + // //_viewModel.UpdateIndicators(this); + + // var message = BuildMessages.GetBuildDoneMessage(_viewModel.SolutionItem, this, settings.BuildMessagesSettings); + // var buildDoneImage = BuildImages.GetBuildDoneImage(this, _viewModel.ProjectsList, out ControlTemplate stateImage); + + // _statusBarNotificationService.ShowText(message); + // _viewModel.TextCurrentState = message; + // _viewModel.ImageCurrentState = buildDoneImage; + // _viewModel.ImageCurrentStateResult = stateImage; + // _viewModel.CurrentProject = null; + // _viewModel.OnBuildDone(this); + + // ApplyWindowState(settings); + // NavigateToBuildErrorIfNeeded(settings); + //} + //catch (Exception ex) + //{ + // ex.TraceUnknownException(); + //} + + VisualStudioSolution.BuildFinishTime = DateTime.Now; + VisualStudioSolution.CurrentBuildState = BuildState.Done; + return VSConstants.S_OK; } - public int UpdateSolution_StartUpdate(ref int pfCancelUpdate) + private ProjectState GetProjectState(BuildActions buildAction) { + switch (buildAction) + { + case BuildActions.BuildActionBuild: + case BuildActions.BuildActionRebuildAll: + return ProjectState.Building; - Debug.WriteLine($"UpdateSolution_StartUpdate"); - return 0; + case BuildActions.BuildActionClean: + return ProjectState.Cleaning; + + case BuildActions.BuildActionDeploy: + throw new InvalidOperationException("vsBuildActionDeploy not supported"); + + default: + throw new ArgumentOutOfRangeException(nameof(buildAction)); + } + } + + private bool PlatformsIsEquals(string platformName1, string platformName2) + { + if (string.Compare(platformName1, platformName2, StringComparison.InvariantCultureIgnoreCase) == 0) + return true; + + // The ambiguity between Project.ActiveConfiguration.PlatformName and + // ProjectStartedEventArgs.ProjectPlatform in Microsoft.Build.Utilities.Logger + // (see BuildOutputLogger). + bool isAnyCpu1 = (platformName1 == "Any CPU" || platformName1 == "AnyCPU"); + bool isAnyCpu2 = (platformName2 == "Any CPU" || platformName2 == "AnyCPU"); + if (isAnyCpu1 && isAnyCpu2) + return true; + + return false; + } + + private void RegisterLogger() + { + _buildLogger = null; + RegisterLoggerResult result = BuildOutputLogger.Register(_parsingErrorsLoggerId, Microsoft.Build.Framework.LoggerVerbosity.Quiet, out _buildLogger); + if (result == RegisterLoggerResult.AlreadyExists) + { + _buildLogger.Projects?.Clear(); + } + } + + //public bool GetProjectItem(IBuildVisionPaneViewModel viewModel, BuildProjectContextEntry projectEntry, out ProjectItem projectItem) + //{ + // projectItem = projectEntry.ProjectItem; + // if (projectItem != null) + // return true; + + // string projectFile = projectEntry.FileName; + // if (ProjectExtensions.IsProjectHidden(projectFile)) + // return false; + + // var projectProperties = projectEntry.Properties; + // var project = viewModel.ProjectsList.FirstOrDefault(x => x.FullName == projectFile); + + + // if (projectProperties.ContainsKey("Configuration") && projectProperties.ContainsKey("Platform")) + // { + // string projectConfiguration = projectProperties["Configuration"]; + // string projectPlatform = projectProperties["Platform"]; + // projectItem = FindProjectItemInProjectsByUniqueName(viewModel, project.UniqueName, projectConfiguration, projectPlatform); + // if (projectItem == null) + // { + // TraceManager.Trace( + // string.Format("Project Item not found by: UniqueName='{0}', Configuration='{1}, Platform='{2}'.", + // project.UniqueName, + // projectConfiguration, + // projectPlatform), + // EventLogEntryType.Warning); + // return false; + // } + // } + // else + // { + // return false; + // } + + // projectEntry.ProjectItem = projectItem; + // return true; + //} + + #region Interface Implementation + + public int UpdateSolution_Begin(ref int pfCancelUpdate) + { + return VSConstants.S_OK; + } + + public int UpdateSolution_StartUpdate(ref int pfCancelUpdate) + { + return VSConstants.S_OK; } public int UpdateSolution_Cancel() { - Debug.WriteLine($"UpdateSolution_Cancel"); - return 0; + return VSConstants.S_OK; } public int OnActiveProjectCfgChange(IVsHierarchy pIVsHierarchy) { - var proj = GetProject(pIVsHierarchy); - Debug.WriteLine($"OnActiveProjectCfgChange {proj.UniqueName}"); + return VSConstants.S_OK; + } - return 0; + public void UpdateSolution_EndUpdateAction(uint dwAction) + { } - public int UpdateProjectCfg_Begin(IVsHierarchy pHierProj, IVsCfg pCfgProj, IVsCfg pCfgSln, uint dwAction, ref int pfCancel) + public void OnActiveProjectCfgChangeBatchBegin() { - var proj = GetProject(pHierProj); - Debug.WriteLine($"UpdateProjectCfg_Begin {proj.UniqueName} (IsDirty: {proj.IsDirty}): dwAction {(VSSOLNBUILDUPDATEFLAGS) dwAction} ({dwAction})"); - return 0; } - public int UpdateProjectCfg_Done(IVsHierarchy pHierProj, IVsCfg pCfgProj, IVsCfg pCfgSln, uint dwAction, int fSuccess, int fCancel) + public void OnActiveProjectCfgChangeBatchEnd() + { + } + + public void UpdateSolution_QueryDelayFirstUpdateAction(out int pfDelay) + { + pfDelay = 0; + } + + public void UpdateSolution_BeginFirstUpdateAction() + { + } + + public void UpdateSolution_EndLastUpdateAction() { - var projects = _buildLogger.Projects; - var proj = GetProject(pHierProj); - Debug.WriteLine($"UpdateProjectCfg_Done {proj.UniqueName} (IsDirty: {proj.IsDirty}): dwAction {(VSSOLNBUILDUPDATEFLAGS)dwAction} ({dwAction}), fSuccess {fSuccess}, fCancel {fCancel}"); - return 0; } + #endregion } } diff --git a/src/BuildVision/Core/StatusBarNotificationService.cs b/src/BuildVision/Core/StatusBarNotificationService.cs index 24967361..d1b2167a 100644 --- a/src/BuildVision/Core/StatusBarNotificationService.cs +++ b/src/BuildVision/Core/StatusBarNotificationService.cs @@ -1,5 +1,6 @@ using System; using System.ComponentModel.Composition; +using BuildVision.Exports.Services; using BuildVision.Views.Settings; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; diff --git a/src/BuildVision/Helpers/EnvDTEProjectKinds.cs b/src/BuildVision/Helpers/EnvDTEProjectKinds.cs new file mode 100644 index 00000000..9dbf1357 --- /dev/null +++ b/src/BuildVision/Helpers/EnvDTEProjectKinds.cs @@ -0,0 +1,7 @@ +namespace BuildVision.Helpers +{ + public class EnvDTEProjectKinds + { + public const string ProjectKindSolutionFolder = "{66A26720-8FB5-11D2-AA7E-00C04F688DDE}"; + } +} diff --git a/src/BuildVision/Helpers/ProjectIdentifierGenerator.cs b/src/BuildVision/Helpers/ProjectIdentifierGenerator.cs new file mode 100644 index 00000000..a788da5a --- /dev/null +++ b/src/BuildVision/Helpers/ProjectIdentifierGenerator.cs @@ -0,0 +1,22 @@ +using EnvDTE; +using Microsoft.VisualStudio; +using Microsoft.VisualStudio.Shell; +using Microsoft.VisualStudio.Shell.Interop; + +namespace BuildVision.Helpers +{ + public static class ProjectIdentifierGenerator + { + public static string GetIdentifierForInteropTypes(IVsHierarchy pHierProj, IVsCfg pCfgProj) + { + var project = pHierProj.ToProject(); + pCfgProj.get_DisplayName(out var projConfiguration); + return $"{project.UniqueName}-{projConfiguration}"; + } + + public static string GetIdentifierForProjectItem(BuildVision.UI.Models.ProjectItem projectItem) + { + return $"{projectItem.UniqueName}-{projectItem.Configuration}|{projectItem.Platform}"; + } + } +} diff --git a/src/BuildVision/Helpers/SolutionProjectsExtensions.cs b/src/BuildVision/Helpers/SolutionProjectsExtensions.cs index 4c199fcf..0f6389bb 100644 --- a/src/BuildVision/Helpers/SolutionProjectsExtensions.cs +++ b/src/BuildVision/Helpers/SolutionProjectsExtensions.cs @@ -3,18 +3,63 @@ using EnvDTE; using IServiceProvider = Microsoft.VisualStudio.OLE.Interop.IServiceProvider; using System.Runtime.InteropServices; -using EnvDTE80; -using BuildVision.UI.Helpers; +using BuildVision.UI; +using System.IO; +using BuildVision.UI.Common.Logging; +using BuildVision.Core; +using ProjectItem = BuildVision.UI.Models.ProjectItem; +using System.Linq; +using BuildVision.Common; namespace BuildVision.Helpers { - public class EnvDTEProjectKinds - { - public const string ProjectKindSolutionFolder = "{66A26720-8FB5-11D2-AA7E-00C04F688DDE}"; - } - public static class SolutionProjectsExtensions { + public static SolutionModel ToSolutionBuildState(this Solution solution) + { + var solutionItem = new SolutionModel(); + try + { + if (solution == null) + { + solutionItem.Name = Resources.GridCellNATextInBrackets; + solutionItem.FullName = Resources.GridCellNATextInBrackets; + solutionItem.IsEmpty = true; + } + else if (string.IsNullOrEmpty(solution.FileName)) + { + if (solution.Count != 0 /* projects count */) + { + var project = solution.Item(1); + solutionItem.Name = Path.GetFileNameWithoutExtension(project.FileName); + solutionItem.FullName = project.FullName; + solutionItem.IsEmpty = false; + } + else + { + solutionItem.Name = Resources.GridCellNATextInBrackets; + solutionItem.FullName = Resources.GridCellNATextInBrackets; + solutionItem.IsEmpty = true; + } + } + else + { + solutionItem.Name = Path.GetFileNameWithoutExtension(solution.FileName); + solutionItem.FullName = solution.FullName; + solutionItem.IsEmpty = false; + } + } + catch (Exception ex) + { + ex.TraceUnknownException(); + + solutionItem.Name = Resources.GridCellNATextInBrackets; + solutionItem.FullName = Resources.GridCellNATextInBrackets; + solutionItem.IsEmpty = true; + } + return solutionItem; + } + public static IList GetProjects(this Solution solution) { var list = new List(); @@ -58,6 +103,174 @@ public static Project GetProject(this Solution solution, Func con return null; } + public static IList GetProjectItems(this Solution solution) + { + IList dteProjects = new List(); + try + { + dteProjects = solution.GetProjects(); + } + catch (Exception ex) + { + ex.TraceUnknownException(); + } + + + var projectItems = new List(dteProjects.Count); + foreach (Project project in dteProjects) + { + try + { + //var msBuildProject = project.GetMsBuildProject(); + var projectItem = new ProjectItem(); + UpdateProperties(project, projectItem); + projectItems.Add(projectItem); + } + catch (Exception ex) + { + ex.TraceUnknownException(); + } + } + + return projectItems; + } + + public static void UpdateProperties(Project project, ProjectItem projectItem, string configuration = null, string platform = null) + { + if (project != null) + { + object projObject; + try + { + projObject = project.Object; + } + catch (Exception ex) + { + ex.TraceUnknownException(); + projObject = null; + } + + try + { + if (projObject == null) + { + projectItem.UniqueName = project.UniqueName; + projectItem.Name = project.Name; + return; + } + + UpdateNameProperties(project, projectItem); + projectItem.Language = project.GetLanguageName(); + projectItem.CommonType = ProjectExtensions.GetProjectType(project.Kind, project.DTE.Version /* "12.0" */); + } + catch (Exception ex) + { + ex.TraceUnknownException(); + } + + #region Set ActiveConfiguration (Configuration and Platform) + + if (configuration != null && platform != null) + { + projectItem.Configuration = configuration; + projectItem.Platform = platform; + } + else + { + Configuration config; + try + { + config = project.ConfigurationManager.ActiveConfiguration; + } + catch (Exception ex) + { + ex.TraceUnknownException(); + config = null; + } + + if (config != null) + { + projectItem.Configuration = config.ConfigurationName; + projectItem.Platform = config.PlatformName; + } + else + { + projectItem.Configuration = @"N\A"; + projectItem.Platform = @"N\A"; + } + } + + #endregion + + try + { + projectItem.Framework = project.GetFrameworkString(); + + var flavourTypes = project.GetFlavourTypes().ToList(); + projectItem.FlavourType = string.Join("; ", flavourTypes); + projectItem.MainFlavourType = flavourTypes.FirstOrDefault(); + + projectItem.OutputType = project.GetOutputType(); + projectItem.ExtenderNames = project.GetExtenderNames(); + + projectItem.RootNamespace = project.GetRootNamespace(); + } + catch (Exception ex) + { + ex.TraceUnknownException(); + } + } + } + + private static void UpdateNameProperties(Project project, ProjectItem projectItem) + { + try + { + projectItem.UniqueName = project.UniqueName; + projectItem.Name = project.Name; + projectItem.FullName = project.FullName; + + if (IsIntegrationServicesProject(project, projectItem)) + AdjustUniqueNameForExtensionProjects(project, projectItem); + + try + { + projectItem.FullPath = string.IsNullOrWhiteSpace(projectItem.FullName) ? null : Path.GetDirectoryName(projectItem.FullName); + } + catch (SystemException ex) + { + // PathTooLongException, ArgumentException (invalid characters). + ex.TraceUnknownException(); + projectItem.FullPath = null; + } + + projectItem.SolutionFolder = project.GetTreePath(false) ?? @"\"; + // TODO: SolutionPath = project.GetTreePath(true); + } + catch (Exception ex) + { + ex.TraceUnknownException(); + } + } + + private const string _GUID_SQL_INTEGRATIONG_SERVICES_PROJECT_KIND = "{159641d6-6404-4a2a-ae62-294de0fe8301}"; + + private static bool IsIntegrationServicesProject(Project project, ProjectItem projectItem) + { + if (project.Kind == _GUID_SQL_INTEGRATIONG_SERVICES_PROJECT_KIND) + return projectItem.UniqueName == projectItem.FullName; + else + return false; + } + + private static void AdjustUniqueNameForExtensionProjects(Project project, ProjectItem projectItem) + { + var directory = Path.GetDirectoryName(project.UniqueName); + var directoryName = Path.GetFileName(directory); + var csprojName = Path.GetFileName(project.UniqueName); + projectItem.UniqueName = Path.Combine(directoryName, csprojName); + } + public static object GetService(object serviceProviderObject, Type type) { object service = null; diff --git a/src/BuildVision/Helpers/StateConverterHelper.cs b/src/BuildVision/Helpers/StateConverterHelper.cs new file mode 100644 index 00000000..bcded05f --- /dev/null +++ b/src/BuildVision/Helpers/StateConverterHelper.cs @@ -0,0 +1,30 @@ +using System; +using Microsoft.VisualStudio.Shell.Interop; +using BuildVision.Contracts; + +namespace BuildVision.Tool.Models +{ + public class StateConverterHelper + { + public static BuildActions ConvertSolutionBuildFlagsToBuildAction(uint dwAction, VSSOLNBUILDUPDATEFLAGS solutionFlags) + { + if (solutionFlags == (VSSOLNBUILDUPDATEFLAGS.SBF_OPERATION_NONE | VSSOLNBUILDUPDATEFLAGS.SBF_OPERATION_BUILD | VSSOLNBUILDUPDATEFLAGS.SBF_OPERATION_FORCE_UPDATE)) + { + return BuildActions.BuildActionRebuildAll; + } + else if (solutionFlags == (VSSOLNBUILDUPDATEFLAGS.SBF_OPERATION_NONE | VSSOLNBUILDUPDATEFLAGS.SBF_OPERATION_CLEAN)) + { + return BuildActions.BuildActionClean; + } + else if (solutionFlags == (VSSOLNBUILDUPDATEFLAGS.SBF_OPERATION_NONE | VSSOLNBUILDUPDATEFLAGS.SBF_OPERATION_BUILD)) + { + return BuildActions.BuildActionBuild; + } + else + { + throw new Exception($"Unkonw buildaction {(VSSOLNBUILDUPDATEFLAGS) dwAction} ({dwAction})"); + } + } + + } +} diff --git a/src/BuildVision/Helpers/ViewModelHelper.cs b/src/BuildVision/Helpers/ViewModelHelper.cs deleted file mode 100644 index 102843c7..00000000 --- a/src/BuildVision/Helpers/ViewModelHelper.cs +++ /dev/null @@ -1,234 +0,0 @@ -using System; -using System.IO; -using System.Linq; - -using EnvDTE; -using System.Collections.Generic; -using BuildVision.UI; -using BuildVision.Helpers; -using BuildVision.UI.Common.Logging; - -using ProjectItem = BuildVision.UI.Models.ProjectItem; -using BuildVision.UI.Models; -using Microsoft.VisualStudio.Shell.Interop; - -namespace BuildVision.Tool.Models -{ - public static class ViewModelHelper - { - public static void UpdateProperties(Project project, ProjectItem projectItem) - { - if (project != null) - { - object projObject; - try - { - projObject = project.Object; - } - catch (Exception ex) - { - ex.TraceUnknownException(); - projObject = null; - } - - try - { - if (projObject == null) - { - projectItem.UniqueName = project.UniqueName; - projectItem.Name = project.Name; - return; - } - - UpdateNameProperties(project, projectItem); - projectItem.Language = project.GetLanguageName(); - projectItem.CommonType = ProjectExtensions.GetProjectType(project.Kind, project.DTE.Version /* "12.0" */); - } - catch (Exception ex) - { - ex.TraceUnknownException(); - } - - #region Set ActiveConfiguration (Configuration and Platform) - - Configuration config; - try - { - config = project.ConfigurationManager.ActiveConfiguration; - } - catch (Exception ex) - { - ex.TraceUnknownException(); - config = null; - } - - if (config != null) - { - projectItem.Configuration = config.ConfigurationName; - projectItem.Platform = config.PlatformName; - } - else - { - projectItem.Configuration = @"N\A"; - projectItem.Platform = @"N\A"; - } - - #endregion - - try - { - projectItem.Framework = project.GetFrameworkString(); - - var flavourTypes = project.GetFlavourTypes().ToList(); - projectItem.FlavourType = string.Join("; ", flavourTypes); - projectItem.MainFlavourType = flavourTypes.FirstOrDefault(); - - projectItem.OutputType = project.GetOutputType(); - projectItem.ExtenderNames = project.GetExtenderNames(); - - projectItem.RootNamespace = project.GetRootNamespace(); - } - catch (Exception ex) - { - ex.TraceUnknownException(); - } - } - } - - private static void UpdateNameProperties(Project project, ProjectItem projectItem) - { - try - { - projectItem.UniqueName = project.UniqueName; - projectItem.Name = project.Name; - projectItem.FullName = project.FullName; - - if (IsIntegrationServicesProject(project, projectItem)) - AdjustUniqueNameForExtensionProjects(project, projectItem); - - try - { - projectItem.FullPath = string.IsNullOrWhiteSpace(projectItem.FullName) ? null : Path.GetDirectoryName(projectItem.FullName); - } - catch (SystemException ex) - { - // PathTooLongException, ArgumentException (invalid characters). - ex.TraceUnknownException(); - projectItem.FullPath = null; - } - - projectItem.SolutionFolder = project.GetTreePath(false) ?? @"\"; - // TODO: SolutionPath = project.GetTreePath(true); - } - catch (Exception ex) - { - ex.TraceUnknownException(); - } - } - - private const string _GUID_SQL_INTEGRATIONG_SERVICES_PROJECT_KIND = "{159641d6-6404-4a2a-ae62-294de0fe8301}"; - - private static bool IsIntegrationServicesProject(Project project, ProjectItem projectItem) - { - if (project.Kind == _GUID_SQL_INTEGRATIONG_SERVICES_PROJECT_KIND) - return projectItem.UniqueName == projectItem.FullName; - else - return false; - } - - private static void AdjustUniqueNameForExtensionProjects(Project project, ProjectItem projectItem) - { - var directory = Path.GetDirectoryName(project.UniqueName); - var directoryName = Path.GetFileName(directory); - var csprojName = Path.GetFileName(project.UniqueName); - projectItem.UniqueName = Path.Combine(directoryName, csprojName); - } - - public static void UpdateSolution(Solution solution, SolutionItem solutionItem) - { - UpdateSolutionProperties(solutionItem, solution); - } - - private static void UpdateSolutionProperties(SolutionItem solutionItem, Solution solution) - { - try - { - if (solution == null) - { - solutionItem.Name = Resources.GridCellNATextInBrackets; - solutionItem.FullName = Resources.GridCellNATextInBrackets; - solutionItem.IsEmpty = true; - } - else if (string.IsNullOrEmpty(solution.FileName)) - { - if (solution.Count != 0 /* projects count */) - { - var project = solution.Item(1); - solutionItem.Name = Path.GetFileNameWithoutExtension(project.FileName); - solutionItem.FullName = project.FullName; - solutionItem.IsEmpty = false; - } - else - { - solutionItem.Name = Resources.GridCellNATextInBrackets; - solutionItem.FullName = Resources.GridCellNATextInBrackets; - solutionItem.IsEmpty = true; - } - } - else - { - solutionItem.Name = Path.GetFileNameWithoutExtension(solution.FileName); - solutionItem.FullName = solution.FullName; - solutionItem.IsEmpty = false; - } - } - catch (Exception ex) - { - ex.TraceUnknownException(); - - solutionItem.Name = Resources.GridCellNATextInBrackets; - solutionItem.FullName = Resources.GridCellNATextInBrackets; - solutionItem.IsEmpty = true; - } - } - - public static void UpdateProjects(SolutionItem solutionItem, Solution solution) - { - solutionItem.AllProjects.Clear(); - - if (solution == null) - return; - - IList dteProjects; - try - { - dteProjects = solution.GetProjects(); - } - catch (Exception ex) - { - ex.TraceUnknownException(); - return; - } - - - - var projectItems = new List(dteProjects.Count); - foreach (Project project in dteProjects) - { - try - { - //var msBuildProject = project.GetMsBuildProject(); - var projectItem = new ProjectItem(); - UpdateProperties(project, projectItem); - projectItems.Add(projectItem); - } - catch (Exception ex) - { - ex.TraceUnknownException(); - } - } - - solutionItem.AllProjects.AddRange(projectItems); - } - } -} diff --git a/src/BuildVision/Helpers/VsCfgExtensions.cs b/src/BuildVision/Helpers/VsCfgExtensions.cs new file mode 100644 index 00000000..c60a673e --- /dev/null +++ b/src/BuildVision/Helpers/VsCfgExtensions.cs @@ -0,0 +1,16 @@ +using System; +using Microsoft.VisualStudio.Shell.Interop; + +namespace BuildVision.Helpers +{ + public static class VsCfgExtensions + { + public static Tuple ToConfigurationTuple(this IVsCfg pCfgProj) + { + pCfgProj.get_DisplayName(out var projConfiguration); + var config = projConfiguration.Split('|'); + + return new Tuple(config[0], config[1]); + } + } +} diff --git a/src/BuildVision/Helpers/VsHierarchyExtensions.cs b/src/BuildVision/Helpers/VsHierarchyExtensions.cs new file mode 100644 index 00000000..ad9c6029 --- /dev/null +++ b/src/BuildVision/Helpers/VsHierarchyExtensions.cs @@ -0,0 +1,17 @@ +using EnvDTE; +using Microsoft.VisualStudio; +using Microsoft.VisualStudio.Shell; +using Microsoft.VisualStudio.Shell.Interop; + +namespace BuildVision.Helpers +{ + public static class VsHierarchyExtensions + { + public static Project ToProject(this IVsHierarchy pHierProj) + { + ThreadHelper.ThrowIfNotOnUIThread(); + pHierProj.GetProperty(VSConstants.VSITEMID_ROOT, (int) __VSHPROPID.VSHPROPID_ExtObject, out var objProj); + return objProj as Project; + } + } +} diff --git a/src/BuildVision/Tool/BuildVisionPane.cs b/src/BuildVision/Tool/BuildVisionPane.cs index 52094631..f60a189d 100644 --- a/src/BuildVision/Tool/BuildVisionPane.cs +++ b/src/BuildVision/Tool/BuildVisionPane.cs @@ -31,8 +31,9 @@ namespace BuildVision.Tool public sealed class BuildVisionPane : ToolWindowPane { private bool _controlCreatedSuccessfully; + private readonly BuildVisionPaneViewModel _viewModel; - public BuildVisionPane() + public BuildVisionPane(BuildVisionPaneViewModel viewModel) :base(null) { Caption = Resources.ToolWindowTitle; @@ -50,6 +51,7 @@ public BuildVisionPane() FrameworkElement.LanguageProperty.OverrideMetadata( typeof(FrameworkElement), new FrameworkPropertyMetadata(XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag))); + _viewModel = viewModel; } protected override void Initialize() @@ -74,12 +76,11 @@ protected override void OnClose() private ControlView CreateControlView() { var packageContext = (IPackageContext)Package; - var viewModel = new BuildVisionPaneViewModel(new ControlModel(), new UI.Settings.Models.ControlSettings());//packageContext.ControlSettings); packageContext.ControlSettingsChanged += (settings) => { - viewModel.OnControlSettingsChanged(settings, buildInfo => BuildMessages.GetBuildDoneMessage(viewModel.SolutionItem, buildInfo, viewModel.ControlSettings.BuildMessagesSettings)); + _viewModel.OnControlSettingsChanged(settings); //, buildInfo => BuildMessages.GetBuildDoneMessage(viewModel.SolutionItem, buildInfo, viewModel.ControlSettings.BuildMessagesSettings)); }; - var view = new ControlView { DataContext = viewModel }; + var view = new ControlView { DataContext = _viewModel }; view.Resources.MergedDictionaries.Add(new ResourceDictionary { Source = new Uri("pack://application:,,,/BuildVision.UI;component/Styles/ExtensionStyle.xaml") diff --git a/src/BuildVision/Tool/Building/BackgroundBuildProcessUpdater.cs b/src/BuildVision/Tool/Building/BackgroundBuildProcessUpdater.cs new file mode 100644 index 00000000..cc581320 --- /dev/null +++ b/src/BuildVision/Tool/Building/BackgroundBuildProcessUpdater.cs @@ -0,0 +1,59 @@ +using System; +using System.Threading; +using BuildVision.UI.Common.Logging; + +namespace BuildVision.Tool.Building +{ + public class BackgroundBuildProcessUpdater + { + private const int BuildInProcessCountOfQuantumSleep = 5; + private const int BuildInProcessQuantumSleep = 50; + private object _buildProcessLockObject; + + public BackgroundBuildProcessUpdater() + { + + } + + public void Start(object state) + { + lock (_buildProcessLockObject) + { + var token = (CancellationToken) state; + while (!token.IsCancellationRequested) + { + OnBuildProcess(); + + for (int i = 0; i < BuildInProcessQuantumSleep * BuildInProcessCountOfQuantumSleep; i += BuildInProcessQuantumSleep) + { + if (token.IsCancellationRequested) + break; + + System.Threading.Thread.Sleep(BuildInProcessQuantumSleep); + } + } + } + } + + + private void OnBuildProcess() + { + try + { + //var labelsSettings = _viewModel.ControlSettings.BuildMessagesSettings; + //string msg = _origTextCurrentState + BuildMessages.GetBuildBeginExtraMessage(this, labelsSettings); + + //_viewModel.TextCurrentState = msg; + //_statusBarNotificationService.ShowTextWithFreeze(msg); + + //var buildingProjects = BuildingProjects; + //for (int i = 0; i < buildingProjects.Count; i++) + // buildingProjects[i].RaiseBuildElapsedTimeChanged(); + } + catch (Exception ex) + { + ex.TraceUnknownException(); + } + } + } +} diff --git a/src/BuildVision/Tool/Building/BuildContext.cs b/src/BuildVision/Tool/Building/BuildContext.cs index a17521a5..7ae143f5 100644 --- a/src/BuildVision/Tool/Building/BuildContext.cs +++ b/src/BuildVision/Tool/Building/BuildContext.cs @@ -18,7 +18,6 @@ using BuildVision.UI.Extensions; using BuildVision.UI.Helpers; using BuildVision.UI.Models; -using BuildVision.UI.Models.Indicators.Core; using BuildVision.UI.Settings.Models.ToolWindow; using BuildVision.UI.ViewModels; using EnvDTE; @@ -31,610 +30,177 @@ namespace BuildVision.Tool.Building { - public class BuildContext : IBuildInfo, IBuildDistributor - { - private const int BuildInProcessCountOfQuantumSleep = 5; - private const int BuildInProcessQuantumSleep = 50; + public class BuildContext + { private const string CancelBuildCommand = "Build.Cancel"; - - private readonly object _buildingProjectsLockObject; - private readonly object _buildProcessLockObject = new object(); - private readonly IVsItemLocatorService _locatorService; - private readonly IStatusBarNotificationService _statusBarNotificationService; - private readonly IPackageContext _packageContext; - private readonly DTE _dte; - private readonly Solution _solution; - private readonly Guid _parsingErrorsLoggerId = new Guid("{64822131-DC4D-4087-B292-61F7E06A7B39}"); - private BuildOutputLogger _buildLogger; private CancellationTokenSource _buildProcessCancellationToken; - private bool _buildCancelledInternally; private readonly BuildVisionPaneViewModel _viewModel; private bool _buildCancelled; - private readonly BuildEvents _buildEvents; - private readonly CommandEvents _commandEvents; - private readonly ToolWindowManager _toolWindowManager; - private bool _buildErrorIsNavigated; - private string _origTextCurrentState; - - public bool BuildIsCancelled => _buildCancelled && !_buildCancelledInternally; - - public BuildActions? BuildAction { get; private set; } - - public BuildScopes? BuildScope { get; private set; } - - public BuildState CurrentBuildState { get; private set; } - - public DateTime? BuildStartTime { get; private set; } - - public DateTime? BuildFinishTime { get; private set; } - - public BuildedProjectsCollection BuildedProjects { get; } - - public IList BuildingProjects { get; } - - public BuildedSolution BuildedSolution { get; private set; } - - public BuildedSolution BuildingSolution { get; private set; } - - public ProjectItem BuildScopeProject { get; private set; } - - public BuildContext(IVsItemLocatorService locatorService, IStatusBarNotificationService statusBarNotificationService, IPackageContext packageContext, DTE dte, BuildVisionPaneViewModel viewModel) - { - _viewModel = viewModel; - BuildedProjects = new BuildedProjectsCollection(); - BuildingProjects = new List(); - _buildingProjectsLockObject = ((ICollection)BuildingProjects).SyncRoot; - _locatorService = locatorService; - _statusBarNotificationService = statusBarNotificationService; - _packageContext = packageContext; - _dte = dte; - _buildEvents = dte.Events.BuildEvents; - _commandEvents = dte.Events.CommandEvents; - - _buildEvents.OnBuildBegin += BuildEvents_OnBuildBegin; - _buildEvents.OnBuildDone += (s, e) => BuildEvents_OnBuildDone(); - _buildEvents.OnBuildProjConfigBegin += BuildEvents_OnBuildProjectBegin; - _buildEvents.OnBuildProjConfigDone += BuildEvents_OnBuildProjectDone; - - _commandEvents.AfterExecute += CommandEvents_AfterExecute; - } - - public void OverrideBuildProperties(BuildActions? buildAction = null, BuildScopes? buildScope = null) - { - BuildAction = buildAction ?? BuildAction; - BuildScope = buildScope ?? BuildScope; - } public async Task CancelBuildAsync() { - if(BuildAction == BuildActions.BuildActionClean) - return; - if (CurrentBuildState != BuildState.InProgress || _buildCancelled || _buildCancelledInternally) - return; - - try - { - // We need to create a separate task here because of some weird things that are going on - // when calling ExecuteCommand directly. Directly calling it leads to a freeze. No need - // for that! - await _packageContext.ExecuteCommandAsync(CancelBuildCommand); - _buildCancelledInternally = true; - } - catch (Exception ex) - { - ex.Trace("Cancel build failed."); - } - } - - private void RegisterLogger() - { - _buildLogger = null; - - // Same Verbosity as in the Error List. - const LoggerVerbosity LoggerVerbosity = LoggerVerbosity.Quiet; - RegisterLoggerResult result = BuildOutputLogger.Register(_parsingErrorsLoggerId, LoggerVerbosity, out _buildLogger); - - if (result == RegisterLoggerResult.AlreadyExists) - { - _buildLogger.Projects?.Clear(); - } + //if (BuildAction == BuildActions.BuildActionClean) + // return; + //if (CurrentBuildState != BuildState.InProgress || _buildCancelled || _buildCancelledInternally) + // return; + + //try + //{ + // // We need to create a separate task here because of some weird things that are going on + // // when calling ExecuteCommand directly. Directly calling it leads to a freeze. No need + // // for that! + // await _packageContext.ExecuteCommandAsync(CancelBuildCommand); + // _buildCancelledInternally = true; + //} + //catch (Exception ex) + //{ + // ex.Trace("Cancel build failed."); + //} } private void CommandEvents_AfterExecute(string guid, int id, object customIn, object customOut) { - if (id == (int)VSConstants.VSStd97CmdID.CancelBuild + if (id == (int) VSConstants.VSStd97CmdID.CancelBuild && Guid.Parse(guid) == VSConstants.GUID_VSStandardCommandSet97) { - _buildCancelled = true; - if (!_buildCancelledInternally) - OnBuildCancelled(); - } - } - - private ProjectState GetProjectState() - { - ProjectState projectState; - switch (BuildAction) - { - case BuildActions.BuildActionBuild: - case BuildActions.BuildActionRebuildAll: - projectState = ProjectState.Building; - break; - - case BuildActions.BuildActionClean: - projectState = ProjectState.Cleaning; - break; - - case BuildActions.BuildActionDeploy: - throw new InvalidOperationException("vsBuildActionDeploy not supported"); - - default: - throw new ArgumentOutOfRangeException(nameof(BuildAction)); - } - - return projectState; - } - - private void BuildEvents_OnBuildBegin(vsBuildScope scope, vsBuildAction action) - { - if (action == vsBuildAction.vsBuildActionDeploy) - return; - - RegisterLogger(); - - CurrentBuildState = BuildState.InProgress; - - BuildStartTime = DateTime.Now; - BuildFinishTime = null; - BuildAction = (BuildActions) action; - - switch (scope) - { - case vsBuildScope.vsBuildScopeSolution: - case vsBuildScope.vsBuildScopeBatch: - case vsBuildScope.vsBuildScopeProject: - BuildScope = (BuildScopes) scope; - break; - - case 0: - // Scope may be 0 in case of Clean solution, then Start (F5). - BuildScope = (BuildScopes) vsBuildScope.vsBuildScopeSolution; - break; - - default: - throw new ArgumentOutOfRangeException("scope"); - } - - if (scope == vsBuildScope.vsBuildScopeProject) - { - var selectedProjects = _dte.ActiveSolutionProjects as object[]; - if (selectedProjects?.Length == 1) - { - var projectItem = new ProjectItem(); - ViewModelHelper.UpdateProperties((Project) selectedProjects[0], projectItem); - BuildScopeProject = projectItem; - } - } - - _buildCancelled = false; - _buildCancelledInternally = false; - - BuildedProjects.Clear(); - lock (_buildingProjectsLockObject) - { - BuildingProjects.Clear(); - } - - BuildedSolution = null; - var solution = _dte.Solution; - BuildingSolution = new BuildedSolution(solution.FullName, solution.FileName); - - OnBuildBegin(); - - _buildProcessCancellationToken = new CancellationTokenSource(); - Task.Factory.StartNew(BuildEvents_BuildInProcess, _buildProcessCancellationToken.Token, _buildProcessCancellationToken.Token); - } - - private void BuildEvents_OnBuildProjectBegin(string project, string projectconfig, string platform, string solutionconfig) - { - if (BuildAction == BuildActions.BuildActionDeploy) - return; - - var eventTime = DateTime.Now; - - ProjectItem currentProject; - if (BuildScope == BuildScopes.BuildScopeBatch) - { - currentProject = _locatorService.FindProjectItemInProjectsByUniqueName(_viewModel, project, projectconfig, platform); - if (currentProject == null) - currentProject = _locatorService.AddProjectToVisibleProjectsByUniqueName(_viewModel, project, projectconfig, platform); - } - else - { - currentProject = _locatorService.FindProjectItemInProjectsByUniqueName(_viewModel, project); - if (currentProject == null) - currentProject = _locatorService.AddProjectToVisibleProjectsByUniqueName(_viewModel, project); - } - - lock (_buildingProjectsLockObject) - { - BuildingProjects.Add(currentProject); - } - - var projectState = GetProjectState(); - OnBuildProjectBegin(new BuildProjectEventArgs(currentProject, projectState, eventTime, null)); - } - - private void BuildEvents_BuildInProcess(object state) - { - lock (_buildProcessLockObject) - { - if (BuildAction == BuildActions.BuildActionDeploy) - return; - - var token = (CancellationToken) state; - while (!token.IsCancellationRequested) - { - OnBuildProcess(); - - for (int i = 0; i < BuildInProcessQuantumSleep * BuildInProcessCountOfQuantumSleep; i += BuildInProcessQuantumSleep) - { - if (token.IsCancellationRequested) - break; - - System.Threading.Thread.Sleep(BuildInProcessQuantumSleep); - } - } - } - } - - private void BuildEvents_OnBuildProjectDone(string project, string projectconfig, string platform, string solutionconfig, bool success) - { - if (BuildAction == BuildActions.BuildActionDeploy) - return; - - var eventTime = DateTime.Now; - var currentProject = _locatorService.GetCurrentProject(_viewModel, BuildScope, project, projectconfig, platform); - - lock (_buildingProjectsLockObject) - { - BuildingProjects.Remove(currentProject); - } - - BuildedProject buildedProject = BuildedProjects[currentProject]; - buildedProject.Success = success; - - ProjectState projectState; - switch (BuildAction) - { - case BuildActions.BuildActionBuild: - case BuildActions.BuildActionRebuildAll: - if (success) - { - if (_viewModel.ControlSettings.GeneralSettings.ShowWarningSignForBuilds && buildedProject.ErrorsBox.WarningsCount > 0) - projectState = ProjectState.BuildWarning; - else - { - bool upToDate = (_buildLogger != null && _buildLogger.Projects != null - && !_buildLogger.Projects.Exists(t => t.FileName == buildedProject.FileName)); - if (upToDate) - { - // Because ErrorBox will be empty if project is UpToDate. - buildedProject.ErrorsBox = currentProject.ErrorsBox; - } - projectState = upToDate ? ProjectState.UpToDate : ProjectState.BuildDone; - } - } - else - { - bool canceled = (_buildCancelled && buildedProject.ErrorsBox.ErrorsCount == 0); - projectState = canceled ? ProjectState.BuildCancelled : ProjectState.BuildError; - } - break; - - case BuildActions.BuildActionClean: - projectState = success ? ProjectState.CleanDone : ProjectState.CleanError; - break; - - case BuildActions.BuildActionDeploy: - throw new InvalidOperationException("vsBuildActionDeploy not supported"); - - default: - throw new ArgumentOutOfRangeException(nameof(BuildAction)); - } - - buildedProject.ProjectState = projectState; - OnBuildProjectDone(new BuildProjectEventArgs(currentProject, projectState, eventTime, buildedProject)); - } - - private void BuildEvents_OnBuildDone() - { - if (BuildAction == BuildActions.BuildActionDeploy) - return; - - if (CurrentBuildState != BuildState.InProgress) - { - // Start command (F5), when Build is not required. - return; - } - - _buildProcessCancellationToken.Cancel(); - - BuildedSolution = BuildingSolution; - BuildingSolution = null; - - lock (_buildingProjectsLockObject) - { - BuildingProjects.Clear(); - } - - BuildFinishTime = DateTime.Now; - CurrentBuildState = BuildState.Done; - - OnBuildDone(); - } - - private void OnBuildProjectBegin(BuildProjectEventArgs e) - { - try - { - ProjectItem currentProject = e.ProjectItem; - currentProject.State = e.ProjectState; - currentProject.BuildFinishTime = null; - currentProject.BuildStartTime = e.EventTime; - - _viewModel.OnBuildProjectBegin(); - if (BuildScope == BuildScopes.BuildScopeSolution && - (BuildAction == BuildActions.BuildActionBuild || - BuildAction == BuildActions.BuildActionRebuildAll)) - { - currentProject.BuildOrder = _viewModel.BuildProgressViewModel.CurrentQueuePosOfBuildingProject; - } - - if (!_viewModel.ProjectsList.Contains(currentProject)) - _viewModel.ProjectsList.Add(currentProject); - else if (_viewModel.ControlSettings.GeneralSettings.FillProjectListOnBuildBegin) - _viewModel.OnPropertyChanged(nameof(BuildVisionPaneViewModel.GroupedProjectsList)); - _viewModel.CurrentProject = currentProject; - } - catch (Exception ex) - { - ex.TraceUnknownException(); - } - } - - private void OnBuildProjectDone(BuildProjectEventArgs e) - { - if (e.ProjectState == ProjectState.BuildError && _viewModel.ControlSettings.GeneralSettings.StopBuildAfterFirstError) - CancelBuildAsync(); - - try - { - ProjectItem currentProject = e.ProjectItem; - currentProject.State = e.ProjectState; - currentProject.BuildFinishTime = DateTime.Now; - currentProject.UpdatePostBuildProperties(e.BuildedProjectInfo); - - if (!_viewModel.ProjectsList.Contains(currentProject)) - _viewModel.ProjectsList.Add(currentProject); - - if (ReferenceEquals(_viewModel.CurrentProject, e.ProjectItem) && BuildingProjects.Any()) - _viewModel.CurrentProject = BuildingProjects.Last(); - } - catch (Exception ex) - { - ex.TraceUnknownException(); - } - - _viewModel.UpdateIndicators(this); - - try - { - _viewModel.OnBuildProjectDone(e.BuildedProjectInfo); - } - catch (Exception ex) - { - ex.TraceUnknownException(); + //_buildCancelled = true; + //if (!_buildCancelledInternally) + // OnBuildCancelled(); } } - private void OnBuildBegin() + private int GetProjectsCount(int projectsCount) { - try - { - _buildErrorIsNavigated = false; - - ApplyToolWindowStateAction(_viewModel.ControlSettings.WindowSettings.WindowActionOnBuildBegin); - - ViewModelHelper.UpdateSolution(_dte.Solution, _viewModel.SolutionItem); - - string message = BuildMessages.GetBuildBeginMajorMessage(_viewModel.SolutionItem, this, _viewModel.ControlSettings.BuildMessagesSettings); + // TODO need to figure out how to get building projectscount + //switch (BuildScope) + //{ + // case BuildScopes.BuildScopeSolution: + // if (_viewModel.ControlSettings.GeneralSettings.FillProjectListOnBuildBegin) + // { + // projectsCount = _viewModel.ProjectsList.Count; + // } + // else + // { + // try + // { + // Solution solution = _dte.Solution; + // if (solution != null) + // projectsCount = solution.GetProjects().Count; + // } + // catch (Exception ex) + // { + // ex.Trace("Unable to count projects in solution."); + // } + // } + // break; - _statusBarNotificationService.ShowTextWithFreeze(message); - _viewModel.TextCurrentState = message; - _origTextCurrentState = message; - _viewModel.ImageCurrentState = BuildImages.GetBuildBeginImage(this); - _viewModel.ImageCurrentStateResult = null; + // case BuildScopes.BuildScopeBatch: + // case BuildScopes.BuildScopeProject: + // break; - ViewModelHelper.UpdateProjects(_viewModel.SolutionItem, Services.Dte.Solution); - _viewModel.ProjectsList.Clear(); + // default: + // throw new ArgumentOutOfRangeException(nameof(BuildScope)); + //} - if (_viewModel.ControlSettings.GeneralSettings.FillProjectListOnBuildBegin) - _viewModel.ProjectsList.AddRange(_viewModel.SolutionItem.AllProjects); - - _viewModel.ResetIndicators(ResetIndicatorMode.ResetValue); - - int projectsCount = -1; - switch (BuildScope) - { - case BuildScopes.BuildScopeSolution: - if (_viewModel.ControlSettings.GeneralSettings.FillProjectListOnBuildBegin) - { - projectsCount = _viewModel.ProjectsList.Count; - } - else - { - try - { - Solution solution = _dte.Solution; - if (solution != null) - projectsCount = solution.GetProjects().Count; - } - catch (Exception ex) - { - ex.Trace("Unable to count projects in solution."); - } - } - break; - - case BuildScopes.BuildScopeBatch: - case BuildScopes.BuildScopeProject: - break; - - default: - throw new ArgumentOutOfRangeException(nameof(BuildScope)); - } - - _viewModel.OnBuildBegin(projectsCount, this); - } - catch (Exception ex) - { - ex.TraceUnknownException(); - } + return projectsCount; } - private void OnBuildProcess() + private void ApplyWindowState(UI.Settings.Models.ControlSettings settings) { - try - { - var labelsSettings = _viewModel.ControlSettings.BuildMessagesSettings; - string msg = _origTextCurrentState + BuildMessages.GetBuildBeginExtraMessage(this, labelsSettings); - - _viewModel.TextCurrentState = msg; - _statusBarNotificationService.ShowTextWithFreeze(msg); - - var buildingProjects = BuildingProjects; - for (int i = 0; i < buildingProjects.Count; i++) - buildingProjects[i].RaiseBuildElapsedTimeChanged(); - } - catch (Exception ex) - { - ex.TraceUnknownException(); - } + // Figure out when build is canceled + //int errorProjectsCount = _viewModel.ProjectsList.Count(item => item.State.IsErrorState()); + //if (errorProjectsCount > 0 || BuildIsCancelled) + // ApplyToolWindowStateAction(settings.WindowSettings.WindowActionOnBuildError); + //else + // ApplyToolWindowStateAction(settings.WindowSettings.WindowActionOnBuildSuccess); } - private void OnBuildDone() + private void NavigateToBuildErrorIfNeeded(UI.Settings.Models.ControlSettings settings) { - try - { - var settings = _viewModel.ControlSettings; - - if (BuildScope == BuildScopes.BuildScopeSolution) - { - foreach (var projectItem in _viewModel.ProjectsList) - { - if (projectItem.State == ProjectState.Pending) - projectItem.State = ProjectState.Skipped; - } - } - - _viewModel.UpdateIndicators(this); - - var message = BuildMessages.GetBuildDoneMessage(_viewModel.SolutionItem, this, settings.BuildMessagesSettings); - var buildDoneImage = BuildImages.GetBuildDoneImage(this, _viewModel.ProjectsList, out ControlTemplate stateImage); - - _statusBarNotificationService.ShowText(message); - _viewModel.TextCurrentState = message; - _viewModel.ImageCurrentState = buildDoneImage; - _viewModel.ImageCurrentStateResult = stateImage; - _viewModel.CurrentProject = null; - _viewModel.OnBuildDone(this); - - int errorProjectsCount = _viewModel.ProjectsList.Count(item => item.State.IsErrorState()); - if (errorProjectsCount > 0 || BuildIsCancelled) - ApplyToolWindowStateAction(settings.WindowSettings.WindowActionOnBuildError); - else - ApplyToolWindowStateAction(settings.WindowSettings.WindowActionOnBuildSuccess); - - bool navigateToBuildFailureReason = (!BuildedProjects.BuildWithoutErrors - && settings.GeneralSettings.NavigateToBuildFailureReason == NavigateToBuildFailureReasonCondition.OnBuildDone); - if (navigateToBuildFailureReason && BuildedProjects.Any(p => p.ErrorsBox.Errors.Any(NavigateToErrorItem))) - { - _buildErrorIsNavigated = true; - } - } - catch (Exception ex) - { - ex.TraceUnknownException(); - } + // How to get errors that happend during build? + //bool navigateToBuildFailureReason = (!BuildedProjects.BuildWithoutErrors + // && settings.GeneralSettings.NavigateToBuildFailureReason == NavigateToBuildFailureReasonCondition.OnBuildDone); + //if (navigateToBuildFailureReason && BuildedProjects.Any(p => p.ErrorsBox.Errors.Any(NavigateToErrorItem))) + //{ + // _buildErrorIsNavigated = true; + //} } - private void OnBuildCancelled() + private void SetFinalStateForUnfinishedProjects() { - _viewModel.OnBuildCancelled(this); + // What happens if project only is builded? What do we do with the projectslist + //if (BuildScope == BuildScopes.BuildScopeSolution) + //{ + // foreach (var projectItem in _viewModel.ProjectsList) + // { + // if (projectItem.State == ProjectState.Pending) + // projectItem.State = ProjectState.Skipped; + // } + //} } private async void OnErrorRaised(object sender, BuildErrorRaisedEventArgs args) { - bool buildNeedToCancel = (args.ErrorLevel == ErrorLevel.Error && _viewModel.ControlSettings.GeneralSettings.StopBuildAfterFirstError); - if (buildNeedToCancel) - await CancelBuildAsync(); + //bool buildNeedToCancel = (args.ErrorLevel == ErrorLevel.Error && _viewModel.ControlSettings.GeneralSettings.StopBuildAfterFirstError); + //if (buildNeedToCancel) + // await CancelBuildAsync(); - bool navigateToBuildFailureReason = (!_buildErrorIsNavigated - && args.ErrorLevel == ErrorLevel.Error - && _viewModel.ControlSettings.GeneralSettings.NavigateToBuildFailureReason == NavigateToBuildFailureReasonCondition.OnErrorRaised); - if (navigateToBuildFailureReason && args.ProjectInfo.ErrorsBox.Errors.Any(NavigateToErrorItem)) - { - _buildErrorIsNavigated = true; - } + //bool navigateToBuildFailureReason = (!_buildErrorIsNavigated + // && args.ErrorLevel == ErrorLevel.Error + // && _viewModel.ControlSettings.GeneralSettings.NavigateToBuildFailureReason == NavigateToBuildFailureReasonCondition.OnErrorRaised); + //if (navigateToBuildFailureReason && args.ProjectInfo.ErrorsBox.Errors.Any(NavigateToErrorItem)) + //{ + // _buildErrorIsNavigated = true; + //} } private bool NavigateToErrorItem(ErrorItem errorItem) { - if (string.IsNullOrEmpty(errorItem?.File) || string.IsNullOrEmpty(errorItem?.ProjectFile)) - return false; + return false; + //if (string.IsNullOrEmpty(errorItem?.File) || string.IsNullOrEmpty(errorItem?.ProjectFile)) + // return false; - try - { - var projectItem = _viewModel.ProjectsList.FirstOrDefault(x => x.FullName == errorItem.ProjectFile); - if (projectItem == null) - return false; + //try + //{ + // var projectItem = _viewModel.ProjectsList.FirstOrDefault(x => x.FullName == errorItem.ProjectFile); + // if (projectItem == null) + // return false; - var project = _dte.Solution.GetProject(x => x.UniqueName == projectItem.UniqueName); - if (project == null) - return false; + // var project = _dte.Solution.GetProject(x => x.UniqueName == projectItem.UniqueName); + // if (project == null) + // return false; - return project.NavigateToErrorItem(errorItem); - } - catch (Exception ex) - { - ex.Trace("Navigate to error item exception"); - return true; - } + // return project.NavigateToErrorItem(errorItem); + //} + //catch (Exception ex) + //{ + // ex.Trace("Navigate to error item exception"); + // return true; + //} } private void ApplyToolWindowStateAction(WindowStateAction windowStateAction) { - switch (windowStateAction.State) - { - case WindowState.Nothing: - break; - case WindowState.Show: - _toolWindowManager.Show(); - break; - case WindowState.ShowNoActivate: - _toolWindowManager.ShowNoActivate(); - break; - case WindowState.Hide: - _toolWindowManager.Hide(); - break; - case WindowState.Close: - _toolWindowManager.Close(); - break; - default: - throw new ArgumentOutOfRangeException(nameof(windowStateAction)); - } + //switch (windowStateAction.State) + //{ + // case WindowState.Nothing: + // break; + // case WindowState.Show: + // _toolWindowManager.Show(); + // break; + // case WindowState.ShowNoActivate: + // _toolWindowManager.ShowNoActivate(); + // break; + // case WindowState.Hide: + // _toolWindowManager.Hide(); + // break; + // case WindowState.Close: + // _toolWindowManager.Close(); + // break; + // default: + // throw new ArgumentOutOfRangeException(nameof(windowStateAction)); + //} } } } diff --git a/src/BuildVision/Tool/Building/BuildManager.cs b/src/BuildVision/Tool/Building/BuildManager.cs index c290cc6b..b9a57662 100644 --- a/src/BuildVision/Tool/Building/BuildManager.cs +++ b/src/BuildVision/Tool/Building/BuildManager.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Collections.Specialized; using System.ComponentModel; +using System.ComponentModel.Composition; using System.IO; using System.Linq; using System.Threading.Tasks; @@ -9,6 +10,7 @@ using BuildVision.Common; using BuildVision.Contracts; using BuildVision.Core; +using BuildVision.Exports.Services; using BuildVision.Helpers; using BuildVision.UI; using BuildVision.UI.Common.Logging; @@ -18,17 +20,10 @@ namespace BuildVision.Tool.Building { - public class BuildManager + [Export(typeof(IBuildService))] + [PartCreationPolicy(CreationPolicy.NonShared)] + public class BuildManager : IBuildService { - public BuildActions? BuildAction { get; private set; } - - public BuildScopes? BuildScope { get; private set; } - - public BuildState CurrentBuildState { get; private set; } - - private bool _buildCancelled; - private bool _buildCancelledInternally; - public BuildManager() { //_viewModel.RaiseCommandForSelectedProject += RaiseCommandForSelectedProject; @@ -60,23 +55,23 @@ public void BuildSolution() public async Task CancelBuildAsync() { - if (BuildAction == BuildActions.BuildActionClean) - return; - if (CurrentBuildState != BuildState.InProgress || _buildCancelled || _buildCancelledInternally) - return; - - try - { - // We need to create a separate task here because of some weird things that are going on - // when calling ExecuteCommand directly. Directly calling it leads to a freeze. No need - // for that! - //await _packageContext.ExecuteCommandAsync(CancelBuildCommand); - _buildCancelledInternally = true; - } - catch (Exception ex) - { - ex.Trace("Cancel build failed."); - } + //if (BuildAction == BuildActions.BuildActionClean) + // return; + //if (CurrentBuildState != BuildState.InProgress || _buildCancelled || _buildCancelledInternally) + // return; + + //try + //{ + // // We need to create a separate task here because of some weird things that are going on + // // when calling ExecuteCommand directly. Directly calling it leads to a freeze. No need + // // for that! + // //await _packageContext.ExecuteCommandAsync(CancelBuildCommand); + // _buildCancelledInternally = true; + //} + //catch (Exception ex) + //{ + // ex.Trace("Cancel build failed."); + //} } public void RaiseCommandForSelectedProject(UI.Models.ProjectItem selectedProjectItem, int commandId) @@ -201,6 +196,26 @@ private void RaiseCommand(VSConstants.VSStd97CmdID command) { ex.TraceUnknownException(); } - } + } + + public void ShowGridColumnsSettingsPage() + { + throw new NotImplementedException(); + } + + public void ShowGeneralSettingsPage() + { + throw new NotImplementedException(); + } + + public void ProjectCopyBuildOutputFilesToClipBoard() + { + throw new NotImplementedException(); + } + + public void RaiseCommandForSelectedProject() + { + throw new NotImplementedException(); + } } } diff --git a/src/BuildVision/Tool/Building/BuildOutputLogger.cs b/src/BuildVision/Tool/Building/BuildOutputLogger.cs index a2024d48..307f7de2 100644 --- a/src/BuildVision/Tool/Building/BuildOutputLogger.cs +++ b/src/BuildVision/Tool/Building/BuildOutputLogger.cs @@ -2,36 +2,28 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; - -using Microsoft.Build.Execution; using Microsoft.Build.Framework; using Microsoft.Build.Utilities; using BuildVision.Contracts; using BuildVision.UI.Contracts; using BuildVision.UI.Common.Logging; using BuildVision.Helpers; -using BuildVision.UI.ViewModels; -using BuildVision.Core; +using System.Diagnostics; namespace BuildVision.Tool.Building { public class BuildOutputLogger : Logger { - private List _projects; private readonly Guid _id; - private readonly IVsItemLocatorService _locatorService; - private readonly BuildVisionPaneViewModel _viewModel; - private BuildOutputLogger(Guid id, IVsItemLocatorService locatorService = null, BuildVisionPaneViewModel viewModel = null) + public List Projects => _projects; + + private BuildOutputLogger(Guid id) { _id = id; - _locatorService = locatorService; - _viewModel = viewModel; } - public List Projects => _projects; - public override void Initialize(IEventSource eventSource) { _projects = new List(); @@ -62,8 +54,6 @@ public static RegisterLoggerResult Register(Guid loggerId, LoggerVerbosity logge Type buildHostType = buildManager.GetType().Assembly.GetType("Microsoft.Build.BackEnd.IBuildComponentHost"); PropertyInfo loggingSeviceProperty = buildHostType.GetProperty("LoggingService", InterfacePropertyFlags); - - object loggingServiceObj; try { @@ -116,7 +106,7 @@ private void EventSource_ErrorRaised(object sender, BuildEventArgs e, ErrorLevel var projectEntry = Projects.Find(t => t.InstanceId == projectInstanceId && t.ContextId == projectContextId); if (projectEntry == null) { - //TraceManager.Trace(string.Format("Project entry not found by ProjectInstanceId='{0}' and ProjectContextId='{1}'.", projectInstanceId, projectContextId), EventLogEntryType.Warning); + TraceManager.Trace(string.Format("Project entry not found by ProjectInstanceId='{0}' and ProjectContextId='{1}'.", projectInstanceId, projectContextId), EventLogEntryType.Warning); return; } if (projectEntry.IsInvalid) diff --git a/src/BuildVision/Tool/Building/IVsItemLocatorService.cs b/src/BuildVision/Tool/Building/IVsItemLocatorService.cs deleted file mode 100644 index 26b1dd07..00000000 --- a/src/BuildVision/Tool/Building/IVsItemLocatorService.cs +++ /dev/null @@ -1,18 +0,0 @@ -using BuildVision.Contracts; -using BuildVision.UI; -using BuildVision.UI.Contracts; -using BuildVision.UI.Models; - -namespace BuildVision.Tool.Building -{ - public interface IVsItemLocatorService - { - ProjectItem AddProjectToVisibleProjectsByUniqueName(IBuildVisionPaneViewModel viewModel, string uniqueName); - ProjectItem AddProjectToVisibleProjectsByUniqueName(IBuildVisionPaneViewModel viewModel, string uniqueName, string configuration, string platform); - ProjectItem FindProjectItemInProjectsByUniqueName(IBuildVisionPaneViewModel viewModel, string uniqueName); - ProjectItem FindProjectItemInProjectsByUniqueName(IBuildVisionPaneViewModel viewModel, string uniqueName, string configuration, string platform); - - ProjectItem GetCurrentProject(IBuildVisionPaneViewModel viewModel, BuildScopes? buildScope, string project, string projectconfig, string platform); - bool GetProjectItem(IBuildVisionPaneViewModel viewModel, BuildScopes? buildScope, BuildProjectContextEntry projectEntry, out ProjectItem projectItem); - } -} diff --git a/src/BuildVision/Tool/Building/VsItemLocatorService.cs b/src/BuildVision/Tool/Building/VsItemLocatorService.cs deleted file mode 100644 index 6e63a657..00000000 --- a/src/BuildVision/Tool/Building/VsItemLocatorService.cs +++ /dev/null @@ -1,132 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using BuildVision.Contracts; -using BuildVision.Helpers; -using BuildVision.UI; -using BuildVision.UI.Common.Logging; -using BuildVision.UI.Contracts; -using ProjectItem = BuildVision.UI.Models.ProjectItem; - -namespace BuildVision.Tool.Building -{ - public class VsItemLocatorService : IVsItemLocatorService - { - public ProjectItem FindProjectItemInProjectsByUniqueName(IBuildVisionPaneViewModel viewModel, string uniqueName, string configuration, string platform) - { - return viewModel.ProjectsList.FirstOrDefault(item => item.UniqueName == uniqueName && item.Configuration == configuration && PlatformsIsEquals(item.Platform, platform)); - } - - public ProjectItem FindProjectItemInProjectsByUniqueName(IBuildVisionPaneViewModel viewModel, string uniqueName) - { - return viewModel.ProjectsList.FirstOrDefault(item => item.UniqueName == uniqueName); - } - - public ProjectItem AddProjectToVisibleProjectsByUniqueName(IBuildVisionPaneViewModel viewModel, string uniqueName) - { - var proj = viewModel.SolutionItem.AllProjects.FirstOrDefault(x => x.UniqueName == uniqueName); - if (proj == null) - throw new InvalidOperationException(); - viewModel.ProjectsList.Add(proj); - return proj; - } - - public ProjectItem AddProjectToVisibleProjectsByUniqueName(IBuildVisionPaneViewModel viewModel, string uniqueName, string configuration, string platform) - { - var currentProject = viewModel.SolutionItem.AllProjects.FirstOrDefault(item => item.UniqueName == uniqueName - && item.Configuration == configuration - && PlatformsIsEquals(item.Platform, platform)); - if (currentProject == null) - { - currentProject = viewModel.SolutionItem.AllProjects.FirstOrDefault(x => x.UniqueName == uniqueName); - if (currentProject == null) - throw new InvalidOperationException(); - currentProject = currentProject.GetBatchBuildCopy(configuration, platform); - viewModel.SolutionItem.AllProjects.Add(currentProject); - } - - viewModel.ProjectsList.Add(currentProject); - return currentProject; - } - - private bool PlatformsIsEquals(string platformName1, string platformName2) - { - if (string.Compare(platformName1, platformName2, StringComparison.InvariantCultureIgnoreCase) == 0) - return true; - - // The ambiguity between Project.ActiveConfiguration.PlatformName and - // ProjectStartedEventArgs.ProjectPlatform in Microsoft.Build.Utilities.Logger - // (see BuildOutputLogger). - bool isAnyCpu1 = (platformName1 == "Any CPU" || platformName1 == "AnyCPU"); - bool isAnyCpu2 = (platformName2 == "Any CPU" || platformName2 == "AnyCPU"); - if (isAnyCpu1 && isAnyCpu2) - return true; - - return false; - } - - public ProjectItem GetCurrentProject(IBuildVisionPaneViewModel viewModel, BuildScopes? buildScope, string project, string projectconfig, string platform) - { - ProjectItem currentProject; - if (buildScope == BuildScopes.BuildScopeBatch) - { - currentProject = FindProjectItemInProjectsByUniqueName(viewModel, project, projectconfig, platform); - if (currentProject == null) - throw new InvalidOperationException(); - } - else - { - currentProject = FindProjectItemInProjectsByUniqueName(viewModel, project); - if (currentProject == null) - throw new InvalidOperationException(); - } - - return currentProject; - } - - public bool GetProjectItem(IBuildVisionPaneViewModel viewModel, BuildScopes? buildScope, BuildProjectContextEntry projectEntry, out ProjectItem projectItem) - { - projectItem = projectEntry.ProjectItem; - if (projectItem != null) - return true; - - string projectFile = projectEntry.FileName; - if (ProjectExtensions.IsProjectHidden(projectFile)) - return false; - - var projectProperties = projectEntry.Properties; - var project = viewModel.ProjectsList.FirstOrDefault(x => x.FullName == projectFile); - - - if (buildScope == BuildScopes.BuildScopeBatch && projectProperties.ContainsKey("Configuration") && projectProperties.ContainsKey("Platform")) - { - string projectConfiguration = projectProperties["Configuration"]; - string projectPlatform = projectProperties["Platform"]; - projectItem = FindProjectItemInProjectsByUniqueName(viewModel, project.UniqueName, projectConfiguration, projectPlatform); - if (projectItem == null) - { - TraceManager.Trace( - string.Format("Project Item not found by: UniqueName='{0}', Configuration='{1}, Platform='{2}'.", - project.UniqueName, - projectConfiguration, - projectPlatform), - EventLogEntryType.Warning); - return false; - } - } - else - { - projectItem = FindProjectItemInProjectsByUniqueName(viewModel, project.UniqueName); - if (projectItem == null) - { - TraceManager.Trace(string.Format("Project Item not found by FullName='{0}'.", projectFile), EventLogEntryType.Warning); - return false; - } - } - - projectEntry.ProjectItem = projectItem; - return true; - } - } -} diff --git a/test/BuildVision.IntegrationTests/PackageTests.cs b/test/BuildVision.IntegrationTests/PackageTests.cs index 737dbb11..f2316feb 100644 --- a/test/BuildVision.IntegrationTests/PackageTests.cs +++ b/test/BuildVision.IntegrationTests/PackageTests.cs @@ -18,7 +18,7 @@ public class PackageTests private static IVsUIShell UiShellService => GlobalServices.GetService() as IVsUIShell; private static DTE DTE => GlobalServices.GetService() as DTE; - [VsixFact(VisualStudioVersion.Current, RootSuffix = "Exp")] + [VsixFact("15.0", RootSuffix = "Exp")] public void PackageLoad_Should_Succeed() { IVsPackage package; @@ -29,7 +29,7 @@ public void PackageLoad_Should_Succeed() Assert.NotNull(package); } - [VsixFact(VisualStudioVersion.Current, RootSuffix = "Exp")] + [VsixFact("15.0", RootSuffix = "Exp")] public void ClickOnBuildVisionMenuItem_Should_ShowBuildVision() { var toolwndCommandId = new CommandID(PackageGuids.GuidBuildVisionCmdSet, (int) PackageIds.CmdIdBuildVisionToolWindow); From 83b9de1d6679629d25185f239a741ad998720751 Mon Sep 17 00:00:00 2001 From: Stefan Kert Date: Sat, 9 Mar 2019 13:21:36 +0100 Subject: [PATCH 010/100] Introducing several services --- .../BuildVision.Contracts.csproj | 2 + .../Enums/BuildActions.cs | 3 +- .../Enums/BuildScopes.cs | 3 +- src/BuildVision.Contracts/Enums/BuildState.cs | 3 +- .../Models/IBuildInformationModel.cs | 24 ++ .../Models/ISolutionModel.cs | 10 + .../BuildVision.Exports.csproj | 4 + .../Providers/IBuildInformationProvider.cs | 13 + .../DisplayStringAttribute.cs | 0 .../GridColumnAttribute.cs | 0 src/BuildVision.UI/BuildVision.UI.csproj | 41 ++- .../Components/ControlHeader.xaml | 4 +- .../Components/ControlView.xaml | 4 +- .../BuildExtraMessageFormat.cs | 0 .../BuildMajorMessageFormat.cs | 0 .../NavigateToBuildFailureReasonCondition.cs | 0 .../ResetTaskBarItemInfoCondition.cs | 0 .../{Helpers => Enums}/SortOrder.cs | 0 .../{Helpers => Enums}/WindowState.cs | 0 src/BuildVision.UI/Helpers/BindingProxy.cs | 2 +- ...ildMessages.cs => BuildMessagesFactory.cs} | 60 ++-- .../Models/BaseGridColumnSettings.cs | 31 -- .../Models/BuildInformationModel.cs | 154 +++++++++ .../Models/BuildProgressSettings.cs | 14 - src/BuildVision.UI/Models/GridSettings.cs | 94 ------ .../{SolutionItem.cs => SolutionModel.cs} | 27 +- src/BuildVision.UI/Models/WindowSettings.cs | 22 -- .../Settings/Models/BaseGridColumnSettings.cs | 31 ++ .../Models/BuildMessagesSettings.cs | 0 .../Settings/Models/BuildProgressSettings.cs | 14 + .../{ => Settings}/Models/ControlSettings.cs | 0 .../{ => Settings}/Models/GeneralSettings.cs | 2 +- .../Models/GridColumnSettings.cs | 14 +- .../Settings/Models/GridSettings.cs | 94 ++++++ .../Models/ProjectItemSettings.cs | 2 +- .../Settings/Models/WindowSettings.cs | 22 ++ .../ViewModels/BuildVisionPaneViewModel.cs | 9 +- .../ViewModels/SolutionModel.cs | 93 ------ .../ViewModels/VisualStudioSolution.cs | 101 ------ src/BuildVision/BuildVision.csproj | 7 +- src/BuildVision/Core/BuildVisionPackage.cs | 34 +- .../Core/ServiceProviderPackage.cs | 34 ++ src/BuildVision/Core/SolutionBuildEvents.cs | 300 ++---------------- .../Services/BuildInformationProvider.cs | 127 ++++++++ .../Services/BuildingProjectsProvider.cs | 246 ++++++++++++++ .../Services/IBuildingProjectsProvider.cs | 14 + src/BuildVision/Services/ISolutionProvider.cs | 13 + src/BuildVision/Services/SolutionProvider.cs | 97 ++++++ .../StatusBarNotificationService.cs | 0 49 files changed, 1032 insertions(+), 737 deletions(-) create mode 100644 src/BuildVision.Contracts/Models/IBuildInformationModel.cs create mode 100644 src/BuildVision.Contracts/Models/ISolutionModel.cs create mode 100644 src/BuildVision.Exports/Providers/IBuildInformationProvider.cs rename src/BuildVision.UI/{Helpers => Attributes}/DisplayStringAttribute.cs (100%) rename src/BuildVision.UI/{Models => Attributes}/GridColumnAttribute.cs (100%) rename src/BuildVision.UI/{Models => Enums}/BuildExtraMessageFormat.cs (100%) rename src/BuildVision.UI/{Models => Enums}/BuildMajorMessageFormat.cs (100%) rename src/BuildVision.UI/{Models => Enums}/NavigateToBuildFailureReasonCondition.cs (100%) rename src/BuildVision.UI/{Helpers => Enums}/ResetTaskBarItemInfoCondition.cs (100%) rename src/BuildVision.UI/{Helpers => Enums}/SortOrder.cs (100%) rename src/BuildVision.UI/{Helpers => Enums}/WindowState.cs (100%) rename src/BuildVision.UI/Helpers/{BuildMessages.cs => BuildMessagesFactory.cs} (75%) delete mode 100644 src/BuildVision.UI/Models/BaseGridColumnSettings.cs create mode 100644 src/BuildVision.UI/Models/BuildInformationModel.cs delete mode 100644 src/BuildVision.UI/Models/BuildProgressSettings.cs delete mode 100644 src/BuildVision.UI/Models/GridSettings.cs rename src/BuildVision.UI/Models/{SolutionItem.cs => SolutionModel.cs} (56%) delete mode 100644 src/BuildVision.UI/Models/WindowSettings.cs create mode 100644 src/BuildVision.UI/Settings/Models/BaseGridColumnSettings.cs rename src/BuildVision.UI/{ => Settings}/Models/BuildMessagesSettings.cs (100%) create mode 100644 src/BuildVision.UI/Settings/Models/BuildProgressSettings.cs rename src/BuildVision.UI/{ => Settings}/Models/ControlSettings.cs (100%) rename src/BuildVision.UI/{ => Settings}/Models/GeneralSettings.cs (99%) rename src/BuildVision.UI/{ => Settings}/Models/GridColumnSettings.cs (83%) create mode 100644 src/BuildVision.UI/Settings/Models/GridSettings.cs rename src/BuildVision.UI/{ => Settings}/Models/ProjectItemSettings.cs (98%) create mode 100644 src/BuildVision.UI/Settings/Models/WindowSettings.cs delete mode 100644 src/BuildVision.UI/ViewModels/SolutionModel.cs delete mode 100644 src/BuildVision.UI/ViewModels/VisualStudioSolution.cs create mode 100644 src/BuildVision/Services/BuildInformationProvider.cs create mode 100644 src/BuildVision/Services/BuildingProjectsProvider.cs create mode 100644 src/BuildVision/Services/IBuildingProjectsProvider.cs create mode 100644 src/BuildVision/Services/ISolutionProvider.cs create mode 100644 src/BuildVision/Services/SolutionProvider.cs rename src/BuildVision/{Core => Services}/StatusBarNotificationService.cs (100%) diff --git a/src/BuildVision.Contracts/BuildVision.Contracts.csproj b/src/BuildVision.Contracts/BuildVision.Contracts.csproj index 37f38f4b..e1ae6667 100644 --- a/src/BuildVision.Contracts/BuildVision.Contracts.csproj +++ b/src/BuildVision.Contracts/BuildVision.Contracts.csproj @@ -61,6 +61,8 @@ + + diff --git a/src/BuildVision.Contracts/Enums/BuildActions.cs b/src/BuildVision.Contracts/Enums/BuildActions.cs index 943ab442..61ef61be 100644 --- a/src/BuildVision.Contracts/Enums/BuildActions.cs +++ b/src/BuildVision.Contracts/Enums/BuildActions.cs @@ -11,6 +11,7 @@ public enum BuildActions BuildActionBuild = 1, BuildActionRebuildAll = 2, BuildActionClean = 3, - BuildActionDeploy = 4 + BuildActionDeploy = 4, + Unknown = 5 } } diff --git a/src/BuildVision.Contracts/Enums/BuildScopes.cs b/src/BuildVision.Contracts/Enums/BuildScopes.cs index 304f2bc8..416b1f00 100644 --- a/src/BuildVision.Contracts/Enums/BuildScopes.cs +++ b/src/BuildVision.Contracts/Enums/BuildScopes.cs @@ -4,6 +4,7 @@ public enum BuildScopes { BuildScopeSolution = 1, BuildScopeBatch = 2, - BuildScopeProject = 3 + BuildScopeProject = 3, + Unknown = 4 } } diff --git a/src/BuildVision.Contracts/Enums/BuildState.cs b/src/BuildVision.Contracts/Enums/BuildState.cs index 9d58869c..5d1e91d7 100644 --- a/src/BuildVision.Contracts/Enums/BuildState.cs +++ b/src/BuildVision.Contracts/Enums/BuildState.cs @@ -5,6 +5,7 @@ public enum BuildState NotStarted = 0, InProgress = 1, Done = 2, - Cancelled = 3 + Cancelled = 3, + Failed = 4 } } diff --git a/src/BuildVision.Contracts/Models/IBuildInformationModel.cs b/src/BuildVision.Contracts/Models/IBuildInformationModel.cs new file mode 100644 index 00000000..fbe28403 --- /dev/null +++ b/src/BuildVision.Contracts/Models/IBuildInformationModel.cs @@ -0,0 +1,24 @@ +using System; + +namespace BuildVision.Contracts.Models +{ + public interface IBuildInformationModel + { + BuildActions BuildAction { get; set; } + DateTime? BuildFinishTime { get; set; } + BuildScopes BuildScope { get; set; } + DateTime? BuildStartTime { get; set; } + BuildState CurrentBuildState { get; set; } + int ErrorCount { get; set; } + int FailedProjectsCount { get; set; } + int MessagesCount { get; set; } + BuildResultState ResultState { get; } + string StateMessage { get; set; } + int SucceededProjectsCount { get; set; } + int UpToDateProjectsCount { get; set; } + int WarnedProjectsCount { get; set; } + int WarningsCount { get; set; } + + BuildResultState GetBuildState(); + } +} diff --git a/src/BuildVision.Contracts/Models/ISolutionModel.cs b/src/BuildVision.Contracts/Models/ISolutionModel.cs new file mode 100644 index 00000000..3eb65d4d --- /dev/null +++ b/src/BuildVision.Contracts/Models/ISolutionModel.cs @@ -0,0 +1,10 @@ +namespace BuildVision.Contracts.Models +{ + public interface ISolutionModel + { + string FileName { get; set; } + string FullName { get; set; } + bool IsEmpty { get; set; } + string Name { get; set; } + } +} diff --git a/src/BuildVision.Exports/BuildVision.Exports.csproj b/src/BuildVision.Exports/BuildVision.Exports.csproj index 2095a5ba..bf5367fa 100644 --- a/src/BuildVision.Exports/BuildVision.Exports.csproj +++ b/src/BuildVision.Exports/BuildVision.Exports.csproj @@ -6,4 +6,8 @@ Key.snk + + + + diff --git a/src/BuildVision.Exports/Providers/IBuildInformationProvider.cs b/src/BuildVision.Exports/Providers/IBuildInformationProvider.cs new file mode 100644 index 00000000..0210b8c0 --- /dev/null +++ b/src/BuildVision.Exports/Providers/IBuildInformationProvider.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using BuildVision.Contracts.Models; + +namespace BuildVision.Exports.Providers +{ + public interface IBuildInformationProvider + { + void BuildFinished(bool success, bool modified, bool canceled); + void BuildStarted(uint dwAction); + void BuildUpdate(); + IBuildInformationModel GetBuildInformationModel(); + } +} diff --git a/src/BuildVision.UI/Helpers/DisplayStringAttribute.cs b/src/BuildVision.UI/Attributes/DisplayStringAttribute.cs similarity index 100% rename from src/BuildVision.UI/Helpers/DisplayStringAttribute.cs rename to src/BuildVision.UI/Attributes/DisplayStringAttribute.cs diff --git a/src/BuildVision.UI/Models/GridColumnAttribute.cs b/src/BuildVision.UI/Attributes/GridColumnAttribute.cs similarity index 100% rename from src/BuildVision.UI/Models/GridColumnAttribute.cs rename to src/BuildVision.UI/Attributes/GridColumnAttribute.cs diff --git a/src/BuildVision.UI/BuildVision.UI.csproj b/src/BuildVision.UI/BuildVision.UI.csproj index 12b18850..a69c589f 100644 --- a/src/BuildVision.UI/BuildVision.UI.csproj +++ b/src/BuildVision.UI/BuildVision.UI.csproj @@ -73,15 +73,15 @@ App.xaml Code - + - - + + - - - + + + @@ -92,13 +92,13 @@ - - - + + + - + - + ControlView.xaml @@ -115,7 +115,7 @@ - + @@ -123,13 +123,12 @@ - - - - + + + + - - + Resources.resx True @@ -153,11 +152,11 @@ WindowSettingsControl.xaml - + + - - + diff --git a/src/BuildVision.UI/Components/ControlHeader.xaml b/src/BuildVision.UI/Components/ControlHeader.xaml index bde829d0..c12648b8 100644 --- a/src/BuildVision.UI/Components/ControlHeader.xaml +++ b/src/BuildVision.UI/Components/ControlHeader.xaml @@ -4,8 +4,8 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" mc:Ignorable="d" - xmlns:dvm="clr-namespace:BuildVision.UI.ViewModels" - d:DataContext ="{d:DesignInstance {x:Type dvm:BuildMetaInformationsViewModel}, IsDesignTimeCreatable=True}" + xmlns:dvm="clr-namespace:BuildVision.Contracts.Models" + d:DataContext ="{d:DesignInstance {x:Type dvm:IBuildInformationModel}, IsDesignTimeCreatable=True}" d:DesignWidth="697" xmlns:res="clr-namespace:BuildVision.UI" xmlns:extensions1="clr-namespace:BuildVision.UI.Extensions" diff --git a/src/BuildVision.UI/Components/ControlView.xaml b/src/BuildVision.UI/Components/ControlView.xaml index 17759e95..04cf0d81 100644 --- a/src/BuildVision.UI/Components/ControlView.xaml +++ b/src/BuildVision.UI/Components/ControlView.xaml @@ -101,7 +101,7 @@ - @@ -345,4 +345,4 @@ - \ No newline at end of file + diff --git a/src/BuildVision.UI/Models/BuildExtraMessageFormat.cs b/src/BuildVision.UI/Enums/BuildExtraMessageFormat.cs similarity index 100% rename from src/BuildVision.UI/Models/BuildExtraMessageFormat.cs rename to src/BuildVision.UI/Enums/BuildExtraMessageFormat.cs diff --git a/src/BuildVision.UI/Models/BuildMajorMessageFormat.cs b/src/BuildVision.UI/Enums/BuildMajorMessageFormat.cs similarity index 100% rename from src/BuildVision.UI/Models/BuildMajorMessageFormat.cs rename to src/BuildVision.UI/Enums/BuildMajorMessageFormat.cs diff --git a/src/BuildVision.UI/Models/NavigateToBuildFailureReasonCondition.cs b/src/BuildVision.UI/Enums/NavigateToBuildFailureReasonCondition.cs similarity index 100% rename from src/BuildVision.UI/Models/NavigateToBuildFailureReasonCondition.cs rename to src/BuildVision.UI/Enums/NavigateToBuildFailureReasonCondition.cs diff --git a/src/BuildVision.UI/Helpers/ResetTaskBarItemInfoCondition.cs b/src/BuildVision.UI/Enums/ResetTaskBarItemInfoCondition.cs similarity index 100% rename from src/BuildVision.UI/Helpers/ResetTaskBarItemInfoCondition.cs rename to src/BuildVision.UI/Enums/ResetTaskBarItemInfoCondition.cs diff --git a/src/BuildVision.UI/Helpers/SortOrder.cs b/src/BuildVision.UI/Enums/SortOrder.cs similarity index 100% rename from src/BuildVision.UI/Helpers/SortOrder.cs rename to src/BuildVision.UI/Enums/SortOrder.cs diff --git a/src/BuildVision.UI/Helpers/WindowState.cs b/src/BuildVision.UI/Enums/WindowState.cs similarity index 100% rename from src/BuildVision.UI/Helpers/WindowState.cs rename to src/BuildVision.UI/Enums/WindowState.cs diff --git a/src/BuildVision.UI/Helpers/BindingProxy.cs b/src/BuildVision.UI/Helpers/BindingProxy.cs index 53e57663..652e08e8 100644 --- a/src/BuildVision.UI/Helpers/BindingProxy.cs +++ b/src/BuildVision.UI/Helpers/BindingProxy.cs @@ -15,7 +15,7 @@ protected override Freezable CreateInstanceCore() public object Data { - get { return (object)GetValue(DataProperty); } + get { return (object) GetValue(DataProperty); } set { SetValue(DataProperty, value); } } diff --git a/src/BuildVision.UI/Helpers/BuildMessages.cs b/src/BuildVision.UI/Helpers/BuildMessagesFactory.cs similarity index 75% rename from src/BuildVision.UI/Helpers/BuildMessages.cs rename to src/BuildVision.UI/Helpers/BuildMessagesFactory.cs index d5311c14..ca2e5b4e 100644 --- a/src/BuildVision.UI/Helpers/BuildMessages.cs +++ b/src/BuildVision.UI/Helpers/BuildMessagesFactory.cs @@ -16,20 +16,20 @@ public BuildMessagesFactory(BuildMessagesSettings labelsSettings) _labelSettings = labelsSettings; } - public string GetBuildBeginMajorMessage(VisualStudioSolution solutionItem) + public string GetBuildBeginMajorMessage(SolutionModel solutionItem, BuildInformationModel buildInformationModel) { - var mainString = GetMainString(solutionItem); + var mainString = GetMainString(solutionItem, buildInformationModel); return string.Format(_labelSettings.BuildBeginMajorMessageStringFormat, mainString); } - private string GetMainString(VisualStudioSolution solutionItem) + private string GetMainString(SolutionModel solutionItem, BuildInformationModel buildInformationModel) { var buildAction = BuildActions.BuildActionBuild; //TOdo replace - var unitName = GetUnitName(solutionItem); - var actionName = GetActionName(solutionItem.BuildAction); - var beginAtString = GetBeginAtString(solutionItem.BuildAction); - var timeString = GetTimeString(solutionItem); + var unitName = GetUnitName(solutionItem, buildInformationModel); + var actionName = GetActionName(buildInformationModel.BuildAction); + var beginAtString = GetBeginAtString(buildInformationModel.BuildAction); + var timeString = GetTimeString(solutionItem, buildInformationModel); string mainString; switch (_labelSettings.MajorMessageFormat) { @@ -48,12 +48,12 @@ private string GetMainString(VisualStudioSolution solutionItem) return mainString; } - private string GetTimeString(VisualStudioSolution solution) + private string GetTimeString(SolutionModel solution, BuildInformationModel buildInformationModel) { string timeString = ""; try { - timeString = solution.BuildStartTime.Value.ToString(_labelSettings.DateTimeFormat); + timeString = buildInformationModel.BuildStartTime.Value.ToString(_labelSettings.DateTimeFormat); } catch (FormatException) { @@ -97,10 +97,10 @@ private string GetActionName(BuildActions buildAction) } } - private string GetUnitName(VisualStudioSolution solutionItem) + private string GetUnitName(SolutionModel solutionItem, BuildInformationModel buildInformationModel) { string unitName = ""; - switch (solutionItem.BuildScope) + switch (buildInformationModel.BuildScope) { case BuildScopes.BuildScopeSolution: unitName = Resources.BuildScopeSolution_UnitName; @@ -118,20 +118,20 @@ private string GetUnitName(VisualStudioSolution solutionItem) break; default: - throw new ArgumentOutOfRangeException(nameof(solutionItem.BuildScope)); + throw new ArgumentOutOfRangeException(nameof(buildInformationModel.BuildScope)); } return unitName; } - public string GetBuildBeginExtraMessage(VisualStudioSolution solutionItem) + public string GetBuildBeginExtraMessage(SolutionModel solutionItem, BuildInformationModel buildInformationModel) { - if (solutionItem.BuildStartTime == null || !_labelSettings.ShowExtraMessage || _labelSettings.ExtraMessageDelay < 0) + if (buildInformationModel.BuildStartTime == null || !_labelSettings.ShowExtraMessage || _labelSettings.ExtraMessageDelay < 0) { return string.Empty; } - TimeSpan timeSpan = DateTime.Now.Subtract(solutionItem.BuildStartTime.Value); + TimeSpan timeSpan = DateTime.Now.Subtract(buildInformationModel.BuildStartTime.Value); if (timeSpan.TotalSeconds > _labelSettings.ExtraMessageDelay) { return GetExtraTimePartString( timeSpan); @@ -140,23 +140,23 @@ public string GetBuildBeginExtraMessage(VisualStudioSolution solutionItem) return string.Empty; } - public string GetBuildDoneMessage(VisualStudioSolution solutionItem) + public string GetBuildDoneMessage(SolutionModel solutionItem, BuildInformationModel buildInformationModel) { - return GetBuildDoneMajorMessage(solutionItem) + GetBuildDoneExtraMessage(solutionItem); + return GetBuildDoneMajorMessage(solutionItem, buildInformationModel) + GetBuildDoneExtraMessage(solutionItem, buildInformationModel); } - private string GetBuildDoneMajorMessage(VisualStudioSolution solutionItem) + private string GetBuildDoneMajorMessage(SolutionModel solutionItem, BuildInformationModel buildInformationModel) { - var buildAction = solutionItem.BuildAction; - var buildScope = solutionItem.BuildScope; + var buildAction = buildInformationModel.BuildAction; + var buildScope = buildInformationModel.BuildScope; - if (solutionItem.BuildFinishTime == null) + if (buildInformationModel.BuildFinishTime == null) throw new InvalidOperationException(); string timeString; try { - timeString = solutionItem.BuildFinishTime.Value.ToString(_labelSettings.DateTimeFormat); + timeString = buildInformationModel.BuildFinishTime.Value.ToString(_labelSettings.DateTimeFormat); } catch (FormatException) { @@ -181,9 +181,9 @@ private string GetBuildDoneMajorMessage(VisualStudioSolution solutionItem) if (_labelSettings.ShowProjectName) { // Todo this is probably wrong. maybe we should go the extra mile and check which projects are selected? - var uniqProjName = solutionItem.Projects.LastOrDefault(x => x.State == ProjectState.BuildDone)?.UniqueName; - var projItem = solutionItem.Projects.FirstOrDefault(item => item.UniqueName == uniqProjName); - unitName += string.Format(Resources.BuildScopeProject_ProjectNameTemplate, projItem.Name); + //var uniqProjName = solutionItem.Projects.LastOrDefault(x => x.State == ProjectState.BuildDone)?.UniqueName; + //var projItem = solutionItem.Projects.FirstOrDefault(item => item.UniqueName == uniqProjName); + //unitName += string.Format(Resources.BuildScopeProject_ProjectNameTemplate, projItem.Name); } break; @@ -191,8 +191,8 @@ private string GetBuildDoneMajorMessage(VisualStudioSolution solutionItem) throw new ArgumentOutOfRangeException(nameof(buildScope)); } - var actionName = GetActionName(solutionItem.BuildAction); - var resultName = GetResultName(solutionItem.ResultState); + var actionName = GetActionName(buildInformationModel.BuildAction); + var resultName = GetResultName(buildInformationModel.ResultState); string mainString; switch (_labelSettings.MajorMessageFormat) @@ -239,12 +239,12 @@ private string GetResultName(BuildResultState resultState) } } - private string GetBuildDoneExtraMessage(VisualStudioSolution solutionItem) + private string GetBuildDoneExtraMessage(SolutionModel solutionItem, BuildInformationModel buildInformationModel) { - if (solutionItem.BuildStartTime == null || solutionItem.BuildFinishTime == null || !_labelSettings.ShowExtraMessage) + if (buildInformationModel.BuildStartTime == null || buildInformationModel.BuildFinishTime == null || !_labelSettings.ShowExtraMessage) return string.Empty; - TimeSpan timeSpan = solutionItem.BuildFinishTime.Value.Subtract(solutionItem.BuildStartTime.Value); + TimeSpan timeSpan = buildInformationModel.BuildFinishTime.Value.Subtract(buildInformationModel.BuildStartTime.Value); string extraTimePartString = GetExtraTimePartString(timeSpan); return string.Format(_labelSettings.ExtraMessageStringFormat, extraTimePartString); } diff --git a/src/BuildVision.UI/Models/BaseGridColumnSettings.cs b/src/BuildVision.UI/Models/BaseGridColumnSettings.cs deleted file mode 100644 index 81e58925..00000000 --- a/src/BuildVision.UI/Models/BaseGridColumnSettings.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; -using System.Runtime.Serialization; - -namespace BuildVision.Contracts -{ - public abstract class BaseGridColumnSettingsAttribute : Attribute - { - public string Header { get; set; } - - public bool Visible { get; set; } - - /// - /// -1 for auto. - /// - public int DisplayIndex { get; set; } - - /// - /// double.NaN for auto. - /// - public double Width { get; set; } - - public string ValueStringFormat { get; set; } - - protected BaseGridColumnSettingsAttribute() - { - Width = double.NaN; - DisplayIndex = -1; - Visible = true; - } - } -} diff --git a/src/BuildVision.UI/Models/BuildInformationModel.cs b/src/BuildVision.UI/Models/BuildInformationModel.cs new file mode 100644 index 00000000..7a1967b1 --- /dev/null +++ b/src/BuildVision.UI/Models/BuildInformationModel.cs @@ -0,0 +1,154 @@ +using System; +using BuildVision.Common; +using BuildVision.Contracts; +using BuildVision.Contracts.Models; + +namespace BuildVision.Core +{ + public class BuildInformationModel : BindableBase, IBuildInformationModel + { + private int _errorCount = -1; + public int ErrorCount + { + get => _errorCount; + set => SetProperty(ref _errorCount, value); + } + + private int _warningsCount = -1; + public int WarningsCount + { + get => _warningsCount; + set => SetProperty(ref _warningsCount, value); + } + + private int _messagesCount = -1; + public int MessagesCount + { + get => _messagesCount; + set => SetProperty(ref _messagesCount, value); + } + + private int _succeededProjectsCount = -1; + public int SucceededProjectsCount + { + get => _warningsCount; + set => SetProperty(ref _succeededProjectsCount, value); + } + + private int _upToDateProjectsCount = -1; + public int UpToDateProjectsCount + { + get => _warningsCount; + set => SetProperty(ref _upToDateProjectsCount, value); + } + + private int _failedProjectsCount = -1; + public int FailedProjectsCount + { + get => _warningsCount; + set => SetProperty(ref _failedProjectsCount, value); + } + + private int _warnedProjectsCount = -1; + public int WarnedProjectsCount + { + get => _warningsCount; + set => SetProperty(ref _warnedProjectsCount, value); + } + + private string _stateMessage = ""; + public string StateMessage + { + get => _stateMessage; + set => SetProperty(ref _stateMessage, value); + } + + private BuildState _currentBuildState = BuildState.NotStarted; + public BuildState CurrentBuildState + { + get => _currentBuildState; + set => SetProperty(ref _currentBuildState, value); + } + + public BuildResultState ResultState => GetBuildState(); + + private BuildActions _buildAction = BuildActions.Unknown; + public BuildActions BuildAction + { + get => _buildAction; + set => SetProperty(ref _buildAction, value); + } + + private BuildScopes _buildScope = BuildScopes.Unknown; + public BuildScopes BuildScope + { + get => _buildScope; + set => SetProperty(ref _buildScope, value); + } + + private DateTime? _buildStartTime; + public DateTime? BuildStartTime + { + get => _buildStartTime; + set => SetProperty(ref _buildStartTime, value); + } + + private DateTime? _buildFinishTime; + public DateTime? BuildFinishTime + { + get => _buildFinishTime; + set => SetProperty(ref _buildFinishTime, value); + } + + public BuildResultState GetBuildState() + { + if (CurrentBuildState == BuildState.InProgress) + { + return BuildResultState.Unknown; + } + else if (CurrentBuildState == BuildState.Done) + { + //TODO Decied what happened + if (BuildAction == BuildActions.BuildActionRebuildAll) + return BuildResultState.RebuildCancelled; + if (BuildAction == BuildActions.BuildActionClean) + return BuildResultState.CleanCancelled; + if (BuildAction == BuildActions.BuildActionBuild) + return BuildResultState.BuildCancelled; + else + return BuildResultState.Unknown; + + if (BuildAction == BuildActions.BuildActionRebuildAll) + return BuildResultState.RebuildFailed; + if (BuildAction == BuildActions.BuildActionClean) + return BuildResultState.CleanFailed; + if (BuildAction == BuildActions.BuildActionBuild) + return BuildResultState.BuildFailed; + else + return BuildResultState.Unknown; + + if (BuildAction == BuildActions.BuildActionRebuildAll) + return BuildResultState.RebuildSucceeded; + if (BuildAction == BuildActions.BuildActionClean) + return BuildResultState.CleanSucceeded; + if (BuildAction == BuildActions.BuildActionBuild) + return BuildResultState.BuildSucceeded; + else + return BuildResultState.Unknown; + + if (BuildAction == BuildActions.BuildActionRebuildAll) + return BuildResultState.RebuildSucceededWithErrors; + if (BuildAction == BuildActions.BuildActionClean) + return BuildResultState.CleanSucceededWithErrors; + if (BuildAction == BuildActions.BuildActionBuild) + return BuildResultState.BuildSucceededWithErrors; + else + return BuildResultState.Unknown; + } + else + { + return BuildResultState.Unknown; + } + } + } +} diff --git a/src/BuildVision.UI/Models/BuildProgressSettings.cs b/src/BuildVision.UI/Models/BuildProgressSettings.cs deleted file mode 100644 index f0b5c17c..00000000 --- a/src/BuildVision.UI/Models/BuildProgressSettings.cs +++ /dev/null @@ -1,14 +0,0 @@ -using BuildVision.UI.Models; -using System.Runtime.Serialization; - -namespace BuildVision.UI.Settings.Models.BuildProgress -{ - public class BuildProgressSettings - { - public bool TaskBarProgressEnabled { get; set; } - - public ResetTaskBarItemInfoCondition ResetTaskBarProgressAfterBuildDone { get; set; } = ResetTaskBarItemInfoCondition.ByMouseClick; - - public int ResetTaskBarProgressDelay { get; set; } = 5000; - } -} \ No newline at end of file diff --git a/src/BuildVision.UI/Models/GridSettings.cs b/src/BuildVision.UI/Models/GridSettings.cs deleted file mode 100644 index 8ad52998..00000000 --- a/src/BuildVision.UI/Models/GridSettings.cs +++ /dev/null @@ -1,94 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using BuildVision.Common; -using BuildVision.UI.DataGrid; -using BuildVision.UI.Settings.Models.Columns; -using BuildVision.UI.Models; -using BuildVision.UI.Settings.Models.Sorting; - -namespace BuildVision.UI.Settings.Models -{ - public class GridSettings : SettingsBase - { - private GridColumnSettingsCollection _columns; - - private string _groupName; - - private string _groupHeaderFormat; - - private SortDescription _sort; - - private List _collapsedGroups; - - private static string[] _groupHeaderFormatArgs; - - public GridColumnSettingsCollection Columns => _columns ?? (_columns = new GridColumnSettingsCollection()); - - public IEnumerable SortableColumnsUIList - { - get - { - yield return GridColumnSettings.Empty; - foreach (GridColumnSettings column in Columns.Where(x => ColumnsManager.ColumnIsSortable(x.PropertyNameId))) - yield return column; - } - } - - public IEnumerable GroupableColumnsUIList - { - get - { - yield return GridColumnSettings.Empty; - foreach (GridColumnSettings column in Columns.Where(ColumnsManager.ColumnIsGroupable)) - yield return column; - } - } - - public string GroupName - { - get => _groupName ?? (_groupName = string.Empty); - set => _groupName = value; - } - - /// - /// User-friendly header format for groups. - /// For example, "{title}: {value} - {count} items". - /// Available arguments see in . - /// - public string GroupHeaderFormat - { - get => _groupHeaderFormat ?? (_groupHeaderFormat = "{title}: {value}"); - set => _groupHeaderFormat = value; - } - - public string GroupHeaderRawFormat => ConvertGroupHeaderToRawFormat(GroupHeaderFormat); - - public static string[] GroupHeaderFormatArgs => _groupHeaderFormatArgs ?? (_groupHeaderFormatArgs = new[] { "title", "value", "count" }); - - public bool ShowColumnsHeader { get; set; } = true; - - public SortDescription Sort - { - get => _sort ?? (_sort = new SortDescription(SortOrder.Ascending, "BuildOrder")); - set => _sort = value; - } - - public List CollapsedGroups => _collapsedGroups ?? (_collapsedGroups = new List()); - - /// - /// Converts user-friendly string format with arguments - /// into system format string (with {0},{1},... arguments). - /// - private static string ConvertGroupHeaderToRawFormat(string userFriendlyFormatString) - { - if (string.IsNullOrEmpty(userFriendlyFormatString)) - return string.Empty; - - string rawFormat = userFriendlyFormatString; - for (int i = 0; i < GroupHeaderFormatArgs.Length; i++) - rawFormat = rawFormat.Replace("{" + GroupHeaderFormatArgs[i], "{" + i); - - return rawFormat; - } - } -} \ No newline at end of file diff --git a/src/BuildVision.UI/Models/SolutionItem.cs b/src/BuildVision.UI/Models/SolutionModel.cs similarity index 56% rename from src/BuildVision.UI/Models/SolutionItem.cs rename to src/BuildVision.UI/Models/SolutionModel.cs index b1d65eaa..a03e5203 100644 --- a/src/BuildVision.UI/Models/SolutionItem.cs +++ b/src/BuildVision.UI/Models/SolutionModel.cs @@ -1,12 +1,17 @@ using BuildVision.Common; -using System.Collections.Generic; -using System.Collections.ObjectModel; +using BuildVision.Contracts.Models; - -namespace BuildVision.UI.Models +namespace BuildVision.Core { - public class SolutionItem : BindableBase + public class SolutionModel : BindableBase, ISolutionModel { + private string _fileName; + public string FileName + { + get => _fileName; + set => SetProperty(ref _fileName, value); + } + private string _name; public string Name { @@ -27,15 +32,5 @@ public bool IsEmpty get => _isEmpty; set => SetProperty(ref _isEmpty, value); } - - public ObservableCollection Projects { get; } - - public List AllProjects { get; } - - public SolutionItem() - { - Projects = new ObservableRangeCollection(); - AllProjects = new List(); - } } -} \ No newline at end of file +} diff --git a/src/BuildVision.UI/Models/WindowSettings.cs b/src/BuildVision.UI/Models/WindowSettings.cs deleted file mode 100644 index d23a0da9..00000000 --- a/src/BuildVision.UI/Models/WindowSettings.cs +++ /dev/null @@ -1,22 +0,0 @@ -using BuildVision.Common; -using BuildVision.UI.Models; -using BuildVision.UI.Settings.Models.ToolWindow; - -namespace BuildVision.UI.Settings.Models -{ - public class WindowSettings : SettingsBase - { - public WindowStateAction WindowActionOnBuildBegin { get; set; } - - public WindowStateAction WindowActionOnBuildSuccess { get; set; } - - public WindowStateAction WindowActionOnBuildError { get; set; } - - public WindowSettings() - { - WindowActionOnBuildBegin = new WindowStateAction(WindowState.Show); - WindowActionOnBuildSuccess = new WindowStateAction(WindowState.Nothing); - WindowActionOnBuildError = new WindowStateAction(WindowState.Show); - } - } -} diff --git a/src/BuildVision.UI/Settings/Models/BaseGridColumnSettings.cs b/src/BuildVision.UI/Settings/Models/BaseGridColumnSettings.cs new file mode 100644 index 00000000..82127fc4 --- /dev/null +++ b/src/BuildVision.UI/Settings/Models/BaseGridColumnSettings.cs @@ -0,0 +1,31 @@ +using System; +using System.Runtime.Serialization; + +namespace BuildVision.Contracts +{ + public abstract class BaseGridColumnSettingsAttribute : Attribute + { + public string Header { get; set; } + + public bool Visible { get; set; } + + /// + /// -1 for auto. + /// + public int DisplayIndex { get; set; } + + /// + /// double.NaN for auto. + /// + public double Width { get; set; } + + public string ValueStringFormat { get; set; } + + protected BaseGridColumnSettingsAttribute() + { + Width = double.NaN; + DisplayIndex = -1; + Visible = true; + } + } +} diff --git a/src/BuildVision.UI/Models/BuildMessagesSettings.cs b/src/BuildVision.UI/Settings/Models/BuildMessagesSettings.cs similarity index 100% rename from src/BuildVision.UI/Models/BuildMessagesSettings.cs rename to src/BuildVision.UI/Settings/Models/BuildMessagesSettings.cs diff --git a/src/BuildVision.UI/Settings/Models/BuildProgressSettings.cs b/src/BuildVision.UI/Settings/Models/BuildProgressSettings.cs new file mode 100644 index 00000000..24032fd3 --- /dev/null +++ b/src/BuildVision.UI/Settings/Models/BuildProgressSettings.cs @@ -0,0 +1,14 @@ +using BuildVision.UI.Models; +using System.Runtime.Serialization; + +namespace BuildVision.UI.Settings.Models.BuildProgress +{ + public class BuildProgressSettings + { + public bool TaskBarProgressEnabled { get; set; } + + public ResetTaskBarItemInfoCondition ResetTaskBarProgressAfterBuildDone { get; set; } = ResetTaskBarItemInfoCondition.ByMouseClick; + + public int ResetTaskBarProgressDelay { get; set; } = 5000; + } +} diff --git a/src/BuildVision.UI/Models/ControlSettings.cs b/src/BuildVision.UI/Settings/Models/ControlSettings.cs similarity index 100% rename from src/BuildVision.UI/Models/ControlSettings.cs rename to src/BuildVision.UI/Settings/Models/ControlSettings.cs diff --git a/src/BuildVision.UI/Models/GeneralSettings.cs b/src/BuildVision.UI/Settings/Models/GeneralSettings.cs similarity index 99% rename from src/BuildVision.UI/Models/GeneralSettings.cs rename to src/BuildVision.UI/Settings/Models/GeneralSettings.cs index a038f01d..9e6e20f8 100644 --- a/src/BuildVision.UI/Models/GeneralSettings.cs +++ b/src/BuildVision.UI/Settings/Models/GeneralSettings.cs @@ -30,4 +30,4 @@ public GeneralSettings() ShowWarningSignForBuilds = true; } } -} \ No newline at end of file +} diff --git a/src/BuildVision.UI/Models/GridColumnSettings.cs b/src/BuildVision.UI/Settings/Models/GridColumnSettings.cs similarity index 83% rename from src/BuildVision.UI/Models/GridColumnSettings.cs rename to src/BuildVision.UI/Settings/Models/GridColumnSettings.cs index d6780355..7171ea9a 100644 --- a/src/BuildVision.UI/Models/GridColumnSettings.cs +++ b/src/BuildVision.UI/Settings/Models/GridColumnSettings.cs @@ -9,7 +9,7 @@ public class GridColumnSettings : BaseGridColumnSettingsAttribute PropertyNameId = string.Empty, Header = Resources.NoneMenuItem }; - + public string PropertyNameId { get; set; } private GridColumnSettings() @@ -17,11 +17,11 @@ private GridColumnSettings() } public GridColumnSettings( - string propertyNameId, - string header, - bool visible, - int displayIndex, - double width, + string propertyNameId, + string header, + bool visible, + int displayIndex, + double width, string valueStringFormat) { PropertyNameId = propertyNameId; @@ -32,4 +32,4 @@ public GridColumnSettings( ValueStringFormat = valueStringFormat; } } -} \ No newline at end of file +} diff --git a/src/BuildVision.UI/Settings/Models/GridSettings.cs b/src/BuildVision.UI/Settings/Models/GridSettings.cs new file mode 100644 index 00000000..c695fb06 --- /dev/null +++ b/src/BuildVision.UI/Settings/Models/GridSettings.cs @@ -0,0 +1,94 @@ +using System.Collections.Generic; +using System.Linq; +using BuildVision.Common; +using BuildVision.UI.DataGrid; +using BuildVision.UI.Settings.Models.Columns; +using BuildVision.UI.Models; +using BuildVision.UI.Settings.Models.Sorting; + +namespace BuildVision.UI.Settings.Models +{ + public class GridSettings : SettingsBase + { + private GridColumnSettingsCollection _columns; + + private string _groupName; + + private string _groupHeaderFormat; + + private SortDescription _sort; + + private List _collapsedGroups; + + private static string[] _groupHeaderFormatArgs; + + public GridColumnSettingsCollection Columns => _columns ?? (_columns = new GridColumnSettingsCollection()); + + public IEnumerable SortableColumnsUIList + { + get + { + yield return GridColumnSettings.Empty; + foreach (GridColumnSettings column in Columns.Where(x => ColumnsManager.ColumnIsSortable(x.PropertyNameId))) + yield return column; + } + } + + public IEnumerable GroupableColumnsUIList + { + get + { + yield return GridColumnSettings.Empty; + foreach (GridColumnSettings column in Columns.Where(ColumnsManager.ColumnIsGroupable)) + yield return column; + } + } + + public string GroupName + { + get => _groupName ?? (_groupName = string.Empty); + set => _groupName = value; + } + + /// + /// User-friendly header format for groups. + /// For example, "{title}: {value} - {count} items". + /// Available arguments see in . + /// + public string GroupHeaderFormat + { + get => _groupHeaderFormat ?? (_groupHeaderFormat = "{title}: {value}"); + set => _groupHeaderFormat = value; + } + + public string GroupHeaderRawFormat => ConvertGroupHeaderToRawFormat(GroupHeaderFormat); + + public static string[] GroupHeaderFormatArgs => _groupHeaderFormatArgs ?? (_groupHeaderFormatArgs = new[] { "title", "value", "count" }); + + public bool ShowColumnsHeader { get; set; } = true; + + public SortDescription Sort + { + get => _sort ?? (_sort = new SortDescription(SortOrder.Ascending, "BuildOrder")); + set => _sort = value; + } + + public List CollapsedGroups => _collapsedGroups ?? (_collapsedGroups = new List()); + + /// + /// Converts user-friendly string format with arguments + /// into system format string (with {0},{1},... arguments). + /// + private static string ConvertGroupHeaderToRawFormat(string userFriendlyFormatString) + { + if (string.IsNullOrEmpty(userFriendlyFormatString)) + return string.Empty; + + string rawFormat = userFriendlyFormatString; + for (int i = 0; i < GroupHeaderFormatArgs.Length; i++) + rawFormat = rawFormat.Replace("{" + GroupHeaderFormatArgs[i], "{" + i); + + return rawFormat; + } + } +} diff --git a/src/BuildVision.UI/Models/ProjectItemSettings.cs b/src/BuildVision.UI/Settings/Models/ProjectItemSettings.cs similarity index 98% rename from src/BuildVision.UI/Models/ProjectItemSettings.cs rename to src/BuildVision.UI/Settings/Models/ProjectItemSettings.cs index 93108f5d..f1a451ed 100644 --- a/src/BuildVision.UI/Models/ProjectItemSettings.cs +++ b/src/BuildVision.UI/Settings/Models/ProjectItemSettings.cs @@ -3,7 +3,7 @@ namespace BuildVision.UI.Settings.Models { public class ProjectItemSettings : SettingsBase - { + { public BuildOutputFileTypes CopyBuildOutputFileTypesToClipboard { get; set; } public ProjectItemSettings() diff --git a/src/BuildVision.UI/Settings/Models/WindowSettings.cs b/src/BuildVision.UI/Settings/Models/WindowSettings.cs new file mode 100644 index 00000000..91acb467 --- /dev/null +++ b/src/BuildVision.UI/Settings/Models/WindowSettings.cs @@ -0,0 +1,22 @@ +using BuildVision.Common; +using BuildVision.UI.Models; +using BuildVision.UI.Settings.Models.ToolWindow; + +namespace BuildVision.UI.Settings.Models +{ + public class WindowSettings : SettingsBase + { + public WindowStateAction WindowActionOnBuildBegin { get; set; } + + public WindowStateAction WindowActionOnBuildSuccess { get; set; } + + public WindowStateAction WindowActionOnBuildError { get; set; } + + public WindowSettings() + { + WindowActionOnBuildBegin = new WindowStateAction(WindowState.Show); + WindowActionOnBuildSuccess = new WindowStateAction(WindowState.Nothing); + WindowActionOnBuildError = new WindowStateAction(WindowState.Show); + } + } +} diff --git a/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs b/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs index 4ea77a04..bcb15ce8 100644 --- a/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs +++ b/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs @@ -28,6 +28,8 @@ using BuildVision.Views.Settings; using BuildVision.Exports.Services; using BuildVision.Exports.ViewModels; +using BuildVision.Exports.Providers; +using BuildVision.Contracts.Models; namespace BuildVision.UI.ViewModels { @@ -46,6 +48,8 @@ public bool HideUpToDateTargets public ControlSettings ControlSettings { get; } + public IBuildInformationModel BuildInformationModel { get; set; } + public string GridGroupPropertyName { get { return ControlSettings.GridSettings.GroupName; } @@ -179,6 +183,7 @@ public DataGridHeadersVisibility GridHeadersVisibility private ProjectItem _selectedProjectItem; private readonly IBuildService _buildManager; + private readonly IBuildInformationProvider _buildInformationProvider; public ProjectItem SelectedProjectItem { @@ -187,9 +192,11 @@ public ProjectItem SelectedProjectItem } [ImportingConstructor] - public BuildVisionPaneViewModel(IBuildService buildManager, VisualStudioSolution solution, IPackageSettingsProvider settingsProvider) + public BuildVisionPaneViewModel(IBuildService buildManager, IBuildInformationProvider buildInformationProvider, IPackageSettingsProvider settingsProvider) { _buildManager = buildManager; + _buildInformationProvider = buildInformationProvider; + BuildInformationModel = _buildInformationProvider.GetBuildInformationModel(); ControlSettings = settingsProvider.Settings; BuildProgressViewModel = new BuildProgressViewModel(ControlSettings); } diff --git a/src/BuildVision.UI/ViewModels/SolutionModel.cs b/src/BuildVision.UI/ViewModels/SolutionModel.cs deleted file mode 100644 index ce8ae774..00000000 --- a/src/BuildVision.UI/ViewModels/SolutionModel.cs +++ /dev/null @@ -1,93 +0,0 @@ -using BuildVision.Common; - -namespace BuildVision.Core -{ - public class SolutionModel : BindableBase - { - public string State { get; set; } = "StandBy"; - - private int _errorCount = -1; - public int ErrorCount - { - get => _errorCount; - set => SetProperty(ref _errorCount, value); - } - - private int _warningsCount = -1; - public int WarningsCount - { - get => _warningsCount; - set => SetProperty(ref _warningsCount, value); - } - - private int _messagesCount = -1; - public int MessagesCount - { - get => _messagesCount; - set => SetProperty(ref _messagesCount, value); - } - - private int _succeededProjectsCount = -1; - public int SucceededProjectsCount - { - get => _warningsCount; - set => SetProperty(ref _succeededProjectsCount, value); - } - - private int _upToDateProjectsCount = -1; - public int UpToDateProjectsCount - { - get => _warningsCount; - set => SetProperty(ref _upToDateProjectsCount, value); - } - - private int _failedProjectsCount = -1; - public int FailedProjectsCount - { - get => _warningsCount; - set => SetProperty(ref _failedProjectsCount, value); - } - - private int _warnedProjectsCount = -1; - public int WarnedProjectsCount - { - get => _warningsCount; - set => SetProperty(ref _warnedProjectsCount, value); - } - - private string _stateMessage = ""; - public string StateMessage - { - get => _stateMessage; - set => SetProperty(ref _stateMessage, value); - } - - private string _fileName; - public string FileName - { - get => _fileName; - set => SetProperty(ref _fileName, value); - } - - private string _name; - public string Name - { - get => _name; - set => SetProperty(ref _name, value); - } - - private string _fullName; - public string FullName - { - get => _fullName; - set => SetProperty(ref _fullName, value); - } - - private bool _isEmpty = true; - public bool IsEmpty - { - get => _isEmpty; - set => SetProperty(ref _isEmpty, value); - } - } -} diff --git a/src/BuildVision.UI/ViewModels/VisualStudioSolution.cs b/src/BuildVision.UI/ViewModels/VisualStudioSolution.cs deleted file mode 100644 index bab610c8..00000000 --- a/src/BuildVision.UI/ViewModels/VisualStudioSolution.cs +++ /dev/null @@ -1,101 +0,0 @@ -using System; -using System.Collections.ObjectModel; -using BuildVision.Common; -using BuildVision.Contracts; -using BuildVision.UI.Contracts; -using BuildVision.UI.Models; - -namespace BuildVision.Core -{ - - public class VisualStudioSolution : BindableBase - { - public BuildState CurrentBuildState { get; set; } - public BuildResultState ResultState => GetBuildState(); - public BuildActions BuildAction { get; set; } - public BuildScopes BuildScope { get; set; } - public DateTime? BuildStartTime { get; set; } - public DateTime? BuildFinishTime { get; set; } - - public ObservableCollection Projects { get; } - - public VisualStudioSolution() - { - Projects = new ObservableCollection(); - } - - public BuildResultState GetBuildState() - { - if (CurrentBuildState == BuildState.InProgress) - { - return BuildResultState.Unknown; - } - else if (CurrentBuildState == BuildState.Done) - { - //TODO Decied what happened - if (BuildAction == BuildActions.BuildActionRebuildAll) - return BuildResultState.RebuildCancelled; - if (BuildAction == BuildActions.BuildActionClean) - return BuildResultState.CleanCancelled; - if (BuildAction == BuildActions.BuildActionBuild) - return BuildResultState.BuildCancelled; - else - return BuildResultState.Unknown; - - if (BuildAction == BuildActions.BuildActionRebuildAll) - return BuildResultState.RebuildFailed; - if (BuildAction == BuildActions.BuildActionClean) - return BuildResultState.CleanFailed; - if (BuildAction == BuildActions.BuildActionBuild) - return BuildResultState.BuildFailed; - else - return BuildResultState.Unknown; - - if (BuildAction == BuildActions.BuildActionRebuildAll) - return BuildResultState.RebuildSucceeded; - if (BuildAction == BuildActions.BuildActionClean) - return BuildResultState.CleanSucceeded; - if (BuildAction == BuildActions.BuildActionBuild) - return BuildResultState.BuildSucceeded; - else - return BuildResultState.Unknown; - - if (BuildAction == BuildActions.BuildActionRebuildAll) - return BuildResultState.RebuildSucceededWithErrors; - if (BuildAction == BuildActions.BuildActionClean) - return BuildResultState.CleanSucceededWithErrors; - if (BuildAction == BuildActions.BuildActionBuild) - return BuildResultState.BuildSucceededWithErrors; - else - return BuildResultState.Unknown; - } - else - { - return BuildResultState.Unknown; - } - } - } - - - /* - * General - * - BuildState / ResultState - * - StateMessage - * - ErrorsCount - * - WarningsCount - * - InformationCount - * - SucceededProjects - * - UpToDateProjects - * - WarningProjects - * - FailedProjects - * - * Projects - * - * Actions - * - Build Solution - * - Rebuild Solution - * - Clean Solution - * - Cancel - * * - * */ -} diff --git a/src/BuildVision/BuildVision.csproj b/src/BuildVision/BuildVision.csproj index bc863a08..05676a66 100644 --- a/src/BuildVision/BuildVision.csproj +++ b/src/BuildVision/BuildVision.csproj @@ -91,13 +91,18 @@ + + + + + - + diff --git a/src/BuildVision/Core/BuildVisionPackage.cs b/src/BuildVision/Core/BuildVisionPackage.cs index 5882d334..927267ba 100644 --- a/src/BuildVision/Core/BuildVisionPackage.cs +++ b/src/BuildVision/Core/BuildVisionPackage.cs @@ -6,6 +6,7 @@ using System.Windows; using BuildVision.Common; using BuildVision.Contracts; +using BuildVision.Exports.Providers; using BuildVision.Helpers; using BuildVision.Tool; using BuildVision.Tool.Building; @@ -41,12 +42,9 @@ namespace BuildVision.Core // This attribute registers a tool window exposed by this package. [ProvideToolWindow(typeof(BuildVisionPane))] [Guid(PackageGuids.GuidBuildVisionPackageString)] - //[ProvideAutoLoad(VSConstants.UICONTEXT.SolutionOpening_string, PackageAutoLoadFlags.BackgroundLoad)] [ProvideBindingPath] [ProvideBindingPath(SubPath = "Lib")] - // TODO: Add ProvideProfileAttribute for each DialogPage and implement IVsUserSettings, IVsUserSettingsQuery. [ProvideProfile(typeof(GeneralSettingsDialogPage), PackageSettingsProvider.settingsCategoryName, "General Options", 0, 0, true)] - // TODO: ProvideOptionPage keywords. [ProvideOptionPage(typeof(GeneralSettingsDialogPage), "BuildVision", "General", 0, 0, true)] [ProvideOptionPage(typeof(WindowSettingsDialogPage), "BuildVision", "Tool Window", 0, 0, true)] [ProvideOptionPage(typeof(GridSettingsDialogPage), "BuildVision", "Projects Grid", 0, 0, true)] @@ -59,13 +57,14 @@ public sealed partial class BuildVisionPackage : AsyncPackage, IPackageContext private SolutionEvents _solutionEvents; private BuildVisionPaneViewModel _viewModel; private IVsSolutionBuildManager2 _solutionBuildManager; + private IVsSolutionBuildManager5 _solutionBuildManager4; + private IBuildInformationProvider _buildInformationProvider; private uint _updateSolutionEvents4Cookie; private readonly Guid _parsingErrorsLoggerId = new Guid("{64822131-DC4D-4087-B292-61F7E06A7B39}"); private BuildOutputLogger _buildLogger; - private Solution _vsSolution; - private IVsSolutionBuildManager5 _solutionBuildManager4; - private SolutionModel _solutionState; private SolutionBuildEvents _solutionBuildEvents; + private ISolutionProvider _solutionProvider; + private IBuildingProjectsProvider _buildingProjectsProvider; public ControlSettings ControlSettings { get; set; } @@ -88,11 +87,13 @@ protected override async Task InitializeAsync(CancellationToken cancellationToke var menuToolWin = new OleMenuCommand(ShowToolWindowAsync, toolwndCommandId); mcs.AddCommand(menuToolWin); } - _solutionBuildManager = ServiceProvider.GlobalProvider.GetService(typeof(SVsSolutionBuildManager)) as IVsSolutionBuildManager2; - _solutionBuildManager4 = ServiceProvider.GlobalProvider.GetService(typeof(SVsSolutionBuildManager)) as IVsSolutionBuildManager5; + _solutionBuildManager = await GetServiceAsync(typeof(SVsSolutionBuildManager)) as IVsSolutionBuildManager2; + _solutionBuildManager4 = await GetServiceAsync(typeof(SVsSolutionBuildManager)) as IVsSolutionBuildManager5; + _buildInformationProvider = await GetServiceAsync(typeof(IBuildInformationProvider)) as IBuildInformationProvider; + _solutionProvider = await GetServiceAsync(typeof(ISolutionProvider)) as ISolutionProvider; + _buildingProjectsProvider = await GetServiceAsync(typeof(IBuildingProjectsProvider)) as IBuildingProjectsProvider; IPackageContext packageContext = this; - _solutionEvents = _dte.Events.SolutionEvents; _solutionEvents.BeforeClosing += SolutionEvents_BeforeClosing; _solutionEvents.AfterClosing += SolutionEvents_AfterClosing; @@ -103,8 +104,8 @@ protected override async Task InitializeAsync(CancellationToken cancellationToke SolutionEvents_Opened(); } - var toolWindow = GetWindowPane(typeof(BuildVisionPane)); - _viewModel = BuildVisionPane.GetViewModel(toolWindow); + //var toolWindow = GetWindowPane(typeof(BuildVisionPane)); + //_viewModel = BuildVisionPane.GetViewModel(toolWindow); } private void SolutionEvents_BeforeClosing() @@ -117,22 +118,15 @@ private void SolutionEvents_BeforeClosing() private void SolutionEvents_Opened() { ThreadHelper.ThrowIfNotOnUIThread(); - _vsSolution = Services.Dte2.Solution; - _solutionState = _vsSolution.ToSolutionBuildState(); - //_solutionBuildEvents = new SolutionBuildEvents(_solutionState); + _solutionBuildEvents = new SolutionBuildEvents(_solutionProvider, _buildInformationProvider, _buildingProjectsProvider); _solutionBuildManager.AdviseUpdateSolutionEvents(_solutionBuildEvents, out _updateSolutionEvents4Cookie); _solutionBuildManager4.AdviseUpdateSolutionEvents4(_solutionBuildEvents, out _updateSolutionEvents4Cookie); - //_viewModel.ResetIndicators(ResetIndicatorMode.ResetValue); } private void SolutionEvents_AfterClosing() { ThreadHelper.ThrowIfNotOnUIThread(); - //_viewModel.TextCurrentState = Resources.BuildDoneText_BuildNotStarted; - ////_viewModel.ImageCurrentState = "TODO SET IMAGE"//VectorResources.TryGet(BuildImages.BuildActionResourcesUri, "StandBy"); - //_viewModel.ProjectsList.Clear(); - //_viewModel.ResetIndicators(ResetIndicatorMode.Disable); - _viewModel.BuildProgressViewModel.ResetTaskBarInfo(); + //_viewModel.BuildProgressViewModel.ResetTaskBarInfo(); } private async void ShowToolWindowAsync(object sender, EventArgs e) diff --git a/src/BuildVision/Core/ServiceProviderPackage.cs b/src/BuildVision/Core/ServiceProviderPackage.cs index 85c48306..5c240024 100644 --- a/src/BuildVision/Core/ServiceProviderPackage.cs +++ b/src/BuildVision/Core/ServiceProviderPackage.cs @@ -2,7 +2,9 @@ using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; +using BuildVision.Exports.Providers; using BuildVision.Views.Settings; +using Microsoft; using Microsoft.VisualStudio.Shell; using Task = System.Threading.Tasks.Task; @@ -11,12 +13,18 @@ namespace BuildVision.Core [PackageRegistration(UseManagedResourcesOnly = true, AllowsBackgroundLoading = true)] [Guid(PackageGuids.GuidBuildVisionServiceProvider)] [ProvideService(typeof(IPackageSettingsProvider), IsAsyncQueryable = true)] + [ProvideService(typeof(IBuildInformationProvider), IsAsyncQueryable = true)] + [ProvideService(typeof(ISolutionProvider), IsAsyncQueryable = true)] + [ProvideService(typeof(IBuildingProjectsProvider), IsAsyncQueryable = true)] public sealed class ServiceProviderPackage : AsyncPackage { protected override async Task InitializeAsync(CancellationToken cancellationToken, IProgress progress) { await Task.CompletedTask; AddService(typeof(IPackageSettingsProvider), CreateServiceAsync, true); + AddService(typeof(IBuildInformationProvider), CreateServiceAsync, true); + AddService(typeof(ISolutionProvider), CreateServiceAsync, true); + AddService(typeof(IBuildingProjectsProvider), CreateServiceAsync, true); } async Task CreateServiceAsync(IAsyncServiceContainer container, CancellationToken cancellation, Type serviceType) @@ -25,8 +33,34 @@ async Task CreateServiceAsync(IAsyncServiceContainer container, Cancella { await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(cancellation); var sp = new ServiceProvider(Services.Dte as Microsoft.VisualStudio.OLE.Interop.IServiceProvider); + Assumes.Present(sp); return new PackageSettingsProvider(sp); } + else if (serviceType == typeof(IBuildInformationProvider)) + { + await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(cancellation); + var sp = new ServiceProvider(Services.Dte as Microsoft.VisualStudio.OLE.Interop.IServiceProvider); + Assumes.Present(sp); + return new BuildInformationProvider(sp); + } + else if (serviceType == typeof(ISolutionProvider)) + { + await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(cancellation); + var sp = new ServiceProvider(Services.Dte as Microsoft.VisualStudio.OLE.Interop.IServiceProvider); + Assumes.Present(sp); + return new SolutionProvider(sp); + } + else if (serviceType == typeof(IBuildingProjectsProvider)) + { + await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(cancellation); + var sp = new ServiceProvider(Services.Dte as Microsoft.VisualStudio.OLE.Interop.IServiceProvider); + Assumes.Present(sp); + var solutionProvider = sp.GetService(typeof(ISolutionProvider)) as ISolutionProvider; + Assumes.Present(solutionProvider); + var buildInformationProvider = sp.GetService(typeof(IBuildInformationProvider)) as IBuildInformationProvider; + Assumes.Present(buildInformationProvider); + return new BuildingProjectsProvider(solutionProvider, buildInformationProvider); + } else { throw new Exception("Not found"); diff --git a/src/BuildVision/Core/SolutionBuildEvents.cs b/src/BuildVision/Core/SolutionBuildEvents.cs index 07fc7d4b..5aef26d7 100644 --- a/src/BuildVision/Core/SolutionBuildEvents.cs +++ b/src/BuildVision/Core/SolutionBuildEvents.cs @@ -4,6 +4,7 @@ using System.Threading; using BuildVision.Common; using BuildVision.Contracts; +using BuildVision.Exports.Providers; using BuildVision.Helpers; using BuildVision.Tool.Building; using BuildVision.Tool.Models; @@ -20,309 +21,56 @@ namespace BuildVision.Core public class SolutionBuildEvents : IVsUpdateSolutionEvents2, IVsUpdateSolutionEvents4 { - private readonly Guid _parsingErrorsLoggerId = new Guid("{64822131-DC4D-4087-B292-61F7E06A7B39}"); - public BuildOutputLogger _buildLogger; // This needs to be static because it is shared accross multiple instances + private readonly ISolutionProvider _solutionProvider; + private readonly IBuildInformationProvider _buildInformationProvider; + private readonly IBuildingProjectsProvider _buildingProjectsProvider; - public VisualStudioSolution VisualStudioSolution { get; } - - private BuildEvents _buildEvents; - private bool _buildCancelled; - private bool _buildCancelledInternally; - private bool _buildErrorIsNavigated; - private string _origTextCurrentState; - - public SolutionBuildEvents(VisualStudioSolution solutionBuildState) + public SolutionBuildEvents( + ISolutionProvider solutionProvider, + IBuildInformationProvider buildInformationProvider, + IBuildingProjectsProvider buildingProjectsProvider) { - VisualStudioSolution = solutionBuildState; + _solutionProvider = solutionProvider; + _buildInformationProvider = buildInformationProvider; + _buildingProjectsProvider = buildingProjectsProvider; } public void UpdateSolution_BeginUpdateAction(uint dwAction) { - _buildCancelled = false; - _buildCancelledInternally = false; - _buildErrorIsNavigated = false; - - RegisterLogger(); - - VisualStudioSolution.Projects.Clear(); - VisualStudioSolution.Projects.AddRange(Services.Dte2.Solution.GetProjectItems()); - VisualStudioSolution.BuildStartTime = DateTime.Now; - VisualStudioSolution.BuildFinishTime = null; - VisualStudioSolution.CurrentBuildState = BuildState.InProgress; - VisualStudioSolution.BuildAction = StateConverterHelper.ConvertSolutionBuildFlagsToBuildAction(dwAction, (VSSOLNBUILDUPDATEFLAGS) dwAction); - - //TODO use settings - string message = new BuildMessagesFactory(new UI.Settings.Models.BuildMessagesSettings()).GetBuildBeginMajorMessage(VisualStudioSolution); - //_statusBarNotificationService.ShowTextWithFreeze(message); - _origTextCurrentState = message; - //VisualStudioSolution.StateMessage = _origTextCurrentState; // Set message - try - { - //ApplyToolWindowStateAction(_viewModel.ControlSettings.WindowSettings.WindowActionOnBuildBegin); - //if (_viewModel.ControlSettings.GeneralSettings.FillProjectListOnBuildBegin) - // _viewModel.ProjectsList.AddRange(_viewModel.SolutionItem.AllProjects); - - // Reset HeaderViewModel - //_viewModel.ResetIndicators(ResetIndicatorMode.ResetValue); - //int projectsCount = -1; - //projectsCount = GetProjectsCount(projectsCount); - //_viewModel.OnBuildBegin(projectsCount, this); - } - catch (Exception ex) - { - ex.TraceUnknownException(); - } + _buildInformationProvider.BuildStarted(dwAction); + _buildingProjectsProvider.ReloadCurrentProjects(); + //ApplyToolWindowStateAction(_viewModel.ControlSettings.WindowSettings.WindowActionOnBuildBegin); + //int projectsCount = -1; + //projectsCount = GetProjectsCount(projectsCount); + //_viewModel.OnBuildBegin(projectsCount, this); //_buildProcessCancellationToken = new CancellationTokenSource(); - //// Startbackground process - ////Task.Factory.StartNew(BuildEvents_BuildInProcess, _buildProcessCancellationToken.Token, _buildProcessCancellationToken.Token); + // Startbackground process + //Task.Factory.StartNew(BuildEvents_BuildInProcess, _buildProcessCancellationToken.Token, _buildProcessCancellationToken.Token); } public int UpdateProjectCfg_Begin(IVsHierarchy pHierProj, IVsCfg pCfgProj, IVsCfg pCfgSln, uint dwAction, ref int pfCancel) { - try - { - var projectItem = VisualStudioSolution.Projects.FirstOrDefault(item => ProjectIdentifierGenerator.GetIdentifierForProjectItem(item) == ProjectIdentifierGenerator.GetIdentifierForInteropTypes(pHierProj, pCfgProj)); - if (projectItem == null) - { - // In this case we are executing a batch build so we need to add the projectitem manually - projectItem = new UI.Models.ProjectItem(); - var configPair = pCfgProj.ToConfigurationTuple(); - SolutionProjectsExtensions.UpdateProperties(pHierProj.ToProject(), projectItem, configPair.Item1, configPair.Item2); - VisualStudioSolution.Projects.Add(projectItem); - } - - projectItem.State = GetProjectState(VisualStudioSolution.BuildAction); - projectItem.BuildFinishTime = null; - projectItem.BuildStartTime = DateTime.Now; - - // _viewModel.OnBuildProjectBegin(); - //if (BuildScope == BuildScopes.BuildScopeSolution && - // (BuildAction == BuildActions.BuildActionBuild || - // BuildAction == BuildActions.BuildActionRebuildAll)) - //{ - // currentProject.BuildOrder = _viewModel.BuildProgressViewModel.CurrentQueuePosOfBuildingProject; - //} - //if (!_viewModel.ProjectsList.Contains(currentProject)) - // _viewModel.ProjectsList.Add(currentProject); - //else if (_viewModel.ControlSettings.GeneralSettings.FillProjectListOnBuildBegin) - // _viewModel.OnPropertyChanged(nameof(BuildVisionPaneViewModel.GroupedProjectsList)); - //_viewModel.CurrentProject = currentProject; - } - catch (Exception ex) - { - ex.TraceUnknownException(); - } + _buildingProjectsProvider.ProjectBuildStarted(pHierProj, pCfgProj, pCfgSln, dwAction); return VSConstants.S_OK; } public int UpdateProjectCfg_Done(IVsHierarchy pHierProj, IVsCfg pCfgProj, IVsCfg pCfgSln, uint dwAction, int fSuccess, int fCancel) { - var currentProject = VisualStudioSolution.Projects.First(item => ProjectIdentifierGenerator.GetIdentifierForProjectItem(item) == ProjectIdentifierGenerator.GetIdentifierForInteropTypes(pHierProj, pCfgProj)); - Debug.WriteLine($"UpdateProjectCfg_Done {currentProject.UniqueName} ({currentProject.Configuration}|{currentProject.Platform})"); - //currentProject.Success = fSuccess == 1; - //ProjectState projectState; - //switch (SolutionBuildState.BuildAction) - //{ - // case BuildActions.BuildActionBuild: - // case BuildActions.BuildActionRebuildAll: - // if (currentProject.Success) - // { - // if (_viewModel.ControlSettings.GeneralSettings.ShowWarningSignForBuilds && buildedProject.ErrorsBox.WarningsCount > 0) - // projectState = ProjectState.BuildWarning; - // else - // { - // bool upToDate = (_buildLogger != null && _buildLogger.Projects != null - // && !_buildLogger.Projects.Exists(t => t.FileName == buildedProject.FileName)); - // if (upToDate) - // { - // // Because ErrorBox will be empty if project is UpToDate. - // buildedProject.ErrorsBox = currentProject.ErrorsBox; - // } - // projectState = upToDate ? ProjectState.UpToDate : ProjectState.BuildDone; - // } - // } - // else - // { - // bool canceled = (_buildCancelled && buildedProject.ErrorsBox.ErrorsCount == 0); - // projectState = canceled ? ProjectState.BuildCancelled : ProjectState.BuildError; - // } - // break; - - // case BuildActions.BuildActionClean: - // projectState = fSuccess == 1 ? ProjectState.CleanDone : ProjectState.CleanError; - // break; - - // case BuildActions.BuildActionDeploy: - // throw new InvalidOperationException("vsBuildActionDeploy not supported"); - - // default: - // throw new ArgumentOutOfRangeException(nameof(SolutionBuildState.BuildAction)); - //} - - //buildedProject.ProjectState = projectState; - //OnBuildProjectDone(new BuildProjectEventArgs(currentProject, projectState, eventTime, buildedProject)); - - //Debug.WriteLine($"UpdateProjectCfg_Done {proj.UniqueName} ({projConfiguration}) ({slnConfiguration}"); - - //if (e.ProjectState == ProjectState.BuildError && _viewModel.ControlSettings.GeneralSettings.StopBuildAfterFirstError) - // CancelBuildAsync(); - - //try - //{ - // ProjectItem currentProject = e.ProjectItem; - // currentProject.State = e.ProjectState; - // currentProject.BuildFinishTime = DateTime.Now; - // currentProject.UpdatePostBuildProperties(e.BuildedProjectInfo); - - // if (!_viewModel.ProjectsList.Contains(currentProject)) - // _viewModel.ProjectsList.Add(currentProject); - - // if (ReferenceEquals(_viewModel.CurrentProject, e.ProjectItem) && BuildingProjects.Any()) - // _viewModel.CurrentProject = BuildingProjects.Last(); - //} - //catch (Exception ex) - //{ - // ex.TraceUnknownException(); - //} - - //_viewModel.UpdateIndicators(this); - - //try - //{ - // _viewModel.OnBuildProjectDone(e.BuildedProjectInfo); - //} - //catch (Exception ex) - //{ - // ex.TraceUnknownException(); - //} + _buildingProjectsProvider.ProjectBuildFinished(pHierProj, pCfgProj, pCfgSln, fSuccess == 1, fCancel == 1); return VSConstants.S_OK; } public int UpdateSolution_Done(int fSucceeded, int fModified, int fCancelCommand) { - if (VisualStudioSolution.CurrentBuildState == BuildState.InProgress) - { - // Start command (F5), when Build is not required. - return VSConstants.S_OK; - } - - //try - //{ - // var settings = _viewModel.ControlSettings; - - // SetFinalStateForUnfinishedProjects(); - - // // Update header? This might be happening impliclty when updating solution - // //_viewModel.UpdateIndicators(this); + _buildInformationProvider.BuildFinished(fSucceeded == 1, fModified == 1, fCancelCommand == 1); - // var message = BuildMessages.GetBuildDoneMessage(_viewModel.SolutionItem, this, settings.BuildMessagesSettings); - // var buildDoneImage = BuildImages.GetBuildDoneImage(this, _viewModel.ProjectsList, out ControlTemplate stateImage); + var result = _buildInformationProvider.GetBuildInformationModel(); + var finishedProjects = _buildingProjectsProvider.GetBuildingProjects(); - // _statusBarNotificationService.ShowText(message); - // _viewModel.TextCurrentState = message; - // _viewModel.ImageCurrentState = buildDoneImage; - // _viewModel.ImageCurrentStateResult = stateImage; - // _viewModel.CurrentProject = null; - // _viewModel.OnBuildDone(this); - - // ApplyWindowState(settings); - // NavigateToBuildErrorIfNeeded(settings); - //} - //catch (Exception ex) - //{ - // ex.TraceUnknownException(); - //} - - VisualStudioSolution.BuildFinishTime = DateTime.Now; - VisualStudioSolution.CurrentBuildState = BuildState.Done; return VSConstants.S_OK; } - private ProjectState GetProjectState(BuildActions buildAction) - { - switch (buildAction) - { - case BuildActions.BuildActionBuild: - case BuildActions.BuildActionRebuildAll: - return ProjectState.Building; - - case BuildActions.BuildActionClean: - return ProjectState.Cleaning; - - case BuildActions.BuildActionDeploy: - throw new InvalidOperationException("vsBuildActionDeploy not supported"); - - default: - throw new ArgumentOutOfRangeException(nameof(buildAction)); - } - } - - private bool PlatformsIsEquals(string platformName1, string platformName2) - { - if (string.Compare(platformName1, platformName2, StringComparison.InvariantCultureIgnoreCase) == 0) - return true; - - // The ambiguity between Project.ActiveConfiguration.PlatformName and - // ProjectStartedEventArgs.ProjectPlatform in Microsoft.Build.Utilities.Logger - // (see BuildOutputLogger). - bool isAnyCpu1 = (platformName1 == "Any CPU" || platformName1 == "AnyCPU"); - bool isAnyCpu2 = (platformName2 == "Any CPU" || platformName2 == "AnyCPU"); - if (isAnyCpu1 && isAnyCpu2) - return true; - - return false; - } - - private void RegisterLogger() - { - _buildLogger = null; - RegisterLoggerResult result = BuildOutputLogger.Register(_parsingErrorsLoggerId, Microsoft.Build.Framework.LoggerVerbosity.Quiet, out _buildLogger); - if (result == RegisterLoggerResult.AlreadyExists) - { - _buildLogger.Projects?.Clear(); - } - } - - //public bool GetProjectItem(IBuildVisionPaneViewModel viewModel, BuildProjectContextEntry projectEntry, out ProjectItem projectItem) - //{ - // projectItem = projectEntry.ProjectItem; - // if (projectItem != null) - // return true; - - // string projectFile = projectEntry.FileName; - // if (ProjectExtensions.IsProjectHidden(projectFile)) - // return false; - - // var projectProperties = projectEntry.Properties; - // var project = viewModel.ProjectsList.FirstOrDefault(x => x.FullName == projectFile); - - - // if (projectProperties.ContainsKey("Configuration") && projectProperties.ContainsKey("Platform")) - // { - // string projectConfiguration = projectProperties["Configuration"]; - // string projectPlatform = projectProperties["Platform"]; - // projectItem = FindProjectItemInProjectsByUniqueName(viewModel, project.UniqueName, projectConfiguration, projectPlatform); - // if (projectItem == null) - // { - // TraceManager.Trace( - // string.Format("Project Item not found by: UniqueName='{0}', Configuration='{1}, Platform='{2}'.", - // project.UniqueName, - // projectConfiguration, - // projectPlatform), - // EventLogEntryType.Warning); - // return false; - // } - // } - // else - // { - // return false; - // } - - // projectEntry.ProjectItem = projectItem; - // return true; - //} - #region Interface Implementation public int UpdateSolution_Begin(ref int pfCancelUpdate) diff --git a/src/BuildVision/Services/BuildInformationProvider.cs b/src/BuildVision/Services/BuildInformationProvider.cs new file mode 100644 index 00000000..9fd80dfd --- /dev/null +++ b/src/BuildVision/Services/BuildInformationProvider.cs @@ -0,0 +1,127 @@ +using System; +using System.ComponentModel.Composition; +using System.IO; +using BuildVision.Contracts; +using BuildVision.Contracts.Models; +using BuildVision.Exports.Providers; +using BuildVision.Exports.Services; +using BuildVision.Tool.Building; +using BuildVision.Tool.Models; +using BuildVision.UI; +using BuildVision.UI.Common.Logging; +using EnvDTE; +using EnvDTE80; +using Microsoft.VisualStudio.Shell; +using Microsoft.VisualStudio.Shell.Interop; + +namespace BuildVision.Core +{ + [Export(typeof(IBuildInformationProvider))] + [PartCreationPolicy(CreationPolicy.Shared)] + public class BuildInformationProvider : IBuildInformationProvider + { + public BuildOutputLogger _buildLogger; + + private readonly Guid _parsingErrorsLoggerId = new Guid("{64822131-DC4D-4087-B292-61F7E06A7B39}"); + private readonly IServiceProvider _serviceProvider; + private Solution _solution; + private BuildInformationModel _buildInformationModel; + private BuildEvents _buildEvents; + private DTE2 _dte; + + [ImportingConstructor] + public BuildInformationProvider([Import(typeof(SVsServiceProvider))] IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + _buildInformationModel = new BuildInformationModel(); + _buildEvents = (serviceProvider.GetService(typeof(DTE)) as DTE).Events.BuildEvents; + _buildEvents.OnBuildBegin += _buildEvents_OnBuildBegin; + } + + private void _buildEvents_OnBuildBegin(vsBuildScope scope, vsBuildAction action) + { + _buildInformationModel.BuildScope = (BuildScopes) scope; // we need to set buildscope explictly because it is not possible to get this via the other api + } + + public IBuildInformationModel GetBuildInformationModel() + { + return _buildInformationModel; + } + + public void BuildStarted(uint dwAction) + { + RegisterLogger(); + + _buildInformationModel.SucceededProjectsCount = 0; + _buildInformationModel.FailedProjectsCount = 0; + _buildInformationModel.WarnedProjectsCount = 0; + _buildInformationModel.UpToDateProjectsCount = 0; + _buildInformationModel.MessagesCount = 0; + _buildInformationModel.WarnedProjectsCount = 0; + _buildInformationModel.ErrorCount = 0; + _buildInformationModel.StateMessage = ""; + _buildInformationModel.BuildStartTime = DateTime.Now; + _buildInformationModel.BuildFinishTime = null; + _buildInformationModel.CurrentBuildState = BuildState.InProgress; + _buildInformationModel.BuildAction = StateConverterHelper.ConvertSolutionBuildFlagsToBuildAction(dwAction, (VSSOLNBUILDUPDATEFLAGS) dwAction); + //TODO use settings + //string message = new BuildMessagesFactory(new UI.Settings.Models.BuildMessagesSettings()).GetBuildBeginMajorMessage(VisualStudioSolution); + //_statusBarNotificationService.ShowTextWithFreeze(message); + //_origTextCurrentState = message; + //VisualStudioSolution.StateMessage = _origTextCurrentState; // Set message + } + + public void BuildUpdate() + { + //_buildInformationModel.StateMessage = _origTextCurrentState + BuildMessages.GetBuildBeginExtraMessage(this, labelsSettings); + } + + public void BuildFinished(bool success, bool modified, bool canceled) + { + //try + //{ + // var settings = _viewModel.ControlSettings; + + // SetFinalStateForUnfinishedProjects(); + + // // Update header? This might be happening impliclty when updating solution + // //_viewModel.UpdateIndicators(this); + + // var message = BuildMessages.GetBuildDoneMessage(_viewModel.SolutionItem, this, settings.BuildMessagesSettings); + // var buildDoneImage = BuildImages.GetBuildDoneImage(this, _viewModel.ProjectsList, out ControlTemplate stateImage); + + // _statusBarNotificationService.ShowText(message); + // _viewModel.TextCurrentState = message; + // _viewModel.ImageCurrentState = buildDoneImage; + // _viewModel.ImageCurrentStateResult = stateImage; + // _viewModel.CurrentProject = null; + // _viewModel.OnBuildDone(this); + + // ApplyWindowState(settings); + // NavigateToBuildErrorIfNeeded(settings); + //} + //catch (Exception ex) + //{ + // ex.TraceUnknownException(); + //} + + _buildInformationModel.BuildFinishTime = DateTime.Now; + if(success) + _buildInformationModel.CurrentBuildState = BuildState.Done; + else if(canceled) + _buildInformationModel.CurrentBuildState = BuildState.Cancelled; + else + _buildInformationModel.CurrentBuildState = BuildState.Failed; + } + + private void RegisterLogger() + { + _buildLogger = null; + RegisterLoggerResult result = BuildOutputLogger.Register(_parsingErrorsLoggerId, Microsoft.Build.Framework.LoggerVerbosity.Quiet, out _buildLogger); + if (result == RegisterLoggerResult.AlreadyExists) + { + _buildLogger.Projects?.Clear(); + } + } + } +} diff --git a/src/BuildVision/Services/BuildingProjectsProvider.cs b/src/BuildVision/Services/BuildingProjectsProvider.cs new file mode 100644 index 00000000..57a18a26 --- /dev/null +++ b/src/BuildVision/Services/BuildingProjectsProvider.cs @@ -0,0 +1,246 @@ +using System; +using System.Collections.ObjectModel; +using System.ComponentModel.Composition; +using System.Linq; +using BuildVision.Common; +using BuildVision.Contracts; +using BuildVision.Contracts.Models; +using BuildVision.Exports.Providers; +using BuildVision.Helpers; +using BuildVision.Tool.Building; +using BuildVision.Tool.Models; +using BuildVision.UI.Common.Logging; +using BuildVision.UI.Models; +using Microsoft.VisualStudio.Shell; +using Microsoft.VisualStudio.Shell.Interop; + +namespace BuildVision.Core +{ + [Export(typeof(IBuildInformationProvider))] + [PartCreationPolicy(CreationPolicy.Shared)] + public class BuildingProjectsProvider : IBuildingProjectsProvider + { + public BuildOutputLogger _buildLogger; + + private readonly Guid _parsingErrorsLoggerId = new Guid("{64822131-DC4D-4087-B292-61F7E06A7B39}"); + private readonly IServiceProvider _serviceProvider; + private readonly ISolutionProvider _solutionProvider; + private readonly IBuildInformationProvider _buildInformationProvider; + private ObservableCollection _projects; + + + [ImportingConstructor] + public BuildingProjectsProvider( + [Import(typeof(ISolutionProvider))] ISolutionProvider solutionProvider, + [Import(typeof(IBuildInformationProvider))] IBuildInformationProvider buildInformationProvider) + { + _projects = new ObservableCollection(); + _solutionProvider = solutionProvider; + _buildInformationProvider = buildInformationProvider; + } + + public void ReloadCurrentProjects() + { + _projects.Clear(); + _projects.AddRange(_solutionProvider.GetProjects()); + } + + public ObservableCollection GetBuildingProjects() + { + return _projects; + } + + public void ProjectBuildStarted(IVsHierarchy pHierProj, IVsCfg pCfgProj, IVsCfg pCfgSln, uint dwAction) + { + try + { + var projectItem = _projects.FirstOrDefault(item => ProjectIdentifierGenerator.GetIdentifierForProjectItem(item) == ProjectIdentifierGenerator.GetIdentifierForInteropTypes(pHierProj, pCfgProj)); + if (projectItem == null) + { + // In this case we are executing a batch build so we need to add the projectitem manually + projectItem = new UI.Models.ProjectItem(); + var configPair = pCfgProj.ToConfigurationTuple(); + SolutionProjectsExtensions.UpdateProperties(pHierProj.ToProject(), projectItem, configPair.Item1, configPair.Item2); + _projects.Add(projectItem); + } + + projectItem.State = GetProjectState(_buildInformationProvider.GetBuildInformationModel().BuildAction); + projectItem.BuildFinishTime = null; + projectItem.BuildStartTime = DateTime.Now; + + // _viewModel.OnBuildProjectBegin(); + //if (BuildScope == BuildScopes.BuildScopeSolution && + // (BuildAction == BuildActions.BuildActionBuild || + // BuildAction == BuildActions.BuildActionRebuildAll)) + //{ + // currentProject.BuildOrder = _viewModel.BuildProgressViewModel.CurrentQueuePosOfBuildingProject; + //} + //if (!_viewModel.ProjectsList.Contains(currentProject)) + // _viewModel.ProjectsList.Add(currentProject); + //else if (_viewModel.ControlSettings.GeneralSettings.FillProjectListOnBuildBegin) + // _viewModel.OnPropertyChanged(nameof(BuildVisionPaneViewModel.GroupedProjectsList)); + //_viewModel.CurrentProject = currentProject; + } + catch (Exception ex) + { + ex.TraceUnknownException(); + } + } + + private bool PlatformsIsEquals(string platformName1, string platformName2) + { + if (string.Compare(platformName1, platformName2, StringComparison.InvariantCultureIgnoreCase) == 0) + return true; + + // The ambiguity between Project.ActiveConfiguration.PlatformName and + // ProjectStartedEventArgs.ProjectPlatform in Microsoft.Build.Utilities.Logger + // (see BuildOutputLogger). + bool isAnyCpu1 = (platformName1 == "Any CPU" || platformName1 == "AnyCPU"); + bool isAnyCpu2 = (platformName2 == "Any CPU" || platformName2 == "AnyCPU"); + if (isAnyCpu1 && isAnyCpu2) + return true; + + return false; + } + + //public bool GetProjectItem(IBuildVisionPaneViewModel viewModel, BuildProjectContextEntry projectEntry, out ProjectItem projectItem) + //{ + // projectItem = projectEntry.ProjectItem; + // if (projectItem != null) + // return true; + + // string projectFile = projectEntry.FileName; + // if (ProjectExtensions.IsProjectHidden(projectFile)) + // return false; + + // var projectProperties = projectEntry.Properties; + // var project = viewModel.ProjectsList.FirstOrDefault(x => x.FullName == projectFile); + + + // if (projectProperties.ContainsKey("Configuration") && projectProperties.ContainsKey("Platform")) + // { + // string projectConfiguration = projectProperties["Configuration"]; + // string projectPlatform = projectProperties["Platform"]; + // projectItem = FindProjectItemInProjectsByUniqueName(viewModel, project.UniqueName, projectConfiguration, projectPlatform); + // if (projectItem == null) + // { + // TraceManager.Trace( + // string.Format("Project Item not found by: UniqueName='{0}', Configuration='{1}, Platform='{2}'.", + // project.UniqueName, + // projectConfiguration, + // projectPlatform), + // EventLogEntryType.Warning); + // return false; + // } + // } + // else + // { + // return false; + // } + + // projectEntry.ProjectItem = projectItem; + // return true; + //} + + private ProjectState GetProjectState(BuildActions buildAction) + { + switch (buildAction) + { + case BuildActions.BuildActionBuild: + case BuildActions.BuildActionRebuildAll: + return ProjectState.Building; + + case BuildActions.BuildActionClean: + return ProjectState.Cleaning; + + case BuildActions.BuildActionDeploy: + throw new InvalidOperationException("vsBuildActionDeploy not supported"); + + default: + throw new ArgumentOutOfRangeException(nameof(buildAction)); + } + } + + public void ProjectBuildFinished(IVsHierarchy pHierProj, IVsCfg pCfgProj, IVsCfg pCfgSln, bool succeess, bool canceled) + { + var currentProject = _projects.First(item => ProjectIdentifierGenerator.GetIdentifierForProjectItem(item) == ProjectIdentifierGenerator.GetIdentifierForInteropTypes(pHierProj, pCfgProj)); + currentProject.State = ProjectState.BuildDone; + //currentProject.Success = fSuccess == 1; + //ProjectState projectState; + //switch (SolutionBuildState.BuildAction) + //{ + // case BuildActions.BuildActionBuild: + // case BuildActions.BuildActionRebuildAll: + // if (currentProject.Success) + // { + // if (_viewModel.ControlSettings.GeneralSettings.ShowWarningSignForBuilds && buildedProject.ErrorsBox.WarningsCount > 0) + // projectState = ProjectState.BuildWarning; + // else + // { + // bool upToDate = (_buildLogger != null && _buildLogger.Projects != null + // && !_buildLogger.Projects.Exists(t => t.FileName == buildedProject.FileName)); + // if (upToDate) + // { + // // Because ErrorBox will be empty if project is UpToDate. + // buildedProject.ErrorsBox = currentProject.ErrorsBox; + // } + // projectState = upToDate ? ProjectState.UpToDate : ProjectState.BuildDone; + // } + // } + // else + // { + // bool canceled = (_buildCancelled && buildedProject.ErrorsBox.ErrorsCount == 0); + // projectState = canceled ? ProjectState.BuildCancelled : ProjectState.BuildError; + // } + // break; + + // case BuildActions.BuildActionClean: + // projectState = fSuccess == 1 ? ProjectState.CleanDone : ProjectState.CleanError; + // break; + + // case BuildActions.BuildActionDeploy: + // throw new InvalidOperationException("vsBuildActionDeploy not supported"); + + // default: + // throw new ArgumentOutOfRangeException(nameof(SolutionBuildState.BuildAction)); + //} + + //buildedProject.ProjectState = projectState; + //OnBuildProjectDone(new BuildProjectEventArgs(currentProject, projectState, eventTime, buildedProject)); + + //Debug.WriteLine($"UpdateProjectCfg_Done {proj.UniqueName} ({projConfiguration}) ({slnConfiguration}"); + + //if (e.ProjectState == ProjectState.BuildError && _viewModel.ControlSettings.GeneralSettings.StopBuildAfterFirstError) + // CancelBuildAsync(); + + //try + //{ + // ProjectItem currentProject = e.ProjectItem; + // currentProject.State = e.ProjectState; + // currentProject.BuildFinishTime = DateTime.Now; + // currentProject.UpdatePostBuildProperties(e.BuildedProjectInfo); + + // if (!_viewModel.ProjectsList.Contains(currentProject)) + // _viewModel.ProjectsList.Add(currentProject); + + // if (ReferenceEquals(_viewModel.CurrentProject, e.ProjectItem) && BuildingProjects.Any()) + // _viewModel.CurrentProject = BuildingProjects.Last(); + //} + //catch (Exception ex) + //{ + // ex.TraceUnknownException(); + //} + + //_viewModel.UpdateIndicators(this); + + //try + //{ + // _viewModel.OnBuildProjectDone(e.BuildedProjectInfo); + //} + //catch (Exception ex) + //{ + // ex.TraceUnknownException(); + //} + } + } +} diff --git a/src/BuildVision/Services/IBuildingProjectsProvider.cs b/src/BuildVision/Services/IBuildingProjectsProvider.cs new file mode 100644 index 00000000..13b8aa47 --- /dev/null +++ b/src/BuildVision/Services/IBuildingProjectsProvider.cs @@ -0,0 +1,14 @@ +using System.Collections.ObjectModel; +using BuildVision.UI.Models; +using Microsoft.VisualStudio.Shell.Interop; + +namespace BuildVision.Core +{ + public interface IBuildingProjectsProvider + { + ObservableCollection GetBuildingProjects(); + void ProjectBuildFinished(IVsHierarchy pHierProj, IVsCfg pCfgProj, IVsCfg pCfgSln, bool succeess, bool canceled); + void ProjectBuildStarted(IVsHierarchy pHierProj, IVsCfg pCfgProj, IVsCfg pCfgSln, uint dwAction); + void ReloadCurrentProjects(); + } +} diff --git a/src/BuildVision/Services/ISolutionProvider.cs b/src/BuildVision/Services/ISolutionProvider.cs new file mode 100644 index 00000000..a471d6b1 --- /dev/null +++ b/src/BuildVision/Services/ISolutionProvider.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using BuildVision.Contracts.Models; +using BuildVision.UI.Models; + +namespace BuildVision.Core +{ + public interface ISolutionProvider + { + ISolutionModel GetSolutionModel(); + void ReloadSolution(); + IEnumerable GetProjects(); + } +} diff --git a/src/BuildVision/Services/SolutionProvider.cs b/src/BuildVision/Services/SolutionProvider.cs new file mode 100644 index 00000000..2d78283a --- /dev/null +++ b/src/BuildVision/Services/SolutionProvider.cs @@ -0,0 +1,97 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.IO; +using BuildVision.Contracts.Models; +using BuildVision.Exports.Services; +using BuildVision.Helpers; +using BuildVision.UI; +using BuildVision.UI.Common.Logging; +using BuildVision.UI.Models; +using EnvDTE; +using EnvDTE80; +using Microsoft.VisualStudio.Shell; +using Microsoft.VisualStudio.Shell.Interop; + +namespace BuildVision.Core +{ + [Export(typeof(IStatusBarNotificationService))] + [PartCreationPolicy(CreationPolicy.Shared)] + public class SolutionProvider : ISolutionProvider + { + private readonly IServiceProvider _serviceProvider; + private Solution _solution; + private SolutionModel _solutionModel; + private DTE2 _dte; + + [ImportingConstructor] + public SolutionProvider([Import(typeof(SVsServiceProvider))] IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + } + + public void ReloadSolution() + { + ThreadHelper.ThrowIfNotOnUIThread(); + _dte = _serviceProvider.GetService(typeof(DTE)) as DTE2; + _solution = _dte.Solution; + + RefrehSolutionModel(); + } + + public ISolutionModel GetSolutionModel() + { + return _solutionModel; + } + + private void RefrehSolutionModel() + { + if(_solutionModel == null) + _solutionModel = new SolutionModel(); + + try + { + if (_solution == null) + { + _solutionModel.Name = Resources.GridCellNATextInBrackets; + _solutionModel.FullName = Resources.GridCellNATextInBrackets; + _solutionModel.IsEmpty = true; + } + else if (string.IsNullOrEmpty(_solution.FileName)) + { + if (_solution.Count != 0 /* projects count */) + { + var project = _solution.Item(1); + _solutionModel.Name = Path.GetFileNameWithoutExtension(project.FileName); + _solutionModel.FullName = project.FullName; + _solutionModel.IsEmpty = false; + } + else + { + _solutionModel.Name = Resources.GridCellNATextInBrackets; + _solutionModel.FullName = Resources.GridCellNATextInBrackets; + _solutionModel.IsEmpty = true; + } + } + else + { + _solutionModel.Name = Path.GetFileNameWithoutExtension(_solution.FileName); + _solutionModel.FullName = _solution.FullName; + _solutionModel.IsEmpty = false; + } + } + catch (Exception ex) + { + ex.TraceUnknownException(); + _solutionModel.Name = Resources.GridCellNATextInBrackets; + _solutionModel.FullName = Resources.GridCellNATextInBrackets; + _solutionModel.IsEmpty = true; + } + } + + public IEnumerable GetProjects() + { + return _solution.GetProjectItems(); + } + } +} diff --git a/src/BuildVision/Core/StatusBarNotificationService.cs b/src/BuildVision/Services/StatusBarNotificationService.cs similarity index 100% rename from src/BuildVision/Core/StatusBarNotificationService.cs rename to src/BuildVision/Services/StatusBarNotificationService.cs From b97a25d9fc2c798f9f4dfd42ba771a251fa3c698 Mon Sep 17 00:00:00 2001 From: Stefan Kert Date: Mon, 11 Mar 2019 07:12:23 +0100 Subject: [PATCH 011/100] Added several additional services and moved some components to Contracts project to make them independent from impl. Added interfaces for some Models (IProjectItem a.e) --- .../BuildErrorRaisedEventArgs.cs | 7 +- .../BuildVision.Contracts.csproj | 11 +- .../Models}/BuildProjectContextEntry.cs | 4 +- .../Models}/BuildProjectEventArgs.cs | 6 +- .../{ => Models}/BuildedProject.cs | 0 .../Models}/BuildedProjectsCollection.cs | 4 +- .../{ => Models}/ErrorItem.cs | 5 +- .../{ => Models}/ErrorsBox.cs | 0 .../Models/IProjectItem.cs | 39 +++ .../Factories/IBuildMessagesFactory.cs | 9 + src/BuildVision.Exports/IBuildOutputLogger.cs | 16 ++ .../Providers/IBuildingProjectsProvider.cs | 15 ++ .../Providers}/ISolutionProvider.cs | 2 +- src/BuildVision.UI/BuildVision.UI.csproj | 3 - .../Components/ErrorsGrid.xaml.cs | 3 +- .../Helpers/BuildMessagesFactory.cs | 73 +++--- src/BuildVision.UI/Helpers/SortDescription.cs | 29 +-- .../Helpers/WindowStateAction.cs | 20 +- src/BuildVision.UI/Models/ProjectItem.cs | 24 +- .../ViewModels/BuildVisionPaneViewModel.cs | 1 - src/BuildVision/BuildVision.csproj | 5 +- .../Core/ServiceProviderExports.cs | 22 -- .../Core/ServiceProviderPackage.cs | 39 ++- src/BuildVision/Core/SolutionBuildEvents.cs | 17 +- src/BuildVision/Helpers/ProjectExtensions.cs | 67 +---- .../Helpers/ProjectIdentifierGenerator.cs | 5 +- src/BuildVision/Helpers/ToolWindowManager.cs | 24 ++ .../Services/BuildInformationProvider.cs | 61 +++-- .../Services/BuildingProjectsProvider.cs | 242 +++++++++--------- .../Services/IBuildingProjectsProvider.cs | 14 - .../Services/ProjectFileNavigationService.cs | 90 +++++++ src/BuildVision/Services/SolutionProvider.cs | 5 +- src/BuildVision/Tool/Building/BuildContext.cs | 206 --------------- src/BuildVision/Tool/Building/BuildManager.cs | 144 +++++++---- .../Tool/Building/BuildOutputLogger.cs | 101 ++++---- .../Tool/Views/Settings/SettingsDialogPage.cs | 2 +- 36 files changed, 648 insertions(+), 667 deletions(-) rename src/{BuildVision.UI/Contracts => BuildVision.Contracts/Models}/BuildProjectContextEntry.cs (92%) rename src/{BuildVision.UI/Contracts => BuildVision.Contracts/Models}/BuildProjectEventArgs.cs (72%) rename src/BuildVision.Contracts/{ => Models}/BuildedProject.cs (100%) rename src/{BuildVision.UI/Contracts => BuildVision.Contracts/Models}/BuildedProjectsCollection.cs (88%) rename src/BuildVision.Contracts/{ => Models}/ErrorItem.cs (95%) rename src/BuildVision.Contracts/{ => Models}/ErrorsBox.cs (100%) create mode 100644 src/BuildVision.Contracts/Models/IProjectItem.cs create mode 100644 src/BuildVision.Exports/Factories/IBuildMessagesFactory.cs create mode 100644 src/BuildVision.Exports/IBuildOutputLogger.cs create mode 100644 src/BuildVision.Exports/Providers/IBuildingProjectsProvider.cs rename src/{BuildVision/Services => BuildVision.Exports/Providers}/ISolutionProvider.cs (84%) delete mode 100644 src/BuildVision/Core/ServiceProviderExports.cs delete mode 100644 src/BuildVision/Services/IBuildingProjectsProvider.cs create mode 100644 src/BuildVision/Services/ProjectFileNavigationService.cs delete mode 100644 src/BuildVision/Tool/Building/BuildContext.cs diff --git a/src/BuildVision.Contracts/BuildErrorRaisedEventArgs.cs b/src/BuildVision.Contracts/BuildErrorRaisedEventArgs.cs index 95112bcc..d4528092 100644 --- a/src/BuildVision.Contracts/BuildErrorRaisedEventArgs.cs +++ b/src/BuildVision.Contracts/BuildErrorRaisedEventArgs.cs @@ -1,16 +1,17 @@ using System; +using BuildVision.UI.Models; namespace BuildVision.Contracts { public class BuildErrorRaisedEventArgs : EventArgs { public ErrorLevel ErrorLevel { get; private set; } - public BuildedProject ProjectInfo { get; private set; } + public IProjectItem ProjectInfo { get; private set; } - public BuildErrorRaisedEventArgs(ErrorLevel errorLevel, BuildedProject projectInfo) + public BuildErrorRaisedEventArgs(ErrorLevel errorLevel, IProjectItem projectInfo) { ErrorLevel = errorLevel; ProjectInfo = projectInfo; } } -} \ No newline at end of file +} diff --git a/src/BuildVision.Contracts/BuildVision.Contracts.csproj b/src/BuildVision.Contracts/BuildVision.Contracts.csproj index e1ae6667..d33ee879 100644 --- a/src/BuildVision.Contracts/BuildVision.Contracts.csproj +++ b/src/BuildVision.Contracts/BuildVision.Contracts.csproj @@ -38,6 +38,7 @@ + @@ -49,19 +50,23 @@ + + - + - + + - + + diff --git a/src/BuildVision.UI/Contracts/BuildProjectContextEntry.cs b/src/BuildVision.Contracts/Models/BuildProjectContextEntry.cs similarity index 92% rename from src/BuildVision.UI/Contracts/BuildProjectContextEntry.cs rename to src/BuildVision.Contracts/Models/BuildProjectContextEntry.cs index c7ef7bc6..8862f0e7 100644 --- a/src/BuildVision.UI/Contracts/BuildProjectContextEntry.cs +++ b/src/BuildVision.Contracts/Models/BuildProjectContextEntry.cs @@ -13,7 +13,7 @@ public class BuildProjectContextEntry public IDictionary Properties { get; set; } - public ProjectItem ProjectItem { get; set; } + public IProjectItem ProjectItem { get; set; } public bool IsInvalid { get; set; } @@ -25,4 +25,4 @@ public BuildProjectContextEntry(int instanceId, int contextId, string fileName, Properties = properties; } } -} \ No newline at end of file +} diff --git a/src/BuildVision.UI/Contracts/BuildProjectEventArgs.cs b/src/BuildVision.Contracts/Models/BuildProjectEventArgs.cs similarity index 72% rename from src/BuildVision.UI/Contracts/BuildProjectEventArgs.cs rename to src/BuildVision.Contracts/Models/BuildProjectEventArgs.cs index 77144067..1f9c671a 100644 --- a/src/BuildVision.UI/Contracts/BuildProjectEventArgs.cs +++ b/src/BuildVision.Contracts/Models/BuildProjectEventArgs.cs @@ -6,12 +6,12 @@ namespace BuildVision.UI.Contracts { public class BuildProjectEventArgs : EventArgs { - public ProjectItem ProjectItem { get; private set; } + public IProjectItem ProjectItem { get; private set; } public ProjectState ProjectState { get; private set; } public DateTime EventTime { get; private set; } public BuildedProject BuildedProjectInfo { get; private set; } - public BuildProjectEventArgs(ProjectItem projectItem, ProjectState projectState, DateTime eventTime, BuildedProject buildedProjectInfo) + public BuildProjectEventArgs(IProjectItem projectItem, ProjectState projectState, DateTime eventTime, BuildedProject buildedProjectInfo) { ProjectItem = projectItem; ProjectState = projectState; @@ -19,4 +19,4 @@ public BuildProjectEventArgs(ProjectItem projectItem, ProjectState projectState, BuildedProjectInfo = buildedProjectInfo; } } -} \ No newline at end of file +} diff --git a/src/BuildVision.Contracts/BuildedProject.cs b/src/BuildVision.Contracts/Models/BuildedProject.cs similarity index 100% rename from src/BuildVision.Contracts/BuildedProject.cs rename to src/BuildVision.Contracts/Models/BuildedProject.cs diff --git a/src/BuildVision.UI/Contracts/BuildedProjectsCollection.cs b/src/BuildVision.Contracts/Models/BuildedProjectsCollection.cs similarity index 88% rename from src/BuildVision.UI/Contracts/BuildedProjectsCollection.cs rename to src/BuildVision.Contracts/Models/BuildedProjectsCollection.cs index 450ecdee..b81f02f3 100644 --- a/src/BuildVision.UI/Contracts/BuildedProjectsCollection.cs +++ b/src/BuildVision.Contracts/Models/BuildedProjectsCollection.cs @@ -6,7 +6,7 @@ namespace BuildVision.UI.Contracts { - public class BuildedProjectsCollection : List + public class BuildedProjectsCollection : List { public int BuildSuccessCount => this.Count(p => p.Success == true && p.State != ProjectState.BuildWarning && p.State != ProjectState.UpToDate); public int BuildErrorCount => this.Count(p => p.Success == false); @@ -16,7 +16,7 @@ public class BuildedProjectsCollection : List public bool BuildWithoutErrors => this.All(p => p.Success == null || p.Success == true); - public ProjectItem this[ProjectItem pi] + public IProjectItem this[IProjectItem pi] { get { diff --git a/src/BuildVision.Contracts/ErrorItem.cs b/src/BuildVision.Contracts/Models/ErrorItem.cs similarity index 95% rename from src/BuildVision.Contracts/ErrorItem.cs rename to src/BuildVision.Contracts/Models/ErrorItem.cs index 8625dd97..1e35a718 100644 --- a/src/BuildVision.Contracts/ErrorItem.cs +++ b/src/BuildVision.Contracts/Models/ErrorItem.cs @@ -48,12 +48,9 @@ public string FileName public string Message { get; set; } - public Action GoToError { get; } - - public ErrorItem(ErrorLevel errorLevel, Action goToError) + public ErrorItem(ErrorLevel errorLevel) { Level = errorLevel; - GoToError = () => goToError(this); } public ErrorItem() { } diff --git a/src/BuildVision.Contracts/ErrorsBox.cs b/src/BuildVision.Contracts/Models/ErrorsBox.cs similarity index 100% rename from src/BuildVision.Contracts/ErrorsBox.cs rename to src/BuildVision.Contracts/Models/ErrorsBox.cs diff --git a/src/BuildVision.Contracts/Models/IProjectItem.cs b/src/BuildVision.Contracts/Models/IProjectItem.cs new file mode 100644 index 00000000..ec7fd09b --- /dev/null +++ b/src/BuildVision.Contracts/Models/IProjectItem.cs @@ -0,0 +1,39 @@ +using System; +using System.Windows.Controls; +using BuildVision.Contracts; + +namespace BuildVision.UI.Models +{ + public interface IProjectItem + { + TimeSpan? BuildElapsedTime { get; } + DateTime? BuildFinishTime { get; set; } + int? BuildOrder { get; set; } + DateTime? BuildStartTime { get; set; } + string CommonType { get; set; } + string Configuration { get; set; } + ErrorsBox ErrorsBox { get; set; } + int ErrorsCount { get; } + string ExtenderNames { get; set; } + string FlavourType { get; set; } + string Framework { get; set; } + string FullName { get; set; } + string FullPath { get; set; } + bool IsBatchBuildProject { get; set; } + string Language { get; set; } + string MainFlavourType { get; set; } + int MessagesCount { get; } + string Name { get; set; } + string OutputType { get; set; } + string Platform { get; set; } + string RootNamespace { get; set; } + string SolutionFolder { get; set; } + ProjectState State { get; set; } + ControlTemplate StateBitmap { get; } + bool Success { get; set; } + string UniqueName { get; set; } + int WarningsCount { get; } + + void RaiseBuildElapsedTimeChanged(); + } +} diff --git a/src/BuildVision.Exports/Factories/IBuildMessagesFactory.cs b/src/BuildVision.Exports/Factories/IBuildMessagesFactory.cs new file mode 100644 index 00000000..8a921a81 --- /dev/null +++ b/src/BuildVision.Exports/Factories/IBuildMessagesFactory.cs @@ -0,0 +1,9 @@ +namespace BuildVision.Exports.Factories +{ + public interface IBuildMessagesFactory + { + string GetBuildBeginExtraMessage(); + string GetBuildBeginMajorMessage(); + string GetBuildDoneMessage(); + } +} diff --git a/src/BuildVision.Exports/IBuildOutputLogger.cs b/src/BuildVision.Exports/IBuildOutputLogger.cs new file mode 100644 index 00000000..bd1a363c --- /dev/null +++ b/src/BuildVision.Exports/IBuildOutputLogger.cs @@ -0,0 +1,16 @@ +using System; +using BuildVision.Contracts; +using BuildVision.UI.Contracts; +using BuildVision.UI.Models; + +namespace BuildVision.Exports +{ + public interface IBuildOutputLogger + { + bool IsProjectUpToDate(IProjectItem projectItem); + + void Attach(); + + event Action OnErrorRaised; + } +} diff --git a/src/BuildVision.Exports/Providers/IBuildingProjectsProvider.cs b/src/BuildVision.Exports/Providers/IBuildingProjectsProvider.cs new file mode 100644 index 00000000..2d546fb0 --- /dev/null +++ b/src/BuildVision.Exports/Providers/IBuildingProjectsProvider.cs @@ -0,0 +1,15 @@ +using System.Collections.ObjectModel; +using BuildVision.UI.Contracts; +using BuildVision.UI.Models; + +namespace BuildVision.Exports.Providers +{ + public interface IBuildingProjectsProvider + { + ObservableCollection GetBuildingProjects(); + void ProjectBuildStarted(IProjectItem projectItem, uint dwAction); + void ProjectBuildFinished(string projectIdentifier, bool succeess, bool canceled); + void ReloadCurrentProjects(); + bool TryGetProjectItem(BuildProjectContextEntry projectEntry, out IProjectItem projectItem); + } +} diff --git a/src/BuildVision/Services/ISolutionProvider.cs b/src/BuildVision.Exports/Providers/ISolutionProvider.cs similarity index 84% rename from src/BuildVision/Services/ISolutionProvider.cs rename to src/BuildVision.Exports/Providers/ISolutionProvider.cs index a471d6b1..a53a7017 100644 --- a/src/BuildVision/Services/ISolutionProvider.cs +++ b/src/BuildVision.Exports/Providers/ISolutionProvider.cs @@ -8,6 +8,6 @@ public interface ISolutionProvider { ISolutionModel GetSolutionModel(); void ReloadSolution(); - IEnumerable GetProjects(); + IEnumerable GetProjects(); } } diff --git a/src/BuildVision.UI/BuildVision.UI.csproj b/src/BuildVision.UI/BuildVision.UI.csproj index a69c589f..4b28ecac 100644 --- a/src/BuildVision.UI/BuildVision.UI.csproj +++ b/src/BuildVision.UI/BuildVision.UI.csproj @@ -90,8 +90,6 @@ ErrorsGrid.xaml - - @@ -99,7 +97,6 @@ - ControlView.xaml diff --git a/src/BuildVision.UI/Components/ErrorsGrid.xaml.cs b/src/BuildVision.UI/Components/ErrorsGrid.xaml.cs index 83d53d86..48c68ca6 100644 --- a/src/BuildVision.UI/Components/ErrorsGrid.xaml.cs +++ b/src/BuildVision.UI/Components/ErrorsGrid.xaml.cs @@ -37,7 +37,8 @@ private void ErrorsGridRowOnMouseLeftButtonUp(object sender, MouseButtonEventArg { var row = (DataGridRow)sender; var errorItem = (ErrorItem)row.Item; - errorItem.GoToError(); + // TODO navigate to error + //errorItem.GoToError(); e.Handled = true; } catch (Exception ex) diff --git a/src/BuildVision.UI/Helpers/BuildMessagesFactory.cs b/src/BuildVision.UI/Helpers/BuildMessagesFactory.cs index ca2e5b4e..a0e0c910 100644 --- a/src/BuildVision.UI/Helpers/BuildMessagesFactory.cs +++ b/src/BuildVision.UI/Helpers/BuildMessagesFactory.cs @@ -4,32 +4,41 @@ using BuildVision.UI.Models; using BuildVision.UI.Settings.Models; using BuildVision.Core; +using BuildVision.Exports.Providers; +using BuildVision.Contracts.Models; +using BuildVision.Exports.Factories; namespace BuildVision.UI.Helpers { - public class BuildMessagesFactory + public class BuildMessagesFactory : IBuildMessagesFactory { private readonly BuildMessagesSettings _labelSettings; + private IBuildInformationProvider _buildInformationProvider; + private IBuildingProjectsProvider _buildingProjectsProvider; + private IBuildInformationModel _buildInformation; - public BuildMessagesFactory(BuildMessagesSettings labelsSettings) + public BuildMessagesFactory(ControlSettings controlSettings, + IBuildInformationProvider buildInformationProvider, + IBuildingProjectsProvider buildingProjectsProvider) { - _labelSettings = labelsSettings; + _labelSettings = controlSettings.BuildMessagesSettings; + _buildInformationProvider = buildInformationProvider; + _buildingProjectsProvider = buildingProjectsProvider; + _buildInformation = _buildInformationProvider.GetBuildInformationModel(); } - public string GetBuildBeginMajorMessage(SolutionModel solutionItem, BuildInformationModel buildInformationModel) + public string GetBuildBeginMajorMessage() { - var mainString = GetMainString(solutionItem, buildInformationModel); + var mainString = GetMainString(_buildInformation.BuildAction); return string.Format(_labelSettings.BuildBeginMajorMessageStringFormat, mainString); } - private string GetMainString(SolutionModel solutionItem, BuildInformationModel buildInformationModel) + private string GetMainString(BuildActions buildAction) { - var buildAction = BuildActions.BuildActionBuild; //TOdo replace - - var unitName = GetUnitName(solutionItem, buildInformationModel); - var actionName = GetActionName(buildInformationModel.BuildAction); - var beginAtString = GetBeginAtString(buildInformationModel.BuildAction); - var timeString = GetTimeString(solutionItem, buildInformationModel); + var unitName = GetUnitName(); + var actionName = GetActionName(buildAction); + var beginAtString = GetBeginAtString(buildAction); + var timeString = GetTimeString(); string mainString; switch (_labelSettings.MajorMessageFormat) { @@ -48,12 +57,12 @@ private string GetMainString(SolutionModel solutionItem, BuildInformationModel b return mainString; } - private string GetTimeString(SolutionModel solution, BuildInformationModel buildInformationModel) + private string GetTimeString() { string timeString = ""; try { - timeString = buildInformationModel.BuildStartTime.Value.ToString(_labelSettings.DateTimeFormat); + timeString = _buildInformation.BuildStartTime.Value.ToString(_labelSettings.DateTimeFormat); } catch (FormatException) { @@ -97,10 +106,10 @@ private string GetActionName(BuildActions buildAction) } } - private string GetUnitName(SolutionModel solutionItem, BuildInformationModel buildInformationModel) + private string GetUnitName() { string unitName = ""; - switch (buildInformationModel.BuildScope) + switch (_buildInformation.BuildScope) { case BuildScopes.BuildScopeSolution: unitName = Resources.BuildScopeSolution_UnitName; @@ -118,20 +127,20 @@ private string GetUnitName(SolutionModel solutionItem, BuildInformationModel bui break; default: - throw new ArgumentOutOfRangeException(nameof(buildInformationModel.BuildScope)); + throw new ArgumentOutOfRangeException(nameof(_buildInformation.BuildScope)); } return unitName; } - public string GetBuildBeginExtraMessage(SolutionModel solutionItem, BuildInformationModel buildInformationModel) + public string GetBuildBeginExtraMessage() { - if (buildInformationModel.BuildStartTime == null || !_labelSettings.ShowExtraMessage || _labelSettings.ExtraMessageDelay < 0) + if (_buildInformation.BuildStartTime == null || !_labelSettings.ShowExtraMessage || _labelSettings.ExtraMessageDelay < 0) { return string.Empty; } - TimeSpan timeSpan = DateTime.Now.Subtract(buildInformationModel.BuildStartTime.Value); + TimeSpan timeSpan = DateTime.Now.Subtract(_buildInformation.BuildStartTime.Value); if (timeSpan.TotalSeconds > _labelSettings.ExtraMessageDelay) { return GetExtraTimePartString( timeSpan); @@ -140,23 +149,23 @@ public string GetBuildBeginExtraMessage(SolutionModel solutionItem, BuildInforma return string.Empty; } - public string GetBuildDoneMessage(SolutionModel solutionItem, BuildInformationModel buildInformationModel) + public string GetBuildDoneMessage() { - return GetBuildDoneMajorMessage(solutionItem, buildInformationModel) + GetBuildDoneExtraMessage(solutionItem, buildInformationModel); + return GetBuildDoneMajorMessage() + GetBuildDoneExtraMessage(); } - private string GetBuildDoneMajorMessage(SolutionModel solutionItem, BuildInformationModel buildInformationModel) + private string GetBuildDoneMajorMessage() { - var buildAction = buildInformationModel.BuildAction; - var buildScope = buildInformationModel.BuildScope; + var buildAction = _buildInformation.BuildAction; + var buildScope = _buildInformation.BuildScope; - if (buildInformationModel.BuildFinishTime == null) + if (_buildInformation.BuildFinishTime == null) throw new InvalidOperationException(); string timeString; try { - timeString = buildInformationModel.BuildFinishTime.Value.ToString(_labelSettings.DateTimeFormat); + timeString = _buildInformation.BuildFinishTime.Value.ToString(_labelSettings.DateTimeFormat); } catch (FormatException) { @@ -191,8 +200,8 @@ private string GetBuildDoneMajorMessage(SolutionModel solutionItem, BuildInforma throw new ArgumentOutOfRangeException(nameof(buildScope)); } - var actionName = GetActionName(buildInformationModel.BuildAction); - var resultName = GetResultName(buildInformationModel.ResultState); + var actionName = GetActionName(_buildInformation.BuildAction); + var resultName = GetResultName(_buildInformation.ResultState); string mainString; switch (_labelSettings.MajorMessageFormat) @@ -239,12 +248,12 @@ private string GetResultName(BuildResultState resultState) } } - private string GetBuildDoneExtraMessage(SolutionModel solutionItem, BuildInformationModel buildInformationModel) + private string GetBuildDoneExtraMessage() { - if (buildInformationModel.BuildStartTime == null || buildInformationModel.BuildFinishTime == null || !_labelSettings.ShowExtraMessage) + if (_buildInformation.BuildStartTime == null || _buildInformation.BuildFinishTime == null || !_labelSettings.ShowExtraMessage) return string.Empty; - TimeSpan timeSpan = buildInformationModel.BuildFinishTime.Value.Subtract(buildInformationModel.BuildStartTime.Value); + TimeSpan timeSpan = _buildInformation.BuildFinishTime.Value.Subtract(_buildInformation.BuildStartTime.Value); string extraTimePartString = GetExtraTimePartString(timeSpan); return string.Format(_labelSettings.ExtraMessageStringFormat, extraTimePartString); } diff --git a/src/BuildVision.UI/Helpers/SortDescription.cs b/src/BuildVision.UI/Helpers/SortDescription.cs index b2589b75..df2cf1c5 100644 --- a/src/BuildVision.UI/Helpers/SortDescription.cs +++ b/src/BuildVision.UI/Helpers/SortDescription.cs @@ -1,20 +1,19 @@ - -using BuildVision.UI.Models; +using BuildVision.UI.Models; namespace BuildVision.UI.Settings.Models.Sorting { - public class SortDescription - { - public SortOrder Order { get; set; } - - public string Property { get; set; } - - public SortDescription(SortOrder order, string property) + public class SortDescription { - Order = order; - Property = property; - } + public SortOrder Order { get; set; } + + public string Property { get; set; } - public SortDescription() { } - } -} \ No newline at end of file + public SortDescription(SortOrder order, string property) + { + Order = order; + Property = property; + } + + public SortDescription() { } + } +} diff --git a/src/BuildVision.UI/Helpers/WindowStateAction.cs b/src/BuildVision.UI/Helpers/WindowStateAction.cs index bcef0a2a..6a1be444 100644 --- a/src/BuildVision.UI/Helpers/WindowStateAction.cs +++ b/src/BuildVision.UI/Helpers/WindowStateAction.cs @@ -3,15 +3,15 @@ namespace BuildVision.UI.Settings.Models.ToolWindow { - public class WindowStateAction - { - public WindowState State { get; set; } - - public WindowStateAction(WindowState state) + public class WindowStateAction { - State = state; - } + public WindowState State { get; set; } - public WindowStateAction() { } - } -} \ No newline at end of file + public WindowStateAction(WindowState state) + { + State = state; + } + + public WindowStateAction() { } + } +} diff --git a/src/BuildVision.UI/Models/ProjectItem.cs b/src/BuildVision.UI/Models/ProjectItem.cs index fa5539f6..63212f1a 100644 --- a/src/BuildVision.UI/Models/ProjectItem.cs +++ b/src/BuildVision.UI/Models/ProjectItem.cs @@ -8,7 +8,7 @@ namespace BuildVision.UI.Models { - public class ProjectItem : BindableBase + public class ProjectItem : BindableBase, IProjectItem { private const string ResourcesUri = @"Resources/ProjectItem.Resources.xaml"; @@ -252,28 +252,6 @@ public string SolutionFolder } public bool Success { get; set; } - public ProjectItem GetBatchBuildCopy(string configuration, string platform) - { - var pi = Clone(); - pi.Configuration = configuration; - pi.Platform = platform; - pi.ErrorsBox = new ErrorsBox(); - pi.IsBatchBuildProject = true; - return pi; - } - - private ProjectItem Clone() - { - var xmlSerializer = new GenericXmlSerializer(); - return xmlSerializer.Deserialize(xmlSerializer.Serialize(this)); - } - - public void UpdatePostBuildProperties(BuildedProject buildedProjectInfo) - { - if (buildedProjectInfo != null) - ErrorsBox = buildedProjectInfo.ErrorsBox; - } - public void RaiseBuildElapsedTimeChanged() { OnPropertyChanged(nameof(BuildElapsedTime)); diff --git a/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs b/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs index bcb15ce8..18561b72 100644 --- a/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs +++ b/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs @@ -12,7 +12,6 @@ using Microsoft.VisualStudio; using BuildVision.Common; using BuildVision.Contracts; -using BuildVision.UI.Contracts; using BuildVision.UI.DataGrid; using BuildVision.UI.Common.Logging; using BuildVision.UI.Helpers; diff --git a/src/BuildVision/BuildVision.csproj b/src/BuildVision/BuildVision.csproj index 05676a66..5195a1e9 100644 --- a/src/BuildVision/BuildVision.csproj +++ b/src/BuildVision/BuildVision.csproj @@ -93,12 +93,10 @@ - - + - @@ -116,7 +114,6 @@ - diff --git a/src/BuildVision/Core/ServiceProviderExports.cs b/src/BuildVision/Core/ServiceProviderExports.cs deleted file mode 100644 index ea3bacb1..00000000 --- a/src/BuildVision/Core/ServiceProviderExports.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; -using System.ComponentModel.Composition; -using BuildVision.Views.Settings; -using Microsoft.VisualStudio.Shell; - -namespace BuildVision.Core -{ - [PartCreationPolicy(CreationPolicy.Shared)] - public class ServiceProviderExports - { - private readonly IServiceProvider _serviceProvider; - - [ImportingConstructor] - public ServiceProviderExports([Import(typeof(SVsServiceProvider))] IServiceProvider serviceProvider) - { - _serviceProvider = serviceProvider; - } - - [Export] - public IPackageSettingsProvider PackageSettingsProvider => (IPackageSettingsProvider) _serviceProvider.GetService(typeof(IPackageSettingsProvider)); - } -} diff --git a/src/BuildVision/Core/ServiceProviderPackage.cs b/src/BuildVision/Core/ServiceProviderPackage.cs index 5c240024..82be19a0 100644 --- a/src/BuildVision/Core/ServiceProviderPackage.cs +++ b/src/BuildVision/Core/ServiceProviderPackage.cs @@ -2,7 +2,12 @@ using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; +using BuildVision.Exports; +using BuildVision.Exports.Factories; using BuildVision.Exports.Providers; +using BuildVision.Tool.Building; +using BuildVision.UI.Helpers; +using BuildVision.UI.Settings.Models; using BuildVision.Views.Settings; using Microsoft; using Microsoft.VisualStudio.Shell; @@ -16,8 +21,12 @@ namespace BuildVision.Core [ProvideService(typeof(IBuildInformationProvider), IsAsyncQueryable = true)] [ProvideService(typeof(ISolutionProvider), IsAsyncQueryable = true)] [ProvideService(typeof(IBuildingProjectsProvider), IsAsyncQueryable = true)] + [ProvideService(typeof(IBuildMessagesFactory), IsAsyncQueryable = true)] + [ProvideService(typeof(IBuildOutputLogger), IsAsyncQueryable = true)] public sealed class ServiceProviderPackage : AsyncPackage { + private readonly Guid _parsingErrorsLoggerId = new Guid("{64822131-DC4D-4087-B292-61F7E06A7B39}"); + protected override async Task InitializeAsync(CancellationToken cancellationToken, IProgress progress) { await Task.CompletedTask; @@ -25,6 +34,8 @@ protected override async Task InitializeAsync(CancellationToken cancellationToke AddService(typeof(IBuildInformationProvider), CreateServiceAsync, true); AddService(typeof(ISolutionProvider), CreateServiceAsync, true); AddService(typeof(IBuildingProjectsProvider), CreateServiceAsync, true); + AddService(typeof(IBuildMessagesFactory), CreateServiceAsync, true); + AddService(typeof(IBuildOutputLogger), CreateServiceAsync, true); } async Task CreateServiceAsync(IAsyncServiceContainer container, CancellationToken cancellation, Type serviceType) @@ -41,7 +52,9 @@ async Task CreateServiceAsync(IAsyncServiceContainer container, Cancella await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(cancellation); var sp = new ServiceProvider(Services.Dte as Microsoft.VisualStudio.OLE.Interop.IServiceProvider); Assumes.Present(sp); - return new BuildInformationProvider(sp); + var buildOutputLogger = sp.GetService(typeof(IBuildOutputLogger)) as IBuildOutputLogger; + Assumes.Present(buildOutputLogger); + return new BuildInformationProvider(sp, buildOutputLogger); } else if (serviceType == typeof(ISolutionProvider)) { @@ -59,8 +72,28 @@ async Task CreateServiceAsync(IAsyncServiceContainer container, Cancella Assumes.Present(solutionProvider); var buildInformationProvider = sp.GetService(typeof(IBuildInformationProvider)) as IBuildInformationProvider; Assumes.Present(buildInformationProvider); - return new BuildingProjectsProvider(solutionProvider, buildInformationProvider); - } + var buildOutputLogger = sp.GetService(typeof(IBuildOutputLogger)) as IBuildOutputLogger; + Assumes.Present(buildOutputLogger); + return new BuildingProjectsProvider(solutionProvider, buildInformationProvider, buildOutputLogger); + } + else if (serviceType == typeof(IBuildMessagesFactory)) + { + await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(cancellation); + var sp = new ServiceProvider(Services.Dte as Microsoft.VisualStudio.OLE.Interop.IServiceProvider); + Assumes.Present(sp); + var solutionProvider = sp.GetService(typeof(ISolutionProvider)) as ISolutionProvider; + Assumes.Present(solutionProvider); + var buildInformationProvider = sp.GetService(typeof(IBuildInformationProvider)) as IBuildInformationProvider; + Assumes.Present(buildInformationProvider); + var buildingProjectsProvider = sp.GetService(typeof(IBuildingProjectsProvider)) as IBuildingProjectsProvider; + Assumes.Present(buildingProjectsProvider); + return new BuildMessagesFactory(new ControlSettings(), buildInformationProvider, buildingProjectsProvider); + } + else if (serviceType == typeof(IBuildOutputLogger)) + { + await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(cancellation); + return new BuildOutputLogger(_parsingErrorsLoggerId, Microsoft.Build.Framework.LoggerVerbosity.Quiet); + } else { throw new Exception("Not found"); diff --git a/src/BuildVision/Core/SolutionBuildEvents.cs b/src/BuildVision/Core/SolutionBuildEvents.cs index 5aef26d7..59ab2f87 100644 --- a/src/BuildVision/Core/SolutionBuildEvents.cs +++ b/src/BuildVision/Core/SolutionBuildEvents.cs @@ -37,6 +37,7 @@ public SolutionBuildEvents( public void UpdateSolution_BeginUpdateAction(uint dwAction) { + _solutionProvider.ReloadSolution(); _buildInformationProvider.BuildStarted(dwAction); _buildingProjectsProvider.ReloadCurrentProjects(); @@ -51,13 +52,16 @@ public void UpdateSolution_BeginUpdateAction(uint dwAction) public int UpdateProjectCfg_Begin(IVsHierarchy pHierProj, IVsCfg pCfgProj, IVsCfg pCfgSln, uint dwAction, ref int pfCancel) { - _buildingProjectsProvider.ProjectBuildStarted(pHierProj, pCfgProj, pCfgSln, dwAction); + var projectItem = new UI.Models.ProjectItem(); + var configPair = pCfgProj.ToConfigurationTuple(); + SolutionProjectsExtensions.UpdateProperties(pHierProj.ToProject(), projectItem, configPair.Item1, configPair.Item2); + _buildingProjectsProvider.ProjectBuildStarted(projectItem, dwAction); return VSConstants.S_OK; } public int UpdateProjectCfg_Done(IVsHierarchy pHierProj, IVsCfg pCfgProj, IVsCfg pCfgSln, uint dwAction, int fSuccess, int fCancel) { - _buildingProjectsProvider.ProjectBuildFinished(pHierProj, pCfgProj, pCfgSln, fSuccess == 1, fCancel == 1); + _buildingProjectsProvider.ProjectBuildFinished(ProjectIdentifierGenerator.GetIdentifierForInteropTypes(pHierProj, pCfgProj), fSuccess == 1, fCancel == 1); return VSConstants.S_OK; } @@ -68,6 +72,15 @@ public int UpdateSolution_Done(int fSucceeded, int fModified, int fCancelCommand var result = _buildInformationProvider.GetBuildInformationModel(); var finishedProjects = _buildingProjectsProvider.GetBuildingProjects(); + if (result.BuildScope == BuildScopes.BuildScopeSolution) + { + foreach (var projectItem in finishedProjects) + { + if (projectItem.State == ProjectState.Pending) + projectItem.State = ProjectState.Skipped; + } + } + return VSConstants.S_OK; } diff --git a/src/BuildVision/Helpers/ProjectExtensions.cs b/src/BuildVision/Helpers/ProjectExtensions.cs index 16df3532..cbc7fc9f 100644 --- a/src/BuildVision/Helpers/ProjectExtensions.cs +++ b/src/BuildVision/Helpers/ProjectExtensions.cs @@ -156,7 +156,7 @@ public static IEnumerable GetBuildOutputFilePaths(this Project project, /// The project. /// File path, relative to the root. /// The found file or null. - private static ProjectItem FindProjectItem(this Project project, string filePath) + public static ProjectItem FindProjectItem(this Project project, string filePath) { return project.ProjectItems.FindProjectItem(filePath); } @@ -494,71 +494,6 @@ public static bool IsDirty(this Project project) return false; } - /// - /// Navigate to the Error Item in the Visual Studio Editor. - /// - /// The project - owner of the Error Item. - /// The Error Item. - public static bool NavigateToErrorItem(this Project project, BuildVision.Contracts.ErrorItem errorItem) - { - try - { - if (project == null) - throw new ArgumentNullException("project"); - - if (errorItem == null) - throw new ArgumentNullException("errorItem"); - - if (!errorItem.CanNavigateTo) - return false; - - if (string.IsNullOrEmpty(errorItem.File)) - return false; - - string fullPath; - - // Check if path is absolute. - if (Path.IsPathRooted(errorItem.File)) - { - // Foo VC++ projects errorItem.File contains full path. - fullPath = errorItem.File; - } - else - { - var projectItemFile = project.FindProjectItem(errorItem.File); - if (projectItemFile == null) - return false; - - fullPath = projectItemFile.Properties.GetPropertyOrDefault("FullPath"); - if (fullPath == null) - throw new KeyNotFoundException("FullPath property not found."); - } - - try - { - var window = project.DTE.ItemOperations.OpenFile(fullPath, EnvDTE.Constants.vsViewKindAny); - if (window == null) - throw new NullReferenceException("Associated window is null reference."); - - window.Activate(); - - var selection = (TextSelection)window.Selection; - selection.MoveToLineAndOffset(errorItem.LineNumber, errorItem.ColumnNumber); - selection.MoveToLineAndOffset(errorItem.EndLineNumber, errorItem.EndColumnNumber, true /*select text*/); - } - catch (Exception ex) - { - var msg = string.Format("Navigate to error item exception (fullPath='{0}').", fullPath); - ex.Trace(msg); - } - } - catch (Exception ex) - { - ex.Trace("Navigate to error item exception."); - } - - return true; - } public static string GetTreePath(this Project project, bool includeSelfProjectName = true) { diff --git a/src/BuildVision/Helpers/ProjectIdentifierGenerator.cs b/src/BuildVision/Helpers/ProjectIdentifierGenerator.cs index a788da5a..bb1d1058 100644 --- a/src/BuildVision/Helpers/ProjectIdentifierGenerator.cs +++ b/src/BuildVision/Helpers/ProjectIdentifierGenerator.cs @@ -1,4 +1,5 @@ -using EnvDTE; +using BuildVision.UI.Models; +using EnvDTE; using Microsoft.VisualStudio; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; @@ -14,7 +15,7 @@ public static string GetIdentifierForInteropTypes(IVsHierarchy pHierProj, IVsCfg return $"{project.UniqueName}-{projConfiguration}"; } - public static string GetIdentifierForProjectItem(BuildVision.UI.Models.ProjectItem projectItem) + public static string GetIdentifierForProjectItem(IProjectItem projectItem) { return $"{projectItem.UniqueName}-{projectItem.Configuration}|{projectItem.Platform}"; } diff --git a/src/BuildVision/Helpers/ToolWindowManager.cs b/src/BuildVision/Helpers/ToolWindowManager.cs index fc1b0eeb..2d5f0756 100644 --- a/src/BuildVision/Helpers/ToolWindowManager.cs +++ b/src/BuildVision/Helpers/ToolWindowManager.cs @@ -5,6 +5,7 @@ using Microsoft.VisualStudio.Shell.Interop; using BuildVision.Core; using BuildVision.Tool; +using BuildVision.UI.Models; namespace BuildVision.Helpers { @@ -111,5 +112,28 @@ private static Window GetWindowInstance(DTE dte, Guid windowGuid) return null; } + + private void ApplyToolWindowStateAction(WindowState windowState) + { + switch (windowState) + { + case WindowState.Nothing: + break; + case WindowState.Show: + Show(); + break; + case WindowState.ShowNoActivate: + ShowNoActivate(); + break; + case WindowState.Hide: + Hide(); + break; + case WindowState.Close: + Close(); + break; + default: + throw new ArgumentOutOfRangeException(nameof(windowState)); + } + } } } diff --git a/src/BuildVision/Services/BuildInformationProvider.cs b/src/BuildVision/Services/BuildInformationProvider.cs index 9fd80dfd..a96f1367 100644 --- a/src/BuildVision/Services/BuildInformationProvider.cs +++ b/src/BuildVision/Services/BuildInformationProvider.cs @@ -1,13 +1,11 @@ using System; using System.ComponentModel.Composition; -using System.IO; using BuildVision.Contracts; using BuildVision.Contracts.Models; +using BuildVision.Exports; using BuildVision.Exports.Providers; -using BuildVision.Exports.Services; -using BuildVision.Tool.Building; +using BuildVision.Helpers; using BuildVision.Tool.Models; -using BuildVision.UI; using BuildVision.UI.Common.Logging; using EnvDTE; using EnvDTE80; @@ -20,25 +18,27 @@ namespace BuildVision.Core [PartCreationPolicy(CreationPolicy.Shared)] public class BuildInformationProvider : IBuildInformationProvider { - public BuildOutputLogger _buildLogger; - - private readonly Guid _parsingErrorsLoggerId = new Guid("{64822131-DC4D-4087-B292-61F7E06A7B39}"); private readonly IServiceProvider _serviceProvider; + private readonly IBuildOutputLogger _buildOutputLogger; + private Solution _solution; private BuildInformationModel _buildInformationModel; private BuildEvents _buildEvents; private DTE2 _dte; [ImportingConstructor] - public BuildInformationProvider([Import(typeof(SVsServiceProvider))] IServiceProvider serviceProvider) + public BuildInformationProvider( + [Import(typeof(SVsServiceProvider))] IServiceProvider serviceProvider, + [Import(typeof(IBuildOutputLogger))] IBuildOutputLogger buildOutputLogger) { _serviceProvider = serviceProvider; + _buildOutputLogger = buildOutputLogger; _buildInformationModel = new BuildInformationModel(); _buildEvents = (serviceProvider.GetService(typeof(DTE)) as DTE).Events.BuildEvents; - _buildEvents.OnBuildBegin += _buildEvents_OnBuildBegin; + _buildEvents.OnBuildBegin += BuildEvents_OnBuildBegin; } - private void _buildEvents_OnBuildBegin(vsBuildScope scope, vsBuildAction action) + private void BuildEvents_OnBuildBegin(vsBuildScope scope, vsBuildAction action) { _buildInformationModel.BuildScope = (BuildScopes) scope; // we need to set buildscope explictly because it is not possible to get this via the other api } @@ -50,7 +50,7 @@ public IBuildInformationModel GetBuildInformationModel() public void BuildStarted(uint dwAction) { - RegisterLogger(); + _buildOutputLogger.Attach(); _buildInformationModel.SucceededProjectsCount = 0; _buildInformationModel.FailedProjectsCount = 0; @@ -71,6 +71,35 @@ public void BuildStarted(uint dwAction) //VisualStudioSolution.StateMessage = _origTextCurrentState; // Set message } + private int GetProjectsCount(int projectsCount) + { + switch (_buildInformationModel.BuildScope) + { + case BuildScopes.BuildScopeSolution: + try + { + Solution solution = _dte.Solution; + if (solution != null) + projectsCount = _solution.GetProjects().Count; + } + catch (Exception ex) + { + ex.Trace("Unable to count projects in solution."); + } + + break; + + case BuildScopes.BuildScopeBatch: + case BuildScopes.BuildScopeProject: + break; + + default: + throw new ArgumentOutOfRangeException(nameof(_buildInformationModel.BuildScope)); + } + + return projectsCount; + } + public void BuildUpdate() { //_buildInformationModel.StateMessage = _origTextCurrentState + BuildMessages.GetBuildBeginExtraMessage(this, labelsSettings); @@ -113,15 +142,5 @@ public void BuildFinished(bool success, bool modified, bool canceled) else _buildInformationModel.CurrentBuildState = BuildState.Failed; } - - private void RegisterLogger() - { - _buildLogger = null; - RegisterLoggerResult result = BuildOutputLogger.Register(_parsingErrorsLoggerId, Microsoft.Build.Framework.LoggerVerbosity.Quiet, out _buildLogger); - if (result == RegisterLoggerResult.AlreadyExists) - { - _buildLogger.Projects?.Clear(); - } - } } } diff --git a/src/BuildVision/Services/BuildingProjectsProvider.cs b/src/BuildVision/Services/BuildingProjectsProvider.cs index 57a18a26..f492d82e 100644 --- a/src/BuildVision/Services/BuildingProjectsProvider.cs +++ b/src/BuildVision/Services/BuildingProjectsProvider.cs @@ -1,18 +1,17 @@ using System; using System.Collections.ObjectModel; using System.ComponentModel.Composition; +using System.Diagnostics; using System.Linq; using BuildVision.Common; using BuildVision.Contracts; -using BuildVision.Contracts.Models; +using BuildVision.Exports; using BuildVision.Exports.Providers; using BuildVision.Helpers; -using BuildVision.Tool.Building; -using BuildVision.Tool.Models; using BuildVision.UI.Common.Logging; +using BuildVision.UI.Contracts; using BuildVision.UI.Models; -using Microsoft.VisualStudio.Shell; -using Microsoft.VisualStudio.Shell.Interop; +using Microsoft.Build.Framework; namespace BuildVision.Core { @@ -20,23 +19,62 @@ namespace BuildVision.Core [PartCreationPolicy(CreationPolicy.Shared)] public class BuildingProjectsProvider : IBuildingProjectsProvider { - public BuildOutputLogger _buildLogger; - - private readonly Guid _parsingErrorsLoggerId = new Guid("{64822131-DC4D-4087-B292-61F7E06A7B39}"); - private readonly IServiceProvider _serviceProvider; private readonly ISolutionProvider _solutionProvider; private readonly IBuildInformationProvider _buildInformationProvider; - private ObservableCollection _projects; + private readonly IBuildOutputLogger _buildOutputLogger; + private ObservableCollection _projects; [ImportingConstructor] public BuildingProjectsProvider( [Import(typeof(ISolutionProvider))] ISolutionProvider solutionProvider, - [Import(typeof(IBuildInformationProvider))] IBuildInformationProvider buildInformationProvider) + [Import(typeof(IBuildInformationProvider))] IBuildInformationProvider buildInformationProvider, + [Import(typeof(IBuildOutputLogger))] IBuildOutputLogger buildOutputLogger) { - _projects = new ObservableCollection(); + _projects = new ObservableCollection(); _solutionProvider = solutionProvider; _buildInformationProvider = buildInformationProvider; + _buildOutputLogger = buildOutputLogger; + + _buildOutputLogger.OnErrorRaised += BuildOutputLogger_OnErrorRaised; + ReloadCurrentProjects(); + } + + private void BuildOutputLogger_OnErrorRaised(BuildProjectContextEntry projectEntry, object e, ErrorLevel errorLevel) + { + try + { + if (!TryGetProjectItem(projectEntry, out var projectItem)) + { + projectEntry.IsInvalid = true; + return; + } + + var errorItem = new ErrorItem(errorLevel); + switch (errorLevel) + { + case ErrorLevel.Message: + errorItem.Init((BuildMessageEventArgs) e); + break; + + case ErrorLevel.Warning: + errorItem.Init((BuildWarningEventArgs) e); + throw new ArgumentOutOfRangeException("errorLevel"); + case ErrorLevel.Error: + errorItem.Init((BuildErrorEventArgs) e); + break; + default: + errorItem.VerifyValues(); + break; + } + + projectItem.ErrorsBox.Add(errorItem); + //OnErrorRaised(this, new BuildErrorRaisedEventArgs(errorLevel, projectItem)); + } + catch (Exception ex) + { + ex.TraceUnknownException(); + } } public void ReloadCurrentProjects() @@ -45,28 +83,24 @@ public void ReloadCurrentProjects() _projects.AddRange(_solutionProvider.GetProjects()); } - public ObservableCollection GetBuildingProjects() + public ObservableCollection GetBuildingProjects() { return _projects; } - public void ProjectBuildStarted(IVsHierarchy pHierProj, IVsCfg pCfgProj, IVsCfg pCfgSln, uint dwAction) + public void ProjectBuildStarted(IProjectItem projectItem, uint dwAction) { try { - var projectItem = _projects.FirstOrDefault(item => ProjectIdentifierGenerator.GetIdentifierForProjectItem(item) == ProjectIdentifierGenerator.GetIdentifierForInteropTypes(pHierProj, pCfgProj)); - if (projectItem == null) + var projInCollection = _projects.FirstOrDefault(item => ProjectIdentifierGenerator.GetIdentifierForProjectItem(item) == ProjectIdentifierGenerator.GetIdentifierForProjectItem(projectItem)); + if(projInCollection == null) { - // In this case we are executing a batch build so we need to add the projectitem manually - projectItem = new UI.Models.ProjectItem(); - var configPair = pCfgProj.ToConfigurationTuple(); - SolutionProjectsExtensions.UpdateProperties(pHierProj.ToProject(), projectItem, configPair.Item1, configPair.Item2); _projects.Add(projectItem); + projInCollection = projectItem; } - - projectItem.State = GetProjectState(_buildInformationProvider.GetBuildInformationModel().BuildAction); - projectItem.BuildFinishTime = null; - projectItem.BuildStartTime = DateTime.Now; + projInCollection.State = GetProjectState(_buildInformationProvider.GetBuildInformationModel().BuildAction); + projInCollection.BuildFinishTime = null; + projInCollection.BuildStartTime = DateTime.Now; // _viewModel.OnBuildProjectBegin(); //if (BuildScope == BuildScopes.BuildScopeSolution && @@ -87,60 +121,43 @@ public void ProjectBuildStarted(IVsHierarchy pHierProj, IVsCfg pCfgProj, IVsCfg } } - private bool PlatformsIsEquals(string platformName1, string platformName2) + public bool TryGetProjectItem(BuildProjectContextEntry projectEntry, out IProjectItem projectItem) { - if (string.Compare(platformName1, platformName2, StringComparison.InvariantCultureIgnoreCase) == 0) + projectItem = projectEntry.ProjectItem; + if (projectItem != null) return true; - // The ambiguity between Project.ActiveConfiguration.PlatformName and - // ProjectStartedEventArgs.ProjectPlatform in Microsoft.Build.Utilities.Logger - // (see BuildOutputLogger). - bool isAnyCpu1 = (platformName1 == "Any CPU" || platformName1 == "AnyCPU"); - bool isAnyCpu2 = (platformName2 == "Any CPU" || platformName2 == "AnyCPU"); - if (isAnyCpu1 && isAnyCpu2) - return true; + string projectFile = projectEntry.FileName; + if (ProjectExtensions.IsProjectHidden(projectFile)) + return false; - return false; - } + var projectProperties = projectEntry.Properties; + var project = _projects.FirstOrDefault(x => x.FullName == projectFile); + + if (projectProperties.ContainsKey("Configuration") && projectProperties.ContainsKey("Platform")) + { + string projectConfiguration = projectProperties["Configuration"]; + string projectPlatform = projectProperties["Platform"]; + projectItem = _projects.First(item => $"{item.FullName}-{item.Configuration}|{item.Platform.Replace(" ","")}" == $"{projectFile}-{projectConfiguration}|{projectPlatform}"); + if (projectItem == null) + { + TraceManager.Trace( + string.Format("Project Item not found by: UniqueName='{0}', Configuration='{1}, Platform='{2}'.", + project.UniqueName, + projectConfiguration, + projectPlatform), + EventLogEntryType.Warning); + return false; + } + } + else + { + return false; + } - //public bool GetProjectItem(IBuildVisionPaneViewModel viewModel, BuildProjectContextEntry projectEntry, out ProjectItem projectItem) - //{ - // projectItem = projectEntry.ProjectItem; - // if (projectItem != null) - // return true; - - // string projectFile = projectEntry.FileName; - // if (ProjectExtensions.IsProjectHidden(projectFile)) - // return false; - - // var projectProperties = projectEntry.Properties; - // var project = viewModel.ProjectsList.FirstOrDefault(x => x.FullName == projectFile); - - - // if (projectProperties.ContainsKey("Configuration") && projectProperties.ContainsKey("Platform")) - // { - // string projectConfiguration = projectProperties["Configuration"]; - // string projectPlatform = projectProperties["Platform"]; - // projectItem = FindProjectItemInProjectsByUniqueName(viewModel, project.UniqueName, projectConfiguration, projectPlatform); - // if (projectItem == null) - // { - // TraceManager.Trace( - // string.Format("Project Item not found by: UniqueName='{0}', Configuration='{1}, Platform='{2}'.", - // project.UniqueName, - // projectConfiguration, - // projectPlatform), - // EventLogEntryType.Warning); - // return false; - // } - // } - // else - // { - // return false; - // } - - // projectEntry.ProjectItem = projectItem; - // return true; - //} + projectEntry.ProjectItem = projectItem; + return true; + } private ProjectState GetProjectState(BuildActions buildAction) { @@ -161,54 +178,43 @@ private ProjectState GetProjectState(BuildActions buildAction) } } - public void ProjectBuildFinished(IVsHierarchy pHierProj, IVsCfg pCfgProj, IVsCfg pCfgSln, bool succeess, bool canceled) + public void ProjectBuildFinished(string projectIdentifier, bool succeess, bool canceled) { - var currentProject = _projects.First(item => ProjectIdentifierGenerator.GetIdentifierForProjectItem(item) == ProjectIdentifierGenerator.GetIdentifierForInteropTypes(pHierProj, pCfgProj)); - currentProject.State = ProjectState.BuildDone; - //currentProject.Success = fSuccess == 1; - //ProjectState projectState; - //switch (SolutionBuildState.BuildAction) - //{ - // case BuildActions.BuildActionBuild: - // case BuildActions.BuildActionRebuildAll: - // if (currentProject.Success) - // { - // if (_viewModel.ControlSettings.GeneralSettings.ShowWarningSignForBuilds && buildedProject.ErrorsBox.WarningsCount > 0) - // projectState = ProjectState.BuildWarning; - // else - // { - // bool upToDate = (_buildLogger != null && _buildLogger.Projects != null - // && !_buildLogger.Projects.Exists(t => t.FileName == buildedProject.FileName)); - // if (upToDate) - // { - // // Because ErrorBox will be empty if project is UpToDate. - // buildedProject.ErrorsBox = currentProject.ErrorsBox; - // } - // projectState = upToDate ? ProjectState.UpToDate : ProjectState.BuildDone; - // } - // } - // else - // { - // bool canceled = (_buildCancelled && buildedProject.ErrorsBox.ErrorsCount == 0); - // projectState = canceled ? ProjectState.BuildCancelled : ProjectState.BuildError; - // } - // break; - - // case BuildActions.BuildActionClean: - // projectState = fSuccess == 1 ? ProjectState.CleanDone : ProjectState.CleanError; - // break; - - // case BuildActions.BuildActionDeploy: - // throw new InvalidOperationException("vsBuildActionDeploy not supported"); - - // default: - // throw new ArgumentOutOfRangeException(nameof(SolutionBuildState.BuildAction)); - //} + var currentProject = _projects.First(item => ProjectIdentifierGenerator.GetIdentifierForProjectItem(item) == projectIdentifier); + var buildAction = _buildInformationProvider.GetBuildInformationModel().BuildAction; + ProjectState projectState; + switch (buildAction) + { + case BuildActions.BuildActionBuild: + case BuildActions.BuildActionRebuildAll: + if (succeess) + { + if (currentProject.ErrorsBox.WarningsCount > 0) + projectState = ProjectState.BuildWarning; + else + { + projectState = _buildOutputLogger.IsProjectUpToDate(currentProject) ? ProjectState.UpToDate : ProjectState.BuildDone; + } + } + else + { + //bool canceled = (_buildCancelled && currentProject.ErrorsBox.ErrorsCount == 0); + projectState = canceled ? ProjectState.BuildCancelled : ProjectState.BuildError; + } + break; - //buildedProject.ProjectState = projectState; - //OnBuildProjectDone(new BuildProjectEventArgs(currentProject, projectState, eventTime, buildedProject)); + case BuildActions.BuildActionClean: + projectState = succeess ? ProjectState.CleanDone : ProjectState.CleanError; + break; - //Debug.WriteLine($"UpdateProjectCfg_Done {proj.UniqueName} ({projConfiguration}) ({slnConfiguration}"); + case BuildActions.BuildActionDeploy: + throw new InvalidOperationException("vsBuildActionDeploy not supported"); + + default: + throw new ArgumentOutOfRangeException(nameof(buildAction)); + } + currentProject.State = projectState; + //OnBuildProjectDone(new BuildProjectEventArgs(currentProject, projectState, eventTime, buildedProject)); //if (e.ProjectState == ProjectState.BuildError && _viewModel.ControlSettings.GeneralSettings.StopBuildAfterFirstError) // CancelBuildAsync(); diff --git a/src/BuildVision/Services/IBuildingProjectsProvider.cs b/src/BuildVision/Services/IBuildingProjectsProvider.cs deleted file mode 100644 index 13b8aa47..00000000 --- a/src/BuildVision/Services/IBuildingProjectsProvider.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Collections.ObjectModel; -using BuildVision.UI.Models; -using Microsoft.VisualStudio.Shell.Interop; - -namespace BuildVision.Core -{ - public interface IBuildingProjectsProvider - { - ObservableCollection GetBuildingProjects(); - void ProjectBuildFinished(IVsHierarchy pHierProj, IVsCfg pCfgProj, IVsCfg pCfgSln, bool succeess, bool canceled); - void ProjectBuildStarted(IVsHierarchy pHierProj, IVsCfg pCfgProj, IVsCfg pCfgSln, uint dwAction); - void ReloadCurrentProjects(); - } -} diff --git a/src/BuildVision/Services/ProjectFileNavigationService.cs b/src/BuildVision/Services/ProjectFileNavigationService.cs new file mode 100644 index 00000000..3acb451a --- /dev/null +++ b/src/BuildVision/Services/ProjectFileNavigationService.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using BuildVision.Contracts; +using BuildVision.Helpers; +using BuildVision.UI.Common.Logging; +using EnvDTE; +using Microsoft.VisualStudio.Shell; + +namespace BuildVision.Services +{ + public class ProjectFileNavigationService + { + private readonly IServiceProvider _serviceProvider; + + [ImportingConstructor] + public ProjectFileNavigationService([Import(typeof(SVsServiceProvider))] IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + } + + public bool NavigateToErrorItem(ErrorItem errorItem) + { + try + { + var dte = _serviceProvider.GetService(typeof(DTE)) as DTE; + var project = dte.Solution.GetProject(x => x.FileName == errorItem.ProjectFile); + + if (project == null) + throw new ArgumentNullException("project"); + + if (errorItem == null) + throw new ArgumentNullException("errorItem"); + + if (!errorItem.CanNavigateTo) + return false; + + if (string.IsNullOrEmpty(errorItem.File)) + return false; + + string fullPath; + + // Check if path is absolute. + if (Path.IsPathRooted(errorItem.File)) + { + // Foo VC++ projects errorItem.File contains full path. + fullPath = errorItem.File; + } + else + { + var projectItemFile = project.FindProjectItem(errorItem.File); + if (projectItemFile == null) + return false; + + fullPath = projectItemFile.Properties.GetPropertyOrDefault("FullPath"); + if (fullPath == null) + throw new KeyNotFoundException("FullPath property not found."); + } + + try + { + var window = project.DTE.ItemOperations.OpenFile(fullPath, EnvDTE.Constants.vsViewKindAny); + if (window == null) + throw new NullReferenceException("Associated window is null reference."); + + window.Activate(); + + var selection = (TextSelection) window.Selection; + selection.MoveToLineAndOffset(errorItem.LineNumber, errorItem.ColumnNumber); + selection.MoveToLineAndOffset(errorItem.EndLineNumber, errorItem.EndColumnNumber, true /*select text*/); + } + catch (Exception ex) + { + var msg = string.Format("Navigate to error item exception (fullPath='{0}').", fullPath); + ex.Trace(msg); + } + } + catch (Exception ex) + { + ex.Trace("Navigate to error item exception."); + } + + return true; + } + } +} diff --git a/src/BuildVision/Services/SolutionProvider.cs b/src/BuildVision/Services/SolutionProvider.cs index 2d78283a..844d8764 100644 --- a/src/BuildVision/Services/SolutionProvider.cs +++ b/src/BuildVision/Services/SolutionProvider.cs @@ -20,6 +20,7 @@ namespace BuildVision.Core public class SolutionProvider : ISolutionProvider { private readonly IServiceProvider _serviceProvider; + private Solution _solution; private SolutionModel _solutionModel; private DTE2 _dte; @@ -89,8 +90,10 @@ private void RefrehSolutionModel() } } - public IEnumerable GetProjects() + public IEnumerable GetProjects() { + if (_solution == null) + ReloadSolution(); return _solution.GetProjectItems(); } } diff --git a/src/BuildVision/Tool/Building/BuildContext.cs b/src/BuildVision/Tool/Building/BuildContext.cs deleted file mode 100644 index 7ae143f5..00000000 --- a/src/BuildVision/Tool/Building/BuildContext.cs +++ /dev/null @@ -1,206 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Controls; -using BuildVision.Common; -using BuildVision.Contracts; -using BuildVision.Core; -using BuildVision.Helpers; -using BuildVision.Tool.Models; -using BuildVision.UI.Common.Logging; -using BuildVision.UI.Contracts; -using BuildVision.UI.Extensions; -using BuildVision.UI.Helpers; -using BuildVision.UI.Models; -using BuildVision.UI.Settings.Models.ToolWindow; -using BuildVision.UI.ViewModels; -using EnvDTE; -using Microsoft.Build.Framework; -using Microsoft.VisualStudio; -using Microsoft.VisualStudio.Shell.Interop; -using ErrorItem = BuildVision.Contracts.ErrorItem; -using ProjectItem = BuildVision.UI.Models.ProjectItem; -using WindowState = BuildVision.UI.Models.WindowState; - -namespace BuildVision.Tool.Building -{ - public class BuildContext - { - private const string CancelBuildCommand = "Build.Cancel"; - private CancellationTokenSource _buildProcessCancellationToken; - private readonly BuildVisionPaneViewModel _viewModel; - private bool _buildCancelled; - - public async Task CancelBuildAsync() - { - //if (BuildAction == BuildActions.BuildActionClean) - // return; - //if (CurrentBuildState != BuildState.InProgress || _buildCancelled || _buildCancelledInternally) - // return; - - //try - //{ - // // We need to create a separate task here because of some weird things that are going on - // // when calling ExecuteCommand directly. Directly calling it leads to a freeze. No need - // // for that! - // await _packageContext.ExecuteCommandAsync(CancelBuildCommand); - // _buildCancelledInternally = true; - //} - //catch (Exception ex) - //{ - // ex.Trace("Cancel build failed."); - //} - } - - private void CommandEvents_AfterExecute(string guid, int id, object customIn, object customOut) - { - if (id == (int) VSConstants.VSStd97CmdID.CancelBuild - && Guid.Parse(guid) == VSConstants.GUID_VSStandardCommandSet97) - { - //_buildCancelled = true; - //if (!_buildCancelledInternally) - // OnBuildCancelled(); - } - } - - private int GetProjectsCount(int projectsCount) - { - // TODO need to figure out how to get building projectscount - //switch (BuildScope) - //{ - // case BuildScopes.BuildScopeSolution: - // if (_viewModel.ControlSettings.GeneralSettings.FillProjectListOnBuildBegin) - // { - // projectsCount = _viewModel.ProjectsList.Count; - // } - // else - // { - // try - // { - // Solution solution = _dte.Solution; - // if (solution != null) - // projectsCount = solution.GetProjects().Count; - // } - // catch (Exception ex) - // { - // ex.Trace("Unable to count projects in solution."); - // } - // } - // break; - - // case BuildScopes.BuildScopeBatch: - // case BuildScopes.BuildScopeProject: - // break; - - // default: - // throw new ArgumentOutOfRangeException(nameof(BuildScope)); - //} - - return projectsCount; - } - - private void ApplyWindowState(UI.Settings.Models.ControlSettings settings) - { - // Figure out when build is canceled - //int errorProjectsCount = _viewModel.ProjectsList.Count(item => item.State.IsErrorState()); - //if (errorProjectsCount > 0 || BuildIsCancelled) - // ApplyToolWindowStateAction(settings.WindowSettings.WindowActionOnBuildError); - //else - // ApplyToolWindowStateAction(settings.WindowSettings.WindowActionOnBuildSuccess); - } - - private void NavigateToBuildErrorIfNeeded(UI.Settings.Models.ControlSettings settings) - { - // How to get errors that happend during build? - //bool navigateToBuildFailureReason = (!BuildedProjects.BuildWithoutErrors - // && settings.GeneralSettings.NavigateToBuildFailureReason == NavigateToBuildFailureReasonCondition.OnBuildDone); - //if (navigateToBuildFailureReason && BuildedProjects.Any(p => p.ErrorsBox.Errors.Any(NavigateToErrorItem))) - //{ - // _buildErrorIsNavigated = true; - //} - } - - private void SetFinalStateForUnfinishedProjects() - { - // What happens if project only is builded? What do we do with the projectslist - //if (BuildScope == BuildScopes.BuildScopeSolution) - //{ - // foreach (var projectItem in _viewModel.ProjectsList) - // { - // if (projectItem.State == ProjectState.Pending) - // projectItem.State = ProjectState.Skipped; - // } - //} - } - - private async void OnErrorRaised(object sender, BuildErrorRaisedEventArgs args) - { - //bool buildNeedToCancel = (args.ErrorLevel == ErrorLevel.Error && _viewModel.ControlSettings.GeneralSettings.StopBuildAfterFirstError); - //if (buildNeedToCancel) - // await CancelBuildAsync(); - - //bool navigateToBuildFailureReason = (!_buildErrorIsNavigated - // && args.ErrorLevel == ErrorLevel.Error - // && _viewModel.ControlSettings.GeneralSettings.NavigateToBuildFailureReason == NavigateToBuildFailureReasonCondition.OnErrorRaised); - //if (navigateToBuildFailureReason && args.ProjectInfo.ErrorsBox.Errors.Any(NavigateToErrorItem)) - //{ - // _buildErrorIsNavigated = true; - //} - } - - private bool NavigateToErrorItem(ErrorItem errorItem) - { - return false; - //if (string.IsNullOrEmpty(errorItem?.File) || string.IsNullOrEmpty(errorItem?.ProjectFile)) - // return false; - - //try - //{ - // var projectItem = _viewModel.ProjectsList.FirstOrDefault(x => x.FullName == errorItem.ProjectFile); - // if (projectItem == null) - // return false; - - - // var project = _dte.Solution.GetProject(x => x.UniqueName == projectItem.UniqueName); - // if (project == null) - // return false; - - // return project.NavigateToErrorItem(errorItem); - //} - //catch (Exception ex) - //{ - // ex.Trace("Navigate to error item exception"); - // return true; - //} - } - - private void ApplyToolWindowStateAction(WindowStateAction windowStateAction) - { - //switch (windowStateAction.State) - //{ - // case WindowState.Nothing: - // break; - // case WindowState.Show: - // _toolWindowManager.Show(); - // break; - // case WindowState.ShowNoActivate: - // _toolWindowManager.ShowNoActivate(); - // break; - // case WindowState.Hide: - // _toolWindowManager.Hide(); - // break; - // case WindowState.Close: - // _toolWindowManager.Close(); - // break; - // default: - // throw new ArgumentOutOfRangeException(nameof(windowStateAction)); - //} - } - } -} diff --git a/src/BuildVision/Tool/Building/BuildManager.cs b/src/BuildVision/Tool/Building/BuildManager.cs index b9a57662..b4332002 100644 --- a/src/BuildVision/Tool/Building/BuildManager.cs +++ b/src/BuildVision/Tool/Building/BuildManager.cs @@ -5,6 +5,7 @@ using System.ComponentModel.Composition; using System.IO; using System.Linq; +using System.Threading; using System.Threading.Tasks; using System.Windows; using BuildVision.Common; @@ -24,6 +25,10 @@ namespace BuildVision.Tool.Building [PartCreationPolicy(CreationPolicy.NonShared)] public class BuildManager : IBuildService { + private const string CancelBuildCommand = "Build.Cancel"; + private CancellationTokenSource _buildProcessCancellationToken; + private bool _buildCancelled; + public BuildManager() { //_viewModel.RaiseCommandForSelectedProject += RaiseCommandForSelectedProject; @@ -89,57 +94,57 @@ public void RaiseCommandForSelectedProject(UI.Models.ProjectItem selectedProject private void SelectProjectInSolutionExplorer(UI.Models.ProjectItem projectItem) { - var solutionExplorer = Services.Dte2.ToolWindows.SolutionExplorer; - var project = Services.Dte2.Solution.GetProject(x => x.UniqueName == projectItem.UniqueName); - var item = solutionExplorer.FindHierarchyItem(project); - if (item == null) - throw new ProjectNotFoundException($"Project '{projectItem.UniqueName}' not found in SolutionExplorer."); - solutionExplorer.Parent.Activate(); - item.Select(vsUISelectionType.vsUISelectionTypeSelect); + //var solutionExplorer = Services.Dte2.ToolWindows.SolutionExplorer; + //var project = Services.Dte2.Solution.GetProject(x => x.UniqueName == projectItem.UniqueName); + //var item = solutionExplorer.FindHierarchyItem(project); + //if (item == null) + // throw new ProjectNotFoundException($"Project '{projectItem.UniqueName}' not found in SolutionExplorer."); + //solutionExplorer.Parent.Activate(); + //item.Select(vsUISelectionType.vsUISelectionTypeSelect); } private void ProjectCopyBuildOutputFilesToClipBoard(UI.Models.ProjectItem projItem) { try { - Project project = Services.Dte.Solution.GetProject(x => x.UniqueName == projItem.UniqueName); - BuildOutputFileTypes fileTypes = null; //_packageContext.ControlSettings.ProjectItemSettings.CopyBuildOutputFileTypesToClipboard; - if (fileTypes.IsEmpty) - { - MessageBox.Show(@"Nothing to copy: all file types unchecked.", Resources.ProductName, MessageBoxButton.OK, MessageBoxImage.Error); - return; - } - - string[] filePaths = project.GetBuildOutputFilePaths(fileTypes, projItem.Configuration, projItem.Platform).ToArray(); - if (filePaths.Length == 0) - { - MessageBox.Show(@"Nothing copied: selected build output groups are empty.", Resources.ProductName, MessageBoxButton.OK, MessageBoxImage.Information); - return; - } - - string[] existFilePaths = filePaths.Where(File.Exists).ToArray(); - if (existFilePaths.Length == 0) - { - string msg = GetCopyBuildOutputFilesToClipboardActionMessage("Nothing copied. {0} wasn't found{1}", filePaths); - MessageBox.Show(msg, Resources.ProductName, MessageBoxButton.OK, MessageBoxImage.Warning); - return; - } - - CopyFiles(existFilePaths); - - if (existFilePaths.Length == filePaths.Length) - { - string msg = GetCopyBuildOutputFilesToClipboardActionMessage("Copied {0}{1}", existFilePaths); - MessageBox.Show(msg, Resources.ProductName, MessageBoxButton.OK, MessageBoxImage.Information); - } - else - { - string[] notExistFilePaths = filePaths.Except(existFilePaths).ToArray(); - string copiedMsg = GetCopyBuildOutputFilesToClipboardActionMessage("Copied {0}{1}", existFilePaths); - string notFoundMsg = GetCopyBuildOutputFilesToClipboardActionMessage("{0} wasn't found{1}", notExistFilePaths); - string msg = string.Concat(copiedMsg, Environment.NewLine, Environment.NewLine, notFoundMsg); - MessageBox.Show(msg, Resources.ProductName, MessageBoxButton.OK, MessageBoxImage.Warning); - } + //Project project = Services.Dte.Solution.GetProject(x => x.UniqueName == projItem.UniqueName); + //BuildOutputFileTypes fileTypes = null; //_packageContext.ControlSettings.ProjectItemSettings.CopyBuildOutputFileTypesToClipboard; + //if (fileTypes.IsEmpty) + //{ + // MessageBox.Show(@"Nothing to copy: all file types unchecked.", Resources.ProductName, MessageBoxButton.OK, MessageBoxImage.Error); + // return; + //} + + //string[] filePaths = project.GetBuildOutputFilePaths(fileTypes, projItem.Configuration, projItem.Platform).ToArray(); + //if (filePaths.Length == 0) + //{ + // MessageBox.Show(@"Nothing copied: selected build output groups are empty.", Resources.ProductName, MessageBoxButton.OK, MessageBoxImage.Information); + // return; + //} + + //string[] existFilePaths = filePaths.Where(File.Exists).ToArray(); + //if (existFilePaths.Length == 0) + //{ + // string msg = GetCopyBuildOutputFilesToClipboardActionMessage("Nothing copied. {0} wasn't found{1}", filePaths); + // MessageBox.Show(msg, Resources.ProductName, MessageBoxButton.OK, MessageBoxImage.Warning); + // return; + //} + + //CopyFiles(existFilePaths); + + //if (existFilePaths.Length == filePaths.Length) + //{ + // string msg = GetCopyBuildOutputFilesToClipboardActionMessage("Copied {0}{1}", existFilePaths); + // MessageBox.Show(msg, Resources.ProductName, MessageBoxButton.OK, MessageBoxImage.Information); + //} + //else + //{ + // string[] notExistFilePaths = filePaths.Except(existFilePaths).ToArray(); + // string copiedMsg = GetCopyBuildOutputFilesToClipboardActionMessage("Copied {0}{1}", existFilePaths); + // string notFoundMsg = GetCopyBuildOutputFilesToClipboardActionMessage("{0} wasn't found{1}", notExistFilePaths); + // string msg = string.Concat(copiedMsg, Environment.NewLine, Environment.NewLine, notFoundMsg); + // MessageBox.Show(msg, Resources.ProductName, MessageBoxButton.OK, MessageBoxImage.Warning); + //} } catch (Win32Exception ex) { @@ -190,7 +195,7 @@ private void RaiseCommand(VSConstants.VSStd97CmdID command) { object customIn = null; object customOut = null; - Services.Dte.Commands.Raise(VSConstants.GUID_VSStandardCommandSet97.ToString(), (int) command, ref customIn, ref customOut); + //Services.Dte.Commands.Raise(VSConstants.GUID_VSStandardCommandSet97.ToString(), (int) command, ref customIn, ref customOut); } catch (Exception ex) { @@ -213,9 +218,56 @@ public void ProjectCopyBuildOutputFilesToClipBoard() throw new NotImplementedException(); } + private void CommandEvents_AfterExecute(string guid, int id, object customIn, object customOut) + { + if (id == (int) VSConstants.VSStd97CmdID.CancelBuild + && Guid.Parse(guid) == VSConstants.GUID_VSStandardCommandSet97) + { + //_buildCancelled = true; + //if (!_buildCancelledInternally) + // OnBuildCancelled(); + } + } + + private void ApplyWindowState(UI.Settings.Models.ControlSettings settings) + { + // Figure out when build is canceled + //int errorProjectsCount = _viewModel.ProjectsList.Count(item => item.State.IsErrorState()); + //if (errorProjectsCount > 0 || BuildIsCancelled) + // ApplyToolWindowStateAction(settings.WindowSettings.WindowActionOnBuildError); + //else + // ApplyToolWindowStateAction(settings.WindowSettings.WindowActionOnBuildSuccess); + } + public void RaiseCommandForSelectedProject() { throw new NotImplementedException(); } + + private void NavigateToBuildErrorIfNeeded(UI.Settings.Models.ControlSettings settings) + { + // How to get errors that happend during build? + //bool navigateToBuildFailureReason = (!BuildedProjects.BuildWithoutErrors + // && settings.GeneralSettings.NavigateToBuildFailureReason == NavigateToBuildFailureReasonCondition.OnBuildDone); + //if (navigateToBuildFailureReason && BuildedProjects.Any(p => p.ErrorsBox.Errors.Any(NavigateToErrorItem))) + //{ + // _buildErrorIsNavigated = true; + //} + } + + private async void OnErrorRaised(object sender, BuildErrorRaisedEventArgs args) + { + //bool buildNeedToCancel = (args.ErrorLevel == ErrorLevel.Error && _viewModel.ControlSettings.GeneralSettings.StopBuildAfterFirstError); + //if (buildNeedToCancel) + // await CancelBuildAsync(); + + //bool navigateToBuildFailureReason = (!_buildErrorIsNavigated + // && args.ErrorLevel == ErrorLevel.Error + // && _viewModel.ControlSettings.GeneralSettings.NavigateToBuildFailureReason == NavigateToBuildFailureReasonCondition.OnErrorRaised); + //if (navigateToBuildFailureReason && args.ProjectInfo.ErrorsBox.Errors.Any(NavigateToErrorItem)) + //{ + // _buildErrorIsNavigated = true; + //} + } } } diff --git a/src/BuildVision/Tool/Building/BuildOutputLogger.cs b/src/BuildVision/Tool/Building/BuildOutputLogger.cs index 307f7de2..b4cd5b30 100644 --- a/src/BuildVision/Tool/Building/BuildOutputLogger.cs +++ b/src/BuildVision/Tool/Building/BuildOutputLogger.cs @@ -9,19 +9,26 @@ using BuildVision.UI.Common.Logging; using BuildVision.Helpers; using System.Diagnostics; +using BuildVision.Core; +using BuildVision.Exports.Providers; +using BuildVision.UI.Models; +using BuildVision.Exports; namespace BuildVision.Tool.Building { - public class BuildOutputLogger : Logger + public class BuildOutputLogger : Logger, IBuildOutputLogger { - private List _projects; - private readonly Guid _id; + private readonly Guid _loggerId; + private readonly LoggerVerbosity _loggerVerbosity; - public List Projects => _projects; + public RegisterLoggerResult LoggerState { get; set; } - private BuildOutputLogger(Guid id) + private List _projects = new List(); + + public BuildOutputLogger(Guid loggerId, LoggerVerbosity loggerVerbosity) { - _id = id; + _loggerId = loggerId; + _loggerVerbosity = loggerVerbosity; } public override void Initialize(IEventSource eventSource) @@ -42,17 +49,18 @@ private void OnProjectStarted(object sender, ProjectStartedEventArgs e) e.GlobalProperties)); } - public static RegisterLoggerResult Register(Guid loggerId, LoggerVerbosity loggerVerbosity, out BuildOutputLogger buildLogger) + public void Attach() { try { + _projects.Clear(); + const BindingFlags InterfacePropertyFlags = BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Instance; - var buildManager = Microsoft.Build.Execution.BuildManager.DefaultBuildManager; - Type buildHostType = buildManager.GetType().Assembly.GetType("Microsoft.Build.BackEnd.IBuildComponentHost"); - PropertyInfo loggingSeviceProperty = buildHostType.GetProperty("LoggingService", InterfacePropertyFlags); + var buildHostType = buildManager.GetType().Assembly.GetType("Microsoft.Build.BackEnd.IBuildComponentHost"); + var loggingSeviceProperty = buildHostType.GetProperty("LoggingService", InterfacePropertyFlags); object loggingServiceObj; try @@ -63,35 +71,36 @@ public static RegisterLoggerResult Register(Guid loggerId, LoggerVerbosity logge catch (TargetInvocationException ex) { ex.Trace("Microsoft.Build.BackEnd.ILoggingService is not available."); - buildLogger = null; - return RegisterLoggerResult.FatalError; + LoggerState = RegisterLoggerResult.FatalError; + return; } - PropertyInfo loggersProperty = loggingServiceObj.GetType().GetProperty("Loggers", InterfacePropertyFlags); - ICollection loggers = (ICollection)loggersProperty.GetValue(loggingServiceObj, null); + var loggersProperty = loggingServiceObj.GetType().GetProperty("Loggers", InterfacePropertyFlags); + var loggers = (ICollection) loggersProperty.GetValue(loggingServiceObj, null); - ILogger logger = loggers.FirstOrDefault(x => x is BuildOutputLogger && ((BuildOutputLogger)x)._id.Equals(loggerId)); + var logger = loggers.FirstOrDefault(x => x is BuildOutputLogger && ((BuildOutputLogger) x)._loggerId.Equals(_loggerId)); if (logger != null) { - buildLogger = (BuildOutputLogger)logger; - buildLogger.Verbosity = loggerVerbosity; - return RegisterLoggerResult.AlreadyExists; + LoggerState = RegisterLoggerResult.AlreadyExists; + return; } - MethodInfo registerLoggerMethod = loggingServiceObj.GetType().GetMethod("RegisterLogger"); - buildLogger = new BuildOutputLogger(loggerId) { Verbosity = loggerVerbosity }; - bool registerResult = (bool)registerLoggerMethod.Invoke(loggingServiceObj, new object[] { buildLogger }); - - return registerResult ? RegisterLoggerResult.RegisterSuccess : RegisterLoggerResult.RegisterFailed; + var registerLoggerMethod = loggingServiceObj.GetType().GetMethod("RegisterLogger"); + var registerResult = (bool) registerLoggerMethod.Invoke(loggingServiceObj, new object[] { this }); + LoggerState = registerResult ? RegisterLoggerResult.RegisterSuccess : RegisterLoggerResult.RegisterFailed; } catch (Exception ex) { ex.TraceUnknownException(); - buildLogger = null; - return RegisterLoggerResult.FatalError; + LoggerState = RegisterLoggerResult.FatalError; } } + public bool IsProjectUpToDate(IProjectItem projectItem) + { + return !_projects.Exists(t => t.FileName == projectItem.FullName); + } + private void EventSource_ErrorRaised(object sender, BuildEventArgs e, ErrorLevel errorLevel) { try @@ -103,7 +112,7 @@ private void EventSource_ErrorRaised(object sender, BuildEventArgs e, ErrorLevel int projectInstanceId = e.BuildEventContext.ProjectInstanceId; int projectContextId = e.BuildEventContext.ProjectContextId; - var projectEntry = Projects.Find(t => t.InstanceId == projectInstanceId && t.ContextId == projectContextId); + var projectEntry = _projects.Find(t => t.InstanceId == projectInstanceId && t.ContextId == projectContextId); if (projectEntry == null) { TraceManager.Trace(string.Format("Project entry not found by ProjectInstanceId='{0}' and ProjectContextId='{1}'.", projectInstanceId, projectContextId), EventLogEntryType.Warning); @@ -112,38 +121,7 @@ private void EventSource_ErrorRaised(object sender, BuildEventArgs e, ErrorLevel if (projectEntry.IsInvalid) return; - //if (!_locatorService.GetProjectItem(_viewModel, BuildScope, projectEntry, out var projectItem)) - //{ - // projectEntry.IsInvalid = true; - // return; - //} - - //BuildedProject buildedProject = BuildedProjects[projectItem]; - //var errorItem = new ErrorItem(errorLevel, (eI) => - //{ - // Services.Dte.Solution.GetProject(x => x.UniqueName == projectItem.UniqueName).NavigateToErrorItem(eI); - //}); - - //switch (errorLevel) - //{ - // case ErrorLevel.Message: - // errorItem.Init((BuildMessageEventArgs) e); - // break; - - // case ErrorLevel.Warning: - // errorItem.Init((BuildWarningEventArgs) e); - // throw new ArgumentOutOfRangeException("errorLevel"); - //} - //errorItem.VerifyValues(); - // break; - - // case ErrorLevel.Error: - // errorItem.Init((BuildErrorEventArgs) e); - // break; - - // default: - //buildedProject.ErrorsBox.Add(errorItem); - //OnErrorRaised(this, new BuildErrorRaisedEventArgs(errorLevel, buildedProject)); + OnErrorRaised(projectEntry, e, errorLevel); } catch (Exception ex) { @@ -165,5 +143,12 @@ private bool VerifyLoggerBuildEvent(BuildEventArgs eventArgs, ErrorLevel errorLe return true; } + + public void Reset() + { + _projects.Clear(); + } + + public event Action OnErrorRaised; } } diff --git a/src/BuildVision/Tool/Views/Settings/SettingsDialogPage.cs b/src/BuildVision/Tool/Views/Settings/SettingsDialogPage.cs index 809f3fb4..5a5c2073 100644 --- a/src/BuildVision/Tool/Views/Settings/SettingsDialogPage.cs +++ b/src/BuildVision/Tool/Views/Settings/SettingsDialogPage.cs @@ -38,7 +38,7 @@ protected override void OnActivate(CancelEventArgs e) if (_ctrl.DataContext == null) _ctrl.DataContext = _editSettings; - _packageSettingsProvider = Services.DefaultExportProvider.GetExportedValue(); + //_packageSettingsProvider = Services.DefaultExportProvider.GetExportedValue(); base.OnActivate(e); } From f4ccea49099f1dd1df17cb538b05b1d3db888e73 Mon Sep 17 00:00:00 2001 From: Stefan Kert Date: Sat, 16 Mar 2019 12:46:03 +0100 Subject: [PATCH 012/100] Moved some controls and components to separate classes --- .../BuildVision.Contracts.csproj | 1 + .../Models/IBuildInformationModel.cs | 1 - .../Models/IBuildProgressViewModel.cs | 16 + src/BuildVision.UI/App.xaml | 1 + src/BuildVision.UI/BuildVision.UI.csproj | 40 +- .../Components/ControlHeader.xaml | 391 ------------------ .../Components/ControlView.xaml | 184 ++++++++- .../Components/ControlView.xaml.cs | 10 +- .../Controls/BuildVisionProgressBar.xaml | 73 ++++ .../BuildVisionProgressBar.xaml.cs} | 8 +- .../Controls/Buttons/BuildSolutionButton.cs | 13 + .../Controls/Buttons/Buttons.Test.xaml | 22 + .../Controls/Buttons/CancelButton.cs | 13 + .../Controls/Buttons/CleanSolutionButton.cs | 13 + .../Controls/Buttons/RebuildSolutionButton.cs | 13 + .../Indicators/ErrorProjectsIndicator.cs | 15 + .../Controls/Indicators/ErrorsIndicator.cs | 12 + .../Controls/Indicators/Indicators.Test.xaml | 28 ++ .../Controls/Indicators/MessagesIndicator.cs | 12 + .../Indicators/SuccessProjectsIndicator.cs | 12 + .../Indicators/UpToDateProjectsIndicator.cs | 12 + .../Controls/Indicators/ValueIndicator.cs | 38 ++ .../Indicators/WarningProjectsIndicator.cs | 12 + .../Controls/Indicators/WarningsIndicator.cs | 12 + .../Models/BuildInformationModel.cs | 2 +- .../Resources/BuildAction.Resources.Test.xaml | 9 +- .../Resources/BuildAction.Resources.xaml | 32 +- .../ValueIndicator.Resources.Test.xaml | 14 +- .../Resources/ValueIndicator.Resources.xaml | 14 +- src/BuildVision.UI/Themes/Generic.xaml | 259 ++++++++++++ .../ViewModels/BuildProgressViewModel.cs | 3 +- .../ViewModels/BuildVisionPaneViewModel.cs | 10 +- src/BuildVision/BuildVision.csproj | 2 +- src/BuildVision/Core/BuildVisionPackage.cs | 12 - src/BuildVision/Core/BuildVisionPane.cs | 132 ++++++ .../Core/ServiceProviderPackage.cs | 8 + .../Helpers/PropertiesExtensions.cs | 3 +- .../Services/BuildInformationProvider.cs | 1 + src/BuildVision/Tool/BuildVisionPane.cs | 106 ----- 39 files changed, 976 insertions(+), 583 deletions(-) create mode 100644 src/BuildVision.Contracts/Models/IBuildProgressViewModel.cs delete mode 100644 src/BuildVision.UI/Components/ControlHeader.xaml create mode 100644 src/BuildVision.UI/Controls/BuildVisionProgressBar.xaml rename src/BuildVision.UI/{Components/ControlHeader.xaml.cs => Controls/BuildVisionProgressBar.xaml.cs} (71%) create mode 100644 src/BuildVision.UI/Controls/Buttons/BuildSolutionButton.cs create mode 100644 src/BuildVision.UI/Controls/Buttons/Buttons.Test.xaml create mode 100644 src/BuildVision.UI/Controls/Buttons/CancelButton.cs create mode 100644 src/BuildVision.UI/Controls/Buttons/CleanSolutionButton.cs create mode 100644 src/BuildVision.UI/Controls/Buttons/RebuildSolutionButton.cs create mode 100644 src/BuildVision.UI/Controls/Indicators/ErrorProjectsIndicator.cs create mode 100644 src/BuildVision.UI/Controls/Indicators/ErrorsIndicator.cs create mode 100644 src/BuildVision.UI/Controls/Indicators/Indicators.Test.xaml create mode 100644 src/BuildVision.UI/Controls/Indicators/MessagesIndicator.cs create mode 100644 src/BuildVision.UI/Controls/Indicators/SuccessProjectsIndicator.cs create mode 100644 src/BuildVision.UI/Controls/Indicators/UpToDateProjectsIndicator.cs create mode 100644 src/BuildVision.UI/Controls/Indicators/ValueIndicator.cs create mode 100644 src/BuildVision.UI/Controls/Indicators/WarningProjectsIndicator.cs create mode 100644 src/BuildVision.UI/Controls/Indicators/WarningsIndicator.cs create mode 100644 src/BuildVision.UI/Themes/Generic.xaml create mode 100644 src/BuildVision/Core/BuildVisionPane.cs delete mode 100644 src/BuildVision/Tool/BuildVisionPane.cs diff --git a/src/BuildVision.Contracts/BuildVision.Contracts.csproj b/src/BuildVision.Contracts/BuildVision.Contracts.csproj index d33ee879..9b1a02b5 100644 --- a/src/BuildVision.Contracts/BuildVision.Contracts.csproj +++ b/src/BuildVision.Contracts/BuildVision.Contracts.csproj @@ -66,6 +66,7 @@ + diff --git a/src/BuildVision.Contracts/Models/IBuildInformationModel.cs b/src/BuildVision.Contracts/Models/IBuildInformationModel.cs index fbe28403..78bf0bcd 100644 --- a/src/BuildVision.Contracts/Models/IBuildInformationModel.cs +++ b/src/BuildVision.Contracts/Models/IBuildInformationModel.cs @@ -18,7 +18,6 @@ public interface IBuildInformationModel int UpToDateProjectsCount { get; set; } int WarnedProjectsCount { get; set; } int WarningsCount { get; set; } - BuildResultState GetBuildState(); } } diff --git a/src/BuildVision.Contracts/Models/IBuildProgressViewModel.cs b/src/BuildVision.Contracts/Models/IBuildProgressViewModel.cs new file mode 100644 index 00000000..842d1f58 --- /dev/null +++ b/src/BuildVision.Contracts/Models/IBuildProgressViewModel.cs @@ -0,0 +1,16 @@ +namespace BuildVision.Contracts.Models +{ + public interface IBuildProgressViewModel + { + bool ActionProgressIsPaused { get; set; } + bool ActionProgressIsVisible { get; set; } + int CurrentQueuePosOfBuildingProject { get; } + + void OnBuildBegin(int projectsCount); + void OnBuildCancelled(); + void OnBuildDone(); + void OnBuildProjectBegin(); + void OnBuildProjectDone(bool success); + void ResetTaskBarInfo(bool ifTaskBarProgressEnabled = true); + } +} diff --git a/src/BuildVision.UI/App.xaml b/src/BuildVision.UI/App.xaml index 8de566f6..a6f67004 100644 --- a/src/BuildVision.UI/App.xaml +++ b/src/BuildVision.UI/App.xaml @@ -6,6 +6,7 @@ + diff --git a/src/BuildVision.UI/BuildVision.UI.csproj b/src/BuildVision.UI/BuildVision.UI.csproj index 4b28ecac..5d725b9e 100644 --- a/src/BuildVision.UI/BuildVision.UI.csproj +++ b/src/BuildVision.UI/BuildVision.UI.csproj @@ -73,6 +73,21 @@ App.xaml Code + + BuildVisionProgressBar.xaml + + + + + + + + + + + + + @@ -84,9 +99,6 @@ - - ControlHeader.xaml - ErrorsGrid.xaml @@ -208,10 +220,6 @@ - - Designer - MSBuild:Compile - MSBuild:Compile Designer @@ -228,6 +236,20 @@ MSBuild:Compile Designer + + Designer + MSBuild:Compile + + + MSBuild:Compile + Designer + Always + + + MSBuild:Compile + Designer + Always + Designer MSBuild:Compile @@ -343,6 +365,10 @@ MSBuild:Compile Designer + + MSBuild:Compile + Designer + diff --git a/src/BuildVision.UI/Components/ControlHeader.xaml b/src/BuildVision.UI/Components/ControlHeader.xaml deleted file mode 100644 index c12648b8..00000000 --- a/src/BuildVision.UI/Components/ControlHeader.xaml +++ /dev/null @@ -1,391 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/BuildVision.UI/Components/ControlView.xaml b/src/BuildVision.UI/Components/ControlView.xaml index 04cf0d81..d6a48c2b 100644 --- a/src/BuildVision.UI/Components/ControlView.xaml +++ b/src/BuildVision.UI/Components/ControlView.xaml @@ -5,11 +5,13 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:res="clr-namespace:BuildVision.UI" xmlns:views="clr-namespace:BuildVision.UI" - xmlns:components="clr-namespace:BuildVision.UI.Components" xmlns:viewModels="clr-namespace:BuildVision.UI.ViewModels" xmlns:extensions="clr-namespace:BuildVision.UI.Extensions" xmlns:helpers="clr-namespace:BuildVision.UI.Helpers" xmlns:contracts="clr-namespace:BuildVision.Contracts;assembly=BuildVision.Contracts" + xmlns:customButtons="clr-namespace:BuildVision.UI.Controls.Buttons" + xmlns:indicators="clr-namespace:BuildVision.UI.Controls.Indicators" + xmlns:controls="clr-namespace:BuildVision.UI.Controls" mc:Ignorable="d" Name="OwnerUserControl" Background="{DynamicResource ToolWindowBackgroundKey}" @@ -28,6 +30,7 @@ + @@ -39,14 +42,14 @@ - - + @@ -101,15 +104,170 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -214,7 +372,7 @@ - + diff --git a/src/BuildVision.UI/Components/ControlView.xaml.cs b/src/BuildVision.UI/Components/ControlView.xaml.cs index 6d1f27af..1d4101ec 100644 --- a/src/BuildVision.UI/Components/ControlView.xaml.cs +++ b/src/BuildVision.UI/Components/ControlView.xaml.cs @@ -34,7 +34,7 @@ public ControlView() // By default, WPF uses en-US as the culture, regardless of the system settings. Language = XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag); - Grid.TargetUpdated += GridOnTargetUpdated; + //Grid.TargetUpdated += GridOnTargetUpdated; } private void GridOnTargetUpdated(object sender, DataTransferEventArgs e) @@ -45,9 +45,9 @@ private void GridOnTargetUpdated(object sender, DataTransferEventArgs e) private void RefreshSortDirectionInGrid() { - DataGridColumn dataGridColumn = Grid.Columns.FirstOrDefault(col => col.GetBindedProperty() == _viewModel.GridSortDescription.Property); - if (dataGridColumn != null) - dataGridColumn.SortDirection = _viewModel.GridSortDescription.Order.ToSystem(); + //DataGridColumn dataGridColumn = Grid.Columns.FirstOrDefault(col => col.GetBindedProperty() == _viewModel.GridSortDescription.Property); + //if (dataGridColumn != null) + // dataGridColumn.SortDirection = _viewModel.GridSortDescription.Order.ToSystem(); } private void GridOnSorting(object sender, DataGridSortingEventArgs e) @@ -61,7 +61,7 @@ private void OnDataContextChanged(object sender, DependencyPropertyChangedEventA Debug.Assert(DataContext != null); _viewModel = (BuildVisionPaneViewModel)DataContext; - _viewModel.SetGridColumnsRef(Grid.Columns); + //_viewModel.SetGridColumnsRef(Grid.Columns); _viewModel.PropertyChanged += ViewModelOnPropertyChanged; } diff --git a/src/BuildVision.UI/Controls/BuildVisionProgressBar.xaml b/src/BuildVision.UI/Controls/BuildVisionProgressBar.xaml new file mode 100644 index 00000000..08e1adb7 --- /dev/null +++ b/src/BuildVision.UI/Controls/BuildVisionProgressBar.xaml @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + diff --git a/src/BuildVision.UI/Components/ControlHeader.xaml.cs b/src/BuildVision.UI/Controls/BuildVisionProgressBar.xaml.cs similarity index 71% rename from src/BuildVision.UI/Components/ControlHeader.xaml.cs rename to src/BuildVision.UI/Controls/BuildVisionProgressBar.xaml.cs index b6047453..54b5125c 100644 --- a/src/BuildVision.UI/Components/ControlHeader.xaml.cs +++ b/src/BuildVision.UI/Controls/BuildVisionProgressBar.xaml.cs @@ -13,14 +13,14 @@ using System.Windows.Navigation; using System.Windows.Shapes; -namespace BuildVision.UI.Components +namespace BuildVision.UI.Controls { /// - /// Interaction logic for ControlHeader.xaml + /// Interaction logic for BuildVisionProgressBar.xaml /// - public partial class ControlHeader : UserControl + public partial class BuildVisionProgressBar : UserControl { - public ControlHeader() + public BuildVisionProgressBar() { InitializeComponent(); } diff --git a/src/BuildVision.UI/Controls/Buttons/BuildSolutionButton.cs b/src/BuildVision.UI/Controls/Buttons/BuildSolutionButton.cs new file mode 100644 index 00000000..4184006e --- /dev/null +++ b/src/BuildVision.UI/Controls/Buttons/BuildSolutionButton.cs @@ -0,0 +1,13 @@ +using System.Windows; +using System.Windows.Controls; + +namespace BuildVision.UI.Controls.Buttons +{ + public class BuildSolutionButton : Button + { + static BuildSolutionButton() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(BuildSolutionButton), new FrameworkPropertyMetadata(typeof(BuildSolutionButton))); + } + } +} diff --git a/src/BuildVision.UI/Controls/Buttons/Buttons.Test.xaml b/src/BuildVision.UI/Controls/Buttons/Buttons.Test.xaml new file mode 100644 index 00000000..14e8c413 --- /dev/null +++ b/src/BuildVision.UI/Controls/Buttons/Buttons.Test.xaml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + diff --git a/src/BuildVision.UI/Controls/Buttons/CancelButton.cs b/src/BuildVision.UI/Controls/Buttons/CancelButton.cs new file mode 100644 index 00000000..e629c52b --- /dev/null +++ b/src/BuildVision.UI/Controls/Buttons/CancelButton.cs @@ -0,0 +1,13 @@ +using System.Windows; +using System.Windows.Controls; + +namespace BuildVision.UI.Controls.Buttons +{ + public class CancelButton : Button + { + static CancelButton() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(CancelButton), new FrameworkPropertyMetadata(typeof(CancelButton))); + } + } +} diff --git a/src/BuildVision.UI/Controls/Buttons/CleanSolutionButton.cs b/src/BuildVision.UI/Controls/Buttons/CleanSolutionButton.cs new file mode 100644 index 00000000..3780f78f --- /dev/null +++ b/src/BuildVision.UI/Controls/Buttons/CleanSolutionButton.cs @@ -0,0 +1,13 @@ +using System.Windows; +using System.Windows.Controls; + +namespace BuildVision.UI.Controls.Buttons +{ + public class CleanSolutionButton : Button + { + static CleanSolutionButton() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(CleanSolutionButton), new FrameworkPropertyMetadata(typeof(CleanSolutionButton))); + } + } +} diff --git a/src/BuildVision.UI/Controls/Buttons/RebuildSolutionButton.cs b/src/BuildVision.UI/Controls/Buttons/RebuildSolutionButton.cs new file mode 100644 index 00000000..e72004b9 --- /dev/null +++ b/src/BuildVision.UI/Controls/Buttons/RebuildSolutionButton.cs @@ -0,0 +1,13 @@ +using System.Windows; +using System.Windows.Controls; + +namespace BuildVision.UI.Controls.Buttons +{ + public class RebuildSolutionButton : Button + { + static RebuildSolutionButton() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(RebuildSolutionButton), new FrameworkPropertyMetadata(typeof(RebuildSolutionButton))); + } + } +} diff --git a/src/BuildVision.UI/Controls/Indicators/ErrorProjectsIndicator.cs b/src/BuildVision.UI/Controls/Indicators/ErrorProjectsIndicator.cs new file mode 100644 index 00000000..44afeb01 --- /dev/null +++ b/src/BuildVision.UI/Controls/Indicators/ErrorProjectsIndicator.cs @@ -0,0 +1,15 @@ +using System; +using System.ComponentModel; +using System.Windows; +using System.Windows.Controls; + +namespace BuildVision.UI.Controls.Indicators +{ + public class ErrorProjectsIndicator : ValueIndicator + { + static ErrorProjectsIndicator() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(ErrorProjectsIndicator), new FrameworkPropertyMetadata(typeof(ErrorProjectsIndicator))); + } + } +} diff --git a/src/BuildVision.UI/Controls/Indicators/ErrorsIndicator.cs b/src/BuildVision.UI/Controls/Indicators/ErrorsIndicator.cs new file mode 100644 index 00000000..1a4fcaec --- /dev/null +++ b/src/BuildVision.UI/Controls/Indicators/ErrorsIndicator.cs @@ -0,0 +1,12 @@ +using System.Windows; + +namespace BuildVision.UI.Controls.Indicators +{ + public class ErrorsIndicator : ValueIndicator + { + static ErrorsIndicator() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(ErrorsIndicator), new FrameworkPropertyMetadata(typeof(ErrorsIndicator))); + } + } +} diff --git a/src/BuildVision.UI/Controls/Indicators/Indicators.Test.xaml b/src/BuildVision.UI/Controls/Indicators/Indicators.Test.xaml new file mode 100644 index 00000000..29a08ecd --- /dev/null +++ b/src/BuildVision.UI/Controls/Indicators/Indicators.Test.xaml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + diff --git a/src/BuildVision.UI/Controls/Indicators/MessagesIndicator.cs b/src/BuildVision.UI/Controls/Indicators/MessagesIndicator.cs new file mode 100644 index 00000000..ae5fb62a --- /dev/null +++ b/src/BuildVision.UI/Controls/Indicators/MessagesIndicator.cs @@ -0,0 +1,12 @@ +using System.Windows; + +namespace BuildVision.UI.Controls.Indicators +{ + public class MessagesIndicator : ValueIndicator + { + static MessagesIndicator() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(MessagesIndicator), new FrameworkPropertyMetadata(typeof(MessagesIndicator))); + } + } +} diff --git a/src/BuildVision.UI/Controls/Indicators/SuccessProjectsIndicator.cs b/src/BuildVision.UI/Controls/Indicators/SuccessProjectsIndicator.cs new file mode 100644 index 00000000..9c172ce6 --- /dev/null +++ b/src/BuildVision.UI/Controls/Indicators/SuccessProjectsIndicator.cs @@ -0,0 +1,12 @@ +using System.Windows; + +namespace BuildVision.UI.Controls.Indicators +{ + public class SuccessProjectsIndicator : ValueIndicator + { + static SuccessProjectsIndicator() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(SuccessProjectsIndicator), new FrameworkPropertyMetadata(typeof(SuccessProjectsIndicator))); + } + } +} diff --git a/src/BuildVision.UI/Controls/Indicators/UpToDateProjectsIndicator.cs b/src/BuildVision.UI/Controls/Indicators/UpToDateProjectsIndicator.cs new file mode 100644 index 00000000..b907eaa6 --- /dev/null +++ b/src/BuildVision.UI/Controls/Indicators/UpToDateProjectsIndicator.cs @@ -0,0 +1,12 @@ +using System.Windows; + +namespace BuildVision.UI.Controls.Indicators +{ + public class UpToDateProjectsIndicator : ValueIndicator + { + static UpToDateProjectsIndicator() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(UpToDateProjectsIndicator), new FrameworkPropertyMetadata(typeof(UpToDateProjectsIndicator))); + } + } +} diff --git a/src/BuildVision.UI/Controls/Indicators/ValueIndicator.cs b/src/BuildVision.UI/Controls/Indicators/ValueIndicator.cs new file mode 100644 index 00000000..82668a26 --- /dev/null +++ b/src/BuildVision.UI/Controls/Indicators/ValueIndicator.cs @@ -0,0 +1,38 @@ +using System; +using System.ComponentModel; +using System.Windows; +using System.Windows.Controls; + +namespace BuildVision.UI.Controls.Indicators +{ + public class ValueIndicator : Control + { + public static readonly DependencyProperty ValueProperty = DependencyProperty.Register( + "Value", + typeof(long), + typeof(ValueIndicator), + new FrameworkPropertyMetadata( + defaultValue: (long)-1, + flags: + FrameworkPropertyMetadataOptions.AffectsArrange + | FrameworkPropertyMetadataOptions.AffectsMeasure + |FrameworkPropertyMetadataOptions.AffectsRender, + propertyChangedCallback: new PropertyChangedCallback(OnValueChange))); + + static ValueIndicator() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(ValueIndicator), new FrameworkPropertyMetadata(typeof(ValueIndicator))); + } + + public long Value + { + get { return (long) GetValue(ValueProperty); } + set { SetValue(ValueProperty, value); } + } + + static void OnValueChange(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + d.SetValue(ValueProperty, (long) e.NewValue); + } + } +} diff --git a/src/BuildVision.UI/Controls/Indicators/WarningProjectsIndicator.cs b/src/BuildVision.UI/Controls/Indicators/WarningProjectsIndicator.cs new file mode 100644 index 00000000..996d2e7a --- /dev/null +++ b/src/BuildVision.UI/Controls/Indicators/WarningProjectsIndicator.cs @@ -0,0 +1,12 @@ +using System.Windows; + +namespace BuildVision.UI.Controls.Indicators +{ + public class WarningProjectsIndicator : ValueIndicator + { + static WarningProjectsIndicator() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(WarningProjectsIndicator), new FrameworkPropertyMetadata(typeof(WarningProjectsIndicator))); + } + } +} diff --git a/src/BuildVision.UI/Controls/Indicators/WarningsIndicator.cs b/src/BuildVision.UI/Controls/Indicators/WarningsIndicator.cs new file mode 100644 index 00000000..e39b2ea1 --- /dev/null +++ b/src/BuildVision.UI/Controls/Indicators/WarningsIndicator.cs @@ -0,0 +1,12 @@ +using System.Windows; + +namespace BuildVision.UI.Controls.Indicators +{ + public class WarningsIndicator : ValueIndicator + { + static WarningsIndicator() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(WarningsIndicator), new FrameworkPropertyMetadata(typeof(WarningsIndicator))); + } + } +} diff --git a/src/BuildVision.UI/Models/BuildInformationModel.cs b/src/BuildVision.UI/Models/BuildInformationModel.cs index 7a1967b1..2dcf6b8e 100644 --- a/src/BuildVision.UI/Models/BuildInformationModel.cs +++ b/src/BuildVision.UI/Models/BuildInformationModel.cs @@ -3,7 +3,7 @@ using BuildVision.Contracts; using BuildVision.Contracts.Models; -namespace BuildVision.Core +namespace BuildVision.UI.Models { public class BuildInformationModel : BindableBase, IBuildInformationModel { diff --git a/src/BuildVision.UI/Resources/BuildAction.Resources.Test.xaml b/src/BuildVision.UI/Resources/BuildAction.Resources.Test.xaml index f8987deb..afc89357 100644 --- a/src/BuildVision.UI/Resources/BuildAction.Resources.Test.xaml +++ b/src/BuildVision.UI/Resources/BuildAction.Resources.Test.xaml @@ -23,7 +23,7 @@ SnapsToDevicePixels="True" ClipToBounds="True" UseLayoutRounding="False" - Template="{StaticResource RebuildSolutionButton}" /> + Template="{StaticResource RebuildSolutionIcon}" /> @@ -32,7 +32,7 @@ SnapsToDevicePixels="True" ClipToBounds="True" UseLayoutRounding="False" - Template="{StaticResource BuildSolutionButton}" /> + Template="{StaticResource BuildSolutionIcon}" /> @@ -41,7 +41,7 @@ SnapsToDevicePixels="True" ClipToBounds="True" UseLayoutRounding="False" - Template="{StaticResource CancelBuildSolutionButton}" /> + Template="{StaticResource CancelBuildSolutionIcon}" /> @@ -50,7 +50,7 @@ SnapsToDevicePixels="True" ClipToBounds="True" UseLayoutRounding="False" - Template="{StaticResource CleanSolutionButton}" /> + Template="{StaticResource CleanSolutionIcon}" /> @@ -77,7 +77,6 @@ ClipToBounds="True" UseLayoutRounding="False" Template="{StaticResource Rebuild}" /> - diff --git a/src/BuildVision.UI/Resources/BuildAction.Resources.xaml b/src/BuildVision.UI/Resources/BuildAction.Resources.xaml index 6127957e..17f4bd4a 100644 --- a/src/BuildVision.UI/Resources/BuildAction.Resources.xaml +++ b/src/BuildVision.UI/Resources/BuildAction.Resources.xaml @@ -1,7 +1,7 @@  - + @@ -12,14 +12,14 @@ - - - + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/BuildVision.UI/ViewModels/BuildProgressViewModel.cs b/src/BuildVision.UI/ViewModels/BuildProgressViewModel.cs index 779e7c47..e47eb962 100644 --- a/src/BuildVision.UI/ViewModels/BuildProgressViewModel.cs +++ b/src/BuildVision.UI/ViewModels/BuildProgressViewModel.cs @@ -8,10 +8,11 @@ using BuildVision.UI.Settings.Models; using BuildVision.UI.Models; using BuildVision.UI.Settings.Models.BuildProgress; +using BuildVision.Contracts.Models; namespace BuildVision.UI.ViewModels { - public class BuildProgressViewModel : BindableBase + public class BuildProgressViewModel : BindableBase, IBuildProgressViewModel { private readonly ControlSettings _settings; diff --git a/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs b/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs index 18561b72..bbb70e16 100644 --- a/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs +++ b/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs @@ -35,6 +35,9 @@ namespace BuildVision.UI.ViewModels [Export(typeof(IBuildVisionPaneViewModel))] public class BuildVisionPaneViewModel : BindableBase, IBuildVisionPaneViewModel { + public IBuildProgressViewModel BuildProgressViewModel { get; set; } + public ISolutionModel SoltuionModel { get; set; } + private ObservableCollection _gridColumnsRef; public bool HideUpToDateTargets @@ -43,8 +46,6 @@ public bool HideUpToDateTargets set => SetProperty(() => ControlSettings.GeneralSettings.HideUpToDateTargets, val => ControlSettings.GeneralSettings.HideUpToDateTargets = val, value); } - public BuildProgressViewModel BuildProgressViewModel { get; } - public ControlSettings ControlSettings { get; } public IBuildInformationModel BuildInformationModel { get; set; } @@ -191,13 +192,14 @@ public ProjectItem SelectedProjectItem } [ImportingConstructor] - public BuildVisionPaneViewModel(IBuildService buildManager, IBuildInformationProvider buildInformationProvider, IPackageSettingsProvider settingsProvider) + public BuildVisionPaneViewModel(IBuildService buildManager, IBuildInformationProvider buildInformationProvider, IPackageSettingsProvider settingsProvider, ISolutionProvider solutionProvider) { _buildManager = buildManager; _buildInformationProvider = buildInformationProvider; BuildInformationModel = _buildInformationProvider.GetBuildInformationModel(); - ControlSettings = settingsProvider.Settings; BuildProgressViewModel = new BuildProgressViewModel(ControlSettings); + SoltuionModel = solutionProvider.GetSolutionModel(); + ControlSettings = settingsProvider.Settings; } /// diff --git a/src/BuildVision/BuildVision.csproj b/src/BuildVision/BuildVision.csproj index 5195a1e9..01d1cb68 100644 --- a/src/BuildVision/BuildVision.csproj +++ b/src/BuildVision/BuildVision.csproj @@ -136,7 +136,7 @@ Component - + diff --git a/src/BuildVision/Core/BuildVisionPackage.cs b/src/BuildVision/Core/BuildVisionPackage.cs index 927267ba..204a48a0 100644 --- a/src/BuildVision/Core/BuildVisionPackage.cs +++ b/src/BuildVision/Core/BuildVisionPackage.cs @@ -30,16 +30,8 @@ namespace BuildVision.Core { - - // This attribute tells the PkgDef creation utility (CreatePkgDef.exe) that this class is - // a package. [PackageRegistration(UseManagedResourcesOnly = true, AllowsBackgroundLoading = true)] - // This attribute is used to register the informations needed to show the this package - // in the Help/About dialog of Visual Studio. Resources are defined in VSPackage.resx. - //[InstalledProductRegistration("#110", "#112", BuildVisionVersion.PackageVersion, IconResourceID = 400)] - // This attribute is needed to let the shell know that this package exposes some menus. [ProvideMenuResource("Menus.ctmenu", 1)] - // This attribute registers a tool window exposed by this package. [ProvideToolWindow(typeof(BuildVisionPane))] [Guid(PackageGuids.GuidBuildVisionPackageString)] [ProvideBindingPath] @@ -103,9 +95,6 @@ protected override async Task InitializeAsync(CancellationToken cancellationToke { SolutionEvents_Opened(); } - - //var toolWindow = GetWindowPane(typeof(BuildVisionPane)); - //_viewModel = BuildVisionPane.GetViewModel(toolWindow); } private void SolutionEvents_BeforeClosing() @@ -126,7 +115,6 @@ private void SolutionEvents_Opened() private void SolutionEvents_AfterClosing() { ThreadHelper.ThrowIfNotOnUIThread(); - //_viewModel.BuildProgressViewModel.ResetTaskBarInfo(); } private async void ShowToolWindowAsync(object sender, EventArgs e) diff --git a/src/BuildVision/Core/BuildVisionPane.cs b/src/BuildVision/Core/BuildVisionPane.cs new file mode 100644 index 00000000..47f299da --- /dev/null +++ b/src/BuildVision/Core/BuildVisionPane.cs @@ -0,0 +1,132 @@ +using System.Globalization; +using System.Runtime.InteropServices; +using System.Windows; +using System.Windows.Markup; + +using Microsoft.VisualStudio.Shell; +using BuildVision.UI; +using BuildVision.Core; +using BuildVision.UI.ViewModels; +using System; +using Microsoft.VisualStudio.Threading; +using System.Threading.Tasks; +using Microsoft; +using BuildVision.Exports.Providers; +using BuildVision.Tool.Building; +using BuildVision.Exports.Services; +using BuildVision.Views.Settings; + +namespace BuildVision.Tool +{ + /// + /// This class implements the tool window exposed by this package and hosts a user control. + /// + /// In Visual Studio tool windows are composed of a frame (implemented by the shell) and a pane, + /// usually implemented by the package implementer. + /// + /// This class derives from the class provided from the MPF + /// in order to use its implementation of the IVsUIElementPane interface. + /// + [Guid(PackageGuids.GuidBuildVisionToolWindowString)] + public sealed class BuildVisionPane : ToolWindowPane + { + private bool _controlCreatedSuccessfully; + private readonly BuildVisionPaneViewModel _viewModel; + + JoinableTask viewModelTask; + public JoinableTaskFactory JoinableTaskFactory { get; private set; } + public ControlView View { get; set; } + + public BuildVisionPane() + :base(null) + { + Caption = Resources.ToolWindowTitle; + BitmapResourceID = 301; + BitmapIndex = 1; + FrameworkElement.LanguageProperty.OverrideMetadata(typeof(FrameworkElement), new FrameworkPropertyMetadata(XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag))); + } + + protected override void Initialize() + { + // Using JoinableTaskFactory from parent AsyncPackage. That way if VS shuts down before this + // work is done, we won't risk crashing due to arbitrary work going on in background threads. + var asyncPackage = (AsyncPackage) Package; + JoinableTaskFactory = asyncPackage.JoinableTaskFactory; + + viewModelTask = JoinableTaskFactory.RunAsync(() => InitializeAsync(asyncPackage)); + + } + + public Task GetViewModelAsync() => viewModelTask.JoinAsync(); + + async Task InitializeAsync(AsyncPackage asyncPackage) + { + await JoinableTaskFactory.SwitchToMainThreadAsync(); + try + { + var sp = (AsyncPackage) Package; + Assumes.Present(sp); + var solutionProvider = await sp.GetServiceAsync(typeof(ISolutionProvider)) as ISolutionProvider; + Assumes.Present(solutionProvider); + var buildInformationProvider = await sp.GetServiceAsync(typeof(IBuildInformationProvider)) as IBuildInformationProvider; + Assumes.Present(buildInformationProvider); + var buildingProjectsProvider = await sp.GetServiceAsync(typeof(IBuildingProjectsProvider)) as IBuildingProjectsProvider; + Assumes.Present(buildingProjectsProvider); + var buildService = await sp.GetServiceAsync(typeof(IBuildService)) as IBuildService; + Assumes.Present(buildService); + var packageSettingsProvider = await sp.GetServiceAsync(typeof(IPackageSettingsProvider)) as IPackageSettingsProvider; + Assumes.Present(packageSettingsProvider); + + var viewModel = new BuildVisionPaneViewModel(buildService, buildInformationProvider, packageSettingsProvider, solutionProvider); + + View = CreateControlView(); + View.DataContext = viewModel; + _controlCreatedSuccessfully = true; + base.Initialize(); + return viewModel; + } + catch (Exception e) + { + throw; + } + } + + protected override void OnClose() + { + if (_controlCreatedSuccessfully) + SaveControlSettings(); + + base.OnClose(); + } + + private ControlView CreateControlView() + { + var packageContext = (IPackageContext)Package; + packageContext.ControlSettingsChanged += (settings) => + { + _viewModel.OnControlSettingsChanged(settings); //, buildInfo => BuildMessages.GetBuildDoneMessage(viewModel.SolutionItem, buildInfo, viewModel.ControlSettings.BuildMessagesSettings)); + }; + var view = new ControlView(); + view.Resources.MergedDictionaries.Add(new ResourceDictionary + { + Source = new Uri("pack://application:,,,/BuildVision.UI;component/Styles/ExtensionStyle.xaml") + }); + return view; + } + + private void SaveControlSettings() + { + var viewModel = GetViewModel(this); + viewModel.SyncColumnSettings(); + + var packageContext = (IPackageContext)Package; + //packageContext.SaveSettings(); + } + + public static BuildVisionPaneViewModel GetViewModel(ToolWindowPane toolWindow) + { + var controlView = (ControlView)toolWindow.Content; + return (BuildVisionPaneViewModel)controlView.DataContext; + } + } +} diff --git a/src/BuildVision/Core/ServiceProviderPackage.cs b/src/BuildVision/Core/ServiceProviderPackage.cs index 82be19a0..b5ba5000 100644 --- a/src/BuildVision/Core/ServiceProviderPackage.cs +++ b/src/BuildVision/Core/ServiceProviderPackage.cs @@ -5,6 +5,7 @@ using BuildVision.Exports; using BuildVision.Exports.Factories; using BuildVision.Exports.Providers; +using BuildVision.Exports.Services; using BuildVision.Tool.Building; using BuildVision.UI.Helpers; using BuildVision.UI.Settings.Models; @@ -23,6 +24,7 @@ namespace BuildVision.Core [ProvideService(typeof(IBuildingProjectsProvider), IsAsyncQueryable = true)] [ProvideService(typeof(IBuildMessagesFactory), IsAsyncQueryable = true)] [ProvideService(typeof(IBuildOutputLogger), IsAsyncQueryable = true)] + [ProvideService(typeof(IBuildService), IsAsyncQueryable = true)] public sealed class ServiceProviderPackage : AsyncPackage { private readonly Guid _parsingErrorsLoggerId = new Guid("{64822131-DC4D-4087-B292-61F7E06A7B39}"); @@ -36,6 +38,7 @@ protected override async Task InitializeAsync(CancellationToken cancellationToke AddService(typeof(IBuildingProjectsProvider), CreateServiceAsync, true); AddService(typeof(IBuildMessagesFactory), CreateServiceAsync, true); AddService(typeof(IBuildOutputLogger), CreateServiceAsync, true); + AddService(typeof(IBuildService), CreateServiceAsync, true); } async Task CreateServiceAsync(IAsyncServiceContainer container, CancellationToken cancellation, Type serviceType) @@ -94,6 +97,11 @@ async Task CreateServiceAsync(IAsyncServiceContainer container, Cancella await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(cancellation); return new BuildOutputLogger(_parsingErrorsLoggerId, Microsoft.Build.Framework.LoggerVerbosity.Quiet); } + else if (serviceType == typeof(IBuildService)) + { + await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(cancellation); + return new BuildManager(); + } else { throw new Exception("Not found"); diff --git a/src/BuildVision/Helpers/PropertiesExtensions.cs b/src/BuildVision/Helpers/PropertiesExtensions.cs index c5ac392a..511c0fae 100644 --- a/src/BuildVision/Helpers/PropertiesExtensions.cs +++ b/src/BuildVision/Helpers/PropertiesExtensions.cs @@ -15,7 +15,6 @@ public static Property GetPropertyOrDefault(this Properties properties, string p } catch (ArgumentException) { - // not found. return null; } } @@ -42,4 +41,4 @@ public static object TryGetPropertyValueOrDefault(this Properties properties, st } } } -} \ No newline at end of file +} diff --git a/src/BuildVision/Services/BuildInformationProvider.cs b/src/BuildVision/Services/BuildInformationProvider.cs index a96f1367..4d69aa19 100644 --- a/src/BuildVision/Services/BuildInformationProvider.cs +++ b/src/BuildVision/Services/BuildInformationProvider.cs @@ -7,6 +7,7 @@ using BuildVision.Helpers; using BuildVision.Tool.Models; using BuildVision.UI.Common.Logging; +using BuildVision.UI.Models; using EnvDTE; using EnvDTE80; using Microsoft.VisualStudio.Shell; diff --git a/src/BuildVision/Tool/BuildVisionPane.cs b/src/BuildVision/Tool/BuildVisionPane.cs deleted file mode 100644 index f60a189d..00000000 --- a/src/BuildVision/Tool/BuildVisionPane.cs +++ /dev/null @@ -1,106 +0,0 @@ -using System.Globalization; -using System.Runtime.InteropServices; -using System.Windows; -using System.Windows.Markup; - -using Microsoft.VisualStudio.Shell; -using BuildVision.UI; -using BuildVision.Core; -using BuildVision.UI.ViewModels; -using BuildVision.UI.Helpers; -using BuildVision.UI.Models; -using System; -using System.Linq; -using System.Windows.Media; -using System.Text; -using System.Collections; -using System.IO; - -namespace BuildVision.Tool -{ - /// - /// This class implements the tool window exposed by this package and hosts a user control. - /// - /// In Visual Studio tool windows are composed of a frame (implemented by the shell) and a pane, - /// usually implemented by the package implementer. - /// - /// This class derives from the class provided from the MPF - /// in order to use its implementation of the IVsUIElementPane interface. - /// - [Guid(PackageGuids.GuidBuildVisionToolWindowString)] - public sealed class BuildVisionPane : ToolWindowPane - { - private bool _controlCreatedSuccessfully; - private readonly BuildVisionPaneViewModel _viewModel; - - public BuildVisionPane(BuildVisionPaneViewModel viewModel) - :base(null) - { - Caption = Resources.ToolWindowTitle; - - // Set the image that will appear on the tab of the window frame - // when docked with an other window. - // The resource ID correspond to the one defined in the VSPackage.resx file - // while the Index is the offset in the bitmap strip. - // Each image in the strip being 16x16. - BitmapResourceID = 301; - BitmapIndex = 1; - - // Ensure the current culture passed into bindings is the OS culture. - // By default, WPF uses en-US as the culture, regardless of the system settings. - FrameworkElement.LanguageProperty.OverrideMetadata( - typeof(FrameworkElement), - new FrameworkPropertyMetadata(XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag))); - _viewModel = viewModel; - } - - protected override void Initialize() - { - // This is the user control hosted by the tool window; Note that, even if this class implements IDisposable, - // we are not calling Dispose on this object. This is because ToolWindowPane calls Dispose on - // the object returned by the Content property. - Content = CreateControlView(); - _controlCreatedSuccessfully = true; - - base.Initialize(); - } - - protected override void OnClose() - { - if (_controlCreatedSuccessfully) - SaveControlSettings(); - - base.OnClose(); - } - - private ControlView CreateControlView() - { - var packageContext = (IPackageContext)Package; - packageContext.ControlSettingsChanged += (settings) => - { - _viewModel.OnControlSettingsChanged(settings); //, buildInfo => BuildMessages.GetBuildDoneMessage(viewModel.SolutionItem, buildInfo, viewModel.ControlSettings.BuildMessagesSettings)); - }; - var view = new ControlView { DataContext = _viewModel }; - view.Resources.MergedDictionaries.Add(new ResourceDictionary - { - Source = new Uri("pack://application:,,,/BuildVision.UI;component/Styles/ExtensionStyle.xaml") - }); - return view; - } - - private void SaveControlSettings() - { - var viewModel = GetViewModel(this); - viewModel.SyncColumnSettings(); - - var packageContext = (IPackageContext)Package; - //packageContext.SaveSettings(); - } - - public static BuildVisionPaneViewModel GetViewModel(ToolWindowPane toolWindow) - { - var controlView = (ControlView)toolWindow.Content; - return (BuildVisionPaneViewModel)controlView.DataContext; - } - } -} From edfb460cd6f6048ace9432dc21ce8d980e2e0961 Mon Sep 17 00:00:00 2001 From: Stefan Kert Date: Sat, 16 Mar 2019 13:21:33 +0100 Subject: [PATCH 013/100] Further cleanup --- .../Components/ControlView.xaml | 59 ++++++++----------- .../Resources/BuildAction.Resources.xaml | 6 +- .../ViewModels/BuildVisionPaneViewModel.cs | 6 +- 3 files changed, 33 insertions(+), 38 deletions(-) diff --git a/src/BuildVision.UI/Components/ControlView.xaml b/src/BuildVision.UI/Components/ControlView.xaml index d6a48c2b..925ea778 100644 --- a/src/BuildVision.UI/Components/ControlView.xaml +++ b/src/BuildVision.UI/Components/ControlView.xaml @@ -112,9 +112,9 @@ - + Template="{DynamicResource State}" /> - - - - - + + + + + + + - + + - + - diff --git a/src/BuildVision.UI/Resources/BuildAction.Resources.xaml b/src/BuildVision.UI/Resources/BuildAction.Resources.xaml index 17f4bd4a..1f882f5a 100644 --- a/src/BuildVision.UI/Resources/BuildAction.Resources.xaml +++ b/src/BuildVision.UI/Resources/BuildAction.Resources.xaml @@ -19,7 +19,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + diff --git a/src/BuildVision.UI/Components/ControlView.xaml.cs b/src/BuildVision.UI/Components/ControlView.xaml.cs index 1d4101ec..0e5a3029 100644 --- a/src/BuildVision.UI/Components/ControlView.xaml.cs +++ b/src/BuildVision.UI/Components/ControlView.xaml.cs @@ -37,31 +37,11 @@ public ControlView() //Grid.TargetUpdated += GridOnTargetUpdated; } - private void GridOnTargetUpdated(object sender, DataTransferEventArgs e) - { - if (e.Property.Name == "ItemsSource") - RefreshSortDirectionInGrid(); - } - - private void RefreshSortDirectionInGrid() - { - //DataGridColumn dataGridColumn = Grid.Columns.FirstOrDefault(col => col.GetBindedProperty() == _viewModel.GridSortDescription.Property); - //if (dataGridColumn != null) - // dataGridColumn.SortDirection = _viewModel.GridSortDescription.Order.ToSystem(); - } - - private void GridOnSorting(object sender, DataGridSortingEventArgs e) - { - if (_viewModel.GridSorting.CanExecute(e)) - _viewModel.GridSorting.Execute(e); - } - private void OnDataContextChanged(object sender, DependencyPropertyChangedEventArgs e) { Debug.Assert(DataContext != null); - _viewModel = (BuildVisionPaneViewModel)DataContext; - //_viewModel.SetGridColumnsRef(Grid.Columns); + _viewModel = (BuildVisionPaneViewModel) DataContext; _viewModel.PropertyChanged += ViewModelOnPropertyChanged; } @@ -78,64 +58,5 @@ private void ViewModelOnPropertyChanged(object sender, PropertyChangedEventArgs //} } - private void DataGridExpanderOnExpanded(object sender, RoutedEventArgs e) - { - ExpanderIsExpandedConverter.SaveState( - (Expander)sender, - false, - _viewModel.ControlSettings.GridSettings.CollapsedGroups); - e.Handled = true; - } - - private void DataGridExpanderOnCollapsed(object sender, RoutedEventArgs e) - { - ExpanderIsExpandedConverter.SaveState( - (Expander)sender, - true, - _viewModel.ControlSettings.GridSettings.CollapsedGroups); - e.Handled = true; - } - - // Send scrolling to the DataGrid. - private void DataGridExpanderOnPreviewMouseWheel(object sender, MouseWheelEventArgs e) - { - e.Handled = true; - var eventArg = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta) - { - RoutedEvent = MouseWheelEvent, - Source = sender - }; - - var parent = (UIElement)VisualTreeHelper.GetParent((DependencyObject)sender); - parent.RaiseEvent(eventArg); - } - - private void DataGridRowDetailsOnMouseLeftButtonDown(object sender, MouseButtonEventArgs e) - { - // http://stackoverflow.com/questions/6279724/mousedoubleclick-events-dont-bubble/6326181#6326181) - if (e.ClickCount == 2) - e.Handled = true; - } - - // Autofocus for RowDetails (without extra mouse click). - private void DataGridRowOnPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) - { - var row = (DataGridRow)sender; - if (!row.IsSelected && e.Source is DataGridDetailsPresenter) - { - row.Focusable = true; - row.Focus(); - - // Gets the element with keyboard focus. - var elementWithFocus = Keyboard.FocusedElement as UIElement; - - // Change keyboard focus. - if (elementWithFocus != null) - { - var request = new TraversalRequest(FocusNavigationDirection.Next); - elementWithFocus.MoveFocus(request); - } - } - } } } diff --git a/src/BuildVision.UI/Components/ProjectGrid.xaml b/src/BuildVision.UI/Components/ProjectGrid.xaml new file mode 100644 index 00000000..950e7741 --- /dev/null +++ b/src/BuildVision.UI/Components/ProjectGrid.xaml @@ -0,0 +1,333 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/BuildVision.UI/Components/ProjectGrid.xaml.cs b/src/BuildVision.UI/Components/ProjectGrid.xaml.cs new file mode 100644 index 00000000..54c595ba --- /dev/null +++ b/src/BuildVision.UI/Components/ProjectGrid.xaml.cs @@ -0,0 +1,136 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Controls.Primitives; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; +using BuildVision.UI.Converters; +using BuildVision.UI.ViewModels; + +namespace BuildVision.UI.Components +{ + /// + /// Interaction logic for ProjectGrid.xaml + /// + public partial class ProjectGrid : UserControl + { + private BuildVisionPaneViewModel _viewModel; + + public ProjectGrid() + { + InitializeComponent(); + } + + private void GridOnTargetUpdated(object sender, DataTransferEventArgs e) + { + if (e.Property.Name == "ItemsSource") + RefreshSortDirectionInGrid(); + } + + private void RefreshSortDirectionInGrid() + { + //DataGridColumn dataGridColumn = Grid.Columns.FirstOrDefault(col => col.GetBindedProperty() == _viewModel.GridSortDescription.Property); + //if (dataGridColumn != null) + // dataGridColumn.SortDirection = _viewModel.GridSortDescription.Order.ToSystem(); + } + + private void GridOnSorting(object sender, DataGridSortingEventArgs e) + { + if (_viewModel.GridSorting.CanExecute(e)) + _viewModel.GridSorting.Execute(e); + } + + private void OnDataContextChanged(object sender, DependencyPropertyChangedEventArgs e) + { + //Debug.Assert(DataContext != null); + + _viewModel = (BuildVisionPaneViewModel) DataContext; + //_viewModel.SetGridColumnsRef(Grid.Columns); + //_viewModel.PropertyChanged += ViewModelOnPropertyChanged; + } + + private void ViewModelOnPropertyChanged(object sender, PropertyChangedEventArgs e) + { + //TODO implement logic for scrolling tu currentproject + //if (_viewModel.CurrentProject != null && e.PropertyName == "CurrentProject") + //{ + // // TODO: Remove SelectedIndex = -1 and implement Unselect row feature by clicking on selected row. + // Grid.SelectedIndex = -1; + + // if (Grid.SelectedIndex == -1) + // Grid.ScrollIntoView(_viewModel.CurrentProject); + //} + } + + private void DataGridExpanderOnExpanded(object sender, RoutedEventArgs e) + { + ExpanderIsExpandedConverter.SaveState( + (Expander) sender, + false, + _viewModel.ControlSettings.GridSettings.CollapsedGroups); + e.Handled = true; + } + + private void DataGridExpanderOnCollapsed(object sender, RoutedEventArgs e) + { + ExpanderIsExpandedConverter.SaveState( + (Expander) sender, + true, + _viewModel.ControlSettings.GridSettings.CollapsedGroups); + e.Handled = true; + } + + // Send scrolling to the DataGrid. + private void DataGridExpanderOnPreviewMouseWheel(object sender, MouseWheelEventArgs e) + { + e.Handled = true; + var eventArg = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta) + { + RoutedEvent = MouseWheelEvent, + Source = sender + }; + + var parent = (UIElement) VisualTreeHelper.GetParent((DependencyObject) sender); + parent.RaiseEvent(eventArg); + } + + private void DataGridRowDetailsOnMouseLeftButtonDown(object sender, MouseButtonEventArgs e) + { + // http://stackoverflow.com/questions/6279724/mousedoubleclick-events-dont-bubble/6326181#6326181) + if (e.ClickCount == 2) + e.Handled = true; + } + + // Autofocus for RowDetails (without extra mouse click). + private void DataGridRowOnPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) + { + var row = (DataGridRow) sender; + if (!row.IsSelected && e.Source is DataGridDetailsPresenter) + { + row.Focusable = true; + row.Focus(); + + // Gets the element with keyboard focus. + var elementWithFocus = Keyboard.FocusedElement as UIElement; + + // Change keyboard focus. + if (elementWithFocus != null) + { + var request = new TraversalRequest(FocusNavigationDirection.Next); + elementWithFocus.MoveFocus(request); + } + } + } + } +} diff --git a/src/BuildVision.UI/Models/BuildInformationModel.cs b/src/BuildVision.UI/Models/BuildInformationModel.cs index 2dcf6b8e..72fbd072 100644 --- a/src/BuildVision.UI/Models/BuildInformationModel.cs +++ b/src/BuildVision.UI/Models/BuildInformationModel.cs @@ -56,7 +56,7 @@ public int WarnedProjectsCount set => SetProperty(ref _warnedProjectsCount, value); } - private string _stateMessage = ""; + private string _stateMessage = Resources.BuildDoneText_BuildNotStarted; public string StateMessage { get => _stateMessage; diff --git a/src/BuildVision.UI/Models/ProjectItem.cs b/src/BuildVision.UI/Models/ProjectItem.cs index 63212f1a..bbdfd149 100644 --- a/src/BuildVision.UI/Models/ProjectItem.cs +++ b/src/BuildVision.UI/Models/ProjectItem.cs @@ -172,11 +172,11 @@ public ErrorsBox ErrorsBox } } - [GridColumn("ProjectItemHeader_ErrorsCount", ColumnsOrder.ErrorsCount, true, ImageDictionaryUri = "Resources/ValueIndicator.Resources.xaml", ImageKey = "ErrorsIndicator", ExampleValue = 4)] + [GridColumn("ProjectItemHeader_ErrorsCount", ColumnsOrder.ErrorsCount, true, ImageDictionaryUri = "Resources/ValueIndicator.Resources.xaml", ImageKey = "ErrorsIndicatorIcon", ExampleValue = 4)] public int ErrorsCount => ErrorsBox.ErrorsCount; - [GridColumn("ProjectItemHeader_WarningsCount", ColumnsOrder.WarningsCount, true, ImageDictionaryUri = "Resources/ValueIndicator.Resources.xaml", ImageKey = "WarningsIndicator", ExampleValue = 1253)] + [GridColumn("ProjectItemHeader_WarningsCount", ColumnsOrder.WarningsCount, true, ImageDictionaryUri = "Resources/ValueIndicator.Resources.xaml", ImageKey = "WarningsIndicatorIcon", ExampleValue = 1253)] public int WarningsCount => ErrorsBox.WarningsCount; - [GridColumn("ProjectItemHeader_MessagesCount", ColumnsOrder.MessagesCount, false, ImageDictionaryUri = "Resources/ValueIndicator.Resources.xaml", ImageKey = "MessagesIndicator", ExampleValue = 2)] + [GridColumn("ProjectItemHeader_MessagesCount", ColumnsOrder.MessagesCount, false, ImageDictionaryUri = "Resources/ValueIndicator.Resources.xaml", ImageKey = "MessagesIndicatorIcon", ExampleValue = 2)] public int MessagesCount => ErrorsBox.MessagesCount; private string _framework; diff --git a/src/BuildVision.UI/Styles/ControlViewStyle.xaml b/src/BuildVision.UI/Styles/ControlViewStyle.xaml index 514fe5c3..5de91183 100644 --- a/src/BuildVision.UI/Styles/ControlViewStyle.xaml +++ b/src/BuildVision.UI/Styles/ControlViewStyle.xaml @@ -32,17 +32,8 @@ diff --git a/src/BuildVision.UI/Themes/Generic.xaml b/src/BuildVision.UI/Themes/Generic.xaml index 8c696e32..485f17df 100644 --- a/src/BuildVision.UI/Themes/Generic.xaml +++ b/src/BuildVision.UI/Themes/Generic.xaml @@ -64,6 +64,8 @@ - - + + diff --git a/src/BuildVision.UI/Components/ProjectGrid.xaml.cs b/src/BuildVision.UI/Components/ProjectGrid.xaml.cs index 54c595ba..a2b16e0a 100644 --- a/src/BuildVision.UI/Components/ProjectGrid.xaml.cs +++ b/src/BuildVision.UI/Components/ProjectGrid.xaml.cs @@ -53,11 +53,11 @@ private void GridOnSorting(object sender, DataGridSortingEventArgs e) private void OnDataContextChanged(object sender, DependencyPropertyChangedEventArgs e) { - //Debug.Assert(DataContext != null); + Debug.Assert(DataContext != null); _viewModel = (BuildVisionPaneViewModel) DataContext; - //_viewModel.SetGridColumnsRef(Grid.Columns); - //_viewModel.PropertyChanged += ViewModelOnPropertyChanged; + _viewModel.SetGridColumnsRef(Grid.Columns); + _viewModel.PropertyChanged += ViewModelOnPropertyChanged; } private void ViewModelOnPropertyChanged(object sender, PropertyChangedEventArgs e) diff --git a/src/BuildVision.UI/MainWindow.xaml.cs b/src/BuildVision.UI/MainWindow.xaml.cs index ee39079a..fe583e43 100644 --- a/src/BuildVision.UI/MainWindow.xaml.cs +++ b/src/BuildVision.UI/MainWindow.xaml.cs @@ -1,5 +1,7 @@ using BuildVision.UI.Settings; using BuildVision.UI.ViewModels; +using Microsoft.VisualStudio.PlatformUI; +using Microsoft.VisualStudio.Shell; using System; using System.Linq; using System.Windows; diff --git a/src/BuildVision.UI/Themes/Generic.xaml b/src/BuildVision.UI/Themes/Generic.xaml index 485f17df..f132e783 100644 --- a/src/BuildVision.UI/Themes/Generic.xaml +++ b/src/BuildVision.UI/Themes/Generic.xaml @@ -10,20 +10,12 @@ - - + + + - + + + + + + + - - - - - - + + + - - - - - - - - - - - - diff --git a/src/BuildVision.UI/Controls/Buttons/CancelButton.cs b/src/BuildVision.UI/Controls/Buttons/CancelButton.cs deleted file mode 100644 index e629c52b..00000000 --- a/src/BuildVision.UI/Controls/Buttons/CancelButton.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Windows; -using System.Windows.Controls; - -namespace BuildVision.UI.Controls.Buttons -{ - public class CancelButton : Button - { - static CancelButton() - { - DefaultStyleKeyProperty.OverrideMetadata(typeof(CancelButton), new FrameworkPropertyMetadata(typeof(CancelButton))); - } - } -} diff --git a/src/BuildVision.UI/Controls/Buttons/CleanSolutionButton.cs b/src/BuildVision.UI/Controls/Buttons/CleanSolutionButton.cs deleted file mode 100644 index 3780f78f..00000000 --- a/src/BuildVision.UI/Controls/Buttons/CleanSolutionButton.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Windows; -using System.Windows.Controls; - -namespace BuildVision.UI.Controls.Buttons -{ - public class CleanSolutionButton : Button - { - static CleanSolutionButton() - { - DefaultStyleKeyProperty.OverrideMetadata(typeof(CleanSolutionButton), new FrameworkPropertyMetadata(typeof(CleanSolutionButton))); - } - } -} diff --git a/src/BuildVision.UI/Controls/Buttons/RebuildSolutionButton.cs b/src/BuildVision.UI/Controls/Buttons/RebuildSolutionButton.cs deleted file mode 100644 index e72004b9..00000000 --- a/src/BuildVision.UI/Controls/Buttons/RebuildSolutionButton.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Windows; -using System.Windows.Controls; - -namespace BuildVision.UI.Controls.Buttons -{ - public class RebuildSolutionButton : Button - { - static RebuildSolutionButton() - { - DefaultStyleKeyProperty.OverrideMetadata(typeof(RebuildSolutionButton), new FrameworkPropertyMetadata(typeof(RebuildSolutionButton))); - } - } -} diff --git a/src/BuildVision.UI/Converters/AlternatingRowBackgroundConverter.cs b/src/BuildVision.UI/Converters/AlternatingRowBackgroundConverter.cs index a19e4596..5af63cd9 100644 --- a/src/BuildVision.UI/Converters/AlternatingRowBackgroundConverter.cs +++ b/src/BuildVision.UI/Converters/AlternatingRowBackgroundConverter.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Globalization; using System.Windows.Data; using System.Windows.Media; @@ -65,4 +65,4 @@ public object ConvertBack(object value, Type targetType, object parameter, Cultu throw new NotImplementedException(); } } -} \ No newline at end of file +} diff --git a/src/BuildVision.UI/DataGrid/DataGridImageColumn.cs b/src/BuildVision.UI/DataGrid/DataGridImageColumn.cs index 79d8005b..a0c254e4 100644 --- a/src/BuildVision.UI/DataGrid/DataGridImageColumn.cs +++ b/src/BuildVision.UI/DataGrid/DataGridImageColumn.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Windows; using System.Windows.Controls; using System.Windows.Data; @@ -10,9 +10,11 @@ public class DataGridImageColumn : DataGridBoundColumn { protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem) { - Image image = (cell != null) ? (cell.Content as Image) : null; + var image = (cell != null) ? (cell.Content as Image) : null; if (image == null) + { image = new Image(); + } image.Stretch = Stretch.None; image.SnapsToDevicePixels = true; @@ -25,4 +27,4 @@ protected override FrameworkElement GenerateEditingElement(DataGridCell cell, ob throw new InvalidOperationException(); } } -} \ No newline at end of file +} diff --git a/src/BuildVision.UI/Extensions/BindingExtensions.cs b/src/BuildVision.UI/Extensions/BindingExtensions.cs index a001d3c8..6e50ade2 100644 --- a/src/BuildVision.UI/Extensions/BindingExtensions.cs +++ b/src/BuildVision.UI/Extensions/BindingExtensions.cs @@ -1,4 +1,4 @@ -using System.Windows; +using System.Windows; using System.Windows.Data; namespace BuildVision.UI.Extensions @@ -7,16 +7,14 @@ public static class BindingExtensions { public static void UpdateTarget(this FrameworkElement element, DependencyProperty property) { - BindingExpression expression = element.GetBindingExpression(property); - if (expression != null) - expression.UpdateTarget(); + var expression = element.GetBindingExpression(property); + expression?.UpdateTarget(); } public static void UpdateSource(this FrameworkElement element, DependencyProperty property) { - BindingExpression expression = element.GetBindingExpression(property); - if (expression != null) - expression.UpdateSource(); + var expression = element.GetBindingExpression(property); + expression?.UpdateSource(); } } -} \ No newline at end of file +} diff --git a/src/BuildVision.UI/Extensions/DataGridColumnExtensions.cs b/src/BuildVision.UI/Extensions/DataGridColumnExtensions.cs index 354f710e..6b325a46 100644 --- a/src/BuildVision.UI/Extensions/DataGridColumnExtensions.cs +++ b/src/BuildVision.UI/Extensions/DataGridColumnExtensions.cs @@ -9,20 +9,14 @@ public static class DataGridColumnExtensions typeof(string), typeof(DataGridColumnExtensions)); - /// - /// Gets the value of the dependency property. - /// public static string GetName(DependencyObject obj) { return (string)obj.GetValue(NameProperty); } - /// - /// Sets the value of the dependency property. - /// public static void SetName(DependencyObject obj, string value) { obj.SetValue(NameProperty, value); } } -} \ No newline at end of file +} diff --git a/src/BuildVision.UI/Extensions/EnumerationExtension.cs b/src/BuildVision.UI/Extensions/EnumerationExtension.cs index f795cebe..9d9073f3 100644 --- a/src/BuildVision.UI/Extensions/EnumerationExtension.cs +++ b/src/BuildVision.UI/Extensions/EnumerationExtension.cs @@ -1,4 +1,4 @@ -using BuildVision.UI.Helpers; +using BuildVision.UI.Helpers; using System; using System.Linq; using System.Windows.Markup; @@ -51,4 +51,4 @@ private string GetDescription(object enumValue) : enumValue.ToString(); } } -} \ No newline at end of file +} diff --git a/src/BuildVision.UI/Extensions/ProjectStateExtensions.cs b/src/BuildVision.UI/Extensions/ProjectStateExtensions.cs index 100eba83..6b0a04fe 100644 --- a/src/BuildVision.UI/Extensions/ProjectStateExtensions.cs +++ b/src/BuildVision.UI/Extensions/ProjectStateExtensions.cs @@ -1,4 +1,4 @@ -using BuildVision.Contracts; +using BuildVision.Contracts; using System.Windows.Controls; namespace BuildVision.UI.Extensions @@ -8,7 +8,6 @@ public static class ProjectStateExtensions public static bool IsErrorState(this ProjectState state) { return state == ProjectState.BuildError || state == ProjectState.CleanError; - } public static ControlTemplate GetAssociatedContent(this ProjectState state) diff --git a/src/BuildVision.UI/Extensions/TextBlockUtils.cs b/src/BuildVision.UI/Extensions/TextBlockUtils.cs index 29901f63..7b7bbd96 100644 --- a/src/BuildVision.UI/Extensions/TextBlockUtils.cs +++ b/src/BuildVision.UI/Extensions/TextBlockUtils.cs @@ -5,29 +5,17 @@ namespace BuildVision.UI.Extensions { public class TextBlockUtils { - /// - /// Identified the attached AutoTooltip property. - /// When true, this will set the - /// property to , and display a tooltip - /// with the full text whenever the text is trimmed. - /// public static readonly DependencyProperty AutoTooltipProperty = DependencyProperty.RegisterAttached( "AutoTooltip", typeof(bool), typeof(TextBlockUtils), new PropertyMetadata(false, OnAutoTooltipPropertyChanged)); - /// - /// Gets the value of the dependency property. - /// public static bool GetAutoTooltip(DependencyObject obj) { return (bool)obj.GetValue(AutoTooltipProperty); } - /// - /// Sets the value of the dependency property. - /// public static void SetAutoTooltip(DependencyObject obj, bool value) { obj.SetValue(AutoTooltipProperty, value); @@ -57,9 +45,6 @@ private static void TextBlock_SizeChanged(object sender, SizeChangedEventArgs e) ComputeAutoTooltip(textBlock); } - /// - /// Assigns the ToolTip for the given TextBlock based on whether the text is trimmed. - /// private static void ComputeAutoTooltip(TextBlock textBlock) { textBlock.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); diff --git a/src/BuildVision.UI/Resources/BuildAction.Resources.xaml b/src/BuildVision.UI/Resources/BuildAction.Resources.xaml index 1f882f5a..8ba4dfcf 100644 --- a/src/BuildVision.UI/Resources/BuildAction.Resources.xaml +++ b/src/BuildVision.UI/Resources/BuildAction.Resources.xaml @@ -19,7 +19,7 @@ + - + + + - + + + + + + + + + + + + + + - - - diff --git a/src/BuildVision.UI/Themes/Generic.xaml b/src/BuildVision.UI/Themes/Generic.xaml index bb051b3b..10af229b 100644 --- a/src/BuildVision.UI/Themes/Generic.xaml +++ b/src/BuildVision.UI/Themes/Generic.xaml @@ -6,7 +6,6 @@ xmlns:vsfx="clr-namespace:Microsoft.VisualStudio.Shell;assembly=Microsoft.VisualStudio.Shell.14.0"> - @@ -47,124 +46,26 @@ - - - - - - - + + diff --git a/src/BuildVision.UI/Converters/InProgressToCollapsedConverter.cs b/src/BuildVision.UI/Converters/InProgressToCollapsedConverter.cs new file mode 100644 index 00000000..1c78b9cb --- /dev/null +++ b/src/BuildVision.UI/Converters/InProgressToCollapsedConverter.cs @@ -0,0 +1,23 @@ +using System; +using System.Globalization; +using System.Windows; +using System.Windows.Data; +using BuildVision.Contracts; + +namespace BuildVision.UI.Converters +{ + [ValueConversion(typeof(BuildState), typeof(Visibility))] + public class InProgressToCollapsedConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + var buildState = (BuildState) value; + return buildState == BuildState.InProgress ? Visibility.Collapsed : Visibility.Visible; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/BuildVision.UI/Converters/InProgressToVisibleConverter.cs b/src/BuildVision.UI/Converters/InProgressToVisibleConverter.cs new file mode 100644 index 00000000..0f6a911b --- /dev/null +++ b/src/BuildVision.UI/Converters/InProgressToVisibleConverter.cs @@ -0,0 +1,23 @@ +using System; +using System.Globalization; +using System.Windows; +using System.Windows.Data; +using BuildVision.Contracts; + +namespace BuildVision.UI.Converters +{ + [ValueConversion(typeof(BuildState), typeof(Visibility))] + public class InProgressToVisibleConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + var buildState = (BuildState)value; + return buildState == BuildState.InProgress ? Visibility.Visible : Visibility.Collapsed; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/BuildVision.UI/Converters/NumberToIsPositiveConverter.cs b/src/BuildVision.UI/Converters/NumberToIsPositiveConverter.cs index b6470a5f..9b7faf9e 100644 --- a/src/BuildVision.UI/Converters/NumberToIsPositiveConverter.cs +++ b/src/BuildVision.UI/Converters/NumberToIsPositiveConverter.cs @@ -21,4 +21,4 @@ public object ConvertBack(object value, Type targetType, object parameter, Cultu throw new InvalidOperationException(); } } -} \ No newline at end of file +} diff --git a/src/BuildVision.UI/Models/ProjectItem.cs b/src/BuildVision.UI/Models/ProjectItem.cs index bbdfd149..231699df 100644 --- a/src/BuildVision.UI/Models/ProjectItem.cs +++ b/src/BuildVision.UI/Models/ProjectItem.cs @@ -5,6 +5,8 @@ using BuildVision.Contracts; using BuildVision.UI.Modelss; using BuildVision.UI.Extensions; +using System.Collections.Generic; +using System.Collections.ObjectModel; namespace BuildVision.UI.Models { @@ -154,30 +156,35 @@ public TimeSpan? BuildElapsedTime } } - private ErrorsBox _errorsBox; + public ObservableCollection Errors { get; set; } = new ObservableCollection(); - public ErrorsBox ErrorsBox + public ObservableCollection Warnings { get; set; } = new ObservableCollection(); + + public ObservableCollection Messages { get; set; } = new ObservableCollection(); + + private int _errorsCount; + [GridColumn("ProjectItemHeader_ErrorsCount", ColumnsOrder.ErrorsCount, true, ImageDictionaryUri = "Resources/ValueIndicator.Resources.xaml", ImageKey = "ErrorsIndicatorIcon", ExampleValue = 4)] + public int ErrorsCount { - get { return _errorsBox ?? (_errorsBox = new ErrorsBox()); } - set - { - if (_errorsBox != value) - { - _errorsBox = value; - OnPropertyChanged("ErrorsBox"); - OnPropertyChanged("ErrorsCount"); - OnPropertyChanged("WarningsCount"); - OnPropertyChanged("MessagesCount"); - } - } + get => _errorsCount; + set => SetProperty(ref _errorsCount, value); } - [GridColumn("ProjectItemHeader_ErrorsCount", ColumnsOrder.ErrorsCount, true, ImageDictionaryUri = "Resources/ValueIndicator.Resources.xaml", ImageKey = "ErrorsIndicatorIcon", ExampleValue = 4)] - public int ErrorsCount => ErrorsBox.ErrorsCount; + private int _warningsCount; [GridColumn("ProjectItemHeader_WarningsCount", ColumnsOrder.WarningsCount, true, ImageDictionaryUri = "Resources/ValueIndicator.Resources.xaml", ImageKey = "WarningsIndicatorIcon", ExampleValue = 1253)] - public int WarningsCount => ErrorsBox.WarningsCount; + public int WarningsCount + { + get => _warningsCount; + set => SetProperty(ref _warningsCount, value); + } + + private int _messagesCount; [GridColumn("ProjectItemHeader_MessagesCount", ColumnsOrder.MessagesCount, false, ImageDictionaryUri = "Resources/ValueIndicator.Resources.xaml", ImageKey = "MessagesIndicatorIcon", ExampleValue = 2)] - public int MessagesCount => ErrorsBox.MessagesCount; + public int MessagesCount + { + get => _messagesCount; + set => SetProperty(ref _messagesCount, value); + } private string _framework; diff --git a/src/BuildVision.UI/Resources/BuildState.Resources.Test.xaml b/src/BuildVision.UI/Resources/BuildState.Resources.Test.xaml index 4b6888c8..3de6dcfb 100644 --- a/src/BuildVision.UI/Resources/BuildState.Resources.Test.xaml +++ b/src/BuildVision.UI/Resources/BuildState.Resources.Test.xaml @@ -19,8 +19,9 @@ - - + - - - - - - - - - - - - - + + Template="{StaticResource FailedIcon}" /> @@ -146,7 +159,7 @@ SnapsToDevicePixels="True" ClipToBounds="True" UseLayoutRounding="False" - Template="{StaticResource Done}" /> + Template="{StaticResource DoneIcon}" /> @@ -155,7 +168,7 @@ SnapsToDevicePixels="True" ClipToBounds="True" UseLayoutRounding="False" - Template="{StaticResource Cancelled}" /> + Template="{StaticResource CancelledIcon}" /> @@ -164,20 +177,20 @@ SnapsToDevicePixels="True" ClipToBounds="True" UseLayoutRounding="False" - Template="{StaticResource FailedWithErrors}" /> + Template="{StaticResource FailedWithErrorsIcon}" /> - + - + - - - - + + + + + + - + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -109,7 +169,7 @@ - + @@ -128,7 +188,7 @@ - + @@ -154,329 +214,192 @@ + + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + + + + - - - - + + + + + + - - - - + + + + + + - - - - + + + + + + - - - - + + + + + + - - - - + + + + + + - - - - + + + + + + - - - - + + + + + + - - - - + + + + + + - - - - + + + + + + - - - - + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + diff --git a/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs b/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs index d2dc0c31..9bbd8ffc 100644 --- a/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs +++ b/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs @@ -185,6 +185,7 @@ public DataGridHeadersVisibility GridHeadersVisibility private readonly IBuildingProjectsProvider _buildingProjectsProvider; private readonly IBuildInformationProvider _buildInformationProvider; private readonly IBuildService _buildService; + private readonly IErrorNavigationService _errorNavigationService; public ProjectItem SelectedProjectItem { @@ -193,11 +194,18 @@ public ProjectItem SelectedProjectItem } [ImportingConstructor] - public BuildVisionPaneViewModel(IBuildingProjectsProvider buildingProjectsProvider, IBuildInformationProvider buildInformationProvider, IPackageSettingsProvider settingsProvider, ISolutionProvider solutionProvider, IBuildService buildService) + public BuildVisionPaneViewModel( + IBuildingProjectsProvider buildingProjectsProvider, + IBuildInformationProvider buildInformationProvider, + IPackageSettingsProvider settingsProvider, + ISolutionProvider solutionProvider, + IBuildService buildService, + IErrorNavigationService errorNavigationService) { _buildingProjectsProvider = buildingProjectsProvider; _buildInformationProvider = buildInformationProvider; _buildService = buildService; + _errorNavigationService = errorNavigationService; BuildInformationModel = _buildInformationProvider.GetBuildInformationModel(); SolutionModel = solutionProvider.GetSolutionModel(); ControlSettings = settingsProvider.Settings; @@ -338,7 +346,7 @@ private void CopyErrorMessageToClipboard(ProjectItem projectItem) try { var errors = new StringBuilder(); - foreach (var errorItem in projectItem.ErrorsBox.Errors) + foreach (var errorItem in projectItem.Errors) { errors.AppendLine(string.Format("{0}({1},{2},{3},{4}): error {5}: {6}", errorItem.File, errorItem.LineNumber, errorItem.ColumnNumber, errorItem.EndLineNumber, errorItem.EndColumnNumber, errorItem.Code, errorItem.Message)); } @@ -352,14 +360,15 @@ private void CopyErrorMessageToClipboard(ProjectItem projectItem) #region Commands + public ICommand NavigateToErrorCommand => new RelayCommand(obj => _errorNavigationService.NavigateToErrorItem(obj as ErrorItem)); + public ICommand ReportIssues => new RelayCommand(obj => GithubHelper.OpenBrowserWithPrefilledIssue()); public ICommand GridSorting => new RelayCommand(obj => ReorderGrid(obj)); public ICommand GridGroupPropertyMenuItemClicked => new RelayCommand(obj => GridGroupPropertyName = (obj != null) ? obj.ToString() : string.Empty); - public ICommand SelectedProjectOpenContainingFolderAction => new RelayCommand(obj => OpenContainingFolder(), - canExecute: obj => (SelectedProjectItem != null && !string.IsNullOrEmpty(SelectedProjectItem.FullName))); + public ICommand SelectedProjectOpenContainingFolderAction => new RelayCommand(obj => OpenContainingFolder(), canExecute: obj => (SelectedProjectItem != null && !string.IsNullOrEmpty(SelectedProjectItem.FullName))); //public ICommand SelectedProjectCopyBuildOutputFilesToClipboardAction => new RelayCommand( // obj => _buildService.ProjectCopyBuildOutputFilesToClipBoard(SelectedProjectItem), @@ -378,8 +387,7 @@ private void CopyErrorMessageToClipboard(ProjectItem projectItem) // obj => _buildService.RaiseCommandForSelectedProject(SelectedProjectItem, (int)VSConstants.VSStd97CmdID.CleanCtx), // canExecute: obj => IsProjectItemEnabledForActions()); - public ICommand SelectedProjectCopyErrorMessagesAction => new RelayCommand(obj => CopyErrorMessageToClipboard(SelectedProjectItem), - canExecute: obj => SelectedProjectItem?.ErrorsCount > 0); + public ICommand SelectedProjectCopyErrorMessagesAction => new RelayCommand(obj => CopyErrorMessageToClipboard(SelectedProjectItem), canExecute: obj => SelectedProjectItem?.ErrorsCount > 0); public ICommand BuildSolutionAction => new RelayCommand(obj => _buildService.BuildSolution()); diff --git a/src/BuildVision/BuildVision.csproj b/src/BuildVision/BuildVision.csproj index a6240743..09dd1c90 100644 --- a/src/BuildVision/BuildVision.csproj +++ b/src/BuildVision/BuildVision.csproj @@ -96,7 +96,6 @@ - diff --git a/src/BuildVision/Core/BuildVisionPackage.cs b/src/BuildVision/Core/BuildVisionPackage.cs index cd90bb28..7262f7bf 100644 --- a/src/BuildVision/Core/BuildVisionPackage.cs +++ b/src/BuildVision/Core/BuildVisionPackage.cs @@ -6,6 +6,7 @@ using System.Windows; using System.Windows.Threading; using BuildVision.Exports.Providers; +using BuildVision.Exports.Services; using BuildVision.Helpers; using BuildVision.Services; using BuildVision.Tool; diff --git a/src/BuildVision/Core/BuildVisionPane.cs b/src/BuildVision/Core/BuildVisionPane.cs index 3f8d1de8..395c15d4 100644 --- a/src/BuildVision/Core/BuildVisionPane.cs +++ b/src/BuildVision/Core/BuildVisionPane.cs @@ -88,8 +88,10 @@ async Task InitializeAsync(AsyncPackage asyncPackage) Assumes.Present(buildService); var packageSettingsProvider = await asyncPackage.GetServiceAsync(typeof(IPackageSettingsProvider)) as IPackageSettingsProvider; Assumes.Present(packageSettingsProvider); + var errorNavigationService = await asyncPackage.GetServiceAsync(typeof(IErrorNavigationService)) as IErrorNavigationService; + Assumes.Present(packageSettingsProvider); - var viewModel = new BuildVisionPaneViewModel(buildingProjectsProvider, buildInformationProvider, packageSettingsProvider, solutionProvider, buildService); + var viewModel = new BuildVisionPaneViewModel(buildingProjectsProvider, buildInformationProvider, packageSettingsProvider, solutionProvider, buildService, errorNavigationService); View = CreateControlView(); View.DataContext = viewModel; diff --git a/src/BuildVision/Services/BuildInformationProvider.cs b/src/BuildVision/Services/BuildInformationProvider.cs index d29e820c..ce15a0bc 100644 --- a/src/BuildVision/Services/BuildInformationProvider.cs +++ b/src/BuildVision/Services/BuildInformationProvider.cs @@ -223,7 +223,7 @@ public void BuildFinished(IEnumerable projects, bool success, bool { if (ErrorNavigationService.BuildErrorNavigated) break; - foreach (var error in project.ErrorsBox) + foreach (var error in project.Errors) { if (ErrorNavigationService.BuildErrorNavigated) break; diff --git a/src/BuildVision/Services/BuildService.cs b/src/BuildVision/Services/BuildService.cs index c89e0b62..0b3909ea 100644 --- a/src/BuildVision/Services/BuildService.cs +++ b/src/BuildVision/Services/BuildService.cs @@ -193,12 +193,13 @@ private string GetCopyBuildOutputFilesToClipboardActionMessage(string template, private void RaiseCommand(VSConstants.VSStd97CmdID command) { - Microsoft.VisualStudio.Shell.ThreadHelper.ThrowIfNotOnUIThread(); + ThreadHelper.ThrowIfNotOnUIThread(); try { object customIn = null; object customOut = null; - //Services.Dte.Commands.Raise(VSConstants.GUID_VSStandardCommandSet97.ToString(), (int) command, ref customIn, ref customOut); + var dte = _serviceProvider.GetService(typeof(DTE)) as DTE; + dte.Commands.Raise(VSConstants.GUID_VSStandardCommandSet97.ToString(), (int) command, ref customIn, ref customOut); } catch (Exception ex) { diff --git a/src/BuildVision/Services/BuildingProjectsProvider.cs b/src/BuildVision/Services/BuildingProjectsProvider.cs index 9f07745a..b9b973a4 100644 --- a/src/BuildVision/Services/BuildingProjectsProvider.cs +++ b/src/BuildVision/Services/BuildingProjectsProvider.cs @@ -78,15 +78,14 @@ private void BuildOutputLogger_OnErrorRaised(BuildProjectContextEntry projectEnt case ErrorLevel.Error: errorItem.Init((BuildErrorEventArgs) e); break; - default: - errorItem.VerifyValues(); + default: break; } - projectItem.ErrorsBox.Add(errorItem); + errorItem.VerifyValues(); + AddErrorItem(projectItem, errorItem); var args = new BuildErrorRaisedEventArgs(errorLevel, projectItem); - bool buildNeedCancel = (args.ErrorLevel == ErrorLevel.Error && _packageSettingsProvider.Settings.GeneralSettings.StopBuildAfterFirstError); if (buildNeedCancel) { @@ -94,7 +93,7 @@ private void BuildOutputLogger_OnErrorRaised(BuildProjectContextEntry projectEnt } bool navigateToBuildFailure = (args.ErrorLevel == ErrorLevel.Error && _packageSettingsProvider.Settings.GeneralSettings.NavigateToBuildFailureReason == NavigateToBuildFailureReasonCondition.OnErrorRaised); - if (_packageSettingsProvider.Settings.GeneralSettings.NavigateToBuildFailureReason == NavigateToBuildFailureReasonCondition.OnBuildDone) + if (_packageSettingsProvider.Settings.GeneralSettings.NavigateToBuildFailureReason == NavigateToBuildFailureReasonCondition.OnBuildDone && !ErrorNavigationService.BuildErrorNavigated) { _errorNavigationService.NavigateToErrorItem(errorItem); } @@ -105,6 +104,46 @@ private void BuildOutputLogger_OnErrorRaised(BuildProjectContextEntry projectEnt } } + public void AddErrorItem(IProjectItem projectItem, ErrorItem errorItem) + { + switch (errorItem.Level) + { + case ErrorLevel.Message: + projectItem.MessagesCount++; + break; + case ErrorLevel.Warning: + projectItem.WarningsCount++; + break; + case ErrorLevel.Error: + projectItem.ErrorsCount++; + break; + default: + throw new ArgumentOutOfRangeException("errorLevel"); + } + if (errorItem.Level != ErrorLevel.Error) + return; + + int errorNumber = projectItem.Errors.Count + projectItem.Warnings.Count + projectItem.Messages.Count + 1; + errorItem.Number = errorNumber; + switch (errorItem.Level) + { + case ErrorLevel.Message: + projectItem.Messages.Add(errorItem); + break; + + case ErrorLevel.Warning: + projectItem.Warnings.Add(errorItem); + break; + + case ErrorLevel.Error: + projectItem.Errors.Add(errorItem); + break; + + default: + throw new ArgumentOutOfRangeException("errorLevel"); + } + } + public void ReloadCurrentProjects() { _projects.Clear(); @@ -231,7 +270,7 @@ public void ProjectBuildFinished(string projectIdentifier, bool success, bool ca case BuildActions.BuildActionRebuildAll: if (success) { - if (_packageSettingsProvider.Settings.GeneralSettings.ShowWarningSignForBuilds && currentProject.ErrorsBox.WarningsCount > 0) + if (_packageSettingsProvider.Settings.GeneralSettings.ShowWarningSignForBuilds && currentProject.WarningsCount > 0) { projectState = ProjectState.BuildWarning; } @@ -246,7 +285,7 @@ public void ProjectBuildFinished(string projectIdentifier, bool success, bool ca } else { - bool buildCancelled = (canceled && currentProject.ErrorsBox.ErrorsCount == 0); + bool buildCancelled = (canceled && currentProject.ErrorsCount == 0); projectState = buildCancelled ? ProjectState.BuildCancelled : ProjectState.BuildError; } break; diff --git a/src/BuildVision/Services/ErrorNavigationService.cs b/src/BuildVision/Services/ErrorNavigationService.cs index cce234f5..48cff658 100644 --- a/src/BuildVision/Services/ErrorNavigationService.cs +++ b/src/BuildVision/Services/ErrorNavigationService.cs @@ -4,6 +4,7 @@ using System.IO; using BuildVision.Contracts; using BuildVision.Exports.Providers; +using BuildVision.Exports.Services; using BuildVision.Helpers; using BuildVision.UI.Common.Logging; using EnvDTE; @@ -14,7 +15,6 @@ namespace BuildVision.Services public class ErrorNavigationService : IErrorNavigationService { private readonly IServiceProvider _serviceProvider; - private readonly IBuildingProjectsProvider _buildingProjectsProvider; public static bool BuildErrorNavigated { get; set; } @@ -27,9 +27,6 @@ public ErrorNavigationService( public void NavigateToErrorItem(ErrorItem errorItem) { - if (BuildErrorNavigated) - return; - try { var dte = _serviceProvider.GetService(typeof(DTE)) as DTE; From 01d54f8bfce3a81e1c72475ce1e70bce65d5e51c Mon Sep 17 00:00:00 2001 From: Stefan Kert Date: Sat, 30 Mar 2019 13:11:56 +0100 Subject: [PATCH 044/100] Fixed setting dialogs and furthe rthings Added basic diagnosticsclient --- src/BuildVision.Common/AppVersionInfo.cs | 2 +- .../BuildVision.Common.csproj | 4 + .../Diagnostics/DiagnosticsClient.cs | 65 ++++ .../Diagnostics/SessionTelemetry.cs | 62 +++ .../Diagnostics/VersionTelemetry.cs | 25 ++ .../Models/IBuildProgressViewModel.cs | 15 - .../Providers/IBuildInformationProvider.cs | 11 +- .../Providers/IBuildingProjectsProvider.cs | 16 - .../Sevices/IBuildService.cs | 10 +- .../Sevices/ITaskBarInfoService.cs | 10 + src/BuildVision.UI/BuildVision.UI.csproj | 11 +- .../Components/ControlView.xaml | 18 +- .../Converters/InProgressToBoolConverter.cs | 22 ++ .../DataGrid/DataGridContentControlColumn.cs | 8 +- .../Helpers/BuildMessagesFactory.cs | 9 +- .../IPackageSettingsProvider.cs | 5 +- .../Models/GridColumnSettingsCollection.cs | 9 +- .../{Helpers => Models}/SortDescription.cs | 0 .../{Helpers => Models}/WindowStateAction.cs | 0 .../ViewModels/BuildVisionPaneViewModel.cs | 135 +++---- src/BuildVision/ApplicationInsights.config | 16 + src/BuildVision/BuildVision.csproj | 11 +- src/BuildVision/Core/BuildVisionPackage.cs | 30 +- src/BuildVision/Core/BuildVisionPane.cs | 89 ++--- src/BuildVision/Core/IPackageContext.cs | 16 - .../Core/ServiceProviderPackage.cs | 28 +- src/BuildVision/Core/Services.cs | 29 +- src/BuildVision/Core/SolutionBuildEvents.cs | 19 +- .../Extensions/IServiceProviderExtensions.cs | 12 + .../Services/BuildInformationProvider.cs | 366 +++++++++++++++--- .../Services/BuildProgressViewModel.cs | 214 ---------- src/BuildVision/Services/BuildService.cs | 38 +- .../Services/BuildingProjectsProvider.cs | 325 ---------------- .../Services/PackageSettingsProvider.cs | 3 + .../Services/StatusBarNotificationService.cs | 24 +- .../Services/TaskBarInfoService.cs | 139 +++++++ .../BuildMessagesSettingsDialogPage.cs | 4 +- .../Settings/GeneralSettingsDialogPage.cs | 8 +- .../Views/Settings/GridSettingsDialogPage.cs | 21 +- .../Settings/ProjectItemSettingsDialogPage.cs | 8 +- .../Views/Settings/SettingsDialogPage.cs | 7 +- .../Settings/WindowSettingsDialogPage.cs | 4 +- 42 files changed, 885 insertions(+), 963 deletions(-) create mode 100644 src/BuildVision.Common/Diagnostics/DiagnosticsClient.cs create mode 100644 src/BuildVision.Common/Diagnostics/SessionTelemetry.cs create mode 100644 src/BuildVision.Common/Diagnostics/VersionTelemetry.cs delete mode 100644 src/BuildVision.Contracts/Models/IBuildProgressViewModel.cs delete mode 100644 src/BuildVision.Exports/Providers/IBuildingProjectsProvider.cs create mode 100644 src/BuildVision.Exports/Sevices/ITaskBarInfoService.cs create mode 100644 src/BuildVision.UI/Converters/InProgressToBoolConverter.cs rename src/BuildVision.UI/{Helpers => Models}/SortDescription.cs (100%) rename src/BuildVision.UI/{Helpers => Models}/WindowStateAction.cs (100%) create mode 100644 src/BuildVision/ApplicationInsights.config delete mode 100644 src/BuildVision/Core/IPackageContext.cs create mode 100644 src/BuildVision/Extensions/IServiceProviderExtensions.cs delete mode 100644 src/BuildVision/Services/BuildProgressViewModel.cs delete mode 100644 src/BuildVision/Services/BuildingProjectsProvider.cs create mode 100644 src/BuildVision/Services/TaskBarInfoService.cs diff --git a/src/BuildVision.Common/AppVersionInfo.cs b/src/BuildVision.Common/AppVersionInfo.cs index 1b98f9c5..42517575 100644 --- a/src/BuildVision.Common/AppVersionInfo.cs +++ b/src/BuildVision.Common/AppVersionInfo.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; using System.Reflection; diff --git a/src/BuildVision.Common/BuildVision.Common.csproj b/src/BuildVision.Common/BuildVision.Common.csproj index ead7e4ce..a29e2344 100644 --- a/src/BuildVision.Common/BuildVision.Common.csproj +++ b/src/BuildVision.Common/BuildVision.Common.csproj @@ -12,6 +12,10 @@ + + + + diff --git a/src/BuildVision.Common/Diagnostics/DiagnosticsClient.cs b/src/BuildVision.Common/Diagnostics/DiagnosticsClient.cs new file mode 100644 index 00000000..cd976446 --- /dev/null +++ b/src/BuildVision.Common/Diagnostics/DiagnosticsClient.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using Microsoft.ApplicationInsights; +using Microsoft.ApplicationInsights.Extensibility; + +namespace BuildVision.Common.Diagnostics +{ + public static class DiagnosticsClient + { + private static bool _initialized; + private static TelemetryClient _client; + + + public static void Initialize(string apiKey) + { + if (!string.IsNullOrWhiteSpace(apiKey)) + { + TelemetryConfiguration.Active.InstrumentationKey = apiKey; + TelemetryConfiguration.Active.TelemetryChannel.DeveloperMode = Debugger.IsAttached; + TelemetryConfiguration.Active.TelemetryInitializers.Add(new VersionTelemetry()); + TelemetryConfiguration.Active.TelemetryInitializers.Add(new SessionTelemetry()); + + _initialized = true; + + _client = new TelemetryClient(); + } + } + + public static void OnExit() + { + if (!_initialized) return; + + _client.Flush(); + // Allow time for flushing: + System.Threading.Thread.Sleep(1000); + } + + public static void TrackEvent(string eventName, IDictionary properties = null, IDictionary metrics = null) + { + if (!_initialized) return; + _client.TrackEvent(eventName, properties, metrics); + } + + public static void TrackTrace(string evt) + { + if (!_initialized) return; + _client.TrackTrace(evt); + } + + public static void Notify(Exception exception) + { + if (!_initialized) return; + + _client.TrackException(exception); + } + + public static void TrackPageView(string pageName) + { + if (!_initialized) return; + + _client.TrackPageView(pageName); + } + } +} diff --git a/src/BuildVision.Common/Diagnostics/SessionTelemetry.cs b/src/BuildVision.Common/Diagnostics/SessionTelemetry.cs new file mode 100644 index 00000000..681c7115 --- /dev/null +++ b/src/BuildVision.Common/Diagnostics/SessionTelemetry.cs @@ -0,0 +1,62 @@ +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Security.Cryptography; +using System.Text; +using Microsoft.ApplicationInsights.Channel; +using Microsoft.ApplicationInsights.Extensibility; + +namespace BuildVision.Common.Diagnostics +{ + class SessionTelemetry : ITelemetryInitializer + { + private readonly string _userName; + private readonly string _operatingSystem = RuntimeInformation.OSDescription?.Replace("Microsoft ", ""); // Shorter description + private readonly string _session = Guid.NewGuid().ToString(); + +#if STORE + private const string Channel = "store"; +#elif NIGHTLY + private const string Channel = "nightly"; +#elif CHOCO + private const string Channel = "chocolatey"; +#else + private const string Channel = "zip"; +#endif + + + public SessionTelemetry() + { + try + { + using (var hash = SHA256.Create()) + { + var hashBytes = hash.ComputeHash(Encoding.UTF8.GetBytes(Environment.MachineName + Environment.UserDomainName + Environment.UserName)); + _userName = Convert.ToBase64String(hashBytes); + } + } + catch + { + // No user id + } + } + + public void Initialize(ITelemetry telemetry) + { + telemetry.Context.GlobalProperties["Environment"] = Channel; + // Always default to development if we're in the debugger + if (Debugger.IsAttached) + { + telemetry.Context.GlobalProperties["Environment"] = "development"; + } + + if (_userName != null) + { + telemetry.Context.User.Id = _userName; + } + + telemetry.Context.Session.Id = _session; + telemetry.Context.Device.OperatingSystem = _operatingSystem; + } + } +} diff --git a/src/BuildVision.Common/Diagnostics/VersionTelemetry.cs b/src/BuildVision.Common/Diagnostics/VersionTelemetry.cs new file mode 100644 index 00000000..f2419183 --- /dev/null +++ b/src/BuildVision.Common/Diagnostics/VersionTelemetry.cs @@ -0,0 +1,25 @@ +using System; +using System.Linq; +using System.Reflection; +using Microsoft.ApplicationInsights.Channel; +using Microsoft.ApplicationInsights.Extensibility; + +namespace BuildVision.Common.Diagnostics +{ + class VersionTelemetry : ITelemetryInitializer + { + private readonly string _appVersion; + + public VersionTelemetry() + { + _appVersion = typeof(DiagnosticsClient).Assembly.GetCustomAttributes() + .FirstOrDefault(ama => string.Equals(ama.Key, "CloudBuildNumber", StringComparison.OrdinalIgnoreCase)) + ?.Value; + } + + public void Initialize(ITelemetry telemetry) + { + telemetry.Context.Component.Version = _appVersion; + } + } +} diff --git a/src/BuildVision.Contracts/Models/IBuildProgressViewModel.cs b/src/BuildVision.Contracts/Models/IBuildProgressViewModel.cs deleted file mode 100644 index e6b46b25..00000000 --- a/src/BuildVision.Contracts/Models/IBuildProgressViewModel.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace BuildVision.Contracts.Models -{ - public interface IBuildProgressViewModel - { - bool ActionProgressIsPaused { get; set; } - int CurrentQueuePosOfBuildingProject { get; } - - void OnBuildBegin(IBuildInformationModel buildInformationModel, int projectsCount); - void OnBuildCancelled(); - void OnBuildDone(); - void OnBuildProjectBegin(); - void OnBuildProjectDone(bool success); - void ResetTaskBarInfo(bool ifTaskBarProgressEnabled = true); - } -} diff --git a/src/BuildVision.Exports/Providers/IBuildInformationProvider.cs b/src/BuildVision.Exports/Providers/IBuildInformationProvider.cs index 6a6b86b1..d5cb7a31 100644 --- a/src/BuildVision.Exports/Providers/IBuildInformationProvider.cs +++ b/src/BuildVision.Exports/Providers/IBuildInformationProvider.cs @@ -1,4 +1,6 @@ using System.Collections.Generic; +using System.Collections.ObjectModel; +using BuildVision.Contracts; using BuildVision.Contracts.Models; using BuildVision.UI.Models; @@ -6,8 +8,13 @@ namespace BuildVision.Exports.Providers { public interface IBuildInformationProvider { - void BuildFinished(IEnumerable projects, bool success, bool canceled); - void BuildStarted(uint dwAction); + ObservableCollection GetBuildingProjects(); + void ProjectBuildStarted(IProjectItem projectItem, BuildActions buildAction); + void ProjectBuildFinished(BuildActions buildAction, string projectIdentifier, bool succeess, bool canceled); + void ReloadCurrentProjects(); + void ResetCurrentProjects(); + void BuildFinished(bool success, bool canceled); + void BuildStarted(BuildActions buildAction); void BuildUpdate(); void ResetBuildInformationModel(); IBuildInformationModel GetBuildInformationModel(); diff --git a/src/BuildVision.Exports/Providers/IBuildingProjectsProvider.cs b/src/BuildVision.Exports/Providers/IBuildingProjectsProvider.cs deleted file mode 100644 index e7002665..00000000 --- a/src/BuildVision.Exports/Providers/IBuildingProjectsProvider.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.Collections.ObjectModel; -using BuildVision.UI.Contracts; -using BuildVision.UI.Models; - -namespace BuildVision.Exports.Providers -{ - public interface IBuildingProjectsProvider - { - ObservableCollection GetBuildingProjects(); - void ProjectBuildStarted(IProjectItem projectItem, uint dwAction); - void ProjectBuildFinished(string projectIdentifier, bool succeess, bool canceled); - void ReloadCurrentProjects(); - void ResetCurrentProjects(); - bool TryGetProjectItem(BuildProjectContextEntry projectEntry, out IProjectItem projectItem); - } -} diff --git a/src/BuildVision.Exports/Sevices/IBuildService.cs b/src/BuildVision.Exports/Sevices/IBuildService.cs index 42789b89..8695f752 100644 --- a/src/BuildVision.Exports/Sevices/IBuildService.cs +++ b/src/BuildVision.Exports/Sevices/IBuildService.cs @@ -1,14 +1,14 @@ -namespace BuildVision.Exports.Services +using BuildVision.UI.Models; + +namespace BuildVision.Exports.Services { public interface IBuildService { - void ShowGridColumnsSettingsPage(); - void ShowGeneralSettingsPage(); void BuildSolution(); void CleanSolution(); void RebuildSolution(); void CancelBuildSolution(); - void ProjectCopyBuildOutputFilesToClipBoard(); - void RaiseCommandForSelectedProject(); + void ProjectCopyBuildOutputFilesToClipBoard(IProjectItem projItem); + void RaiseCommandForSelectedProject(IProjectItem projectItem, int command); } } diff --git a/src/BuildVision.Exports/Sevices/ITaskBarInfoService.cs b/src/BuildVision.Exports/Sevices/ITaskBarInfoService.cs new file mode 100644 index 00000000..58f39b8e --- /dev/null +++ b/src/BuildVision.Exports/Sevices/ITaskBarInfoService.cs @@ -0,0 +1,10 @@ +using BuildVision.Contracts; + +namespace BuildVision.Exports.Services +{ + public interface ITaskBarInfoService + { + void ResetTaskBarInfo(bool ifTaskBarProgressEnabled = true); + void UpdateTaskBarInfo(BuildState buildState, BuildScopes buildScope, int projectsCount, int finishedProjects); + } +} diff --git a/src/BuildVision.UI/BuildVision.UI.csproj b/src/BuildVision.UI/BuildVision.UI.csproj index 0a96eab7..987a546f 100644 --- a/src/BuildVision.UI/BuildVision.UI.csproj +++ b/src/BuildVision.UI/BuildVision.UI.csproj @@ -89,14 +89,15 @@ + - + - + @@ -372,9 +373,15 @@ + + 2.10.17-preview + 14.3.25407 + + + \ No newline at end of file diff --git a/src/BuildVision.UI/Components/ControlView.xaml b/src/BuildVision.UI/Components/ControlView.xaml index cd23afca..52f95327 100644 --- a/src/BuildVision.UI/Components/ControlView.xaml +++ b/src/BuildVision.UI/Components/ControlView.xaml @@ -42,7 +42,7 @@ - + @@ -115,26 +115,16 @@ HorizontalAlignment="Stretch" MinWidth="66" ToolTip="{x:Static res:Resources.CancelBuildSolutionButtonTooltip}" - IsEnabled="False" + IsEnabled="{Binding BuildInformationModel.CurrentBuildState, Converter={StaticResource InProgressToBoolConverter}}" Visibility="{Binding BuildInformationModel.CurrentBuildState, Converter={StaticResource InProgressToVisibleConverter}}"> - + - - - - + diff --git a/src/BuildVision.UI/Converters/InProgressToBoolConverter.cs b/src/BuildVision.UI/Converters/InProgressToBoolConverter.cs new file mode 100644 index 00000000..71f80f74 --- /dev/null +++ b/src/BuildVision.UI/Converters/InProgressToBoolConverter.cs @@ -0,0 +1,22 @@ +using System; +using System.Globalization; +using System.Windows.Data; +using BuildVision.Contracts; + +namespace BuildVision.UI.Converters +{ + [ValueConversion(typeof(BuildState), typeof(bool))] + public class InProgressToBoolConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + var buildState = (BuildState)value; + return buildState == BuildState.InProgress; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/BuildVision.UI/DataGrid/DataGridContentControlColumn.cs b/src/BuildVision.UI/DataGrid/DataGridContentControlColumn.cs index 5ead63b3..235c8497 100644 --- a/src/BuildVision.UI/DataGrid/DataGridContentControlColumn.cs +++ b/src/BuildVision.UI/DataGrid/DataGridContentControlColumn.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Windows; using System.Windows.Controls; using System.Windows.Data; @@ -9,9 +9,11 @@ public class DataGridContentControlColumn : DataGridBoundColumn { protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem) { - ContentControl contentControl = (cell != null) ? (cell.Content as ContentControl) : null; + var contentControl = (cell != null) ? (cell.Content as ContentControl) : null; if (contentControl == null) + { contentControl = new ContentControl(); + } contentControl.ClipToBounds = true; contentControl.SnapsToDevicePixels = true; @@ -26,4 +28,4 @@ protected override FrameworkElement GenerateEditingElement(DataGridCell cell, ob throw new InvalidOperationException(); } } -} \ No newline at end of file +} diff --git a/src/BuildVision.UI/Helpers/BuildMessagesFactory.cs b/src/BuildVision.UI/Helpers/BuildMessagesFactory.cs index 598692d8..6283bc51 100644 --- a/src/BuildVision.UI/Helpers/BuildMessagesFactory.cs +++ b/src/BuildVision.UI/Helpers/BuildMessagesFactory.cs @@ -52,17 +52,14 @@ private string GetMainString(IBuildInformationModel buildInformationModel) private string GetTimeString(DateTime? startTime) { - string timeString = ""; try { - timeString = startTime.Value.ToString(_packageSettingsProvider.Settings.BuildMessagesSettings.DateTimeFormat); + return startTime.Value.ToString(_packageSettingsProvider.Settings.BuildMessagesSettings.DateTimeFormat); } catch (FormatException) { - timeString = Resources.InvalidTimeStringFormat; + return Resources.InvalidTimeStringFormat; } - - return timeString; } private string GetBeginAtString(BuildActions? buildAction) @@ -133,7 +130,7 @@ public string GetBuildBeginExtraMessage(IBuildInformationModel buildInformationM return string.Empty; } - TimeSpan timeSpan = DateTime.Now.Subtract(buildInformationModel.BuildStartTime.Value); + var timeSpan = DateTime.Now.Subtract(buildInformationModel.BuildStartTime.Value); if (timeSpan.TotalSeconds > _packageSettingsProvider.Settings.BuildMessagesSettings.ExtraMessageDelay) { return GetExtraTimePartString( timeSpan); diff --git a/src/BuildVision.UI/IPackageSettingsProvider.cs b/src/BuildVision.UI/IPackageSettingsProvider.cs index 6ea186a1..1ab1d206 100644 --- a/src/BuildVision.UI/IPackageSettingsProvider.cs +++ b/src/BuildVision.UI/IPackageSettingsProvider.cs @@ -1,4 +1,5 @@ -using System.ComponentModel; +using System; +using System.ComponentModel; using BuildVision.UI.Settings.Models; namespace BuildVision.Views.Settings @@ -8,5 +9,7 @@ public interface IPackageSettingsProvider : INotifyPropertyChanged void Save(); ControlSettings Settings { get; } + + event Action SettingsChanged; } } diff --git a/src/BuildVision.UI/Models/GridColumnSettingsCollection.cs b/src/BuildVision.UI/Models/GridColumnSettingsCollection.cs index 4b3a9afb..530f7dd1 100644 --- a/src/BuildVision.UI/Models/GridColumnSettingsCollection.cs +++ b/src/BuildVision.UI/Models/GridColumnSettingsCollection.cs @@ -1,12 +1,9 @@ -using System.Collections.Generic; +using System.Collections.Generic; namespace BuildVision.UI.Settings.Models.Columns { public class GridColumnSettingsCollection : List { - public GridColumnSettings this[string propertyName] - { - get { return Find(s => s.PropertyNameId == propertyName); } - } + public GridColumnSettings this[string propertyName] => Find(s => s.PropertyNameId == propertyName); } -} \ No newline at end of file +} diff --git a/src/BuildVision.UI/Helpers/SortDescription.cs b/src/BuildVision.UI/Models/SortDescription.cs similarity index 100% rename from src/BuildVision.UI/Helpers/SortDescription.cs rename to src/BuildVision.UI/Models/SortDescription.cs diff --git a/src/BuildVision.UI/Helpers/WindowStateAction.cs b/src/BuildVision.UI/Models/WindowStateAction.cs similarity index 100% rename from src/BuildVision.UI/Helpers/WindowStateAction.cs rename to src/BuildVision.UI/Models/WindowStateAction.cs diff --git a/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs b/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs index 9bbd8ffc..b0aca8d8 100644 --- a/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs +++ b/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs @@ -1,42 +1,51 @@ using System; using System.Collections.ObjectModel; +using System.ComponentModel; +using System.ComponentModel.Composition; using System.Diagnostics; using System.IO; +using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Input; -using System.ComponentModel; - -using Process = System.Diagnostics.Process; using BuildVision.Common; using BuildVision.Contracts; -using BuildVision.UI.DataGrid; +using BuildVision.Contracts.Models; +using BuildVision.Core; +using BuildVision.Exports.Providers; +using BuildVision.Exports.Services; +using BuildVision.Exports.ViewModels; +using BuildVision.Helpers; using BuildVision.UI.Common.Logging; +using BuildVision.UI.DataGrid; using BuildVision.UI.Helpers; using BuildVision.UI.Models; -using BuildVision.UI.Settings.Models.Columns; -using SortDescription = BuildVision.UI.Settings.Models.Sorting.SortDescription; using BuildVision.UI.Settings.Models; -using BuildVision.Helpers; -using System.ComponentModel.Composition; -using System.Text; -using BuildVision.Core; +using BuildVision.UI.Settings.Models.Columns; using BuildVision.Views.Settings; -using BuildVision.Exports.Services; -using BuildVision.Exports.ViewModels; -using BuildVision.Exports.Providers; -using BuildVision.Contracts.Models; using Microsoft.VisualStudio; +using Process = System.Diagnostics.Process; +using SortDescription = BuildVision.UI.Settings.Models.Sorting.SortDescription; namespace BuildVision.UI.ViewModels { [Export(typeof(IBuildVisionPaneViewModel))] public class BuildVisionPaneViewModel : BindableBase, IBuildVisionPaneViewModel { + private ProjectItem _selectedProjectItem; + private readonly IBuildInformationProvider _buildInformationProvider; + private readonly IBuildService _buildService; + private readonly IErrorNavigationService _errorNavigationService; + private readonly ITaskBarInfoService _taskBarInfoService; + private readonly IPackageSettingsProvider _settingsProvider; + private ObservableCollection _gridColumnsRef; + public ISolutionModel SolutionModel { get; set; } - private ObservableCollection _gridColumnsRef; + public string GridGroupHeaderName => string.IsNullOrEmpty(GridGroupPropertyName) ? string.Empty : ControlSettings.GridSettings.Columns[GridGroupPropertyName].Header; + + public CompositeCollection GridColumnsGroupMenuItems => CreateContextMenu(); public bool HideUpToDateTargets { @@ -66,19 +75,6 @@ public string GridGroupPropertyName } } - public string GridGroupHeaderName - { - get - { - if (string.IsNullOrEmpty(GridGroupPropertyName)) - return string.Empty; - - return ControlSettings.GridSettings.Columns[GridGroupPropertyName].Header; - } - } - - public CompositeCollection GridColumnsGroupMenuItems => CreateContextMenu(); - private CompositeCollection CreateContextMenu() { var collection = new CompositeCollection(); @@ -88,7 +84,7 @@ private CompositeCollection CreateContextMenu() Tag = string.Empty }); - foreach (GridColumnSettings column in ControlSettings.GridSettings.Columns) + foreach (var column in ControlSettings.GridSettings.Columns) { if (!ColumnsManager.ColumnIsGroupable(column)) continue; @@ -181,35 +177,44 @@ public DataGridHeadersVisibility GridHeadersVisibility } } - private ProjectItem _selectedProjectItem; - private readonly IBuildingProjectsProvider _buildingProjectsProvider; - private readonly IBuildInformationProvider _buildInformationProvider; - private readonly IBuildService _buildService; - private readonly IErrorNavigationService _errorNavigationService; - public ProjectItem SelectedProjectItem { get => _selectedProjectItem; set => SetProperty(ref _selectedProjectItem, value); } + internal BuildVisionPaneViewModel() + { + ControlSettings = new ControlSettings(); + BuildInformationModel = new BuildInformationModel(); + SolutionModel = new SolutionModel(); + Projects = new ObservableCollection(); + } + [ImportingConstructor] public BuildVisionPaneViewModel( - IBuildingProjectsProvider buildingProjectsProvider, IBuildInformationProvider buildInformationProvider, IPackageSettingsProvider settingsProvider, ISolutionProvider solutionProvider, IBuildService buildService, - IErrorNavigationService errorNavigationService) + IErrorNavigationService errorNavigationService, + ITaskBarInfoService taskBarInfoService) { - _buildingProjectsProvider = buildingProjectsProvider; _buildInformationProvider = buildInformationProvider; _buildService = buildService; _errorNavigationService = errorNavigationService; + _taskBarInfoService = taskBarInfoService; BuildInformationModel = _buildInformationProvider.GetBuildInformationModel(); SolutionModel = solutionProvider.GetSolutionModel(); ControlSettings = settingsProvider.Settings; - Projects = _buildingProjectsProvider.GetBuildingProjects(); + Projects = _buildInformationProvider.GetBuildingProjects(); + + _settingsProvider = settingsProvider; + _settingsProvider.SettingsChanged += () => + { + SyncColumnSettings(); + OnControlSettingsChanged(); + }; if (settingsProvider.Settings.GeneralSettings.FillProjectListOnBuildBegin) { @@ -220,18 +225,6 @@ public BuildVisionPaneViewModel( } } - - /// - /// Uses as design-time ViewModel. - /// - internal BuildVisionPaneViewModel() - { - ControlSettings = new ControlSettings(); - BuildInformationModel = new BuildInformationModel(); - SolutionModel = new SolutionModel(); - Projects = new ObservableCollection(); - } - private void OpenContainingFolder() { try @@ -284,7 +277,7 @@ private void ReorderGrid(object obj) private static ProjectItemColumnSorter GetProjectItemSorter(SortDescription sortDescription) { - SortOrder sortOrder = sortDescription.Order; + var sortOrder = sortDescription.Order; string sortPropertyName = sortDescription.Property; if (sortOrder != SortOrder.None && !string.IsNullOrEmpty(sortPropertyName)) @@ -318,22 +311,13 @@ public void SyncColumnSettings() ColumnsManager.SyncColumnSettings(_gridColumnsRef, ControlSettings.GridSettings); } - public void OnControlSettingsChanged(ControlSettings settings) + public void OnControlSettingsChanged() { - ControlSettings.InitFrom(settings); - + ControlSettings.InitFrom(_settingsProvider.Settings); GenerateColumns(); - - //Refresh build message - //if (_buildState == BuildState.Done) - //{ - // Model.TextCurrentState = getBuildMessage(_buildInfo); - //} - // Raise all properties have changed. OnPropertyChanged(null); - - //BuildProgressViewModel.ResetTaskBarInfo(false); + _taskBarInfoService.ResetTaskBarInfo(false); } private bool IsProjectItemEnabledForActions() @@ -370,22 +354,13 @@ private void CopyErrorMessageToClipboard(ProjectItem projectItem) public ICommand SelectedProjectOpenContainingFolderAction => new RelayCommand(obj => OpenContainingFolder(), canExecute: obj => (SelectedProjectItem != null && !string.IsNullOrEmpty(SelectedProjectItem.FullName))); - //public ICommand SelectedProjectCopyBuildOutputFilesToClipboardAction => new RelayCommand( - // obj => _buildService.ProjectCopyBuildOutputFilesToClipBoard(SelectedProjectItem), - // canExecute: obj => (SelectedProjectItem != null && !string.IsNullOrEmpty(SelectedProjectItem.UniqueName) && !ControlSettings.ProjectItemSettings.CopyBuildOutputFileTypesToClipboard.IsEmpty)); + public ICommand SelectedProjectCopyBuildOutputFilesToClipboardAction => new RelayCommand(obj => _buildService.ProjectCopyBuildOutputFilesToClipBoard(SelectedProjectItem), canExecute: obj => (SelectedProjectItem != null && !string.IsNullOrEmpty(SelectedProjectItem.UniqueName) && !ControlSettings.ProjectItemSettings.CopyBuildOutputFileTypesToClipboard.IsEmpty)); - //public ICommand SelectedProjectBuildAction => new RelayCommand( - // obj => _buildService.RaiseCommandForSelectedProject(SelectedProjectItem, (int)VSConstants.VSStd97CmdID.BuildCtx), - // canExecute: obj => IsProjectItemEnabledForActions()); + public ICommand SelectedProjectBuildAction => new RelayCommand(obj => _buildService.RaiseCommandForSelectedProject(SelectedProjectItem, (int)VSConstants.VSStd97CmdID.BuildCtx), canExecute: obj => IsProjectItemEnabledForActions()); + public ICommand SelectedProjectRebuildAction => new RelayCommand(obj => _buildService.RaiseCommandForSelectedProject(SelectedProjectItem, (int)VSConstants.VSStd97CmdID.RebuildCtx), canExecute: obj => IsProjectItemEnabledForActions()); - //public ICommand SelectedProjectRebuildAction => new RelayCommand( - // obj => _buildService.RaiseCommandForSelectedProject(SelectedProjectItem, (int)VSConstants.VSStd97CmdID.RebuildCtx), - // canExecute: obj => IsProjectItemEnabledForActions()); - - //public ICommand SelectedProjectCleanAction => new RelayCommand( - // obj => _buildService.RaiseCommandForSelectedProject(SelectedProjectItem, (int)VSConstants.VSStd97CmdID.CleanCtx), - // canExecute: obj => IsProjectItemEnabledForActions()); + public ICommand SelectedProjectCleanAction => new RelayCommand(obj => _buildService.RaiseCommandForSelectedProject(SelectedProjectItem, (int)VSConstants.VSStd97CmdID.CleanCtx), canExecute: obj => IsProjectItemEnabledForActions()); public ICommand SelectedProjectCopyErrorMessagesAction => new RelayCommand(obj => CopyErrorMessageToClipboard(SelectedProjectItem), canExecute: obj => SelectedProjectItem?.ErrorsCount > 0); @@ -397,10 +372,12 @@ private void CopyErrorMessageToClipboard(ProjectItem projectItem) public ICommand CancelBuildSolutionAction => new RelayCommand(obj => _buildService.CancelBuildSolution()); - public ICommand OpenGridColumnsSettingsAction => new RelayCommand(obj => _buildService.ShowGridColumnsSettingsPage()); + public ICommand OpenGridColumnsSettingsAction => new RelayCommand(obj => ShowOptionPage?.Invoke(typeof(GridSettings))); - public ICommand OpenGeneralSettingsAction => new RelayCommand(obj => _buildService.ShowGeneralSettingsPage()); + public ICommand OpenGeneralSettingsAction => new RelayCommand(obj => ShowOptionPage?.Invoke(typeof(GeneralSettings))); #endregion + + public event Action ShowOptionPage; } } diff --git a/src/BuildVision/ApplicationInsights.config b/src/BuildVision/ApplicationInsights.config new file mode 100644 index 00000000..ea80d3ef --- /dev/null +++ b/src/BuildVision/ApplicationInsights.config @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/src/BuildVision/BuildVision.csproj b/src/BuildVision/BuildVision.csproj index 09dd1c90..b5d176fb 100644 --- a/src/BuildVision/BuildVision.csproj +++ b/src/BuildVision/BuildVision.csproj @@ -92,9 +92,8 @@ + - - @@ -117,7 +116,7 @@ - + Component @@ -151,6 +150,9 @@ + + PreserveNewest + Designer @@ -222,6 +224,9 @@ + + 2.10.17-preview + 8.0.2 diff --git a/src/BuildVision/Core/BuildVisionPackage.cs b/src/BuildVision/Core/BuildVisionPackage.cs index 7262f7bf..17ff8650 100644 --- a/src/BuildVision/Core/BuildVisionPackage.cs +++ b/src/BuildVision/Core/BuildVisionPackage.cs @@ -38,7 +38,7 @@ namespace BuildVision.Core [ProvideOptionPage(typeof(GridSettingsDialogPage), "BuildVision", "Projects Grid", 0, 0, true)] [ProvideOptionPage(typeof(BuildMessagesSettingsDialogPage), "BuildVision", "Build Messages", 0, 0, true)] [ProvideOptionPage(typeof(ProjectItemSettingsDialogPage), "BuildVision", "Project Item", 0, 0, true)] - public sealed partial class BuildVisionPackage : AsyncPackage, IPackageContext + public sealed partial class BuildVisionPackage : AsyncPackage { private DTE _dte; private DTE2 _dte2; @@ -51,9 +51,7 @@ public sealed partial class BuildVisionPackage : AsyncPackage, IPackageContext private uint _updateSolutionEvents4Cookie; private SolutionBuildEvents _solutionBuildEvents; private ISolutionProvider _solutionProvider; - private IBuildingProjectsProvider _buildingProjectsProvider; private Window _activeProjectContext; - private IErrorNavigationService _errorNavigationService; public ControlSettings ControlSettings { get; set; } @@ -74,8 +72,6 @@ private void Current_DispatcherUnhandledException(object sender, DispatcherUnhan e.Handled = true; } - public event Action ControlSettingsChanged = delegate { }; - protected override async Task InitializeAsync(CancellationToken cancellationToken, IProgress progress) { await base.InitializeAsync(cancellationToken, progress); @@ -97,13 +93,9 @@ protected override async Task InitializeAsync(CancellationToken cancellationToke Assumes.Present(_buildInformationProvider); _solutionProvider = await GetServiceAsync(typeof(ISolutionProvider)) as ISolutionProvider; Assumes.Present(_solutionProvider); - _buildingProjectsProvider = await GetServiceAsync(typeof(IBuildingProjectsProvider)) as IBuildingProjectsProvider; - Assumes.Present(_buildingProjectsProvider); - - IPackageContext packageContext = this; _commandEvents = _dte.Events.CommandEvents; - // _commandEvents.AfterExecute += CommandEvents_AfterExecute; + _commandEvents.AfterExecute += CommandEvents_AfterExecute; _windowEvents = _dte.Events.WindowEvents; _windowEvents.WindowActivated += WindowEvents_WindowActivated; @@ -123,10 +115,10 @@ private void SolutionEvents_Opened() ThreadHelper.ThrowIfNotOnUIThread(); _solutionProvider.ReloadSolution(); - _buildingProjectsProvider.ResetCurrentProjects(); + _buildInformationProvider.ResetCurrentProjects(); _buildInformationProvider.ResetBuildInformationModel(); - _solutionBuildEvents = new SolutionBuildEvents(_solutionProvider, _buildInformationProvider, _buildingProjectsProvider); + _solutionBuildEvents = new SolutionBuildEvents(_solutionProvider, _buildInformationProvider); _solutionBuildManager.AdviseUpdateSolutionEvents(_solutionBuildEvents, out _updateSolutionEvents4Cookie); _solutionBuildManager4.AdviseUpdateSolutionEvents4(_solutionBuildEvents, out _updateSolutionEvents4Cookie); } @@ -136,14 +128,13 @@ private void SolutionEvents_AfterClosing() ThreadHelper.ThrowIfNotOnUIThread(); _solutionProvider.ReloadSolution(); - _buildingProjectsProvider.ResetCurrentProjects(); + _buildInformationProvider.ResetCurrentProjects(); _buildInformationProvider.ResetBuildInformationModel(); _solutionBuildManager.UnadviseUpdateSolutionEvents(_updateSolutionEvents4Cookie); _solutionBuildManager4.UnadviseUpdateSolutionEvents4(_updateSolutionEvents4Cookie); } - private void WindowEvents_WindowActivated(Window gotFocus, Window lostFocus) { if (gotFocus == null) @@ -229,16 +220,5 @@ ToolWindowPane ShowToolWindow(Guid windowGuid) } return docView as ToolWindowPane; } - - public void NotifyControlSettingsChanged() - { - ControlSettingsChanged(ControlSettings); - } - - public async Task ExecuteCommandAsync(string commandName) - { - await JoinableTaskFactory.SwitchToMainThreadAsync(DisposalToken); - _dte.ExecuteCommand(commandName); - } } } diff --git a/src/BuildVision/Core/BuildVisionPane.cs b/src/BuildVision/Core/BuildVisionPane.cs index 395c15d4..1e6fe568 100644 --- a/src/BuildVision/Core/BuildVisionPane.cs +++ b/src/BuildVision/Core/BuildVisionPane.cs @@ -17,6 +17,8 @@ using BuildVision.Views.Settings; using Microsoft.VisualStudio.Shell.Interop; using System.Windows.Controls; +using BuildVision.UI.Settings.Models; +using BuildVision.UI.Settings.Models.Columns; namespace BuildVision.Tool { @@ -33,19 +35,16 @@ namespace BuildVision.Tool public sealed class BuildVisionPane : ToolWindowPane { private bool _controlCreatedSuccessfully; - private readonly BuildVisionPaneViewModel _viewModel; JoinableTask viewModelTask; private ContentPresenter _contentPresenter; + private IPackageSettingsProvider _packageSettingsProvider; public JoinableTaskFactory JoinableTaskFactory { get; private set; } public ControlView View { - get { return _contentPresenter.Content as ControlView; } - set - { - _contentPresenter.Content = value; - } + get => _contentPresenter.Content as ControlView; + set => _contentPresenter.Content = value; } public BuildVisionPane() @@ -76,49 +75,48 @@ protected override void Initialize() async Task InitializeAsync(AsyncPackage asyncPackage) { await JoinableTaskFactory.SwitchToMainThreadAsync(); - try - { - var solutionProvider = await asyncPackage.GetServiceAsync(typeof(ISolutionProvider)) as ISolutionProvider; - Assumes.Present(solutionProvider); - var buildInformationProvider = await asyncPackage.GetServiceAsync(typeof(IBuildInformationProvider)) as IBuildInformationProvider; - Assumes.Present(buildInformationProvider); - var buildingProjectsProvider = await asyncPackage.GetServiceAsync(typeof(IBuildingProjectsProvider)) as IBuildingProjectsProvider; - Assumes.Present(buildingProjectsProvider); - var buildService = await asyncPackage.GetServiceAsync(typeof(IBuildService)) as IBuildService; - Assumes.Present(buildService); - var packageSettingsProvider = await asyncPackage.GetServiceAsync(typeof(IPackageSettingsProvider)) as IPackageSettingsProvider; - Assumes.Present(packageSettingsProvider); - var errorNavigationService = await asyncPackage.GetServiceAsync(typeof(IErrorNavigationService)) as IErrorNavigationService; - Assumes.Present(packageSettingsProvider); - - var viewModel = new BuildVisionPaneViewModel(buildingProjectsProvider, buildInformationProvider, packageSettingsProvider, solutionProvider, buildService, errorNavigationService); - - View = CreateControlView(); - View.DataContext = viewModel; - _controlCreatedSuccessfully = true; - return viewModel; - } - catch (Exception e) - { - throw; - } + + _packageSettingsProvider = await asyncPackage.GetServiceAsync(typeof(IPackageSettingsProvider)) as IPackageSettingsProvider; + Assumes.Present(_packageSettingsProvider); + var solutionProvider = await asyncPackage.GetServiceAsync(typeof(ISolutionProvider)) as ISolutionProvider; + Assumes.Present(solutionProvider); + var buildInformationProvider = await asyncPackage.GetServiceAsync(typeof(IBuildInformationProvider)) as IBuildInformationProvider; + Assumes.Present(buildInformationProvider); + var buildService = await asyncPackage.GetServiceAsync(typeof(IBuildService)) as IBuildService; + Assumes.Present(buildService); + var errorNavigationService = await asyncPackage.GetServiceAsync(typeof(IErrorNavigationService)) as IErrorNavigationService; + Assumes.Present(errorNavigationService); + var taskBarInfoService = await asyncPackage.GetServiceAsync(typeof(ITaskBarInfoService)) as ITaskBarInfoService; + Assumes.Present(taskBarInfoService); + + var viewModel = new BuildVisionPaneViewModel(buildInformationProvider, _packageSettingsProvider, solutionProvider, buildService, errorNavigationService, taskBarInfoService); + + View = CreateControlView(); + View.DataContext = viewModel; + viewModel.ShowOptionPage += ViewModel_ShowOptionPage; + _controlCreatedSuccessfully = true; + return viewModel; + } + + private void ViewModel_ShowOptionPage(Type obj) + { + var asyncPackage = (AsyncPackage)Package; + if (obj == typeof(GeneralSettings)) + asyncPackage.ShowOptionPage(typeof(GeneralSettingsDialogPage)); + if(obj == typeof(GridColumnSettings)) + asyncPackage.ShowOptionPage(typeof(GridSettingsDialogPage)); } protected override void OnClose() { if (_controlCreatedSuccessfully) - SaveControlSettings(); + _packageSettingsProvider.Save(); base.OnClose(); } private ControlView CreateControlView() { - var packageContext = (IPackageContext)Package; - packageContext.ControlSettingsChanged += (settings) => - { - _viewModel.OnControlSettingsChanged(settings); //, buildInfo => BuildMessages.GetBuildDoneMessage(viewModel.SolutionItem, buildInfo, viewModel.ControlSettings.BuildMessagesSettings)); - }; var view = new ControlView(); view.Resources.MergedDictionaries.Add(new ResourceDictionary { @@ -126,20 +124,5 @@ private ControlView CreateControlView() }); return view; } - - private void SaveControlSettings() - { - var viewModel = GetViewModel(this); - viewModel.SyncColumnSettings(); - - var packageContext = (IPackageContext)Package; - //packageContext.SaveSettings(); - } - - public static BuildVisionPaneViewModel GetViewModel(ToolWindowPane toolWindow) - { - var controlView = (ControlView)toolWindow.Content; - return (BuildVisionPaneViewModel)controlView.DataContext; - } } } diff --git a/src/BuildVision/Core/IPackageContext.cs b/src/BuildVision/Core/IPackageContext.cs deleted file mode 100644 index 21c7c078..00000000 --- a/src/BuildVision/Core/IPackageContext.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; -using Microsoft.VisualStudio.Shell; -using BuildVision.UI.Settings.Models; - -using Task = System.Threading.Tasks.Task; - -namespace BuildVision.Core -{ - public interface IPackageContext - { - event Action ControlSettingsChanged; - void NotifyControlSettingsChanged(); - void ShowOptionPage(Type optionsPageType); - Task ExecuteCommandAsync(string command); - } -} diff --git a/src/BuildVision/Core/ServiceProviderPackage.cs b/src/BuildVision/Core/ServiceProviderPackage.cs index 35265b1f..fea7f084 100644 --- a/src/BuildVision/Core/ServiceProviderPackage.cs +++ b/src/BuildVision/Core/ServiceProviderPackage.cs @@ -25,13 +25,12 @@ namespace BuildVision.Core [ProvideService(typeof(IPackageSettingsProvider), IsAsyncQueryable = true)] [ProvideService(typeof(IBuildInformationProvider), IsAsyncQueryable = true)] [ProvideService(typeof(ISolutionProvider), IsAsyncQueryable = true)] - [ProvideService(typeof(IBuildingProjectsProvider), IsAsyncQueryable = true)] [ProvideService(typeof(IBuildMessagesFactory), IsAsyncQueryable = true)] [ProvideService(typeof(IBuildOutputLogger), IsAsyncQueryable = true)] [ProvideService(typeof(IBuildService), IsAsyncQueryable = true)] [ProvideService(typeof(IStatusBarNotificationService), IsAsyncQueryable = true)] [ProvideService(typeof(IWindowStateService), IsAsyncQueryable = true)] - [ProvideService(typeof(IBuildProgressViewModel), IsAsyncQueryable = true)] + [ProvideService(typeof(ITaskBarInfoService), IsAsyncQueryable = true)] [ProvideService(typeof(IErrorNavigationService), IsAsyncQueryable = true)] public sealed class ServiceProviderPackage : AsyncPackage { @@ -43,13 +42,12 @@ protected override async Task InitializeAsync(CancellationToken cancellationToke AddService(typeof(IPackageSettingsProvider), CreateServiceAsync, true); AddService(typeof(IBuildInformationProvider), CreateServiceAsync, true); AddService(typeof(ISolutionProvider), CreateServiceAsync, true); - AddService(typeof(IBuildingProjectsProvider), CreateServiceAsync, true); AddService(typeof(IBuildMessagesFactory), CreateServiceAsync, true); AddService(typeof(IBuildOutputLogger), CreateServiceAsync, true); AddService(typeof(IBuildService), CreateServiceAsync, true); AddService(typeof(IStatusBarNotificationService), CreateServiceAsync, true); AddService(typeof(IWindowStateService), CreateServiceAsync, true); - AddService(typeof(IBuildProgressViewModel), CreateServiceAsync, true); + AddService(typeof(ITaskBarInfoService), CreateServiceAsync, true); AddService(typeof(IErrorNavigationService), CreateServiceAsync, true); } @@ -84,17 +82,18 @@ async Task CreateServiceAsync(IAsyncServiceContainer container, Cancella } else if (serviceType == typeof(IStatusBarNotificationService)) { - return new StatusBarNotificationService(sp); + var packageSettingsProvider = await GetServiceAsync(cancellation); + return new StatusBarNotificationService(sp, packageSettingsProvider); } else if (serviceType == typeof(IBuildMessagesFactory)) { var packageSettingsProvider = await GetServiceAsync(cancellation); return new BuildMessagesFactory(packageSettingsProvider); } - else if (serviceType == typeof(IBuildProgressViewModel)) + else if (serviceType == typeof(ITaskBarInfoService)) { var packageSettingsProvider = await GetServiceAsync(cancellation); - return new BuildProgressViewModel(packageSettingsProvider); + return new TaskBarInfoService(packageSettingsProvider); } else if (serviceType == typeof(IBuildInformationProvider)) { @@ -104,21 +103,10 @@ async Task CreateServiceAsync(IAsyncServiceContainer container, Cancella var packageSettingsProvider = await GetServiceAsync(cancellation); var statusBarNotificationService = await GetServiceAsync(cancellation); var windowStateService = await GetServiceAsync(cancellation); - var buildProgressViewModel = await GetServiceAsync(cancellation); - var buildService = await GetServiceAsync(cancellation); - var errorNavigationService = await GetServiceAsync(cancellation); - return new BuildInformationProvider(sp, buildOutputLogger, statusBarNotificationService, buildMessagesFactory, windowStateService, packageSettingsProvider, buildProgressViewModel, errorNavigationService); - } - else if (serviceType == typeof(IBuildingProjectsProvider)) - { - var solutionProvider = await GetServiceAsync(cancellation); - var buildInformationProvider = await GetServiceAsync(cancellation); - var buildOutputLogger = await GetServiceAsync(cancellation); - var packageSettingsProvider = await GetServiceAsync(cancellation); - var buildProgressViewModel = await GetServiceAsync(cancellation); + var taskBarInfoService = await GetServiceAsync(cancellation); var buildService = await GetServiceAsync(cancellation); var errorNavigationService = await GetServiceAsync(cancellation); - return new BuildingProjectsProvider(solutionProvider, buildInformationProvider, buildOutputLogger, buildProgressViewModel, packageSettingsProvider, buildService, errorNavigationService); + return new BuildInformationProvider(sp, buildOutputLogger, statusBarNotificationService, buildMessagesFactory, windowStateService, packageSettingsProvider, errorNavigationService, solutionProvider, buildService, taskBarInfoService); } else { diff --git a/src/BuildVision/Core/Services.cs b/src/BuildVision/Core/Services.cs index a2e3e899..b1495633 100644 --- a/src/BuildVision/Core/Services.cs +++ b/src/BuildVision/Core/Services.cs @@ -4,31 +4,30 @@ using EnvDTE80; using Microsoft.VisualStudio.ComponentModelHost; using Microsoft.VisualStudio.Shell; -using Microsoft.VisualStudio.Shell.Interop; namespace BuildVision.Core { public static class Services { - static TResult GetGlobalService(IServiceProvider provider = null) where T : class where TResult : class - { + public static IServiceProvider UnitTestServiceProvider { get; set; } - if(provider != null) - return provider.GetService(typeof(T)) as TResult; - return Package.GetGlobalService(typeof(T)) as TResult; + static Ret GetGlobalService(IServiceProvider provider = null) where T : class where Ret : class + { + Ret ret = null; + if (provider != null) + ret = provider.GetService(typeof(T)) as Ret; + if (ret != null) + return ret; + if (UnitTestServiceProvider != null) + return UnitTestServiceProvider.GetService(typeof(T)) as Ret; + return Package.GetGlobalService(typeof(T)) as Ret; } - public static DTE Dte => GetGlobalService(); - - public static DTE2 Dte2 => Dte as DTE2; - + public static IComponentModel ComponentModel => GetGlobalService(); public static ExportProvider DefaultExportProvider => ComponentModel.DefaultExportProvider; - public static IComponentModel ComponentModel => GetGlobalService(); + public static DTE Dte => GetGlobalService(); - public static Solution GetSolution(this IServiceProvider provider) - { - return Dte.Solution; - } + public static DTE2 Dte2 => Dte as DTE2; } } diff --git a/src/BuildVision/Core/SolutionBuildEvents.cs b/src/BuildVision/Core/SolutionBuildEvents.cs index 8fdc82bd..18264990 100644 --- a/src/BuildVision/Core/SolutionBuildEvents.cs +++ b/src/BuildVision/Core/SolutionBuildEvents.cs @@ -25,44 +25,43 @@ public class SolutionBuildEvents : IVsUpdateSolutionEvents2, IVsUpdateSolutionEv { private readonly ISolutionProvider _solutionProvider; private readonly IBuildInformationProvider _buildInformationProvider; - private readonly IBuildingProjectsProvider _buildingProjectsProvider; public SolutionBuildEvents( ISolutionProvider solutionProvider, - IBuildInformationProvider buildInformationProvider, - IBuildingProjectsProvider buildingProjectsProvider) + IBuildInformationProvider buildInformationProvider) { _solutionProvider = solutionProvider; _buildInformationProvider = buildInformationProvider; - _buildingProjectsProvider = buildingProjectsProvider; } public void UpdateSolution_BeginUpdateAction(uint dwAction) { _solutionProvider.ReloadSolution(); - _buildInformationProvider.BuildStarted(dwAction); - _buildingProjectsProvider.ReloadCurrentProjects(); + var buildAction = StateConverterHelper.ConvertSolutionBuildFlagsToBuildAction(dwAction, (VSSOLNBUILDUPDATEFLAGS)dwAction); + _buildInformationProvider.BuildStarted(buildAction); + _buildInformationProvider.ReloadCurrentProjects(); } - public int UpdateProjectCfg_Begin(IVsHierarchy pHierProj, IVsCfg pCfgProj, IVsCfg pCfgSln, uint dwAction, ref int pfCancel) { var projectItem = new UI.Models.ProjectItem(); var configPair = pCfgProj.ToConfigurationTuple(); SolutionProjectsExtensions.UpdateProperties(pHierProj.ToProject(), projectItem, configPair.Item1, configPair.Item2); - _buildingProjectsProvider.ProjectBuildStarted(projectItem, dwAction); + var buildAction = StateConverterHelper.ConvertSolutionBuildFlagsToBuildAction(dwAction, (VSSOLNBUILDUPDATEFLAGS)dwAction); + _buildInformationProvider.ProjectBuildStarted(projectItem, buildAction); return VSConstants.S_OK; } public int UpdateProjectCfg_Done(IVsHierarchy pHierProj, IVsCfg pCfgProj, IVsCfg pCfgSln, uint dwAction, int fSuccess, int fCancel) { - _buildingProjectsProvider.ProjectBuildFinished(ProjectIdentifierGenerator.GetIdentifierForInteropTypes(pHierProj, pCfgProj), fSuccess == 1, fCancel == 1); + var buildAction = StateConverterHelper.ConvertSolutionBuildFlagsToBuildAction(dwAction, (VSSOLNBUILDUPDATEFLAGS)dwAction); + _buildInformationProvider.ProjectBuildFinished(buildAction, ProjectIdentifierGenerator.GetIdentifierForInteropTypes(pHierProj, pCfgProj), fSuccess == 1, fCancel == 1); return VSConstants.S_OK; } public int UpdateSolution_Done(int fSucceeded, int fModified, int fCancelCommand) { - _buildInformationProvider.BuildFinished(_buildingProjectsProvider.GetBuildingProjects(), fSucceeded == 1, fCancelCommand == 1); + _buildInformationProvider.BuildFinished(fSucceeded == 1, fCancelCommand == 1); return VSConstants.S_OK; } diff --git a/src/BuildVision/Extensions/IServiceProviderExtensions.cs b/src/BuildVision/Extensions/IServiceProviderExtensions.cs new file mode 100644 index 00000000..12221b05 --- /dev/null +++ b/src/BuildVision/Extensions/IServiceProviderExtensions.cs @@ -0,0 +1,12 @@ +using System; + +namespace BuildVision.Extensions +{ + public static class IServiceProviderExtensions + { + public static T GetService(this IServiceProvider serviceProvider) where T : class + { + return serviceProvider.GetService(typeof(T)) as T; + } + } +} diff --git a/src/BuildVision/Services/BuildInformationProvider.cs b/src/BuildVision/Services/BuildInformationProvider.cs index ce15a0bc..498bf66a 100644 --- a/src/BuildVision/Services/BuildInformationProvider.cs +++ b/src/BuildVision/Services/BuildInformationProvider.cs @@ -1,7 +1,11 @@ using System; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.ComponentModel.Composition; +using System.Diagnostics; +using System.Linq; using System.Threading; +using BuildVision.Common; using BuildVision.Contracts; using BuildVision.Contracts.Models; using BuildVision.Exports; @@ -14,13 +18,16 @@ using BuildVision.Tool.Models; using BuildVision.UI; using BuildVision.UI.Common.Logging; +using BuildVision.UI.Contracts; using BuildVision.UI.Helpers; using BuildVision.UI.Models; using BuildVision.Views.Settings; using EnvDTE; using EnvDTE80; +using Microsoft.Build.Framework; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; +using ErrorItem = BuildVision.Contracts.ErrorItem; namespace BuildVision.Core { @@ -28,15 +35,17 @@ namespace BuildVision.Core [PartCreationPolicy(CreationPolicy.Shared)] public class BuildInformationProvider : IBuildInformationProvider { - private readonly IServiceProvider _serviceProvider; private readonly IPackageSettingsProvider _packageSettingsProvider; - private readonly IBuildProgressViewModel _buildProgressViewModel; private readonly IErrorNavigationService _errorNavigationService; private readonly IBuildOutputLogger _buildOutputLogger; private readonly IStatusBarNotificationService _statusBarNotificationService; private readonly IBuildMessagesFactory _buildMessagesFactory; private readonly IWindowStateService _windowStateService; - private Solution _solution; + private readonly ISolutionProvider _solutionProvider; + private readonly IBuildService _buildService; + private readonly ITaskBarInfoService _taskBarInfoService; + private ObservableCollection _projects; + private BuildInformationModel _buildInformationModel; private BuildEvents _buildEvents; private DTE2 _dte; @@ -46,7 +55,9 @@ public class BuildInformationProvider : IBuildInformationProvider private const int BuildInProcessQuantumSleep = 50; private readonly object _buildProcessLockObject; private CancellationTokenSource _buildProcessCancellationToken; - + private int _currentQueuePosOfBuildingProject = 0; + + [ImportingConstructor] public BuildInformationProvider( [Import(typeof(SVsServiceProvider))] IServiceProvider serviceProvider, @@ -55,12 +66,12 @@ public BuildInformationProvider( [Import(typeof(IBuildMessagesFactory))] IBuildMessagesFactory buildMessagesFactory, [Import(typeof(IWindowStateService))] IWindowStateService windowStateService, [Import(typeof(IPackageSettingsProvider))] IPackageSettingsProvider packageSettingsProvider, - [Import(typeof(IBuildProgressViewModel))] IBuildProgressViewModel buildProgressViewModel, - [Import(typeof(IErrorNavigationService))] IErrorNavigationService errorNavigationService) + [Import(typeof(IErrorNavigationService))] IErrorNavigationService errorNavigationService, + [Import(typeof(ISolutionProvider))] ISolutionProvider solutionProvider, + [Import(typeof(IBuildService))] IBuildService buildService, + [Import(typeof(ITaskBarInfoService))] ITaskBarInfoService taskBarInfoService) { - _serviceProvider = serviceProvider; _packageSettingsProvider = packageSettingsProvider; - _buildProgressViewModel = buildProgressViewModel; _errorNavigationService = errorNavigationService; _buildOutputLogger = buildOutputLogger; _statusBarNotificationService = statusBarNotificationService; @@ -69,19 +80,26 @@ public BuildInformationProvider( _buildInformationModel = new BuildInformationModel(); _buildEvents = (serviceProvider.GetService(typeof(DTE)) as DTE).Events.BuildEvents; _buildEvents.OnBuildBegin += BuildEvents_OnBuildBegin; + _projects = new ObservableCollection(); + _solutionProvider = solutionProvider; + _buildService = buildService; + _taskBarInfoService = taskBarInfoService; + _buildOutputLogger.OnErrorRaised += BuildOutputLogger_OnErrorRaised; } - private void BuildEvents_OnBuildBegin(vsBuildScope scope, vsBuildAction action) + public IBuildInformationModel GetBuildInformationModel() => _buildInformationModel; + + public ObservableCollection GetBuildingProjects() => _projects; + + public void ReloadCurrentProjects() { - _buildInformationModel.BuildScope = (BuildScopes) scope; // we need to set buildscope explictly because it is not possible to get this via the other api - //TODO use settings - string message = _buildMessagesFactory.GetBuildBeginMajorMessage(_buildInformationModel); - _statusBarNotificationService.ShowTextWithFreeze(message); - _origTextCurrentState = message; - _buildInformationModel.StateMessage = _origTextCurrentState; + _projects.Clear(); + _projects.AddRange(_solutionProvider.GetProjects()); + } - var projectsCount = GetProjectsCount(); - _buildProgressViewModel.OnBuildBegin(_buildInformationModel, projectsCount); + public void ResetCurrentProjects() + { + _projects.Clear(); } public void ResetBuildInformationModel() @@ -101,13 +119,183 @@ public void ResetBuildInformationModel() _buildInformationModel.BuildFinishTime = null; } - public IBuildInformationModel GetBuildInformationModel() + private void BuildEvents_OnBuildBegin(vsBuildScope scope, vsBuildAction action) + { + _buildInformationModel.BuildScope = (BuildScopes)scope; // we need to set buildscope explictly because it is not possible to get this via the other api + string message = _buildMessagesFactory.GetBuildBeginMajorMessage(_buildInformationModel); + _statusBarNotificationService.ShowTextWithFreeze(message); + _origTextCurrentState = message; + _buildInformationModel.StateMessage = _origTextCurrentState; + _taskBarInfoService.UpdateTaskBarInfo(_buildInformationModel.CurrentBuildState, _buildInformationModel.BuildScope, _projects.Count, GetFinishedProjectsCount()); + } + + private void BuildOutputLogger_OnErrorRaised(BuildProjectContextEntry projectEntry, object e, ErrorLevel errorLevel) + { + try + { + if (!TryGetProjectItem(projectEntry, out var projectItem)) + { + projectEntry.IsInvalid = true; + return; + } + + var errorItem = new ErrorItem(errorLevel); + switch (errorLevel) + { + case ErrorLevel.Message: + errorItem.Init((BuildMessageEventArgs)e); + break; + + case ErrorLevel.Warning: + errorItem.Init((BuildWarningEventArgs)e); + break; + case ErrorLevel.Error: + errorItem.Init((BuildErrorEventArgs)e); + break; + default: + break; + } + + errorItem.VerifyValues(); + AddErrorItem(projectItem, errorItem); + + var args = new BuildErrorRaisedEventArgs(errorLevel, projectItem); + bool buildNeedCancel = (args.ErrorLevel == ErrorLevel.Error && _packageSettingsProvider.Settings.GeneralSettings.StopBuildAfterFirstError); + if (buildNeedCancel) + { + _buildService.CancelBuildSolution(); + } + + bool navigateToBuildFailure = (args.ErrorLevel == ErrorLevel.Error && _packageSettingsProvider.Settings.GeneralSettings.NavigateToBuildFailureReason == NavigateToBuildFailureReasonCondition.OnErrorRaised); + if (_packageSettingsProvider.Settings.GeneralSettings.NavigateToBuildFailureReason == NavigateToBuildFailureReasonCondition.OnErrorRaised && !ErrorNavigationService.BuildErrorNavigated) + { + _errorNavigationService.NavigateToErrorItem(errorItem); + } + } + catch (Exception ex) + { + ex.TraceUnknownException(); + } + } + + private bool TryGetProjectItem(BuildProjectContextEntry projectEntry, out IProjectItem projectItem) + { + projectItem = projectEntry.ProjectItem; + if (projectItem != null) + return true; + + string projectFile = projectEntry.FileName; + if (ProjectExtensions.IsProjectHidden(projectFile)) + return false; + + var projectProperties = projectEntry.Properties; + var project = _projects.FirstOrDefault(x => x.FullName == projectFile); + + if (projectProperties.ContainsKey("Configuration") && projectProperties.ContainsKey("Platform")) + { + string projectConfiguration = projectProperties["Configuration"]; + string projectPlatform = projectProperties["Platform"]; + projectItem = _projects.First(item => $"{item.FullName}-{item.Configuration}|{item.Platform.Replace(" ", "")}" == $"{projectFile}-{projectConfiguration}|{projectPlatform}"); + if (projectItem == null) + { + TraceManager.Trace( + string.Format("Project Item not found by: UniqueName='{0}', Configuration='{1}, Platform='{2}'.", + project.UniqueName, + projectConfiguration, + projectPlatform), + EventLogEntryType.Warning); + return false; + } + } + else + { + return false; + } + + projectEntry.ProjectItem = projectItem; + return true; + } + + private void AddErrorItem(IProjectItem projectItem, ErrorItem errorItem) + { + switch (errorItem.Level) + { + case ErrorLevel.Message: + projectItem.MessagesCount++; + break; + case ErrorLevel.Warning: + projectItem.WarningsCount++; + break; + case ErrorLevel.Error: + projectItem.ErrorsCount++; + break; + default: + throw new ArgumentOutOfRangeException("errorLevel"); + } + if (errorItem.Level != ErrorLevel.Error) + return; + + int errorNumber = projectItem.Errors.Count + projectItem.Warnings.Count + projectItem.Messages.Count + 1; + errorItem.Number = errorNumber; + switch (errorItem.Level) + { + case ErrorLevel.Message: + projectItem.Messages.Add(errorItem); + break; + + case ErrorLevel.Warning: + projectItem.Warnings.Add(errorItem); + break; + + case ErrorLevel.Error: + projectItem.Errors.Add(errorItem); + break; + + default: + throw new ArgumentOutOfRangeException("errorLevel"); + } + } + + private ProjectState GetProjectState(BuildActions buildAction) + { + switch (buildAction) + { + case BuildActions.BuildActionBuild: + case BuildActions.BuildActionRebuildAll: + return ProjectState.Building; + + case BuildActions.BuildActionClean: + return ProjectState.Cleaning; + + case BuildActions.BuildActionDeploy: + throw new InvalidOperationException("vsBuildActionDeploy not supported"); + + default: + throw new ArgumentOutOfRangeException(nameof(buildAction)); + } + } + + public void Run(CancellationToken cancellationToken) { - return _buildInformationModel; + while (!cancellationToken.IsCancellationRequested) + { + BuildUpdate(); + + for (int i = 0; i < BuildInProcessQuantumSleep * BuildInProcessCountOfQuantumSleep; i += BuildInProcessQuantumSleep) + { + if (cancellationToken.IsCancellationRequested) + { + break; + } + + System.Threading.Thread.Sleep(BuildInProcessQuantumSleep); + } + } } - public void BuildStarted(uint dwAction) + public void BuildStarted(BuildActions buildAction) { + _currentQueuePosOfBuildingProject = 0; ErrorNavigationService.BuildErrorNavigated = false; _buildOutputLogger.Attach(); @@ -116,41 +304,119 @@ public void BuildStarted(uint dwAction) _buildInformationModel.BuildStartTime = DateTime.Now; _buildInformationModel.BuildFinishTime = null; _buildInformationModel.CurrentBuildState = BuildState.InProgress; - _buildInformationModel.BuildAction = StateConverterHelper.ConvertSolutionBuildFlagsToBuildAction(dwAction, (VSSOLNBUILDUPDATEFLAGS) dwAction); + _buildInformationModel.BuildAction = buildAction; _buildProcessCancellationToken = new CancellationTokenSource(); _windowStateService.ApplyToolWindowStateAction(_packageSettingsProvider.Settings.WindowSettings.WindowActionOnBuildBegin); System.Threading.Tasks.Task.Run(() => Run(_buildProcessCancellationToken.Token), _buildProcessCancellationToken.Token); } - private int GetProjectsCount() + public void ProjectBuildStarted(IProjectItem projectItem, BuildActions buildAction) { - int projectsCount = -1; - switch (_buildInformationModel.BuildScope) + if (_buildInformationModel.BuildAction == BuildActions.BuildActionDeploy) + { + return; + } + + try + { + var projInCollection = _projects.FirstOrDefault(item => ProjectIdentifierGenerator.GetIdentifierForProjectItem(item) == ProjectIdentifierGenerator.GetIdentifierForProjectItem(projectItem)); + if (projInCollection == null) + { + _projects.Add(projectItem); + projInCollection = projectItem; + } + projInCollection.State = GetProjectState(_buildInformationModel.BuildAction); + projInCollection.BuildFinishTime = null; + projInCollection.BuildStartTime = DateTime.Now; + + _taskBarInfoService.UpdateTaskBarInfo(_buildInformationModel.CurrentBuildState, _buildInformationModel.BuildScope, _projects.Count, GetFinishedProjectsCount()); + _currentQueuePosOfBuildingProject++; + + if (_buildInformationModel.BuildScope == BuildScopes.BuildScopeSolution && + (_buildInformationModel.BuildAction == BuildActions.BuildActionBuild || + _buildInformationModel.BuildAction == BuildActions.BuildActionRebuildAll)) + { + projInCollection.BuildOrder = _currentQueuePosOfBuildingProject; + } + _buildInformationModel.CurrentProject = projInCollection; + } + catch (Exception ex) { - case BuildScopes.BuildScopeSolution: - try + ex.TraceUnknownException(); + } + } + + private int GetFinishedProjectsCount() + { + return _buildInformationModel.SucceededProjectsCount + _buildInformationModel.UpToDateProjectsCount + _buildInformationModel.WarnedProjectsCount + _buildInformationModel.FailedProjectsCount; + } + + public void ProjectBuildFinished(BuildActions buildAction, string projectIdentifier, bool success, bool canceled) + { + if (_buildInformationModel.BuildAction == BuildActions.BuildActionDeploy) + { + return; + } + + var currentProject = _projects.First(item => ProjectIdentifierGenerator.GetIdentifierForProjectItem(item) == projectIdentifier); + ProjectState projectState; + switch (_buildInformationModel.BuildAction) + { + case BuildActions.BuildActionBuild: + case BuildActions.BuildActionRebuildAll: + if (success) { - var solution = _serviceProvider.GetSolution(); - if (solution != null) - projectsCount = solution.GetProjects().Count; + if (_packageSettingsProvider.Settings.GeneralSettings.ShowWarningSignForBuilds && currentProject.WarningsCount > 0) + { + projectState = ProjectState.BuildWarning; + } + else + { + projectState = _buildOutputLogger.IsProjectUpToDate(currentProject) ? ProjectState.UpToDate : ProjectState.BuildDone; + if (projectState == ProjectState.UpToDate) + { + // do i have to set errorbox here? + } + } } - catch (Exception ex) + else { - ex.Trace("Unable to count projects in solution."); + bool buildCancelled = (canceled && currentProject.ErrorsCount == 0); + projectState = buildCancelled ? ProjectState.BuildCancelled : ProjectState.BuildError; } - break; - case BuildScopes.BuildScopeBatch: - case BuildScopes.BuildScopeProject: + case BuildActions.BuildActionClean: + projectState = success ? ProjectState.CleanDone : ProjectState.CleanError; break; default: - throw new ArgumentOutOfRangeException(nameof(_buildInformationModel.BuildScope)); + throw new ArgumentOutOfRangeException(nameof(buildAction)); + } + currentProject.Success = success; + currentProject.State = projectState; + currentProject.BuildFinishTime = DateTime.Now; + + if (currentProject.State == ProjectState.BuildError && _packageSettingsProvider.Settings.GeneralSettings.StopBuildAfterFirstError) + { + _buildService.CancelBuildSolution(); } - return projectsCount; + _buildInformationModel.SucceededProjectsCount = _projects.Count(x => x.State == ProjectState.BuildDone || x.State == ProjectState.CleanDone); + _buildInformationModel.FailedProjectsCount = _projects.Count(x => x.State == ProjectState.BuildError || x.State == ProjectState.CleanError); + _buildInformationModel.WarnedProjectsCount = _projects.Count(x => x.State == ProjectState.BuildWarning); + _buildInformationModel.UpToDateProjectsCount = _projects.Count(x => x.State == ProjectState.UpToDate); + _buildInformationModel.MessagesCount = _projects.Sum(x => x.MessagesCount); + _buildInformationModel.ErrorCount = _projects.Sum(x => x.ErrorsCount); + _buildInformationModel.WarningsCount = _projects.Sum(x => x.WarningsCount); + + if (_buildInformationModel.CurrentProject == null) + { + _buildInformationModel.CurrentProject = GetBuildingProjects().Last(); + } + + _taskBarInfoService.UpdateTaskBarInfo(_buildInformationModel.CurrentBuildState, _buildInformationModel.BuildScope, _projects.Count, GetFinishedProjectsCount()); } public void BuildUpdate() @@ -164,7 +430,7 @@ public void BuildUpdate() */ } - public void BuildFinished(IEnumerable projects, bool success, bool canceled) + public void BuildFinished(bool success, bool canceled) { if (_buildInformationModel.BuildAction == BuildActions.BuildActionDeploy) { @@ -173,7 +439,7 @@ public void BuildFinished(IEnumerable projects, bool success, bool if (_buildInformationModel.BuildScope == BuildScopes.BuildScopeSolution) { - foreach (var projectItem in projects) + foreach (var projectItem in _projects) { if (projectItem.State == ProjectState.Pending) projectItem.State = ProjectState.Skipped; @@ -203,9 +469,9 @@ public void BuildFinished(IEnumerable projects, bool success, bool var message = _buildMessagesFactory.GetBuildDoneMessage(_buildInformationModel); _statusBarNotificationService.ShowText(message); _buildInformationModel.StateMessage = message; - _buildProgressViewModel.OnBuildDone(); + _taskBarInfoService.UpdateTaskBarInfo(_buildInformationModel.CurrentBuildState, _buildInformationModel.BuildScope, _projects.Count, GetFinishedProjectsCount()); - if(_buildInformationModel.FailedProjectsCount > 0 || canceled) + if (_buildInformationModel.FailedProjectsCount > 0 || canceled) { _windowStateService.ApplyToolWindowStateAction(_packageSettingsProvider.Settings.WindowSettings.WindowActionOnBuildError); } @@ -219,7 +485,7 @@ public void BuildFinished(IEnumerable projects, bool success, bool { if (_packageSettingsProvider.Settings.GeneralSettings.NavigateToBuildFailureReason == NavigateToBuildFailureReasonCondition.OnBuildDone) { - foreach (var project in projects) + foreach (var project in _projects) { if (ErrorNavigationService.BuildErrorNavigated) break; @@ -233,23 +499,5 @@ public void BuildFinished(IEnumerable projects, bool success, bool } } } - - public void Run(CancellationToken cancellationToken) - { - while (!cancellationToken.IsCancellationRequested) - { - BuildUpdate(); - - for (int i = 0; i < BuildInProcessQuantumSleep * BuildInProcessCountOfQuantumSleep; i += BuildInProcessQuantumSleep) - { - if (cancellationToken.IsCancellationRequested) - { - break; - } - - System.Threading.Thread.Sleep(BuildInProcessQuantumSleep); - } - } - } } } diff --git a/src/BuildVision/Services/BuildProgressViewModel.cs b/src/BuildVision/Services/BuildProgressViewModel.cs deleted file mode 100644 index a3103c59..00000000 --- a/src/BuildVision/Services/BuildProgressViewModel.cs +++ /dev/null @@ -1,214 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Shell; -using BuildVision.Common; -using BuildVision.UI.Settings.Models; -using BuildVision.UI.Models; -using BuildVision.UI.Settings.Models.BuildProgress; -using BuildVision.Contracts.Models; -using BuildVision.Contracts; -using BuildVision.Views.Settings; - -namespace BuildVision.UI.ViewModels -{ - public class BuildProgressViewModel : BindableBase, IBuildProgressViewModel - { - private readonly IPackageSettingsProvider _packageSettingsProvider; - private IBuildInformationModel _buildInformationModel; - private CancellationTokenSource _resetTaskBarInfoCts; - - private int _projectsCount; - - private double _incProgressValue; - - private double _actionProgressValue; - - private bool _actionProgressIsMarquee; - - private readonly Lazy _taskbarItemInfo = new Lazy(() => - { - var window = Application.Current.MainWindow; - return window.TaskbarItemInfo ?? (window.TaskbarItemInfo = new TaskbarItemInfo()); - }); - - private TaskbarItemInfo TaskbarItemInfo => _taskbarItemInfo.Value; - public int CurrentQueuePosOfBuildingProject { get; private set; } - - private bool _actionProgressIsPaused; - public bool ActionProgressIsPaused - { - get => _actionProgressIsPaused; - set => SetProperty(ref _actionProgressIsPaused, value); - } - - public BuildProgressViewModel(IPackageSettingsProvider packageSettingsProvider) - { - _packageSettingsProvider = packageSettingsProvider; - } - - private void UpdateTaskBarInfo() - { - if (!_packageSettingsProvider.Settings.GeneralSettings.BuildProgressSettings.TaskBarProgressEnabled) - return; - - TaskbarItemProgressState state; - - if (_buildInformationModel.CurrentBuildState != BuildState.InProgress) - state = TaskbarItemProgressState.None; - else if (_actionProgressIsPaused) - state = TaskbarItemProgressState.Paused; - else if (_actionProgressIsMarquee) - state = TaskbarItemProgressState.Indeterminate; - else if (_buildInformationModel.CurrentBuildState == BuildState.Failed) - state = TaskbarItemProgressState.Error; - else - state = TaskbarItemProgressState.Normal; - - TaskbarItemInfo.ProgressState = state; - TaskbarItemInfo.ProgressValue = _actionProgressValue; - } - - public void ResetTaskBarInfo(bool ifTaskBarProgressEnabled = true) - { - if (_taskbarItemInfo.IsValueCreated - && _packageSettingsProvider.Settings.GeneralSettings.BuildProgressSettings.TaskBarProgressEnabled == ifTaskBarProgressEnabled) - { - TaskbarItemInfo.ProgressState = TaskbarItemProgressState.None; - TaskbarItemInfo.ProgressValue = 0; - } - } - - public void OnBuildBegin(IBuildInformationModel buildInformationModel, int projectsCount) - { - _buildInformationModel = buildInformationModel; - if (_resetTaskBarInfoCts != null) - _resetTaskBarInfoCts.Cancel(); - - if (projectsCount > 0) - { - _projectsCount = projectsCount; - _incProgressValue = 1.0 / (projectsCount * 2.0); - } - else - { - _projectsCount = 0; - _incProgressValue = 0; - } - - CurrentQueuePosOfBuildingProject = 0; - _actionProgressValue = 0; - _actionProgressIsMarquee = true; - ActionProgressIsPaused = false; - - UpdateTaskBarInfo(); - } - - public void OnBuildProjectBegin() - { - if (_projectsCount > 0) - { - _actionProgressIsMarquee = false; - _actionProgressValue += _incProgressValue; - } - else - { - _actionProgressIsMarquee = true; - } - - CurrentQueuePosOfBuildingProject += 1; - UpdateTaskBarInfo(); - } - - public void OnBuildProjectDone(bool success) - { - if (_projectsCount > 0) - { - _actionProgressIsMarquee = false; - _actionProgressValue += _incProgressValue; - } - else - { - _actionProgressIsMarquee = true; - } - - UpdateTaskBarInfo(); - } - - public void OnBuildDone() - { - _actionProgressValue = 1; - _actionProgressIsMarquee = false; - UpdateTaskBarInfo(); - _actionProgressValue = 0; - ResetTaskBarInfoOnBuildDone(); - } - - private void ResetTaskBarInfoOnBuildDone() - { - var buildProgressSettings = _packageSettingsProvider.Settings.GeneralSettings.BuildProgressSettings; - if (!buildProgressSettings.TaskBarProgressEnabled) - return; - - switch (buildProgressSettings.ResetTaskBarProgressAfterBuildDone) - { - case ResetTaskBarItemInfoCondition.Never: - break; - - case ResetTaskBarItemInfoCondition.Immediately: - ResetTaskBarInfo(); - break; - - case ResetTaskBarItemInfoCondition.AfterDelay: - { - int delay = buildProgressSettings.ResetTaskBarProgressDelay; - if (delay > 0) - { - _resetTaskBarInfoCts = new CancellationTokenSource(); - var resetTask = new Task(() => Thread.Sleep(delay), _resetTaskBarInfoCts.Token); - resetTask.ContinueWith((tsk, cancelToken) => - { - if (!((CancellationToken)cancelToken).IsCancellationRequested) - ResetTaskBarInfo(); - }, - _resetTaskBarInfoCts.Token, - TaskScheduler.FromCurrentSynchronizationContext()); - resetTask.Start(); - } - else - { - ResetTaskBarInfo(); - } - } - break; - - case ResetTaskBarItemInfoCondition.ByMouseClick: - Window window = Application.Current.MainWindow; - window.PreviewMouseDown += OnMainWindowTouched; - window.LocationChanged += OnMainWindowTouched; - window.SizeChanged += OnMainWindowTouched; - break; - - default: - throw new ArgumentOutOfRangeException(nameof(buildProgressSettings.ResetTaskBarProgressAfterBuildDone)); - } - } - - private void OnMainWindowTouched(object sender, EventArgs e) - { - ResetTaskBarInfo(); - - var window = (Window)sender; - window.PreviewMouseDown -= OnMainWindowTouched; - window.LocationChanged -= OnMainWindowTouched; - window.SizeChanged -= OnMainWindowTouched; - } - - public void OnBuildCancelled() - { - ActionProgressIsPaused = true; - UpdateTaskBarInfo(); - } - } -} diff --git a/src/BuildVision/Services/BuildService.cs b/src/BuildVision/Services/BuildService.cs index 0b3909ea..81949c97 100644 --- a/src/BuildVision/Services/BuildService.cs +++ b/src/BuildVision/Services/BuildService.cs @@ -17,6 +17,7 @@ using BuildVision.UI.Common.Logging; using BuildVision.UI.Models; using EnvDTE; +using EnvDTE80; using Microsoft.VisualStudio; using Microsoft.VisualStudio.Shell; @@ -28,7 +29,6 @@ public class BuildService : IBuildService { private const string CancelBuildCommand = "Build.Cancel"; private bool _buildCancelledInternally; - private CancellationTokenSource _buildProcessCancellationToken; private bool _buildCancelled; private IServiceProvider _serviceProvider; @@ -82,7 +82,7 @@ public async System.Threading.Tasks.Task CancelBuildAsync(IBuildInformationModel } } - public void RaiseCommandForSelectedProject(UI.Models.ProjectItem selectedProjectItem, int commandId) + public void RaiseCommandForSelectedProject(IProjectItem selectedProjectItem, int commandId) { try { @@ -95,18 +95,18 @@ public void RaiseCommandForSelectedProject(UI.Models.ProjectItem selectedProject } } - private void SelectProjectInSolutionExplorer(UI.Models.ProjectItem projectItem) + private void SelectProjectInSolutionExplorer(IProjectItem projectItem) { - //var solutionExplorer = Services.Dte2.ToolWindows.SolutionExplorer; - //var project = Services.Dte2.Solution.GetProject(x => x.UniqueName == projectItem.UniqueName); - //var item = solutionExplorer.FindHierarchyItem(project); - //if (item == null) - // throw new ProjectNotFoundException($"Project '{projectItem.UniqueName}' not found in SolutionExplorer."); - //solutionExplorer.Parent.Activate(); - //item.Select(vsUISelectionType.vsUISelectionTypeSelect); + var solutionExplorer = Core.Services.Dte2.ToolWindows.SolutionExplorer; + var project = Core.Services.Dte2.Solution.GetProject(x => x.UniqueName == projectItem.UniqueName); + var item = solutionExplorer.FindHierarchyItem(project); + if (item == null) + throw new ProjectNotFoundException($"Project '{projectItem.UniqueName}' not found in SolutionExplorer."); + solutionExplorer.Parent.Activate(); + item.Select(vsUISelectionType.vsUISelectionTypeSelect); } - private void ProjectCopyBuildOutputFilesToClipBoard(UI.Models.ProjectItem projItem) + public void ProjectCopyBuildOutputFilesToClipBoard(IProjectItem projItem) { try { @@ -193,7 +193,6 @@ private string GetCopyBuildOutputFilesToClipboardActionMessage(string template, private void RaiseCommand(VSConstants.VSStd97CmdID command) { - ThreadHelper.ThrowIfNotOnUIThread(); try { object customIn = null; @@ -207,26 +206,11 @@ private void RaiseCommand(VSConstants.VSStd97CmdID command) } } - public void ShowGridColumnsSettingsPage() - { - throw new NotImplementedException(); - } - - public void ShowGeneralSettingsPage() - { - throw new NotImplementedException(); - } - public void ProjectCopyBuildOutputFilesToClipBoard() { throw new NotImplementedException(); } - public void RaiseCommandForSelectedProject() - { - throw new NotImplementedException(); - } - private void NavigateToBuildErrorIfNeeded(UI.Settings.Models.ControlSettings settings) { // How to get errors that happend during build? diff --git a/src/BuildVision/Services/BuildingProjectsProvider.cs b/src/BuildVision/Services/BuildingProjectsProvider.cs deleted file mode 100644 index b9b973a4..00000000 --- a/src/BuildVision/Services/BuildingProjectsProvider.cs +++ /dev/null @@ -1,325 +0,0 @@ -using System; -using System.Collections.ObjectModel; -using System.ComponentModel.Composition; -using System.Diagnostics; -using System.Linq; -using BuildVision.Common; -using BuildVision.Contracts; -using BuildVision.Contracts.Models; -using BuildVision.Exports; -using BuildVision.Exports.Factories; -using BuildVision.Exports.Providers; -using BuildVision.Exports.Services; -using BuildVision.Helpers; -using BuildVision.Services; -using BuildVision.UI.Common.Logging; -using BuildVision.UI.Contracts; -using BuildVision.UI.Models; -using BuildVision.Views.Settings; -using Microsoft.Build.Framework; -using Microsoft.VisualStudio.Shell; - -namespace BuildVision.Core -{ - [Export(typeof(IBuildInformationProvider))] - [PartCreationPolicy(CreationPolicy.Shared)] - public class BuildingProjectsProvider : IBuildingProjectsProvider - { - private readonly ISolutionProvider _solutionProvider; - private readonly IBuildInformationProvider _buildInformationProvider; - private readonly IBuildOutputLogger _buildOutputLogger; - private readonly IBuildProgressViewModel _buildProgressViewModel; - private readonly IPackageSettingsProvider _packageSettingsProvider; - private readonly IBuildService _buildService; - private readonly IErrorNavigationService _errorNavigationService; - private ObservableCollection _projects; - - [ImportingConstructor] - public BuildingProjectsProvider( - [Import(typeof(ISolutionProvider))] ISolutionProvider solutionProvider, - [Import(typeof(IBuildInformationProvider))] IBuildInformationProvider buildInformationProvider, - [Import(typeof(IBuildOutputLogger))] IBuildOutputLogger buildOutputLogger, - [Import(typeof(IBuildProgressViewModel))] IBuildProgressViewModel buildProgressViewModel, - [Import(typeof(IPackageSettingsProvider))] IPackageSettingsProvider packageSettingsProvider, - [Import(typeof(IBuildService))] IBuildService buildService, - [Import(typeof(IErrorNavigationService))] IErrorNavigationService errorNavigationService) - { - _projects = new ObservableCollection(); - _solutionProvider = solutionProvider; - _buildInformationProvider = buildInformationProvider; - _buildOutputLogger = buildOutputLogger; - _buildProgressViewModel = buildProgressViewModel; - _packageSettingsProvider = packageSettingsProvider; - _buildService = buildService; - _errorNavigationService = errorNavigationService; - _buildOutputLogger.OnErrorRaised += BuildOutputLogger_OnErrorRaised; - } - - private void BuildOutputLogger_OnErrorRaised(BuildProjectContextEntry projectEntry, object e, ErrorLevel errorLevel) - { - try - { - if (!TryGetProjectItem(projectEntry, out var projectItem)) - { - projectEntry.IsInvalid = true; - return; - } - - var errorItem = new ErrorItem(errorLevel); - switch (errorLevel) - { - case ErrorLevel.Message: - errorItem.Init((BuildMessageEventArgs) e); - break; - - case ErrorLevel.Warning: - errorItem.Init((BuildWarningEventArgs) e); - break; - case ErrorLevel.Error: - errorItem.Init((BuildErrorEventArgs) e); - break; - default: - break; - } - - errorItem.VerifyValues(); - AddErrorItem(projectItem, errorItem); - - var args = new BuildErrorRaisedEventArgs(errorLevel, projectItem); - bool buildNeedCancel = (args.ErrorLevel == ErrorLevel.Error && _packageSettingsProvider.Settings.GeneralSettings.StopBuildAfterFirstError); - if (buildNeedCancel) - { - _buildService.CancelBuildSolution(); - } - - bool navigateToBuildFailure = (args.ErrorLevel == ErrorLevel.Error && _packageSettingsProvider.Settings.GeneralSettings.NavigateToBuildFailureReason == NavigateToBuildFailureReasonCondition.OnErrorRaised); - if (_packageSettingsProvider.Settings.GeneralSettings.NavigateToBuildFailureReason == NavigateToBuildFailureReasonCondition.OnBuildDone && !ErrorNavigationService.BuildErrorNavigated) - { - _errorNavigationService.NavigateToErrorItem(errorItem); - } - } - catch (Exception ex) - { - ex.TraceUnknownException(); - } - } - - public void AddErrorItem(IProjectItem projectItem, ErrorItem errorItem) - { - switch (errorItem.Level) - { - case ErrorLevel.Message: - projectItem.MessagesCount++; - break; - case ErrorLevel.Warning: - projectItem.WarningsCount++; - break; - case ErrorLevel.Error: - projectItem.ErrorsCount++; - break; - default: - throw new ArgumentOutOfRangeException("errorLevel"); - } - if (errorItem.Level != ErrorLevel.Error) - return; - - int errorNumber = projectItem.Errors.Count + projectItem.Warnings.Count + projectItem.Messages.Count + 1; - errorItem.Number = errorNumber; - switch (errorItem.Level) - { - case ErrorLevel.Message: - projectItem.Messages.Add(errorItem); - break; - - case ErrorLevel.Warning: - projectItem.Warnings.Add(errorItem); - break; - - case ErrorLevel.Error: - projectItem.Errors.Add(errorItem); - break; - - default: - throw new ArgumentOutOfRangeException("errorLevel"); - } - } - - public void ReloadCurrentProjects() - { - _projects.Clear(); - _projects.AddRange(_solutionProvider.GetProjects()); - } - - public void ResetCurrentProjects() - { - _projects.Clear(); - } - - public ObservableCollection GetBuildingProjects() - { - return _projects; - } - - public void ProjectBuildStarted(IProjectItem projectItem, uint dwAction) - { - var buildInformationModel = _buildInformationProvider.GetBuildInformationModel(); - if (buildInformationModel.BuildAction == BuildActions.BuildActionDeploy) - { - return; - } - - try - { - var projInCollection = _projects.FirstOrDefault(item => ProjectIdentifierGenerator.GetIdentifierForProjectItem(item) == ProjectIdentifierGenerator.GetIdentifierForProjectItem(projectItem)); - if(projInCollection == null) - { - _projects.Add(projectItem); - projInCollection = projectItem; - } - projInCollection.State = GetProjectState(buildInformationModel.BuildAction); - projInCollection.BuildFinishTime = null; - projInCollection.BuildStartTime = DateTime.Now; - - _buildProgressViewModel.OnBuildProjectBegin(); - - if (buildInformationModel.BuildScope == BuildScopes.BuildScopeSolution && - (buildInformationModel.BuildAction == BuildActions.BuildActionBuild || - buildInformationModel.BuildAction == BuildActions.BuildActionRebuildAll)) - { - projInCollection.BuildOrder = _buildProgressViewModel.CurrentQueuePosOfBuildingProject; - } - buildInformationModel.CurrentProject = projInCollection; - } - catch (Exception ex) - { - ex.TraceUnknownException(); - } - } - - public bool TryGetProjectItem(BuildProjectContextEntry projectEntry, out IProjectItem projectItem) - { - projectItem = projectEntry.ProjectItem; - if (projectItem != null) - return true; - - string projectFile = projectEntry.FileName; - if (ProjectExtensions.IsProjectHidden(projectFile)) - return false; - - var projectProperties = projectEntry.Properties; - var project = _projects.FirstOrDefault(x => x.FullName == projectFile); - - if (projectProperties.ContainsKey("Configuration") && projectProperties.ContainsKey("Platform")) - { - string projectConfiguration = projectProperties["Configuration"]; - string projectPlatform = projectProperties["Platform"]; - projectItem = _projects.First(item => $"{item.FullName}-{item.Configuration}|{item.Platform.Replace(" ","")}" == $"{projectFile}-{projectConfiguration}|{projectPlatform}"); - if (projectItem == null) - { - TraceManager.Trace( - string.Format("Project Item not found by: UniqueName='{0}', Configuration='{1}, Platform='{2}'.", - project.UniqueName, - projectConfiguration, - projectPlatform), - EventLogEntryType.Warning); - return false; - } - } - else - { - return false; - } - - projectEntry.ProjectItem = projectItem; - return true; - } - - private ProjectState GetProjectState(BuildActions buildAction) - { - switch (buildAction) - { - case BuildActions.BuildActionBuild: - case BuildActions.BuildActionRebuildAll: - return ProjectState.Building; - - case BuildActions.BuildActionClean: - return ProjectState.Cleaning; - - case BuildActions.BuildActionDeploy: - throw new InvalidOperationException("vsBuildActionDeploy not supported"); - - default: - throw new ArgumentOutOfRangeException(nameof(buildAction)); - } - } - - public void ProjectBuildFinished(string projectIdentifier, bool success, bool canceled) - { - var buildInformationModel = _buildInformationProvider.GetBuildInformationModel(); - if (buildInformationModel.BuildAction == BuildActions.BuildActionDeploy) - { - return; - } - - var currentProject = _projects.First(item => ProjectIdentifierGenerator.GetIdentifierForProjectItem(item) == projectIdentifier); - var buildAction = _buildInformationProvider.GetBuildInformationModel().BuildAction; - ProjectState projectState; - switch (buildAction) - { - case BuildActions.BuildActionBuild: - case BuildActions.BuildActionRebuildAll: - if (success) - { - if (_packageSettingsProvider.Settings.GeneralSettings.ShowWarningSignForBuilds && currentProject.WarningsCount > 0) - { - projectState = ProjectState.BuildWarning; - } - else - { - projectState = _buildOutputLogger.IsProjectUpToDate(currentProject) ? ProjectState.UpToDate : ProjectState.BuildDone; - if(projectState == ProjectState.UpToDate) - { - // do i have to set errorbox here? - } - } - } - else - { - bool buildCancelled = (canceled && currentProject.ErrorsCount == 0); - projectState = buildCancelled ? ProjectState.BuildCancelled : ProjectState.BuildError; - } - break; - - case BuildActions.BuildActionClean: - projectState = success ? ProjectState.CleanDone : ProjectState.CleanError; - break; - - default: - throw new ArgumentOutOfRangeException(nameof(buildAction)); - } - currentProject.Success = success; - currentProject.State = projectState; - currentProject.BuildFinishTime = DateTime.Now; - - if (currentProject.State == ProjectState.BuildError && _packageSettingsProvider.Settings.GeneralSettings.StopBuildAfterFirstError) - { - _buildService.CancelBuildSolution(); - } - - buildInformationModel.SucceededProjectsCount = _projects.Count(x => x.State == ProjectState.BuildDone || x.State == ProjectState.CleanDone); - buildInformationModel.FailedProjectsCount = _projects.Count(x => x.State == ProjectState.BuildError || x.State == ProjectState.CleanError); - buildInformationModel.WarnedProjectsCount = _projects.Count(x => x.State == ProjectState.BuildWarning); - buildInformationModel.UpToDateProjectsCount = _projects.Count(x => x.State == ProjectState.UpToDate); - buildInformationModel.MessagesCount = _projects.Sum(x => x.MessagesCount); - buildInformationModel.ErrorCount = _projects.Sum(x => x.ErrorsCount); - buildInformationModel.WarningsCount = _projects.Sum(x => x.WarningsCount); - - if (buildInformationModel.CurrentProject == null) - { - buildInformationModel.CurrentProject = GetBuildingProjects().Last(); - } - - _buildProgressViewModel.OnBuildProjectDone(success); - } - } -} diff --git a/src/BuildVision/Services/PackageSettingsProvider.cs b/src/BuildVision/Services/PackageSettingsProvider.cs index d75bc28f..3a3ce466 100644 --- a/src/BuildVision/Services/PackageSettingsProvider.cs +++ b/src/BuildVision/Services/PackageSettingsProvider.cs @@ -31,6 +31,7 @@ public PackageSettingsProvider(IServiceProvider serviceProvider) public void Save() { SaveSettings(); + SettingsChanged?.Invoke(); } private void SaveSettings() @@ -64,5 +65,7 @@ private void LoadSettings() MessageBox.Show("An error occurred when trying to load current settings. To make sure everything is still working the settings are set to default."); } } + + public event Action SettingsChanged; } } diff --git a/src/BuildVision/Services/StatusBarNotificationService.cs b/src/BuildVision/Services/StatusBarNotificationService.cs index 2cc725ee..b5c993fc 100644 --- a/src/BuildVision/Services/StatusBarNotificationService.cs +++ b/src/BuildVision/Services/StatusBarNotificationService.cs @@ -2,8 +2,10 @@ using System.ComponentModel.Composition; using BuildVision.Exports.Services; using BuildVision.Views.Settings; +using Microsoft.VisualStudio; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; +using BuildVision.Extensions; namespace BuildVision.Core { @@ -12,37 +14,33 @@ namespace BuildVision.Core public class StatusBarNotificationService : IStatusBarNotificationService { private readonly IServiceProvider _serviceProvider; + private readonly IPackageSettingsProvider _packageSettingsProvider; [ImportingConstructor] - public StatusBarNotificationService([Import(typeof(SVsServiceProvider))] IServiceProvider serviceProvider) + public StatusBarNotificationService( + [Import(typeof(SVsServiceProvider))] IServiceProvider serviceProvider, + [Import(typeof(IPackageSettingsProvider))] IPackageSettingsProvider packageSettingsProvider) { _serviceProvider = serviceProvider; + _packageSettingsProvider = packageSettingsProvider; } public void ShowText(string str) { - ThreadHelper.ThrowIfNotOnUIThread(); - var statusBar = _serviceProvider.GetService(typeof(IVsStatusbar)) as IVsStatusbar; - var settings = _serviceProvider.GetService(typeof(IPackageSettingsProvider)) as IPackageSettingsProvider; - if (settings == null || statusBar == null) + if (!_packageSettingsProvider.Settings.GeneralSettings.EnableStatusBarOutput) return; - if (!settings.Settings.GeneralSettings.EnableStatusBarOutput) - return; + var statusBar = _serviceProvider.GetService(typeof(IVsStatusbar)) as IVsStatusbar; statusBar.FreezeOutput(0); statusBar.SetText(str); } public void ShowTextWithFreeze(string str) { - //ThreadHelper.ThrowIfNotOnUIThread(); - var statusBar = _serviceProvider.GetService(typeof(IVsStatusbar)) as IVsStatusbar; - var settings = _serviceProvider.GetService(typeof(IPackageSettingsProvider)) as IPackageSettingsProvider; - if (settings == null || statusBar == null) + if (!_packageSettingsProvider.Settings.GeneralSettings.EnableStatusBarOutput) return; - if (!settings.Settings.GeneralSettings.EnableStatusBarOutput) - return; + var statusBar = _serviceProvider.GetService(); statusBar.FreezeOutput(0); statusBar.SetText(str); statusBar.FreezeOutput(1); diff --git a/src/BuildVision/Services/TaskBarInfoService.cs b/src/BuildVision/Services/TaskBarInfoService.cs new file mode 100644 index 00000000..423eef55 --- /dev/null +++ b/src/BuildVision/Services/TaskBarInfoService.cs @@ -0,0 +1,139 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Shell; +using BuildVision.UI.Models; +using BuildVision.Contracts; +using BuildVision.Views.Settings; +using BuildVision.Exports.Services; + +namespace BuildVision.UI.ViewModels +{ + public class TaskBarInfoService : ITaskBarInfoService + { + private CancellationTokenSource _resetTaskBarInfoCts; + + private readonly IPackageSettingsProvider _packageSettingsProvider; + + private readonly Lazy _taskbarItemInfo = new Lazy(() => + { + var window = Application.Current.MainWindow; + return window.TaskbarItemInfo ?? (window.TaskbarItemInfo = new TaskbarItemInfo()); + }); + + public TaskBarInfoService(IPackageSettingsProvider packageSettingsProvider) + { + _packageSettingsProvider = packageSettingsProvider; + } + + public void UpdateTaskBarInfo(BuildState buildState, BuildScopes buildScope, int projectsCount, int finishedProjects) + { + if (_resetTaskBarInfoCts != null && !_resetTaskBarInfoCts.IsCancellationRequested) + _resetTaskBarInfoCts.Cancel(); + + if (!_packageSettingsProvider.Settings.GeneralSettings.BuildProgressSettings.TaskBarProgressEnabled) + return; + + if (buildState == BuildState.Cancelled) + _taskbarItemInfo.Value.ProgressState = TaskbarItemProgressState.Paused; + else if (buildState == BuildState.Failed) + _taskbarItemInfo.Value.ProgressState = TaskbarItemProgressState.Error; + else if (buildState != BuildState.InProgress) + _taskbarItemInfo.Value.ProgressState = TaskbarItemProgressState.None; + else if (buildScope != BuildScopes.BuildScopeSolution) + _taskbarItemInfo.Value.ProgressState = TaskbarItemProgressState.Indeterminate; + else + _taskbarItemInfo.Value.ProgressState = TaskbarItemProgressState.Normal; + + if (projectsCount <= 0) + { + _taskbarItemInfo.Value.ProgressValue = 0; + } + else if (projectsCount == finishedProjects) + { + _taskbarItemInfo.Value.ProgressValue = 1; + } + else + { + var incProgressValue = 1.0 / (projectsCount * 2.0); + _taskbarItemInfo.Value.ProgressValue = incProgressValue * finishedProjects; + } + + if (buildState == BuildState.Done || buildState == BuildState.ErrorDone || buildState == BuildState.Failed || buildState == BuildState.Cancelled) + { + ResetTaskBarInfoOnBuildDone(); + } + } + + public void ResetTaskBarInfo(bool ifTaskBarProgressEnabled = true) + { + if (_taskbarItemInfo.IsValueCreated + && _packageSettingsProvider.Settings.GeneralSettings.BuildProgressSettings.TaskBarProgressEnabled == ifTaskBarProgressEnabled) + { + _taskbarItemInfo.Value.ProgressState = TaskbarItemProgressState.None; + _taskbarItemInfo.Value.ProgressValue = 0; + } + } + + private void ResetTaskBarInfoOnBuildDone() + { + var buildProgressSettings = _packageSettingsProvider.Settings.GeneralSettings.BuildProgressSettings; + if (!buildProgressSettings.TaskBarProgressEnabled) + return; + + switch (buildProgressSettings.ResetTaskBarProgressAfterBuildDone) + { + case ResetTaskBarItemInfoCondition.Never: + break; + + case ResetTaskBarItemInfoCondition.Immediately: + ResetTaskBarInfo(); + break; + + case ResetTaskBarItemInfoCondition.AfterDelay: + { + int delay = buildProgressSettings.ResetTaskBarProgressDelay; + if (delay > 0) + { + _resetTaskBarInfoCts = new CancellationTokenSource(); + var resetTask = new Task(() => Thread.Sleep(delay), _resetTaskBarInfoCts.Token); + _ = resetTask.ContinueWith((tsk, cancelToken) => + { + if (!((CancellationToken)cancelToken).IsCancellationRequested) + { + ResetTaskBarInfo(); + } + }, _resetTaskBarInfoCts.Token, TaskScheduler.FromCurrentSynchronizationContext()); + resetTask.Start(); + } + else + { + ResetTaskBarInfo(); + } + } + break; + + case ResetTaskBarItemInfoCondition.ByMouseClick: + var window = Application.Current.MainWindow; + window.PreviewMouseDown += OnMainWindowTouched; + window.LocationChanged += OnMainWindowTouched; + window.SizeChanged += OnMainWindowTouched; + break; + + default: + throw new ArgumentOutOfRangeException(nameof(buildProgressSettings.ResetTaskBarProgressAfterBuildDone)); + } + } + + private void OnMainWindowTouched(object sender, EventArgs e) + { + ResetTaskBarInfo(); + + var window = (Window)sender; + window.PreviewMouseDown -= OnMainWindowTouched; + window.LocationChanged -= OnMainWindowTouched; + window.SizeChanged -= OnMainWindowTouched; + } + } +} diff --git a/src/BuildVision/Views/Settings/BuildMessagesSettingsDialogPage.cs b/src/BuildVision/Views/Settings/BuildMessagesSettingsDialogPage.cs index 11b14277..b5b73e49 100644 --- a/src/BuildVision/Views/Settings/BuildMessagesSettingsDialogPage.cs +++ b/src/BuildVision/Views/Settings/BuildMessagesSettingsDialogPage.cs @@ -11,8 +11,8 @@ public class BuildMessagesSettingsDialogPage : SettingsDialogPage ControlSettings?.BuildMessagesSettings; + set => ControlSettings.BuildMessagesSettings = value; } } } diff --git a/src/BuildVision/Views/Settings/GeneralSettingsDialogPage.cs b/src/BuildVision/Views/Settings/GeneralSettingsDialogPage.cs index 7733cd9e..a8fe04f7 100644 --- a/src/BuildVision/Views/Settings/GeneralSettingsDialogPage.cs +++ b/src/BuildVision/Views/Settings/GeneralSettingsDialogPage.cs @@ -1,4 +1,4 @@ -using BuildVision.UI.Settings; +using BuildVision.UI.Settings; using BuildVision.UI.Settings.Models; using System.Runtime.InteropServices; @@ -11,8 +11,8 @@ public class GeneralSettingsDialogPage : SettingsDialogPage ControlSettings?.GeneralSettings; + set => ControlSettings.GeneralSettings = value; } } -} \ No newline at end of file +} diff --git a/src/BuildVision/Views/Settings/GridSettingsDialogPage.cs b/src/BuildVision/Views/Settings/GridSettingsDialogPage.cs index 82ce3b00..67ea75fe 100644 --- a/src/BuildVision/Views/Settings/GridSettingsDialogPage.cs +++ b/src/BuildVision/Views/Settings/GridSettingsDialogPage.cs @@ -1,9 +1,4 @@ -using System.ComponentModel; -using System.Runtime.InteropServices; - -using Microsoft.VisualStudio.Shell; -using BuildVision.UI.ViewModels; -using BuildVision.Tool; +using System.Runtime.InteropServices; using BuildVision.UI.Settings.Models; using BuildVision.UI.Settings; @@ -15,18 +10,8 @@ public class GridSettingsDialogPage : SettingsDialogPage ControlSettings?.GridSettings; + set => ControlSettings.GridSettings = value; } } } diff --git a/src/BuildVision/Views/Settings/ProjectItemSettingsDialogPage.cs b/src/BuildVision/Views/Settings/ProjectItemSettingsDialogPage.cs index 726adb3d..550ee97b 100644 --- a/src/BuildVision/Views/Settings/ProjectItemSettingsDialogPage.cs +++ b/src/BuildVision/Views/Settings/ProjectItemSettingsDialogPage.cs @@ -1,4 +1,4 @@ -using System.Runtime.InteropServices; +using System.Runtime.InteropServices; using BuildVision.UI.Settings.Models; using BuildVision.UI.Settings; @@ -11,8 +11,8 @@ public class ProjectItemSettingsDialogPage : SettingsDialogPage ControlSettings?.ProjectItemSettings; + set => ControlSettings.ProjectItemSettings = value; } } -} \ No newline at end of file +} diff --git a/src/BuildVision/Views/Settings/SettingsDialogPage.cs b/src/BuildVision/Views/Settings/SettingsDialogPage.cs index 5a5c2073..700f3999 100644 --- a/src/BuildVision/Views/Settings/SettingsDialogPage.cs +++ b/src/BuildVision/Views/Settings/SettingsDialogPage.cs @@ -6,6 +6,7 @@ using BuildVision.Common; using BuildVision.Core; using BuildVision.UI.Settings.Models; +using Microsoft; namespace BuildVision.Views.Settings { @@ -32,13 +33,13 @@ protected override UIElement Child protected override void OnActivate(CancelEventArgs e) { + _packageSettingsProvider = Package.GetGlobalService(typeof(IPackageSettingsProvider)) as IPackageSettingsProvider; + Assumes.Present(_packageSettingsProvider); if (_editSettings == null) _editSettings = Settings.Clone(); if (_ctrl.DataContext == null) _ctrl.DataContext = _editSettings; - - //_packageSettingsProvider = Services.DefaultExportProvider.GetExportedValue(); base.OnActivate(e); } @@ -77,6 +78,6 @@ public override void ResetSettings() base.ResetSettings(); } - protected ControlSettings ControlSettings => _packageSettingsProvider.Settings; + protected ControlSettings ControlSettings => _packageSettingsProvider?.Settings; } } diff --git a/src/BuildVision/Views/Settings/WindowSettingsDialogPage.cs b/src/BuildVision/Views/Settings/WindowSettingsDialogPage.cs index e9c4c8c6..0dd6b63b 100644 --- a/src/BuildVision/Views/Settings/WindowSettingsDialogPage.cs +++ b/src/BuildVision/Views/Settings/WindowSettingsDialogPage.cs @@ -11,8 +11,8 @@ public class WindowSettingsDialogPage : SettingsDialogPage ControlSettings?.WindowSettings; + set => ControlSettings.WindowSettings = value; } } } From d43a806b059cedbe7a197e249647246e99a24886 Mon Sep 17 00:00:00 2001 From: Stefan Kert Date: Sat, 30 Mar 2019 13:12:08 +0100 Subject: [PATCH 045/100] Removed unused channel .. maybe later --- .../Diagnostics/SessionTelemetry.cs | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/src/BuildVision.Common/Diagnostics/SessionTelemetry.cs b/src/BuildVision.Common/Diagnostics/SessionTelemetry.cs index 681c7115..5243b33d 100644 --- a/src/BuildVision.Common/Diagnostics/SessionTelemetry.cs +++ b/src/BuildVision.Common/Diagnostics/SessionTelemetry.cs @@ -14,17 +14,6 @@ class SessionTelemetry : ITelemetryInitializer private readonly string _operatingSystem = RuntimeInformation.OSDescription?.Replace("Microsoft ", ""); // Shorter description private readonly string _session = Guid.NewGuid().ToString(); -#if STORE - private const string Channel = "store"; -#elif NIGHTLY - private const string Channel = "nightly"; -#elif CHOCO - private const string Channel = "chocolatey"; -#else - private const string Channel = "zip"; -#endif - - public SessionTelemetry() { try @@ -43,7 +32,7 @@ public SessionTelemetry() public void Initialize(ITelemetry telemetry) { - telemetry.Context.GlobalProperties["Environment"] = Channel; + telemetry.Context.GlobalProperties["Environment"] = "release"; // Always default to development if we're in the debugger if (Debugger.IsAttached) { From c0d8a8be19cabda2fd0b0be0bf125c6ee61c92b1 Mon Sep 17 00:00:00 2001 From: Stefan Kert Date: Fri, 5 Apr 2019 16:16:55 +0200 Subject: [PATCH 046/100] Added global exceptionhandling --- src/BuildVision/Core/BuildVisionPackage.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/BuildVision/Core/BuildVisionPackage.cs b/src/BuildVision/Core/BuildVisionPackage.cs index 17ff8650..6865e3d2 100644 --- a/src/BuildVision/Core/BuildVisionPackage.cs +++ b/src/BuildVision/Core/BuildVisionPackage.cs @@ -5,6 +5,7 @@ using System.Threading; using System.Windows; using System.Windows.Threading; +using BuildVision.Common.Diagnostics; using BuildVision.Exports.Providers; using BuildVision.Exports.Services; using BuildVision.Helpers; @@ -62,14 +63,13 @@ public BuildVisionPackage() if (Application.Current != null) { - Application.Current.DispatcherUnhandledException += Current_DispatcherUnhandledException; ; + Application.Current.DispatcherUnhandledException += Current_DispatcherUnhandledException; } } private void Current_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e) { - MessageBox.Show($"Diagnostics mode caught and marked as handled the following DispatcherUnhandledException raised in Visual Studio: {e.Exception}."); - e.Handled = true; + DiagnosticsClient.Notify(e.Exception); } protected override async Task InitializeAsync(CancellationToken cancellationToken, IProgress progress) From 08b6200751fbc18a403b5ddb3f772487fdf84abf Mon Sep 17 00:00:00 2001 From: Stefan Kert Date: Fri, 5 Apr 2019 16:17:05 +0200 Subject: [PATCH 047/100] Reset current projects on rebuild --- src/BuildVision/Services/BuildInformationProvider.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/BuildVision/Services/BuildInformationProvider.cs b/src/BuildVision/Services/BuildInformationProvider.cs index 498bf66a..b40df8ce 100644 --- a/src/BuildVision/Services/BuildInformationProvider.cs +++ b/src/BuildVision/Services/BuildInformationProvider.cs @@ -300,6 +300,7 @@ public void BuildStarted(BuildActions buildAction) _buildOutputLogger.Attach(); ResetBuildInformationModel(); + ResetCurrentProjects(); _buildInformationModel.BuildStartTime = DateTime.Now; _buildInformationModel.BuildFinishTime = null; From 00b0fe6664e282f7c521194cbf43aa70788304d9 Mon Sep 17 00:00:00 2001 From: Stefan Kert Date: Fri, 5 Apr 2019 16:35:54 +0200 Subject: [PATCH 048/100] Fixed issue with progressbar --- src/BuildVision.UI/Components/ControlView.xaml | 2 +- src/BuildVision.UI/Components/ControlView.xaml.cs | 1 - src/BuildVision.UI/Components/ProjectGrid.xaml.cs | 2 -- .../Controls/BuildVisionProgressBar.xaml | 13 +++++++++++-- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/BuildVision.UI/Components/ControlView.xaml b/src/BuildVision.UI/Components/ControlView.xaml index 52f95327..b559b81e 100644 --- a/src/BuildVision.UI/Components/ControlView.xaml +++ b/src/BuildVision.UI/Components/ControlView.xaml @@ -74,7 +74,7 @@ VerticalAlignment="Center" /> - + diff --git a/src/BuildVision.UI/Components/ControlView.xaml.cs b/src/BuildVision.UI/Components/ControlView.xaml.cs index 2c44051f..a86bfc17 100644 --- a/src/BuildVision.UI/Components/ControlView.xaml.cs +++ b/src/BuildVision.UI/Components/ControlView.xaml.cs @@ -54,6 +54,5 @@ private void ViewModelOnPropertyChanged(object sender, PropertyChangedEventArgs // Grid.ScrollIntoView(_viewModel.CurrentProject); //} } - } } diff --git a/src/BuildVision.UI/Components/ProjectGrid.xaml.cs b/src/BuildVision.UI/Components/ProjectGrid.xaml.cs index 581253c7..74b3a8de 100644 --- a/src/BuildVision.UI/Components/ProjectGrid.xaml.cs +++ b/src/BuildVision.UI/Components/ProjectGrid.xaml.cs @@ -55,8 +55,6 @@ private void GridOnSorting(object sender, DataGridSortingEventArgs e) private void OnDataContextChanged(object sender, DependencyPropertyChangedEventArgs e) { - Debug.Assert(DataContext != null); - _viewModel = (BuildVisionPaneViewModel) DataContext; _viewModel.SetGridColumnsRef(Grid.Columns); _viewModel.PropertyChanged += ViewModelOnPropertyChanged; diff --git a/src/BuildVision.UI/Controls/BuildVisionProgressBar.xaml b/src/BuildVision.UI/Controls/BuildVisionProgressBar.xaml index f0736e2c..7fb6e891 100644 --- a/src/BuildVision.UI/Controls/BuildVisionProgressBar.xaml +++ b/src/BuildVision.UI/Controls/BuildVisionProgressBar.xaml @@ -5,7 +5,16 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" mc:Ignorable="d" xmlns:contracts="clr-namespace:BuildVision.Contracts;assembly=BuildVision.Contracts" - d:DesignWidth="697"> + xmlns:models="clr-namespace:BuildVision.UI.Models" + d:DesignWidth="697" + d:DataContext="{Binding Source={StaticResource DesignViewModel}}"> + + + + + + + - - - - - - - - - + d:DataContext="{d:DesignInstance viewModels:BuildVisionPaneViewModel}"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/BuildVision.UI/Components/ErrorsGrid.xaml.cs b/src/BuildVision.UI/Components/ErrorsGrid.xaml.cs index 5702a68c..259d8738 100644 --- a/src/BuildVision.UI/Components/ErrorsGrid.xaml.cs +++ b/src/BuildVision.UI/Components/ErrorsGrid.xaml.cs @@ -1,13 +1,13 @@ -using BuildVision.Contracts; -using BuildVision.UI.Common.Logging; -using BuildVision.UI.Extensions; -using BuildVision.UI.Models; -using System; +using System; using System.Diagnostics; using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; +using BuildVision.Contracts; +using BuildVision.UI.Common.Logging; +using BuildVision.UI.Extensions; +using BuildVision.UI.Models; namespace BuildVision.UI { diff --git a/src/BuildVision.UI/Components/SpinnerControl.xaml.cs b/src/BuildVision.UI/Components/SpinnerControl.xaml.cs index 15836e2a..b33786ae 100644 --- a/src/BuildVision.UI/Components/SpinnerControl.xaml.cs +++ b/src/BuildVision.UI/Components/SpinnerControl.xaml.cs @@ -1,11 +1,11 @@ -using BuildVision.UI.Extensions; -using System; +using System; using System.ComponentModel; using System.Globalization; using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; +using BuildVision.UI.Extensions; namespace BuildVision.UI.Components { @@ -48,13 +48,7 @@ static SpinnerControl() /// Returns the formatted version of the value, with the specified /// number of DecimalPlaces. /// - public string FormattedValue - { - get - { - return (string)GetValue(FormattedValueProperty); - } - } + public string FormattedValue => (string)GetValue(FormattedValueProperty); /// /// Update the formatted value. @@ -80,8 +74,8 @@ protected void UpdateFormattedValue(decimal newValue) [Category("SpinnerControl")] public decimal Value { - get { return (decimal)GetValue(ValueProperty); } - set { SetValue(ValueProperty, value); } + get => (decimal)GetValue(ValueProperty); + set => SetValue(ValueProperty, value); } private static readonly DependencyProperty ValueProperty = @@ -156,8 +150,8 @@ private static object CoerceValue(DependencyObject obj, object value) [Category("SpinnerControl")] public decimal Minimum { - get { return (decimal)GetValue(MinimumValueProperty); } - set { SetValue(MinimumValueProperty, value); } + get => (decimal)GetValue(MinimumValueProperty); + set => SetValue(MinimumValueProperty, value); } private static readonly DependencyProperty MinimumValueProperty = @@ -173,8 +167,8 @@ public decimal Minimum [Category("SpinnerControl")] public decimal Maximum { - get { return (decimal)GetValue(MaximumValueProperty); } - set { SetValue(MaximumValueProperty, value); } + get => (decimal)GetValue(MaximumValueProperty); + set => SetValue(MaximumValueProperty, value); } private static readonly DependencyProperty MaximumValueProperty = @@ -191,8 +185,8 @@ public decimal Maximum [Category("SpinnerControl")] public int DecimalPlaces { - get { return (int)GetValue(DecimalPlacesProperty); } - set { SetValue(DecimalPlacesProperty, value); } + get => (int)GetValue(DecimalPlacesProperty); + set => SetValue(DecimalPlacesProperty, value); } private static readonly DependencyProperty DecimalPlacesProperty = @@ -209,8 +203,8 @@ public int DecimalPlaces [Category("SpinnerControl")] public decimal Change { - get { return (decimal)GetValue(ChangeProperty); } - set { SetValue(ChangeProperty, value); } + get => (decimal)GetValue(ChangeProperty); + set => SetValue(ChangeProperty, value); } private static readonly DependencyProperty ChangeProperty = @@ -320,8 +314,7 @@ private void TextBox_TextChanged(object sender, TextChangedEventArgs e) { var textBox = (TextBox)sender; - decimal val; - if (!string.IsNullOrEmpty(textBox.Text) && decimal.TryParse(textBox.Text, out val)) + if (!string.IsNullOrEmpty(textBox.Text) && decimal.TryParse(textBox.Text, out var val)) { Value = val; BorderBrush = _defaultBorderBrush; diff --git a/src/BuildVision.UI/Controls/BuildVisionProgressBar.xaml.cs b/src/BuildVision.UI/Controls/BuildVisionProgressBar.xaml.cs index 54b5125c..86f96aa3 100644 --- a/src/BuildVision.UI/Controls/BuildVisionProgressBar.xaml.cs +++ b/src/BuildVision.UI/Controls/BuildVisionProgressBar.xaml.cs @@ -1,17 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Documents; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Media.Imaging; -using System.Windows.Navigation; -using System.Windows.Shapes; +using System.Windows.Controls; namespace BuildVision.UI.Controls { diff --git a/src/BuildVision.UI/Controls/Indicators/ErrorProjectsIndicator.cs b/src/BuildVision.UI/Controls/Indicators/ErrorProjectsIndicator.cs index 2f0ec56d..9e5b9963 100644 --- a/src/BuildVision.UI/Controls/Indicators/ErrorProjectsIndicator.cs +++ b/src/BuildVision.UI/Controls/Indicators/ErrorProjectsIndicator.cs @@ -1,7 +1,4 @@ -using System; -using System.ComponentModel; -using System.Windows; -using System.Windows.Controls; +using System.Windows; namespace BuildVision.UI.Controls.Indicators { diff --git a/src/BuildVision.UI/Controls/Indicators/ErrorsIndicator.cs b/src/BuildVision.UI/Controls/Indicators/ErrorsIndicator.cs index 43e071d9..fe5e3692 100644 --- a/src/BuildVision.UI/Controls/Indicators/ErrorsIndicator.cs +++ b/src/BuildVision.UI/Controls/Indicators/ErrorsIndicator.cs @@ -1,5 +1,4 @@ using System.Windows; -using BuildVision.UI.Extensions; namespace BuildVision.UI.Controls.Indicators { diff --git a/src/BuildVision.UI/Controls/Indicators/ValueIndicator.cs b/src/BuildVision.UI/Controls/Indicators/ValueIndicator.cs index febea502..943dceaf 100644 --- a/src/BuildVision.UI/Controls/Indicators/ValueIndicator.cs +++ b/src/BuildVision.UI/Controls/Indicators/ValueIndicator.cs @@ -1,6 +1,4 @@ -using System; -using System.ComponentModel; -using System.Windows; +using System.Windows; using System.Windows.Controls; using BuildVision.UI.Extensions; @@ -15,15 +13,15 @@ public class ValueIndicator : Control public static readonly DependencyProperty IconProperty = DependencyProperty.Register(nameof(Icon), typeof(ControlTemplate), typeof(ValueIndicator), new PropertyMetadata(null)); public static readonly DependencyProperty ValueProperty = DependencyProperty.Register( - nameof(Value), - typeof(long), - typeof(ValueIndicator), + nameof(Value), + typeof(long), + typeof(ValueIndicator), new FrameworkPropertyMetadata( defaultValue: (long)-1, - flags: - FrameworkPropertyMetadataOptions.AffectsArrange - | FrameworkPropertyMetadataOptions.AffectsMeasure - |FrameworkPropertyMetadataOptions.AffectsRender, + flags: + FrameworkPropertyMetadataOptions.AffectsArrange + | FrameworkPropertyMetadataOptions.AffectsMeasure + | FrameworkPropertyMetadataOptions.AffectsRender, propertyChangedCallback: new PropertyChangedCallback(OnValueChange))); static ValueIndicator() @@ -38,25 +36,25 @@ public ValueIndicator() public long Value { - get { return (long) GetValue(ValueProperty); } - set { SetValue(ValueProperty, value); } + get => (long)GetValue(ValueProperty); + set => SetValue(ValueProperty, value); } public string Header { - get { return (string)GetValue(HeaderProperty); } - set { SetValue(HeaderProperty, value); } + get => (string)GetValue(HeaderProperty); + set => SetValue(HeaderProperty, value); } public ControlTemplate Icon { - get { return (ControlTemplate) GetValue(IconProperty); } - set { SetValue(IconProperty, value); } + get => (ControlTemplate)GetValue(IconProperty); + set => SetValue(IconProperty, value); } static void OnValueChange(DependencyObject d, DependencyPropertyChangedEventArgs e) { - d.SetValue(ValueProperty, (long) e.NewValue); + d.SetValue(ValueProperty, (long)e.NewValue); } } } diff --git a/src/BuildVision.UI/Controls/Indicators/WarningProjectsIndicator.cs b/src/BuildVision.UI/Controls/Indicators/WarningProjectsIndicator.cs index 05cb5d73..a85c6772 100644 --- a/src/BuildVision.UI/Controls/Indicators/WarningProjectsIndicator.cs +++ b/src/BuildVision.UI/Controls/Indicators/WarningProjectsIndicator.cs @@ -1,5 +1,4 @@ using System.Windows; -using BuildVision.UI.Extensions; namespace BuildVision.UI.Controls.Indicators { diff --git a/src/BuildVision.UI/Converters/DataGridLengthStringConverter.cs b/src/BuildVision.UI/Converters/DataGridLengthStringConverter.cs index 05f91ca9..34265bf9 100644 --- a/src/BuildVision.UI/Converters/DataGridLengthStringConverter.cs +++ b/src/BuildVision.UI/Converters/DataGridLengthStringConverter.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Globalization; using System.Windows.Controls; using System.Windows.Data; @@ -13,7 +13,7 @@ public object Convert(object value, Type targetType, object parameter, CultureIn var val = (DataGridLength)value; if (val.IsAuto) - return "auto"; + return "auto"; if (val.IsStar) return val.DisplayValue.ToString("0.0") + "*"; @@ -41,4 +41,4 @@ public object ConvertBack(object value, Type targetType, object parameter, Cultu } } } -} \ No newline at end of file +} diff --git a/src/BuildVision.UI/Converters/GridColumnSettingsToColumnExampleValueConverter.cs b/src/BuildVision.UI/Converters/GridColumnSettingsToColumnExampleValueConverter.cs index b3439b07..0be9b2ad 100644 --- a/src/BuildVision.UI/Converters/GridColumnSettingsToColumnExampleValueConverter.cs +++ b/src/BuildVision.UI/Converters/GridColumnSettingsToColumnExampleValueConverter.cs @@ -1,8 +1,6 @@ -using System; +using System; using System.Globalization; using System.Windows.Data; - -using BuildVision.UI; using BuildVision.UI.DataGrid; using BuildVision.UI.Settings.Models.Columns; @@ -49,4 +47,4 @@ public object[] ConvertBack(object value, Type[] targetTypes, object parameter, throw new InvalidOperationException(); } } -} \ No newline at end of file +} diff --git a/src/BuildVision.UI/Converters/InProgressToCollapsedConverter.cs b/src/BuildVision.UI/Converters/InProgressToCollapsedConverter.cs index 1c78b9cb..2fe585a9 100644 --- a/src/BuildVision.UI/Converters/InProgressToCollapsedConverter.cs +++ b/src/BuildVision.UI/Converters/InProgressToCollapsedConverter.cs @@ -11,7 +11,7 @@ public class InProgressToCollapsedConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { - var buildState = (BuildState) value; + var buildState = (BuildState)value; return buildState == BuildState.InProgress ? Visibility.Collapsed : Visibility.Visible; } diff --git a/src/BuildVision.UI/Converters/NumberToIsPositiveConverter.cs b/src/BuildVision.UI/Converters/NumberToIsPositiveConverter.cs index 9b7faf9e..076e6aed 100644 --- a/src/BuildVision.UI/Converters/NumberToIsPositiveConverter.cs +++ b/src/BuildVision.UI/Converters/NumberToIsPositiveConverter.cs @@ -9,8 +9,7 @@ public class NumberToIsPositiveConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { - double val; - if (value != null && double.TryParse(value.ToString(), out val)) + if (value != null && double.TryParse(value.ToString(), out var val)) return val > 0; return false; diff --git a/src/BuildVision.UI/Converters/StateIconKeyToIconConverter.cs b/src/BuildVision.UI/Converters/StateIconKeyToIconConverter.cs index 417b8ce2..729f5965 100644 --- a/src/BuildVision.UI/Converters/StateIconKeyToIconConverter.cs +++ b/src/BuildVision.UI/Converters/StateIconKeyToIconConverter.cs @@ -2,9 +2,7 @@ using System.Globalization; using System.Windows.Controls; using System.Windows.Data; -using BuildVision.Contracts; using BuildVision.UI.Extensions; -using BuildVision.UI.Models; namespace BuildVision.UI.Converters { @@ -16,7 +14,7 @@ public class StateIconKeyToIconConverter : IValueConverter public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { var stateIconKey = (string)value; - var vector = VectorResources.TryGet(ResourcesUri, stateIconKey) ?? VectorResources.TryGet(ResourcesUri, "StandBy"); + var vector = VectorResources.TryGet(ResourcesUri, stateIconKey) ?? VectorResources.TryGet(ResourcesUri, "StandBy"); return vector; } diff --git a/src/BuildVision.UI/DataGrid/ColumnsManager.cs b/src/BuildVision.UI/DataGrid/ColumnsManager.cs index fc0e5a19..883385e0 100644 --- a/src/BuildVision.UI/DataGrid/ColumnsManager.cs +++ b/src/BuildVision.UI/DataGrid/ColumnsManager.cs @@ -8,7 +8,7 @@ using System.Windows.Data; using System.Windows.Media; using System.Windows.Media.Imaging; -using BuildVision.Contracts; +using BuildVision.Contracts.Exceptions; using BuildVision.UI.Common.Logging; using BuildVision.UI.Extensions; using BuildVision.UI.Helpers; diff --git a/src/BuildVision.UI/Models/ProjectItem.cs b/src/BuildVision.UI/Models/ProjectItem.cs index 231699df..7471c8c5 100644 --- a/src/BuildVision.UI/Models/ProjectItem.cs +++ b/src/BuildVision.UI/Models/ProjectItem.cs @@ -1,12 +1,11 @@ using System; +using System.Collections.ObjectModel; using System.Windows.Controls; using BuildVision.Common; using BuildVision.Common.Extensions; using BuildVision.Contracts; -using BuildVision.UI.Modelss; using BuildVision.UI.Extensions; -using System.Collections.Generic; -using System.Collections.ObjectModel; +using BuildVision.UI.Modelss; namespace BuildVision.UI.Models { diff --git a/src/BuildVision.UI/Models/WindowStateAction.cs b/src/BuildVision.UI/Models/WindowStateAction.cs index 6a1be444..df24bff9 100644 --- a/src/BuildVision.UI/Models/WindowStateAction.cs +++ b/src/BuildVision.UI/Models/WindowStateAction.cs @@ -1,5 +1,4 @@ -using BuildVision.UI.Models; -using System.Runtime.Serialization; +using BuildVision.UI.Models; namespace BuildVision.UI.Settings.Models.ToolWindow { diff --git a/src/BuildVision.UI/Settings/GeneralSettingsControl.xaml.cs b/src/BuildVision.UI/Settings/GeneralSettingsControl.xaml.cs index 36fbfc51..b0143873 100644 --- a/src/BuildVision.UI/Settings/GeneralSettingsControl.xaml.cs +++ b/src/BuildVision.UI/Settings/GeneralSettingsControl.xaml.cs @@ -1,10 +1,6 @@ -using BuildVision.Common; -using BuildVision.Helpers; -using Microsoft.VisualStudio.Shell; -using System; -using System.Diagnostics; -using System.Windows.Controls; +using System.Windows.Controls; using System.Windows.Navigation; +using BuildVision.Helpers; namespace BuildVision.UI.Settings { @@ -21,4 +17,4 @@ private void HyperlinkOnRequestNavigate(object sender, RequestNavigateEventArgs e.Handled = true; } } -} \ No newline at end of file +} diff --git a/src/BuildVision.UI/Settings/GridSettingsControl.xaml.cs b/src/BuildVision.UI/Settings/GridSettingsControl.xaml.cs index d4fb7f3f..603b3833 100644 --- a/src/BuildVision.UI/Settings/GridSettingsControl.xaml.cs +++ b/src/BuildVision.UI/Settings/GridSettingsControl.xaml.cs @@ -4,10 +4,9 @@ using System.Windows.Controls; using System.Windows.Data; using System.Windows.Input; - -using Microsoft.VisualStudio.Shell; -using BuildVision.UI.Settings.Models.Columns; using BuildVision.UI.Extensions; +using BuildVision.UI.Settings.Models.Columns; +using Microsoft.VisualStudio.Shell; namespace BuildVision.UI.Settings { @@ -127,4 +126,4 @@ private void GridOnTargetUpdated(object sender, DataTransferEventArgs e) } } } -} \ No newline at end of file +} diff --git a/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs b/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs index 3c1146ad..6263b6c7 100644 --- a/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs +++ b/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs @@ -12,6 +12,7 @@ using System.Windows.Input; using BuildVision.Common; using BuildVision.Contracts; +using BuildVision.Contracts.Exceptions; using BuildVision.Contracts.Models; using BuildVision.Core; using BuildVision.Exports.Providers; @@ -61,7 +62,7 @@ public bool HideUpToDateTargets public string GridGroupPropertyName { - get { return ControlSettings.GridSettings.GroupName; } + get => ControlSettings.GridSettings.GroupName; set { if (ControlSettings.GridSettings.GroupName != value) @@ -104,7 +105,7 @@ private CompositeCollection CreateContextMenu() { menuItem.IsCheckable = false; menuItem.StaysOpenOnClick = false; - menuItem.IsChecked = (GridGroupPropertyName == (string) menuItem.Tag); + menuItem.IsChecked = (GridGroupPropertyName == (string)menuItem.Tag); menuItem.Command = GridGroupPropertyMenuItemClicked; menuItem.CommandParameter = menuItem.Tag; } @@ -151,7 +152,7 @@ public ListCollectionView GroupedProjectsList } groupedList.CustomSort = GetProjectItemSorter(GridSortDescription); - groupedList.IsLiveGrouping = true; + groupedList.IsLiveGrouping = true; groupedList.IsLiveSorting = true; return groupedList; } @@ -159,12 +160,9 @@ public ListCollectionView GroupedProjectsList public DataGridHeadersVisibility GridHeadersVisibility { - get - { - return ControlSettings.GridSettings.ShowColumnsHeader + get => ControlSettings.GridSettings.ShowColumnsHeader ? DataGridHeadersVisibility.Column : DataGridHeadersVisibility.None; - } set { bool showColumnsHeader = (value != DataGridHeadersVisibility.None); @@ -178,7 +176,7 @@ public DataGridHeadersVisibility GridHeadersVisibility public ProjectItem SelectedProjectItem { - get => _selectedProjectItem; + get => _selectedProjectItem; set => SetProperty(ref _selectedProjectItem, value); } @@ -192,9 +190,9 @@ internal BuildVisionPaneViewModel() [ImportingConstructor] public BuildVisionPaneViewModel( - IBuildInformationProvider buildInformationProvider, - IPackageSettingsProvider settingsProvider, - ISolutionProvider solutionProvider, + IBuildInformationProvider buildInformationProvider, + IPackageSettingsProvider settingsProvider, + ISolutionProvider solutionProvider, IBuildService buildService, IErrorNavigationService errorNavigationService, ITaskBarInfoService taskBarInfoService) @@ -233,7 +231,7 @@ private void OpenContainingFolder() Process.Start(dir); } catch (Exception ex) - { + { ex.Trace(string.Format( "Unable to open folder '{0}' containing the project '{1}'.", SelectedProjectItem.FullName, @@ -371,7 +369,7 @@ private void CopyErrorMessageToClipboard(ProjectItem projectItem) public ICommand CancelBuildSolutionAction => new RelayCommand(obj => _buildService.CancelBuildSolution()); - public ICommand OpenGridColumnsSettingsAction => new RelayCommand(obj => ShowOptionPage?.Invoke(typeof(GridSettings))); + public ICommand OpenGridColumnsSettingsAction => new RelayCommand(obj => ShowOptionPage?.Invoke(typeof(GridSettings))); public ICommand OpenGeneralSettingsAction => new RelayCommand(obj => ShowOptionPage?.Invoke(typeof(GeneralSettings))); diff --git a/src/BuildVision/Core/BuildVisionPackage.cs b/src/BuildVision/Core/BuildVisionPackage.cs index 90b55c7f..f84664d3 100644 --- a/src/BuildVision/Core/BuildVisionPackage.cs +++ b/src/BuildVision/Core/BuildVisionPackage.cs @@ -1,5 +1,4 @@ using System; -using System.ComponentModel.Design; using System.Diagnostics; using System.Runtime.InteropServices; using System.Threading; @@ -8,9 +7,7 @@ using BuildVision.Commands; using BuildVision.Common.Diagnostics; using BuildVision.Exports.Providers; -using BuildVision.Helpers; using BuildVision.Tool; -using BuildVision.Tool.Building; using BuildVision.UI; using BuildVision.UI.Common.Logging; using BuildVision.UI.Settings.Models; @@ -22,9 +19,7 @@ using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; using Task = System.Threading.Tasks.Task; -using Window = EnvDTE.Window; using ui = Microsoft.VisualStudio.VSConstants.UICONTEXT; -using System.Threading.Tasks; namespace BuildVision.Core { @@ -50,7 +45,7 @@ public sealed class BuildVisionPackage : AsyncPackage, IVsPackageDynamicToolOwne private DTE _dte; private DTE2 _dte2; private CommandEvents _commandEvents; - private WindowEvents _windowEvents; + private readonly WindowEvents _windowEvents; private SolutionEvents _solutionEvents; private IVsSolutionBuildManager2 _solutionBuildManager; private IVsSolutionBuildManager5 _solutionBuildManager4; diff --git a/src/BuildVision/Core/BuildVisionPane.cs b/src/BuildVision/Core/BuildVisionPane.cs index 808b8f9f..5a0ce02e 100644 --- a/src/BuildVision/Core/BuildVisionPane.cs +++ b/src/BuildVision/Core/BuildVisionPane.cs @@ -1,22 +1,21 @@ -using System.Runtime.InteropServices; +using System; +using System.Globalization; +using System.Runtime.InteropServices; +using System.Threading.Tasks; using System.Windows; - -using Microsoft.VisualStudio.Shell; -using BuildVision.UI; +using System.Windows.Controls; +using System.Windows.Markup; using BuildVision.Core; -using BuildVision.UI.ViewModels; -using System; -using Microsoft.VisualStudio.Threading; -using System.Threading.Tasks; -using Microsoft; using BuildVision.Exports.Providers; using BuildVision.Exports.Services; -using BuildVision.Views.Settings; -using System.Windows.Controls; +using BuildVision.UI; using BuildVision.UI.Settings.Models; using BuildVision.UI.Settings.Models.Columns; -using System.Windows.Markup; -using System.Globalization; +using BuildVision.UI.ViewModels; +using BuildVision.Views.Settings; +using Microsoft; +using Microsoft.VisualStudio.Shell; +using Microsoft.VisualStudio.Threading; namespace BuildVision.Tool { @@ -35,7 +34,7 @@ public sealed class BuildVisionPane : ToolWindowPane private bool _controlCreatedSuccessfully; JoinableTask viewModelTask; - private ContentPresenter _contentPresenter; + private readonly ContentPresenter _contentPresenter; private IPackageSettingsProvider _packageSettingsProvider; public JoinableTaskFactory JoinableTaskFactory { get; private set; } @@ -46,7 +45,7 @@ public ControlView View } public BuildVisionPane() - :base(null) + : base(null) { Caption = Resources.ToolWindowTitle; BitmapResourceID = 301; @@ -60,7 +59,7 @@ protected override void Initialize() { // Using JoinableTaskFactory from parent AsyncPackage. That way if VS shuts down before this // work is done, we won't risk crashing due to arbitrary work going on in background threads. - var asyncPackage = (AsyncPackage) Package; + var asyncPackage = (AsyncPackage)Package; JoinableTaskFactory = asyncPackage.JoinableTaskFactory; viewModelTask = JoinableTaskFactory.RunAsync(() => InitializeAsync(asyncPackage)); @@ -68,7 +67,10 @@ protected override void Initialize() base.Initialize(); } - public Task GetViewModelAsync() => viewModelTask.JoinAsync(); + public Task GetViewModelAsync() + { + return viewModelTask.JoinAsync(); + } async Task InitializeAsync(AsyncPackage asyncPackage) { @@ -101,7 +103,7 @@ private void ViewModel_ShowOptionPage(Type obj) var asyncPackage = (AsyncPackage)Package; if (obj == typeof(GeneralSettings)) asyncPackage.ShowOptionPage(typeof(GeneralSettingsDialogPage)); - if(obj == typeof(GridColumnSettings)) + if (obj == typeof(GridColumnSettings)) asyncPackage.ShowOptionPage(typeof(GridSettingsDialogPage)); } diff --git a/src/BuildVision/Helpers/ProjectIdentifierGenerator.cs b/src/BuildVision/Helpers/ProjectIdentifierGenerator.cs index bb1d1058..5cbbf3fe 100644 --- a/src/BuildVision/Helpers/ProjectIdentifierGenerator.cs +++ b/src/BuildVision/Helpers/ProjectIdentifierGenerator.cs @@ -1,7 +1,4 @@ using BuildVision.UI.Models; -using EnvDTE; -using Microsoft.VisualStudio; -using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; namespace BuildVision.Helpers diff --git a/src/BuildVision/Helpers/SolutionProjectsExtensions.cs b/src/BuildVision/Helpers/SolutionProjectsExtensions.cs index bf565a66..67190fec 100644 --- a/src/BuildVision/Helpers/SolutionProjectsExtensions.cs +++ b/src/BuildVision/Helpers/SolutionProjectsExtensions.cs @@ -60,9 +60,9 @@ public static SolutionModel ToSolutionBuildState(this Solution solution) } public static IList GetProjects(this Solution solution) - { + { var list = new List(); - foreach(var proj in solution.Projects) + foreach (var proj in solution.Projects) { Project project = proj as Project; if (project == null) @@ -273,12 +273,11 @@ private static void AdjustUniqueNameForExtensionProjects(Project project, Projec public static object GetService(object serviceProviderObject, Type type) { object service = null; - IntPtr serviceIntPtr; Guid sidGuid = type.GUID; Guid iidGuid = sidGuid; var serviceProvider = (IServiceProvider)serviceProviderObject; - int hr = serviceProvider.QueryService(ref sidGuid, ref iidGuid, out serviceIntPtr); + int hr = serviceProvider.QueryService(ref sidGuid, ref iidGuid, out var serviceIntPtr); if (hr != 0) { diff --git a/src/BuildVision/Helpers/StateConverterHelper.cs b/src/BuildVision/Helpers/StateConverterHelper.cs index 6a8a8020..d561f403 100644 --- a/src/BuildVision/Helpers/StateConverterHelper.cs +++ b/src/BuildVision/Helpers/StateConverterHelper.cs @@ -1,6 +1,5 @@ -using System; +using BuildVision.Contracts; using Microsoft.VisualStudio.Shell.Interop; -using BuildVision.Contracts; namespace BuildVision.Tool.Models { diff --git a/src/BuildVision/Helpers/UIHierarchyExtensions.cs b/src/BuildVision/Helpers/UIHierarchyExtensions.cs index 177db178..b11977ca 100644 --- a/src/BuildVision/Helpers/UIHierarchyExtensions.cs +++ b/src/BuildVision/Helpers/UIHierarchyExtensions.cs @@ -1,6 +1,6 @@ -using EnvDTE; -using System; +using System; using System.Collections; +using EnvDTE; namespace BuildVision.Helpers { @@ -115,4 +115,4 @@ private static void CreateItemHierarchy(Stack itemHierarchy, object item) } } } -} \ No newline at end of file +} diff --git a/src/BuildVision/Helpers/VsHierarchyExtensions.cs b/src/BuildVision/Helpers/VsHierarchyExtensions.cs index ad9c6029..6f5e9faf 100644 --- a/src/BuildVision/Helpers/VsHierarchyExtensions.cs +++ b/src/BuildVision/Helpers/VsHierarchyExtensions.cs @@ -10,7 +10,7 @@ public static class VsHierarchyExtensions public static Project ToProject(this IVsHierarchy pHierProj) { ThreadHelper.ThrowIfNotOnUIThread(); - pHierProj.GetProperty(VSConstants.VSITEMID_ROOT, (int) __VSHPROPID.VSHPROPID_ExtObject, out var objProj); + pHierProj.GetProperty(VSConstants.VSITEMID_ROOT, (int)__VSHPROPID.VSHPROPID_ExtObject, out var objProj); return objProj as Project; } } diff --git a/src/BuildVision/Services/BuildService.cs b/src/BuildVision/Services/BuildService.cs index 57dc690e..dcd05221 100644 --- a/src/BuildVision/Services/BuildService.cs +++ b/src/BuildVision/Services/BuildService.cs @@ -6,6 +6,7 @@ using System.Windows; using BuildVision.Common; using BuildVision.Contracts; +using BuildVision.Contracts.Exceptions; using BuildVision.Contracts.Models; using BuildVision.Exports.Services; using BuildVision.Helpers; diff --git a/src/BuildVision/Services/StatusBarNotificationService.cs b/src/BuildVision/Services/StatusBarNotificationService.cs index b5c993fc..346fbf3b 100644 --- a/src/BuildVision/Services/StatusBarNotificationService.cs +++ b/src/BuildVision/Services/StatusBarNotificationService.cs @@ -1,11 +1,10 @@ using System; using System.ComponentModel.Composition; using BuildVision.Exports.Services; +using BuildVision.Extensions; using BuildVision.Views.Settings; -using Microsoft.VisualStudio; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; -using BuildVision.Extensions; namespace BuildVision.Core { diff --git a/src/BuildVision/Services/TaskBarInfoService.cs b/src/BuildVision/Services/TaskBarInfoService.cs index 423eef55..a1a485bb 100644 --- a/src/BuildVision/Services/TaskBarInfoService.cs +++ b/src/BuildVision/Services/TaskBarInfoService.cs @@ -3,10 +3,10 @@ using System.Threading.Tasks; using System.Windows; using System.Windows.Shell; -using BuildVision.UI.Models; using BuildVision.Contracts; -using BuildVision.Views.Settings; using BuildVision.Exports.Services; +using BuildVision.UI.Models; +using BuildVision.Views.Settings; namespace BuildVision.UI.ViewModels { diff --git a/src/BuildVision/Services/WindowStateService.cs b/src/BuildVision/Services/WindowStateService.cs index 301cbeaa..a84dfdbe 100644 --- a/src/BuildVision/Services/WindowStateService.cs +++ b/src/BuildVision/Services/WindowStateService.cs @@ -18,12 +18,12 @@ public class WindowStateService : IWindowStateService private DTE _dte; private IVsWindowFrame _windowFrame; private Window _window; - private IServiceProvider _serviceProvider; - private AsyncPackage _package; + private readonly IServiceProvider _serviceProvider; + private readonly AsyncPackage _package; [ImportingConstructor] public WindowStateService( - [Import(typeof(SVsServiceProvider))] IServiceProvider serviceProvider, + [Import(typeof(SVsServiceProvider))] IServiceProvider serviceProvider, AsyncPackage package) { _serviceProvider = serviceProvider; @@ -144,13 +144,13 @@ public void Initialize(ToolWindowPane toolWindowPane) public void ApplyToolWindowStateAction(WindowStateAction windowStateAction) { - if(BuildVisionPackage.ToolWindowPane == null) + if (BuildVisionPackage.ToolWindowPane == null) { return; } Initialize(BuildVisionPackage.ToolWindowPane); - ApplyToolWindowStateAction(windowStateAction.State); + ApplyToolWindowStateAction(windowStateAction.State); } } } From 901673d7dfcbfee36093dc78ce3722fbd592e949 Mon Sep 17 00:00:00 2001 From: Stefan Kert Date: Fri, 12 Apr 2019 18:47:43 +0200 Subject: [PATCH 064/100] Using new logging framework Serilog do trace errors more easily --- src/BuildVision.Common/ApplicationInfo.cs | 20 ++ .../BuildVision.Common.csproj | 6 + .../Logging/ILoggerExtensions.cs | 64 +++++++ src/BuildVision.Common/Logging/Log.cs | 13 ++ src/BuildVision.Common/Logging/LogManager.cs | 56 ++++++ src/BuildVision.UI/BuildVision.UI.csproj | 6 +- .../Common/Logging/BindingErrorListener.cs | 16 -- .../Common/Logging/TraceManager.cs | 172 ------------------ .../Components/ErrorsGrid.xaml.cs | 4 +- .../MultiBindingStringFormatConverter.cs | 8 +- src/BuildVision.UI/DataGrid/ColumnsManager.cs | 9 +- .../ViewModels/BuildVisionPaneViewModel.cs | 16 +- src/BuildVision/Core/BuildVisionPackage.cs | 14 +- .../Core/ServiceProviderPackage.cs | 3 +- src/BuildVision/Helpers/ProjectExtensions.cs | 46 ++--- .../Helpers/ProjectItemExtensions.cs | 2 +- .../Helpers/SolutionProjectsExtensions.cs | 36 ++-- .../Services/BuildInformationProvider.cs | 33 ++-- src/BuildVision/Services/BuildOutputLogger.cs | 12 +- src/BuildVision/Services/BuildService.cs | 135 ++++++-------- .../Services/ErrorNavigationService.cs | 9 +- .../Services/PackageSettingsProvider.cs | 5 +- src/BuildVision/Services/SolutionProvider.cs | 6 +- .../BuildVision.UnitTests.csproj | 2 +- 24 files changed, 316 insertions(+), 377 deletions(-) create mode 100644 src/BuildVision.Common/ApplicationInfo.cs create mode 100644 src/BuildVision.Common/Logging/ILoggerExtensions.cs create mode 100644 src/BuildVision.Common/Logging/Log.cs create mode 100644 src/BuildVision.Common/Logging/LogManager.cs delete mode 100644 src/BuildVision.UI/Common/Logging/BindingErrorListener.cs delete mode 100644 src/BuildVision.UI/Common/Logging/TraceManager.cs diff --git a/src/BuildVision.Common/ApplicationInfo.cs b/src/BuildVision.Common/ApplicationInfo.cs new file mode 100644 index 00000000..f023f807 --- /dev/null +++ b/src/BuildVision.Common/ApplicationInfo.cs @@ -0,0 +1,20 @@ +using System; +using System.Diagnostics; + +namespace BuildVision.Common +{ + public static class ApplicationInfo + { + public const string ApplicationName = "BuildVision"; + + public static FileVersionInfo GetHostVersionInfo() + { + return Process.GetCurrentProcess().MainModule.FileVersionInfo; + } + + public static Version GetPackageVersion(object package) + { + return package.GetType().Assembly.GetName().Version; + } + } +} diff --git a/src/BuildVision.Common/BuildVision.Common.csproj b/src/BuildVision.Common/BuildVision.Common.csproj index a29e2344..0731d117 100644 --- a/src/BuildVision.Common/BuildVision.Common.csproj +++ b/src/BuildVision.Common/BuildVision.Common.csproj @@ -14,6 +14,12 @@ + + + + + + diff --git a/src/BuildVision.Common/Logging/ILoggerExtensions.cs b/src/BuildVision.Common/Logging/ILoggerExtensions.cs new file mode 100644 index 00000000..7e5490e1 --- /dev/null +++ b/src/BuildVision.Common/Logging/ILoggerExtensions.cs @@ -0,0 +1,64 @@ +using System; +using System.Globalization; +using System.Threading.Tasks; +using Serilog; + +namespace BuildVision.Common.Logging +{ + public static class ILoggerExtensions + { + public static void Assert(this ILogger logger, bool condition, string messageTemplate) + { + if (!condition) + { + messageTemplate = "Assertion Failed: " + messageTemplate; +#pragma warning disable Serilog004 // propertyValues might not be strings + logger.Warning(messageTemplate); +#pragma warning restore Serilog004 + } + } + + public static void Assert(this ILogger logger, bool condition, string messageTemplate, params object[] propertyValues) + { + if (!condition) + { + messageTemplate = "Assertion Failed: " + messageTemplate; +#pragma warning disable Serilog004 // propertyValues might not be strings + logger.Warning(messageTemplate, propertyValues); +#pragma warning restore Serilog004 + } + } + + public static void Time(this ILogger logger, string name, Action method) + { + var startTime = DateTime.Now; + method(); + logger.Verbose("{Name} took {Seconds} seconds", name, FormatSeconds(DateTime.Now - startTime)); + } + + public static T Time(this ILogger logger, string name, Func method) + { + var startTime = DateTime.Now; + var value = method(); + logger.Verbose("{Name} took {Seconds} seconds", name, FormatSeconds(DateTime.Now - startTime)); + return value; + } + + public static async Task TimeAsync(this ILogger logger, string name, Func methodAsync) + { + var startTime = DateTime.Now; + await methodAsync().ConfigureAwait(false); + logger.Verbose("{Name} took {Seconds} seconds", name, FormatSeconds(DateTime.Now - startTime)); + } + + public static async Task TimeAsync(this ILogger logger, string name, Func> methodAsync) + { + var startTime = DateTime.Now; + var value = await methodAsync().ConfigureAwait(false); + logger.Verbose("{Name} took {Seconds} seconds", name, FormatSeconds(DateTime.Now - startTime)); + return value; + } + + static string FormatSeconds(TimeSpan timeSpan) => timeSpan.TotalSeconds.ToString("0.##", CultureInfo.InvariantCulture); + } +} diff --git a/src/BuildVision.Common/Logging/Log.cs b/src/BuildVision.Common/Logging/Log.cs new file mode 100644 index 00000000..0eff06fb --- /dev/null +++ b/src/BuildVision.Common/Logging/Log.cs @@ -0,0 +1,13 @@ +using System; +using Serilog; + +namespace BuildVision.Common.Logging +{ + public static class Log + { + private static Lazy Logger { get; } = new Lazy(() => LogManager.ForContext(typeof(Log))); + + public static void Assert(bool condition, string messageTemplate) + => Logger.Value.Assert(condition, messageTemplate); + } +} diff --git a/src/BuildVision.Common/Logging/LogManager.cs b/src/BuildVision.Common/Logging/LogManager.cs new file mode 100644 index 00000000..c224f6a6 --- /dev/null +++ b/src/BuildVision.Common/Logging/LogManager.cs @@ -0,0 +1,56 @@ +using System; +using System.IO; +using Serilog; +using Serilog.Core; +using Serilog.Events; + +namespace BuildVision.Common.Logging +{ + public static class LogManager + { +#if DEBUG + private static LogEventLevel DefaultLoggingLevel = LogEventLevel.Debug; +#else + private static LogEventLevel DefaultLoggingLevel = LogEventLevel.Information; +#endif + + private static LoggingLevelSwitch LoggingLevelSwitch = new LoggingLevelSwitch(DefaultLoggingLevel); + + static Logger CreateLogger() + { + var logPath = Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), + ApplicationInfo.ApplicationName, + "extension.log"); + + const string outputTemplate = + "{Timestamp:yyyy-MM-dd HH:mm:ss.fff} [{ProcessId:00000}] {Level:u4} [{ThreadId:00}] {ShortSourceContext,-25} {Message:lj}{NewLine}{Exception}"; + + return new LoggerConfiguration() + .Enrich.WithProcessId() + .Enrich.WithThreadId() + .MinimumLevel.ControlledBy(LoggingLevelSwitch) + .WriteTo.File(logPath, + fileSizeLimitBytes: null, + outputTemplate: outputTemplate, + shared: true) + .CreateLogger(); + } + + public static void EnableTraceLogging(bool enable) + { + var logEventLevel = enable ? LogEventLevel.Verbose : DefaultLoggingLevel; + if (LoggingLevelSwitch.MinimumLevel != logEventLevel) + { + ForContext(typeof(LogManager)).Information("Set Logging Level: {LogEventLevel}", logEventLevel); + LoggingLevelSwitch.MinimumLevel = logEventLevel; + } + } + + static Lazy Logger { get; } = new Lazy(CreateLogger); + + public static ILogger ForContext() => ForContext(typeof(T)); + + public static ILogger ForContext(Type type) => Logger.Value.ForContext(type).ForContext("ShortSourceContext", type.Name); + } +} diff --git a/src/BuildVision.UI/BuildVision.UI.csproj b/src/BuildVision.UI/BuildVision.UI.csproj index 8fb41c75..7343144d 100644 --- a/src/BuildVision.UI/BuildVision.UI.csproj +++ b/src/BuildVision.UI/BuildVision.UI.csproj @@ -103,8 +103,6 @@ - - ErrorsGrid.xaml @@ -376,8 +374,6 @@ 14.3.81-pre - - - + \ No newline at end of file diff --git a/src/BuildVision.UI/Common/Logging/BindingErrorListener.cs b/src/BuildVision.UI/Common/Logging/BindingErrorListener.cs deleted file mode 100644 index 515d9249..00000000 --- a/src/BuildVision.UI/Common/Logging/BindingErrorListener.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.Diagnostics; - -namespace BuildVision.UI.Common.Logging -{ - public class BindingErrorListener : TraceListener - { - public override void Write(string message) - { - } - - public override void WriteLine(string message) - { - TraceManager.Trace("Binding error: " + message, EventLogEntryType.Warning); - } - } -} \ No newline at end of file diff --git a/src/BuildVision.UI/Common/Logging/TraceManager.cs b/src/BuildVision.UI/Common/Logging/TraceManager.cs deleted file mode 100644 index 780722d1..00000000 --- a/src/BuildVision.UI/Common/Logging/TraceManager.cs +++ /dev/null @@ -1,172 +0,0 @@ -using System; -using System.Diagnostics; -using System.IO; -using System.Text; -using System.Windows; - -namespace BuildVision.UI.Common.Logging -{ - public static class TraceManager - { -#if DEBUG - static TraceManager() - { - string logDirectoryPath = Path.Combine( - Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), - Resources.ProductName, - "log"); - string logFilePath = Path.Combine( - logDirectoryPath, - string.Format("log_{0}.svclog", Guid.NewGuid())); - - if (!Directory.Exists(logDirectoryPath)) - Directory.CreateDirectory(logDirectoryPath); - - var traceListener = new XmlWriterTraceListener(logFilePath) - { - TraceOutputOptions = TraceOptions.DateTime - }; - - System.Diagnostics.Trace.AutoFlush = true; - System.Diagnostics.Trace.Listeners.Add(traceListener); - - // Tracing binding errors - PresentationTraceSources.DataBindingSource.Listeners.Add(new BindingErrorListener()); - PresentationTraceSources.DataBindingSource.Switch.Level = SourceLevels.Error; - } -#endif - - public static void TraceUnknownException(this Exception ex) - { - Trace(ex, Resources.UnknownExceptionMsg); - } - - public static void TraceError(string message) - { - Trace(message, EventLogEntryType.Error); - } - - public static void Trace(this Exception ex, string message, EventLogEntryType type = EventLogEntryType.Error) - { - TraceAction(ex.ToLogString(message), type); - } - - public static void Trace(string message, EventLogEntryType type) - { - TraceAction(message, type); - } - - private static void TraceAction(string message, EventLogEntryType type) - { - System.Threading.Tasks.Task.Run(() => - { - - // ActivityLog works if devenv.exe started with /log switch. - // Read more https://msdn.microsoft.com/en-us/library/ms241272.aspx. - switch (type) - { - case EventLogEntryType.Error: - //ActivityLog.LogError(Resources.ProductName, message); -#if DEBUG - System.Diagnostics.Trace.TraceError(message); - MessageBox.Show(message, Resources.ProductName + " error", MessageBoxButton.OK, MessageBoxImage.Error); -#endif - break; - - case EventLogEntryType.Warning: - case EventLogEntryType.FailureAudit: - //ActivityLog.LogWarning(Resources.ProductName, message); -#if DEBUG - System.Diagnostics.Trace.TraceWarning(message); -#endif - break; - - case EventLogEntryType.Information: - case EventLogEntryType.SuccessAudit: - //ActivityLog.LogInformation(Resources.ProductName, message); -#if DEBUG - System.Diagnostics.Trace.TraceInformation(message); -#endif - break; - - default: - throw new ArgumentOutOfRangeException(nameof(type)); - } - }); - } - - public static string ToLogString(this Exception ex, string additionalMessage) - { - var msg = new StringBuilder(); - if (!string.IsNullOrEmpty(additionalMessage)) - msg.AppendLine(additionalMessage); - - if (ex == null) - return msg.ToString(); - - Exception orgEx = ex; - msg.AppendLine("Exception:"); - while (orgEx != null) - { - msg.AppendLine(orgEx.Message); - orgEx = orgEx.InnerException; - } - - AddDataEntries(ex, msg); - AddStackTrace(ex, msg); - AddSource(ex, msg); - AddTargetSite(ex, msg); - AddBaseExcception(ex, msg); - return msg.ToString(); - } - - private static void AddBaseExcception(Exception ex, StringBuilder msg) - { - Exception baseException = ex.GetBaseException(); - if (baseException != null) - { - msg.AppendLine("BaseException:"); - msg.Append(ex.GetBaseException()); - } - } - - private static void AddTargetSite(Exception ex, StringBuilder msg) - { - if (ex.TargetSite != null) - { - msg.AppendLine("TargetSite:"); - msg.AppendLine(ex.TargetSite.ToString()); - } - } - - private static void AddSource(Exception ex, StringBuilder msg) - { - if (ex.Source != null) - { - msg.AppendLine("Source:"); - msg.AppendLine(ex.Source.ToString()); - } - } - - private static void AddStackTrace(Exception ex, StringBuilder msg) - { - if (ex.StackTrace != null) - { - msg.AppendLine("StackTrace:"); - msg.AppendLine(ex.StackTrace); - } - } - - private static void AddDataEntries(Exception ex, StringBuilder msg) - { - if (ex.Data != null && ex.Data.Count > 0) - { - msg.AppendLine("Data:"); - foreach (System.Collections.DictionaryEntry dataEntry in ex.Data) - { - msg.AppendLine(string.Format("Key='{0}';Value='{1}'", dataEntry.Key, dataEntry.Value)); - } - } - } - } -} diff --git a/src/BuildVision.UI/Components/ErrorsGrid.xaml.cs b/src/BuildVision.UI/Components/ErrorsGrid.xaml.cs index 259d8738..c6c74857 100644 --- a/src/BuildVision.UI/Components/ErrorsGrid.xaml.cs +++ b/src/BuildVision.UI/Components/ErrorsGrid.xaml.cs @@ -4,8 +4,8 @@ using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; +using BuildVision.Common.Logging; using BuildVision.Contracts; -using BuildVision.UI.Common.Logging; using BuildVision.UI.Extensions; using BuildVision.UI.Models; @@ -50,7 +50,7 @@ private void ErrorsGridRowOnMouseLeftButtonUp(object sender, MouseButtonEventArg } catch (Exception ex) { - ex.Trace("Navigate to error item exception."); + LogManager.ForContext().Error(ex, "Navigate to error item exception."); } } diff --git a/src/BuildVision.UI/Converters/MultiBindingStringFormatConverter.cs b/src/BuildVision.UI/Converters/MultiBindingStringFormatConverter.cs index 217e7733..aedbb977 100644 --- a/src/BuildVision.UI/Converters/MultiBindingStringFormatConverter.cs +++ b/src/BuildVision.UI/Converters/MultiBindingStringFormatConverter.cs @@ -1,9 +1,9 @@ -using System; +using System; using System.Globalization; using System.Linq; using System.Windows.Data; using BuildVision.Common; -using BuildVision.UI.Common.Logging; +using BuildVision.Common.Logging; namespace BuildVision.UI.Converters { @@ -25,7 +25,7 @@ public object Convert(object[] values, Type targetType, object parameter, Cultur } catch (Exception ex) { - ex.Trace("Format error: " + ex.Message); + LogManager.ForContext< MultiBindingStringFormatConverter>().Error(ex, "Error during MultiBindingStringFormatConverter."); return string.Format("", ex.Message); } } @@ -35,4 +35,4 @@ public object[] ConvertBack(object value, Type[] targetTypes, object parameter, throw new InvalidOperationException(); } } -} \ No newline at end of file +} diff --git a/src/BuildVision.UI/DataGrid/ColumnsManager.cs b/src/BuildVision.UI/DataGrid/ColumnsManager.cs index 883385e0..2d4811ec 100644 --- a/src/BuildVision.UI/DataGrid/ColumnsManager.cs +++ b/src/BuildVision.UI/DataGrid/ColumnsManager.cs @@ -8,8 +8,8 @@ using System.Windows.Data; using System.Windows.Media; using System.Windows.Media.Imaging; +using BuildVision.Common.Logging; using BuildVision.Contracts.Exceptions; -using BuildVision.UI.Common.Logging; using BuildVision.UI.Extensions; using BuildVision.UI.Helpers; using BuildVision.UI.Models; @@ -17,6 +17,7 @@ using BuildVision.UI.Settings.Models; using BuildVision.UI.Settings.Models.Columns; using BuildVision.UI.Settings.Models.Sorting; +using Serilog; namespace BuildVision.UI.DataGrid { @@ -138,7 +139,7 @@ public static void GenerateColumns(ObservableCollection columns, } catch (Exception ex) { - ex.TraceUnknownException(); + LogManager.ForContext(typeof(ColumnsManager)).Error(ex, "Failed to sync generatecolumns."); } } @@ -160,7 +161,7 @@ public static void SyncColumnSettings(ObservableCollection colum } catch (Exception ex) { - ex.TraceUnknownException(); + LogManager.ForContext(typeof(ColumnsManager)).Error(ex, "Failed to sync columnsettings."); } } @@ -189,7 +190,7 @@ private static T GetPropertyAttribute(string propertyName) if (propertyInfo == null) { var ex = new PropertyNotFoundException(propertyName, _itemRowType); - ex.Trace("Unable to find attribute by property."); + LogManager.ForContext(typeof(ColumnsManager)).Error(ex, "Failed to load data for property {PropertyName}.", propertyName); throw ex; } diff --git a/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs b/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs index 6263b6c7..95189a38 100644 --- a/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs +++ b/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs @@ -11,6 +11,7 @@ using System.Windows.Data; using System.Windows.Input; using BuildVision.Common; +using BuildVision.Common.Logging; using BuildVision.Contracts; using BuildVision.Contracts.Exceptions; using BuildVision.Contracts.Models; @@ -19,13 +20,13 @@ using BuildVision.Exports.Services; using BuildVision.Exports.ViewModels; using BuildVision.Helpers; -using BuildVision.UI.Common.Logging; using BuildVision.UI.DataGrid; using BuildVision.UI.Helpers; using BuildVision.UI.Models; using BuildVision.UI.Settings.Models; using BuildVision.Views.Settings; using Microsoft.VisualStudio; +using Serilog; using Process = System.Diagnostics.Process; using SortDescription = BuildVision.UI.Settings.Models.Sorting.SortDescription; @@ -42,6 +43,8 @@ public class BuildVisionPaneViewModel : BindableBase, IBuildVisionPaneViewModel private readonly IPackageSettingsProvider _settingsProvider; private ObservableCollection _gridColumnsRef; + private ILogger _logger = LogManager.ForContext(); + public ISolutionModel SolutionModel { get; set; } public string GridGroupHeaderName => string.IsNullOrEmpty(GridGroupPropertyName) ? string.Empty : ControlSettings.GridSettings.Columns[GridGroupPropertyName].Header; @@ -232,10 +235,7 @@ private void OpenContainingFolder() } catch (Exception ex) { - ex.Trace(string.Format( - "Unable to open folder '{0}' containing the project '{1}'.", - SelectedProjectItem.FullName, - SelectedProjectItem.UniqueName)); + _logger.Error(ex, "Unable to open folder '{FullName}' containing the project '{UniqueName}'.", SelectedProjectItem.FullName, SelectedProjectItem.UniqueName); MessageBox.Show( ex.Message + "\n\nSee log for details.", @@ -272,7 +272,7 @@ private void ReorderGrid(object obj) GridSortDescription = new SortDescription(newSortDirection.ToMedia(), e.Column.GetBindedProperty()); } - private static ProjectItemColumnSorter GetProjectItemSorter(SortDescription sortDescription) + private ProjectItemColumnSorter GetProjectItemSorter(SortDescription sortDescription) { var sortOrder = sortDescription.Order; string sortPropertyName = sortDescription.Property; @@ -288,7 +288,7 @@ private static ProjectItemColumnSorter GetProjectItemSorter(SortDescription sort } catch (PropertyNotFoundException ex) { - ex.Trace("Trying to sort Project Items by nonexistent property."); + _logger.Error(ex, "Trying to sort Project Items by nonexistent property."); return null; } } @@ -335,7 +335,7 @@ private void CopyErrorMessageToClipboard(ProjectItem projectItem) } catch (Exception ex) { - ex.TraceUnknownException(); + _logger.Error(ex, "Unable to CopyErrorMessageToClipboard for project '{UniqueName}'.", projectItem.UniqueName); } } diff --git a/src/BuildVision/Core/BuildVisionPackage.cs b/src/BuildVision/Core/BuildVisionPackage.cs index f84664d3..74321e85 100644 --- a/src/BuildVision/Core/BuildVisionPackage.cs +++ b/src/BuildVision/Core/BuildVisionPackage.cs @@ -5,11 +5,12 @@ using System.Windows; using System.Windows.Threading; using BuildVision.Commands; +using BuildVision.Common; using BuildVision.Common.Diagnostics; +using BuildVision.Common.Logging; using BuildVision.Exports.Providers; using BuildVision.Tool; using BuildVision.UI; -using BuildVision.UI.Common.Logging; using BuildVision.UI.Settings.Models; using BuildVision.Views.Settings; using EnvDTE; @@ -18,6 +19,7 @@ using Microsoft.VisualStudio; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; +using Serilog; using Task = System.Threading.Tasks.Task; using ui = Microsoft.VisualStudio.VSConstants.UICONTEXT; @@ -40,12 +42,9 @@ namespace BuildVision.Core [ProvideOptionPage(typeof(ProjectItemSettingsDialogPage), "BuildVision", "Project Item", 0, 0, true)] public sealed class BuildVisionPackage : AsyncPackage, IVsPackageDynamicToolOwnerEx { - private const string _loadContext = "dec9f70a-b8b1-4050-ae96-08f89c6eccd1"; - private DTE _dte; private DTE2 _dte2; private CommandEvents _commandEvents; - private readonly WindowEvents _windowEvents; private SolutionEvents _solutionEvents; private IVsSolutionBuildManager2 _solutionBuildManager; private IVsSolutionBuildManager5 _solutionBuildManager4; @@ -55,7 +54,7 @@ public sealed class BuildVisionPackage : AsyncPackage, IVsPackageDynamicToolOwne private SolutionBuildEvents _solutionBuildEvents; private ISolutionProvider _solutionProvider; private ServiceProvider _serviceProvider; - + private ILogger _logger = LogManager.ForContext(); public static ToolWindowPane ToolWindowPane { get; set; } @@ -63,8 +62,7 @@ public sealed class BuildVisionPackage : AsyncPackage, IVsPackageDynamicToolOwne public BuildVisionPackage() { - string hello = string.Format("{0} {1}", Resources.ProductName, "BuildVisionVersion.PackageVersion"); - TraceManager.Trace(hello, EventLogEntryType.Information); + _logger.Information("Starting {ProductName} with Version {PackageVersion}", Resources.ProductName, ApplicationInfo.GetPackageVersion(this)); if (Application.Current != null) { @@ -74,7 +72,7 @@ public BuildVisionPackage() private void Current_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e) { - DiagnosticsClient.Notify(e.Exception); + _logger.Fatal(e.Exception, "Unhandled Exception"); } protected override async Task InitializeAsync(CancellationToken cancellationToken, IProgress progress) diff --git a/src/BuildVision/Core/ServiceProviderPackage.cs b/src/BuildVision/Core/ServiceProviderPackage.cs index 3b93b745..ebba77da 100644 --- a/src/BuildVision/Core/ServiceProviderPackage.cs +++ b/src/BuildVision/Core/ServiceProviderPackage.cs @@ -75,7 +75,8 @@ async Task CreateServiceAsync(IAsyncServiceContainer container, Cancella } else if (serviceType == typeof(IBuildService)) { - return new BuildService(sp); + var packageSettingsProvider = await GetServiceAsync(cancellation); + return new BuildService(sp, packageSettingsProvider); } else if (serviceType == typeof(IStatusBarNotificationService)) { diff --git a/src/BuildVision/Helpers/ProjectExtensions.cs b/src/BuildVision/Helpers/ProjectExtensions.cs index 703ac904..22e3c866 100644 --- a/src/BuildVision/Helpers/ProjectExtensions.cs +++ b/src/BuildVision/Helpers/ProjectExtensions.cs @@ -4,9 +4,9 @@ using System.Globalization; using System.Linq; using System.Text; +using BuildVision.Common.Logging; using BuildVision.Contracts; using BuildVision.UI; -using BuildVision.UI.Common.Logging; using EnvDTE; using Microsoft.VisualStudio.Shell.Interop; using Microsoft.Win32; @@ -134,7 +134,7 @@ public static IEnumerable GetBuildOutputFilePaths(this Project project, catch (ArgumentException ex) { var msg = $"Build Output Group \"{groupName}\" not found (Project Kind is \"{project.Kind}\")."; - ex.Trace(msg, EventLogEntryType.Warning); + LogManager.ForContext().Warning(ex, "{Msg}", msg); } } @@ -220,7 +220,7 @@ public static string GetFrameworkString(this Project project) } catch (Exception ex) { - ex.TraceUnknownException(); + LogManager.ForContext().Error(ex, "Error when trying to parse framework version (Hex)."); return Resources.GridCellNAText; } } @@ -237,7 +237,7 @@ public static string GetFrameworkString(this Project project) } catch (Exception ex) { - ex.TraceUnknownException(); + LogManager.ForContext().Error(ex, "Error when trying to get framework string."); return Resources.GridCellNAText; } } @@ -284,7 +284,7 @@ public static string GetLanguageName(this Project project) } catch (Exception ex) { - ex.TraceUnknownException(); + LogManager.ForContext().Error(ex, "Error when trying to get language name."); return Resources.GridCellNAText; } } @@ -315,7 +315,7 @@ public static IEnumerable GetFlavourTypes(this Project project) } catch (Exception ex) { - ex.TraceUnknownException(); + LogManager.ForContext().Error(ex, "Error when trying to get framework string."); return Enumerable.Empty(); } } @@ -371,16 +371,9 @@ public static string GetOutputType(this Project project) } } } - catch (ArgumentException) - { - // We are catching this seperatly because in the current VS2017 Version - // there is a bug that makes it impossible for us to retrieve the extenders - // for specific projects (https://github.com/dotnet/project-system/issues/2686) - return Resources.GridCellNAText; - } catch (Exception ex) { - ex.TraceUnknownException(); + LogManager.ForContext().Error(ex, "Error when trying to get output type."); return Resources.GridCellNAText; } } @@ -395,13 +388,9 @@ public static string GetExtenderNames(this Project project) return string.Join("; ", extenderNames); } - catch (ArgumentException) - { - return ""; // Leaving this in for now until visual studio team fixes the issue with extendernames - } catch (Exception ex) { - ex.TraceUnknownException(); + LogManager.ForContext().Error(ex, "Error when trying to get extendernames."); return Resources.GridCellNAText; } } @@ -447,10 +436,7 @@ private static string GetProjectTypeFromRegistry(string projectKind, string vers } } - TraceManager.Trace( - string.Format("Project type is taken from the registry: Kind={0}, DTEVersion={1}, Type={2}", projectKind, version, type), - EventLogEntryType.Warning); - + LogManager.ForContext().Warning("Project type is taken from the registry: Kind={ProjectKind}, DTEVersion={Version}, Type={Type}", projectKind, version, type); if (string.IsNullOrWhiteSpace(type)) return null; @@ -459,7 +445,7 @@ private static string GetProjectTypeFromRegistry(string projectKind, string vers } catch (Exception ex) { - ex.Trace(string.Format("Unable to get project type from registry: (Kind={0}, DTEVersion={1})", projectKind, version)); + LogManager.ForContext().Error(ex, "Unable to get project type from registry: (Kind ={ProjectKind}, DTEVersion ={Version})", projectKind, version); return null; } } @@ -509,7 +495,7 @@ public static string GetTreePath(this Project project, bool includeSelfProjectNa } catch (Exception ex) { - ex.TraceUnknownException(); + LogManager.ForContext().Error(ex, "Failed to get treepath for project {UniqueName}", project?.UniqueName); } return (path.Length != 0) ? path.ToString() : null; @@ -524,7 +510,7 @@ public static Project TryGetParentProject(this Project project) } catch (Exception ex) { - ex.TraceUnknownException(); + LogManager.ForContext().Error(ex, "Failed to load parent project for project {UniqueName}", project?.UniqueName); return null; } } @@ -533,14 +519,14 @@ public static Project GetSubProject(this Project solutionFolder, Func().Error(ex, "Failed to check if project {UniqueName} is hidden.", project?.UniqueName); return true; } } @@ -613,7 +599,7 @@ public static bool IsProjectHidden(string projectFileName) } catch (Exception ex) { - ex.TraceUnknownException(); + LogManager.ForContext().Error(ex, "Failed to check if project {ProjectFileName} is hidden.", projectFileName); return true; } } diff --git a/src/BuildVision/Helpers/ProjectItemExtensions.cs b/src/BuildVision/Helpers/ProjectItemExtensions.cs index d45fbd45..10156649 100644 --- a/src/BuildVision/Helpers/ProjectItemExtensions.cs +++ b/src/BuildVision/Helpers/ProjectItemExtensions.cs @@ -60,7 +60,7 @@ public static ProjectItem FindProjectItem(this ProjectItems items, string filePa // Nested item, e.g. Default.aspx or MainWindow.xaml. if (item.ProjectItems.Count > 0) { - ProjectItem childItem = FindProjectItem(item.ProjectItems, fileName); + var childItem = FindProjectItem(item.ProjectItems, fileName); if (childItem != null) return childItem; } diff --git a/src/BuildVision/Helpers/SolutionProjectsExtensions.cs b/src/BuildVision/Helpers/SolutionProjectsExtensions.cs index 67190fec..9f31f50a 100644 --- a/src/BuildVision/Helpers/SolutionProjectsExtensions.cs +++ b/src/BuildVision/Helpers/SolutionProjectsExtensions.cs @@ -3,9 +3,9 @@ using System.IO; using System.Linq; using System.Runtime.InteropServices; +using BuildVision.Common.Logging; using BuildVision.Core; using BuildVision.UI; -using BuildVision.UI.Common.Logging; using EnvDTE; using IServiceProvider = Microsoft.VisualStudio.OLE.Interop.IServiceProvider; using ProjectItem = BuildVision.UI.Models.ProjectItem; @@ -50,7 +50,7 @@ public static SolutionModel ToSolutionBuildState(this Solution solution) } catch (Exception ex) { - ex.TraceUnknownException(); + LogManager.ForContext().Error(ex, "Failed to load solution {FullName}", solution?.FullName); solutionItem.Name = Resources.GridCellNATextInBrackets; solutionItem.FullName = Resources.GridCellNATextInBrackets; @@ -64,7 +64,7 @@ public static IList GetProjects(this Solution solution) var list = new List(); foreach (var proj in solution.Projects) { - Project project = proj as Project; + var project = proj as Project; if (project == null) continue; @@ -78,17 +78,17 @@ public static IList GetProjects(this Solution solution) public static Project GetProject(this Solution solution, Func cond) { - Projects projects = solution.Projects; + var projects = solution.Projects; var item = projects.GetEnumerator(); while (item.MoveNext()) { - Project project = item.Current as Project; + var project = item.Current as Project; if (project == null) continue; if (project.Kind == EnvDTEProjectKinds.ProjectKindSolutionFolder) { - Project sub = project.GetSubProject(cond); + var sub = project.GetSubProject(cond); if (sub != null) return sub; } @@ -111,12 +111,12 @@ public static IList GetProjectItems(this Solution solution) } catch (Exception ex) { - ex.TraceUnknownException(); + LogManager.ForContext().Error(ex, "Failed to get projectitems for solution {FullName}", solution?.FullName); } var projectItems = new List(dteProjects.Count); - foreach (Project project in dteProjects) + foreach (var project in dteProjects) { try { @@ -127,7 +127,7 @@ public static IList GetProjectItems(this Solution solution) } catch (Exception ex) { - ex.TraceUnknownException(); + LogManager.ForContext().Error(ex, "Failed to update project properties for solution {FullName}", solution?.FullName); } } @@ -145,7 +145,7 @@ public static void UpdateProperties(Project project, ProjectItem projectItem, st } catch (Exception ex) { - ex.TraceUnknownException(); + LogManager.ForContext().Error(ex, "Failed to load project.Object for project {UniqueName}", project?.UniqueName); projObject = null; } @@ -164,7 +164,7 @@ public static void UpdateProperties(Project project, ProjectItem projectItem, st } catch (Exception ex) { - ex.TraceUnknownException(); + LogManager.ForContext().Error(ex, "Failed to updatename properties project properties for project {UniqueName}", project?.UniqueName); } #region Set ActiveConfiguration (Configuration and Platform) @@ -183,7 +183,7 @@ public static void UpdateProperties(Project project, ProjectItem projectItem, st } catch (Exception ex) { - ex.TraceUnknownException(); + LogManager.ForContext().Error(ex, "Failed to get active configuration for {UniqueName}", project?.UniqueName); config = null; } @@ -216,7 +216,7 @@ public static void UpdateProperties(Project project, ProjectItem projectItem, st } catch (Exception ex) { - ex.TraceUnknownException(); + LogManager.ForContext().Error(ex, "Failed to load settings for project {UniqueName}", project?.UniqueName); } } } @@ -239,7 +239,7 @@ private static void UpdateNameProperties(Project project, ProjectItem projectIte catch (SystemException ex) { // PathTooLongException, ArgumentException (invalid characters). - ex.TraceUnknownException(); + LogManager.ForContext().Error(ex, "Failed because path has been to long for {UniqueName}", project?.UniqueName); projectItem.FullPath = null; } @@ -248,7 +248,7 @@ private static void UpdateNameProperties(Project project, ProjectItem projectIte } catch (Exception ex) { - ex.TraceUnknownException(); + LogManager.ForContext().Error(ex, "Failed to update name properties for {UniqueName}", project?.UniqueName); } } @@ -274,10 +274,10 @@ public static object GetService(object serviceProviderObject, Type type) { object service = null; - Guid sidGuid = type.GUID; - Guid iidGuid = sidGuid; + var sidGuid = type.GUID; + var iidGuid = sidGuid; var serviceProvider = (IServiceProvider)serviceProviderObject; - int hr = serviceProvider.QueryService(ref sidGuid, ref iidGuid, out var serviceIntPtr); + var hr = serviceProvider.QueryService(ref sidGuid, ref iidGuid, out var serviceIntPtr); if (hr != 0) { diff --git a/src/BuildVision/Services/BuildInformationProvider.cs b/src/BuildVision/Services/BuildInformationProvider.cs index 95a621aa..76039c0e 100644 --- a/src/BuildVision/Services/BuildInformationProvider.cs +++ b/src/BuildVision/Services/BuildInformationProvider.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Threading; using BuildVision.Common; +using BuildVision.Common.Logging; using BuildVision.Contracts; using BuildVision.Contracts.Models; using BuildVision.Exports; @@ -14,7 +15,6 @@ using BuildVision.Helpers; using BuildVision.Services; using BuildVision.Tool.Building; -using BuildVision.UI.Common.Logging; using BuildVision.UI.Contracts; using BuildVision.UI.Models; using BuildVision.Views.Settings; @@ -36,13 +36,13 @@ public class BuildInformationProvider : IBuildInformationProvider private readonly ISolutionProvider _solutionProvider; private readonly IBuildService _buildService; private readonly ITaskBarInfoService _taskBarInfoService; - private string _origTextCurrentState; private const int BuildInProcessCountOfQuantumSleep = 5; private const int BuildInProcessQuantumSleep = 50; - private readonly object _buildProcessLockObject; private CancellationTokenSource _buildProcessCancellationToken; private int _currentQueuePosOfBuildingProject = 0; + private Serilog.ILogger _logger = LogManager.ForContext(); + public IBuildInformationModel BuildInformationModel { get; } = new BuildInformationModel(); public ObservableCollection Projects { get; } = new ObservableCollection(); @@ -132,7 +132,7 @@ private void BuildOutputLogger_OnErrorRaised(BuildProjectContextEntry projectEnt } catch (Exception ex) { - ex.TraceUnknownException(); + _logger.Error(ex, "Failed to fetch errormessage."); } } @@ -140,11 +140,15 @@ private bool TryGetProjectItem(BuildProjectContextEntry projectEntry, out IProje { projectItem = projectEntry.ProjectItem; if (projectItem != null) + { return true; + } string projectFile = projectEntry.FileName; if (ProjectExtensions.IsProjectHidden(projectFile)) + { return false; + } var projectProperties = projectEntry.Properties; var project = Projects.FirstOrDefault(x => x.FullName == projectFile); @@ -156,12 +160,7 @@ private bool TryGetProjectItem(BuildProjectContextEntry projectEntry, out IProje projectItem = Projects.First(item => $"{item.FullName}-{item.Configuration}|{item.Platform.Replace(" ", "")}" == $"{projectFile}-{projectConfiguration}|{projectPlatform}"); if (projectItem == null) { - TraceManager.Trace( - string.Format("Project Item not found by: UniqueName='{0}', Configuration='{1}, Platform='{2}'.", - project.UniqueName, - projectConfiguration, - projectPlatform), - EventLogEntryType.Warning); + _logger.Warning("Project Item not found by: UniqueName='{UniqueName}', Configuration='{ProjectConfiguration}, Platform='{ProjectPlatform}'.", project.UniqueName, projectConfiguration, projectPlatform); return false; } } @@ -191,7 +190,9 @@ private void AddErrorItem(IProjectItem projectItem, ErrorItem errorItem) throw new ArgumentOutOfRangeException("errorLevel"); } if (errorItem.Level != ErrorLevel.Error) + { return; + } int errorNumber = projectItem.Errors.Count + projectItem.Warnings.Count + projectItem.Messages.Count + 1; errorItem.Number = errorNumber; @@ -246,7 +247,7 @@ public void Run(CancellationToken cancellationToken) break; } - System.Threading.Thread.Sleep(BuildInProcessQuantumSleep); + Thread.Sleep(BuildInProcessQuantumSleep); } } } @@ -309,7 +310,7 @@ public void ProjectBuildStarted(IProjectItem projectItem, BuildActions buildActi } catch (Exception ex) { - ex.TraceUnknownException(); + _logger.Error(ex, "Failed during Project Build start."); } } @@ -429,10 +430,13 @@ public void BuildFinished(bool success, bool canceled) } } else if (canceled) + { BuildInformationModel.CurrentBuildState = BuildState.Cancelled; + } else + { BuildInformationModel.CurrentBuildState = BuildState.Failed; - + } var message = _buildMessagesFactory.GetBuildDoneMessage(BuildInformationModel); _statusBarNotificationService.ShowText(message); @@ -463,7 +467,10 @@ public void BuildFinished(bool success, bool canceled) foreach (var error in project.Errors) { if (ErrorNavigationService.BuildErrorNavigated) + { break; + } + _errorNavigationService.NavigateToErrorItem(error); } } diff --git a/src/BuildVision/Services/BuildOutputLogger.cs b/src/BuildVision/Services/BuildOutputLogger.cs index 72e4f2e9..9856f508 100644 --- a/src/BuildVision/Services/BuildOutputLogger.cs +++ b/src/BuildVision/Services/BuildOutputLogger.cs @@ -3,10 +3,10 @@ using System.Diagnostics; using System.Linq; using System.Reflection; +using BuildVision.Common.Logging; using BuildVision.Contracts; using BuildVision.Exports; using BuildVision.Helpers; -using BuildVision.UI.Common.Logging; using BuildVision.UI.Contracts; using BuildVision.UI.Models; using Microsoft.Build.Framework; @@ -17,7 +17,7 @@ namespace BuildVision.Tool.Building public class BuildOutputLogger : Logger, IBuildOutputLogger { private readonly Guid _loggerId; - + private Serilog.ILogger _logger = LogManager.ForContext(); public RegisterLoggerResult LoggerState { get; set; } private List _projects = new List(); @@ -67,7 +67,7 @@ public void Attach() } catch (TargetInvocationException ex) { - ex.Trace("Microsoft.Build.BackEnd.ILoggingService is not available."); + _logger.Error(ex, "Microsoft.Build.BackEnd.ILoggingService is not available."); LoggerState = RegisterLoggerResult.FatalError; return; } @@ -88,7 +88,7 @@ public void Attach() } catch (Exception ex) { - ex.TraceUnknownException(); + _logger.Error(ex, "Error registering MSBuild Logger"); LoggerState = RegisterLoggerResult.FatalError; } } @@ -112,7 +112,7 @@ private void EventSource_ErrorRaised(object sender, BuildEventArgs e, ErrorLevel var projectEntry = _projects.Find(t => t.InstanceId == projectInstanceId && t.ContextId == projectContextId); if (projectEntry == null) { - TraceManager.Trace(string.Format("Project entry not found by ProjectInstanceId='{0}' and ProjectContextId='{1}'.", projectInstanceId, projectContextId), EventLogEntryType.Warning); + _logger.Warning("Project entry not found by ProjectInstanceId='{ProjectInstanceId}' and ProjectContextId='{ProjectContextId}'.", projectInstanceId, projectContextId); return; } if (projectEntry.IsInvalid) @@ -122,7 +122,7 @@ private void EventSource_ErrorRaised(object sender, BuildEventArgs e, ErrorLevel } catch (Exception ex) { - ex.TraceUnknownException(); + _logger.Error(ex, "Error during eventsource_raised."); } } diff --git a/src/BuildVision/Services/BuildService.cs b/src/BuildVision/Services/BuildService.cs index dcd05221..b47c6efd 100644 --- a/src/BuildVision/Services/BuildService.cs +++ b/src/BuildVision/Services/BuildService.cs @@ -1,21 +1,24 @@ using System; -using System.Collections.Generic; using System.Collections.Specialized; using System.ComponentModel; using System.ComponentModel.Composition; +using System.IO; +using System.Linq; using System.Windows; using BuildVision.Common; +using BuildVision.Common.Logging; using BuildVision.Contracts; using BuildVision.Contracts.Exceptions; using BuildVision.Contracts.Models; using BuildVision.Exports.Services; using BuildVision.Helpers; using BuildVision.UI; -using BuildVision.UI.Common.Logging; using BuildVision.UI.Models; +using BuildVision.Views.Settings; using EnvDTE; using Microsoft.VisualStudio; using Microsoft.VisualStudio.Shell; +using Serilog; namespace BuildVision.Tool.Building { @@ -23,16 +26,20 @@ namespace BuildVision.Tool.Building [PartCreationPolicy(CreationPolicy.NonShared)] public class BuildService : IBuildService { + private ILogger _logger = LogManager.ForContext(); private const string CancelBuildCommand = "Build.Cancel"; private bool _buildCancelledInternally; private readonly bool _buildCancelled; private readonly IServiceProvider _serviceProvider; + private readonly IPackageSettingsProvider _packageSettingsProvider; [ImportingConstructor] public BuildService( - [Import(typeof(SVsServiceProvider))] IServiceProvider serviceProvider) + [Import(typeof(SVsServiceProvider))] IServiceProvider serviceProvider, + [Import(typeof(IPackageSettingsProvider))] IPackageSettingsProvider packageSettingsProvider) { _serviceProvider = serviceProvider; + _packageSettingsProvider = packageSettingsProvider; } public void CancelBuildSolution() @@ -74,7 +81,7 @@ public async System.Threading.Tasks.Task CancelBuildAsync(IBuildInformationModel } catch (Exception ex) { - ex.Trace("Cancel build failed."); + _logger.Error(ex, "Cancel build failed."); } } @@ -87,7 +94,7 @@ public void RaiseCommandForSelectedProject(IProjectItem selectedProjectItem, int } catch (Exception ex) { - ex.TraceUnknownException(); + _logger.Error(ex, "Raising command {CommandId} for project {UniqueName} failed.", selectedProjectItem.UniqueName, commandId); } } @@ -106,54 +113,53 @@ public void ProjectCopyBuildOutputFilesToClipBoard(IProjectItem projItem) { try { - //Project project = Services.Dte.Solution.GetProject(x => x.UniqueName == projItem.UniqueName); - //BuildOutputFileTypes fileTypes = null; //_packageContext.ControlSettings.ProjectItemSettings.CopyBuildOutputFileTypesToClipboard; - //if (fileTypes.IsEmpty) - //{ - // MessageBox.Show(@"Nothing to copy: all file types unchecked.", Resources.ProductName, MessageBoxButton.OK, MessageBoxImage.Error); - // return; - //} - - //string[] filePaths = project.GetBuildOutputFilePaths(fileTypes, projItem.Configuration, projItem.Platform).ToArray(); - //if (filePaths.Length == 0) - //{ - // MessageBox.Show(@"Nothing copied: selected build output groups are empty.", Resources.ProductName, MessageBoxButton.OK, MessageBoxImage.Information); - // return; - //} - - //string[] existFilePaths = filePaths.Where(File.Exists).ToArray(); - //if (existFilePaths.Length == 0) - //{ - // string msg = GetCopyBuildOutputFilesToClipboardActionMessage("Nothing copied. {0} wasn't found{1}", filePaths); - // MessageBox.Show(msg, Resources.ProductName, MessageBoxButton.OK, MessageBoxImage.Warning); - // return; - //} - - //CopyFiles(existFilePaths); - - //if (existFilePaths.Length == filePaths.Length) - //{ - // string msg = GetCopyBuildOutputFilesToClipboardActionMessage("Copied {0}{1}", existFilePaths); - // MessageBox.Show(msg, Resources.ProductName, MessageBoxButton.OK, MessageBoxImage.Information); - //} - //else - //{ - // string[] notExistFilePaths = filePaths.Except(existFilePaths).ToArray(); - // string copiedMsg = GetCopyBuildOutputFilesToClipboardActionMessage("Copied {0}{1}", existFilePaths); - // string notFoundMsg = GetCopyBuildOutputFilesToClipboardActionMessage("{0} wasn't found{1}", notExistFilePaths); - // string msg = string.Concat(copiedMsg, Environment.NewLine, Environment.NewLine, notFoundMsg); - // MessageBox.Show(msg, Resources.ProductName, MessageBoxButton.OK, MessageBoxImage.Warning); - //} + var project = Core.Services.Dte.Solution.GetProject(x => x.UniqueName == projItem.UniqueName); + var fileTypes = _packageSettingsProvider.Settings.ProjectItemSettings.CopyBuildOutputFileTypesToClipboard; + if (fileTypes.IsEmpty) + { + MessageBox.Show(@"Nothing to copy: all file types unchecked.", Resources.ProductName, MessageBoxButton.OK, MessageBoxImage.Error); + return; + } + + string[] filePaths = project.GetBuildOutputFilePaths(fileTypes, projItem.Configuration, projItem.Platform).ToArray(); + if (filePaths.Length == 0) + { + MessageBox.Show(@"Nothing copied: selected build output groups are empty.", Resources.ProductName, MessageBoxButton.OK, MessageBoxImage.Information); + return; + } + + string[] existFilePaths = filePaths.Where(File.Exists).ToArray(); + if (existFilePaths.Length == 0) + { + string msg = GetCopyBuildOutputFilesToClipboardActionMessage("Nothing copied. {0} wasn't found{1}", filePaths); + MessageBox.Show(msg, Resources.ProductName, MessageBoxButton.OK, MessageBoxImage.Warning); + return; + } + + CopyFiles(existFilePaths); + + if (existFilePaths.Length == filePaths.Length) + { + string msg = GetCopyBuildOutputFilesToClipboardActionMessage("Copied {0}{1}", existFilePaths); + MessageBox.Show(msg, Resources.ProductName, MessageBoxButton.OK, MessageBoxImage.Information); + } + else + { + string[] notExistFilePaths = filePaths.Except(existFilePaths).ToArray(); + string copiedMsg = GetCopyBuildOutputFilesToClipboardActionMessage("Copied {0}{1}", existFilePaths); + string notFoundMsg = GetCopyBuildOutputFilesToClipboardActionMessage("{0} wasn't found{1}", notExistFilePaths); + string msg = string.Concat(copiedMsg, Environment.NewLine, Environment.NewLine, notFoundMsg); + MessageBox.Show(msg, Resources.ProductName, MessageBoxButton.OK, MessageBoxImage.Warning); + } } catch (Win32Exception ex) { - string msg = string.Format("Error copying files to the Clipboard: 0x{0:X} ({1})", ex.ErrorCode, ex.Message); - ex.Trace(msg); - MessageBox.Show(msg, Resources.ProductName, MessageBoxButton.OK, MessageBoxImage.Error); + _logger.Error(ex, "Error copying files to the Clipboard 0x{ErrorCode} ({Message})", ex.ErrorCode, ex.Message); + MessageBox.Show($"Error copying files to the Clipboard 0x{ex.ErrorCode} ({ex.Message})", Resources.ProductName, MessageBoxButton.OK, MessageBoxImage.Error); } catch (Exception ex) { - ex.TraceUnknownException(); + _logger.Error(ex, "Copy buildoutput for project {UniqueName} failed.", projItem.UniqueName); MessageBox.Show(ex.Message, Resources.ProductName, MessageBoxButton.OK, MessageBoxImage.Error); } } @@ -175,7 +181,7 @@ private string GetCopyBuildOutputFilesToClipboardActionMessage(string template, string filesListArg; if (filePaths.Length < MaxFilePathLinesInMessage) { - IEnumerable shortenedFilePaths = FilePathHelper.ShortenPaths(filePaths, MaxFilePathLengthInMessage); + var shortenedFilePaths = FilePathHelper.ShortenPaths(filePaths, MaxFilePathLengthInMessage); filesListArg = string.Concat(":", Environment.NewLine, string.Join(Environment.NewLine, shortenedFilePaths)); } else @@ -198,39 +204,8 @@ private void RaiseCommand(VSConstants.VSStd97CmdID command) } catch (Exception ex) { - ex.TraceUnknownException(); + _logger.Error(ex, "Raising command {Command} failed.", command); } } - - public void ProjectCopyBuildOutputFilesToClipBoard() - { - throw new NotImplementedException(); - } - - private void NavigateToBuildErrorIfNeeded(UI.Settings.Models.ControlSettings settings) - { - // How to get errors that happend during build? - //bool navigateToBuildFailureReason = (!BuildedProjects.BuildWithoutErrors - // && settings.GeneralSettings.NavigateToBuildFailureReason == NavigateToBuildFailureReasonCondition.OnBuildDone); - //if (navigateToBuildFailureReason && BuildedProjects.Any(p => p.ErrorsBox.Errors.Any(NavigateToErrorItem))) - //{ - // _buildErrorIsNavigated = true; - //} - } - - private async void OnErrorRaised(object sender, BuildErrorRaisedEventArgs args) - { - //bool buildNeedToCancel = (args.ErrorLevel == ErrorLevel.Error && _viewModel.ControlSettings.GeneralSettings.StopBuildAfterFirstError); - //if (buildNeedToCancel) - // await CancelBuildAsync(); - - //bool navigateToBuildFailureReason = (!_buildErrorIsNavigated - // && args.ErrorLevel == ErrorLevel.Error - // && _viewModel.ControlSettings.GeneralSettings.NavigateToBuildFailureReason == NavigateToBuildFailureReasonCondition.OnErrorRaised); - //if (navigateToBuildFailureReason && args.ProjectInfo.ErrorsBox.Errors.Any(NavigateToErrorItem)) - //{ - // _buildErrorIsNavigated = true; - //} - } } } diff --git a/src/BuildVision/Services/ErrorNavigationService.cs b/src/BuildVision/Services/ErrorNavigationService.cs index 00573c3f..6aaa9fc0 100644 --- a/src/BuildVision/Services/ErrorNavigationService.cs +++ b/src/BuildVision/Services/ErrorNavigationService.cs @@ -2,18 +2,20 @@ using System.Collections.Generic; using System.ComponentModel.Composition; using System.IO; +using BuildVision.Common.Logging; using BuildVision.Contracts; using BuildVision.Exports.Services; using BuildVision.Helpers; -using BuildVision.UI.Common.Logging; using EnvDTE; using Microsoft.VisualStudio.Shell; +using Serilog; namespace BuildVision.Services { public class ErrorNavigationService : IErrorNavigationService { private readonly IServiceProvider _serviceProvider; + private ILogger _logger = LogManager.ForContext(); public static bool BuildErrorNavigated { get; set; } @@ -76,13 +78,12 @@ public void NavigateToErrorItem(ErrorItem errorItem) } catch (Exception ex) { - var msg = string.Format("Navigate to error item exception (fullPath='{0}').", fullPath); - ex.Trace(msg); + _logger.Error(ex, "Navigate to error item exception (fullPath='{FullPath}').", fullPath); } } catch (Exception ex) { - ex.Trace("Navigate to error item exception."); + _logger.Error(ex, "Navigate to error item exception."); } BuildErrorNavigated = true; diff --git a/src/BuildVision/Services/PackageSettingsProvider.cs b/src/BuildVision/Services/PackageSettingsProvider.cs index 947601c4..3b5c1fd0 100644 --- a/src/BuildVision/Services/PackageSettingsProvider.cs +++ b/src/BuildVision/Services/PackageSettingsProvider.cs @@ -2,7 +2,7 @@ using System.Diagnostics; using System.Windows; using BuildVision.Common; -using BuildVision.UI.Common.Logging; +using BuildVision.Common.Logging; using BuildVision.UI.Settings.Models; using Microsoft.VisualStudio.Settings; using Microsoft.VisualStudio.Shell.Settings; @@ -11,6 +11,7 @@ namespace BuildVision.Views.Settings { public class PackageSettingsProvider : BindableBase, IPackageSettingsProvider { + private Serilog.ILogger _logger = LogManager.ForContext(); public const string settingsCategoryName = "BuildVision"; public const string settingsPropertyName = "Settings"; @@ -59,7 +60,7 @@ private void LoadSettings() } catch (Exception ex) { - ex.Trace("Error when trying to load settings: " + ex.Message, EventLogEntryType.Error); + _logger.Error(ex, "Error when trying to load settings."); MessageBox.Show("An error occurred when trying to load current settings. To make sure everything is still working the settings are set to default."); } } diff --git a/src/BuildVision/Services/SolutionProvider.cs b/src/BuildVision/Services/SolutionProvider.cs index 0cc0d470..7dee7e07 100644 --- a/src/BuildVision/Services/SolutionProvider.cs +++ b/src/BuildVision/Services/SolutionProvider.cs @@ -2,16 +2,17 @@ using System.Collections.Generic; using System.ComponentModel.Composition; using System.IO; +using BuildVision.Common.Logging; using BuildVision.Contracts.Models; using BuildVision.Exports.Providers; using BuildVision.Exports.Services; using BuildVision.Helpers; using BuildVision.UI; -using BuildVision.UI.Common.Logging; using BuildVision.UI.Models; using EnvDTE; using EnvDTE80; using Microsoft.VisualStudio.Shell; +using Serilog; namespace BuildVision.Core { @@ -19,6 +20,7 @@ namespace BuildVision.Core [PartCreationPolicy(CreationPolicy.Shared)] public class SolutionProvider : ISolutionProvider { + private ILogger _logger = LogManager.ForContext(); private readonly IServiceProvider _serviceProvider; private Solution _solution; @@ -83,7 +85,7 @@ private void RefrehSolutionModel() } catch (Exception ex) { - ex.TraceUnknownException(); + _logger.Error(ex, "Failed to refresh solutionmodel."); _solutionModel.Name = Resources.GridCellNATextInBrackets; _solutionModel.FullName = Resources.GridCellNATextInBrackets; _solutionModel.IsEmpty = true; diff --git a/test/BuildVision.UnitTests/BuildVision.UnitTests.csproj b/test/BuildVision.UnitTests/BuildVision.UnitTests.csproj index 56f2fbd9..a532cbc4 100644 --- a/test/BuildVision.UnitTests/BuildVision.UnitTests.csproj +++ b/test/BuildVision.UnitTests/BuildVision.UnitTests.csproj @@ -3,7 +3,7 @@ net472 - + From 58a8042ac8eb34d8439b75ab64de0027aa7c11c4 Mon Sep 17 00:00:00 2001 From: Stefan Kert Date: Fri, 12 Apr 2019 19:46:59 +0200 Subject: [PATCH 065/100] Further cleanup --- .../Models/IProjectItem.cs | 1 + src/BuildVision.UI/Models/ProjectItem.cs | 42 ++++++++++ src/BuildVision/BuildVision.csproj | 1 + src/BuildVision/Core/BuildVisionPackage.cs | 1 + src/BuildVision/Core/Services.cs | 11 +++ .../Extensions/BuildActionsExtensions.cs | 27 +++++++ src/BuildVision/Helpers/ProjectExtensions.cs | 6 +- .../Helpers/ProjectItemExtensions.cs | 16 +++- .../Helpers/PropertiesExtensions.cs | 1 - .../Helpers/SolutionProjectsExtensions.cs | 29 +------ .../Helpers/StateConverterHelper.cs | 1 - .../Helpers/UIHierarchyExtensions.cs | 17 +---- .../Services/BuildInformationProvider.cs | 76 ++----------------- 13 files changed, 111 insertions(+), 118 deletions(-) create mode 100644 src/BuildVision/Extensions/BuildActionsExtensions.cs diff --git a/src/BuildVision.Contracts/Models/IProjectItem.cs b/src/BuildVision.Contracts/Models/IProjectItem.cs index 75c9a5f5..369474e4 100644 --- a/src/BuildVision.Contracts/Models/IProjectItem.cs +++ b/src/BuildVision.Contracts/Models/IProjectItem.cs @@ -38,5 +38,6 @@ public interface IProjectItem ObservableCollection Messages { get; set; } void RaiseBuildElapsedTimeChanged(); + void AddErrorItem(ErrorItem errorItem); } } diff --git a/src/BuildVision.UI/Models/ProjectItem.cs b/src/BuildVision.UI/Models/ProjectItem.cs index 7471c8c5..15f8f31b 100644 --- a/src/BuildVision.UI/Models/ProjectItem.cs +++ b/src/BuildVision.UI/Models/ProjectItem.cs @@ -262,5 +262,47 @@ public void RaiseBuildElapsedTimeChanged() { OnPropertyChanged(nameof(BuildElapsedTime)); } + + public void AddErrorItem(ErrorItem errorItem) + { + switch (errorItem.Level) + { + case ErrorLevel.Message: + MessagesCount++; + break; + case ErrorLevel.Warning: + WarningsCount++; + break; + case ErrorLevel.Error: + ErrorsCount++; + break; + default: + throw new ArgumentOutOfRangeException(nameof(errorItem)); + } + if (errorItem.Level != ErrorLevel.Error) + { + return; + } + + int errorNumber = Errors.Count + Warnings.Count + Messages.Count + 1; + errorItem.Number = errorNumber; + switch (errorItem.Level) + { + case ErrorLevel.Message: + Messages.Add(errorItem); + break; + + case ErrorLevel.Warning: + Warnings.Add(errorItem); + break; + + case ErrorLevel.Error: + Errors.Add(errorItem); + break; + + default: + throw new ArgumentOutOfRangeException(nameof(errorItem)); + } + } } } diff --git a/src/BuildVision/BuildVision.csproj b/src/BuildVision/BuildVision.csproj index 63bd4dcd..5581f363 100644 --- a/src/BuildVision/BuildVision.csproj +++ b/src/BuildVision/BuildVision.csproj @@ -83,6 +83,7 @@ + diff --git a/src/BuildVision/Core/BuildVisionPackage.cs b/src/BuildVision/Core/BuildVisionPackage.cs index 74321e85..b8653396 100644 --- a/src/BuildVision/Core/BuildVisionPackage.cs +++ b/src/BuildVision/Core/BuildVisionPackage.cs @@ -73,6 +73,7 @@ public BuildVisionPackage() private void Current_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e) { _logger.Fatal(e.Exception, "Unhandled Exception"); + DiagnosticsClient.Notify(e.Exception); } protected override async Task InitializeAsync(CancellationToken cancellationToken, IProgress progress) diff --git a/src/BuildVision/Core/Services.cs b/src/BuildVision/Core/Services.cs index b1495633..37efa8b8 100644 --- a/src/BuildVision/Core/Services.cs +++ b/src/BuildVision/Core/Services.cs @@ -4,6 +4,7 @@ using EnvDTE80; using Microsoft.VisualStudio.ComponentModelHost; using Microsoft.VisualStudio.Shell; +using Microsoft.VisualStudio.Shell.Interop; namespace BuildVision.Core { @@ -29,5 +30,15 @@ static Ret GetGlobalService(IServiceProvider provider = null) where T : public static DTE Dte => GetGlobalService(); public static DTE2 Dte2 => Dte as DTE2; + + public static IVsSolution GetSolution(this IServiceProvider provider) + { + return GetGlobalService(provider); + } + + public static IVsSolution GetSolution() + { + return GetGlobalService(); + } } } diff --git a/src/BuildVision/Extensions/BuildActionsExtensions.cs b/src/BuildVision/Extensions/BuildActionsExtensions.cs new file mode 100644 index 00000000..f5346f22 --- /dev/null +++ b/src/BuildVision/Extensions/BuildActionsExtensions.cs @@ -0,0 +1,27 @@ +using System; +using BuildVision.Contracts; + +namespace BuildVision.Extensions +{ + public static class BuildActionsExtensions + { + public static ProjectState GetProjectState(this BuildActions buildAction) + { + switch (buildAction) + { + case BuildActions.BuildActionBuild: + case BuildActions.BuildActionRebuildAll: + return ProjectState.Building; + + case BuildActions.BuildActionClean: + return ProjectState.Cleaning; + + case BuildActions.BuildActionDeploy: + throw new InvalidOperationException("vsBuildActionDeploy not supported"); + + default: + throw new ArgumentOutOfRangeException(nameof(buildAction)); + } + } + } +} diff --git a/src/BuildVision/Helpers/ProjectExtensions.cs b/src/BuildVision/Helpers/ProjectExtensions.cs index 22e3c866..c70f1374 100644 --- a/src/BuildVision/Helpers/ProjectExtensions.cs +++ b/src/BuildVision/Helpers/ProjectExtensions.cs @@ -245,10 +245,8 @@ public static string GetFrameworkString(this Project project) public static string GetProjectTypeGuids(this Project proj) { string projectTypeGuids = string.Empty; - - var service = SolutionProjectsExtensions.GetService(proj.DTE, typeof(IVsSolution)); - var solution = (IVsSolution)service; - + var solution = Core.Services.GetSolution(); + int result = solution.GetProjectOfUniqueName(proj.UniqueName, out var hierarchy); if (!string.IsNullOrEmpty(proj.Kind)) diff --git a/src/BuildVision/Helpers/ProjectItemExtensions.cs b/src/BuildVision/Helpers/ProjectItemExtensions.cs index 10156649..74edcee1 100644 --- a/src/BuildVision/Helpers/ProjectItemExtensions.cs +++ b/src/BuildVision/Helpers/ProjectItemExtensions.cs @@ -9,10 +9,14 @@ public static class ProjectItemExtensions public static bool ProjectItemIsDirty(this ProjectItem projectItem) { if (projectItem.IsDirty) + { return true; + } if (projectItem.ProjectItems != null && projectItem.ProjectItems.Cast().Any(ProjectItemIsDirty)) + { return true; + } return false; } @@ -26,10 +30,12 @@ public static bool ProjectItemIsDirty(this ProjectItem projectItem) public static ProjectItem FindProjectItem(this ProjectItems items, string filePath) { if (string.IsNullOrEmpty(filePath)) + { throw new ArgumentException("Argument `filePath` is null or empty.", "filePath"); + } int backslashIndex = filePath.IndexOf("\\", StringComparison.Ordinal); - bool findFolder = (backslashIndex != -1); + bool findFolder = backslashIndex != -1; if (findFolder) { string folderName = filePath.Substring(0, backslashIndex); @@ -37,7 +43,9 @@ public static ProjectItem FindProjectItem(this ProjectItems items, string filePa { if (item.Kind != Constants.vsProjectItemKindVirtualFolder && item.Kind != Constants.vsProjectItemKindPhysicalFolder) + { continue; + } if (folderName == item.Name) { @@ -52,17 +60,23 @@ public static ProjectItem FindProjectItem(this ProjectItems items, string filePa foreach (ProjectItem item in items) { if (item.Kind != Constants.vsProjectItemKindPhysicalFile) + { continue; + } if (item.Name == fileName) + { return item; + } // Nested item, e.g. Default.aspx or MainWindow.xaml. if (item.ProjectItems.Count > 0) { var childItem = FindProjectItem(item.ProjectItems, fileName); if (childItem != null) + { return childItem; + } } } } diff --git a/src/BuildVision/Helpers/PropertiesExtensions.cs b/src/BuildVision/Helpers/PropertiesExtensions.cs index 511c0fae..1f16c172 100644 --- a/src/BuildVision/Helpers/PropertiesExtensions.cs +++ b/src/BuildVision/Helpers/PropertiesExtensions.cs @@ -6,7 +6,6 @@ namespace BuildVision.Helpers { public static class PropertiesExtensions { - public static Property GetPropertyOrDefault(this Properties properties, string propertyName) { try diff --git a/src/BuildVision/Helpers/SolutionProjectsExtensions.cs b/src/BuildVision/Helpers/SolutionProjectsExtensions.cs index 9f31f50a..409e46e0 100644 --- a/src/BuildVision/Helpers/SolutionProjectsExtensions.cs +++ b/src/BuildVision/Helpers/SolutionProjectsExtensions.cs @@ -2,12 +2,10 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using System.Runtime.InteropServices; using BuildVision.Common.Logging; using BuildVision.Core; using BuildVision.UI; using EnvDTE; -using IServiceProvider = Microsoft.VisualStudio.OLE.Interop.IServiceProvider; using ProjectItem = BuildVision.UI.Models.ProjectItem; namespace BuildVision.Helpers @@ -256,10 +254,7 @@ private static void UpdateNameProperties(Project project, ProjectItem projectIte private static bool IsIntegrationServicesProject(Project project, ProjectItem projectItem) { - if (project.Kind == _GUID_SQL_INTEGRATIONG_SERVICES_PROJECT_KIND) - return projectItem.UniqueName == projectItem.FullName; - else - return false; + return project.Kind == _GUID_SQL_INTEGRATIONG_SERVICES_PROJECT_KIND ? projectItem.UniqueName == projectItem.FullName : false; } private static void AdjustUniqueNameForExtensionProjects(Project project, ProjectItem projectItem) @@ -269,27 +264,5 @@ private static void AdjustUniqueNameForExtensionProjects(Project project, Projec var csprojName = Path.GetFileName(project.UniqueName); projectItem.UniqueName = Path.Combine(directoryName, csprojName); } - - public static object GetService(object serviceProviderObject, Type type) - { - object service = null; - - var sidGuid = type.GUID; - var iidGuid = sidGuid; - var serviceProvider = (IServiceProvider)serviceProviderObject; - var hr = serviceProvider.QueryService(ref sidGuid, ref iidGuid, out var serviceIntPtr); - - if (hr != 0) - { - Marshal.ThrowExceptionForHR(hr); - } - else if (!serviceIntPtr.Equals(IntPtr.Zero)) - { - service = Marshal.GetObjectForIUnknown(serviceIntPtr); - Marshal.Release(serviceIntPtr); - } - - return service; - } } } diff --git a/src/BuildVision/Helpers/StateConverterHelper.cs b/src/BuildVision/Helpers/StateConverterHelper.cs index d561f403..6a942a9c 100644 --- a/src/BuildVision/Helpers/StateConverterHelper.cs +++ b/src/BuildVision/Helpers/StateConverterHelper.cs @@ -24,6 +24,5 @@ public static BuildActions ConvertSolutionBuildFlagsToBuildAction(uint dwAction, return BuildActions.Unknown; } } - } } diff --git a/src/BuildVision/Helpers/UIHierarchyExtensions.cs b/src/BuildVision/Helpers/UIHierarchyExtensions.cs index b11977ca..e6c1ecd9 100644 --- a/src/BuildVision/Helpers/UIHierarchyExtensions.cs +++ b/src/BuildVision/Helpers/UIHierarchyExtensions.cs @@ -4,19 +4,8 @@ namespace BuildVision.Helpers { - /// - /// Extends functionality for UIHierarchy classes, e.g: - /// VisualStudioServices.Dte.ToolWindows.SolutionExplorer - /// public static class UIHierarchyExtensions { - /// - /// Finds the hierarchy item for the given item. - /// - /// The hierarchy object - /// The item. - /// The found UIHierarchyItem, null if none found. For example, in case of the Solution explorer, it would be the item in the solution - /// explorer that represents the given project public static UIHierarchyItem FindHierarchyItem(this UIHierarchy hierarchy, Project item) { return FindHierarchyItem(hierarchy, (object)item); @@ -25,15 +14,17 @@ public static UIHierarchyItem FindHierarchyItem(this UIHierarchy hierarchy, Proj private static UIHierarchyItem FindHierarchyItem(UIHierarchy hierarchy, object item) { // This gets children of the root note in the hierarchy - UIHierarchyItems items = hierarchy.UIHierarchyItems.Item(1).UIHierarchyItems; + var items = hierarchy.UIHierarchyItems.Item(1).UIHierarchyItems; // Finds the given item in the hierarchy - UIHierarchyItem uiItem = FindHierarchyItem(items, item); + var uiItem = FindHierarchyItem(items, item); // uiItem would be null in most cases, however, for projects inside Solution Folders, there is a strange behavior in which the project byitself can't // be found in the hierarchy. Instead, in case of failure we'll search for the UIHierarchyItem if (uiItem == null && item is Project && ((Project)item).ParentProjectItem != null) + { uiItem = FindHierarchyItem(items, ((Project)item).ParentProjectItem); + } return uiItem; } diff --git a/src/BuildVision/Services/BuildInformationProvider.cs b/src/BuildVision/Services/BuildInformationProvider.cs index 76039c0e..8877e6d7 100644 --- a/src/BuildVision/Services/BuildInformationProvider.cs +++ b/src/BuildVision/Services/BuildInformationProvider.cs @@ -12,6 +12,7 @@ using BuildVision.Exports.Factories; using BuildVision.Exports.Providers; using BuildVision.Exports.Services; +using BuildVision.Extensions; using BuildVision.Helpers; using BuildVision.Services; using BuildVision.Tool.Building; @@ -27,6 +28,8 @@ namespace BuildVision.Core [PartCreationPolicy(CreationPolicy.Shared)] public class BuildInformationProvider : IBuildInformationProvider { + private readonly Serilog.ILogger _logger = LogManager.ForContext(); + private readonly IPackageSettingsProvider _packageSettingsProvider; private readonly IErrorNavigationService _errorNavigationService; private readonly IBuildOutputLogger _buildOutputLogger; @@ -41,8 +44,6 @@ public class BuildInformationProvider : IBuildInformationProvider private const int BuildInProcessQuantumSleep = 50; private CancellationTokenSource _buildProcessCancellationToken; private int _currentQueuePosOfBuildingProject = 0; - private Serilog.ILogger _logger = LogManager.ForContext(); - public IBuildInformationModel BuildInformationModel { get; } = new BuildInformationModel(); public ObservableCollection Projects { get; } = new ObservableCollection(); @@ -115,7 +116,7 @@ private void BuildOutputLogger_OnErrorRaised(BuildProjectContextEntry projectEnt } errorItem.VerifyValues(); - AddErrorItem(projectItem, errorItem); + projectItem.AddErrorItem(errorItem); var args = new BuildErrorRaisedEventArgs(errorLevel, projectItem); bool buildNeedCancel = (args.ErrorLevel == ErrorLevel.Error && _packageSettingsProvider.Settings.GeneralSettings.StopBuildAfterFirstError); @@ -173,67 +174,6 @@ private bool TryGetProjectItem(BuildProjectContextEntry projectEntry, out IProje return true; } - private void AddErrorItem(IProjectItem projectItem, ErrorItem errorItem) - { - switch (errorItem.Level) - { - case ErrorLevel.Message: - projectItem.MessagesCount++; - break; - case ErrorLevel.Warning: - projectItem.WarningsCount++; - break; - case ErrorLevel.Error: - projectItem.ErrorsCount++; - break; - default: - throw new ArgumentOutOfRangeException("errorLevel"); - } - if (errorItem.Level != ErrorLevel.Error) - { - return; - } - - int errorNumber = projectItem.Errors.Count + projectItem.Warnings.Count + projectItem.Messages.Count + 1; - errorItem.Number = errorNumber; - switch (errorItem.Level) - { - case ErrorLevel.Message: - projectItem.Messages.Add(errorItem); - break; - - case ErrorLevel.Warning: - projectItem.Warnings.Add(errorItem); - break; - - case ErrorLevel.Error: - projectItem.Errors.Add(errorItem); - break; - - default: - throw new ArgumentOutOfRangeException("errorLevel"); - } - } - - private ProjectState GetProjectState(BuildActions buildAction) - { - switch (buildAction) - { - case BuildActions.BuildActionBuild: - case BuildActions.BuildActionRebuildAll: - return ProjectState.Building; - - case BuildActions.BuildActionClean: - return ProjectState.Cleaning; - - case BuildActions.BuildActionDeploy: - throw new InvalidOperationException("vsBuildActionDeploy not supported"); - - default: - throw new ArgumentOutOfRangeException(nameof(buildAction)); - } - } - public void Run(CancellationToken cancellationToken) { while (!cancellationToken.IsCancellationRequested) @@ -293,7 +233,7 @@ public void ProjectBuildStarted(IProjectItem projectItem, BuildActions buildActi Projects.Add(projectItem); projInCollection = projectItem; } - projInCollection.State = GetProjectState(BuildInformationModel.BuildAction); + projInCollection.State = BuildInformationModel.BuildAction.GetProjectState(); projInCollection.BuildFinishTime = null; projInCollection.BuildStartTime = DateTime.Now; @@ -429,13 +369,9 @@ public void BuildFinished(bool success, bool canceled) BuildInformationModel.CurrentBuildState = BuildState.Done; } } - else if (canceled) - { - BuildInformationModel.CurrentBuildState = BuildState.Cancelled; - } else { - BuildInformationModel.CurrentBuildState = BuildState.Failed; + BuildInformationModel.CurrentBuildState = canceled ? BuildState.Cancelled : BuildState.Failed; } var message = _buildMessagesFactory.GetBuildDoneMessage(BuildInformationModel); From 82e540ecc2d496797d1327849b1736b01a9d1283 Mon Sep 17 00:00:00 2001 From: Stefan Kert Date: Sat, 13 Apr 2019 13:12:40 +0200 Subject: [PATCH 066/100] Fixed grouping Filling projects at startup --- .../Components/ControlView.xaml | 252 +++++++++--------- .../Components/ControlView.xaml.cs | 15 +- .../Components/ProjectGrid.xaml | 98 +++---- .../Components/ProjectGrid.xaml.cs | 54 ++-- .../Converters/ExpanderIsExpandedConverter.cs | 4 +- src/BuildVision.UI/Models/ProjectItem.cs | 10 +- .../Settings/Models/GridSettings.cs | 13 +- .../ViewModels/BuildVisionPaneViewModel.cs | 13 +- src/BuildVision/BuildVision.csproj | 1 + .../Extensions/BuildStateExtensions.cs | 35 +++ .../Services/BuildInformationProvider.cs | 58 ++-- src/BuildVision/Services/BuildOutputLogger.cs | 33 +-- .../Services/TaskBarInfoService.cs | 18 +- 13 files changed, 303 insertions(+), 301 deletions(-) create mode 100644 src/BuildVision/Extensions/BuildStateExtensions.cs diff --git a/src/BuildVision.UI/Components/ControlView.xaml b/src/BuildVision.UI/Components/ControlView.xaml index 3faf5418..f15b1e38 100644 --- a/src/BuildVision.UI/Components/ControlView.xaml +++ b/src/BuildVision.UI/Components/ControlView.xaml @@ -19,130 +19,130 @@ UseLayoutRounding="True" d:DesignHeight="148" d:DesignWidth="697" - d:DataContext="{d:DesignInstance viewModels:BuildVisionPaneViewModel}"> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + d:DataContext="{d:DesignInstance viewModels:BuildVisionPaneViewModel, IsDesignTimeCreatable=True}"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/BuildVision.UI/Components/ControlView.xaml.cs b/src/BuildVision.UI/Components/ControlView.xaml.cs index 42e9aea6..4d0338ea 100644 --- a/src/BuildVision.UI/Components/ControlView.xaml.cs +++ b/src/BuildVision.UI/Components/ControlView.xaml.cs @@ -1,6 +1,8 @@ -using System.Globalization; +using System.ComponentModel; +using System.Globalization; using System.Windows.Controls; using System.Windows.Markup; +using BuildVision.UI.ViewModels; namespace BuildVision.UI { @@ -9,12 +11,23 @@ namespace BuildVision.UI /// public partial class ControlView : UserControl { + public BuildVisionPaneViewModel ViewModel + { + get => (BuildVisionPaneViewModel)DataContext; + set => DataContext = value; + } + public ControlView() { InitializeComponent(); // Ensure the current culture passed into bindings is the OS culture. // By default, WPF uses en-US as the culture, regardless of the system settings. Language = XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag); + + if (DesignerProperties.GetIsInDesignMode(new System.Windows.DependencyObject())) + { + ViewModel = new BuildVisionPaneViewModel(); + } } } } diff --git a/src/BuildVision.UI/Components/ProjectGrid.xaml b/src/BuildVision.UI/Components/ProjectGrid.xaml index 03aa0ee2..f2d19bcd 100644 --- a/src/BuildVision.UI/Components/ProjectGrid.xaml +++ b/src/BuildVision.UI/Components/ProjectGrid.xaml @@ -10,14 +10,16 @@ xmlns:helpers="clr-namespace:BuildVision.UI.Helpers" xmlns:contracts="clr-namespace:BuildVision.Contracts;assembly=BuildVision.Contracts" xmlns:local="clr-namespace:BuildVision.UI.Components" + xmlns:converters="clr-namespace:BuildVision.UI.Converters" mc:Ignorable="d" Background="{DynamicResource ToolWindowBackgroundKey}" DataContextChanged="OnDataContextChanged" SnapsToDevicePixels="True" UseLayoutRounding="True" + x:Name="ProjectGridControl" d:DesignHeight="148" d:DesignWidth="697" - d:DataContext="{Binding Source={StaticResource DesignViewModel}}"> + d:DataContext="{d:DesignInstance viewModels:BuildVisionPaneViewModel, IsDesignTimeCreatable=True}"> @@ -31,13 +33,9 @@ - - + - - - + @@ -73,8 +70,7 @@ - + @@ -92,11 +88,9 @@ + - - - + + + - + + + + - - + @@ -156,7 +143,6 @@ BorderBrush="{TemplateBinding Border.BorderBrush}" BorderThickness="0" SnapsToDevicePixels="True"> - - + - + @@ -190,7 +176,7 @@ - + @@ -198,7 +184,7 @@ - + @@ -206,7 +192,6 @@ - @@ -218,37 +203,24 @@ - + - - - + + + - - + + - + @@ -267,7 +239,7 @@ - + @@ -275,8 +247,8 @@ - - + + @@ -308,5 +280,7 @@ MaxHeight="100" /> + + diff --git a/src/BuildVision.UI/Components/ProjectGrid.xaml.cs b/src/BuildVision.UI/Components/ProjectGrid.xaml.cs index c41be47c..d01e33f3 100644 --- a/src/BuildVision.UI/Components/ProjectGrid.xaml.cs +++ b/src/BuildVision.UI/Components/ProjectGrid.xaml.cs @@ -1,10 +1,13 @@ using System.ComponentModel; +using System.Diagnostics; +using System.Globalization; using System.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Controls.Primitives; using System.Windows.Data; using System.Windows.Input; +using System.Windows.Markup; using System.Windows.Media; using BuildVision.UI.Converters; using BuildVision.UI.DataGrid; @@ -15,73 +18,77 @@ namespace BuildVision.UI.Components { public partial class ProjectGrid : UserControl { - private BuildVisionPaneViewModel _viewModel; + public BuildVisionPaneViewModel ViewModel + { + get => (BuildVisionPaneViewModel)DataContext; + set => DataContext = value; + } public ProjectGrid() { InitializeComponent(); - + // Ensure the current culture passed into bindings is the OS culture. + // By default, WPF uses en-US as the culture, regardless of the system settings. + Language = XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag); Grid.TargetUpdated += GridOnTargetUpdated; } private void GridOnTargetUpdated(object sender, DataTransferEventArgs e) { - if (e.Property.Name == "ItemsSource") + if (e.Property.Name == nameof(Grid.ItemsSource)) + { RefreshSortDirectionInGrid(); + } } private void RefreshSortDirectionInGrid() { - DataGridColumn dataGridColumn = Grid.Columns.FirstOrDefault(col => col.GetBindedProperty() == _viewModel.GridSortDescription.Property); + Debug.Assert(Grid.Columns != null); + var dataGridColumn = Grid.Columns.FirstOrDefault(col => col.GetBindedProperty() == ViewModel.GridSortDescription.Property); if (dataGridColumn != null) { - dataGridColumn.SortDirection = _viewModel.GridSortDescription.Order.ToSystem(); + dataGridColumn.SortDirection = ViewModel.GridSortDescription.Order.ToSystem(); } } private void GridOnSorting(object sender, DataGridSortingEventArgs e) { - if (_viewModel.GridSorting.CanExecute(e)) + if (ViewModel.GridSorting.CanExecute(e)) { - _viewModel.GridSorting.Execute(e); + ViewModel.GridSorting.Execute(e); } } private void OnDataContextChanged(object sender, DependencyPropertyChangedEventArgs e) { - _viewModel = (BuildVisionPaneViewModel)DataContext; - _viewModel.SetGridColumnsRef(Grid.Columns); - _viewModel.PropertyChanged += ViewModelOnPropertyChanged; + Debug.Assert(ViewModel != null); + ViewModel = (BuildVisionPaneViewModel)DataContext; + ViewModel.SetGridColumnsRef(Grid.Columns); + ViewModel.PropertyChanged += ViewModelOnPropertyChanged; } private void ViewModelOnPropertyChanged(object sender, PropertyChangedEventArgs e) { //TODO implement logic for scrolling tu currentproject - if (_viewModel.BuildInformationModel.CurrentProject != null && e.PropertyName == "CurrentProject") + if (ViewModel.BuildInformationModel.CurrentProject != null && e.PropertyName == "CurrentProject") { // TODO: Remove SelectedIndex = -1 and implement Unselect row feature by clicking on selected row. Grid.SelectedIndex = -1; if (Grid.SelectedIndex == -1) - Grid.ScrollIntoView(_viewModel.BuildInformationModel.CurrentProject); + Grid.ScrollIntoView(ViewModel.BuildInformationModel.CurrentProject); } } private void DataGridExpanderOnExpanded(object sender, RoutedEventArgs e) { - ExpanderIsExpandedConverter.SaveState( - (Expander)sender, - false, - _viewModel.ControlSettings.GridSettings.CollapsedGroups); + ExpanderIsExpandedConverter.SaveState((Expander)sender, false, ViewModel.ControlSettings.GridSettings.CollapsedGroups); e.Handled = true; } private void DataGridExpanderOnCollapsed(object sender, RoutedEventArgs e) { - ExpanderIsExpandedConverter.SaveState( - (Expander)sender, - true, - _viewModel.ControlSettings.GridSettings.CollapsedGroups); + ExpanderIsExpandedConverter.SaveState((Expander)sender, true, ViewModel.ControlSettings.GridSettings.CollapsedGroups); e.Handled = true; } @@ -114,12 +121,7 @@ private void DataGridRowOnPreviewMouseLeftButtonDown(object sender, MouseButtonE { row.Focusable = true; row.Focus(); - - // Gets the element with keyboard focus. - var elementWithFocus = Keyboard.FocusedElement as UIElement; - - // Change keyboard focus. - if (elementWithFocus != null) + if (Keyboard.FocusedElement is UIElement elementWithFocus) { var request = new TraversalRequest(FocusNavigationDirection.Next); elementWithFocus.MoveFocus(request); diff --git a/src/BuildVision.UI/Converters/ExpanderIsExpandedConverter.cs b/src/BuildVision.UI/Converters/ExpanderIsExpandedConverter.cs index ab7d6f5d..91f6f032 100644 --- a/src/BuildVision.UI/Converters/ExpanderIsExpandedConverter.cs +++ b/src/BuildVision.UI/Converters/ExpanderIsExpandedConverter.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Globalization; using System.Windows.Controls; @@ -11,7 +11,7 @@ public class ExpanderIsExpandedConverter : IMultiValueConverter public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) { var collectionViewGroup = (CollectionViewGroup)values[0]; - var collapsedGroups = (IList)values[1]; + var collapsedGroups = values[1] as IList; if (collapsedGroups == null || collapsedGroups.Count == 0) return true; diff --git a/src/BuildVision.UI/Models/ProjectItem.cs b/src/BuildVision.UI/Models/ProjectItem.cs index 15f8f31b..d2bcb3fe 100644 --- a/src/BuildVision.UI/Models/ProjectItem.cs +++ b/src/BuildVision.UI/Models/ProjectItem.cs @@ -13,11 +13,6 @@ public class ProjectItem : BindableBase, IProjectItem { private const string ResourcesUri = @"Resources/ProjectItem.Resources.xaml"; - public ProjectItem() - { - State = ProjectState.Pending; - } - public bool IsBatchBuildProject { get; set; } private string _uniqueName; @@ -258,6 +253,11 @@ public string SolutionFolder } public bool Success { get; set; } + public ProjectItem() + { + State = ProjectState.Pending; + } + public void RaiseBuildElapsedTimeChanged() { OnPropertyChanged(nameof(BuildElapsedTime)); diff --git a/src/BuildVision.UI/Settings/Models/GridSettings.cs b/src/BuildVision.UI/Settings/Models/GridSettings.cs index 72cd7808..b936ffa2 100644 --- a/src/BuildVision.UI/Settings/Models/GridSettings.cs +++ b/src/BuildVision.UI/Settings/Models/GridSettings.cs @@ -50,11 +50,6 @@ public string GroupName set => _groupName = value; } - /// - /// User-friendly header format for groups. - /// For example, "{title}: {value} - {count} items". - /// Available arguments see in . - /// public string GroupHeaderFormat { get => _groupHeaderFormat ?? (_groupHeaderFormat = "{title}: {value}"); @@ -75,18 +70,18 @@ public SortDescription Sort public List CollapsedGroups => _collapsedGroups ?? (_collapsedGroups = new List()); - /// - /// Converts user-friendly string format with arguments - /// into system format string (with {0},{1},... arguments). - /// private static string ConvertGroupHeaderToRawFormat(string userFriendlyFormatString) { if (string.IsNullOrEmpty(userFriendlyFormatString)) + { return string.Empty; + } string rawFormat = userFriendlyFormatString; for (int i = 0; i < GroupHeaderFormatArgs.Length; i++) + { rawFormat = rawFormat.Replace("{" + GroupHeaderFormatArgs[i], "{" + i); + } return rawFormat; } diff --git a/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs b/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs index 95189a38..08242f9b 100644 --- a/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs +++ b/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs @@ -59,7 +59,7 @@ public bool HideUpToDateTargets public ControlSettings ControlSettings { get; } - public ObservableCollection Projects { get; set; } + public ObservableCollection Projects { get; } public IBuildInformationModel BuildInformationModel { get; set; } @@ -146,14 +146,12 @@ public ListCollectionView GroupedProjectsList { get { - var groupedList = new ListCollectionView(Projects); // todo use projects here ProjectsList); - + var groupedList = new ListCollectionView(Projects); if (!string.IsNullOrWhiteSpace(GridGroupPropertyName)) { Debug.Assert(groupedList.GroupDescriptions != null); groupedList.GroupDescriptions.Add(new PropertyGroupDescription(GridGroupPropertyName)); } - groupedList.CustomSort = GetProjectItemSorter(GridSortDescription); groupedList.IsLiveGrouping = true; groupedList.IsLiveSorting = true; @@ -183,7 +181,7 @@ public ProjectItem SelectedProjectItem set => SetProperty(ref _selectedProjectItem, value); } - internal BuildVisionPaneViewModel() + public BuildVisionPaneViewModel() { ControlSettings = new ControlSettings(); BuildInformationModel = new BuildInformationModel(); @@ -347,7 +345,10 @@ private void CopyErrorMessageToClipboard(ProjectItem projectItem) public ICommand GridSorting => new RelayCommand(obj => ReorderGrid(obj)); - public ICommand GridGroupPropertyMenuItemClicked => new RelayCommand(obj => GridGroupPropertyName = (obj != null) ? obj.ToString() : string.Empty); + public ICommand GridGroupPropertyMenuItemClicked => new RelayCommand(obj => + { + GridGroupPropertyName = (obj != null) ? obj.ToString() : string.Empty; + }); public ICommand SelectedProjectOpenContainingFolderAction => new RelayCommand(obj => OpenContainingFolder(), canExecute: obj => (SelectedProjectItem != null && !string.IsNullOrEmpty(SelectedProjectItem.FullName))); diff --git a/src/BuildVision/BuildVision.csproj b/src/BuildVision/BuildVision.csproj index 5581f363..95579d18 100644 --- a/src/BuildVision/BuildVision.csproj +++ b/src/BuildVision/BuildVision.csproj @@ -84,6 +84,7 @@ + diff --git a/src/BuildVision/Extensions/BuildStateExtensions.cs b/src/BuildVision/Extensions/BuildStateExtensions.cs new file mode 100644 index 00000000..9d57c88f --- /dev/null +++ b/src/BuildVision/Extensions/BuildStateExtensions.cs @@ -0,0 +1,35 @@ +using System.Windows.Shell; +using BuildVision.Contracts; + +namespace BuildVision.Extensions +{ + public static class BuildStateExtensions + { + public static TaskbarItemProgressState ToTaskBarItemProgressState(this BuildState buildState, BuildScopes buildScope) + { + var progressState = TaskbarItemProgressState.Normal; + if (buildState == BuildState.Cancelled) + { + progressState = TaskbarItemProgressState.Paused; + } + else if (buildState == BuildState.Failed) + { + progressState = TaskbarItemProgressState.Error; + } + else if (buildState != BuildState.InProgress) + { + progressState = TaskbarItemProgressState.None; + } + else if (buildScope != BuildScopes.BuildScopeSolution) + { + progressState = TaskbarItemProgressState.Indeterminate; + } + else + { + progressState = TaskbarItemProgressState.Normal; + } + + return progressState; + } + } +} diff --git a/src/BuildVision/Services/BuildInformationProvider.cs b/src/BuildVision/Services/BuildInformationProvider.cs index 8877e6d7..96531b42 100644 --- a/src/BuildVision/Services/BuildInformationProvider.cs +++ b/src/BuildVision/Services/BuildInformationProvider.cs @@ -199,7 +199,7 @@ public void BuildStarted(BuildActions buildAction, BuildScopes buildScope) _buildOutputLogger.Attach(); ResetBuildInformationModel(); - ResetCurrentProjects(); + ReloadCurrentProjects(); BuildInformationModel.BuildStartTime = DateTime.Now; BuildInformationModel.BuildFinishTime = null; @@ -267,6 +267,33 @@ public void ProjectBuildFinished(BuildActions buildAction, string projectIdentif } var currentProject = Projects.First(item => ProjectIdentifierGenerator.GetIdentifierForProjectItem(item) == projectIdentifier); + currentProject.Success = success; + currentProject.State = GetProjectState(success, canceled, currentProject); + currentProject.BuildFinishTime = DateTime.Now; + + if (currentProject.State == ProjectState.BuildError && _packageSettingsProvider.Settings.GeneralSettings.StopBuildAfterFirstError) + { + _buildService.CancelBuildSolution(); + } + + BuildInformationModel.SucceededProjectsCount = Projects.Count(x => x.State == ProjectState.BuildDone || x.State == ProjectState.CleanDone); + BuildInformationModel.FailedProjectsCount = Projects.Count(x => x.State == ProjectState.BuildError || x.State == ProjectState.CleanError); + BuildInformationModel.WarnedProjectsCount = Projects.Count(x => x.State == ProjectState.BuildWarning); + BuildInformationModel.UpToDateProjectsCount = Projects.Count(x => x.State == ProjectState.UpToDate); + BuildInformationModel.MessagesCount = Projects.Sum(x => x.MessagesCount); + BuildInformationModel.ErrorCount = Projects.Sum(x => x.ErrorsCount); + BuildInformationModel.WarningsCount = Projects.Sum(x => x.WarningsCount); + + if (BuildInformationModel.CurrentProject == null) + { + BuildInformationModel.CurrentProject = Projects.Last(); + } + + _taskBarInfoService.UpdateTaskBarInfo(BuildInformationModel.CurrentBuildState, BuildInformationModel.BuildScope, Projects.Count, GetFinishedProjectsCount()); + } + + private ProjectState GetProjectState(bool success, bool canceled, IProjectItem currentProject) + { ProjectState projectState; switch (BuildInformationModel.BuildAction) { @@ -281,10 +308,6 @@ public void ProjectBuildFinished(BuildActions buildAction, string projectIdentif else { projectState = _buildOutputLogger.IsProjectUpToDate(currentProject) ? ProjectState.UpToDate : ProjectState.BuildDone; - if (projectState == ProjectState.UpToDate) - { - // do i have to set errorbox here? - } } } else @@ -299,31 +322,10 @@ public void ProjectBuildFinished(BuildActions buildAction, string projectIdentif break; default: - throw new ArgumentOutOfRangeException(nameof(buildAction)); - } - currentProject.Success = success; - currentProject.State = projectState; - currentProject.BuildFinishTime = DateTime.Now; - - if (currentProject.State == ProjectState.BuildError && _packageSettingsProvider.Settings.GeneralSettings.StopBuildAfterFirstError) - { - _buildService.CancelBuildSolution(); - } - - BuildInformationModel.SucceededProjectsCount = Projects.Count(x => x.State == ProjectState.BuildDone || x.State == ProjectState.CleanDone); - BuildInformationModel.FailedProjectsCount = Projects.Count(x => x.State == ProjectState.BuildError || x.State == ProjectState.CleanError); - BuildInformationModel.WarnedProjectsCount = Projects.Count(x => x.State == ProjectState.BuildWarning); - BuildInformationModel.UpToDateProjectsCount = Projects.Count(x => x.State == ProjectState.UpToDate); - BuildInformationModel.MessagesCount = Projects.Sum(x => x.MessagesCount); - BuildInformationModel.ErrorCount = Projects.Sum(x => x.ErrorsCount); - BuildInformationModel.WarningsCount = Projects.Sum(x => x.WarningsCount); - - if (BuildInformationModel.CurrentProject == null) - { - BuildInformationModel.CurrentProject = Projects.Last(); + throw new ArgumentOutOfRangeException(nameof(BuildInformationModel.BuildAction)); } - _taskBarInfoService.UpdateTaskBarInfo(BuildInformationModel.CurrentBuildState, BuildInformationModel.BuildScope, Projects.Count, GetFinishedProjectsCount()); + return projectState; } public void BuildUpdate() diff --git a/src/BuildVision/Services/BuildOutputLogger.cs b/src/BuildVision/Services/BuildOutputLogger.cs index 9856f508..96fb9904 100644 --- a/src/BuildVision/Services/BuildOutputLogger.cs +++ b/src/BuildVision/Services/BuildOutputLogger.cs @@ -32,9 +32,9 @@ public override void Initialize(IEventSource eventSource) { _projects = new List(); eventSource.ProjectStarted += OnProjectStarted; - eventSource.MessageRaised += (s, e) => EventSource_ErrorRaised(s, e, ErrorLevel.Message); - eventSource.WarningRaised += (s, e) => EventSource_ErrorRaised(s, e, ErrorLevel.Warning); - eventSource.ErrorRaised += (s, e) => EventSource_ErrorRaised(s, e, ErrorLevel.Error); + eventSource.MessageRaised += (s, e) => EventSource_ErrorRaised(e, ErrorLevel.Message); + eventSource.WarningRaised += (s, e) => EventSource_ErrorRaised(e, ErrorLevel.Warning); + eventSource.ErrorRaised += (s, e) => EventSource_ErrorRaised(e, ErrorLevel.Error); } private void OnProjectStarted(object sender, ProjectStartedEventArgs e) @@ -98,12 +98,11 @@ public bool IsProjectUpToDate(IProjectItem projectItem) return !_projects.Exists(t => t.FileName == projectItem.FullName); } - private void EventSource_ErrorRaised(object sender, BuildEventArgs e, ErrorLevel errorLevel) + private void EventSource_ErrorRaised(BuildEventArgs e, ErrorLevel errorLevel) { try { - bool verified = VerifyLoggerBuildEvent(e, errorLevel); - if (!verified) + if (e.BuildEventContext.IsBuildEventContextInvalid()) return; int projectInstanceId = e.BuildEventContext.ProjectInstanceId; @@ -116,7 +115,9 @@ private void EventSource_ErrorRaised(object sender, BuildEventArgs e, ErrorLevel return; } if (projectEntry.IsInvalid) + { return; + } OnErrorRaised(projectEntry, e, errorLevel); } @@ -126,26 +127,6 @@ private void EventSource_ErrorRaised(object sender, BuildEventArgs e, ErrorLevel } } - private bool VerifyLoggerBuildEvent(BuildEventArgs eventArgs, ErrorLevel errorLevel) - { - if (eventArgs.BuildEventContext.IsBuildEventContextInvalid()) - return false; - - if (errorLevel == ErrorLevel.Message) - { - var messageEventArgs = (BuildMessageEventArgs)eventArgs; - if (!messageEventArgs.IsUserMessage(this)) - return false; - } - - return true; - } - - public void Reset() - { - _projects.Clear(); - } - public event Action OnErrorRaised; } } diff --git a/src/BuildVision/Services/TaskBarInfoService.cs b/src/BuildVision/Services/TaskBarInfoService.cs index a1a485bb..99105d68 100644 --- a/src/BuildVision/Services/TaskBarInfoService.cs +++ b/src/BuildVision/Services/TaskBarInfoService.cs @@ -5,6 +5,7 @@ using System.Windows.Shell; using BuildVision.Contracts; using BuildVision.Exports.Services; +using BuildVision.Extensions; using BuildVision.UI.Models; using BuildVision.Views.Settings; @@ -30,21 +31,16 @@ public TaskBarInfoService(IPackageSettingsProvider packageSettingsProvider) public void UpdateTaskBarInfo(BuildState buildState, BuildScopes buildScope, int projectsCount, int finishedProjects) { if (_resetTaskBarInfoCts != null && !_resetTaskBarInfoCts.IsCancellationRequested) + { _resetTaskBarInfoCts.Cancel(); + } if (!_packageSettingsProvider.Settings.GeneralSettings.BuildProgressSettings.TaskBarProgressEnabled) + { return; + } - if (buildState == BuildState.Cancelled) - _taskbarItemInfo.Value.ProgressState = TaskbarItemProgressState.Paused; - else if (buildState == BuildState.Failed) - _taskbarItemInfo.Value.ProgressState = TaskbarItemProgressState.Error; - else if (buildState != BuildState.InProgress) - _taskbarItemInfo.Value.ProgressState = TaskbarItemProgressState.None; - else if (buildScope != BuildScopes.BuildScopeSolution) - _taskbarItemInfo.Value.ProgressState = TaskbarItemProgressState.Indeterminate; - else - _taskbarItemInfo.Value.ProgressState = TaskbarItemProgressState.Normal; + _taskbarItemInfo.Value.ProgressState = buildState.ToTaskBarItemProgressState(buildScope); ; if (projectsCount <= 0) { @@ -80,7 +76,9 @@ private void ResetTaskBarInfoOnBuildDone() { var buildProgressSettings = _packageSettingsProvider.Settings.GeneralSettings.BuildProgressSettings; if (!buildProgressSettings.TaskBarProgressEnabled) + { return; + } switch (buildProgressSettings.ResetTaskBarProgressAfterBuildDone) { From cd1845640b92449ee039c6c1a6dcf41a12cbdbaf Mon Sep 17 00:00:00 2001 From: Stefan Kert Date: Sat, 27 Apr 2019 07:27:15 +0200 Subject: [PATCH 067/100] Updated nuget packages to latest versions --- Directory.Build.props | 2 +- src/BuildVision.Common/BuildVision.Common.csproj | 10 +++++----- src/BuildVision.Contracts/BuildVision.Contracts.csproj | 4 ++++ src/BuildVision.Exports/BuildVision.Exports.csproj | 4 ++++ src/BuildVision.UI/BuildVision.UI.csproj | 5 ++++- src/BuildVision/BuildVision.csproj | 3 +++ .../BuildVision.IntegrationTests.csproj | 1 + .../BuildVision.UnitTests/BuildVision.UnitTests.csproj | 3 ++- 8 files changed, 24 insertions(+), 8 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 0a6d21ed..3b8b6907 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -2,7 +2,7 @@ - 2.2.33 + 2.3.138 all diff --git a/src/BuildVision.Common/BuildVision.Common.csproj b/src/BuildVision.Common/BuildVision.Common.csproj index 0731d117..e77e895b 100644 --- a/src/BuildVision.Common/BuildVision.Common.csproj +++ b/src/BuildVision.Common/BuildVision.Common.csproj @@ -13,13 +13,13 @@ - - - + + + - - + + diff --git a/src/BuildVision.Contracts/BuildVision.Contracts.csproj b/src/BuildVision.Contracts/BuildVision.Contracts.csproj index d5f97ced..80d21da2 100644 --- a/src/BuildVision.Contracts/BuildVision.Contracts.csproj +++ b/src/BuildVision.Contracts/BuildVision.Contracts.csproj @@ -12,6 +12,10 @@ + + + + diff --git a/src/BuildVision.Exports/BuildVision.Exports.csproj b/src/BuildVision.Exports/BuildVision.Exports.csproj index bf5367fa..9b277d43 100644 --- a/src/BuildVision.Exports/BuildVision.Exports.csproj +++ b/src/BuildVision.Exports/BuildVision.Exports.csproj @@ -6,6 +6,10 @@ Key.snk + + + + diff --git a/src/BuildVision.UI/BuildVision.UI.csproj b/src/BuildVision.UI/BuildVision.UI.csproj index 7343144d..fb253e5e 100644 --- a/src/BuildVision.UI/BuildVision.UI.csproj +++ b/src/BuildVision.UI/BuildVision.UI.csproj @@ -368,11 +368,14 @@ - 2.10.17-preview + 2.10.34-preview 14.3.81-pre + + 2.9.2 + diff --git a/src/BuildVision/BuildVision.csproj b/src/BuildVision/BuildVision.csproj index 95579d18..6464240e 100644 --- a/src/BuildVision/BuildVision.csproj +++ b/src/BuildVision/BuildVision.csproj @@ -235,6 +235,9 @@ 16.0.461 + + 2.9.2 + 15.8.36 diff --git a/test/BuildVision.IntegrationTests/BuildVision.IntegrationTests.csproj b/test/BuildVision.IntegrationTests/BuildVision.IntegrationTests.csproj index a85b2828..5cc24e17 100644 --- a/test/BuildVision.IntegrationTests/BuildVision.IntegrationTests.csproj +++ b/test/BuildVision.IntegrationTests/BuildVision.IntegrationTests.csproj @@ -7,6 +7,7 @@ + diff --git a/test/BuildVision.UnitTests/BuildVision.UnitTests.csproj b/test/BuildVision.UnitTests/BuildVision.UnitTests.csproj index a532cbc4..75b91cf2 100644 --- a/test/BuildVision.UnitTests/BuildVision.UnitTests.csproj +++ b/test/BuildVision.UnitTests/BuildVision.UnitTests.csproj @@ -4,7 +4,8 @@ - + + all From 8d9518c4573364466e9ad138ae95be012edcef77 Mon Sep 17 00:00:00 2001 From: Stefan Kert Date: Sat, 27 Apr 2019 07:31:10 +0200 Subject: [PATCH 068/100] Adaptions --- LICENSE.txt | 2 +- src/BuildVision.UI/Settings/GeneralSettingsControl.xaml | 2 +- src/BuildVision/LICENSE.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/LICENSE.txt b/LICENSE.txt index 34f2aaa5..4f94642f 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,4 +1,4 @@ - Copyright © 2017 Aleksey Nagovitsyn, Stefan Kert and Tom Schmiedlechner + Copyright © 2019 Aleksey Nagovitsyn, Stefan Kert Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/src/BuildVision.UI/Settings/GeneralSettingsControl.xaml b/src/BuildVision.UI/Settings/GeneralSettingsControl.xaml index 23c39680..c0a15327 100644 --- a/src/BuildVision.UI/Settings/GeneralSettingsControl.xaml +++ b/src/BuildVision.UI/Settings/GeneralSettingsControl.xaml @@ -176,7 +176,7 @@ - + diff --git a/src/BuildVision/LICENSE.txt b/src/BuildVision/LICENSE.txt index 9a906eec..880b5dd2 100644 --- a/src/BuildVision/LICENSE.txt +++ b/src/BuildVision/LICENSE.txt @@ -1,4 +1,4 @@ -Copyright © 2017 Aleksey Nagovitsyn, Stefan Kert and Tom Schmiedlechner +Copyright © 2017 Aleksey Nagovitsyn, Stefan Kert Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the From 97cffaaa32df03a408c6390653bd33011c5e3442 Mon Sep 17 00:00:00 2001 From: Stefan Kert Date: Sat, 27 Apr 2019 07:31:16 +0200 Subject: [PATCH 069/100] Adaptions --- LICENSE.txt | 2 +- src/BuildVision/LICENSE.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/LICENSE.txt b/LICENSE.txt index 4f94642f..8371b4bf 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,4 +1,4 @@ - Copyright © 2019 Aleksey Nagovitsyn, Stefan Kert + Copyright © 2019 Stefan Kert Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/src/BuildVision/LICENSE.txt b/src/BuildVision/LICENSE.txt index 880b5dd2..6285eb4d 100644 --- a/src/BuildVision/LICENSE.txt +++ b/src/BuildVision/LICENSE.txt @@ -1,4 +1,4 @@ -Copyright © 2017 Aleksey Nagovitsyn, Stefan Kert +Copyright © 2017 Stefan Kert Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the From c1cf87df21f5a118d9e4af02d8cdd939897620a7 Mon Sep 17 00:00:00 2001 From: Stefan Kert Date: Sat, 27 Apr 2019 07:54:55 +0200 Subject: [PATCH 070/100] Fixed many compilation warnings --- src/BuildVision.Common/AppVersionInfo.cs | 2 + src/BuildVision.Common/BindableBase.cs | 8 +- .../CustomStringFormatProvider.cs | 2 + .../Diagnostics/DiagnosticsClient.cs | 27 ++++-- .../Extensions/DateTimeExtensions.cs | 3 + src/BuildVision.Common/FilePathHelper.cs | 2 +- src/BuildVision.Common/GithubHelper.cs | 11 +-- .../PropertyColumnSorter.cs | 6 ++ src/BuildVision.Common/RelayCommand.cs | 5 +- src/BuildVision.Common/SettingsBase.cs | 2 + src/BuildVision.Common/VSVersion.cs | 2 + .../Enums/BuildActions.cs | 10 +-- .../Enums/BuildScopes.cs | 8 +- .../Exceptions/PropertyNotFoundException.cs | 15 ++-- .../Models/BuildProjectContextEntry.cs | 4 +- src/BuildVision.Contracts/Models/ErrorItem.cs | 4 + .../Models/IBuildInformationModel.cs | 4 +- .../Models/IProjectItem.cs | 6 +- .../Providers/IBuildInformationProvider.cs | 6 +- .../Sevices/ITaskBarInfoService.cs | 2 +- .../Attributes/DisplayStringAttribute.cs | 2 + .../Components/ErrorsGrid.xaml.cs | 2 + .../Components/ProjectGrid.xaml.cs | 4 + .../Components/SpinnerControl.xaml.cs | 4 + .../AlternatingRowBackgroundConverter.cs | 24 +++-- .../Converters/BooleanToHiddenConverter.cs | 10 +-- .../Converters/ColumnWidthConverter.cs | 13 +-- .../DataGridLengthStringConverter.cs | 13 +-- .../Converters/ExpanderIsExpandedConverter.cs | 19 ++-- ...mnSettingsToColumnExampleValueConverter.cs | 8 ++ .../MultiBindingStringFormatConverter.cs | 4 +- .../Converters/NumberToIsPositiveConverter.cs | 2 + .../ObjectsReferencesEqualsConverter.cs | 6 +- .../Converters/SubtractConstantConverter.cs | 4 +- src/BuildVision.UI/DataGrid/ColumnsManager.cs | 33 +++++++ .../Extensions/EnumerationExtension.cs | 6 ++ .../Extensions/TextBlockUtils.cs | 2 + src/BuildVision.UI/Extensions/VisualHelper.cs | 8 ++ .../Helpers/BuildMessagesFactory.cs | 34 +++---- .../Models/BuildInformationModel.cs | 90 ++++++++++++++----- src/BuildVision.UI/Models/ProjectItem.cs | 4 + .../Settings/GridSettingsControl.xaml.cs | 20 +++++ .../Settings/Models/BuildMessagesSettings.cs | 6 ++ .../Settings/Models/ControlSettings.cs | 10 +++ .../Settings/Models/GridSettings.cs | 4 + .../Commands/ShowToolWindowCommand.cs | 2 + src/BuildVision/Core/BuildVisionPane.cs | 7 ++ src/BuildVision/Core/Services.cs | 9 ++ src/BuildVision/Core/SolutionBuildEvents.cs | 4 +- .../Extensions/BuildActionsExtensions.cs | 10 +-- .../Extensions/BuildStateExtensions.cs | 4 +- src/BuildVision/Helpers/ProjectExtensions.cs | 70 +++++++++++++++ .../Helpers/PropertiesExtensions.cs | 2 + .../Helpers/SolutionProjectsExtensions.cs | 14 +++ .../Helpers/StateConverterHelper.cs | 10 +-- .../Services/BuildInformationProvider.cs | 26 +++--- src/BuildVision/Services/BuildOutputLogger.cs | 2 + src/BuildVision/Services/BuildService.cs | 13 ++- .../Services/ErrorNavigationService.cs | 14 +++ .../Services/PackageSettingsProvider.cs | 2 + src/BuildVision/Services/SolutionProvider.cs | 5 ++ .../Services/StatusBarNotificationService.cs | 4 + .../Services/TaskBarInfoService.cs | 2 +- .../Services/WindowStateService.cs | 7 ++ .../Views/Settings/SettingsDialogPage.cs | 7 ++ .../BuildInformationModelTests.cs | 52 +++++------ 66 files changed, 549 insertions(+), 178 deletions(-) diff --git a/src/BuildVision.Common/AppVersionInfo.cs b/src/BuildVision.Common/AppVersionInfo.cs index 42517575..c993da81 100644 --- a/src/BuildVision.Common/AppVersionInfo.cs +++ b/src/BuildVision.Common/AppVersionInfo.cs @@ -40,7 +40,9 @@ private static DateTime RetrieveLinkerTimestamp(Assembly assembly) finally { if (stream != null) + { stream.Close(); + } } int i = BitConverter.ToInt32(buffer, PeHeaderOffset); diff --git a/src/BuildVision.Common/BindableBase.cs b/src/BuildVision.Common/BindableBase.cs index 5efa5848..5d2ecec8 100644 --- a/src/BuildVision.Common/BindableBase.cs +++ b/src/BuildVision.Common/BindableBase.cs @@ -11,7 +11,9 @@ public abstract class BindableBase : INotifyPropertyChanged public virtual bool SetProperty(ref T storage, T value, [CallerMemberName] string propertyName = null) { if (Equals(storage, value)) + { return false; + } storage = value; OnPropertyChanged(propertyName); @@ -19,12 +21,14 @@ public virtual bool SetProperty(ref T storage, T value, [CallerMemberName] st return true; } - public virtual bool SetProperty(Func storage, Action set, T value, [CallerMemberName] string propertyName = null) + public virtual bool SetProperty(Func storage, Action setAction, T value, [CallerMemberName] string propertyName = null) { if (Equals(storage(), value)) + { return false; + } - set(value); + setAction(value); OnPropertyChanged(propertyName); return true; diff --git a/src/BuildVision.Common/CustomStringFormatProvider.cs b/src/BuildVision.Common/CustomStringFormatProvider.cs index d343b0fa..0703ede6 100644 --- a/src/BuildVision.Common/CustomStringFormatProvider.cs +++ b/src/BuildVision.Common/CustomStringFormatProvider.cs @@ -19,7 +19,9 @@ public object GetFormat(Type formatType) public string Format(string format, object arg, IFormatProvider formatProvider) { if (arg == null) + { return null; + } if (format != null && arg is string) { diff --git a/src/BuildVision.Common/Diagnostics/DiagnosticsClient.cs b/src/BuildVision.Common/Diagnostics/DiagnosticsClient.cs index cd976446..62006f2b 100644 --- a/src/BuildVision.Common/Diagnostics/DiagnosticsClient.cs +++ b/src/BuildVision.Common/Diagnostics/DiagnosticsClient.cs @@ -29,7 +29,10 @@ public static void Initialize(string apiKey) public static void OnExit() { - if (!_initialized) return; + if (!_initialized) + { + return; + } _client.Flush(); // Allow time for flushing: @@ -38,26 +41,40 @@ public static void OnExit() public static void TrackEvent(string eventName, IDictionary properties = null, IDictionary metrics = null) { - if (!_initialized) return; + if (!_initialized) + { + return; + } + _client.TrackEvent(eventName, properties, metrics); } public static void TrackTrace(string evt) { - if (!_initialized) return; + if (!_initialized) + { + return; + } + _client.TrackTrace(evt); } public static void Notify(Exception exception) { - if (!_initialized) return; + if (!_initialized) + { + return; + } _client.TrackException(exception); } public static void TrackPageView(string pageName) { - if (!_initialized) return; + if (!_initialized) + { + return; + } _client.TrackPageView(pageName); } diff --git a/src/BuildVision.Common/Extensions/DateTimeExtensions.cs b/src/BuildVision.Common/Extensions/DateTimeExtensions.cs index c2cffa78..62aa887b 100644 --- a/src/BuildVision.Common/Extensions/DateTimeExtensions.cs +++ b/src/BuildVision.Common/Extensions/DateTimeExtensions.cs @@ -7,7 +7,10 @@ public static class DateTimeExtensions public static DateTime Truncate(this DateTime dateTime, TimeSpan timeSpan) { if (timeSpan <= TimeSpan.Zero) + { return dateTime; + } + return dateTime.AddTicks(-(dateTime.Ticks % timeSpan.Ticks)); } } diff --git a/src/BuildVision.Common/FilePathHelper.cs b/src/BuildVision.Common/FilePathHelper.cs index d7c52811..12e72f8c 100644 --- a/src/BuildVision.Common/FilePathHelper.cs +++ b/src/BuildVision.Common/FilePathHelper.cs @@ -120,7 +120,7 @@ public static string ShortenPath(string path, int maxLength) } } - if (lastPart == "") + if (string.IsNullOrEmpty(lastPart)) { //the filename (and root path) in itself was longer than maxLength, shorten it lastPart = pathParts[pathParts.Length - 1];//"pathParts[pathParts.Length -1]" is the equivalent of "Path.GetFileName(pathToShorten)" diff --git a/src/BuildVision.Common/GithubHelper.cs b/src/BuildVision.Common/GithubHelper.cs index d05914c3..b6679ac6 100644 --- a/src/BuildVision.Common/GithubHelper.cs +++ b/src/BuildVision.Common/GithubHelper.cs @@ -1,11 +1,12 @@ using System; using System.Diagnostics; +using System.Globalization; using System.Net; using BuildVision.Common; namespace BuildVision.Helpers { - public class GithubHelper + public static class GithubHelper { const string ASSIGNEE = "stefankert"; const string URL_TEMPLATE = "https://github.com/StefanKert/BuildVision/issues/new?labels={0}&title={1}&assignee={2}&body={3}"; @@ -24,13 +25,13 @@ public static void OpenBrowserWithPrefilledIssue() { var appVersion = new AppVersionInfo(); - var url = GetUrlForNewBug(string.Format(template, VsVersion.FullVersion, appVersion.BuildVersion, Environment.OSVersion)); - Process.Start(new ProcessStartInfo(url)); + var url = GetUrlForNewBug(string.Format(CultureInfo.CurrentCulture, template, VsVersion.FullVersion, appVersion.BuildVersion, Environment.OSVersion)); + Process.Start(new ProcessStartInfo(url.ToString())); } - public static string GetUrlForNewBug(string body) + public static Uri GetUrlForNewBug(string body) { - return string.Format(URL_TEMPLATE, "Bug", "", ASSIGNEE, WebUtility.UrlEncode(body)); + return new Uri(string.Format(CultureInfo.CurrentCulture, URL_TEMPLATE, "Bug", "", ASSIGNEE, WebUtility.UrlEncode(body))); } } } diff --git a/src/BuildVision.Common/PropertyColumnSorter.cs b/src/BuildVision.Common/PropertyColumnSorter.cs index e1f5d14c..849ab477 100644 --- a/src/BuildVision.Common/PropertyColumnSorter.cs +++ b/src/BuildVision.Common/PropertyColumnSorter.cs @@ -18,7 +18,9 @@ public PropertyColumnSorter(ListSortDirection direction, string propertyName) _propertyInfo = typeof(T).GetProperty(propertyName); if (_propertyInfo == null) + { throw new PropertyNotFoundException(propertyName, typeof(T)); + } } int IComparer.Compare(object x, object y) @@ -32,10 +34,14 @@ protected int Compare(T x, T y) var y1 = _propertyInfo.GetValue(y, null) as IComparable; if (x1 != null && y1 != null) + { return x1.CompareTo(y1) * _direction; + } if (x1 == null && y1 == null) + { return 0; + } // Null values always in the bottom. return (x1 == null) ? 1 : -1; diff --git a/src/BuildVision.Common/RelayCommand.cs b/src/BuildVision.Common/RelayCommand.cs index cec77435..3d8c3080 100644 --- a/src/BuildVision.Common/RelayCommand.cs +++ b/src/BuildVision.Common/RelayCommand.cs @@ -32,10 +32,7 @@ public RelayCommand(Action execute) /// The execution status logic. public RelayCommand(Action execute, Predicate canExecute) { - if (execute == null) - throw new ArgumentNullException("execute"); - - _execute = execute; + _execute = execute ?? throw new ArgumentNullException(nameof(execute)); _canExecute = canExecute; } diff --git a/src/BuildVision.Common/SettingsBase.cs b/src/BuildVision.Common/SettingsBase.cs index da0a4cb9..ec4f5e96 100644 --- a/src/BuildVision.Common/SettingsBase.cs +++ b/src/BuildVision.Common/SettingsBase.cs @@ -14,7 +14,9 @@ public void InitFrom(T source) where T : SettingsBase { PropertyInfo[] properties = typeof(T).GetProperties(); foreach (var property in properties) + { property.SetValue(this, property.GetValue(source, null), null); + } } } } diff --git a/src/BuildVision.Common/VSVersion.cs b/src/BuildVision.Common/VSVersion.cs index 33539271..47bd2d92 100644 --- a/src/BuildVision.Common/VSVersion.cs +++ b/src/BuildVision.Common/VSVersion.cs @@ -36,7 +36,9 @@ public static Version FullVersion mVsVersion = new Version(verName); } else + { mVsVersion = new Version(0, 0); // Not running inside Visual Studio! + } } } diff --git a/src/BuildVision.Contracts/Enums/BuildActions.cs b/src/BuildVision.Contracts/Enums/BuildActions.cs index 48a92cce..b1078a2e 100644 --- a/src/BuildVision.Contracts/Enums/BuildActions.cs +++ b/src/BuildVision.Contracts/Enums/BuildActions.cs @@ -1,11 +1,11 @@ namespace BuildVision.Contracts { - public enum BuildActions + public enum BuildAction { - BuildActionBuild = 1, - BuildActionRebuildAll = 2, - BuildActionClean = 3, - BuildActionDeploy = 4, + Build = 1, + RebuildAll = 2, + Clean = 3, + Deploy = 4, Unknown = 5 } } diff --git a/src/BuildVision.Contracts/Enums/BuildScopes.cs b/src/BuildVision.Contracts/Enums/BuildScopes.cs index 416b1f00..0a762b7f 100644 --- a/src/BuildVision.Contracts/Enums/BuildScopes.cs +++ b/src/BuildVision.Contracts/Enums/BuildScopes.cs @@ -1,10 +1,10 @@ namespace BuildVision.Contracts { - public enum BuildScopes + public enum BuildScope { - BuildScopeSolution = 1, - BuildScopeBatch = 2, - BuildScopeProject = 3, + Solution = 1, + Batch = 2, + Project = 3, Unknown = 4 } } diff --git a/src/BuildVision.Contracts/Exceptions/PropertyNotFoundException.cs b/src/BuildVision.Contracts/Exceptions/PropertyNotFoundException.cs index 527c0ef8..0420d0d5 100644 --- a/src/BuildVision.Contracts/Exceptions/PropertyNotFoundException.cs +++ b/src/BuildVision.Contracts/Exceptions/PropertyNotFoundException.cs @@ -2,18 +2,19 @@ namespace BuildVision.Contracts.Exceptions { + [Serializable] public class PropertyNotFoundException : Exception { + public string PropertyName { get; } + + public Type PropertyType { get; } + + public override string Message => string.Format("Property '{0}' not found in '{1}' type.", PropertyName, PropertyType); + public PropertyNotFoundException(string propertyName, Type type) { PropertyName = propertyName; - Type = type; + PropertyType = type; } - - public string PropertyName { get; } - - public Type Type { get; } - - public override string Message => string.Format("Property '{0}' not found in '{1}' type.", PropertyName, Type); } } diff --git a/src/BuildVision.Contracts/Models/BuildProjectContextEntry.cs b/src/BuildVision.Contracts/Models/BuildProjectContextEntry.cs index 8862f0e7..41b5a3c6 100644 --- a/src/BuildVision.Contracts/Models/BuildProjectContextEntry.cs +++ b/src/BuildVision.Contracts/Models/BuildProjectContextEntry.cs @@ -1,4 +1,4 @@ -using BuildVision.UI.Models; +using BuildVision.UI.Models; using System.Collections.Generic; namespace BuildVision.UI.Contracts @@ -11,7 +11,7 @@ public class BuildProjectContextEntry public string FileName { get; set; } - public IDictionary Properties { get; set; } + public IDictionary Properties { get; } public IProjectItem ProjectItem { get; set; } diff --git a/src/BuildVision.Contracts/Models/ErrorItem.cs b/src/BuildVision.Contracts/Models/ErrorItem.cs index 75e67afe..1b320c2b 100644 --- a/src/BuildVision.Contracts/Models/ErrorItem.cs +++ b/src/BuildVision.Contracts/Models/ErrorItem.cs @@ -107,10 +107,14 @@ public void VerifyValues() } if (LineNumber < 1) + { LineNumber = 1; + } if (ColumnNumber < 1) + { ColumnNumber = 1; + } if (EndLineNumber == 0 && EndColumnNumber == 0) { diff --git a/src/BuildVision.Contracts/Models/IBuildInformationModel.cs b/src/BuildVision.Contracts/Models/IBuildInformationModel.cs index 7e1f9d31..8ed56319 100644 --- a/src/BuildVision.Contracts/Models/IBuildInformationModel.cs +++ b/src/BuildVision.Contracts/Models/IBuildInformationModel.cs @@ -7,9 +7,9 @@ namespace BuildVision.Contracts.Models { public interface IBuildInformationModel : INotifyPropertyChanged { - BuildActions BuildAction { get; set; } + BuildAction BuildAction { get; set; } DateTime? BuildFinishTime { get; set; } - BuildScopes BuildScope { get; set; } + BuildScope BuildScope { get; set; } DateTime? BuildStartTime { get; set; } BuildState CurrentBuildState { get; set; } int ErrorCount { get; set; } diff --git a/src/BuildVision.Contracts/Models/IProjectItem.cs b/src/BuildVision.Contracts/Models/IProjectItem.cs index 369474e4..1b28cbf7 100644 --- a/src/BuildVision.Contracts/Models/IProjectItem.cs +++ b/src/BuildVision.Contracts/Models/IProjectItem.cs @@ -33,9 +33,9 @@ public interface IProjectItem int MessagesCount { get; set; } int ErrorsCount { get; set; } int WarningsCount { get; set; } - ObservableCollection Errors { get; set; } - ObservableCollection Warnings { get; set; } - ObservableCollection Messages { get; set; } + ObservableCollection Errors { get; } + ObservableCollection Warnings { get; } + ObservableCollection Messages { get; } void RaiseBuildElapsedTimeChanged(); void AddErrorItem(ErrorItem errorItem); diff --git a/src/BuildVision.Exports/Providers/IBuildInformationProvider.cs b/src/BuildVision.Exports/Providers/IBuildInformationProvider.cs index e5dc7e5d..f3316d36 100644 --- a/src/BuildVision.Exports/Providers/IBuildInformationProvider.cs +++ b/src/BuildVision.Exports/Providers/IBuildInformationProvider.cs @@ -11,12 +11,12 @@ public interface IBuildInformationProvider IBuildInformationModel BuildInformationModel { get; } ObservableCollection Projects { get; } - void ProjectBuildStarted(IProjectItem projectItem, BuildActions buildAction); - void ProjectBuildFinished(BuildActions buildAction, string projectIdentifier, bool succeess, bool canceled); + void ProjectBuildStarted(IProjectItem projectItem, BuildAction buildAction); + void ProjectBuildFinished(BuildAction buildAction, string projectIdentifier, bool succeess, bool canceled); void ReloadCurrentProjects(); void ResetCurrentProjects(); void BuildFinished(bool success, bool canceled); - void BuildStarted(BuildActions currentBuildAction, BuildScopes scope); + void BuildStarted(BuildAction currentBuildAction, BuildScope scope); void BuildUpdate(); void ResetBuildInformationModel(); } diff --git a/src/BuildVision.Exports/Sevices/ITaskBarInfoService.cs b/src/BuildVision.Exports/Sevices/ITaskBarInfoService.cs index 58f39b8e..d46ca586 100644 --- a/src/BuildVision.Exports/Sevices/ITaskBarInfoService.cs +++ b/src/BuildVision.Exports/Sevices/ITaskBarInfoService.cs @@ -5,6 +5,6 @@ namespace BuildVision.Exports.Services public interface ITaskBarInfoService { void ResetTaskBarInfo(bool ifTaskBarProgressEnabled = true); - void UpdateTaskBarInfo(BuildState buildState, BuildScopes buildScope, int projectsCount, int finishedProjects); + void UpdateTaskBarInfo(BuildState buildState, BuildScope buildScope, int projectsCount, int finishedProjects); } } diff --git a/src/BuildVision.UI/Attributes/DisplayStringAttribute.cs b/src/BuildVision.UI/Attributes/DisplayStringAttribute.cs index ddb5a0e3..348e512a 100644 --- a/src/BuildVision.UI/Attributes/DisplayStringAttribute.cs +++ b/src/BuildVision.UI/Attributes/DisplayStringAttribute.cs @@ -66,7 +66,9 @@ public override bool Equals(object obj) { var dsaObj = obj as DisplayStringAttribute; if (dsaObj == null) + { return false; + } return DisplayString.Equals(dsaObj.DisplayString); } diff --git a/src/BuildVision.UI/Components/ErrorsGrid.xaml.cs b/src/BuildVision.UI/Components/ErrorsGrid.xaml.cs index c6c74857..ed4074c4 100644 --- a/src/BuildVision.UI/Components/ErrorsGrid.xaml.cs +++ b/src/BuildVision.UI/Components/ErrorsGrid.xaml.cs @@ -58,7 +58,9 @@ private void ErrorsGridRowOnMouseLeftButtonUp(object sender, MouseButtonEventArg private void ErrorsGridOnPreviewMouseWheel(object sender, MouseWheelEventArgs e) { if (_errorsGridScrollViewer.ComputedVerticalScrollBarVisibility == Visibility.Visible) + { return; + } e.Handled = true; var eventArg = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta) diff --git a/src/BuildVision.UI/Components/ProjectGrid.xaml.cs b/src/BuildVision.UI/Components/ProjectGrid.xaml.cs index d01e33f3..823dc06c 100644 --- a/src/BuildVision.UI/Components/ProjectGrid.xaml.cs +++ b/src/BuildVision.UI/Components/ProjectGrid.xaml.cs @@ -76,7 +76,9 @@ private void ViewModelOnPropertyChanged(object sender, PropertyChangedEventArgs Grid.SelectedIndex = -1; if (Grid.SelectedIndex == -1) + { Grid.ScrollIntoView(ViewModel.BuildInformationModel.CurrentProject); + } } } @@ -110,7 +112,9 @@ private void DataGridRowDetailsOnMouseLeftButtonDown(object sender, MouseButtonE { // http://stackoverflow.com/questions/6279724/mousedoubleclick-events-dont-bubble/6326181#6326181) if (e.ClickCount == 2) + { e.Handled = true; + } } // Autofocus for RowDetails (without extra mouse click). diff --git a/src/BuildVision.UI/Components/SpinnerControl.xaml.cs b/src/BuildVision.UI/Components/SpinnerControl.xaml.cs index b33786ae..839a2888 100644 --- a/src/BuildVision.UI/Components/SpinnerControl.xaml.cs +++ b/src/BuildVision.UI/Components/SpinnerControl.xaml.cs @@ -240,7 +240,9 @@ protected static void OnIncreaseCommand(Object sender, ExecutedRoutedEventArgs e { var control = sender as SpinnerControl; if (control != null) + { control.OnIncrease(); + } } protected void OnIncrease() @@ -256,7 +258,9 @@ protected static void OnDecreaseCommand(Object sender, ExecutedRoutedEventArgs e { var control = sender as SpinnerControl; if (control != null) + { control.OnDecrease(); + } } protected void OnDecrease() diff --git a/src/BuildVision.UI/Converters/AlternatingRowBackgroundConverter.cs b/src/BuildVision.UI/Converters/AlternatingRowBackgroundConverter.cs index 5af63cd9..86fd46ad 100644 --- a/src/BuildVision.UI/Converters/AlternatingRowBackgroundConverter.cs +++ b/src/BuildVision.UI/Converters/AlternatingRowBackgroundConverter.cs @@ -13,11 +13,12 @@ public class AlternatingRowBackgroundConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { - var backg = value as SolidColorBrush; - if (backg == null) + if (!(value is SolidColorBrush backg)) + { return value; + } - Color color = backg.Color; + var color = backg.Color; int darkerDelta = -15; int r = color.R + darkerDelta; @@ -51,9 +52,20 @@ public object Convert(object value, Type targetType, object parameter, CultureIn g = color.G + lighterDelta; b = color.B + lighterDelta; - if (r > 255) r = 255; - if (g > 255) g = 255; - if (b > 255) b = 255; + if (r > 255) + { + r = 255; + } + + if (g > 255) + { + g = 255; + } + + if (b > 255) + { + b = 255; + } } var newColor = Color.FromArgb(255, (byte)r, (byte)g, (byte)b); diff --git a/src/BuildVision.UI/Converters/BooleanToHiddenConverter.cs b/src/BuildVision.UI/Converters/BooleanToHiddenConverter.cs index f567f678..8b920a78 100644 --- a/src/BuildVision.UI/Converters/BooleanToHiddenConverter.cs +++ b/src/BuildVision.UI/Converters/BooleanToHiddenConverter.cs @@ -17,19 +17,15 @@ public object Convert(object value, Type targetType, object parameter, CultureIn } else if (value is bool?) { - bool? nullable = (bool?)value; - flag = (nullable.HasValue && nullable.Value); + var nullable = (bool?)value; + flag = nullable.HasValue && nullable.Value; } return flag ? Visibility.Hidden : Visibility.Visible; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { - if (value is Visibility) - { - return (Visibility)value == Visibility.Hidden; - } - return false; + return value is Visibility ? (Visibility)value == Visibility.Hidden : (object)false; } } } diff --git a/src/BuildVision.UI/Converters/ColumnWidthConverter.cs b/src/BuildVision.UI/Converters/ColumnWidthConverter.cs index 559bda2e..be9d2595 100644 --- a/src/BuildVision.UI/Converters/ColumnWidthConverter.cs +++ b/src/BuildVision.UI/Converters/ColumnWidthConverter.cs @@ -9,20 +9,13 @@ public class ColumnWidthConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { - double val = (double)value; - - if (double.IsNaN(val)) - return "auto"; - - return val; + var val = (double)value; + return double.IsNaN(val) ? "auto" : (object)val; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { - if (value as string == "auto") - return double.NaN; - - return value; + return value as string == "auto" ? double.NaN : value; } } } diff --git a/src/BuildVision.UI/Converters/DataGridLengthStringConverter.cs b/src/BuildVision.UI/Converters/DataGridLengthStringConverter.cs index 34265bf9..0dfa6aee 100644 --- a/src/BuildVision.UI/Converters/DataGridLengthStringConverter.cs +++ b/src/BuildVision.UI/Converters/DataGridLengthStringConverter.cs @@ -13,12 +13,11 @@ public object Convert(object value, Type targetType, object parameter, CultureIn var val = (DataGridLength)value; if (val.IsAuto) + { return "auto"; + } - if (val.IsStar) - return val.DisplayValue.ToString("0.0") + "*"; - - return val.Value.ToString("0.0"); + return val.IsStar ? val.DisplayValue.ToString("0.0") + "*" : val.Value.ToString("0.0"); } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) @@ -28,10 +27,14 @@ public object ConvertBack(object value, Type targetType, object parameter, Cultu var val = ((string)value).Trim().ToLower(); if (val == "auto") + { return new DataGridLength(1.0, DataGridLengthUnitType.Auto); + } - if (val.EndsWith("*")) + if (val.EndsWith("*", StringComparison.InvariantCulture)) + { return new DataGridLength(double.Parse(val.TrimEnd('*')), DataGridLengthUnitType.Star); + } return new DataGridLength(double.Parse(val)); } diff --git a/src/BuildVision.UI/Converters/ExpanderIsExpandedConverter.cs b/src/BuildVision.UI/Converters/ExpanderIsExpandedConverter.cs index 91f6f032..14e823db 100644 --- a/src/BuildVision.UI/Converters/ExpanderIsExpandedConverter.cs +++ b/src/BuildVision.UI/Converters/ExpanderIsExpandedConverter.cs @@ -11,10 +11,11 @@ public class ExpanderIsExpandedConverter : IMultiValueConverter public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) { var collectionViewGroup = (CollectionViewGroup)values[0]; - var collapsedGroups = values[1] as IList; - if (collapsedGroups == null || collapsedGroups.Count == 0) + if (!(values[1] is IList collapsedGroups) || collapsedGroups.Count == 0) + { return true; + } string groupId = GetGroupIdentifier(collectionViewGroup); bool collapsed = collapsedGroups.Contains(groupId); @@ -28,15 +29,18 @@ public object[] ConvertBack(object value, Type[] targetTypes, object parameter, public static void SaveState(Expander exp, bool collapsed, IList collapsedGroups) { - var collectionViewGroup = exp.DataContext as CollectionViewGroup; - if (collectionViewGroup == null) + if (!(exp.DataContext is CollectionViewGroup collectionViewGroup)) + { return; + } string groupId = GetGroupIdentifier(collectionViewGroup); if (collapsed) { if (!collapsedGroups.Contains(groupId)) + { collapsedGroups.Add(groupId); + } } else { @@ -48,12 +52,11 @@ private static string GetGroupIdentifier(CollectionViewGroup collectionViewGroup { object groupId = collectionViewGroup.Name; if (groupId == null) + { return null; + } - if (groupId is string) - return (string)groupId; - - return groupId.ToString(); + return groupId is string ? (string)groupId : groupId.ToString(); } } } diff --git a/src/BuildVision.UI/Converters/GridColumnSettingsToColumnExampleValueConverter.cs b/src/BuildVision.UI/Converters/GridColumnSettingsToColumnExampleValueConverter.cs index 0be9b2ad..ffbd26da 100644 --- a/src/BuildVision.UI/Converters/GridColumnSettingsToColumnExampleValueConverter.cs +++ b/src/BuildVision.UI/Converters/GridColumnSettingsToColumnExampleValueConverter.cs @@ -21,18 +21,26 @@ public object Convert(object[] values, Type targetType, object parameter, Cultur private static string FormatExample(object example, string stringFormat) { if (example == null) + { return Resources.GridCellNoneTextInBrackets; + } try { if (string.IsNullOrWhiteSpace(stringFormat)) + { return example.ToString(); + } if (example is DateTime) + { return ((DateTime)example).ToString(stringFormat); + } if (example is TimeSpan) + { return ((TimeSpan)example).ToString(stringFormat); + } return string.Format(stringFormat, example); } diff --git a/src/BuildVision.UI/Converters/MultiBindingStringFormatConverter.cs b/src/BuildVision.UI/Converters/MultiBindingStringFormatConverter.cs index aedbb977..1280542b 100644 --- a/src/BuildVision.UI/Converters/MultiBindingStringFormatConverter.cs +++ b/src/BuildVision.UI/Converters/MultiBindingStringFormatConverter.cs @@ -16,7 +16,9 @@ public class MultiBindingStringFormatConverter : IMultiValueConverter public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) { if (values == null || values.Length < 2) + { return string.Empty; + } try { @@ -25,7 +27,7 @@ public object Convert(object[] values, Type targetType, object parameter, Cultur } catch (Exception ex) { - LogManager.ForContext< MultiBindingStringFormatConverter>().Error(ex, "Error during MultiBindingStringFormatConverter."); + LogManager.ForContext().Error(ex, "Error during MultiBindingStringFormatConverter."); return string.Format("", ex.Message); } } diff --git a/src/BuildVision.UI/Converters/NumberToIsPositiveConverter.cs b/src/BuildVision.UI/Converters/NumberToIsPositiveConverter.cs index 076e6aed..46f83c87 100644 --- a/src/BuildVision.UI/Converters/NumberToIsPositiveConverter.cs +++ b/src/BuildVision.UI/Converters/NumberToIsPositiveConverter.cs @@ -10,7 +10,9 @@ public class NumberToIsPositiveConverter : IValueConverter public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (value != null && double.TryParse(value.ToString(), out var val)) + { return val > 0; + } return false; } diff --git a/src/BuildVision.UI/Converters/ObjectsReferencesEqualsConverter.cs b/src/BuildVision.UI/Converters/ObjectsReferencesEqualsConverter.cs index e34707c3..d12cf1b2 100644 --- a/src/BuildVision.UI/Converters/ObjectsReferencesEqualsConverter.cs +++ b/src/BuildVision.UI/Converters/ObjectsReferencesEqualsConverter.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Globalization; using System.Windows.Data; @@ -12,7 +12,9 @@ public object Convert(object[] values, Type targetType, object parameter, Cultur for (int i = 0; i < values.Length - 1; i++) { if (!ReferenceEquals(values[i], values[i + 1])) + { return false; + } } return true; @@ -23,4 +25,4 @@ public object[] ConvertBack(object value, Type[] targetTypes, object parameter, throw new InvalidOperationException(); } } -} \ No newline at end of file +} diff --git a/src/BuildVision.UI/Converters/SubtractConstantConverter.cs b/src/BuildVision.UI/Converters/SubtractConstantConverter.cs index 94f1e477..6873b0b4 100644 --- a/src/BuildVision.UI/Converters/SubtractConstantConverter.cs +++ b/src/BuildVision.UI/Converters/SubtractConstantConverter.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Globalization; using System.Windows.Data; @@ -19,4 +19,4 @@ public object ConvertBack(object value, Type targetType, object parameter, Cultu return null; } } -} \ No newline at end of file +} diff --git a/src/BuildVision.UI/DataGrid/ColumnsManager.cs b/src/BuildVision.UI/DataGrid/ColumnsManager.cs index 2d4811ec..ffde95f2 100644 --- a/src/BuildVision.UI/DataGrid/ColumnsManager.cs +++ b/src/BuildVision.UI/DataGrid/ColumnsManager.cs @@ -68,14 +68,20 @@ public static object GetColumnExampleValue(GridColumnSettings gridColumnSettings public static bool ColumnIsSortable(string propertyName) { if (_nonSortableColumns.Contains(propertyName)) + { return false; + } + return true; } public static bool ColumnIsGroupable(GridColumnSettings gridColumnSettings) { if (_nonGroupableColumns.Contains(gridColumnSettings.PropertyNameId)) + { return false; + } + return true; } @@ -101,7 +107,9 @@ public static void GenerateColumns(ObservableCollection columns, { GridColumnAttribute columnConfiguration = property.GetCustomAttribute(); if (columnConfiguration == null) + { continue; + } string propertyName = property.Name; GridColumnSettings columnSettings; @@ -152,7 +160,9 @@ public static void SyncColumnSettings(ObservableCollection colum string propertyName = column.GetBindedProperty(); var columnSettings = gridSettings.Columns[propertyName]; if (columnSettings == null) + { continue; + } columnSettings.Visible = (column.Visibility == Visibility.Visible); columnSettings.DisplayIndex = column.DisplayIndex; @@ -169,11 +179,15 @@ public static string GetBindedProperty(this DataGridColumn column) { var boundColumn = column as DataGridBoundColumn; if (boundColumn == null) + { return string.Empty; + } var binding = boundColumn.Binding as Binding; if (binding == null) + { return string.Empty; + } return binding.Path.Path; } @@ -211,13 +225,22 @@ private static DataGridBoundColumn CreateColumnForProperty(PropertyInfo property { DataGridBoundColumn column; if (property.PropertyType == typeof(BitmapSource) || property.PropertyType == typeof(ImageSource)) + { column = new DataGridImageColumn(); + } else if (property.PropertyType == typeof(ControlTemplate)) + { column = new DataGridContentControlColumn(); + } else if (property.PropertyType == typeof(bool)) + { column = new DataGridCheckBoxColumn(); + } else + { column = new DataGridTextColumn(); + } + return column; } @@ -266,20 +289,30 @@ private static void InitColumn(DataGridBoundColumn column, GridColumnAttribute c column.Visibility = columnSettings.Visible ? Visibility.Visible : Visibility.Collapsed; if (columnSettings.DisplayIndex != -1) + { column.DisplayIndex = columnSettings.DisplayIndex; + } if (!double.IsNaN(columnSettings.Width)) + { column.Width = new DataGridLength(columnSettings.Width); + } if (columnSettings.ValueStringFormat != null) + { column.Binding.StringFormat = columnSettings.ValueStringFormat; + } if (column.GetBindedProperty() == sortDescription.Property) + { column.SortDirection = sortDescription.Order.ToSystem(); + } string columnName = columnSettings.Header; if (string.IsNullOrEmpty(columnName)) + { columnName = columnConfiguration.Header; + } column.SetValue(DataGridColumnExtensions.NameProperty, columnName); } diff --git a/src/BuildVision.UI/Extensions/EnumerationExtension.cs b/src/BuildVision.UI/Extensions/EnumerationExtension.cs index 26112ff6..bf5ff149 100644 --- a/src/BuildVision.UI/Extensions/EnumerationExtension.cs +++ b/src/BuildVision.UI/Extensions/EnumerationExtension.cs @@ -12,7 +12,9 @@ public class EnumerationExtension : MarkupExtension public EnumerationExtension(Type enumType) { if (enumType == null) + { throw new ArgumentNullException("enumType"); + } SetEnumType(enumType); } @@ -20,12 +22,16 @@ public EnumerationExtension(Type enumType) private void SetEnumType(Type value) { if (_enumType == value) + { return; + } var enumType = Nullable.GetUnderlyingType(value) ?? value; if (enumType.IsEnum == false) + { throw new ArgumentException("Type must be an Enum."); + } _enumType = value; } diff --git a/src/BuildVision.UI/Extensions/TextBlockUtils.cs b/src/BuildVision.UI/Extensions/TextBlockUtils.cs index 7b7bbd96..62713946 100644 --- a/src/BuildVision.UI/Extensions/TextBlockUtils.cs +++ b/src/BuildVision.UI/Extensions/TextBlockUtils.cs @@ -25,7 +25,9 @@ private static void OnAutoTooltipPropertyChanged(DependencyObject obj, Dependenc { var textBlock = obj as TextBlock; if (textBlock == null) + { return; + } if (e.NewValue.Equals(true)) { diff --git a/src/BuildVision.UI/Extensions/VisualHelper.cs b/src/BuildVision.UI/Extensions/VisualHelper.cs index e91ca506..53a97057 100644 --- a/src/BuildVision.UI/Extensions/VisualHelper.cs +++ b/src/BuildVision.UI/Extensions/VisualHelper.cs @@ -19,11 +19,15 @@ public static T FindVisualChild(DependencyObject obj) { DependencyObject child = VisualTreeHelper.GetChild(obj, i); if (child is T) + { return (T)child; + } var childOfChild = FindVisualChild(child); if (childOfChild != null) + { return childOfChild; + } } return null; @@ -41,10 +45,14 @@ public static IEnumerable FindVisualChildren(DependencyObject obj) { DependencyObject child = VisualTreeHelper.GetChild(obj, i); if (child is T) + { yield return (T)child; + } foreach (T childOfChild in FindVisualChildren(child)) + { yield return childOfChild; + } } } } diff --git a/src/BuildVision.UI/Helpers/BuildMessagesFactory.cs b/src/BuildVision.UI/Helpers/BuildMessagesFactory.cs index ca7fdc36..9139e68c 100644 --- a/src/BuildVision.UI/Helpers/BuildMessagesFactory.cs +++ b/src/BuildVision.UI/Helpers/BuildMessagesFactory.cs @@ -58,56 +58,56 @@ private string GetTimeString(DateTime? startTime) } } - private string GetBeginAtString(BuildActions? buildAction) + private string GetBeginAtString(BuildAction? buildAction) { switch (buildAction.Value) { - case BuildActions.BuildActionRebuildAll: + case BuildAction.RebuildAll: return Resources.BuildActionRebuildAll_BeginAtString; - case BuildActions.BuildActionBuild: + case BuildAction.Build: return Resources.BuildActionBuild_BeginAtString; - case BuildActions.BuildActionClean: + case BuildAction.Clean: return Resources.BuildActionClean_BeginAtString; default: throw new ArgumentOutOfRangeException(nameof(buildAction)); } } - private string GetActionName(BuildActions buildAction) + private string GetActionName(BuildAction buildAction) { switch (buildAction) { - case BuildActions.BuildActionRebuildAll: + case BuildAction.RebuildAll: return Resources.BuildActionRebuildAll; - case BuildActions.BuildActionBuild: + case BuildAction.Build: return Resources.BuildActionBuild; - case BuildActions.BuildActionClean: + case BuildAction.Clean: return Resources.BuildActionClean; default: throw new ArgumentOutOfRangeException(nameof(buildAction)); } } - private string GetUnitName(BuildScopes buildScope) + private string GetUnitName(BuildScope buildScope) { string unitName = ""; switch (buildScope) { - case BuildScopes.BuildScopeSolution: + case BuildScope.Solution: unitName = Resources.BuildScopeSolution_UnitName; //if (_labelSettings.ShowSolutionName) //unitName += string.Format(Resources.BuildScopeSolution_SolutionNameTemplate, solutionItem.Name); break; - case BuildScopes.BuildScopeBatch: + case BuildScope.Batch: unitName = Resources.BuildScopeBatch_UnitName; break; - case BuildScopes.BuildScopeProject: + case BuildScope.Project: unitName = Resources.BuildScopeProject_UnitName; // TODO specify name for project? break; @@ -146,7 +146,9 @@ private string GetBuildDoneMajorMessage(IBuildInformationModel buildInformationM var buildScope = buildInformationModel.BuildScope; if (buildInformationModel.BuildFinishTime == null) + { throw new InvalidOperationException(); + } string timeString; try @@ -161,17 +163,17 @@ private string GetBuildDoneMajorMessage(IBuildInformationModel buildInformationM string unitName; switch (buildScope) { - case BuildScopes.BuildScopeSolution: + case BuildScope.Solution: unitName = Resources.BuildScopeSolution_UnitName; //if (_labelSettings.ShowSolutionName) //unitName += string.Format(Resources.BuildScopeSolution_SolutionNameTemplate, solutionItem.Name); break; - case BuildScopes.BuildScopeBatch: + case BuildScope.Batch: unitName = Resources.BuildScopeBatch_UnitName; break; - case BuildScopes.BuildScopeProject: + case BuildScope.Project: unitName = Resources.BuildScopeProject_UnitName; if (_packageSettingsProvider.Settings.BuildMessagesSettings.ShowProjectName) { @@ -237,7 +239,9 @@ private string GetResultName(BuildResultState resultState) private string GetBuildDoneExtraMessage(IBuildInformationModel buildInformationModel) { if (buildInformationModel.BuildStartTime == null || buildInformationModel.BuildFinishTime == null || !_packageSettingsProvider.Settings.BuildMessagesSettings.ShowExtraMessage) + { return string.Empty; + } TimeSpan timeSpan = buildInformationModel.BuildFinishTime.Value.Subtract(buildInformationModel.BuildStartTime.Value); string extraTimePartString = GetExtraTimePartString(timeSpan); diff --git a/src/BuildVision.UI/Models/BuildInformationModel.cs b/src/BuildVision.UI/Models/BuildInformationModel.cs index 1c88d094..3df365a3 100644 --- a/src/BuildVision.UI/Models/BuildInformationModel.cs +++ b/src/BuildVision.UI/Models/BuildInformationModel.cs @@ -78,8 +78,8 @@ public BuildState CurrentBuildState public BuildResultState ResultState => GetBuildResultState(); - private BuildActions _buildAction = BuildActions.Unknown; - public BuildActions BuildAction + private BuildAction _buildAction = BuildAction.Unknown; + public BuildAction BuildAction { get => _buildAction; set @@ -89,8 +89,8 @@ public BuildActions BuildAction } } - private BuildScopes _buildScope = BuildScopes.Unknown; - public BuildScopes BuildScope + private BuildScope _buildScope = BuildScope.Unknown; + public BuildScope BuildScope { get => _buildScope; set => SetProperty(ref _buildScope, value); @@ -132,12 +132,20 @@ private string GetStateIconKey() var resultState = GetBuildResultState(); if (CurrentBuildState == BuildState.InProgress && resultState == BuildResultState.Unknown) { - if (BuildAction == BuildActions.BuildActionRebuildAll) + if (BuildAction == BuildAction.RebuildAll) + { return "Rebuild"; - if (BuildAction == BuildActions.BuildActionClean) + } + + if (BuildAction == BuildAction.Clean) + { return "Clean"; - if (BuildAction == BuildActions.BuildActionBuild) + } + + if (BuildAction == BuildAction.Build) + { return "Build"; + } } if (resultState == BuildResultState.Unknown) @@ -155,47 +163,87 @@ private BuildResultState GetBuildResultState() } else if (CurrentBuildState == BuildState.Cancelled) { - if (BuildAction == BuildActions.BuildActionRebuildAll) + if (BuildAction == BuildAction.RebuildAll) + { return BuildResultState.RebuildCancelled; - if (BuildAction == BuildActions.BuildActionClean) + } + + if (BuildAction == BuildAction.Clean) + { return BuildResultState.CleanCancelled; - if (BuildAction == BuildActions.BuildActionBuild) + } + + if (BuildAction == BuildAction.Build) + { return BuildResultState.BuildCancelled; + } else + { return BuildResultState.Unknown; + } } else if (CurrentBuildState == BuildState.Failed) { - if (BuildAction == BuildActions.BuildActionRebuildAll) + if (BuildAction == BuildAction.RebuildAll) + { return BuildResultState.RebuildFailed; - if (BuildAction == BuildActions.BuildActionClean) + } + + if (BuildAction == BuildAction.Clean) + { return BuildResultState.CleanFailed; - if (BuildAction == BuildActions.BuildActionBuild) + } + + if (BuildAction == BuildAction.Build) + { return BuildResultState.BuildFailed; + } else + { return BuildResultState.Unknown; + } } else if (CurrentBuildState == BuildState.ErrorDone) { - if (BuildAction == BuildActions.BuildActionRebuildAll) + if (BuildAction == BuildAction.RebuildAll) + { return BuildResultState.RebuildErrorDone; - if (BuildAction == BuildActions.BuildActionClean) + } + + if (BuildAction == BuildAction.Clean) + { return BuildResultState.CleanErrorDone; - if (BuildAction == BuildActions.BuildActionBuild) + } + + if (BuildAction == BuildAction.Build) + { return BuildResultState.BuildErrorDone; + } else + { return BuildResultState.Unknown; + } } else if (CurrentBuildState == BuildState.Done) { - if (BuildAction == BuildActions.BuildActionRebuildAll) + if (BuildAction == BuildAction.RebuildAll) + { return BuildResultState.RebuildDone; - if (BuildAction == BuildActions.BuildActionClean) + } + + if (BuildAction == BuildAction.Clean) + { return BuildResultState.CleanDone; - if (BuildAction == BuildActions.BuildActionBuild) + } + + if (BuildAction == BuildAction.Build) + { return BuildResultState.BuildDone; + } else + { return BuildResultState.Unknown; + } } else { @@ -214,8 +262,8 @@ public void ResetState() WarnedProjectsCount = 0; StateMessage = Resources.BuildDoneText_BuildNotStarted; CurrentBuildState = BuildState.NotStarted; - BuildAction = BuildActions.Unknown; - BuildScope = BuildScopes.Unknown; + BuildAction = BuildAction.Unknown; + BuildScope = BuildScope.Unknown; BuildStartTime = null; BuildFinishTime = null; } diff --git a/src/BuildVision.UI/Models/ProjectItem.cs b/src/BuildVision.UI/Models/ProjectItem.cs index d2bcb3fe..7062551a 100644 --- a/src/BuildVision.UI/Models/ProjectItem.cs +++ b/src/BuildVision.UI/Models/ProjectItem.cs @@ -140,10 +140,14 @@ public TimeSpan? BuildElapsedTime get { if (_buildStartTime == null) + { return null; + } if (_buildFinishTime == null) + { return DateTime.Now.Subtract(_buildStartTime.Value); + } return _buildFinishTime.Value.Truncate(TimeSpan.FromSeconds(1)) .Subtract(_buildStartTime.Value.Truncate(TimeSpan.FromSeconds(1))); diff --git a/src/BuildVision.UI/Settings/GridSettingsControl.xaml.cs b/src/BuildVision.UI/Settings/GridSettingsControl.xaml.cs index 603b3833..0b3d31d7 100644 --- a/src/BuildVision.UI/Settings/GridSettingsControl.xaml.cs +++ b/src/BuildVision.UI/Settings/GridSettingsControl.xaml.cs @@ -31,7 +31,9 @@ private void OnDataContextChanged(object sender, DependencyPropertyChangedEventA { // http://stackoverflow.com/questions/15025865/wpf-datagrid-not-exiting-edit-mode if (e.NewValue == null) + { Grid.CommitEdit(); + } } private void OnDialogKeyPendingEvent(object sender, RoutedEventArgs e) @@ -56,20 +58,28 @@ private void GridOnCurrentCellChanged(object sender, EventArgs e) private void GridOnCellEditEnding(object sender, DataGridCellEditEndingEventArgs e) { if (_displayIndexCommiting) + { return; + } if (!ReferenceEquals(e.Column, ColumnDisplayIndex)) + { return; + } if (e.EditAction != DataGridEditAction.Commit) + { return; + } _displayIndexCommiting = true; bool commited = Grid.CommitEdit(DataGridEditingUnit.Row, true); _displayIndexCommiting = false; if (!commited) + { return; + } var editedItem = (GridColumnSettings)e.Row.Item; _newDisplayIndex = editedItem.DisplayIndex; @@ -90,10 +100,14 @@ private void GridOnCellEditEnding(object sender, DataGridCellEditEndingEventArgs foreach (GridColumnSettings item in Grid.Items) { if (ReferenceEquals(item, editedItem)) + { continue; + } if (item.DisplayIndex >= _oldDisplayIndex + 1 && item.DisplayIndex <= _newDisplayIndex) + { item.DisplayIndex -= 1; + } } } else @@ -101,10 +115,14 @@ private void GridOnCellEditEnding(object sender, DataGridCellEditEndingEventArgs foreach (GridColumnSettings item in Grid.Items) { if (ReferenceEquals(item, editedItem)) + { continue; + } if (item.DisplayIndex >= _newDisplayIndex && item.DisplayIndex <= _oldDisplayIndex - 1) + { item.DisplayIndex += 1; + } } } @@ -117,7 +135,9 @@ private void GridOnTargetUpdated(object sender, DataTransferEventArgs e) { var grid = (System.Windows.Controls.DataGrid)sender; if (grid.ItemsSource == null) + { return; + } grid.Items.SortDescriptions.Add(new SortDescription("DisplayIndex", ListSortDirection.Ascending)); diff --git a/src/BuildVision.UI/Settings/Models/BuildMessagesSettings.cs b/src/BuildVision.UI/Settings/Models/BuildMessagesSettings.cs index 0026b644..fb1cbea9 100644 --- a/src/BuildVision.UI/Settings/Models/BuildMessagesSettings.cs +++ b/src/BuildVision.UI/Settings/Models/BuildMessagesSettings.cs @@ -65,7 +65,9 @@ public string BuildBeginMajorMessageStringFormat OnPropertyChanged(nameof(BuildBeginMajorMessageStringFormat)); if (!value.Contains("{0}")) + { throw new FormatException("Format must contain '{0}' argument."); + } string tmp = string.Format(value, "test"); } @@ -83,7 +85,9 @@ public string BuildDoneMajorMessageStringFormat OnPropertyChanged(nameof(BuildDoneMajorMessageStringFormat)); if (!value.Contains("{0}")) + { throw new FormatException("Format must contain '{0}' argument."); + } string tmp = string.Format(value, "test"); } @@ -131,7 +135,9 @@ public string ExtraMessageStringFormat OnPropertyChanged(nameof(ExtraMessageStringFormat)); if (!value.Contains("{0}")) + { throw new FormatException("Format must contain '{0}' argument."); + } var tmp = string.Format(value, "test"); } diff --git a/src/BuildVision.UI/Settings/Models/ControlSettings.cs b/src/BuildVision.UI/Settings/Models/ControlSettings.cs index 0753314a..f73528cf 100644 --- a/src/BuildVision.UI/Settings/Models/ControlSettings.cs +++ b/src/BuildVision.UI/Settings/Models/ControlSettings.cs @@ -28,19 +28,29 @@ private void OnDeserialized(StreamingContext context) private void Init() { if (GeneralSettings == null) + { GeneralSettings = new GeneralSettings(); + } if (WindowSettings == null) + { WindowSettings = new WindowSettings(); + } if (GridSettings == null) + { GridSettings = new GridSettings(); + } if (BuildMessagesSettings == null) + { BuildMessagesSettings = new BuildMessagesSettings(); + } if (ProjectItemSettings == null) + { ProjectItemSettings = new ProjectItemSettings(); + } } } } diff --git a/src/BuildVision.UI/Settings/Models/GridSettings.cs b/src/BuildVision.UI/Settings/Models/GridSettings.cs index b936ffa2..a762410c 100644 --- a/src/BuildVision.UI/Settings/Models/GridSettings.cs +++ b/src/BuildVision.UI/Settings/Models/GridSettings.cs @@ -30,7 +30,9 @@ public IEnumerable SortableColumnsUIList { yield return GridColumnSettings.Empty; foreach (GridColumnSettings column in Columns.Where(x => ColumnsManager.ColumnIsSortable(x.PropertyNameId))) + { yield return column; + } } } @@ -40,7 +42,9 @@ public IEnumerable GroupableColumnsUIList { yield return GridColumnSettings.Empty; foreach (GridColumnSettings column in Columns.Where(ColumnsManager.ColumnIsGroupable)) + { yield return column; + } } } diff --git a/src/BuildVision/Commands/ShowToolWindowCommand.cs b/src/BuildVision/Commands/ShowToolWindowCommand.cs index 691f602e..071dd3e4 100644 --- a/src/BuildVision/Commands/ShowToolWindowCommand.cs +++ b/src/BuildVision/Commands/ShowToolWindowCommand.cs @@ -35,7 +35,9 @@ private static ToolWindowPane ShowToolWindow(AsyncPackage package) // The last flag is set to true so that if the tool window does not exists it will be created. var window = package.FindToolWindow(typeof(BuildVisionPane), 0, true); if (window == null || window.Frame == null) + { throw new InvalidOperationException(Resources.CanNotCreateWindow); + } var windowFrame = (IVsWindowFrame)window.Frame; ErrorHandler.ThrowOnFailure(windowFrame.Show()); diff --git a/src/BuildVision/Core/BuildVisionPane.cs b/src/BuildVision/Core/BuildVisionPane.cs index 5a0ce02e..2002f1f8 100644 --- a/src/BuildVision/Core/BuildVisionPane.cs +++ b/src/BuildVision/Core/BuildVisionPane.cs @@ -102,15 +102,22 @@ private void ViewModel_ShowOptionPage(Type obj) { var asyncPackage = (AsyncPackage)Package; if (obj == typeof(GeneralSettings)) + { asyncPackage.ShowOptionPage(typeof(GeneralSettingsDialogPage)); + } + if (obj == typeof(GridColumnSettings)) + { asyncPackage.ShowOptionPage(typeof(GridSettingsDialogPage)); + } } protected override void OnClose() { if (_controlCreatedSuccessfully) + { _packageSettingsProvider.Save(); + } base.OnClose(); } diff --git a/src/BuildVision/Core/Services.cs b/src/BuildVision/Core/Services.cs index 37efa8b8..8ed77ae0 100644 --- a/src/BuildVision/Core/Services.cs +++ b/src/BuildVision/Core/Services.cs @@ -16,11 +16,20 @@ static Ret GetGlobalService(IServiceProvider provider = null) where T : { Ret ret = null; if (provider != null) + { ret = provider.GetService(typeof(T)) as Ret; + } + if (ret != null) + { return ret; + } + if (UnitTestServiceProvider != null) + { return UnitTestServiceProvider.GetService(typeof(T)) as Ret; + } + return Package.GetGlobalService(typeof(T)) as Ret; } diff --git a/src/BuildVision/Core/SolutionBuildEvents.cs b/src/BuildVision/Core/SolutionBuildEvents.cs index 50804eae..9be3860f 100644 --- a/src/BuildVision/Core/SolutionBuildEvents.cs +++ b/src/BuildVision/Core/SolutionBuildEvents.cs @@ -15,7 +15,7 @@ public class SolutionBuildEvents : IVsUpdateSolutionEvents2, IVsUpdateSolutionEv private readonly ISolutionProvider _solutionProvider; private readonly IBuildInformationProvider _buildInformationProvider; private readonly BuildEvents _buildEvents; - private BuildActions _currentBuildAction; + private BuildAction _currentBuildAction; public SolutionBuildEvents( ISolutionProvider solutionProvider, @@ -38,7 +38,7 @@ public void UpdateSolution_BeginUpdateAction(uint dwAction) private void BuildEvents_OnBuildBegin(vsBuildScope scope, vsBuildAction action) { // We use the action from UpdateSolution_BeginUpdateAction here because it givs closer details on the current action - _buildInformationProvider.BuildStarted(_currentBuildAction, (BuildScopes)scope); + _buildInformationProvider.BuildStarted(_currentBuildAction, (BuildScope)scope); } public int UpdateProjectCfg_Begin(IVsHierarchy pHierProj, IVsCfg pCfgProj, IVsCfg pCfgSln, uint dwAction, ref int pfCancel) diff --git a/src/BuildVision/Extensions/BuildActionsExtensions.cs b/src/BuildVision/Extensions/BuildActionsExtensions.cs index f5346f22..311c2cac 100644 --- a/src/BuildVision/Extensions/BuildActionsExtensions.cs +++ b/src/BuildVision/Extensions/BuildActionsExtensions.cs @@ -5,18 +5,18 @@ namespace BuildVision.Extensions { public static class BuildActionsExtensions { - public static ProjectState GetProjectState(this BuildActions buildAction) + public static ProjectState GetProjectState(this BuildAction buildAction) { switch (buildAction) { - case BuildActions.BuildActionBuild: - case BuildActions.BuildActionRebuildAll: + case BuildAction.Build: + case BuildAction.RebuildAll: return ProjectState.Building; - case BuildActions.BuildActionClean: + case BuildAction.Clean: return ProjectState.Cleaning; - case BuildActions.BuildActionDeploy: + case BuildAction.Deploy: throw new InvalidOperationException("vsBuildActionDeploy not supported"); default: diff --git a/src/BuildVision/Extensions/BuildStateExtensions.cs b/src/BuildVision/Extensions/BuildStateExtensions.cs index 9d57c88f..a0bf0c95 100644 --- a/src/BuildVision/Extensions/BuildStateExtensions.cs +++ b/src/BuildVision/Extensions/BuildStateExtensions.cs @@ -5,7 +5,7 @@ namespace BuildVision.Extensions { public static class BuildStateExtensions { - public static TaskbarItemProgressState ToTaskBarItemProgressState(this BuildState buildState, BuildScopes buildScope) + public static TaskbarItemProgressState ToTaskBarItemProgressState(this BuildState buildState, BuildScope buildScope) { var progressState = TaskbarItemProgressState.Normal; if (buildState == BuildState.Cancelled) @@ -20,7 +20,7 @@ public static TaskbarItemProgressState ToTaskBarItemProgressState(this BuildStat { progressState = TaskbarItemProgressState.None; } - else if (buildScope != BuildScopes.BuildScopeSolution) + else if (buildScope != BuildScope.Solution) { progressState = TaskbarItemProgressState.Indeterminate; } diff --git a/src/BuildVision/Helpers/ProjectExtensions.cs b/src/BuildVision/Helpers/ProjectExtensions.cs index c70f1374..2139453d 100644 --- a/src/BuildVision/Helpers/ProjectExtensions.cs +++ b/src/BuildVision/Helpers/ProjectExtensions.cs @@ -102,25 +102,49 @@ public static IEnumerable GetBuildOutputFilePaths(this Project project, { Configuration targetConfig; if (configuration != null && platform != null) + { targetConfig = project.ConfigurationManager.Item(configuration, platform); + } else + { targetConfig = project.ConfigurationManager.ActiveConfiguration; + } var groups = new List(); if (fileTypes.LocalizedResourceDlls) + { groups.Add(BuildOutputGroup.LocalizedResourceDlls); + } + if (fileTypes.XmlSerializer) + { groups.Add("XmlSerializer"); + } + if (fileTypes.ContentFiles) + { groups.Add(BuildOutputGroup.ContentFiles); + } + if (fileTypes.Built) + { groups.Add(BuildOutputGroup.Built); + } + if (fileTypes.SourceFiles) + { groups.Add(BuildOutputGroup.SourceFiles); + } + if (fileTypes.Symbols) + { groups.Add(BuildOutputGroup.Symbols); + } + if (fileTypes.Documentation) + { groups.Add(BuildOutputGroup.Documentation); + } var filePaths = new List(); foreach (string groupName in groups) @@ -161,7 +185,9 @@ public static string GetFrameworkString(this Project project) { var framMonikerValue = (string)framMonikerProperty.Value; if (string.IsNullOrWhiteSpace(framMonikerValue)) + { return Resources.GridCellNoneText; + } framMonikerValue = framMonikerValue.Replace(",Version=v", " "); return framMonikerValue; @@ -171,7 +197,9 @@ public static string GetFrameworkString(this Project project) var framVersionProperty = project.GetPropertyOrDefault("TargetFrameworkVersion") ?? project.GetPropertyOrDefault("TargetFramework"); if (framVersionProperty == null || framVersionProperty.Value == null) + { return Resources.GridCellNoneText; + } var version = Convert.ToInt32(framVersionProperty.Value); string versionStr; @@ -302,11 +330,15 @@ public static IEnumerable GetFlavourTypes(this Project project) var myType = project.TryGetPropertyValueOrDefault("MyType"); // for VB.NET projects if (myType != null && myType.ToString() != "Empty") + { flavourTypes.Add(myType.ToString()); + } var keyword = project.TryGetPropertyValueOrDefault("keyword"); // for C++ projects if (keyword != null) + { flavourTypes.Add(keyword.ToString()); + } var filteredValues = flavourTypes.Where(str => !string.IsNullOrWhiteSpace(str)).Distinct(); return filteredValues; @@ -350,7 +382,9 @@ public static string GetOutputType(this Project project) { var property = project.GetPropertyOrDefault("OutputType"); if (property == null || property.Value == null) + { return Resources.GridCellNoneText; + } if (!Enum.TryParse(property.Value.ToString(), out prjOutputType outputType)) { @@ -382,7 +416,9 @@ public static string GetExtenderNames(this Project project) { var extenderNames = (object[])project.ExtenderNames; if (extenderNames == null || extenderNames.Length == 0) + { return Resources.GridCellNoneText; + } return string.Join("; ", extenderNames); } @@ -436,7 +472,9 @@ private static string GetProjectTypeFromRegistry(string projectKind, string vers LogManager.ForContext().Warning("Project type is taken from the registry: Kind={ProjectKind}, DTEVersion={Version}, Type={Type}", projectKind, version, type); if (string.IsNullOrWhiteSpace(type)) + { return null; + } _knownProjectTypes[projectKind] = type; return type; @@ -460,10 +498,14 @@ public static string GetRootNamespace(this Project project) public static bool IsDirty(this Project project) { if (project.IsDirty) + { return true; + } if (project.ProjectItems != null && project.ProjectItems.Cast().Any(x => x.ProjectItemIsDirty())) + { return true; + } return false; } @@ -476,17 +518,23 @@ public static string GetTreePath(this Project project, bool includeSelfProjectNa try { if (includeSelfProjectName) + { path.Append(project.Name); + } var parent = project; while (true) { parent = TryGetParentProject(parent); if (parent == null || parent == project) + { break; + } if (path.Length != 0) + { path.Insert(0, '\\'); + } path.Insert(0, parent.Name); } @@ -519,19 +567,25 @@ public static Project GetSubProject(this Project solutionFolder, Func GetSubProjects(this Project solutionFolder) { Project subProject = solutionFolder.ProjectItems.Item(i).SubProject; if (subProject == null) + { continue; + } // If this is another solution folder, do a recursive call, otherwise add if (subProject.Kind == EnvDTEProjectKinds.ProjectKindSolutionFolder) + { list.AddRange(GetSubProjects(subProject)); + } else if (!subProject.IsHidden()) + { list.Add(subProject); + } } return list; @@ -562,17 +622,23 @@ public static bool IsHidden(this Project project) try { if (_hiddenProjectsUniqueNames.Contains(project.UniqueName)) + { return true; + } // Solution Folder. if (project.Kind == EnvDTE.Constants.vsProjectKindSolutionItems) + { return true; + } // If projectIsInitialized == false then NotImplementedException will be occured // in project.FullName or project.FileName getters. bool projectIsInitialized = (project.Object != null); if (projectIsInitialized && project.FullName.EndsWith(".tmp_proj")) + { return true; + } return false; } @@ -588,10 +654,14 @@ public static bool IsProjectHidden(string projectFileName) try { if (_hiddenProjectsUniqueNames.Contains(projectFileName)) + { return true; + } if (projectFileName.EndsWith(".tmp_proj")) + { return true; + } return false; } diff --git a/src/BuildVision/Helpers/PropertiesExtensions.cs b/src/BuildVision/Helpers/PropertiesExtensions.cs index 1f16c172..600c1bba 100644 --- a/src/BuildVision/Helpers/PropertiesExtensions.cs +++ b/src/BuildVision/Helpers/PropertiesExtensions.cs @@ -23,7 +23,9 @@ public static T GetPropertyOrDefault(this Properties properties, string prope { var property = GetPropertyOrDefault(properties, propertyName); if (property == null) + { return null; + } return (T)property.Value; } diff --git a/src/BuildVision/Helpers/SolutionProjectsExtensions.cs b/src/BuildVision/Helpers/SolutionProjectsExtensions.cs index 409e46e0..e6ca27a3 100644 --- a/src/BuildVision/Helpers/SolutionProjectsExtensions.cs +++ b/src/BuildVision/Helpers/SolutionProjectsExtensions.cs @@ -64,12 +64,18 @@ public static IList GetProjects(this Solution solution) { var project = proj as Project; if (project == null) + { continue; + } if (project.Kind == EnvDTEProjectKinds.ProjectKindSolutionFolder) + { list.AddRange(project.GetSubProjects()); + } else if (!project.IsHidden()) + { list.Add(project); + } } return list; } @@ -82,18 +88,24 @@ public static Project GetProject(this Solution solution, Func con { var project = item.Current as Project; if (project == null) + { continue; + } if (project.Kind == EnvDTEProjectKinds.ProjectKindSolutionFolder) { var sub = project.GetSubProject(cond); if (sub != null) + { return sub; + } } else if (!project.IsHidden()) { if (cond(project)) + { return project; + } } } @@ -228,7 +240,9 @@ private static void UpdateNameProperties(Project project, ProjectItem projectIte projectItem.FullName = project.FullName; if (IsIntegrationServicesProject(project, projectItem)) + { AdjustUniqueNameForExtensionProjects(project, projectItem); + } try { diff --git a/src/BuildVision/Helpers/StateConverterHelper.cs b/src/BuildVision/Helpers/StateConverterHelper.cs index 6a942a9c..898e6f21 100644 --- a/src/BuildVision/Helpers/StateConverterHelper.cs +++ b/src/BuildVision/Helpers/StateConverterHelper.cs @@ -5,23 +5,23 @@ namespace BuildVision.Tool.Models { public class StateConverterHelper { - public static BuildActions ConvertSolutionBuildFlagsToBuildAction(uint dwAction, VSSOLNBUILDUPDATEFLAGS solutionFlags) + public static BuildAction ConvertSolutionBuildFlagsToBuildAction(uint dwAction, VSSOLNBUILDUPDATEFLAGS solutionFlags) { if (solutionFlags == (VSSOLNBUILDUPDATEFLAGS.SBF_OPERATION_NONE | VSSOLNBUILDUPDATEFLAGS.SBF_OPERATION_BUILD | VSSOLNBUILDUPDATEFLAGS.SBF_OPERATION_FORCE_UPDATE)) { - return BuildActions.BuildActionRebuildAll; + return BuildAction.RebuildAll; } else if (solutionFlags == (VSSOLNBUILDUPDATEFLAGS.SBF_OPERATION_NONE | VSSOLNBUILDUPDATEFLAGS.SBF_OPERATION_CLEAN)) { - return BuildActions.BuildActionClean; + return BuildAction.Clean; } else if (solutionFlags == (VSSOLNBUILDUPDATEFLAGS.SBF_OPERATION_NONE | VSSOLNBUILDUPDATEFLAGS.SBF_OPERATION_BUILD)) { - return BuildActions.BuildActionBuild; + return BuildAction.Build; } else { - return BuildActions.Unknown; + return BuildAction.Unknown; } } } diff --git a/src/BuildVision/Services/BuildInformationProvider.cs b/src/BuildVision/Services/BuildInformationProvider.cs index 96531b42..025261cb 100644 --- a/src/BuildVision/Services/BuildInformationProvider.cs +++ b/src/BuildVision/Services/BuildInformationProvider.cs @@ -192,7 +192,7 @@ public void Run(CancellationToken cancellationToken) } } - public void BuildStarted(BuildActions buildAction, BuildScopes buildScope) + public void BuildStarted(BuildAction buildAction, BuildScope buildScope) { _currentQueuePosOfBuildingProject = 0; ErrorNavigationService.BuildErrorNavigated = false; @@ -218,9 +218,9 @@ public void BuildStarted(BuildActions buildAction, BuildScopes buildScope) _taskBarInfoService.UpdateTaskBarInfo(BuildInformationModel.CurrentBuildState, BuildInformationModel.BuildScope, Projects.Count, GetFinishedProjectsCount()); } - public void ProjectBuildStarted(IProjectItem projectItem, BuildActions buildAction) + public void ProjectBuildStarted(IProjectItem projectItem, BuildAction buildAction) { - if (BuildInformationModel.BuildAction == BuildActions.BuildActionDeploy) + if (BuildInformationModel.BuildAction == BuildAction.Deploy) { return; } @@ -240,9 +240,9 @@ public void ProjectBuildStarted(IProjectItem projectItem, BuildActions buildActi _taskBarInfoService.UpdateTaskBarInfo(BuildInformationModel.CurrentBuildState, BuildInformationModel.BuildScope, Projects.Count, GetFinishedProjectsCount()); _currentQueuePosOfBuildingProject++; - if (BuildInformationModel.BuildScope == BuildScopes.BuildScopeSolution && - (BuildInformationModel.BuildAction == BuildActions.BuildActionBuild || - BuildInformationModel.BuildAction == BuildActions.BuildActionRebuildAll)) + if (BuildInformationModel.BuildScope == BuildScope.Solution && + (BuildInformationModel.BuildAction == BuildAction.Build || + BuildInformationModel.BuildAction == BuildAction.RebuildAll)) { projInCollection.BuildOrder = _currentQueuePosOfBuildingProject; } @@ -259,9 +259,9 @@ private int GetFinishedProjectsCount() return BuildInformationModel.SucceededProjectsCount + BuildInformationModel.UpToDateProjectsCount + BuildInformationModel.WarnedProjectsCount + BuildInformationModel.FailedProjectsCount; } - public void ProjectBuildFinished(BuildActions buildAction, string projectIdentifier, bool success, bool canceled) + public void ProjectBuildFinished(BuildAction buildAction, string projectIdentifier, bool success, bool canceled) { - if (BuildInformationModel.BuildAction == BuildActions.BuildActionDeploy) + if (BuildInformationModel.BuildAction == BuildAction.Deploy) { return; } @@ -297,8 +297,8 @@ private ProjectState GetProjectState(bool success, bool canceled, IProjectItem c ProjectState projectState; switch (BuildInformationModel.BuildAction) { - case BuildActions.BuildActionBuild: - case BuildActions.BuildActionRebuildAll: + case BuildAction.Build: + case BuildAction.RebuildAll: if (success) { if (_packageSettingsProvider.Settings.GeneralSettings.ShowWarningSignForBuilds && currentProject.WarningsCount > 0) @@ -317,7 +317,7 @@ private ProjectState GetProjectState(bool success, bool canceled, IProjectItem c } break; - case BuildActions.BuildActionClean: + case BuildAction.Clean: projectState = success ? ProjectState.CleanDone : ProjectState.CleanError; break; @@ -341,12 +341,12 @@ public void BuildUpdate() public void BuildFinished(bool success, bool canceled) { - if (BuildInformationModel.BuildAction == BuildActions.BuildActionDeploy) + if (BuildInformationModel.BuildAction == BuildAction.Deploy) { return; } - if (BuildInformationModel.BuildScope == BuildScopes.BuildScopeSolution) + if (BuildInformationModel.BuildScope == BuildScope.Solution) { foreach (var projectItem in Projects) { diff --git a/src/BuildVision/Services/BuildOutputLogger.cs b/src/BuildVision/Services/BuildOutputLogger.cs index 96fb9904..fdc015b7 100644 --- a/src/BuildVision/Services/BuildOutputLogger.cs +++ b/src/BuildVision/Services/BuildOutputLogger.cs @@ -103,7 +103,9 @@ private void EventSource_ErrorRaised(BuildEventArgs e, ErrorLevel errorLevel) try { if (e.BuildEventContext.IsBuildEventContextInvalid()) + { return; + } int projectInstanceId = e.BuildEventContext.ProjectInstanceId; int projectContextId = e.BuildEventContext.ProjectContextId; diff --git a/src/BuildVision/Services/BuildService.cs b/src/BuildVision/Services/BuildService.cs index b47c6efd..a9a5aa3a 100644 --- a/src/BuildVision/Services/BuildService.cs +++ b/src/BuildVision/Services/BuildService.cs @@ -65,10 +65,15 @@ public void BuildSolution() public async System.Threading.Tasks.Task CancelBuildAsync(IBuildInformationModel buildInformationModel) { await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); - if (buildInformationModel.BuildAction == BuildActions.BuildActionClean) + if (buildInformationModel.BuildAction == BuildAction.Clean) + { return; + } + if (buildInformationModel.CurrentBuildState != BuildState.InProgress || _buildCancelled || _buildCancelledInternally) + { return; + } try { @@ -104,7 +109,10 @@ private void SelectProjectInSolutionExplorer(IProjectItem projectItem) var project = Core.Services.Dte2.Solution.GetProject(x => x.UniqueName == projectItem.UniqueName); var item = solutionExplorer.FindHierarchyItem(project); if (item == null) + { throw new ProjectNotFoundException($"Project '{projectItem.UniqueName}' not found in SolutionExplorer."); + } + solutionExplorer.Parent.Activate(); item.Select(vsUISelectionType.vsUISelectionTypeSelect); } @@ -189,8 +197,7 @@ private string GetCopyBuildOutputFilesToClipboardActionMessage(string template, filesListArg = "."; } - string msg = string.Format(template, filesCountArg, filesListArg); - return msg; + return string.Format(template, filesCountArg, filesListArg); } private void RaiseCommand(VSConstants.VSStd97CmdID command) diff --git a/src/BuildVision/Services/ErrorNavigationService.cs b/src/BuildVision/Services/ErrorNavigationService.cs index 6aaa9fc0..22c8151e 100644 --- a/src/BuildVision/Services/ErrorNavigationService.cs +++ b/src/BuildVision/Services/ErrorNavigationService.cs @@ -34,16 +34,24 @@ public void NavigateToErrorItem(ErrorItem errorItem) var project = dte.Solution.GetProject(x => x.FileName == errorItem.ProjectFile); if (project == null) + { throw new ArgumentNullException("project"); + } if (errorItem == null) + { throw new ArgumentNullException("errorItem"); + } if (!errorItem.CanNavigateTo) + { return; + } if (string.IsNullOrEmpty(errorItem.File)) + { return; + } string fullPath; @@ -57,18 +65,24 @@ public void NavigateToErrorItem(ErrorItem errorItem) { var projectItemFile = project.FindProjectItem(errorItem.File); if (projectItemFile == null) + { return; + } fullPath = projectItemFile.Properties.GetPropertyOrDefault("FullPath"); if (fullPath == null) + { throw new KeyNotFoundException("FullPath property not found."); + } } try { var window = project.DTE.ItemOperations.OpenFile(fullPath, EnvDTE.Constants.vsViewKindAny); if (window == null) + { throw new NullReferenceException("Associated window is null reference."); + } window.Activate(); diff --git a/src/BuildVision/Services/PackageSettingsProvider.cs b/src/BuildVision/Services/PackageSettingsProvider.cs index 3b5c1fd0..62e988c1 100644 --- a/src/BuildVision/Services/PackageSettingsProvider.cs +++ b/src/BuildVision/Services/PackageSettingsProvider.cs @@ -36,7 +36,9 @@ public void Save() private void SaveSettings() { if (!_settingsStore.CollectionExists(settingsCategoryName)) + { _settingsStore.CreateCollection(settingsCategoryName); + } var legacySerializer = new LegacyConfigurationSerializer(); var value = legacySerializer.Serialize(Settings); diff --git a/src/BuildVision/Services/SolutionProvider.cs b/src/BuildVision/Services/SolutionProvider.cs index 7dee7e07..25a37df8 100644 --- a/src/BuildVision/Services/SolutionProvider.cs +++ b/src/BuildVision/Services/SolutionProvider.cs @@ -50,7 +50,9 @@ public ISolutionModel GetSolutionModel() private void RefrehSolutionModel() { if (_solutionModel == null) + { _solutionModel = new SolutionModel(); + } try { @@ -95,7 +97,10 @@ private void RefrehSolutionModel() public IEnumerable GetProjects() { if (_solution == null) + { ReloadSolution(); + } + return _solution.GetProjectItems(); } } diff --git a/src/BuildVision/Services/StatusBarNotificationService.cs b/src/BuildVision/Services/StatusBarNotificationService.cs index 346fbf3b..84685775 100644 --- a/src/BuildVision/Services/StatusBarNotificationService.cs +++ b/src/BuildVision/Services/StatusBarNotificationService.cs @@ -27,7 +27,9 @@ public StatusBarNotificationService( public void ShowText(string str) { if (!_packageSettingsProvider.Settings.GeneralSettings.EnableStatusBarOutput) + { return; + } var statusBar = _serviceProvider.GetService(typeof(IVsStatusbar)) as IVsStatusbar; statusBar.FreezeOutput(0); @@ -37,7 +39,9 @@ public void ShowText(string str) public void ShowTextWithFreeze(string str) { if (!_packageSettingsProvider.Settings.GeneralSettings.EnableStatusBarOutput) + { return; + } var statusBar = _serviceProvider.GetService(); statusBar.FreezeOutput(0); diff --git a/src/BuildVision/Services/TaskBarInfoService.cs b/src/BuildVision/Services/TaskBarInfoService.cs index 99105d68..4587ca9d 100644 --- a/src/BuildVision/Services/TaskBarInfoService.cs +++ b/src/BuildVision/Services/TaskBarInfoService.cs @@ -28,7 +28,7 @@ public TaskBarInfoService(IPackageSettingsProvider packageSettingsProvider) _packageSettingsProvider = packageSettingsProvider; } - public void UpdateTaskBarInfo(BuildState buildState, BuildScopes buildScope, int projectsCount, int finishedProjects) + public void UpdateTaskBarInfo(BuildState buildState, BuildScope buildScope, int projectsCount, int finishedProjects) { if (_resetTaskBarInfoCts != null && !_resetTaskBarInfoCts.IsCancellationRequested) { diff --git a/src/BuildVision/Services/WindowStateService.cs b/src/BuildVision/Services/WindowStateService.cs index a84dfdbe..e27fdf5d 100644 --- a/src/BuildVision/Services/WindowStateService.cs +++ b/src/BuildVision/Services/WindowStateService.cs @@ -85,7 +85,9 @@ private void MinimizeToolWindow() var doc = _dte.ActiveDocument; if (doc != null) + { doc.Activate(); + } } private static Window GetWindowInstance(DTE dte, Guid windowGuid) @@ -129,7 +131,10 @@ private void ApplyToolWindowStateAction(WindowState windowState) public void Initialize(ToolWindowPane toolWindowPane) { if (toolWindowPane == null) + { return; + } + if (_window == null || _windowFrame == null) { ThreadHelper.ThrowIfNotOnUIThread(); @@ -138,7 +143,9 @@ public void Initialize(ToolWindowPane toolWindowPane) _windowFrame = (IVsWindowFrame)toolWindowPane.Frame; _window = GetWindowInstance(_dte, typeof(BuildVisionPane).GUID); if (_window == null) + { throw new InvalidOperationException("Unable to get Window instance."); + } } } diff --git a/src/BuildVision/Views/Settings/SettingsDialogPage.cs b/src/BuildVision/Views/Settings/SettingsDialogPage.cs index 700f3999..38c95de6 100644 --- a/src/BuildVision/Views/Settings/SettingsDialogPage.cs +++ b/src/BuildVision/Views/Settings/SettingsDialogPage.cs @@ -36,10 +36,15 @@ protected override void OnActivate(CancelEventArgs e) _packageSettingsProvider = Package.GetGlobalService(typeof(IPackageSettingsProvider)) as IPackageSettingsProvider; Assumes.Present(_packageSettingsProvider); if (_editSettings == null) + { _editSettings = Settings.Clone(); + } if (_ctrl.DataContext == null) + { _ctrl.DataContext = _editSettings; + } + base.OnActivate(e); } @@ -59,7 +64,9 @@ protected override void OnClosed(EventArgs e) { _editSettings = null; if (_ctrl != null) + { _ctrl.DataContext = null; + } if (_notifySettingsChangedOnce) { diff --git a/test/BuildVision.UnitTests/BuildInformationModelTests.cs b/test/BuildVision.UnitTests/BuildInformationModelTests.cs index abcb0a46..47c444e0 100644 --- a/test/BuildVision.UnitTests/BuildInformationModelTests.cs +++ b/test/BuildVision.UnitTests/BuildInformationModelTests.cs @@ -26,7 +26,7 @@ public void SetBuildAction_ShouldTrigger_PropertyChanged_ForStateIconKey() var sut = new BuildInformationModel(); using (var monitoredSut = sut.Monitor()) { - sut.BuildAction = BuildActions.BuildActionBuild; + sut.BuildAction = BuildAction.Build; monitoredSut.Should().RaisePropertyChangeFor(x => x.BuildAction); monitoredSut.Should().RaisePropertyChangeFor(x => x.StateIconKey); @@ -54,11 +54,11 @@ public void StateIconKey_ForNonStartedProject_ShouldBe_StandBy() } [Theory] - [InlineData(BuildActions.BuildActionRebuildAll, "Rebuild")] - [InlineData(BuildActions.BuildActionBuild, "Build")] - [InlineData(BuildActions.BuildActionClean, "Clean")] - [InlineData(BuildActions.BuildActionDeploy, "StandBy")] - public void StateIconKey_For_InProgressState_ShouldBe_RightStateDependingOnAction(BuildActions buildAction, string expectedStateKey) + [InlineData(BuildAction.RebuildAll, "Rebuild")] + [InlineData(BuildAction.Build, "Build")] + [InlineData(BuildAction.Clean, "Clean")] + [InlineData(BuildAction.Deploy, "StandBy")] + public void StateIconKey_For_InProgressState_ShouldBe_RightStateDependingOnAction(BuildAction buildAction, string expectedStateKey) { var buildInformationModel = new BuildInformationModel(); buildInformationModel.CurrentBuildState = BuildState.InProgress; @@ -67,11 +67,11 @@ public void StateIconKey_For_InProgressState_ShouldBe_RightStateDependingOnActio } [Theory] - [InlineData(BuildActions.BuildActionRebuildAll, "RebuildDone")] - [InlineData(BuildActions.BuildActionBuild, "BuildDone")] - [InlineData(BuildActions.BuildActionClean, "CleanDone")] - [InlineData(BuildActions.BuildActionDeploy, "StandBy")] - public void StateIconKey_For_InDoneState_ShouldBe_RightStateDependingOnAction(BuildActions buildAction, string expectedStateKey) + [InlineData(BuildAction.RebuildAll, "RebuildDone")] + [InlineData(BuildAction.Build, "BuildDone")] + [InlineData(BuildAction.Clean, "CleanDone")] + [InlineData(BuildAction.Deploy, "StandBy")] + public void StateIconKey_For_InDoneState_ShouldBe_RightStateDependingOnAction(BuildAction buildAction, string expectedStateKey) { var buildInformationModel = new BuildInformationModel(); buildInformationModel.CurrentBuildState = BuildState.Done; @@ -80,11 +80,11 @@ public void StateIconKey_For_InDoneState_ShouldBe_RightStateDependingOnAction(Bu } [Theory] - [InlineData(BuildActions.BuildActionRebuildAll, "RebuildFailed")] - [InlineData(BuildActions.BuildActionBuild, "BuildFailed")] - [InlineData(BuildActions.BuildActionClean, "CleanFailed")] - [InlineData(BuildActions.BuildActionDeploy, "StandBy")] - public void StateIconKey_For_InFailedState_ShouldBe_RightStateDependingOnAction(BuildActions buildAction, string expectedStateKey) + [InlineData(BuildAction.RebuildAll, "RebuildFailed")] + [InlineData(BuildAction.Build, "BuildFailed")] + [InlineData(BuildAction.Clean, "CleanFailed")] + [InlineData(BuildAction.Deploy, "StandBy")] + public void StateIconKey_For_InFailedState_ShouldBe_RightStateDependingOnAction(BuildAction buildAction, string expectedStateKey) { var buildInformationModel = new BuildInformationModel(); buildInformationModel.CurrentBuildState = BuildState.Failed; @@ -93,11 +93,11 @@ public void StateIconKey_For_InFailedState_ShouldBe_RightStateDependingOnAction( } [Theory] - [InlineData(BuildActions.BuildActionRebuildAll, "RebuildErrorDone")] - [InlineData(BuildActions.BuildActionBuild, "BuildErrorDone")] - [InlineData(BuildActions.BuildActionClean, "CleanErrorDone")] - [InlineData(BuildActions.BuildActionDeploy, "StandBy")] - public void StateIconKey_For_InErrorDoneState_ShouldBe_RightStateDependingOnAction(BuildActions buildAction, string expectedStateKey) + [InlineData(BuildAction.RebuildAll, "RebuildErrorDone")] + [InlineData(BuildAction.Build, "BuildErrorDone")] + [InlineData(BuildAction.Clean, "CleanErrorDone")] + [InlineData(BuildAction.Deploy, "StandBy")] + public void StateIconKey_For_InErrorDoneState_ShouldBe_RightStateDependingOnAction(BuildAction buildAction, string expectedStateKey) { var buildInformationModel = new BuildInformationModel(); buildInformationModel.CurrentBuildState = BuildState.ErrorDone; @@ -106,11 +106,11 @@ public void StateIconKey_For_InErrorDoneState_ShouldBe_RightStateDependingOnActi } [Theory] - [InlineData(BuildActions.BuildActionRebuildAll, "RebuildCancelled")] - [InlineData(BuildActions.BuildActionBuild, "BuildCancelled")] - [InlineData(BuildActions.BuildActionClean, "CleanCancelled")] - [InlineData(BuildActions.BuildActionDeploy, "StandBy")] - public void StateIconKey_For_InCancelledState_ShouldBe_RightStateDependingOnAction(BuildActions buildAction, string expectedStateKey) + [InlineData(BuildAction.RebuildAll, "RebuildCancelled")] + [InlineData(BuildAction.Build, "BuildCancelled")] + [InlineData(BuildAction.Clean, "CleanCancelled")] + [InlineData(BuildAction.Deploy, "StandBy")] + public void StateIconKey_For_InCancelledState_ShouldBe_RightStateDependingOnAction(BuildAction buildAction, string expectedStateKey) { var buildInformationModel = new BuildInformationModel(); buildInformationModel.CurrentBuildState = BuildState.Cancelled; From 764e267a0c5faf34ce867a8f68662b26f3db3a87 Mon Sep 17 00:00:00 2001 From: Stefan Kert Date: Sat, 27 Apr 2019 08:54:01 +0200 Subject: [PATCH 071/100] Fixed some warnings Fixed wrong version displayed --- src/BuildVision.Common/AppVersionInfo.cs | 16 ++++---- .../Extensions/DateTimeExtensions.cs | 7 +--- src/BuildVision.Common/Logging/Log.cs | 13 ------- .../ObservableCollectionExtensions.cs | 16 -------- .../Properties/GlobalSuppressions.cs | 9 +++++ .../PropertyColumnSorter.cs | 3 +- .../Properties/GlobalSuppressions.cs | 8 ++++ src/BuildVision.UI/BuildVision.UI.csproj | 1 + .../Properties/GlobalSuppressions.cs | 37 ++++++++++++++++++ src/BuildVision/BuildVision.csproj | 3 +- src/BuildVision/Core/Services.cs | 6 +++ .../Extensions/IServiceProviderExtensions.cs | 2 + .../Helpers/SolutionProjectsExtensions.cs | 36 ++++------------- .../IWindowStateService.cs | 1 - .../Properties/GlobalSuppressions.cs | 36 +++++++++++++++++ .../Services/BuildInformationProvider.cs | 13 ++----- src/BuildVision/Services/BuildService.cs | 39 ++++++++++--------- .../Services/ErrorNavigationService.cs | 14 ++----- src/BuildVision/Services/SolutionProvider.cs | 8 +--- .../Services/StatusBarNotificationService.cs | 19 ++++----- .../Services/TaskBarInfoService.cs | 19 ++++++++- 21 files changed, 177 insertions(+), 129 deletions(-) delete mode 100644 src/BuildVision.Common/Logging/Log.cs delete mode 100644 src/BuildVision.Common/ObservableCollectionExtensions.cs create mode 100644 src/BuildVision.Common/Properties/GlobalSuppressions.cs create mode 100644 src/BuildVision.Contracts/Properties/GlobalSuppressions.cs create mode 100644 src/BuildVision.UI/Properties/GlobalSuppressions.cs rename src/BuildVision/{Services => Interfaces}/IWindowStateService.cs (99%) create mode 100644 src/BuildVision/Properties/GlobalSuppressions.cs diff --git a/src/BuildVision.Common/AppVersionInfo.cs b/src/BuildVision.Common/AppVersionInfo.cs index c993da81..33295b32 100644 --- a/src/BuildVision.Common/AppVersionInfo.cs +++ b/src/BuildVision.Common/AppVersionInfo.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics; using System.IO; using System.Reflection; @@ -12,12 +13,11 @@ public class AppVersionInfo public AppVersionInfo() { - Assembly assembly = Assembly.GetExecutingAssembly(); - AssemblyName assemblyName = assembly.GetName(); - Version version = assemblyName.Version; + var assembly = Assembly.GetExecutingAssembly(); + var versionInfo = FileVersionInfo.GetVersionInfo(assembly.Location); - AppVersion = version.ToString(3); - BuildVersion = version.ToString(4); + AppVersion = new Version(versionInfo.ProductVersion).ToString(); + BuildVersion = new Version(versionInfo.FileVersion).ToString(); BuildDateTime = RetrieveLinkerTimestamp(assembly); } @@ -26,7 +26,7 @@ public AppVersionInfo() /// private static DateTime RetrieveLinkerTimestamp(Assembly assembly) { - string filePath = assembly.Location; + var filePath = assembly.Location; const int PeHeaderOffset = 60; const int LinkerTimestampOffset = 8; var buffer = new byte[2048]; @@ -45,8 +45,8 @@ private static DateTime RetrieveLinkerTimestamp(Assembly assembly) } } - int i = BitConverter.ToInt32(buffer, PeHeaderOffset); - int secondsSince1970 = BitConverter.ToInt32(buffer, i + LinkerTimestampOffset); + var i = BitConverter.ToInt32(buffer, PeHeaderOffset); + var secondsSince1970 = BitConverter.ToInt32(buffer, i + LinkerTimestampOffset); var dt = new DateTime(1970, 1, 1, 0, 0, 0); dt = dt.AddSeconds(secondsSince1970); dt = dt.AddHours(TimeZone.CurrentTimeZone.GetUtcOffset(dt).Hours); diff --git a/src/BuildVision.Common/Extensions/DateTimeExtensions.cs b/src/BuildVision.Common/Extensions/DateTimeExtensions.cs index 62aa887b..6d789e96 100644 --- a/src/BuildVision.Common/Extensions/DateTimeExtensions.cs +++ b/src/BuildVision.Common/Extensions/DateTimeExtensions.cs @@ -6,12 +6,7 @@ public static class DateTimeExtensions { public static DateTime Truncate(this DateTime dateTime, TimeSpan timeSpan) { - if (timeSpan <= TimeSpan.Zero) - { - return dateTime; - } - - return dateTime.AddTicks(-(dateTime.Ticks % timeSpan.Ticks)); + return timeSpan <= TimeSpan.Zero ? dateTime : dateTime.AddTicks(-(dateTime.Ticks % timeSpan.Ticks)); } } } diff --git a/src/BuildVision.Common/Logging/Log.cs b/src/BuildVision.Common/Logging/Log.cs deleted file mode 100644 index 0eff06fb..00000000 --- a/src/BuildVision.Common/Logging/Log.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using Serilog; - -namespace BuildVision.Common.Logging -{ - public static class Log - { - private static Lazy Logger { get; } = new Lazy(() => LogManager.ForContext(typeof(Log))); - - public static void Assert(bool condition, string messageTemplate) - => Logger.Value.Assert(condition, messageTemplate); - } -} diff --git a/src/BuildVision.Common/ObservableCollectionExtensions.cs b/src/BuildVision.Common/ObservableCollectionExtensions.cs deleted file mode 100644 index 98f2b01a..00000000 --- a/src/BuildVision.Common/ObservableCollectionExtensions.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.Collections.Generic; -using System.Collections.ObjectModel; - -namespace BuildVision.Common -{ - public static class ObservableCollectionExtensions - { - public static void AddRange(this ObservableCollection collection, IEnumerable range) - { - foreach (T item in range) - { - collection.Add(item); - } - } - } -} diff --git a/src/BuildVision.Common/Properties/GlobalSuppressions.cs b/src/BuildVision.Common/Properties/GlobalSuppressions.cs new file mode 100644 index 00000000..d9509ec9 --- /dev/null +++ b/src/BuildVision.Common/Properties/GlobalSuppressions.cs @@ -0,0 +1,9 @@ + +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1305:Specify IFormatProvider", Justification = "", Scope = "member", Target = "~M:BuildVision.Common.FilePathHelper.ShortenPath(System.String,System.Int32)~System.String")] + +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.Common.Diagnostics.SessionTelemetry.#ctor")] diff --git a/src/BuildVision.Common/PropertyColumnSorter.cs b/src/BuildVision.Common/PropertyColumnSorter.cs index 849ab477..2ba96d16 100644 --- a/src/BuildVision.Common/PropertyColumnSorter.cs +++ b/src/BuildVision.Common/PropertyColumnSorter.cs @@ -6,8 +6,7 @@ namespace BuildVision.Common { - public class PropertyColumnSorter : IComparer - where T : class + public class PropertyColumnSorter : IComparer where T : class { private readonly int _direction; private readonly PropertyInfo _propertyInfo; diff --git a/src/BuildVision.Contracts/Properties/GlobalSuppressions.cs b/src/BuildVision.Contracts/Properties/GlobalSuppressions.cs new file mode 100644 index 00000000..99acc86e --- /dev/null +++ b/src/BuildVision.Contracts/Properties/GlobalSuppressions.cs @@ -0,0 +1,8 @@ + +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1305:Specify IFormatProvider", Justification = "", Scope = "member", Target = "~P:BuildVision.Contracts.Exceptions.PropertyNotFoundException.Message")] + diff --git a/src/BuildVision.UI/BuildVision.UI.csproj b/src/BuildVision.UI/BuildVision.UI.csproj index fb253e5e..310f45fa 100644 --- a/src/BuildVision.UI/BuildVision.UI.csproj +++ b/src/BuildVision.UI/BuildVision.UI.csproj @@ -95,6 +95,7 @@ + diff --git a/src/BuildVision.UI/Properties/GlobalSuppressions.cs b/src/BuildVision.UI/Properties/GlobalSuppressions.cs new file mode 100644 index 00000000..80b7b6d5 --- /dev/null +++ b/src/BuildVision.UI/Properties/GlobalSuppressions.cs @@ -0,0 +1,37 @@ + +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1305:Specify IFormatProvider", Justification = "", Scope = "member", Target = "~F:BuildVision.UI.Components.SpinnerControl.FormattedValuePropertyKey")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1305:Specify IFormatProvider", Justification = "", Scope = "member", Target = "~F:BuildVision.UI.Extensions.VectorResources._baseUri")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1305:Specify IFormatProvider", Justification = "", Scope = "member", Target = "~M:BuildVision.UI.Converters.DataGridLengthStringConverter.Convert(System.Object,System.Type,System.Object,System.Globalization.CultureInfo)~System.Object")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1305:Specify IFormatProvider", Justification = "", Scope = "member", Target = "~M:BuildVision.UI.Converters.DataGridLengthStringConverter.ConvertBack(System.Object,System.Type,System.Object,System.Globalization.CultureInfo)~System.Object")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1305:Specify IFormatProvider", Justification = "", Scope = "member", Target = "~M:BuildVision.UI.Converters.GridColumnSettingsToColumnExampleValueConverter.FormatExample(System.Object,System.String)~System.String")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1305:Specify IFormatProvider", Justification = "", Scope = "member", Target = "~M:BuildVision.UI.Converters.MultiBindingStringFormatConverter.Convert(System.Object[],System.Type,System.Object,System.Globalization.CultureInfo)~System.Object")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1305:Specify IFormatProvider", Justification = "", Scope = "member", Target = "~M:BuildVision.UI.Converters.SubtractConstantConverter.Convert(System.Object,System.Type,System.Object,System.Globalization.CultureInfo)~System.Object")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1305:Specify IFormatProvider", Justification = "", Scope = "member", Target = "~M:BuildVision.UI.Helpers.BuildMessagesFactory.GetBuildBeginMajorMessage(BuildVision.Contracts.Models.IBuildInformationModel)~System.String")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1305:Specify IFormatProvider", Justification = "", Scope = "member", Target = "~M:BuildVision.UI.Helpers.BuildMessagesFactory.GetBuildDoneExtraMessage(BuildVision.Contracts.Models.IBuildInformationModel)~System.String")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1305:Specify IFormatProvider", Justification = "", Scope = "member", Target = "~M:BuildVision.UI.Helpers.BuildMessagesFactory.GetBuildDoneMajorMessage(BuildVision.Contracts.Models.IBuildInformationModel)~System.String")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1305:Specify IFormatProvider", Justification = "", Scope = "member", Target = "~M:BuildVision.UI.Helpers.BuildMessagesFactory.GetExtraTimePartString(System.TimeSpan)~System.String")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1305:Specify IFormatProvider", Justification = "", Scope = "member", Target = "~M:BuildVision.UI.Helpers.BuildMessagesFactory.GetMainString(BuildVision.Contracts.Models.IBuildInformationModel)~System.String")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1305:Specify IFormatProvider", Justification = "", Scope = "member", Target = "~M:BuildVision.UI.Helpers.BuildMessagesFactory.GetTimeString(System.Nullable{System.DateTime})~System.String")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1305:Specify IFormatProvider", Justification = "", Scope = "member", Target = "~M:BuildVision.UI.ViewModels.BuildVisionPaneViewModel.CopyErrorMessageToClipboard(BuildVision.UI.Models.ProjectItem)")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1305:Specify IFormatProvider", Justification = "", Scope = "member", Target = "~P:BuildVision.UI.Modelss.GridColumnAttribute.DateTimeExampleValue")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1305:Specify IFormatProvider", Justification = "", Scope = "member", Target = "~P:BuildVision.UI.Modelss.GridColumnAttribute.TimeSpanExampleValue")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1305:Specify IFormatProvider", Justification = "", Scope = "member", Target = "~P:BuildVision.UI.Settings.Models.BuildMessagesSettings.BuildBeginMajorMessageStringFormat")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1305:Specify IFormatProvider", Justification = "", Scope = "member", Target = "~P:BuildVision.UI.Settings.Models.BuildMessagesSettings.BuildDoneMajorMessageStringFormat")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1305:Specify IFormatProvider", Justification = "", Scope = "member", Target = "~P:BuildVision.UI.Settings.Models.BuildMessagesSettings.DateTimeFormat")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1305:Specify IFormatProvider", Justification = "", Scope = "member", Target = "~P:BuildVision.UI.Settings.Models.BuildMessagesSettings.ExtraMessageStringFormat")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1305:Specify IFormatProvider", Justification = "", Scope = "member", Target = "~P:BuildVision.UI.Settings.Models.BuildMessagesSettings.TimeSpanFormat")] + +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.UI.Converters.DataGridLengthStringConverter.ConvertBack(System.Object,System.Type,System.Object,System.Globalization.CultureInfo)~System.Object")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.UI.Converters.GridColumnSettingsToColumnExampleValueConverter.FormatExample(System.Object,System.String)~System.String")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.UI.Converters.MultiBindingStringFormatConverter.Convert(System.Object[],System.Type,System.Object,System.Globalization.CultureInfo)~System.Object")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.UI.DataGrid.ColumnsManager.GenerateColumns(System.Collections.ObjectModel.ObservableCollection{System.Windows.Controls.DataGridColumn},BuildVision.UI.Settings.Models.GridSettings)")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.UI.DataGrid.ColumnsManager.SyncColumnSettings(System.Collections.ObjectModel.ObservableCollection{System.Windows.Controls.DataGridColumn},BuildVision.UI.Settings.Models.GridSettings)")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.UI.ErrorsGrid.ErrorsGridRowOnMouseLeftButtonUp(System.Object,System.Windows.Input.MouseButtonEventArgs)")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.UI.Extensions.VectorResources.TryGet(System.String,System.String)~System.Windows.Controls.ControlTemplate")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.UI.ViewModels.BuildVisionPaneViewModel.CopyErrorMessageToClipboard(BuildVision.UI.Models.ProjectItem)")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.UI.ViewModels.BuildVisionPaneViewModel.OpenContainingFolder")] diff --git a/src/BuildVision/BuildVision.csproj b/src/BuildVision/BuildVision.csproj index 6464240e..2a4ed336 100644 --- a/src/BuildVision/BuildVision.csproj +++ b/src/BuildVision/BuildVision.csproj @@ -86,9 +86,10 @@ + - + diff --git a/src/BuildVision/Core/Services.cs b/src/BuildVision/Core/Services.cs index 8ed77ae0..523b6873 100644 --- a/src/BuildVision/Core/Services.cs +++ b/src/BuildVision/Core/Services.cs @@ -45,6 +45,12 @@ public static IVsSolution GetSolution(this IServiceProvider provider) return GetGlobalService(provider); } + public static Solution GetDteSolution(this IServiceProvider provider) + { + var ret = provider.GetService(typeof(DTE)) as DTE2; + return ret.Solution; + } + public static IVsSolution GetSolution() { return GetGlobalService(); diff --git a/src/BuildVision/Extensions/IServiceProviderExtensions.cs b/src/BuildVision/Extensions/IServiceProviderExtensions.cs index 12221b05..0e53e381 100644 --- a/src/BuildVision/Extensions/IServiceProviderExtensions.cs +++ b/src/BuildVision/Extensions/IServiceProviderExtensions.cs @@ -1,4 +1,6 @@ using System; +using BuildVision.Common.Logging; +using Serilog; namespace BuildVision.Extensions { diff --git a/src/BuildVision/Helpers/SolutionProjectsExtensions.cs b/src/BuildVision/Helpers/SolutionProjectsExtensions.cs index e6ca27a3..1321f323 100644 --- a/src/BuildVision/Helpers/SolutionProjectsExtensions.cs +++ b/src/BuildVision/Helpers/SolutionProjectsExtensions.cs @@ -80,36 +80,16 @@ public static IList GetProjects(this Solution solution) return list; } - public static Project GetProject(this Solution solution, Func cond) + public static Project FirstOrDefaultProject(this Solution solution, Func cond) { - var projects = solution.Projects; - var item = projects.GetEnumerator(); - while (item.MoveNext()) - { - var project = item.Current as Project; - if (project == null) - { - continue; - } - - if (project.Kind == EnvDTEProjectKinds.ProjectKindSolutionFolder) - { - var sub = project.GetSubProject(cond); - if (sub != null) - { - return sub; - } - } - else if (!project.IsHidden()) - { - if (cond(project)) - { - return project; - } - } - } + var projects = solution.GetProjects(); + return projects.FirstOrDefault(cond); + } - return null; + public static Project FirstProject(this Solution solution, Func cond) + { + var projects = solution.GetProjects(); + return projects.First(cond); } public static IList GetProjectItems(this Solution solution) diff --git a/src/BuildVision/Services/IWindowStateService.cs b/src/BuildVision/Interfaces/IWindowStateService.cs similarity index 99% rename from src/BuildVision/Services/IWindowStateService.cs rename to src/BuildVision/Interfaces/IWindowStateService.cs index dc2a4b3d..a9d38921 100644 --- a/src/BuildVision/Services/IWindowStateService.cs +++ b/src/BuildVision/Interfaces/IWindowStateService.cs @@ -1,6 +1,5 @@ using BuildVision.UI.Settings.Models.ToolWindow; using Microsoft.VisualStudio.Shell; - namespace BuildVision.Tool.Building { public interface IWindowStateService diff --git a/src/BuildVision/Properties/GlobalSuppressions.cs b/src/BuildVision/Properties/GlobalSuppressions.cs new file mode 100644 index 00000000..1d0c218f --- /dev/null +++ b/src/BuildVision/Properties/GlobalSuppressions.cs @@ -0,0 +1,36 @@ + +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1305:Specify IFormatProvider", Justification = "", Scope = "member", Target = "~M:BuildVision.Helpers.ProjectExtensions.GetFrameworkString(EnvDTE.Project)~System.String")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1305:Specify IFormatProvider", Justification = "", Scope = "member", Target = "~M:BuildVision.Helpers.ProjectExtensions.GetProjectTypeFromRegistry(System.String,System.String)~System.String")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1305:Specify IFormatProvider", Justification = "", Scope = "member", Target = "~M:BuildVision.Tool.Building.BuildService.GetCopyBuildOutputFilesToClipboardActionMessage(System.String,System.String[])~System.String")] + +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.Core.BuildInformationProvider.BuildOutputLogger_OnErrorRaised(BuildVision.UI.Contracts.BuildProjectContextEntry,System.Object,BuildVision.Contracts.ErrorLevel)")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.Core.BuildInformationProvider.ProjectBuildStarted(BuildVision.UI.Models.IProjectItem,BuildVision.Contracts.BuildAction)")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.Core.SolutionProvider.RefrehSolutionModel")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.Helpers.ProjectExtensions.GetExtenderNames(EnvDTE.Project)~System.String")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.Helpers.ProjectExtensions.GetFlavourTypes(EnvDTE.Project)~System.Collections.Generic.IEnumerable{System.String}")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.Helpers.ProjectExtensions.GetFrameworkString(EnvDTE.Project)~System.String")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.Helpers.ProjectExtensions.GetLanguageName(EnvDTE.Project)~System.String")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.Helpers.ProjectExtensions.GetOutputType(EnvDTE.Project)~System.String")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.Helpers.ProjectExtensions.GetProjectTypeFromRegistry(System.String,System.String)~System.String")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.Helpers.ProjectExtensions.GetTreePath(EnvDTE.Project,System.Boolean)~System.String")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.Helpers.ProjectExtensions.IsHidden(EnvDTE.Project)~System.Boolean")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.Helpers.ProjectExtensions.IsProjectHidden(System.String)~System.Boolean")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.Helpers.ProjectExtensions.TryGetParentProject(EnvDTE.Project)~EnvDTE.Project")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.Helpers.PropertiesExtensions.TryGetPropertyValueOrDefault(EnvDTE.Properties,System.String)~System.Object")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.Helpers.SolutionProjectsExtensions.GetProjectItems(EnvDTE.Solution)~System.Collections.Generic.IList{BuildVision.UI.Models.ProjectItem}")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.Helpers.SolutionProjectsExtensions.ToSolutionBuildState(EnvDTE.Solution)~BuildVision.Core.SolutionModel")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.Helpers.SolutionProjectsExtensions.UpdateNameProperties(EnvDTE.Project,BuildVision.UI.Models.ProjectItem)")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.Helpers.SolutionProjectsExtensions.UpdateProperties(EnvDTE.Project,BuildVision.UI.Models.ProjectItem,System.String,System.String)")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.Services.ErrorNavigationService.NavigateToErrorItem(BuildVision.Contracts.ErrorItem)")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.Tool.Building.BuildOutputLogger.Attach")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.Tool.Building.BuildOutputLogger.EventSource_ErrorRaised(Microsoft.Build.Framework.BuildEventArgs,BuildVision.Contracts.ErrorLevel)")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.Tool.Building.BuildService.CancelBuildAsync(BuildVision.Contracts.Models.IBuildInformationModel)~System.Threading.Tasks.Task")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.Tool.Building.BuildService.ProjectCopyBuildOutputFilesToClipBoard(BuildVision.UI.Models.IProjectItem)")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.Tool.Building.BuildService.RaiseCommand(Microsoft.VisualStudio.VSConstants.VSStd97CmdID)")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.Tool.Building.BuildService.RaiseCommandForSelectedProject(BuildVision.UI.Models.IProjectItem,System.Int32)")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.Views.Settings.PackageSettingsProvider.LoadSettings")] diff --git a/src/BuildVision/Services/BuildInformationProvider.cs b/src/BuildVision/Services/BuildInformationProvider.cs index 025261cb..d77e7c41 100644 --- a/src/BuildVision/Services/BuildInformationProvider.cs +++ b/src/BuildVision/Services/BuildInformationProvider.cs @@ -46,7 +46,9 @@ public class BuildInformationProvider : IBuildInformationProvider private int _currentQueuePosOfBuildingProject = 0; public IBuildInformationModel BuildInformationModel { get; } = new BuildInformationModel(); - public ObservableCollection Projects { get; } = new ObservableCollection(); + public ObservableRangeCollection Projects { get; } = new ObservableRangeCollection(); + + ObservableCollection IBuildInformationProvider.Projects => throw new NotImplementedException(); [ImportingConstructor] public BuildInformationProvider( @@ -362,14 +364,7 @@ public void BuildFinished(bool success, bool canceled) BuildInformationModel.BuildFinishTime = DateTime.Now; if (success) { - if (BuildInformationModel.ErrorCount > 0) - { - BuildInformationModel.CurrentBuildState = BuildState.ErrorDone; - } - else - { - BuildInformationModel.CurrentBuildState = BuildState.Done; - } + BuildInformationModel.CurrentBuildState = BuildInformationModel.ErrorCount > 0 ? BuildState.ErrorDone : BuildState.Done; } else { diff --git a/src/BuildVision/Services/BuildService.cs b/src/BuildVision/Services/BuildService.cs index a9a5aa3a..1185e76e 100644 --- a/src/BuildVision/Services/BuildService.cs +++ b/src/BuildVision/Services/BuildService.cs @@ -19,6 +19,8 @@ using Microsoft.VisualStudio; using Microsoft.VisualStudio.Shell; using Serilog; +using BuildVision.Extensions; +using BuildVision.Core; namespace BuildVision.Tool.Building { @@ -80,7 +82,7 @@ public async System.Threading.Tasks.Task CancelBuildAsync(IBuildInformationModel // We need to create a separate task here because of some weird things that are going on // when calling ExecuteCommand directly. Directly calling it leads to a freeze. No need // for that! - var dte = _serviceProvider.GetService(typeof(DTE)) as DTE; + var dte = _serviceProvider.GetService(); dte.ExecuteCommand(CancelBuildCommand); _buildCancelledInternally = true; } @@ -103,10 +105,26 @@ public void RaiseCommandForSelectedProject(IProjectItem selectedProjectItem, int } } + + private void RaiseCommand(VSConstants.VSStd97CmdID command) + { + try + { + object customIn = null; + object customOut = null; + var dte = _serviceProvider.GetService(); + dte.Commands.Raise(VSConstants.GUID_VSStandardCommandSet97.ToString(), (int)command, ref customIn, ref customOut); + } + catch (Exception ex) + { + _logger.Error(ex, "Raising command {Command} failed.", command); + } + } + private void SelectProjectInSolutionExplorer(IProjectItem projectItem) { var solutionExplorer = Core.Services.Dte2.ToolWindows.SolutionExplorer; - var project = Core.Services.Dte2.Solution.GetProject(x => x.UniqueName == projectItem.UniqueName); + var project = _serviceProvider.GetDteSolution().FirstOrDefaultProject(x => x.UniqueName == projectItem.UniqueName); var item = solutionExplorer.FindHierarchyItem(project); if (item == null) { @@ -121,7 +139,7 @@ public void ProjectCopyBuildOutputFilesToClipBoard(IProjectItem projItem) { try { - var project = Core.Services.Dte.Solution.GetProject(x => x.UniqueName == projItem.UniqueName); + var project = _serviceProvider.GetDteSolution().FirstOrDefaultProject(x => x.UniqueName == projItem.UniqueName); var fileTypes = _packageSettingsProvider.Settings.ProjectItemSettings.CopyBuildOutputFileTypesToClipboard; if (fileTypes.IsEmpty) { @@ -199,20 +217,5 @@ private string GetCopyBuildOutputFilesToClipboardActionMessage(string template, return string.Format(template, filesCountArg, filesListArg); } - - private void RaiseCommand(VSConstants.VSStd97CmdID command) - { - try - { - object customIn = null; - object customOut = null; - var dte = _serviceProvider.GetService(typeof(DTE)) as DTE; - dte.Commands.Raise(VSConstants.GUID_VSStandardCommandSet97.ToString(), (int)command, ref customIn, ref customOut); - } - catch (Exception ex) - { - _logger.Error(ex, "Raising command {Command} failed.", command); - } - } } } diff --git a/src/BuildVision/Services/ErrorNavigationService.cs b/src/BuildVision/Services/ErrorNavigationService.cs index 22c8151e..f962637f 100644 --- a/src/BuildVision/Services/ErrorNavigationService.cs +++ b/src/BuildVision/Services/ErrorNavigationService.cs @@ -4,6 +4,7 @@ using System.IO; using BuildVision.Common.Logging; using BuildVision.Contracts; +using BuildVision.Core; using BuildVision.Exports.Services; using BuildVision.Helpers; using EnvDTE; @@ -30,19 +31,12 @@ public void NavigateToErrorItem(ErrorItem errorItem) { try { - var dte = _serviceProvider.GetService(typeof(DTE)) as DTE; - var project = dte.Solution.GetProject(x => x.FileName == errorItem.ProjectFile); - - if (project == null) - { - throw new ArgumentNullException("project"); - } - if (errorItem == null) { - throw new ArgumentNullException("errorItem"); + throw new ArgumentNullException(nameof(errorItem)); } + var project = _serviceProvider.GetDteSolution().FirstProject(x => x.FileName == errorItem.ProjectFile); if (!errorItem.CanNavigateTo) { return; @@ -78,7 +72,7 @@ public void NavigateToErrorItem(ErrorItem errorItem) try { - var window = project.DTE.ItemOperations.OpenFile(fullPath, EnvDTE.Constants.vsViewKindAny); + var window = project.DTE.ItemOperations.OpenFile(fullPath, Constants.vsViewKindAny); if (window == null) { throw new NullReferenceException("Associated window is null reference."); diff --git a/src/BuildVision/Services/SolutionProvider.cs b/src/BuildVision/Services/SolutionProvider.cs index 25a37df8..d8b2d79e 100644 --- a/src/BuildVision/Services/SolutionProvider.cs +++ b/src/BuildVision/Services/SolutionProvider.cs @@ -25,7 +25,6 @@ public class SolutionProvider : ISolutionProvider private Solution _solution; private SolutionModel _solutionModel; - private DTE2 _dte; [ImportingConstructor] public SolutionProvider([Import(typeof(SVsServiceProvider))] IServiceProvider serviceProvider) @@ -35,10 +34,7 @@ public SolutionProvider([Import(typeof(SVsServiceProvider))] IServiceProvider se public void ReloadSolution() { - ThreadHelper.ThrowIfNotOnUIThread(); - _dte = _serviceProvider.GetService(typeof(DTE)) as DTE2; - _solution = _dte.Solution; - + _solution = _serviceProvider.GetDteSolution(); RefrehSolutionModel(); } @@ -64,7 +60,7 @@ private void RefrehSolutionModel() } else if (string.IsNullOrEmpty(_solution.FileName)) { - if (_solution.Count != 0 /* projects count */) + if (_solution.Count != 0) { var project = _solution.Item(1); _solutionModel.Name = Path.GetFileNameWithoutExtension(project.FileName); diff --git a/src/BuildVision/Services/StatusBarNotificationService.cs b/src/BuildVision/Services/StatusBarNotificationService.cs index 84685775..09ff105f 100644 --- a/src/BuildVision/Services/StatusBarNotificationService.cs +++ b/src/BuildVision/Services/StatusBarNotificationService.cs @@ -26,17 +26,15 @@ public StatusBarNotificationService( public void ShowText(string str) { - if (!_packageSettingsProvider.Settings.GeneralSettings.EnableStatusBarOutput) - { - return; - } - - var statusBar = _serviceProvider.GetService(typeof(IVsStatusbar)) as IVsStatusbar; - statusBar.FreezeOutput(0); - statusBar.SetText(str); + SetText(str); } public void ShowTextWithFreeze(string str) + { + SetText(str, freezeOutput: true); + } + + private void SetText(string str, bool freezeOutput = false) { if (!_packageSettingsProvider.Settings.GeneralSettings.EnableStatusBarOutput) { @@ -46,7 +44,10 @@ public void ShowTextWithFreeze(string str) var statusBar = _serviceProvider.GetService(); statusBar.FreezeOutput(0); statusBar.SetText(str); - statusBar.FreezeOutput(1); + if (freezeOutput) + { + statusBar.FreezeOutput(1); + } } } } diff --git a/src/BuildVision/Services/TaskBarInfoService.cs b/src/BuildVision/Services/TaskBarInfoService.cs index 4587ca9d..a84cfb3d 100644 --- a/src/BuildVision/Services/TaskBarInfoService.cs +++ b/src/BuildVision/Services/TaskBarInfoService.cs @@ -11,7 +11,7 @@ namespace BuildVision.UI.ViewModels { - public class TaskBarInfoService : ITaskBarInfoService + public class TaskBarInfoService : ITaskBarInfoService, IDisposable { private CancellationTokenSource _resetTaskBarInfoCts; @@ -120,7 +120,7 @@ private void ResetTaskBarInfoOnBuildDone() break; default: - throw new ArgumentOutOfRangeException(nameof(buildProgressSettings.ResetTaskBarProgressAfterBuildDone)); + throw new InvalidOperationException(nameof(buildProgressSettings.ResetTaskBarProgressAfterBuildDone)); } } @@ -133,5 +133,20 @@ private void OnMainWindowTouched(object sender, EventArgs e) window.LocationChanged -= OnMainWindowTouched; window.SizeChanged -= OnMainWindowTouched; } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + _resetTaskBarInfoCts?.Dispose(); + _resetTaskBarInfoCts = null; + } + } } } From 66299632f5aa8b46b8cf4b96914c94c5da83188a Mon Sep 17 00:00:00 2001 From: Stefan Kert Date: Sat, 27 Apr 2019 09:50:18 +0200 Subject: [PATCH 072/100] Showing error if something fails at startup --- src/BuildVision/Core/BuildVisionPane.cs | 65 ++++++++++++++++--------- 1 file changed, 41 insertions(+), 24 deletions(-) diff --git a/src/BuildVision/Core/BuildVisionPane.cs b/src/BuildVision/Core/BuildVisionPane.cs index 2002f1f8..7ebaad3b 100644 --- a/src/BuildVision/Core/BuildVisionPane.cs +++ b/src/BuildVision/Core/BuildVisionPane.cs @@ -38,9 +38,9 @@ public sealed class BuildVisionPane : ToolWindowPane private IPackageSettingsProvider _packageSettingsProvider; public JoinableTaskFactory JoinableTaskFactory { get; private set; } - public ControlView View + public FrameworkElement View { - get => _contentPresenter.Content as ControlView; + get => _contentPresenter.Content as FrameworkElement; set => _contentPresenter.Content = value; } @@ -74,28 +74,45 @@ public Task GetViewModelAsync() async Task InitializeAsync(AsyncPackage asyncPackage) { - await JoinableTaskFactory.SwitchToMainThreadAsync(); - - _packageSettingsProvider = await asyncPackage.GetServiceAsync(typeof(IPackageSettingsProvider)) as IPackageSettingsProvider; - Assumes.Present(_packageSettingsProvider); - var solutionProvider = await asyncPackage.GetServiceAsync(typeof(ISolutionProvider)) as ISolutionProvider; - Assumes.Present(solutionProvider); - var buildInformationProvider = await asyncPackage.GetServiceAsync(typeof(IBuildInformationProvider)) as IBuildInformationProvider; - Assumes.Present(buildInformationProvider); - var buildService = await asyncPackage.GetServiceAsync(typeof(IBuildService)) as IBuildService; - Assumes.Present(buildService); - var errorNavigationService = await asyncPackage.GetServiceAsync(typeof(IErrorNavigationService)) as IErrorNavigationService; - Assumes.Present(errorNavigationService); - var taskBarInfoService = await asyncPackage.GetServiceAsync(typeof(ITaskBarInfoService)) as ITaskBarInfoService; - Assumes.Present(taskBarInfoService); - - var viewModel = new BuildVisionPaneViewModel(buildInformationProvider, _packageSettingsProvider, solutionProvider, buildService, errorNavigationService, taskBarInfoService); - - View = CreateControlView(); - View.DataContext = viewModel; - viewModel.ShowOptionPage += ViewModel_ShowOptionPage; - _controlCreatedSuccessfully = true; - return viewModel; + try + { + await JoinableTaskFactory.SwitchToMainThreadAsync(); + + _packageSettingsProvider = await asyncPackage.GetServiceAsync(typeof(IPackageSettingsProvider)) as IPackageSettingsProvider; + Assumes.Present(_packageSettingsProvider); + var solutionProvider = await asyncPackage.GetServiceAsync(typeof(ISolutionProvider)) as ISolutionProvider; + Assumes.Present(solutionProvider); + var buildInformationProvider = await asyncPackage.GetServiceAsync(typeof(IBuildInformationProvider)) as IBuildInformationProvider; + Assumes.Present(buildInformationProvider); + var buildService = await asyncPackage.GetServiceAsync(typeof(IBuildService)) as IBuildService; + Assumes.Present(buildService); + var errorNavigationService = await asyncPackage.GetServiceAsync(typeof(IErrorNavigationService)) as IErrorNavigationService; + Assumes.Present(errorNavigationService); + var taskBarInfoService = await asyncPackage.GetServiceAsync(typeof(ITaskBarInfoService)) as ITaskBarInfoService; + Assumes.Present(taskBarInfoService); + + var viewModel = new BuildVisionPaneViewModel(buildInformationProvider, _packageSettingsProvider, solutionProvider, buildService, errorNavigationService, taskBarInfoService); + + View = CreateControlView(); + View.DataContext = viewModel; + viewModel.ShowOptionPage += ViewModel_ShowOptionPage; + _controlCreatedSuccessfully = true; + return viewModel; + } + catch (Exception e) + { + ShowError(e); + throw; + } + } + + void ShowError(Exception e) + { + View = new TextBox + { + Text = e.ToString(), + IsReadOnly = true, + }; } private void ViewModel_ShowOptionPage(Type obj) From f78baaf6928dea74db44dac4ab32d4620d47ddc7 Mon Sep 17 00:00:00 2001 From: Stefan Kert Date: Sat, 27 Apr 2019 09:50:29 +0200 Subject: [PATCH 073/100] Use ObservableCollection again --- src/BuildVision/Services/BuildInformationProvider.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/BuildVision/Services/BuildInformationProvider.cs b/src/BuildVision/Services/BuildInformationProvider.cs index d77e7c41..199fc14b 100644 --- a/src/BuildVision/Services/BuildInformationProvider.cs +++ b/src/BuildVision/Services/BuildInformationProvider.cs @@ -46,9 +46,7 @@ public class BuildInformationProvider : IBuildInformationProvider private int _currentQueuePosOfBuildingProject = 0; public IBuildInformationModel BuildInformationModel { get; } = new BuildInformationModel(); - public ObservableRangeCollection Projects { get; } = new ObservableRangeCollection(); - - ObservableCollection IBuildInformationProvider.Projects => throw new NotImplementedException(); + public ObservableCollection Projects { get; } = new ObservableRangeCollection(); [ImportingConstructor] public BuildInformationProvider( @@ -77,7 +75,7 @@ public BuildInformationProvider( public void ReloadCurrentProjects() { Projects.Clear(); - Projects.AddRange(_solutionProvider.GetProjects()); + ((ObservableRangeCollection< IProjectItem>)Projects).AddRange(_solutionProvider.GetProjects()); } public void ResetCurrentProjects() From 39622602a95255465bb717a3d83a8d109c52ae6b Mon Sep 17 00:00:00 2001 From: Stefan Kert Date: Sat, 27 Apr 2019 09:50:38 +0200 Subject: [PATCH 074/100] No need to display timestamp --- src/BuildVision.Common/AppVersionInfo.cs | 37 +------------------ src/BuildVision.Common/ApplicationInfo.cs | 5 ++- .../Settings/GeneralSettingsControl.xaml | 2 - 3 files changed, 5 insertions(+), 39 deletions(-) diff --git a/src/BuildVision.Common/AppVersionInfo.cs b/src/BuildVision.Common/AppVersionInfo.cs index 33295b32..b5707524 100644 --- a/src/BuildVision.Common/AppVersionInfo.cs +++ b/src/BuildVision.Common/AppVersionInfo.cs @@ -2,6 +2,7 @@ using System.Diagnostics; using System.IO; using System.Reflection; +using System.Runtime.InteropServices; namespace BuildVision.Common { @@ -9,48 +10,14 @@ public class AppVersionInfo { public string AppVersion { get; set; } public string BuildVersion { get; set; } - public DateTime BuildDateTime { get; set; } public AppVersionInfo() { var assembly = Assembly.GetExecutingAssembly(); var versionInfo = FileVersionInfo.GetVersionInfo(assembly.Location); - AppVersion = new Version(versionInfo.ProductVersion).ToString(); + AppVersion = versionInfo.ProductVersion.ToString(); BuildVersion = new Version(versionInfo.FileVersion).ToString(); - BuildDateTime = RetrieveLinkerTimestamp(assembly); - } - - /// - /// Get last build datetime. - /// - private static DateTime RetrieveLinkerTimestamp(Assembly assembly) - { - var filePath = assembly.Location; - const int PeHeaderOffset = 60; - const int LinkerTimestampOffset = 8; - var buffer = new byte[2048]; - Stream stream = null; - - try - { - stream = new FileStream(filePath, FileMode.Open, FileAccess.Read); - stream.Read(buffer, 0, 2048); - } - finally - { - if (stream != null) - { - stream.Close(); - } - } - - var i = BitConverter.ToInt32(buffer, PeHeaderOffset); - var secondsSince1970 = BitConverter.ToInt32(buffer, i + LinkerTimestampOffset); - var dt = new DateTime(1970, 1, 1, 0, 0, 0); - dt = dt.AddSeconds(secondsSince1970); - dt = dt.AddHours(TimeZone.CurrentTimeZone.GetUtcOffset(dt).Hours); - return dt; } } } diff --git a/src/BuildVision.Common/ApplicationInfo.cs b/src/BuildVision.Common/ApplicationInfo.cs index f023f807..99e050ac 100644 --- a/src/BuildVision.Common/ApplicationInfo.cs +++ b/src/BuildVision.Common/ApplicationInfo.cs @@ -12,9 +12,10 @@ public static FileVersionInfo GetHostVersionInfo() return Process.GetCurrentProcess().MainModule.FileVersionInfo; } - public static Version GetPackageVersion(object package) + public static string GetPackageVersion(object package) { - return package.GetType().Assembly.GetName().Version; + var versionInfo = FileVersionInfo.GetVersionInfo(package.GetType().Assembly.Location); + return versionInfo.ProductVersion; } } } diff --git a/src/BuildVision.UI/Settings/GeneralSettingsControl.xaml b/src/BuildVision.UI/Settings/GeneralSettingsControl.xaml index c0a15327..70de442d 100644 --- a/src/BuildVision.UI/Settings/GeneralSettingsControl.xaml +++ b/src/BuildVision.UI/Settings/GeneralSettingsControl.xaml @@ -173,8 +173,6 @@ - - Date: Sat, 27 Apr 2019 09:55:06 +0200 Subject: [PATCH 075/100] Refresh columns after settings have changed --- src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs b/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs index 08242f9b..e318d90e 100644 --- a/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs +++ b/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs @@ -210,8 +210,9 @@ public BuildVisionPaneViewModel( _settingsProvider = settingsProvider; _settingsProvider.SettingsChanged += () => { - SyncColumnSettings(); OnControlSettingsChanged(); + SyncColumnSettings(); + }; if (settingsProvider.Settings.GeneralSettings.FillProjectListOnBuildBegin) From 77201357710cea9181643b0d61c0cbc61d15f150 Mon Sep 17 00:00:00 2001 From: Stefan Kert Date: Sat, 27 Apr 2019 10:00:00 +0200 Subject: [PATCH 076/100] Warning label for projects with warnings is now default --- src/BuildVision.UI/Settings/GeneralSettingsControl.xaml | 4 ---- src/BuildVision.UI/Settings/Models/GeneralSettings.cs | 3 --- src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs | 5 ++--- src/BuildVision/Services/BuildInformationProvider.cs | 2 +- 4 files changed, 3 insertions(+), 11 deletions(-) diff --git a/src/BuildVision.UI/Settings/GeneralSettingsControl.xaml b/src/BuildVision.UI/Settings/GeneralSettingsControl.xaml index 70de442d..bbd9f3c2 100644 --- a/src/BuildVision.UI/Settings/GeneralSettingsControl.xaml +++ b/src/BuildVision.UI/Settings/GeneralSettingsControl.xaml @@ -126,10 +126,6 @@ Content="{x:Static res:Resources.BuildMessagesSettings_StatusBarOutputCheckBox}" IsChecked="{Binding EnableStatusBarOutput}" /> - - diff --git a/src/BuildVision.UI/Settings/Models/GeneralSettings.cs b/src/BuildVision.UI/Settings/Models/GeneralSettings.cs index b4b4d694..61ac7295 100644 --- a/src/BuildVision.UI/Settings/Models/GeneralSettings.cs +++ b/src/BuildVision.UI/Settings/Models/GeneralSettings.cs @@ -14,8 +14,6 @@ public class GeneralSettings : SettingsBase public bool StopBuildAfterFirstError { get; set; } - public bool ShowWarningSignForBuilds { get; set; } - public bool HideUpToDateTargets { get; set; } public NavigateToBuildFailureReasonCondition NavigateToBuildFailureReason { get; set; } @@ -27,7 +25,6 @@ public GeneralSettings() BuildProgressSettings = new BuildProgressSettings(); EnableStatusBarOutput = true; IndicatorsPanelVisible = true; - ShowWarningSignForBuilds = true; } } } diff --git a/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs b/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs index e318d90e..58022796 100644 --- a/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs +++ b/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs @@ -43,7 +43,7 @@ public class BuildVisionPaneViewModel : BindableBase, IBuildVisionPaneViewModel private readonly IPackageSettingsProvider _settingsProvider; private ObservableCollection _gridColumnsRef; - private ILogger _logger = LogManager.ForContext(); + private readonly ILogger _logger = LogManager.ForContext(); public ISolutionModel SolutionModel { get; set; } @@ -211,8 +211,7 @@ public BuildVisionPaneViewModel( _settingsProvider.SettingsChanged += () => { OnControlSettingsChanged(); - SyncColumnSettings(); - + SyncColumnSettings(); }; if (settingsProvider.Settings.GeneralSettings.FillProjectListOnBuildBegin) diff --git a/src/BuildVision/Services/BuildInformationProvider.cs b/src/BuildVision/Services/BuildInformationProvider.cs index 199fc14b..db9a3e8a 100644 --- a/src/BuildVision/Services/BuildInformationProvider.cs +++ b/src/BuildVision/Services/BuildInformationProvider.cs @@ -301,7 +301,7 @@ private ProjectState GetProjectState(bool success, bool canceled, IProjectItem c case BuildAction.RebuildAll: if (success) { - if (_packageSettingsProvider.Settings.GeneralSettings.ShowWarningSignForBuilds && currentProject.WarningsCount > 0) + if (currentProject.WarningsCount > 0) { projectState = ProjectState.BuildWarning; } From 9251aca5b5a80f35b81f67463079dd1310148c2f Mon Sep 17 00:00:00 2001 From: Stefan Kert Date: Sat, 27 Apr 2019 10:15:50 +0200 Subject: [PATCH 077/100] Fixed issue with buildvision breaking on breaking build --- src/BuildVision/Core/Services.cs | 6 ------ src/BuildVision/Services/BuildService.cs | 4 ++-- src/BuildVision/Services/ErrorNavigationService.cs | 2 +- src/BuildVision/Services/SolutionProvider.cs | 2 +- 4 files changed, 4 insertions(+), 10 deletions(-) diff --git a/src/BuildVision/Core/Services.cs b/src/BuildVision/Core/Services.cs index 523b6873..8ed77ae0 100644 --- a/src/BuildVision/Core/Services.cs +++ b/src/BuildVision/Core/Services.cs @@ -45,12 +45,6 @@ public static IVsSolution GetSolution(this IServiceProvider provider) return GetGlobalService(provider); } - public static Solution GetDteSolution(this IServiceProvider provider) - { - var ret = provider.GetService(typeof(DTE)) as DTE2; - return ret.Solution; - } - public static IVsSolution GetSolution() { return GetGlobalService(); diff --git a/src/BuildVision/Services/BuildService.cs b/src/BuildVision/Services/BuildService.cs index 1185e76e..a1625d31 100644 --- a/src/BuildVision/Services/BuildService.cs +++ b/src/BuildVision/Services/BuildService.cs @@ -124,7 +124,7 @@ private void RaiseCommand(VSConstants.VSStd97CmdID command) private void SelectProjectInSolutionExplorer(IProjectItem projectItem) { var solutionExplorer = Core.Services.Dte2.ToolWindows.SolutionExplorer; - var project = _serviceProvider.GetDteSolution().FirstOrDefaultProject(x => x.UniqueName == projectItem.UniqueName); + var project = Core.Services.Dte2.Solution.FirstOrDefaultProject(x => x.UniqueName == projectItem.UniqueName); var item = solutionExplorer.FindHierarchyItem(project); if (item == null) { @@ -139,7 +139,7 @@ public void ProjectCopyBuildOutputFilesToClipBoard(IProjectItem projItem) { try { - var project = _serviceProvider.GetDteSolution().FirstOrDefaultProject(x => x.UniqueName == projItem.UniqueName); + var project = Core.Services.Dte2.Solution.FirstOrDefaultProject(x => x.UniqueName == projItem.UniqueName); var fileTypes = _packageSettingsProvider.Settings.ProjectItemSettings.CopyBuildOutputFileTypesToClipboard; if (fileTypes.IsEmpty) { diff --git a/src/BuildVision/Services/ErrorNavigationService.cs b/src/BuildVision/Services/ErrorNavigationService.cs index f962637f..62b016cb 100644 --- a/src/BuildVision/Services/ErrorNavigationService.cs +++ b/src/BuildVision/Services/ErrorNavigationService.cs @@ -36,7 +36,7 @@ public void NavigateToErrorItem(ErrorItem errorItem) throw new ArgumentNullException(nameof(errorItem)); } - var project = _serviceProvider.GetDteSolution().FirstProject(x => x.FileName == errorItem.ProjectFile); + var project = Core.Services.Dte2.Solution.FirstProject(x => x.FileName == errorItem.ProjectFile); if (!errorItem.CanNavigateTo) { return; diff --git a/src/BuildVision/Services/SolutionProvider.cs b/src/BuildVision/Services/SolutionProvider.cs index d8b2d79e..2977e669 100644 --- a/src/BuildVision/Services/SolutionProvider.cs +++ b/src/BuildVision/Services/SolutionProvider.cs @@ -34,7 +34,7 @@ public SolutionProvider([Import(typeof(SVsServiceProvider))] IServiceProvider se public void ReloadSolution() { - _solution = _serviceProvider.GetDteSolution(); + _solution = Services.Dte2.Solution; RefrehSolutionModel(); } From 125ee49a9eb83c90441f17ab7fa2e292eb462d20 Mon Sep 17 00:00:00 2001 From: Stefan Kert Date: Sat, 27 Apr 2019 11:01:07 +0200 Subject: [PATCH 078/100] Added option to opt out participating in telemetry. Building multiple assemblies --- Directory.Build.props | 7 +++++ azure-pipelines.yml | 26 +++++++++++++------ .../Diagnostics/DiagnosticsClient.cs | 23 ++++++++-------- .../Diagnostics/SessionTelemetry.cs | 21 +++++++++++++-- .../Diagnostics/VersionTelemetry.cs | 8 +++--- src/BuildVision.UI/Resources.Designer.cs | 11 +++++++- src/BuildVision.UI/Resources.resx | 3 +++ .../Settings/GeneralSettingsControl.xaml | 4 +++ .../Settings/Models/GeneralSettings.cs | 3 +++ src/BuildVision/Core/BuildVisionPackage.cs | 22 +++++++++++++++- .../Services/PackageSettingsProvider.cs | 5 ++++ 11 files changed, 106 insertions(+), 27 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 3b8b6907..f8117bd5 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -7,4 +7,11 @@ + + $(DefineConstants);VSIXGallery + $(DefineConstants);MARKETPLACE + $(DefineConstants);VSIX + $(DefineConstants);VSIX + + \ No newline at end of file diff --git a/azure-pipelines.yml b/azure-pipelines.yml index b991e391..8e4c14ad 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -16,6 +16,18 @@ jobs: - job: Build pool: vmImage: vs2017-win2016 + strategy: + matrix: + Config_Release: + BuildConfiguration: Release + BuildOutputDirectory: Zip + Config_Marketplace: + BuildConfiguration: Marketplace + BuildOutputDirectory: Marketplace + Config_VSIXGallery: + BuildConfiguration: VSIXGallery + BuildOutputDirectory: VSIXGallery + steps: - task: DotNetCoreCLI@2 inputs: @@ -25,6 +37,9 @@ jobs: displayName: Install NBGV tool continueOnError: true + - powershell: | + mkdir $(Build.ArtifactStagingDirectory)\$(BuildOutputDirectory) + - script: nbgv cloud -a displayName: Set Version @@ -47,7 +62,7 @@ jobs: - task: CopyFiles@2 inputs: contents: '**/bin/$(BuildConfiguration)/*.vsix' - targetFolder: $(Build.ArtifactStagingDirectory)/artifacts + targetFolder: $(Build.ArtifactStagingDirectory)/$(BuildOutputDirectory) flattenFolders: true - task: DotNetCoreCLI@2 @@ -57,13 +72,8 @@ jobs: arguments: -c $(BuildConfiguration) --no-build --no-restore displayName: Run Unittests - - powershell: | - & "$env:userprofile/.nuget/packages/xunit.runner.console/2.4.1/tools/net472/xunit.console.x86.exe" (Get-Childitem -Filter "BuildVision.IntegrationTests.dll" -Recurse | Where-Object {$_.FullName -like "*\bin\$(BuildConfiguration)\*" }).FullName - displayName: Execute Integration Tests - enabled: false - - task: PublishBuildArtifacts@1 inputs: - PathtoPublish: $(Build.ArtifactStagingDirectory)/artifacts - ArtifactName: artifacts + PathtoPublish: $(Build.ArtifactStagingDirectory)/$(BuildOutputDirectory) + ArtifactName: $(BuildOutputDirectory) publishLocation: Container \ No newline at end of file diff --git a/src/BuildVision.Common/Diagnostics/DiagnosticsClient.cs b/src/BuildVision.Common/Diagnostics/DiagnosticsClient.cs index 62006f2b..3bb88059 100644 --- a/src/BuildVision.Common/Diagnostics/DiagnosticsClient.cs +++ b/src/BuildVision.Common/Diagnostics/DiagnosticsClient.cs @@ -11,25 +11,24 @@ public static class DiagnosticsClient private static bool _initialized; private static TelemetryClient _client; + public static bool ParticipateInTelemetry { get; set; } = true; - public static void Initialize(string apiKey) + public static void Initialize(string edition, string vsVersion, string apiKey) { if (!string.IsNullOrWhiteSpace(apiKey)) { - TelemetryConfiguration.Active.InstrumentationKey = apiKey; TelemetryConfiguration.Active.TelemetryChannel.DeveloperMode = Debugger.IsAttached; TelemetryConfiguration.Active.TelemetryInitializers.Add(new VersionTelemetry()); - TelemetryConfiguration.Active.TelemetryInitializers.Add(new SessionTelemetry()); + TelemetryConfiguration.Active.TelemetryInitializers.Add(new SessionTelemetry(vsVersion, edition)); _initialized = true; - _client = new TelemetryClient(); } } public static void OnExit() { - if (!_initialized) + if (!_initialized || !ParticipateInTelemetry) { return; } @@ -41,7 +40,7 @@ public static void OnExit() public static void TrackEvent(string eventName, IDictionary properties = null, IDictionary metrics = null) { - if (!_initialized) + if (!_initialized || !ParticipateInTelemetry) { return; } @@ -49,19 +48,19 @@ public static void TrackEvent(string eventName, IDictionary prop _client.TrackEvent(eventName, properties, metrics); } - public static void TrackTrace(string evt) + public static void TrackTrace(string trace) { - if (!_initialized) + if (!_initialized || !ParticipateInTelemetry) { return; } - _client.TrackTrace(evt); + _client.TrackTrace(trace); } - public static void Notify(Exception exception) + public static void TrackException(Exception exception) { - if (!_initialized) + if (!_initialized || !ParticipateInTelemetry) { return; } @@ -71,7 +70,7 @@ public static void Notify(Exception exception) public static void TrackPageView(string pageName) { - if (!_initialized) + if (!_initialized || !ParticipateInTelemetry) { return; } diff --git a/src/BuildVision.Common/Diagnostics/SessionTelemetry.cs b/src/BuildVision.Common/Diagnostics/SessionTelemetry.cs index 5243b33d..24ae1db1 100644 --- a/src/BuildVision.Common/Diagnostics/SessionTelemetry.cs +++ b/src/BuildVision.Common/Diagnostics/SessionTelemetry.cs @@ -13,8 +13,20 @@ class SessionTelemetry : ITelemetryInitializer private readonly string _userName; private readonly string _operatingSystem = RuntimeInformation.OSDescription?.Replace("Microsoft ", ""); // Shorter description private readonly string _session = Guid.NewGuid().ToString(); + private readonly string _vsVersion; + private readonly string _dteEdition; - public SessionTelemetry() +#if VSIXGallery + private const string Channel = "vsixgallery"; +#elif MARKETPLACE + private const string Channel = "marketplace"; +#elif VSIX + private const string Channel = "vsix"; +#else + private const string Channel = "vsix"; +#endif + + public SessionTelemetry(string vsVersion, string dteEdition) { try { @@ -28,11 +40,14 @@ public SessionTelemetry() { // No user id } + + _vsVersion = vsVersion; + _dteEdition = dteEdition; } public void Initialize(ITelemetry telemetry) { - telemetry.Context.GlobalProperties["Environment"] = "release"; + telemetry.Context.GlobalProperties["Environment"] = Channel; // Always default to development if we're in the debugger if (Debugger.IsAttached) { @@ -46,6 +61,8 @@ public void Initialize(ITelemetry telemetry) telemetry.Context.Session.Id = _session; telemetry.Context.Device.OperatingSystem = _operatingSystem; + telemetry.Context.Device.Model = _vsVersion; + telemetry.Context.Device.Type = _dteEdition; } } } diff --git a/src/BuildVision.Common/Diagnostics/VersionTelemetry.cs b/src/BuildVision.Common/Diagnostics/VersionTelemetry.cs index f2419183..1fcc320f 100644 --- a/src/BuildVision.Common/Diagnostics/VersionTelemetry.cs +++ b/src/BuildVision.Common/Diagnostics/VersionTelemetry.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics; using System.Linq; using System.Reflection; using Microsoft.ApplicationInsights.Channel; @@ -12,9 +13,10 @@ class VersionTelemetry : ITelemetryInitializer public VersionTelemetry() { - _appVersion = typeof(DiagnosticsClient).Assembly.GetCustomAttributes() - .FirstOrDefault(ama => string.Equals(ama.Key, "CloudBuildNumber", StringComparison.OrdinalIgnoreCase)) - ?.Value; + var assembly = Assembly.GetExecutingAssembly(); + var versionInfo = FileVersionInfo.GetVersionInfo(assembly.Location); + + _appVersion = versionInfo.ProductVersion.ToString(); } public void Initialize(ITelemetry telemetry) diff --git a/src/BuildVision.UI/Resources.Designer.cs b/src/BuildVision.UI/Resources.Designer.cs index 7ddc39b9..504fb22b 100644 --- a/src/BuildVision.UI/Resources.Designer.cs +++ b/src/BuildVision.UI/Resources.Designer.cs @@ -19,7 +19,7 @@ namespace BuildVision.UI { // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] public class Resources { @@ -692,6 +692,15 @@ public static string GeneralSettings_NavigateToBuildFailureReasonLabelToolTip { } } + /// + /// Looks up a localized string similar to Help improve BuildVision by providing anynonymous usage data and crash reports. + /// + public static string GeneralSettings_ParticipateInTelemetry { + get { + return ResourceManager.GetString("GeneralSettings_ParticipateInTelemetry", resourceCulture); + } + } + /// /// Looks up a localized string similar to Reset progress after build done. /// diff --git a/src/BuildVision.UI/Resources.resx b/src/BuildVision.UI/Resources.resx index 5e12b259..27ee9cc9 100644 --- a/src/BuildVision.UI/Resources.resx +++ b/src/BuildVision.UI/Resources.resx @@ -607,4 +607,7 @@ on build done Up-to-date Projects + + Help improve BuildVision by providing anynonymous usage data and crash reports + \ No newline at end of file diff --git a/src/BuildVision.UI/Settings/GeneralSettingsControl.xaml b/src/BuildVision.UI/Settings/GeneralSettingsControl.xaml index bbd9f3c2..5c66c702 100644 --- a/src/BuildVision.UI/Settings/GeneralSettingsControl.xaml +++ b/src/BuildVision.UI/Settings/GeneralSettingsControl.xaml @@ -130,6 +130,10 @@ Content="{x:Static res:Resources.BuildMessagesSettings_HideUpToDateTargets}" IsChecked="{Binding HideUpToDateTargets}" /> + + diff --git a/src/BuildVision.UI/Settings/Models/GeneralSettings.cs b/src/BuildVision.UI/Settings/Models/GeneralSettings.cs index 61ac7295..55c38961 100644 --- a/src/BuildVision.UI/Settings/Models/GeneralSettings.cs +++ b/src/BuildVision.UI/Settings/Models/GeneralSettings.cs @@ -20,11 +20,14 @@ public class GeneralSettings : SettingsBase public bool FillProjectListOnBuildBegin { get; set; } + public bool ParticipateInTelemetry { get; set; } + public GeneralSettings() { BuildProgressSettings = new BuildProgressSettings(); EnableStatusBarOutput = true; IndicatorsPanelVisible = true; + ParticipateInTelemetry = true; } } } diff --git a/src/BuildVision/Core/BuildVisionPackage.cs b/src/BuildVision/Core/BuildVisionPackage.cs index b8653396..08e0e1c0 100644 --- a/src/BuildVision/Core/BuildVisionPackage.cs +++ b/src/BuildVision/Core/BuildVisionPackage.cs @@ -1,5 +1,6 @@ using System; using System.Diagnostics; +using System.Globalization; using System.Runtime.InteropServices; using System.Threading; using System.Windows; @@ -68,12 +69,31 @@ public BuildVisionPackage() { Application.Current.DispatcherUnhandledException += Current_DispatcherUnhandledException; } + + DiagnosticsClient.Initialize(GetEdition(), VisualStudioVersion.ToString(), "c437ad44-0c76-4006-968d-42d4369bc0ed"); + } + + public static Version VisualStudioVersion => GetGlobalService(typeof(DTE)) is DTE dte + ? new Version(int.Parse(dte.Version.Split('.')[0], CultureInfo.InvariantCulture), 0) + : new Version(0, 0, 0, 0); + + private string GetEdition() + { + try + { + _dte2 = GetService(typeof(DTE)) as DTE2; + return _dte2.Edition; + } + catch (Exception ex) + { + return ""; + } } private void Current_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e) { _logger.Fatal(e.Exception, "Unhandled Exception"); - DiagnosticsClient.Notify(e.Exception); + DiagnosticsClient.TrackException(e.Exception); } protected override async Task InitializeAsync(CancellationToken cancellationToken, IProgress progress) diff --git a/src/BuildVision/Services/PackageSettingsProvider.cs b/src/BuildVision/Services/PackageSettingsProvider.cs index 62e988c1..0edddbae 100644 --- a/src/BuildVision/Services/PackageSettingsProvider.cs +++ b/src/BuildVision/Services/PackageSettingsProvider.cs @@ -2,6 +2,7 @@ using System.Diagnostics; using System.Windows; using BuildVision.Common; +using BuildVision.Common.Diagnostics; using BuildVision.Common.Logging; using BuildVision.UI.Settings.Models; using Microsoft.VisualStudio.Settings; @@ -31,6 +32,8 @@ public void Save() { SaveSettings(); SettingsChanged?.Invoke(); + + DiagnosticsClient.ParticipateInTelemetry = Settings.GeneralSettings.ParticipateInTelemetry; } private void SaveSettings() @@ -59,6 +62,8 @@ private void LoadSettings() { Settings = new ControlSettings(); } + + DiagnosticsClient.ParticipateInTelemetry = Settings.GeneralSettings.ParticipateInTelemetry; } catch (Exception ex) { From 77de19d1798bf9344baaa64c9f1b32ebde5c4883 Mon Sep 17 00:00:00 2001 From: Stefan Kert Date: Sat, 27 Apr 2019 11:04:07 +0200 Subject: [PATCH 079/100] Fixed yaml buildscript --- azure-pipelines.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 8e4c14ad..08ae4dc5 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -20,7 +20,7 @@ jobs: matrix: Config_Release: BuildConfiguration: Release - BuildOutputDirectory: Zip + BuildOutputDirectory: VSIX Config_Marketplace: BuildConfiguration: Marketplace BuildOutputDirectory: Marketplace @@ -37,8 +37,7 @@ jobs: displayName: Install NBGV tool continueOnError: true - - powershell: | - mkdir $(Build.ArtifactStagingDirectory)\$(BuildOutputDirectory) + - powershell: | mkdir $(Build.ArtifactStagingDirectory)\$(BuildOutputDirectory) - script: nbgv cloud -a displayName: Set Version From 5c3c62fd501eb8b4f9e0fe599dcc0ad5fc5b066b Mon Sep 17 00:00:00 2001 From: Stefan Kert Date: Sat, 27 Apr 2019 11:05:30 +0200 Subject: [PATCH 080/100] once again.. to less whitespaces --- azure-pipelines.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 08ae4dc5..bab84847 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -37,7 +37,8 @@ jobs: displayName: Install NBGV tool continueOnError: true - - powershell: | mkdir $(Build.ArtifactStagingDirectory)\$(BuildOutputDirectory) + - powershell: | + mkdir $(Build.ArtifactStagingDirectory)\$(BuildOutputDirectory) - script: nbgv cloud -a displayName: Set Version From d1eb54177059987647c6ffe47e896bb58410cb2f Mon Sep 17 00:00:00 2001 From: Stefan Kert Date: Sat, 27 Apr 2019 11:12:02 +0200 Subject: [PATCH 081/100] added build configs --- BuildVision.sln | 40 ++++++++++++++++--- azure-pipelines.yml | 6 +-- .../BuildVision.Common.csproj | 1 + .../BuildVision.Contracts.csproj | 1 + .../BuildVision.Exports.csproj | 1 + src/BuildVision.UI/BuildVision.UI.csproj | 20 ++++++++++ src/BuildVision/BuildVision.csproj | 20 ++++++++++ .../BuildVision.IntegrationTests.csproj | 1 + .../BuildVision.UnitTests.csproj | 1 + 9 files changed, 83 insertions(+), 8 deletions(-) diff --git a/BuildVision.sln b/BuildVision.sln index 2e4cbd62..11426b07 100644 --- a/BuildVision.sln +++ b/BuildVision.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.28307.136 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.28803.202 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Misc", "Misc", "{A8C25F90-8847-4EBE-A66B-02E5D1B42EC0}" ProjectSection(SolutionItems) = preProject @@ -19,9 +19,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{AE904AFF-1B2 EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BuildVision", "src\BuildVision\BuildVision.csproj", "{9925A635-1827-4BB4-9C31-FE0FC87A6265}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BuildVision.Common", "src\BuildVision.Common\BuildVision.Common.csproj", "{848412D1-95BF-4E56-A9EF-2926AF5C6D67}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BuildVision.Common", "src\BuildVision.Common\BuildVision.Common.csproj", "{848412D1-95BF-4E56-A9EF-2926AF5C6D67}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BuildVision.Contracts", "src\BuildVision.Contracts\BuildVision.Contracts.csproj", "{13D64A57-5DB3-4CC7-AC2B-9034E767D754}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BuildVision.Contracts", "src\BuildVision.Contracts\BuildVision.Contracts.csproj", "{13D64A57-5DB3-4CC7-AC2B-9034E767D754}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BuildVision.UI", "src\BuildVision.UI\BuildVision.UI.csproj", "{84E8BA65-9A4B-4C50-A115-6EF3208E4058}" EndProject @@ -31,42 +31,72 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BuildVision.IntegrationTest EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BuildVision.UnitTests", "test\BuildVision.UnitTests\BuildVision.UnitTests.csproj", "{2A7DE186-A1FA-4BA8-B393-3CA9ECBF444F}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BuildVision.Exports", "src\BuildVision.Exports\BuildVision.Exports.csproj", "{F16E6593-DDF9-4E9E-A2F8-56A3C43A643E}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BuildVision.Exports", "src\BuildVision.Exports\BuildVision.Exports.csproj", "{F16E6593-DDF9-4E9E-A2F8-56A3C43A643E}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU + Marketplace|Any CPU = Marketplace|Any CPU Release|Any CPU = Release|Any CPU + VsixGallery|Any CPU = VsixGallery|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {9925A635-1827-4BB4-9C31-FE0FC87A6265}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {9925A635-1827-4BB4-9C31-FE0FC87A6265}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9925A635-1827-4BB4-9C31-FE0FC87A6265}.Marketplace|Any CPU.ActiveCfg = Marketplace|Any CPU + {9925A635-1827-4BB4-9C31-FE0FC87A6265}.Marketplace|Any CPU.Build.0 = Marketplace|Any CPU {9925A635-1827-4BB4-9C31-FE0FC87A6265}.Release|Any CPU.ActiveCfg = Release|Any CPU {9925A635-1827-4BB4-9C31-FE0FC87A6265}.Release|Any CPU.Build.0 = Release|Any CPU + {9925A635-1827-4BB4-9C31-FE0FC87A6265}.VsixGallery|Any CPU.ActiveCfg = VsixGallery|Any CPU + {9925A635-1827-4BB4-9C31-FE0FC87A6265}.VsixGallery|Any CPU.Build.0 = VsixGallery|Any CPU {848412D1-95BF-4E56-A9EF-2926AF5C6D67}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {848412D1-95BF-4E56-A9EF-2926AF5C6D67}.Debug|Any CPU.Build.0 = Debug|Any CPU + {848412D1-95BF-4E56-A9EF-2926AF5C6D67}.Marketplace|Any CPU.ActiveCfg = Marketplace|Any CPU + {848412D1-95BF-4E56-A9EF-2926AF5C6D67}.Marketplace|Any CPU.Build.0 = Marketplace|Any CPU {848412D1-95BF-4E56-A9EF-2926AF5C6D67}.Release|Any CPU.ActiveCfg = Release|Any CPU {848412D1-95BF-4E56-A9EF-2926AF5C6D67}.Release|Any CPU.Build.0 = Release|Any CPU + {848412D1-95BF-4E56-A9EF-2926AF5C6D67}.VsixGallery|Any CPU.ActiveCfg = VsixGallery|Any CPU + {848412D1-95BF-4E56-A9EF-2926AF5C6D67}.VsixGallery|Any CPU.Build.0 = VsixGallery|Any CPU {13D64A57-5DB3-4CC7-AC2B-9034E767D754}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {13D64A57-5DB3-4CC7-AC2B-9034E767D754}.Debug|Any CPU.Build.0 = Debug|Any CPU + {13D64A57-5DB3-4CC7-AC2B-9034E767D754}.Marketplace|Any CPU.ActiveCfg = Marketplace|Any CPU + {13D64A57-5DB3-4CC7-AC2B-9034E767D754}.Marketplace|Any CPU.Build.0 = Marketplace|Any CPU {13D64A57-5DB3-4CC7-AC2B-9034E767D754}.Release|Any CPU.ActiveCfg = Release|Any CPU {13D64A57-5DB3-4CC7-AC2B-9034E767D754}.Release|Any CPU.Build.0 = Release|Any CPU + {13D64A57-5DB3-4CC7-AC2B-9034E767D754}.VsixGallery|Any CPU.ActiveCfg = VsixGallery|Any CPU + {13D64A57-5DB3-4CC7-AC2B-9034E767D754}.VsixGallery|Any CPU.Build.0 = VsixGallery|Any CPU {84E8BA65-9A4B-4C50-A115-6EF3208E4058}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {84E8BA65-9A4B-4C50-A115-6EF3208E4058}.Debug|Any CPU.Build.0 = Debug|Any CPU + {84E8BA65-9A4B-4C50-A115-6EF3208E4058}.Marketplace|Any CPU.ActiveCfg = Marketplace|Any CPU + {84E8BA65-9A4B-4C50-A115-6EF3208E4058}.Marketplace|Any CPU.Build.0 = Marketplace|Any CPU {84E8BA65-9A4B-4C50-A115-6EF3208E4058}.Release|Any CPU.ActiveCfg = Release|Any CPU {84E8BA65-9A4B-4C50-A115-6EF3208E4058}.Release|Any CPU.Build.0 = Release|Any CPU + {84E8BA65-9A4B-4C50-A115-6EF3208E4058}.VsixGallery|Any CPU.ActiveCfg = VsixGallery|Any CPU + {84E8BA65-9A4B-4C50-A115-6EF3208E4058}.VsixGallery|Any CPU.Build.0 = VsixGallery|Any CPU {FBB4F3ED-B1B8-4401-8667-5180194BAA54}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {FBB4F3ED-B1B8-4401-8667-5180194BAA54}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FBB4F3ED-B1B8-4401-8667-5180194BAA54}.Marketplace|Any CPU.ActiveCfg = Marketplace|Any CPU + {FBB4F3ED-B1B8-4401-8667-5180194BAA54}.Marketplace|Any CPU.Build.0 = Marketplace|Any CPU {FBB4F3ED-B1B8-4401-8667-5180194BAA54}.Release|Any CPU.ActiveCfg = Release|Any CPU {FBB4F3ED-B1B8-4401-8667-5180194BAA54}.Release|Any CPU.Build.0 = Release|Any CPU + {FBB4F3ED-B1B8-4401-8667-5180194BAA54}.VsixGallery|Any CPU.ActiveCfg = VsixGallery|Any CPU + {FBB4F3ED-B1B8-4401-8667-5180194BAA54}.VsixGallery|Any CPU.Build.0 = VsixGallery|Any CPU {2A7DE186-A1FA-4BA8-B393-3CA9ECBF444F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {2A7DE186-A1FA-4BA8-B393-3CA9ECBF444F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2A7DE186-A1FA-4BA8-B393-3CA9ECBF444F}.Marketplace|Any CPU.ActiveCfg = Marketplace|Any CPU + {2A7DE186-A1FA-4BA8-B393-3CA9ECBF444F}.Marketplace|Any CPU.Build.0 = Marketplace|Any CPU {2A7DE186-A1FA-4BA8-B393-3CA9ECBF444F}.Release|Any CPU.ActiveCfg = Release|Any CPU {2A7DE186-A1FA-4BA8-B393-3CA9ECBF444F}.Release|Any CPU.Build.0 = Release|Any CPU + {2A7DE186-A1FA-4BA8-B393-3CA9ECBF444F}.VsixGallery|Any CPU.ActiveCfg = VsixGallery|Any CPU + {2A7DE186-A1FA-4BA8-B393-3CA9ECBF444F}.VsixGallery|Any CPU.Build.0 = VsixGallery|Any CPU {F16E6593-DDF9-4E9E-A2F8-56A3C43A643E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F16E6593-DDF9-4E9E-A2F8-56A3C43A643E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F16E6593-DDF9-4E9E-A2F8-56A3C43A643E}.Marketplace|Any CPU.ActiveCfg = Marketplace|Any CPU + {F16E6593-DDF9-4E9E-A2F8-56A3C43A643E}.Marketplace|Any CPU.Build.0 = Marketplace|Any CPU {F16E6593-DDF9-4E9E-A2F8-56A3C43A643E}.Release|Any CPU.ActiveCfg = Release|Any CPU {F16E6593-DDF9-4E9E-A2F8-56A3C43A643E}.Release|Any CPU.Build.0 = Release|Any CPU + {F16E6593-DDF9-4E9E-A2F8-56A3C43A643E}.VsixGallery|Any CPU.ActiveCfg = VsixGallery|Any CPU + {F16E6593-DDF9-4E9E-A2F8-56A3C43A643E}.VsixGallery|Any CPU.Build.0 = VsixGallery|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/azure-pipelines.yml b/azure-pipelines.yml index bab84847..61b79f0b 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -20,13 +20,13 @@ jobs: matrix: Config_Release: BuildConfiguration: Release - BuildOutputDirectory: VSIX + BuildOutputDirectory: Vsix Config_Marketplace: BuildConfiguration: Marketplace BuildOutputDirectory: Marketplace Config_VSIXGallery: - BuildConfiguration: VSIXGallery - BuildOutputDirectory: VSIXGallery + BuildConfiguration: VsixGallery + BuildOutputDirectory: VsixGallery steps: - task: DotNetCoreCLI@2 diff --git a/src/BuildVision.Common/BuildVision.Common.csproj b/src/BuildVision.Common/BuildVision.Common.csproj index e77e895b..de2843bf 100644 --- a/src/BuildVision.Common/BuildVision.Common.csproj +++ b/src/BuildVision.Common/BuildVision.Common.csproj @@ -1,6 +1,7 @@  net472 + Debug;Release;Marketplace;VsixGallery diff --git a/src/BuildVision.Contracts/BuildVision.Contracts.csproj b/src/BuildVision.Contracts/BuildVision.Contracts.csproj index 80d21da2..2d804ff4 100644 --- a/src/BuildVision.Contracts/BuildVision.Contracts.csproj +++ b/src/BuildVision.Contracts/BuildVision.Contracts.csproj @@ -1,6 +1,7 @@  net472 + Debug;Release;Marketplace;VsixGallery diff --git a/src/BuildVision.Exports/BuildVision.Exports.csproj b/src/BuildVision.Exports/BuildVision.Exports.csproj index 9b277d43..5662c57a 100644 --- a/src/BuildVision.Exports/BuildVision.Exports.csproj +++ b/src/BuildVision.Exports/BuildVision.Exports.csproj @@ -4,6 +4,7 @@ net472 true Key.snk + Debug;Release;Marketplace;VsixGallery diff --git a/src/BuildVision.UI/BuildVision.UI.csproj b/src/BuildVision.UI/BuildVision.UI.csproj index 310f45fa..98779a1d 100644 --- a/src/BuildVision.UI/BuildVision.UI.csproj +++ b/src/BuildVision.UI/BuildVision.UI.csproj @@ -40,6 +40,26 @@ Key.snk + + bin\Marketplace\ + TRACE + true + pdbonly + AnyCPU + prompt + MinimumRecommendedRules.ruleset + true + + + bin\VsixGallery\ + TRACE + true + pdbonly + AnyCPU + prompt + MinimumRecommendedRules.ruleset + true + diff --git a/src/BuildVision/BuildVision.csproj b/src/BuildVision/BuildVision.csproj index 2a4ed336..4fe3e216 100644 --- a/src/BuildVision/BuildVision.csproj +++ b/src/BuildVision/BuildVision.csproj @@ -258,6 +258,26 @@ 12.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + bin\Marketplace\ + CODE_ANALYSIS;TRACE + true + pdbonly + AnyCPU + true + prompt + MinimumRecommendedRules.ruleset + + + bin\VsixGallery\ + CODE_ANALYSIS;TRACE + true + pdbonly + AnyCPU + true + prompt + MinimumRecommendedRules.ruleset + diff --git a/test/BuildVision.IntegrationTests/BuildVision.IntegrationTests.csproj b/test/BuildVision.IntegrationTests/BuildVision.IntegrationTests.csproj index 5cc24e17..d2bb95a9 100644 --- a/test/BuildVision.IntegrationTests/BuildVision.IntegrationTests.csproj +++ b/test/BuildVision.IntegrationTests/BuildVision.IntegrationTests.csproj @@ -2,6 +2,7 @@ net472 true + Debug;Release;Marketplace;VsixGallery diff --git a/test/BuildVision.UnitTests/BuildVision.UnitTests.csproj b/test/BuildVision.UnitTests/BuildVision.UnitTests.csproj index 75b91cf2..5afa2490 100644 --- a/test/BuildVision.UnitTests/BuildVision.UnitTests.csproj +++ b/test/BuildVision.UnitTests/BuildVision.UnitTests.csproj @@ -1,6 +1,7 @@  net472 + Debug;Release;Marketplace;VsixGallery From 63b4efbfd789a3cb8ae164e08e835a4a0fa4ebff Mon Sep 17 00:00:00 2001 From: Stefan Kert Date: Sat, 27 Apr 2019 11:26:23 +0200 Subject: [PATCH 082/100] Added initial event --- src/BuildVision/Core/BuildVisionPane.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/BuildVision/Core/BuildVisionPane.cs b/src/BuildVision/Core/BuildVisionPane.cs index 7ebaad3b..ee71d7b5 100644 --- a/src/BuildVision/Core/BuildVisionPane.cs +++ b/src/BuildVision/Core/BuildVisionPane.cs @@ -5,6 +5,7 @@ using System.Windows; using System.Windows.Controls; using System.Windows.Markup; +using BuildVision.Common.Diagnostics; using BuildVision.Core; using BuildVision.Exports.Providers; using BuildVision.Exports.Services; @@ -97,10 +98,14 @@ async Task InitializeAsync(AsyncPackage asyncPackage) View.DataContext = viewModel; viewModel.ShowOptionPage += ViewModel_ShowOptionPage; _controlCreatedSuccessfully = true; + + DiagnosticsClient.TrackEvent("BuildVisionStarted"); + return viewModel; } catch (Exception e) { + DiagnosticsClient.TrackException(e); ShowError(e); throw; } From b8ee8a54c09585bf06ddc8fd01894763294c7642 Mon Sep 17 00:00:00 2001 From: Stefan Kert Date: Sat, 27 Apr 2019 12:27:42 +0200 Subject: [PATCH 083/100] Added preview icon --- .../Components/ControlView.xaml | 218 +++++++++--------- .../ViewModels/BuildVisionPaneViewModel.cs | 6 + 2 files changed, 120 insertions(+), 104 deletions(-) diff --git a/src/BuildVision.UI/Components/ControlView.xaml b/src/BuildVision.UI/Components/ControlView.xaml index f15b1e38..382c0850 100644 --- a/src/BuildVision.UI/Components/ControlView.xaml +++ b/src/BuildVision.UI/Components/ControlView.xaml @@ -39,110 +39,120 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + Preview + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs b/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs index 58022796..8d8e7cf3 100644 --- a/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs +++ b/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs @@ -45,6 +45,12 @@ public class BuildVisionPaneViewModel : BindableBase, IBuildVisionPaneViewModel private readonly ILogger _logger = LogManager.ForContext(); +#if MARKETPLACE + public const string PreviewVersion = "false"; +#else + public const string PreviewVersion = "true"; +#endif + public ISolutionModel SolutionModel { get; set; } public string GridGroupHeaderName => string.IsNullOrEmpty(GridGroupPropertyName) ? string.Empty : ControlSettings.GridSettings.Columns[GridGroupPropertyName].Header; From a38259fed388de0b311f0b19d8b5014c9b26389e Mon Sep 17 00:00:00 2001 From: Stefan Kert Date: Sat, 27 Apr 2019 12:46:33 +0200 Subject: [PATCH 084/100] Do not track roleinstance and rolename --- src/BuildVision.Common/ApplicationInfo.cs | 7 +++++++ src/BuildVision.Common/Diagnostics/SessionTelemetry.cs | 2 ++ src/BuildVision/Core/BuildVisionPane.cs | 3 ++- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/BuildVision.Common/ApplicationInfo.cs b/src/BuildVision.Common/ApplicationInfo.cs index 99e050ac..78e92de3 100644 --- a/src/BuildVision.Common/ApplicationInfo.cs +++ b/src/BuildVision.Common/ApplicationInfo.cs @@ -1,5 +1,6 @@ using System; using System.Diagnostics; +using System.Reflection; namespace BuildVision.Common { @@ -17,5 +18,11 @@ public static string GetPackageVersion(object package) var versionInfo = FileVersionInfo.GetVersionInfo(package.GetType().Assembly.Location); return versionInfo.ProductVersion; } + + public static string GetProductVersion() + { + var versionInfo = FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location); + return versionInfo.ProductVersion; + } } } diff --git a/src/BuildVision.Common/Diagnostics/SessionTelemetry.cs b/src/BuildVision.Common/Diagnostics/SessionTelemetry.cs index 24ae1db1..fc4fac9b 100644 --- a/src/BuildVision.Common/Diagnostics/SessionTelemetry.cs +++ b/src/BuildVision.Common/Diagnostics/SessionTelemetry.cs @@ -61,6 +61,8 @@ public void Initialize(ITelemetry telemetry) telemetry.Context.Session.Id = _session; telemetry.Context.Device.OperatingSystem = _operatingSystem; + telemetry.Context.Cloud.RoleInstance = ""; + telemetry.Context.Cloud.RoleName = ""; telemetry.Context.Device.Model = _vsVersion; telemetry.Context.Device.Type = _dteEdition; } diff --git a/src/BuildVision/Core/BuildVisionPane.cs b/src/BuildVision/Core/BuildVisionPane.cs index ee71d7b5..3d5dde45 100644 --- a/src/BuildVision/Core/BuildVisionPane.cs +++ b/src/BuildVision/Core/BuildVisionPane.cs @@ -5,6 +5,7 @@ using System.Windows; using System.Windows.Controls; using System.Windows.Markup; +using BuildVision.Common; using BuildVision.Common.Diagnostics; using BuildVision.Core; using BuildVision.Exports.Providers; @@ -48,7 +49,7 @@ public FrameworkElement View public BuildVisionPane() : base(null) { - Caption = Resources.ToolWindowTitle; + Caption = string.Format("{0} - {1}", Resources.ToolWindowTitle, ApplicationInfo.GetProductVersion()); BitmapResourceID = 301; BitmapIndex = 1; From ea508d5846b052791e2fc3be54eadf3f0428d8c3 Mon Sep 17 00:00:00 2001 From: Stefan Kert Date: Sat, 27 Apr 2019 13:27:05 +0200 Subject: [PATCH 085/100] Flush diagnostics client --- src/BuildVision.Common/Diagnostics/DiagnosticsClient.cs | 2 +- src/BuildVision/Core/BuildVisionPackage.cs | 3 +++ src/BuildVision/Core/BuildVisionPane.cs | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/BuildVision.Common/Diagnostics/DiagnosticsClient.cs b/src/BuildVision.Common/Diagnostics/DiagnosticsClient.cs index 3bb88059..7f5bc3cb 100644 --- a/src/BuildVision.Common/Diagnostics/DiagnosticsClient.cs +++ b/src/BuildVision.Common/Diagnostics/DiagnosticsClient.cs @@ -26,7 +26,7 @@ public static void Initialize(string edition, string vsVersion, string apiKey) } } - public static void OnExit() + public static void Flush() { if (!_initialized || !ParticipateInTelemetry) { diff --git a/src/BuildVision/Core/BuildVisionPackage.cs b/src/BuildVision/Core/BuildVisionPackage.cs index 08e0e1c0..76381d5e 100644 --- a/src/BuildVision/Core/BuildVisionPackage.cs +++ b/src/BuildVision/Core/BuildVisionPackage.cs @@ -94,6 +94,7 @@ private void Current_DispatcherUnhandledException(object sender, DispatcherUnhan { _logger.Fatal(e.Exception, "Unhandled Exception"); DiagnosticsClient.TrackException(e.Exception); + DiagnosticsClient.Flush(); } protected override async Task InitializeAsync(CancellationToken cancellationToken, IProgress progress) @@ -154,6 +155,8 @@ private void SolutionEvents_AfterClosing() _solutionBuildManager.UnadviseUpdateSolutionEvents(_updateSolutionEventsCookie); _solutionBuildManager4.UnadviseUpdateSolutionEvents4(_updateSolutionEvents4Cookie); + + DiagnosticsClient.Flush(); } private void CommandEvents_AfterExecute(string guid, int id, object customIn, object customOut) diff --git a/src/BuildVision/Core/BuildVisionPane.cs b/src/BuildVision/Core/BuildVisionPane.cs index 3d5dde45..ce7b4684 100644 --- a/src/BuildVision/Core/BuildVisionPane.cs +++ b/src/BuildVision/Core/BuildVisionPane.cs @@ -101,7 +101,7 @@ async Task InitializeAsync(AsyncPackage asyncPackage) _controlCreatedSuccessfully = true; DiagnosticsClient.TrackEvent("BuildVisionStarted"); - + DiagnosticsClient.Flush(); return viewModel; } catch (Exception e) From f4de25445a0800d071cf5c2e0692599cad4abc02 Mon Sep 17 00:00:00 2001 From: Stefan Kert Date: Sat, 27 Apr 2019 13:32:50 +0200 Subject: [PATCH 086/100] Resolved most of the warnings in codefactor --- src/BuildVision.Common/Properties/GlobalSuppressions.cs | 5 +---- src/BuildVision.Contracts/Properties/GlobalSuppressions.cs | 5 +---- src/BuildVision.UI/Converters/StateIconKeyToIconConverter.cs | 1 - src/BuildVision.UI/Properties/GlobalSuppressions.cs | 5 +---- src/BuildVision/Core/BuildVisionPackage.cs | 1 - src/BuildVision/Core/SolutionBuildEvents.cs | 1 - src/BuildVision/Helpers/ProjectExtensions.cs | 1 - src/BuildVision/Helpers/SolutionProjectsExtensions.cs | 1 - src/BuildVision/Properties/GlobalSuppressions.cs | 5 +---- src/BuildVision/Services/BuildService.cs | 2 -- src/BuildVision/Services/TaskBarInfoService.cs | 2 +- src/BuildVision/Views/Settings/GeneralSettingsDialogPage.cs | 1 - .../Helpers/BuildMessageEventArgsExtensionsTests.cs | 1 - 13 files changed, 5 insertions(+), 26 deletions(-) diff --git a/src/BuildVision.Common/Properties/GlobalSuppressions.cs b/src/BuildVision.Common/Properties/GlobalSuppressions.cs index d9509ec9..f29fc8c0 100644 --- a/src/BuildVision.Common/Properties/GlobalSuppressions.cs +++ b/src/BuildVision.Common/Properties/GlobalSuppressions.cs @@ -1,9 +1,6 @@ - -// This file is used by Code Analysis to maintain SuppressMessage +// This file is used by Code Analysis to maintain SuppressMessage // attributes that are applied to this project. // Project-level suppressions either have no target or are given // a specific target and scoped to a namespace, type, member, etc. - [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1305:Specify IFormatProvider", Justification = "", Scope = "member", Target = "~M:BuildVision.Common.FilePathHelper.ShortenPath(System.String,System.Int32)~System.String")] - [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.Common.Diagnostics.SessionTelemetry.#ctor")] diff --git a/src/BuildVision.Contracts/Properties/GlobalSuppressions.cs b/src/BuildVision.Contracts/Properties/GlobalSuppressions.cs index 99acc86e..c860c334 100644 --- a/src/BuildVision.Contracts/Properties/GlobalSuppressions.cs +++ b/src/BuildVision.Contracts/Properties/GlobalSuppressions.cs @@ -1,8 +1,5 @@ - -// This file is used by Code Analysis to maintain SuppressMessage +// This file is used by Code Analysis to maintain SuppressMessage // attributes that are applied to this project. // Project-level suppressions either have no target or are given // a specific target and scoped to a namespace, type, member, etc. - [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1305:Specify IFormatProvider", Justification = "", Scope = "member", Target = "~P:BuildVision.Contracts.Exceptions.PropertyNotFoundException.Message")] - diff --git a/src/BuildVision.UI/Converters/StateIconKeyToIconConverter.cs b/src/BuildVision.UI/Converters/StateIconKeyToIconConverter.cs index 729f5965..daba00e5 100644 --- a/src/BuildVision.UI/Converters/StateIconKeyToIconConverter.cs +++ b/src/BuildVision.UI/Converters/StateIconKeyToIconConverter.cs @@ -25,4 +25,3 @@ public object ConvertBack(object value, Type targetType, object parameter, Cultu } } } - diff --git a/src/BuildVision.UI/Properties/GlobalSuppressions.cs b/src/BuildVision.UI/Properties/GlobalSuppressions.cs index 80b7b6d5..41b8c33d 100644 --- a/src/BuildVision.UI/Properties/GlobalSuppressions.cs +++ b/src/BuildVision.UI/Properties/GlobalSuppressions.cs @@ -1,9 +1,7 @@ - -// This file is used by Code Analysis to maintain SuppressMessage +// This file is used by Code Analysis to maintain SuppressMessage // attributes that are applied to this project. // Project-level suppressions either have no target or are given // a specific target and scoped to a namespace, type, member, etc. - [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1305:Specify IFormatProvider", Justification = "", Scope = "member", Target = "~F:BuildVision.UI.Components.SpinnerControl.FormattedValuePropertyKey")] [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1305:Specify IFormatProvider", Justification = "", Scope = "member", Target = "~F:BuildVision.UI.Extensions.VectorResources._baseUri")] [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1305:Specify IFormatProvider", Justification = "", Scope = "member", Target = "~M:BuildVision.UI.Converters.DataGridLengthStringConverter.Convert(System.Object,System.Type,System.Object,System.Globalization.CultureInfo)~System.Object")] @@ -25,7 +23,6 @@ [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1305:Specify IFormatProvider", Justification = "", Scope = "member", Target = "~P:BuildVision.UI.Settings.Models.BuildMessagesSettings.DateTimeFormat")] [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1305:Specify IFormatProvider", Justification = "", Scope = "member", Target = "~P:BuildVision.UI.Settings.Models.BuildMessagesSettings.ExtraMessageStringFormat")] [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1305:Specify IFormatProvider", Justification = "", Scope = "member", Target = "~P:BuildVision.UI.Settings.Models.BuildMessagesSettings.TimeSpanFormat")] - [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.UI.Converters.DataGridLengthStringConverter.ConvertBack(System.Object,System.Type,System.Object,System.Globalization.CultureInfo)~System.Object")] [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.UI.Converters.GridColumnSettingsToColumnExampleValueConverter.FormatExample(System.Object,System.String)~System.String")] [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.UI.Converters.MultiBindingStringFormatConverter.Convert(System.Object[],System.Type,System.Object,System.Globalization.CultureInfo)~System.Object")] diff --git a/src/BuildVision/Core/BuildVisionPackage.cs b/src/BuildVision/Core/BuildVisionPackage.cs index 76381d5e..8fe625e8 100644 --- a/src/BuildVision/Core/BuildVisionPackage.cs +++ b/src/BuildVision/Core/BuildVisionPackage.cs @@ -58,7 +58,6 @@ public sealed class BuildVisionPackage : AsyncPackage, IVsPackageDynamicToolOwne private ILogger _logger = LogManager.ForContext(); public static ToolWindowPane ToolWindowPane { get; set; } - public ControlSettings ControlSettings { get; set; } public BuildVisionPackage() diff --git a/src/BuildVision/Core/SolutionBuildEvents.cs b/src/BuildVision/Core/SolutionBuildEvents.cs index 9be3860f..07fa3f7a 100644 --- a/src/BuildVision/Core/SolutionBuildEvents.cs +++ b/src/BuildVision/Core/SolutionBuildEvents.cs @@ -9,7 +9,6 @@ namespace BuildVision.Core { - public class SolutionBuildEvents : IVsUpdateSolutionEvents2, IVsUpdateSolutionEvents4 { private readonly ISolutionProvider _solutionProvider; diff --git a/src/BuildVision/Helpers/ProjectExtensions.cs b/src/BuildVision/Helpers/ProjectExtensions.cs index 2139453d..a3d73037 100644 --- a/src/BuildVision/Helpers/ProjectExtensions.cs +++ b/src/BuildVision/Helpers/ProjectExtensions.cs @@ -510,7 +510,6 @@ public static bool IsDirty(this Project project) return false; } - public static string GetTreePath(this Project project, bool includeSelfProjectName = true) { var path = new StringBuilder(); diff --git a/src/BuildVision/Helpers/SolutionProjectsExtensions.cs b/src/BuildVision/Helpers/SolutionProjectsExtensions.cs index 1321f323..fd153970 100644 --- a/src/BuildVision/Helpers/SolutionProjectsExtensions.cs +++ b/src/BuildVision/Helpers/SolutionProjectsExtensions.cs @@ -104,7 +104,6 @@ public static IList GetProjectItems(this Solution solution) LogManager.ForContext().Error(ex, "Failed to get projectitems for solution {FullName}", solution?.FullName); } - var projectItems = new List(dteProjects.Count); foreach (var project in dteProjects) { diff --git a/src/BuildVision/Properties/GlobalSuppressions.cs b/src/BuildVision/Properties/GlobalSuppressions.cs index 1d0c218f..89393d0c 100644 --- a/src/BuildVision/Properties/GlobalSuppressions.cs +++ b/src/BuildVision/Properties/GlobalSuppressions.cs @@ -1,13 +1,10 @@ - -// This file is used by Code Analysis to maintain SuppressMessage +// This file is used by Code Analysis to maintain SuppressMessage // attributes that are applied to this project. // Project-level suppressions either have no target or are given // a specific target and scoped to a namespace, type, member, etc. - [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1305:Specify IFormatProvider", Justification = "", Scope = "member", Target = "~M:BuildVision.Helpers.ProjectExtensions.GetFrameworkString(EnvDTE.Project)~System.String")] [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1305:Specify IFormatProvider", Justification = "", Scope = "member", Target = "~M:BuildVision.Helpers.ProjectExtensions.GetProjectTypeFromRegistry(System.String,System.String)~System.String")] [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1305:Specify IFormatProvider", Justification = "", Scope = "member", Target = "~M:BuildVision.Tool.Building.BuildService.GetCopyBuildOutputFilesToClipboardActionMessage(System.String,System.String[])~System.String")] - [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.Core.BuildInformationProvider.BuildOutputLogger_OnErrorRaised(BuildVision.UI.Contracts.BuildProjectContextEntry,System.Object,BuildVision.Contracts.ErrorLevel)")] [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.Core.BuildInformationProvider.ProjectBuildStarted(BuildVision.UI.Models.IProjectItem,BuildVision.Contracts.BuildAction)")] [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.Core.SolutionProvider.RefrehSolutionModel")] diff --git a/src/BuildVision/Services/BuildService.cs b/src/BuildVision/Services/BuildService.cs index a1625d31..76c48b9f 100644 --- a/src/BuildVision/Services/BuildService.cs +++ b/src/BuildVision/Services/BuildService.cs @@ -20,7 +20,6 @@ using Microsoft.VisualStudio.Shell; using Serilog; using BuildVision.Extensions; -using BuildVision.Core; namespace BuildVision.Tool.Building { @@ -105,7 +104,6 @@ public void RaiseCommandForSelectedProject(IProjectItem selectedProjectItem, int } } - private void RaiseCommand(VSConstants.VSStd97CmdID command) { try diff --git a/src/BuildVision/Services/TaskBarInfoService.cs b/src/BuildVision/Services/TaskBarInfoService.cs index a84cfb3d..92be0afe 100644 --- a/src/BuildVision/Services/TaskBarInfoService.cs +++ b/src/BuildVision/Services/TaskBarInfoService.cs @@ -40,7 +40,7 @@ public void UpdateTaskBarInfo(BuildState buildState, BuildScope buildScope, int return; } - _taskbarItemInfo.Value.ProgressState = buildState.ToTaskBarItemProgressState(buildScope); ; + _taskbarItemInfo.Value.ProgressState = buildState.ToTaskBarItemProgressState(buildScope); if (projectsCount <= 0) { diff --git a/src/BuildVision/Views/Settings/GeneralSettingsDialogPage.cs b/src/BuildVision/Views/Settings/GeneralSettingsDialogPage.cs index a8fe04f7..517b023e 100644 --- a/src/BuildVision/Views/Settings/GeneralSettingsDialogPage.cs +++ b/src/BuildVision/Views/Settings/GeneralSettingsDialogPage.cs @@ -2,7 +2,6 @@ using BuildVision.UI.Settings.Models; using System.Runtime.InteropServices; - namespace BuildVision.Views.Settings { [ClassInterface(ClassInterfaceType.AutoDual)] diff --git a/test/BuildVision.UnitTests/Helpers/BuildMessageEventArgsExtensionsTests.cs b/test/BuildVision.UnitTests/Helpers/BuildMessageEventArgsExtensionsTests.cs index 44c643df..c7405483 100644 --- a/test/BuildVision.UnitTests/Helpers/BuildMessageEventArgsExtensionsTests.cs +++ b/test/BuildVision.UnitTests/Helpers/BuildMessageEventArgsExtensionsTests.cs @@ -45,4 +45,3 @@ public void IsUserMessage_ShouldReturn_False_If_ForCombinations(LoggerVerbosity } } } - From 35192283f980105327378644fa2a62cdafafc197 Mon Sep 17 00:00:00 2001 From: Stefan Kert Date: Sat, 27 Apr 2019 14:10:45 +0200 Subject: [PATCH 087/100] Added back instrumentationkey --- src/BuildVision.Common/Diagnostics/DiagnosticsClient.cs | 1 + src/BuildVision/Services/BuildInformationProvider.cs | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/BuildVision.Common/Diagnostics/DiagnosticsClient.cs b/src/BuildVision.Common/Diagnostics/DiagnosticsClient.cs index 7f5bc3cb..1ab889ff 100644 --- a/src/BuildVision.Common/Diagnostics/DiagnosticsClient.cs +++ b/src/BuildVision.Common/Diagnostics/DiagnosticsClient.cs @@ -17,6 +17,7 @@ public static void Initialize(string edition, string vsVersion, string apiKey) { if (!string.IsNullOrWhiteSpace(apiKey)) { + TelemetryConfiguration.Active.InstrumentationKey = apiKey; TelemetryConfiguration.Active.TelemetryChannel.DeveloperMode = Debugger.IsAttached; TelemetryConfiguration.Active.TelemetryInitializers.Add(new VersionTelemetry()); TelemetryConfiguration.Active.TelemetryInitializers.Add(new SessionTelemetry(vsVersion, edition)); diff --git a/src/BuildVision/Services/BuildInformationProvider.cs b/src/BuildVision/Services/BuildInformationProvider.cs index db9a3e8a..66f37863 100644 --- a/src/BuildVision/Services/BuildInformationProvider.cs +++ b/src/BuildVision/Services/BuildInformationProvider.cs @@ -383,7 +383,6 @@ public void BuildFinished(bool success, bool canceled) _windowStateService.ApplyToolWindowStateAction(_packageSettingsProvider.Settings.WindowSettings.WindowActionOnBuildSuccess); } - if (BuildInformationModel.FailedProjectsCount > 0) { if (_packageSettingsProvider.Settings.GeneralSettings.NavigateToBuildFailureReason == NavigateToBuildFailureReasonCondition.OnBuildDone) From b1b05308cfb7ec025d6fe02ce14c1203d5f73dae Mon Sep 17 00:00:00 2001 From: Stefan Kert Date: Sat, 27 Apr 2019 14:22:53 +0200 Subject: [PATCH 088/100] Add basic tracing for builds --- .../Models/IBuildInformationModel.cs | 1 + .../Helpers/StateConverterHelper.cs | 4 ++- .../Properties/GlobalSuppressions.cs | 30 +------------------ .../Services/BuildInformationProvider.cs | 21 +++++++++++++ .../Views/Settings/SettingsDialogPage.cs | 2 ++ 5 files changed, 28 insertions(+), 30 deletions(-) diff --git a/src/BuildVision.Contracts/Models/IBuildInformationModel.cs b/src/BuildVision.Contracts/Models/IBuildInformationModel.cs index 8ed56319..f524b06d 100644 --- a/src/BuildVision.Contracts/Models/IBuildInformationModel.cs +++ b/src/BuildVision.Contracts/Models/IBuildInformationModel.cs @@ -7,6 +7,7 @@ namespace BuildVision.Contracts.Models { public interface IBuildInformationModel : INotifyPropertyChanged { + Guid BuildId { get; set; } BuildAction BuildAction { get; set; } DateTime? BuildFinishTime { get; set; } BuildScope BuildScope { get; set; } diff --git a/src/BuildVision/Helpers/StateConverterHelper.cs b/src/BuildVision/Helpers/StateConverterHelper.cs index 898e6f21..e03bdc12 100644 --- a/src/BuildVision/Helpers/StateConverterHelper.cs +++ b/src/BuildVision/Helpers/StateConverterHelper.cs @@ -1,4 +1,5 @@ -using BuildVision.Contracts; +using BuildVision.Common.Diagnostics; +using BuildVision.Contracts; using Microsoft.VisualStudio.Shell.Interop; namespace BuildVision.Tool.Models @@ -21,6 +22,7 @@ public static BuildAction ConvertSolutionBuildFlagsToBuildAction(uint dwAction, } else { + DiagnosticsClient.TrackTrace($"Received unknown DW Action {dwAction} (SolutionFlags: {solutionFlags}."); return BuildAction.Unknown; } } diff --git a/src/BuildVision/Properties/GlobalSuppressions.cs b/src/BuildVision/Properties/GlobalSuppressions.cs index 89393d0c..d7cbbcd4 100644 --- a/src/BuildVision/Properties/GlobalSuppressions.cs +++ b/src/BuildVision/Properties/GlobalSuppressions.cs @@ -2,32 +2,4 @@ // attributes that are applied to this project. // Project-level suppressions either have no target or are given // a specific target and scoped to a namespace, type, member, etc. -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1305:Specify IFormatProvider", Justification = "", Scope = "member", Target = "~M:BuildVision.Helpers.ProjectExtensions.GetFrameworkString(EnvDTE.Project)~System.String")] -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1305:Specify IFormatProvider", Justification = "", Scope = "member", Target = "~M:BuildVision.Helpers.ProjectExtensions.GetProjectTypeFromRegistry(System.String,System.String)~System.String")] -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1305:Specify IFormatProvider", Justification = "", Scope = "member", Target = "~M:BuildVision.Tool.Building.BuildService.GetCopyBuildOutputFilesToClipboardActionMessage(System.String,System.String[])~System.String")] -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.Core.BuildInformationProvider.BuildOutputLogger_OnErrorRaised(BuildVision.UI.Contracts.BuildProjectContextEntry,System.Object,BuildVision.Contracts.ErrorLevel)")] -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.Core.BuildInformationProvider.ProjectBuildStarted(BuildVision.UI.Models.IProjectItem,BuildVision.Contracts.BuildAction)")] -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.Core.SolutionProvider.RefrehSolutionModel")] -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.Helpers.ProjectExtensions.GetExtenderNames(EnvDTE.Project)~System.String")] -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.Helpers.ProjectExtensions.GetFlavourTypes(EnvDTE.Project)~System.Collections.Generic.IEnumerable{System.String}")] -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.Helpers.ProjectExtensions.GetFrameworkString(EnvDTE.Project)~System.String")] -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.Helpers.ProjectExtensions.GetLanguageName(EnvDTE.Project)~System.String")] -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.Helpers.ProjectExtensions.GetOutputType(EnvDTE.Project)~System.String")] -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.Helpers.ProjectExtensions.GetProjectTypeFromRegistry(System.String,System.String)~System.String")] -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.Helpers.ProjectExtensions.GetTreePath(EnvDTE.Project,System.Boolean)~System.String")] -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.Helpers.ProjectExtensions.IsHidden(EnvDTE.Project)~System.Boolean")] -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.Helpers.ProjectExtensions.IsProjectHidden(System.String)~System.Boolean")] -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.Helpers.ProjectExtensions.TryGetParentProject(EnvDTE.Project)~EnvDTE.Project")] -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.Helpers.PropertiesExtensions.TryGetPropertyValueOrDefault(EnvDTE.Properties,System.String)~System.Object")] -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.Helpers.SolutionProjectsExtensions.GetProjectItems(EnvDTE.Solution)~System.Collections.Generic.IList{BuildVision.UI.Models.ProjectItem}")] -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.Helpers.SolutionProjectsExtensions.ToSolutionBuildState(EnvDTE.Solution)~BuildVision.Core.SolutionModel")] -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.Helpers.SolutionProjectsExtensions.UpdateNameProperties(EnvDTE.Project,BuildVision.UI.Models.ProjectItem)")] -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.Helpers.SolutionProjectsExtensions.UpdateProperties(EnvDTE.Project,BuildVision.UI.Models.ProjectItem,System.String,System.String)")] -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.Services.ErrorNavigationService.NavigateToErrorItem(BuildVision.Contracts.ErrorItem)")] -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.Tool.Building.BuildOutputLogger.Attach")] -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.Tool.Building.BuildOutputLogger.EventSource_ErrorRaised(Microsoft.Build.Framework.BuildEventArgs,BuildVision.Contracts.ErrorLevel)")] -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.Tool.Building.BuildService.CancelBuildAsync(BuildVision.Contracts.Models.IBuildInformationModel)~System.Threading.Tasks.Task")] -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.Tool.Building.BuildService.ProjectCopyBuildOutputFilesToClipBoard(BuildVision.UI.Models.IProjectItem)")] -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.Tool.Building.BuildService.RaiseCommand(Microsoft.VisualStudio.VSConstants.VSStd97CmdID)")] -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.Tool.Building.BuildService.RaiseCommandForSelectedProject(BuildVision.UI.Models.IProjectItem,System.Int32)")] -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:BuildVision.Views.Settings.PackageSettingsProvider.LoadSettings")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1305:Specify IFormatProvider", Justification = "")] diff --git a/src/BuildVision/Services/BuildInformationProvider.cs b/src/BuildVision/Services/BuildInformationProvider.cs index 66f37863..ffb84d4c 100644 --- a/src/BuildVision/Services/BuildInformationProvider.cs +++ b/src/BuildVision/Services/BuildInformationProvider.cs @@ -1,10 +1,12 @@ using System; +using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel.Composition; using System.Diagnostics; using System.Linq; using System.Threading; using BuildVision.Common; +using BuildVision.Common.Diagnostics; using BuildVision.Common.Logging; using BuildVision.Contracts; using BuildVision.Contracts.Models; @@ -206,6 +208,7 @@ public void BuildStarted(BuildAction buildAction, BuildScope buildScope) BuildInformationModel.CurrentBuildState = BuildState.InProgress; BuildInformationModel.BuildAction = buildAction; BuildInformationModel.BuildScope = buildScope; + BuildInformationModel.BuildId = Guid.NewGuid(); _buildProcessCancellationToken = new CancellationTokenSource(); _windowStateService.ApplyToolWindowStateAction(_packageSettingsProvider.Settings.WindowSettings.WindowActionOnBuildBegin); @@ -216,6 +219,13 @@ public void BuildStarted(BuildAction buildAction, BuildScope buildScope) _origTextCurrentState = message; BuildInformationModel.StateMessage = _origTextCurrentState; _taskBarInfoService.UpdateTaskBarInfo(BuildInformationModel.CurrentBuildState, BuildInformationModel.BuildScope, Projects.Count, GetFinishedProjectsCount()); + + DiagnosticsClient.TrackEvent("BuildStarted", new Dictionary + { + { "BuildId", BuildInformationModel.BuildId.ToString() }, + { "BuildAction", buildAction.ToString() }, + { "BuildScope", buildScope.ToString() } + }); } public void ProjectBuildStarted(IProjectItem projectItem, BuildAction buildAction) @@ -369,6 +379,17 @@ public void BuildFinished(bool success, bool canceled) BuildInformationModel.CurrentBuildState = canceled ? BuildState.Cancelled : BuildState.Failed; } + DiagnosticsClient.TrackEvent("BuildFinished", new Dictionary + { + { "BuildId", BuildInformationModel.BuildId.ToString() }, + { "BuildAction", BuildInformationModel.BuildAction.ToString() }, + { "BuildScope", BuildInformationModel.BuildScope.ToString() }, + { "BuildState", BuildInformationModel.CurrentBuildState.ToString() }, + { "BuildStartTime", BuildInformationModel.BuildStartTime.ToString() }, + { "BuildFinishTime", BuildInformationModel.BuildFinishTime.ToString() }, + { "ProjectsCount", Projects.Count.ToString() }, + }); + var message = _buildMessagesFactory.GetBuildDoneMessage(BuildInformationModel); _statusBarNotificationService.ShowText(message); BuildInformationModel.StateMessage = message; diff --git a/src/BuildVision/Views/Settings/SettingsDialogPage.cs b/src/BuildVision/Views/Settings/SettingsDialogPage.cs index 38c95de6..e0fd4f4e 100644 --- a/src/BuildVision/Views/Settings/SettingsDialogPage.cs +++ b/src/BuildVision/Views/Settings/SettingsDialogPage.cs @@ -7,6 +7,7 @@ using BuildVision.Core; using BuildVision.UI.Settings.Models; using Microsoft; +using BuildVision.Common.Diagnostics; namespace BuildVision.Views.Settings { @@ -46,6 +47,7 @@ protected override void OnActivate(CancelEventArgs e) } base.OnActivate(e); + DiagnosticsClient.TrackPageView(GetType().Name); } protected override void OnApply(PageApplyEventArgs args) From edc8082e0a44964b7344cb0cd81189f787e6d89b Mon Sep 17 00:00:00 2001 From: Stefan Kert Date: Sat, 27 Apr 2019 14:29:35 +0200 Subject: [PATCH 089/100] fixed build --- src/BuildVision.UI/Models/BuildInformationModel.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/BuildVision.UI/Models/BuildInformationModel.cs b/src/BuildVision.UI/Models/BuildInformationModel.cs index 3df365a3..530f20b6 100644 --- a/src/BuildVision.UI/Models/BuildInformationModel.cs +++ b/src/BuildVision.UI/Models/BuildInformationModel.cs @@ -126,7 +126,14 @@ public IProjectItem CurrentProject get => _currentProject; set => SetProperty(ref _currentProject, value); } - + + private Guid _buildId = Guid.Empty; + public Guid BuildId + { + get => _buildId; + set => SetProperty(ref _buildId, value); + } + private string GetStateIconKey() { var resultState = GetBuildResultState(); From 393c29b5e2b91d716bf70c9aac2e97c792c3cbca Mon Sep 17 00:00:00 2001 From: Stefan Kert Date: Fri, 5 Jul 2019 15:33:02 +0200 Subject: [PATCH 090/100] Updating order of elements --- .../Providers/IBuildInformationProvider.cs | 5 ++++- src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs | 7 +++++++ src/BuildVision/Services/BuildInformationProvider.cs | 6 +++++- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/BuildVision.Exports/Providers/IBuildInformationProvider.cs b/src/BuildVision.Exports/Providers/IBuildInformationProvider.cs index f3316d36..82d8842c 100644 --- a/src/BuildVision.Exports/Providers/IBuildInformationProvider.cs +++ b/src/BuildVision.Exports/Providers/IBuildInformationProvider.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Collections.ObjectModel; using BuildVision.Contracts; using BuildVision.Contracts.Models; @@ -19,5 +20,7 @@ public interface IBuildInformationProvider void BuildStarted(BuildAction currentBuildAction, BuildScope scope); void BuildUpdate(); void ResetBuildInformationModel(); + + event Action BuildUpdated; } } diff --git a/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs b/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs index 8d8e7cf3..9bd494c4 100644 --- a/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs +++ b/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs @@ -10,6 +10,7 @@ using System.Windows.Controls; using System.Windows.Data; using System.Windows.Input; +using System.Windows.Threading; using BuildVision.Common; using BuildVision.Common.Logging; using BuildVision.Contracts; @@ -26,6 +27,7 @@ using BuildVision.UI.Settings.Models; using BuildVision.Views.Settings; using Microsoft.VisualStudio; +using Microsoft.VisualStudio.Threading; using Serilog; using Process = System.Diagnostics.Process; using SortDescription = BuildVision.UI.Settings.Models.Sorting.SortDescription; @@ -212,6 +214,11 @@ public BuildVisionPaneViewModel( SolutionModel = solutionProvider.GetSolutionModel(); ControlSettings = settingsProvider.Settings; Projects = _buildInformationProvider.Projects; + + _buildInformationProvider.BuildUpdated += () => + { + Application.Current.Dispatcher.BeginInvoke(new Action(() => OnPropertyChanged(nameof(GroupedProjectsList)))); + }; _settingsProvider = settingsProvider; _settingsProvider.SettingsChanged += () => diff --git a/src/BuildVision/Services/BuildInformationProvider.cs b/src/BuildVision/Services/BuildInformationProvider.cs index ffb84d4c..7efef66c 100644 --- a/src/BuildVision/Services/BuildInformationProvider.cs +++ b/src/BuildVision/Services/BuildInformationProvider.cs @@ -5,6 +5,7 @@ using System.Diagnostics; using System.Linq; using System.Threading; +using System.Threading.Tasks; using BuildVision.Common; using BuildVision.Common.Diagnostics; using BuildVision.Common.Logging; @@ -212,7 +213,7 @@ public void BuildStarted(BuildAction buildAction, BuildScope buildScope) _buildProcessCancellationToken = new CancellationTokenSource(); _windowStateService.ApplyToolWindowStateAction(_packageSettingsProvider.Settings.WindowSettings.WindowActionOnBuildBegin); - System.Threading.Tasks.Task.Run(() => Run(_buildProcessCancellationToken.Token), _buildProcessCancellationToken.Token); + Task.Run(() => Run(_buildProcessCancellationToken.Token), _buildProcessCancellationToken.Token); string message = _buildMessagesFactory.GetBuildBeginMajorMessage(BuildInformationModel); _statusBarNotificationService.ShowTextWithFreeze(message); @@ -347,6 +348,7 @@ public void BuildUpdate() { project.RaiseBuildElapsedTimeChanged(); } + BuildUpdated?.Invoke(); } public void BuildFinished(bool success, bool canceled) @@ -428,5 +430,7 @@ public void BuildFinished(bool success, bool canceled) } } } + + public event Action BuildUpdated; } } From 8fd3995b464325e33fea4b8a5a0b7f8d7fc7d274 Mon Sep 17 00:00:00 2001 From: Stefan Kert Date: Fri, 5 Jul 2019 16:07:32 +0200 Subject: [PATCH 091/100] Returning right number for warned projects --- src/BuildVision.UI/Models/BuildInformationModel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/BuildVision.UI/Models/BuildInformationModel.cs b/src/BuildVision.UI/Models/BuildInformationModel.cs index 530f20b6..c0039dca 100644 --- a/src/BuildVision.UI/Models/BuildInformationModel.cs +++ b/src/BuildVision.UI/Models/BuildInformationModel.cs @@ -53,7 +53,7 @@ public int FailedProjectsCount private int _warnedProjectsCount = 0; public int WarnedProjectsCount { - get => _warningsCount; + get => _warnedProjectsCount; set => SetProperty(ref _warnedProjectsCount, value); } From 10838b8cc14c4ddbe16e5026e83696a082a48fc9 Mon Sep 17 00:00:00 2001 From: Stefan Kert Date: Fri, 5 Jul 2019 16:17:30 +0200 Subject: [PATCH 092/100] Fixed double parantheses (as proposed by toughengineer thanks :)) --- src/BuildVision.UI/Helpers/BuildMessagesFactory.cs | 13 ++++++------- .../Services/BuildInformationProvider.cs | 2 +- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/BuildVision.UI/Helpers/BuildMessagesFactory.cs b/src/BuildVision.UI/Helpers/BuildMessagesFactory.cs index 9139e68c..36af09c4 100644 --- a/src/BuildVision.UI/Helpers/BuildMessagesFactory.cs +++ b/src/BuildVision.UI/Helpers/BuildMessagesFactory.cs @@ -58,7 +58,7 @@ private string GetTimeString(DateTime? startTime) } } - private string GetBeginAtString(BuildAction? buildAction) + private static string GetBeginAtString(BuildAction? buildAction) { switch (buildAction.Value) { @@ -75,7 +75,7 @@ private string GetBeginAtString(BuildAction? buildAction) } } - private string GetActionName(BuildAction buildAction) + private static string GetActionName(BuildAction buildAction) { switch (buildAction) { @@ -92,7 +92,7 @@ private string GetActionName(BuildAction buildAction) } } - private string GetUnitName(BuildScope buildScope) + private static string GetUnitName(BuildScope buildScope) { string unitName = ""; switch (buildScope) @@ -210,7 +210,7 @@ private string GetBuildDoneMajorMessage(IBuildInformationModel buildInformationM return resultMainString; } - private string GetResultName(BuildResultState resultState) + private static string GetResultName(BuildResultState resultState) { switch (resultState) { @@ -243,9 +243,8 @@ private string GetBuildDoneExtraMessage(IBuildInformationModel buildInformationM return string.Empty; } - TimeSpan timeSpan = buildInformationModel.BuildFinishTime.Value.Subtract(buildInformationModel.BuildStartTime.Value); - string extraTimePartString = GetExtraTimePartString(timeSpan); - return string.Format(_packageSettingsProvider.Settings.BuildMessagesSettings.ExtraMessageStringFormat, extraTimePartString); + var timeSpan = buildInformationModel.BuildFinishTime.Value.Subtract(buildInformationModel.BuildStartTime.Value); + return GetExtraTimePartString(timeSpan); } private string GetExtraTimePartString(TimeSpan timeSpan) diff --git a/src/BuildVision/Services/BuildInformationProvider.cs b/src/BuildVision/Services/BuildInformationProvider.cs index 7efef66c..8acbffc8 100644 --- a/src/BuildVision/Services/BuildInformationProvider.cs +++ b/src/BuildVision/Services/BuildInformationProvider.cs @@ -50,7 +50,7 @@ public class BuildInformationProvider : IBuildInformationProvider public IBuildInformationModel BuildInformationModel { get; } = new BuildInformationModel(); public ObservableCollection Projects { get; } = new ObservableRangeCollection(); - + [ImportingConstructor] public BuildInformationProvider( [Import(typeof(IBuildOutputLogger))] IBuildOutputLogger buildOutputLogger, From 13eb0fa3567bcb1eb4074dbeaa8770a6a57e58f3 Mon Sep 17 00:00:00 2001 From: Stefan Kert Date: Fri, 5 Jul 2019 16:37:05 +0200 Subject: [PATCH 093/100] Fixed contextmenu checkboxes. Settings are now refreshed if the checkbox is activated/deactivated --- src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs b/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs index 9bd494c4..67519696 100644 --- a/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs +++ b/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs @@ -227,6 +227,12 @@ public BuildVisionPaneViewModel( SyncColumnSettings(); }; + ControlSettings.PropertyChanged += (sender, e) => + { + OnControlSettingsChanged(); + SyncColumnSettings(); + }; + if (settingsProvider.Settings.GeneralSettings.FillProjectListOnBuildBegin) { Projects.CollectionChanged += (sender, e) => From 74ff988887322d44b74fed244a205d6801b7e968 Mon Sep 17 00:00:00 2001 From: Stefan Kert Date: Fri, 4 Oct 2019 14:08:22 +0200 Subject: [PATCH 094/100] Cleanup --- src/BuildVision/Core/Services.cs | 10 +--- src/BuildVision/Core/SolutionBuildEvents.cs | 55 ++++--------------- .../Services/BuildInformationProvider.cs | 10 +--- 3 files changed, 14 insertions(+), 61 deletions(-) diff --git a/src/BuildVision/Core/Services.cs b/src/BuildVision/Core/Services.cs index 8ed77ae0..3dd6735a 100644 --- a/src/BuildVision/Core/Services.cs +++ b/src/BuildVision/Core/Services.cs @@ -40,14 +40,8 @@ static Ret GetGlobalService(IServiceProvider provider = null) where T : public static DTE2 Dte2 => Dte as DTE2; - public static IVsSolution GetSolution(this IServiceProvider provider) - { - return GetGlobalService(provider); - } + public static IVsSolution GetSolution(this IServiceProvider provider) => GetGlobalService(provider); - public static IVsSolution GetSolution() - { - return GetGlobalService(); - } + public static IVsSolution GetSolution() => GetGlobalService(); } } diff --git a/src/BuildVision/Core/SolutionBuildEvents.cs b/src/BuildVision/Core/SolutionBuildEvents.cs index 07fa3f7a..4963338a 100644 --- a/src/BuildVision/Core/SolutionBuildEvents.cs +++ b/src/BuildVision/Core/SolutionBuildEvents.cs @@ -64,51 +64,16 @@ public int UpdateSolution_Done(int fSucceeded, int fModified, int fCancelCommand } #region Interface Implementation - - public int UpdateSolution_Begin(ref int pfCancelUpdate) - { - return VSConstants.S_OK; - } - - public int UpdateSolution_StartUpdate(ref int pfCancelUpdate) - { - return VSConstants.S_OK; - } - - public int UpdateSolution_Cancel() - { - return VSConstants.S_OK; - } - - public int OnActiveProjectCfgChange(IVsHierarchy pIVsHierarchy) - { - return VSConstants.S_OK; - } - - public void UpdateSolution_EndUpdateAction(uint dwAction) - { - } - - public void OnActiveProjectCfgChangeBatchBegin() - { - } - - public void OnActiveProjectCfgChangeBatchEnd() - { - } - - public void UpdateSolution_QueryDelayFirstUpdateAction(out int pfDelay) - { - pfDelay = 0; - } - - public void UpdateSolution_BeginFirstUpdateAction() - { - } - - public void UpdateSolution_EndLastUpdateAction() - { - } + public int UpdateSolution_Begin(ref int pfCancelUpdate) => VSConstants.S_OK; + public int UpdateSolution_StartUpdate(ref int pfCancelUpdate) => VSConstants.S_OK; + public int UpdateSolution_Cancel() => VSConstants.S_OK; + public int OnActiveProjectCfgChange(IVsHierarchy pIVsHierarchy) => VSConstants.S_OK; + public void UpdateSolution_QueryDelayFirstUpdateAction(out int pfDelay) => pfDelay = 0; + public void UpdateSolution_EndUpdateAction(uint dwAction) { } + public void OnActiveProjectCfgChangeBatchBegin() { } + public void OnActiveProjectCfgChangeBatchEnd() { } + public void UpdateSolution_BeginFirstUpdateAction() { } + public void UpdateSolution_EndLastUpdateAction() { } #endregion } } diff --git a/src/BuildVision/Services/BuildInformationProvider.cs b/src/BuildVision/Services/BuildInformationProvider.cs index 8acbffc8..00d6be3f 100644 --- a/src/BuildVision/Services/BuildInformationProvider.cs +++ b/src/BuildVision/Services/BuildInformationProvider.cs @@ -81,15 +81,9 @@ public void ReloadCurrentProjects() ((ObservableRangeCollection< IProjectItem>)Projects).AddRange(_solutionProvider.GetProjects()); } - public void ResetCurrentProjects() - { - Projects.Clear(); - } + public void ResetCurrentProjects() => Projects.Clear(); - public void ResetBuildInformationModel() - { - BuildInformationModel.ResetState(); - } + public void ResetBuildInformationModel() => BuildInformationModel.ResetState(); private void BuildOutputLogger_OnErrorRaised(BuildProjectContextEntry projectEntry, object e, ErrorLevel errorLevel) { From bae30e615b26ed9d778aac9ff1d10a59485dd755 Mon Sep 17 00:00:00 2001 From: Stefan Kert Date: Fri, 4 Oct 2019 21:04:45 +0200 Subject: [PATCH 095/100] Fixed some performance issues --- .../Providers/IBuildInformationProvider.cs | 2 - .../ViewModels/BuildVisionPaneViewModel.cs | 5 -- .../Helpers/SolutionProjectsExtensions.cs | 61 +++++++++---------- .../Services/BuildInformationProvider.cs | 43 ++++--------- src/BuildVision/Services/BuildOutputLogger.cs | 14 ++--- 5 files changed, 47 insertions(+), 78 deletions(-) diff --git a/src/BuildVision.Exports/Providers/IBuildInformationProvider.cs b/src/BuildVision.Exports/Providers/IBuildInformationProvider.cs index 82d8842c..f010b82a 100644 --- a/src/BuildVision.Exports/Providers/IBuildInformationProvider.cs +++ b/src/BuildVision.Exports/Providers/IBuildInformationProvider.cs @@ -20,7 +20,5 @@ public interface IBuildInformationProvider void BuildStarted(BuildAction currentBuildAction, BuildScope scope); void BuildUpdate(); void ResetBuildInformationModel(); - - event Action BuildUpdated; } } diff --git a/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs b/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs index 67519696..61c0f4ec 100644 --- a/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs +++ b/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs @@ -215,11 +215,6 @@ public BuildVisionPaneViewModel( ControlSettings = settingsProvider.Settings; Projects = _buildInformationProvider.Projects; - _buildInformationProvider.BuildUpdated += () => - { - Application.Current.Dispatcher.BeginInvoke(new Action(() => OnPropertyChanged(nameof(GroupedProjectsList)))); - }; - _settingsProvider = settingsProvider; _settingsProvider.SettingsChanged += () => { diff --git a/src/BuildVision/Helpers/SolutionProjectsExtensions.cs b/src/BuildVision/Helpers/SolutionProjectsExtensions.cs index fd153970..f7ddcd5c 100644 --- a/src/BuildVision/Helpers/SolutionProjectsExtensions.cs +++ b/src/BuildVision/Helpers/SolutionProjectsExtensions.cs @@ -12,6 +12,8 @@ namespace BuildVision.Helpers { public static class SolutionProjectsExtensions { + private static IList _cachedProjects; + public static SolutionModel ToSolutionBuildState(this Solution solution) { var solutionItem = new SolutionModel(); @@ -57,40 +59,9 @@ public static SolutionModel ToSolutionBuildState(this Solution solution) return solutionItem; } - public static IList GetProjects(this Solution solution) - { - var list = new List(); - foreach (var proj in solution.Projects) - { - var project = proj as Project; - if (project == null) - { - continue; - } - - if (project.Kind == EnvDTEProjectKinds.ProjectKindSolutionFolder) - { - list.AddRange(project.GetSubProjects()); - } - else if (!project.IsHidden()) - { - list.Add(project); - } - } - return list; - } + public static Project FirstOrDefaultProject(this Solution solution, Func cond) => _cachedProjects.FirstOrDefault(cond); - public static Project FirstOrDefaultProject(this Solution solution, Func cond) - { - var projects = solution.GetProjects(); - return projects.FirstOrDefault(cond); - } - - public static Project FirstProject(this Solution solution, Func cond) - { - var projects = solution.GetProjects(); - return projects.First(cond); - } + public static Project FirstProject(this Solution solution, Func cond) => _cachedProjects.First(cond); public static IList GetProjectItems(this Solution solution) { @@ -98,6 +69,7 @@ public static IList GetProjectItems(this Solution solution) try { dteProjects = solution.GetProjects(); + _cachedProjects = dteProjects; } catch (Exception ex) { @@ -123,6 +95,29 @@ public static IList GetProjectItems(this Solution solution) return projectItems; } + public static IList GetProjects(this Solution solution) + { + var list = new List(); + foreach (var proj in solution.Projects) + { + var project = proj as Project; + if (project == null) + { + continue; + } + + if (project.Kind == EnvDTEProjectKinds.ProjectKindSolutionFolder) + { + list.AddRange(project.GetSubProjects()); + } + else if (!project.IsHidden()) + { + list.Add(project); + } + } + return list; + } + public static void UpdateProperties(Project project, ProjectItem projectItem, string configuration = null, string platform = null) { if (project != null) diff --git a/src/BuildVision/Services/BuildInformationProvider.cs b/src/BuildVision/Services/BuildInformationProvider.cs index 00d6be3f..c52d9ccb 100644 --- a/src/BuildVision/Services/BuildInformationProvider.cs +++ b/src/BuildVision/Services/BuildInformationProvider.cs @@ -43,10 +43,9 @@ public class BuildInformationProvider : IBuildInformationProvider private readonly IBuildService _buildService; private readonly ITaskBarInfoService _taskBarInfoService; private string _origTextCurrentState; - private const int BuildInProcessCountOfQuantumSleep = 5; - private const int BuildInProcessQuantumSleep = 50; - private CancellationTokenSource _buildProcessCancellationToken; + private const int BuildInProcessQuantumSleep = 250; private int _currentQueuePosOfBuildingProject = 0; + private Timer _timer; public IBuildInformationModel BuildInformationModel { get; } = new BuildInformationModel(); public ObservableCollection Projects { get; } = new ObservableRangeCollection(); @@ -78,7 +77,7 @@ public BuildInformationProvider( public void ReloadCurrentProjects() { Projects.Clear(); - ((ObservableRangeCollection< IProjectItem>)Projects).AddRange(_solutionProvider.GetProjects()); + ((ObservableRangeCollection)Projects).AddRange(_solutionProvider.GetProjects()); } public void ResetCurrentProjects() => Projects.Clear(); @@ -171,24 +170,6 @@ private bool TryGetProjectItem(BuildProjectContextEntry projectEntry, out IProje return true; } - public void Run(CancellationToken cancellationToken) - { - while (!cancellationToken.IsCancellationRequested) - { - BuildUpdate(); - - for (int i = 0; i < BuildInProcessQuantumSleep * BuildInProcessCountOfQuantumSleep; i += BuildInProcessQuantumSleep) - { - if (cancellationToken.IsCancellationRequested) - { - break; - } - - Thread.Sleep(BuildInProcessQuantumSleep); - } - } - } - public void BuildStarted(BuildAction buildAction, BuildScope buildScope) { _currentQueuePosOfBuildingProject = 0; @@ -205,10 +186,9 @@ public void BuildStarted(BuildAction buildAction, BuildScope buildScope) BuildInformationModel.BuildScope = buildScope; BuildInformationModel.BuildId = Guid.NewGuid(); - _buildProcessCancellationToken = new CancellationTokenSource(); _windowStateService.ApplyToolWindowStateAction(_packageSettingsProvider.Settings.WindowSettings.WindowActionOnBuildBegin); - Task.Run(() => Run(_buildProcessCancellationToken.Token), _buildProcessCancellationToken.Token); - + _timer = new Timer(state => BuildUpdate(), null, BuildInProcessQuantumSleep, BuildInProcessQuantumSleep); + string message = _buildMessagesFactory.GetBuildBeginMajorMessage(BuildInformationModel); _statusBarNotificationService.ShowTextWithFreeze(message); _origTextCurrentState = message; @@ -335,14 +315,17 @@ private ProjectState GetProjectState(bool success, bool canceled, IProjectItem c public void BuildUpdate() { + if(BuildInformationModel.CurrentBuildState != BuildState.InProgress) + { + _logger.Error("Build is finished but thread still running."); + } var message = _origTextCurrentState + _buildMessagesFactory.GetBuildBeginExtraMessage(BuildInformationModel); BuildInformationModel.StateMessage = message; _statusBarNotificationService.ShowTextWithFreeze(message); - foreach (var project in Projects) + foreach (var project in Projects.Where(x => x.BuildStartTime.HasValue && !x.BuildFinishTime.HasValue)) { project.RaiseBuildElapsedTimeChanged(); } - BuildUpdated?.Invoke(); } public void BuildFinished(bool success, bool canceled) @@ -363,8 +346,8 @@ public void BuildFinished(bool success, bool canceled) } } - _buildProcessCancellationToken.Cancel(); - + _timer.Dispose(); + _logger.Information("Canceled build"); BuildInformationModel.BuildFinishTime = DateTime.Now; if (success) { @@ -424,7 +407,5 @@ public void BuildFinished(bool success, bool canceled) } } } - - public event Action BuildUpdated; } } diff --git a/src/BuildVision/Services/BuildOutputLogger.cs b/src/BuildVision/Services/BuildOutputLogger.cs index fdc015b7..5cd7db13 100644 --- a/src/BuildVision/Services/BuildOutputLogger.cs +++ b/src/BuildVision/Services/BuildOutputLogger.cs @@ -20,7 +20,7 @@ public class BuildOutputLogger : Logger, IBuildOutputLogger private Serilog.ILogger _logger = LogManager.ForContext(); public RegisterLoggerResult LoggerState { get; set; } - private List _projects = new List(); + private Dictionary _projects = new Dictionary(); public BuildOutputLogger(Guid loggerId, LoggerVerbosity loggerVerbosity) { @@ -30,7 +30,7 @@ public BuildOutputLogger(Guid loggerId, LoggerVerbosity loggerVerbosity) public override void Initialize(IEventSource eventSource) { - _projects = new List(); + _projects = new Dictionary(); eventSource.ProjectStarted += OnProjectStarted; eventSource.MessageRaised += (s, e) => EventSource_ErrorRaised(e, ErrorLevel.Message); eventSource.WarningRaised += (s, e) => EventSource_ErrorRaised(e, ErrorLevel.Warning); @@ -39,7 +39,8 @@ public override void Initialize(IEventSource eventSource) private void OnProjectStarted(object sender, ProjectStartedEventArgs e) { - _projects.Add(new BuildProjectContextEntry( + var identifier = $"{e.BuildEventContext.ProjectInstanceId}{e.BuildEventContext.ProjectContextId}"; + _projects.Add(identifier, new BuildProjectContextEntry( e.BuildEventContext.ProjectInstanceId, e.BuildEventContext.ProjectContextId, e.ProjectFile, @@ -95,7 +96,7 @@ public void Attach() public bool IsProjectUpToDate(IProjectItem projectItem) { - return !_projects.Exists(t => t.FileName == projectItem.FullName); + return !_projects.Any(x => x.Value.FileName == projectItem.FullName); } private void EventSource_ErrorRaised(BuildEventArgs e, ErrorLevel errorLevel) @@ -109,9 +110,8 @@ private void EventSource_ErrorRaised(BuildEventArgs e, ErrorLevel errorLevel) int projectInstanceId = e.BuildEventContext.ProjectInstanceId; int projectContextId = e.BuildEventContext.ProjectContextId; - - var projectEntry = _projects.Find(t => t.InstanceId == projectInstanceId && t.ContextId == projectContextId); - if (projectEntry == null) + var identifier = $"{projectInstanceId}{projectContextId}"; + if (!_projects.TryGetValue(identifier, out var projectEntry)) { _logger.Warning("Project entry not found by ProjectInstanceId='{ProjectInstanceId}' and ProjectContextId='{ProjectContextId}'.", projectInstanceId, projectContextId); return; From 3da540bb625b511e373c8244bb27f30251fc28c2 Mon Sep 17 00:00:00 2001 From: Stefan Kert Date: Sat, 5 Oct 2019 14:05:03 +0200 Subject: [PATCH 096/100] Several fixes --- .../Models/BuildProjectContextEntry.cs | 12 +-- .../Models/IBuildInformationModel.cs | 1 + .../Providers/IBuildInformationProvider.cs | 3 +- .../Helpers/BuildMessagesFactory.cs | 2 +- .../Models/BuildInformationModel.cs | 2 + .../ViewModels/BuildVisionPaneViewModel.cs | 4 +- src/BuildVision/Core/BuildVisionPackage.cs | 2 +- src/BuildVision/Core/SolutionBuildEvents.cs | 78 +++++++++++---- src/BuildVision/Helpers/ProjectExtensions.cs | 9 +- .../Helpers/SolutionProjectsExtensions.cs | 18 +++- .../Services/BuildInformationProvider.cs | 99 ++++++++++--------- src/BuildVision/Services/BuildOutputLogger.cs | 48 ++++----- 12 files changed, 172 insertions(+), 106 deletions(-) diff --git a/src/BuildVision.Contracts/Models/BuildProjectContextEntry.cs b/src/BuildVision.Contracts/Models/BuildProjectContextEntry.cs index 41b5a3c6..64f8528a 100644 --- a/src/BuildVision.Contracts/Models/BuildProjectContextEntry.cs +++ b/src/BuildVision.Contracts/Models/BuildProjectContextEntry.cs @@ -5,11 +5,7 @@ namespace BuildVision.UI.Contracts { public class BuildProjectContextEntry { - public int InstanceId { get; set; } - - public int ContextId { get; set; } - - public string FileName { get; set; } + public string ProjectFile { get; set; } public IDictionary Properties { get; } @@ -17,11 +13,9 @@ public class BuildProjectContextEntry public bool IsInvalid { get; set; } - public BuildProjectContextEntry(int instanceId, int contextId, string fileName, IDictionary properties) + public BuildProjectContextEntry(string fileName, IDictionary properties) { - InstanceId = instanceId; - ContextId = contextId; - FileName = fileName; + ProjectFile = fileName; Properties = properties; } } diff --git a/src/BuildVision.Contracts/Models/IBuildInformationModel.cs b/src/BuildVision.Contracts/Models/IBuildInformationModel.cs index f524b06d..4e35f442 100644 --- a/src/BuildVision.Contracts/Models/IBuildInformationModel.cs +++ b/src/BuildVision.Contracts/Models/IBuildInformationModel.cs @@ -26,6 +26,7 @@ public interface IBuildInformationModel : INotifyPropertyChanged string StateIconKey { get; } IProjectItem CurrentProject { get; set; } + int GetFinishedProjectsCount(); void ResetState(); } } diff --git a/src/BuildVision.Exports/Providers/IBuildInformationProvider.cs b/src/BuildVision.Exports/Providers/IBuildInformationProvider.cs index f010b82a..ed69e19c 100644 --- a/src/BuildVision.Exports/Providers/IBuildInformationProvider.cs +++ b/src/BuildVision.Exports/Providers/IBuildInformationProvider.cs @@ -18,7 +18,8 @@ public interface IBuildInformationProvider void ResetCurrentProjects(); void BuildFinished(bool success, bool canceled); void BuildStarted(BuildAction currentBuildAction, BuildScope scope); - void BuildUpdate(); void ResetBuildInformationModel(); + + event Action BuildStateChanged; } } diff --git a/src/BuildVision.UI/Helpers/BuildMessagesFactory.cs b/src/BuildVision.UI/Helpers/BuildMessagesFactory.cs index 36af09c4..f7b3da21 100644 --- a/src/BuildVision.UI/Helpers/BuildMessagesFactory.cs +++ b/src/BuildVision.UI/Helpers/BuildMessagesFactory.cs @@ -88,7 +88,7 @@ private static string GetActionName(BuildAction buildAction) case BuildAction.Clean: return Resources.BuildActionClean; default: - throw new ArgumentOutOfRangeException(nameof(buildAction)); + throw new ArgumentOutOfRangeException(nameof(buildAction), $"Actual: {buildAction}"); } } diff --git a/src/BuildVision.UI/Models/BuildInformationModel.cs b/src/BuildVision.UI/Models/BuildInformationModel.cs index c0039dca..a6620f2b 100644 --- a/src/BuildVision.UI/Models/BuildInformationModel.cs +++ b/src/BuildVision.UI/Models/BuildInformationModel.cs @@ -258,6 +258,8 @@ private BuildResultState GetBuildResultState() } } + public int GetFinishedProjectsCount() => SucceededProjectsCount + UpToDateProjectsCount + WarnedProjectsCount + FailedProjectsCount; + public void ResetState() { ErrorCount = 0; diff --git a/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs b/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs index 61c0f4ec..fa237bfb 100644 --- a/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs +++ b/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs @@ -214,7 +214,9 @@ public BuildVisionPaneViewModel( SolutionModel = solutionProvider.GetSolutionModel(); ControlSettings = settingsProvider.Settings; Projects = _buildInformationProvider.Projects; - + + _buildInformationProvider.BuildStateChanged += () => OnPropertyChanged(nameof(GroupedProjectsList)); + _settingsProvider = settingsProvider; _settingsProvider.SettingsChanged += () => { diff --git a/src/BuildVision/Core/BuildVisionPackage.cs b/src/BuildVision/Core/BuildVisionPackage.cs index 8fe625e8..966c43c3 100644 --- a/src/BuildVision/Core/BuildVisionPackage.cs +++ b/src/BuildVision/Core/BuildVisionPackage.cs @@ -139,7 +139,7 @@ private void SolutionEvents_Opened() _buildInformationProvider.ResetCurrentProjects(); _buildInformationProvider.ResetBuildInformationModel(); - _solutionBuildEvents = new SolutionBuildEvents(_solutionProvider, _buildInformationProvider, _serviceProvider); + _solutionBuildEvents = new SolutionBuildEvents(_solutionProvider, _buildInformationProvider, _serviceProvider, LogManager.ForContext()); _solutionBuildManager.AdviseUpdateSolutionEvents(_solutionBuildEvents, out _updateSolutionEventsCookie); _solutionBuildManager4.AdviseUpdateSolutionEvents4(_solutionBuildEvents, out _updateSolutionEvents4Cookie); } diff --git a/src/BuildVision/Core/SolutionBuildEvents.cs b/src/BuildVision/Core/SolutionBuildEvents.cs index 4963338a..386c13b7 100644 --- a/src/BuildVision/Core/SolutionBuildEvents.cs +++ b/src/BuildVision/Core/SolutionBuildEvents.cs @@ -6,6 +6,7 @@ using EnvDTE; using Microsoft.VisualStudio; using Microsoft.VisualStudio.Shell.Interop; +using Serilog; namespace BuildVision.Core { @@ -13,54 +14,97 @@ public class SolutionBuildEvents : IVsUpdateSolutionEvents2, IVsUpdateSolutionEv { private readonly ISolutionProvider _solutionProvider; private readonly IBuildInformationProvider _buildInformationProvider; + private readonly ILogger _logger; private readonly BuildEvents _buildEvents; private BuildAction _currentBuildAction; public SolutionBuildEvents( ISolutionProvider solutionProvider, IBuildInformationProvider buildInformationProvider, - IServiceProvider serviceProvider) + IServiceProvider serviceProvider, + ILogger logger) { _solutionProvider = solutionProvider; _buildInformationProvider = buildInformationProvider; + _logger = logger; _buildEvents = (serviceProvider.GetService(typeof(DTE)) as DTE).Events.BuildEvents; _buildEvents.OnBuildBegin += BuildEvents_OnBuildBegin; } public void UpdateSolution_BeginUpdateAction(uint dwAction) { - _solutionProvider.ReloadSolution(); - _currentBuildAction = StateConverterHelper.ConvertSolutionBuildFlagsToBuildAction(dwAction, (VSSOLNBUILDUPDATEFLAGS)dwAction); - _buildInformationProvider.ReloadCurrentProjects(); + try + { + _solutionProvider.ReloadSolution(); + _currentBuildAction = StateConverterHelper.ConvertSolutionBuildFlagsToBuildAction(dwAction, (VSSOLNBUILDUPDATEFLAGS)dwAction); + _buildInformationProvider.ReloadCurrentProjects(); + } + catch (Exception ex) + { + _logger.Error(ex, ""); + throw; + } } private void BuildEvents_OnBuildBegin(vsBuildScope scope, vsBuildAction action) { - // We use the action from UpdateSolution_BeginUpdateAction here because it givs closer details on the current action - _buildInformationProvider.BuildStarted(_currentBuildAction, (BuildScope)scope); + try + { + // We use the action from UpdateSolution_BeginUpdateAction here because it givs closer details on the current action + _buildInformationProvider.BuildStarted(_currentBuildAction, (BuildScope)scope); + } + catch (Exception ex) + { + _logger.Error(ex, ""); + throw; + } } public int UpdateProjectCfg_Begin(IVsHierarchy pHierProj, IVsCfg pCfgProj, IVsCfg pCfgSln, uint dwAction, ref int pfCancel) { - var projectItem = new UI.Models.ProjectItem(); - var configPair = pCfgProj.ToConfigurationTuple(); - SolutionProjectsExtensions.UpdateProperties(pHierProj.ToProject(), projectItem, configPair.Item1, configPair.Item2); - var buildAction = StateConverterHelper.ConvertSolutionBuildFlagsToBuildAction(dwAction, (VSSOLNBUILDUPDATEFLAGS)dwAction); - _buildInformationProvider.ProjectBuildStarted(projectItem, buildAction); - return VSConstants.S_OK; + try + { + var projectItem = new UI.Models.ProjectItem(); + var configPair = pCfgProj.ToConfigurationTuple(); + SolutionProjectsExtensions.UpdateProperties(pHierProj.ToProject(), projectItem, configPair.Item1, configPair.Item2); + var buildAction = StateConverterHelper.ConvertSolutionBuildFlagsToBuildAction(dwAction, (VSSOLNBUILDUPDATEFLAGS)dwAction); + _buildInformationProvider.ProjectBuildStarted(projectItem, buildAction); + return VSConstants.S_OK; + } + catch (Exception ex) + { + _logger.Error(ex, ""); + throw; + } } public int UpdateProjectCfg_Done(IVsHierarchy pHierProj, IVsCfg pCfgProj, IVsCfg pCfgSln, uint dwAction, int fSuccess, int fCancel) { - var buildAction = StateConverterHelper.ConvertSolutionBuildFlagsToBuildAction(dwAction, (VSSOLNBUILDUPDATEFLAGS)dwAction); - _buildInformationProvider.ProjectBuildFinished(buildAction, ProjectIdentifierGenerator.GetIdentifierForInteropTypes(pHierProj, pCfgProj), fSuccess == 1, fCancel == 1); - return VSConstants.S_OK; + try + { + var buildAction = StateConverterHelper.ConvertSolutionBuildFlagsToBuildAction(dwAction, (VSSOLNBUILDUPDATEFLAGS)dwAction); + _buildInformationProvider.ProjectBuildFinished(buildAction, ProjectIdentifierGenerator.GetIdentifierForInteropTypes(pHierProj, pCfgProj), fSuccess == 1, fCancel == 1); + return VSConstants.S_OK; + } + catch (Exception ex) + { + _logger.Error(ex, ""); + throw; + } } public int UpdateSolution_Done(int fSucceeded, int fModified, int fCancelCommand) { - _buildInformationProvider.BuildFinished(fSucceeded == 1, fCancelCommand == 1); - return VSConstants.S_OK; + try + { + _buildInformationProvider.BuildFinished(fSucceeded == 1, fCancelCommand == 1); + return VSConstants.S_OK; + } + catch (Exception ex) + { + _logger.Error(ex, ""); + throw; + } } #region Interface Implementation diff --git a/src/BuildVision/Helpers/ProjectExtensions.cs b/src/BuildVision/Helpers/ProjectExtensions.cs index a3d73037..f01b4816 100644 --- a/src/BuildVision/Helpers/ProjectExtensions.cs +++ b/src/BuildVision/Helpers/ProjectExtensions.cs @@ -27,10 +27,11 @@ public static class ProjectExtensions private static readonly Dictionary _knownProjectTypes = new Dictionary { - {"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}", "Windows"}, // C# - {"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}", "Windows"}, // VB.NET - {"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}", "Windows"}, // C++ - {"{F2A71F9B-5D33-465A-A702-920D77279786}", "Windows"}, // F# + {"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}", "Windows C#"}, // C# + {"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}", "Windows VB.NET"}, // VB.NET + {"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}", "Windows C++"}, // C++ + {"{F2A71F9B-5D33-465A-A702-920D77279786}", "Windows F#"}, // F# + {"{D954291E-2A0B-460D-934E-DC6B0785DB48}", "Shared Project" }, {"{349C5851-65DF-11DA-9384-00065B846F21}", "Web Application"}, {"{E24C65DC-7377-472B-9ABA-BC803B73C61A}", "Web Site"}, {"{603c0e0b-db56-11dc-be95-000d561079b0}", "ASP.NET MVC1"}, diff --git a/src/BuildVision/Helpers/SolutionProjectsExtensions.cs b/src/BuildVision/Helpers/SolutionProjectsExtensions.cs index f7ddcd5c..61f8c328 100644 --- a/src/BuildVision/Helpers/SolutionProjectsExtensions.cs +++ b/src/BuildVision/Helpers/SolutionProjectsExtensions.cs @@ -106,6 +106,11 @@ public static IList GetProjects(this Solution solution) continue; } + if (project.FileName.EndsWith(".shproj")) // Shared Projects shouldn´t be displayed in BuildVision + { + continue; + } + if (project.Kind == EnvDTEProjectKinds.ProjectKindSolutionFolder) { list.AddRange(project.GetSubProjects()); @@ -163,7 +168,7 @@ public static void UpdateProperties(Project project, ProjectItem projectItem, st Configuration config; try { - config = project.ConfigurationManager.ActiveConfiguration; + config = project.ConfigurationManager?.ActiveConfiguration; } catch (Exception ex) { @@ -178,6 +183,14 @@ public static void UpdateProperties(Project project, ProjectItem projectItem, st } else { + if (project.ConfigurationManager == null) + { + LogManager.ForContext().Warning("ConfigurationManager for project {UniqueName} was null.", project?.UniqueName); + } + else if (project.ConfigurationManager.ActiveConfiguration == null) + { + LogManager.ForContext().Warning("ActiveConfiguration for project {UniqueName} was null.", project?.UniqueName); + } projectItem.Configuration = @"N\A"; projectItem.Platform = @"N\A"; } @@ -188,14 +201,11 @@ public static void UpdateProperties(Project project, ProjectItem projectItem, st try { projectItem.Framework = project.GetFrameworkString(); - var flavourTypes = project.GetFlavourTypes().ToList(); projectItem.FlavourType = string.Join("; ", flavourTypes); projectItem.MainFlavourType = flavourTypes.FirstOrDefault(); - projectItem.OutputType = project.GetOutputType(); projectItem.ExtenderNames = project.GetExtenderNames(); - projectItem.RootNamespace = project.GetRootNamespace(); } catch (Exception ex) diff --git a/src/BuildVision/Services/BuildInformationProvider.cs b/src/BuildVision/Services/BuildInformationProvider.cs index c52d9ccb..f1fe75b6 100644 --- a/src/BuildVision/Services/BuildInformationProvider.cs +++ b/src/BuildVision/Services/BuildInformationProvider.cs @@ -2,10 +2,8 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel.Composition; -using System.Diagnostics; using System.Linq; using System.Threading; -using System.Threading.Tasks; using BuildVision.Common; using BuildVision.Common.Diagnostics; using BuildVision.Common.Logging; @@ -88,10 +86,14 @@ private void BuildOutputLogger_OnErrorRaised(BuildProjectContextEntry projectEnt { try { - if (!TryGetProjectItem(projectEntry, out var projectItem)) + var projectItem = projectEntry.ProjectItem; + if (projectItem == null) { - projectEntry.IsInvalid = true; - return; + if (!TryGetProjectItem(projectEntry, out projectItem)) + { + projectEntry.IsInvalid = true; + return; + } } var errorItem = new ErrorItem(errorLevel); @@ -135,29 +137,36 @@ private void BuildOutputLogger_OnErrorRaised(BuildProjectContextEntry projectEnt private bool TryGetProjectItem(BuildProjectContextEntry projectEntry, out IProjectItem projectItem) { - projectItem = projectEntry.ProjectItem; + projectItem = projectEntry?.ProjectItem; if (projectItem != null) { return true; } - string projectFile = projectEntry.FileName; + string projectFile = projectEntry.ProjectFile; if (ProjectExtensions.IsProjectHidden(projectFile)) { return false; } var projectProperties = projectEntry.Properties; - var project = Projects.FirstOrDefault(x => x.FullName == projectFile); - if (projectProperties.ContainsKey("Configuration") && projectProperties.ContainsKey("Platform")) { string projectConfiguration = projectProperties["Configuration"]; string projectPlatform = projectProperties["Platform"]; - projectItem = Projects.First(item => $"{item.FullName}-{item.Configuration}|{item.Platform.Replace(" ", "")}" == $"{projectFile}-{projectConfiguration}|{projectPlatform}"); + _logger.Information("Lookup ProjectItem for ProjectFile='{ProjectFile}', Configuration='{ProjectConfiguration}, Platform='{ProjectPlatform}'.", projectFile, projectConfiguration, projectPlatform); + projectItem = Projects.FirstOrDefault(item => $"{item.FullName}-{item.Configuration}|{item.Platform.Replace(" ", "")}" == $"{projectFile}-{projectConfiguration}|{projectPlatform}"); if (projectItem == null) { - _logger.Warning("Project Item not found by: UniqueName='{UniqueName}', Configuration='{ProjectConfiguration}, Platform='{ProjectPlatform}'.", project.UniqueName, projectConfiguration, projectPlatform); + var project = Projects.FirstOrDefault(x => x.FullName == projectFile); + if (project == null) + { + _logger.Error("Project Item and Project were not found by: ProjectFile='{ProjectFile}', Configuration='{ProjectConfiguration}, Platform='{ProjectPlatform}'.", projectFile, projectConfiguration, projectPlatform); + } + else + { + _logger.Warning("Project Item not found by: UniqueName='{UniqueName}', Configuration='{ProjectConfiguration}, Platform='{ProjectPlatform}'.", project.UniqueName, projectConfiguration, projectPlatform); + } return false; } } @@ -188,12 +197,13 @@ public void BuildStarted(BuildAction buildAction, BuildScope buildScope) _windowStateService.ApplyToolWindowStateAction(_packageSettingsProvider.Settings.WindowSettings.WindowActionOnBuildBegin); _timer = new Timer(state => BuildUpdate(), null, BuildInProcessQuantumSleep, BuildInProcessQuantumSleep); - + string message = _buildMessagesFactory.GetBuildBeginMajorMessage(BuildInformationModel); _statusBarNotificationService.ShowTextWithFreeze(message); _origTextCurrentState = message; BuildInformationModel.StateMessage = _origTextCurrentState; - _taskBarInfoService.UpdateTaskBarInfo(BuildInformationModel.CurrentBuildState, BuildInformationModel.BuildScope, Projects.Count, GetFinishedProjectsCount()); + UpdateTaskBar(); + BuildStateChanged(); DiagnosticsClient.TrackEvent("BuildStarted", new Dictionary { @@ -210,38 +220,28 @@ public void ProjectBuildStarted(IProjectItem projectItem, BuildAction buildActio return; } - try + var projInCollection = Projects.FirstOrDefault(item => ProjectIdentifierGenerator.GetIdentifierForProjectItem(item) == ProjectIdentifierGenerator.GetIdentifierForProjectItem(projectItem)); + if (projInCollection == null) { - var projInCollection = Projects.FirstOrDefault(item => ProjectIdentifierGenerator.GetIdentifierForProjectItem(item) == ProjectIdentifierGenerator.GetIdentifierForProjectItem(projectItem)); - if (projInCollection == null) - { - Projects.Add(projectItem); - projInCollection = projectItem; - } - projInCollection.State = BuildInformationModel.BuildAction.GetProjectState(); - projInCollection.BuildFinishTime = null; - projInCollection.BuildStartTime = DateTime.Now; + Projects.Add(projectItem); + projInCollection = projectItem; + } + projInCollection.State = BuildInformationModel.BuildAction.GetProjectState(); + projInCollection.BuildFinishTime = null; + projInCollection.BuildStartTime = DateTime.Now; - _taskBarInfoService.UpdateTaskBarInfo(BuildInformationModel.CurrentBuildState, BuildInformationModel.BuildScope, Projects.Count, GetFinishedProjectsCount()); - _currentQueuePosOfBuildingProject++; + UpdateTaskBar(); - if (BuildInformationModel.BuildScope == BuildScope.Solution && - (BuildInformationModel.BuildAction == BuildAction.Build || - BuildInformationModel.BuildAction == BuildAction.RebuildAll)) - { - projInCollection.BuildOrder = _currentQueuePosOfBuildingProject; - } - BuildInformationModel.CurrentProject = projInCollection; - } - catch (Exception ex) + _currentQueuePosOfBuildingProject++; + + if (BuildInformationModel.BuildScope == BuildScope.Solution && + (BuildInformationModel.BuildAction == BuildAction.Build || + BuildInformationModel.BuildAction == BuildAction.RebuildAll)) { - _logger.Error(ex, "Failed during Project Build start."); + projInCollection.BuildOrder = _currentQueuePosOfBuildingProject; } - } - - private int GetFinishedProjectsCount() - { - return BuildInformationModel.SucceededProjectsCount + BuildInformationModel.UpToDateProjectsCount + BuildInformationModel.WarnedProjectsCount + BuildInformationModel.FailedProjectsCount; + BuildInformationModel.CurrentProject = projInCollection; + BuildStateChanged(); } public void ProjectBuildFinished(BuildAction buildAction, string projectIdentifier, bool success, bool canceled) @@ -274,7 +274,8 @@ public void ProjectBuildFinished(BuildAction buildAction, string projectIdentifi BuildInformationModel.CurrentProject = Projects.Last(); } - _taskBarInfoService.UpdateTaskBarInfo(BuildInformationModel.CurrentBuildState, BuildInformationModel.BuildScope, Projects.Count, GetFinishedProjectsCount()); + UpdateTaskBar(); + BuildStateChanged(); } private ProjectState GetProjectState(bool success, bool canceled, IProjectItem currentProject) @@ -313,7 +314,7 @@ private ProjectState GetProjectState(bool success, bool canceled, IProjectItem c return projectState; } - public void BuildUpdate() + private void BuildUpdate() { if(BuildInformationModel.CurrentBuildState != BuildState.InProgress) { @@ -322,7 +323,7 @@ public void BuildUpdate() var message = _origTextCurrentState + _buildMessagesFactory.GetBuildBeginExtraMessage(BuildInformationModel); BuildInformationModel.StateMessage = message; _statusBarNotificationService.ShowTextWithFreeze(message); - foreach (var project in Projects.Where(x => x.BuildStartTime.HasValue && !x.BuildFinishTime.HasValue)) + foreach (var project in Projects.Where(x => x.State != ProjectState.Cleaning && x.State != ProjectState.Building)) { project.RaiseBuildElapsedTimeChanged(); } @@ -372,8 +373,8 @@ public void BuildFinished(bool success, bool canceled) var message = _buildMessagesFactory.GetBuildDoneMessage(BuildInformationModel); _statusBarNotificationService.ShowText(message); BuildInformationModel.StateMessage = message; - _taskBarInfoService.UpdateTaskBarInfo(BuildInformationModel.CurrentBuildState, BuildInformationModel.BuildScope, Projects.Count, GetFinishedProjectsCount()); - + UpdateTaskBar(); + BuildStateChanged(); if (BuildInformationModel.FailedProjectsCount > 0 || canceled) { _windowStateService.ApplyToolWindowStateAction(_packageSettingsProvider.Settings.WindowSettings.WindowActionOnBuildError); @@ -407,5 +408,13 @@ public void BuildFinished(bool success, bool canceled) } } } + + private void UpdateTaskBar() + { + _taskBarInfoService.UpdateTaskBarInfo(BuildInformationModel.CurrentBuildState, BuildInformationModel.BuildScope, Projects.Count, BuildInformationModel.GetFinishedProjectsCount()); + } + + + public event Action BuildStateChanged; } } diff --git a/src/BuildVision/Services/BuildOutputLogger.cs b/src/BuildVision/Services/BuildOutputLogger.cs index 5cd7db13..edd80bd9 100644 --- a/src/BuildVision/Services/BuildOutputLogger.cs +++ b/src/BuildVision/Services/BuildOutputLogger.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; using System.Reflection; using BuildVision.Common.Logging; @@ -20,7 +19,7 @@ public class BuildOutputLogger : Logger, IBuildOutputLogger private Serilog.ILogger _logger = LogManager.ForContext(); public RegisterLoggerResult LoggerState { get; set; } - private Dictionary _projects = new Dictionary(); + private Dictionary _projectsLookup = new Dictionary(); public BuildOutputLogger(Guid loggerId, LoggerVerbosity loggerVerbosity) { @@ -30,28 +29,29 @@ public BuildOutputLogger(Guid loggerId, LoggerVerbosity loggerVerbosity) public override void Initialize(IEventSource eventSource) { - _projects = new Dictionary(); + _projectsLookup = new Dictionary(); eventSource.ProjectStarted += OnProjectStarted; - eventSource.MessageRaised += (s, e) => EventSource_ErrorRaised(e, ErrorLevel.Message); - eventSource.WarningRaised += (s, e) => EventSource_ErrorRaised(e, ErrorLevel.Warning); - eventSource.ErrorRaised += (s, e) => EventSource_ErrorRaised(e, ErrorLevel.Error); + eventSource.MessageRaised += (sender, e) => EventSource_Event(e.ProjectFile, e, ErrorLevel.Message); + eventSource.WarningRaised += (sender, e) => EventSource_Event(e.ProjectFile, e, ErrorLevel.Warning); + eventSource.ErrorRaised += (sender, e) => EventSource_Event(e.ProjectFile, e, ErrorLevel.Error); } private void OnProjectStarted(object sender, ProjectStartedEventArgs e) { - var identifier = $"{e.BuildEventContext.ProjectInstanceId}{e.BuildEventContext.ProjectContextId}"; - _projects.Add(identifier, new BuildProjectContextEntry( - e.BuildEventContext.ProjectInstanceId, - e.BuildEventContext.ProjectContextId, - e.ProjectFile, - e.GlobalProperties)); + var entry = new BuildProjectContextEntry(e.ProjectFile, e.GlobalProperties); + if (!_projectsLookup.ContainsKey(entry.ProjectFile)) + { + _projectsLookup.Add(entry.ProjectFile, entry); + } + + _logger.Information("Currently there are {Count} projects listed.", _projectsLookup.Count); } public void Attach() { try { - _projects.Clear(); + _projectsLookup.Clear(); const BindingFlags InterfacePropertyFlags = BindingFlags.GetProperty | BindingFlags.Public @@ -76,6 +76,9 @@ public void Attach() var loggersProperty = loggingServiceObj.GetType().GetProperty("Loggers", InterfacePropertyFlags); var loggers = (ICollection)loggersProperty.GetValue(loggingServiceObj, null); + + + var logger = loggers.FirstOrDefault(x => x is BuildOutputLogger && ((BuildOutputLogger)x)._loggerId.Equals(_loggerId)); if (logger != null) { @@ -83,6 +86,7 @@ public void Attach() return; } + var registerLoggerMethod = loggingServiceObj.GetType().GetMethod("RegisterLogger"); var registerResult = (bool)registerLoggerMethod.Invoke(loggingServiceObj, new object[] { this }); LoggerState = registerResult ? RegisterLoggerResult.RegisterSuccess : RegisterLoggerResult.RegisterFailed; @@ -94,12 +98,9 @@ public void Attach() } } - public bool IsProjectUpToDate(IProjectItem projectItem) - { - return !_projects.Any(x => x.Value.FileName == projectItem.FullName); - } + public bool IsProjectUpToDate(IProjectItem projectItem) => !_projectsLookup.ContainsKey(projectItem.FullName); - private void EventSource_ErrorRaised(BuildEventArgs e, ErrorLevel errorLevel) + private void EventSource_Event(string projectFile, BuildEventArgs e, ErrorLevel errorLevel) { try { @@ -107,13 +108,14 @@ private void EventSource_ErrorRaised(BuildEventArgs e, ErrorLevel errorLevel) { return; } + if(projectFile == null) + { + return; + } - int projectInstanceId = e.BuildEventContext.ProjectInstanceId; - int projectContextId = e.BuildEventContext.ProjectContextId; - var identifier = $"{projectInstanceId}{projectContextId}"; - if (!_projects.TryGetValue(identifier, out var projectEntry)) + if (!_projectsLookup.TryGetValue(projectFile, out var projectEntry)) { - _logger.Warning("Project entry not found by ProjectInstanceId='{ProjectInstanceId}' and ProjectContextId='{ProjectContextId}'.", projectInstanceId, projectContextId); + _logger.Warning("Project entry not found by ProjectFile='{ProjectFile}'.", projectFile); return; } if (projectEntry.IsInvalid) From 3df9af8cad052b36ecb1d12401c4281b6cc72f19 Mon Sep 17 00:00:00 2001 From: Stefan Kert Date: Sat, 5 Oct 2019 14:06:10 +0200 Subject: [PATCH 097/100] removed logging --- src/BuildVision/Services/BuildInformationProvider.cs | 1 - src/BuildVision/Services/BuildOutputLogger.cs | 2 -- 2 files changed, 3 deletions(-) diff --git a/src/BuildVision/Services/BuildInformationProvider.cs b/src/BuildVision/Services/BuildInformationProvider.cs index f1fe75b6..e57d20f6 100644 --- a/src/BuildVision/Services/BuildInformationProvider.cs +++ b/src/BuildVision/Services/BuildInformationProvider.cs @@ -154,7 +154,6 @@ private bool TryGetProjectItem(BuildProjectContextEntry projectEntry, out IProje { string projectConfiguration = projectProperties["Configuration"]; string projectPlatform = projectProperties["Platform"]; - _logger.Information("Lookup ProjectItem for ProjectFile='{ProjectFile}', Configuration='{ProjectConfiguration}, Platform='{ProjectPlatform}'.", projectFile, projectConfiguration, projectPlatform); projectItem = Projects.FirstOrDefault(item => $"{item.FullName}-{item.Configuration}|{item.Platform.Replace(" ", "")}" == $"{projectFile}-{projectConfiguration}|{projectPlatform}"); if (projectItem == null) { diff --git a/src/BuildVision/Services/BuildOutputLogger.cs b/src/BuildVision/Services/BuildOutputLogger.cs index edd80bd9..e48a96dc 100644 --- a/src/BuildVision/Services/BuildOutputLogger.cs +++ b/src/BuildVision/Services/BuildOutputLogger.cs @@ -43,8 +43,6 @@ private void OnProjectStarted(object sender, ProjectStartedEventArgs e) { _projectsLookup.Add(entry.ProjectFile, entry); } - - _logger.Information("Currently there are {Count} projects listed.", _projectsLookup.Count); } public void Attach() From 9b03434f69600d88dd01a9d7ce91d247d78bd92d Mon Sep 17 00:00:00 2001 From: Stefan Kert Date: Sat, 5 Oct 2019 14:50:51 +0200 Subject: [PATCH 098/100] Do not use reflection for sorting --- .../PropertyColumnSorter.cs | 49 --------- .../Helpers/ProjectItemColumnSorter.cs | 37 ++++++- .../ViewModels/BuildVisionPaneViewModel.cs | 103 ++++++++++++------ .../Services/BuildInformationProvider.cs | 1 - 4 files changed, 105 insertions(+), 85 deletions(-) delete mode 100644 src/BuildVision.Common/PropertyColumnSorter.cs diff --git a/src/BuildVision.Common/PropertyColumnSorter.cs b/src/BuildVision.Common/PropertyColumnSorter.cs deleted file mode 100644 index 2ba96d16..00000000 --- a/src/BuildVision.Common/PropertyColumnSorter.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System; -using System.Collections; -using System.ComponentModel; -using System.Reflection; -using BuildVision.Contracts.Exceptions; - -namespace BuildVision.Common -{ - public class PropertyColumnSorter : IComparer where T : class - { - private readonly int _direction; - private readonly PropertyInfo _propertyInfo; - - public PropertyColumnSorter(ListSortDirection direction, string propertyName) - { - _direction = (direction == ListSortDirection.Ascending) ? 1 : -1; - _propertyInfo = typeof(T).GetProperty(propertyName); - - if (_propertyInfo == null) - { - throw new PropertyNotFoundException(propertyName, typeof(T)); - } - } - - int IComparer.Compare(object x, object y) - { - return Compare((T)x, (T)y); - } - - protected int Compare(T x, T y) - { - var x1 = _propertyInfo.GetValue(x, null) as IComparable; - var y1 = _propertyInfo.GetValue(y, null) as IComparable; - - if (x1 != null && y1 != null) - { - return x1.CompareTo(y1) * _direction; - } - - if (x1 == null && y1 == null) - { - return 0; - } - - // Null values always in the bottom. - return (x1 == null) ? 1 : -1; - } - } -} diff --git a/src/BuildVision.UI/Helpers/ProjectItemColumnSorter.cs b/src/BuildVision.UI/Helpers/ProjectItemColumnSorter.cs index ad089909..6849d9b9 100644 --- a/src/BuildVision.UI/Helpers/ProjectItemColumnSorter.cs +++ b/src/BuildVision.UI/Helpers/ProjectItemColumnSorter.cs @@ -1,14 +1,43 @@ -using System.ComponentModel; +using System; +using System.Collections; +using System.ComponentModel; +using System.Reflection; using BuildVision.Common; +using BuildVision.Contracts.Exceptions; using BuildVision.UI.Models; namespace BuildVision.UI.Helpers { - public class ProjectItemColumnSorter : PropertyColumnSorter + public class ProjectItemColumnSorter : IComparer { - public ProjectItemColumnSorter(ListSortDirection direction, string propertyName) - : base(direction, propertyName) + private readonly int _direction; + private readonly Func _getProperrty; + + public ProjectItemColumnSorter(ListSortDirection direction, Func getProperrty) + { + _direction = (direction == ListSortDirection.Ascending) ? 1 : -1; + _getProperrty = getProperrty; + } + + int IComparer.Compare(object x, object y) => Compare((ProjectItem)x, (ProjectItem)y); + + protected int Compare(ProjectItem x, ProjectItem y) { + var x1 = _getProperrty(x) as IComparable; + var y1 = _getProperrty(y) as IComparable; + + if (x1 != null && y1 != null) + { + return x1.CompareTo(y1) * _direction; + } + + if (x1 == null && y1 == null) + { + return 0; + } + + // Null values always in the bottom. + return (x1 == null) ? 1 : -1; } } } diff --git a/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs b/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs index fa237bfb..c882ac89 100644 --- a/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs +++ b/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs @@ -133,7 +133,6 @@ public SortDescription GridSortDescription { ControlSettings.GridSettings.Sort = value; OnPropertyChanged(nameof(GridSortDescription)); - OnPropertyChanged(nameof(GroupedProjectsList)); } } } @@ -154,13 +153,12 @@ public ListCollectionView GroupedProjectsList { get { - var groupedList = new ListCollectionView(Projects); + var groupedList = CollectionViewSource.GetDefaultView(Projects) as ListCollectionView; if (!string.IsNullOrWhiteSpace(GridGroupPropertyName)) { - Debug.Assert(groupedList.GroupDescriptions != null); groupedList.GroupDescriptions.Add(new PropertyGroupDescription(GridGroupPropertyName)); } - groupedList.CustomSort = GetProjectItemSorter(GridSortDescription); + groupedList.CustomSort = SortOrderFactory.GetProjectItemSorter(GridSortDescription); groupedList.IsLiveGrouping = true; groupedList.IsLiveSorting = true; return groupedList; @@ -215,13 +213,13 @@ public BuildVisionPaneViewModel( ControlSettings = settingsProvider.Settings; Projects = _buildInformationProvider.Projects; - _buildInformationProvider.BuildStateChanged += () => OnPropertyChanged(nameof(GroupedProjectsList)); + _buildInformationProvider.BuildStateChanged += () => { }; _settingsProvider = settingsProvider; _settingsProvider.SettingsChanged += () => { OnControlSettingsChanged(); - SyncColumnSettings(); + SyncColumnSettings(); }; ControlSettings.PropertyChanged += (sender, e) => @@ -282,32 +280,8 @@ private void ReorderGrid(object obj) e.Handled = true; e.Column.SortDirection = newSortDirection; - GridSortDescription = new SortDescription(newSortDirection.ToMedia(), e.Column.GetBindedProperty()); - } - - private ProjectItemColumnSorter GetProjectItemSorter(SortDescription sortDescription) - { - var sortOrder = sortDescription.Order; - string sortPropertyName = sortDescription.Property; - - if (sortOrder != SortOrder.None && !string.IsNullOrEmpty(sortPropertyName)) - { - ListSortDirection? sortDirection = sortOrder.ToSystem(); - Debug.Assert(sortDirection != null); - - try - { - return new ProjectItemColumnSorter(sortDirection.Value, sortPropertyName); - } - catch (PropertyNotFoundException ex) - { - _logger.Error(ex, "Trying to sort Project Items by nonexistent property."); - return null; - } - } - - return null; + GroupedProjectsList.CustomSort = SortOrderFactory.GetProjectItemSorter(GridSortDescription); } public void GenerateColumns() @@ -394,4 +368,71 @@ private void CopyErrorMessageToClipboard(ProjectItem projectItem) public event Action ShowOptionPage; } + + public class SortOrderFactory + { + public static ProjectItemColumnSorter GetProjectItemSorter(SortDescription sortDescription) + { + var sortOrder = sortDescription.Order; + string sortPropertyName = sortDescription.Property; + if (sortOrder != SortOrder.None && !string.IsNullOrEmpty(sortPropertyName)) + { + ListSortDirection? sortDirection = sortOrder.ToSystem(); + Debug.Assert(sortDirection != null); + + switch (sortPropertyName) + { + case nameof(ProjectItem.BuildElapsedTime): + return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.BuildElapsedTime); + case nameof(ProjectItem.BuildFinishTime): + return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.BuildFinishTime); + case nameof(ProjectItem.BuildOrder): + return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.BuildOrder); + case nameof(ProjectItem.CommonType): + return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.CommonType); + case nameof(ProjectItem.Configuration): + return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.Configuration); + case nameof(ProjectItem.ErrorsCount): + return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.ErrorsCount); + case nameof(ProjectItem.ExtenderNames): + return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.ExtenderNames); + case nameof(ProjectItem.FlavourType): + return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.FlavourType); + case nameof(ProjectItem.Framework): + return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.Framework); + case nameof(ProjectItem.FullName): + return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.FullName); + case nameof(ProjectItem.FullPath): + return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.FullPath); + case nameof(ProjectItem.IsBatchBuildProject): + return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.IsBatchBuildProject); + case nameof(ProjectItem.Language): + return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.Language); + case nameof(ProjectItem.MainFlavourType): + return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.MainFlavourType); + case nameof(ProjectItem.MessagesCount): + return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.MessagesCount); + case nameof(ProjectItem.Name): + return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.Name); + case nameof(ProjectItem.OutputType): + return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.OutputType); + case nameof(ProjectItem.Platform): + return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.Platform); + case nameof(ProjectItem.RootNamespace): + return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.RootNamespace); + case nameof(ProjectItem.SolutionFolder): + return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.SolutionFolder); + case nameof(ProjectItem.State): + return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.State); + case nameof(ProjectItem.Success): + return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.Success); + case nameof(ProjectItem.UniqueName): + return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.UniqueName); + case nameof(ProjectItem.WarningsCount): + return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.WarningsCount); + } + } + return null; + } + } } diff --git a/src/BuildVision/Services/BuildInformationProvider.cs b/src/BuildVision/Services/BuildInformationProvider.cs index e57d20f6..68391f4a 100644 --- a/src/BuildVision/Services/BuildInformationProvider.cs +++ b/src/BuildVision/Services/BuildInformationProvider.cs @@ -413,7 +413,6 @@ private void UpdateTaskBar() _taskBarInfoService.UpdateTaskBarInfo(BuildInformationModel.CurrentBuildState, BuildInformationModel.BuildScope, Projects.Count, BuildInformationModel.GetFinishedProjectsCount()); } - public event Action BuildStateChanged; } } From f316dcf1b4b5d205815e24c1a2e505c588d2a9bd Mon Sep 17 00:00:00 2001 From: Stefan Kert Date: Sun, 6 Oct 2019 19:07:17 +0200 Subject: [PATCH 099/100] Removed some things from projectitem Sorting by methods not reflection --- src/BuildVision.UI/BuildVision.UI.csproj | 1 + src/BuildVision.UI/Models/ProjectItem.cs | 207 ++++-------------- .../ViewModels/BuildVisionPaneViewModel.cs | 127 ++--------- .../ViewModels/SortOrderFactory.cs | 75 +++++++ 4 files changed, 136 insertions(+), 274 deletions(-) create mode 100644 src/BuildVision.UI/ViewModels/SortOrderFactory.cs diff --git a/src/BuildVision.UI/BuildVision.UI.csproj b/src/BuildVision.UI/BuildVision.UI.csproj index 98779a1d..03c964d2 100644 --- a/src/BuildVision.UI/BuildVision.UI.csproj +++ b/src/BuildVision.UI/BuildVision.UI.csproj @@ -189,6 +189,7 @@ + diff --git a/src/BuildVision.UI/Models/ProjectItem.cs b/src/BuildVision.UI/Models/ProjectItem.cs index 7062551a..5516e796 100644 --- a/src/BuildVision.UI/Models/ProjectItem.cs +++ b/src/BuildVision.UI/Models/ProjectItem.cs @@ -14,84 +14,59 @@ public class ProjectItem : BindableBase, IProjectItem private const string ResourcesUri = @"Resources/ProjectItem.Resources.xaml"; public bool IsBatchBuildProject { get; set; } - - private string _uniqueName; + public bool Success { get; set; } [GridColumn("ProjectItemHeader_UniqueName", ColumnsOrder.UniqueName, false, ExampleValue = @"ConsoleApplication1\ConsoleApplication1.csproj")] - public string UniqueName - { - get => _uniqueName; - set => SetProperty(ref _uniqueName, value); - } - - private string _name; - + public string UniqueName { get; set; } [GridColumn("ProjectItemHeader_Name", ColumnsOrder.Name, true, ExampleValue = @"ConsoleApplication1")] - public string Name - { - get => _name; - set => SetProperty(ref _name, value); - } - - private string _fullName; - + public string Name { get; set; } [GridColumn("ProjectItemHeader_FullName", ColumnsOrder.FullName, false, ExampleValue = @"D:\Projects\ConsoleApplication1\ConsoleApplication1.csproj")] - public string FullName - { - get => _fullName; - set => SetProperty(ref _fullName, value); - } - - private string _fullPath; - + public string FullName { get; set; } [GridColumn("ProjectItemHeader_FullPath", ColumnsOrder.FullPath, false, ExampleValue = @"D:\Projects\ConsoleApplication1")] - public string FullPath - { - get => _fullPath; - set => SetProperty(ref _fullPath, value); - } - - private string _language; - + public string FullPath { get; set; } [GridColumn("ProjectItemHeader_Language", ColumnsOrder.Language, true, ExampleValue = @"C#")] - public string Language - { - get => _language; - set => SetProperty(ref _language, value); - } - - private string _commonType; - - /// - /// See registered types in HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\[Version "11.0"]\Projects. - /// + public string Language { get; set; } [GridColumn("ProjectItemHeader_CommonType", ColumnsOrder.CommonType, false, ExampleValue = @"Windows")] - public string CommonType - { - get => _commonType; - set => SetProperty(ref _commonType, value); - } - - private string _configuration; - + public string CommonType { get; set; } [GridColumn("ProjectItemHeader_Configuration", ColumnsOrder.Configuration, true, ExampleValue = @"Debug")] - public string Configuration - { - get => _configuration; - set => SetProperty(ref _configuration, value); - } - - private string _platform; - + public string Configuration { get; set; } [GridColumn("ProjectItemHeader_Platform", ColumnsOrder.Platform, true, ExampleValue = @"x86")] - public string Platform + public string Platform { get; set; } + [GridColumn("ProjectItemHeader_Framework", ColumnsOrder.Framework, false, ExampleValue = @"3.5")] + public string Framework { get; set; } + [GridColumn("ProjectItemHeader_FlavourType", ColumnsOrder.FlavourType, true, ExampleValue = @"Windows; VSTA")] + public string FlavourType { get; set; } + [GridColumn("ProjectItemHeader_MainFlavourType", ColumnsOrder.MainFlavourType, false, ExampleValue = @"VSTA")] + public string MainFlavourType { get; set; } + [GridColumn("ProjectItemHeader_OutputType", ColumnsOrder.OutputType, false, ExampleValue = @"Library")] + public string OutputType { get; set; } + [GridColumn("ProjectItemHeader_ExtenderNames", ColumnsOrder.ExtenderNames, false, ExampleValue = @"VST")] + public string ExtenderNames { get; set; } + [GridColumn("ProjectItemHeader_RootNamespace", ColumnsOrder.RootNamespace, false, ExampleValue = @"MyApplication")] + public string RootNamespace { get; set; } + [GridColumn("ProjectItemHeader_SolutionFolder", ColumnsOrder.SolutionFolder, false, ExampleValue = @"SolutionFolder1\SolutionFolder2")] + public string SolutionFolder { get; set; } + + [GridColumn("ProjectItemHeader_StateBitmap", ColumnsOrder.StateBitmap, true, ImageKey = GridColumnAttribute.EmptyHeaderImageKey)] + public ControlTemplate StateBitmap => _state.GetAssociatedContent(); + [GridColumn("ProjectItemHeader_BuildElapsedTime", ColumnsOrder.BuildElapsedTime, true, ValueStringFormat = @"mm\:ss", TimeSpanExampleValue = @"00:09:21.60")] + public TimeSpan? BuildElapsedTime { - get => _platform; - set => SetProperty(ref _platform, value); + get + { + if (_buildStartTime == null) + { + return null; + } + if (_buildFinishTime == null) + { + return DateTime.Now.Subtract(_buildStartTime.Value); + } + return _buildFinishTime.Value.Truncate(TimeSpan.FromSeconds(1)).Subtract(_buildStartTime.Value.Truncate(TimeSpan.FromSeconds(1))); + } } private ProjectState _state; - [GridColumn("ProjectItemHeader_State", ColumnsOrder.State, true, ExampleValue = @"BuildDone")] public ProjectState State { @@ -102,12 +77,7 @@ public ProjectState State OnPropertyChanged(nameof(StateBitmap)); } } - - [GridColumn("ProjectItemHeader_StateBitmap", ColumnsOrder.StateBitmap, true, ImageKey = GridColumnAttribute.EmptyHeaderImageKey)] - public ControlTemplate StateBitmap => _state.GetAssociatedContent(); - private DateTime? _buildStartTime; - [GridColumn("ProjectItemHeader_BuildStartTime", ColumnsOrder.BuildStartTime, true, ValueStringFormat = @"HH:mm:ss", DateTimeExampleValue = @"2012-07-27T20:06:12.3691406+06:00")] public DateTime? BuildStartTime { @@ -119,9 +89,7 @@ public DateTime? BuildStartTime OnPropertyChanged(nameof(BuildElapsedTime)); } } - private DateTime? _buildFinishTime; - [GridColumn("ProjectItemHeader_BuildFinishTime", ColumnsOrder.BuildFinishTime, true, ValueStringFormat = @"HH:mm:ss", DateTimeExampleValue = @"2012-07-27T20:06:12.3691406+06:00")] public DateTime? BuildFinishTime { @@ -134,26 +102,6 @@ public DateTime? BuildFinishTime } } - [GridColumn("ProjectItemHeader_BuildElapsedTime", ColumnsOrder.BuildElapsedTime, true, ValueStringFormat = @"mm\:ss", TimeSpanExampleValue = @"00:09:21.60")] - public TimeSpan? BuildElapsedTime - { - get - { - if (_buildStartTime == null) - { - return null; - } - - if (_buildFinishTime == null) - { - return DateTime.Now.Subtract(_buildStartTime.Value); - } - - return _buildFinishTime.Value.Truncate(TimeSpan.FromSeconds(1)) - .Subtract(_buildStartTime.Value.Truncate(TimeSpan.FromSeconds(1))); - } - } - public ObservableCollection Errors { get; set; } = new ObservableCollection(); public ObservableCollection Warnings { get; set; } = new ObservableCollection(); @@ -184,53 +132,7 @@ public int MessagesCount set => SetProperty(ref _messagesCount, value); } - private string _framework; - - [GridColumn("ProjectItemHeader_Framework", ColumnsOrder.Framework, false, ExampleValue = @"3.5")] - public string Framework - { - get => _framework; - set => SetProperty(ref _framework, value); - } - - private string _flavourType; - - [GridColumn("ProjectItemHeader_FlavourType", ColumnsOrder.FlavourType, true, ExampleValue = @"Windows; VSTA")] - public string FlavourType - { - get => _flavourType; - set => SetProperty(ref _flavourType, value); - } - - private string _mainFlavourType; - - [GridColumn("ProjectItemHeader_MainFlavourType", ColumnsOrder.MainFlavourType, false, ExampleValue = @"VSTA")] - public string MainFlavourType - { - get => _mainFlavourType; - set => SetProperty(ref _mainFlavourType, value); - } - - private string _outputType; - - [GridColumn("ProjectItemHeader_OutputType", ColumnsOrder.OutputType, false, ExampleValue = @"Library")] - public string OutputType - { - get => _outputType; - set => SetProperty(ref _outputType, value); - } - - private string _extenderNames; - - [GridColumn("ProjectItemHeader_ExtenderNames", ColumnsOrder.ExtenderNames, false, ExampleValue = @"VST")] - public string ExtenderNames - { - get => _extenderNames; - set => SetProperty(ref _extenderNames, value); - } - private int? _buildOrder; - [GridColumn("ProjectItemHeader_BuildOrder", ColumnsOrder.BuildOrder, false, ImageDictionaryUri = ResourcesUri, ImageKey = "BuildOrder", Width = 23, ExampleValue = 4)] public int? BuildOrder { @@ -238,34 +140,9 @@ public int? BuildOrder set => SetProperty(ref _buildOrder, value); } - private string _rootNamespace; + public ProjectItem() => State = ProjectState.Pending; - [GridColumn("ProjectItemHeader_RootNamespace", ColumnsOrder.RootNamespace, false, ExampleValue = @"MyApplication")] - public string RootNamespace - { - get => _rootNamespace; - set => SetProperty(ref _rootNamespace, value); - } - - private string _solutionFolder; - - [GridColumn("ProjectItemHeader_SolutionFolder", ColumnsOrder.SolutionFolder, false, ExampleValue = @"SolutionFolder1\SolutionFolder2")] - public string SolutionFolder - { - get => _solutionFolder; - set => SetProperty(ref _solutionFolder, value); - } - public bool Success { get; set; } - - public ProjectItem() - { - State = ProjectState.Pending; - } - - public void RaiseBuildElapsedTimeChanged() - { - OnPropertyChanged(nameof(BuildElapsedTime)); - } + public void RaiseBuildElapsedTimeChanged() => OnPropertyChanged(nameof(BuildElapsedTime)); public void AddErrorItem(ErrorItem errorItem) { diff --git a/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs b/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs index c882ac89..cc43224b 100644 --- a/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs +++ b/src/BuildVision.UI/ViewModels/BuildVisionPaneViewModel.cs @@ -79,8 +79,9 @@ public string GridGroupPropertyName if (ControlSettings.GridSettings.GroupName != value) { ControlSettings.GridSettings.GroupName = value; + GroupedProjectsList.GroupDescriptions.Clear(); + GroupedProjectsList.GroupDescriptions.Add(new PropertyGroupDescription(value)); OnPropertyChanged(nameof(GridGroupPropertyName)); - OnPropertyChanged(nameof(GroupedProjectsList)); OnPropertyChanged(nameof(GridColumnsGroupMenuItems)); OnPropertyChanged(nameof(GridGroupHeaderName)); } @@ -116,7 +117,7 @@ private CompositeCollection CreateContextMenu() { menuItem.IsCheckable = false; menuItem.StaysOpenOnClick = false; - menuItem.IsChecked = (GridGroupPropertyName == (string)menuItem.Tag); + menuItem.IsChecked = GridGroupPropertyName == (string)menuItem.Tag; menuItem.Command = GridGroupPropertyMenuItemClicked; menuItem.CommandParameter = menuItem.Tag; } @@ -149,21 +150,7 @@ public void SetGridColumnsRef(ObservableCollection gridColumnsRe // TODO: Rewrite using CollectionViewSource? // http://stackoverflow.com/questions/11505283/re-sort-wpf-datagrid-after-bounded-data-has-changed - public ListCollectionView GroupedProjectsList - { - get - { - var groupedList = CollectionViewSource.GetDefaultView(Projects) as ListCollectionView; - if (!string.IsNullOrWhiteSpace(GridGroupPropertyName)) - { - groupedList.GroupDescriptions.Add(new PropertyGroupDescription(GridGroupPropertyName)); - } - groupedList.CustomSort = SortOrderFactory.GetProjectItemSorter(GridSortDescription); - groupedList.IsLiveGrouping = true; - groupedList.IsLiveSorting = true; - return groupedList; - } - } + public ListCollectionView GroupedProjectsList { get; } public DataGridHeadersVisibility GridHeadersVisibility { @@ -213,6 +200,15 @@ public BuildVisionPaneViewModel( ControlSettings = settingsProvider.Settings; Projects = _buildInformationProvider.Projects; + GroupedProjectsList = CollectionViewSource.GetDefaultView(Projects) as ListCollectionView; + if (!string.IsNullOrWhiteSpace(GridGroupPropertyName)) + { + GroupedProjectsList.GroupDescriptions.Add(new PropertyGroupDescription(GridGroupPropertyName)); + } + GroupedProjectsList.CustomSort = SortOrderFactory.GetProjectItemSorter(GridSortDescription); + GroupedProjectsList.IsLiveGrouping = true; + GroupedProjectsList.IsLiveSorting = true; + _buildInformationProvider.BuildStateChanged += () => { }; _settingsProvider = settingsProvider; @@ -242,18 +238,12 @@ private void OpenContainingFolder() try { string dir = Path.GetDirectoryName(SelectedProjectItem.FullName); - Debug.Assert(dir != null); Process.Start(dir); } catch (Exception ex) { _logger.Error(ex, "Unable to open folder '{FullName}' containing the project '{UniqueName}'.", SelectedProjectItem.FullName, SelectedProjectItem.UniqueName); - - MessageBox.Show( - ex.Message + "\n\nSee log for details.", - Resources.ProductName, - MessageBoxButton.OK, - MessageBoxImage.Error); + MessageBox.Show(ex.Message + "\n\nSee log for details.", Resources.ProductName, MessageBoxButton.OK, MessageBoxImage.Error); } } @@ -284,17 +274,9 @@ private void ReorderGrid(object obj) GroupedProjectsList.CustomSort = SortOrderFactory.GetProjectItemSorter(GridSortDescription); } - public void GenerateColumns() - { - Debug.Assert(_gridColumnsRef != null); - ColumnsManager.GenerateColumns(_gridColumnsRef, ControlSettings.GridSettings); - } + public void GenerateColumns() => ColumnsManager.GenerateColumns(_gridColumnsRef, ControlSettings.GridSettings); - public void SyncColumnSettings() - { - Debug.Assert(_gridColumnsRef != null); - ColumnsManager.SyncColumnSettings(_gridColumnsRef, ControlSettings.GridSettings); - } + public void SyncColumnSettings() => ColumnsManager.SyncColumnSettings(_gridColumnsRef, ControlSettings.GridSettings); public void OnControlSettingsChanged() { @@ -305,10 +287,7 @@ public void OnControlSettingsChanged() _taskBarInfoService.ResetTaskBarInfo(false); } - private bool IsProjectItemEnabledForActions() - { - return (SelectedProjectItem != null && !string.IsNullOrEmpty(SelectedProjectItem.UniqueName) && !SelectedProjectItem.IsBatchBuildProject); - } + private bool IsProjectItemEnabledForActions() => SelectedProjectItem != null && !string.IsNullOrEmpty(SelectedProjectItem.UniqueName) && !SelectedProjectItem.IsBatchBuildProject; private void CopyErrorMessageToClipboard(ProjectItem projectItem) { @@ -335,10 +314,7 @@ private void CopyErrorMessageToClipboard(ProjectItem projectItem) public ICommand GridSorting => new RelayCommand(obj => ReorderGrid(obj)); - public ICommand GridGroupPropertyMenuItemClicked => new RelayCommand(obj => - { - GridGroupPropertyName = (obj != null) ? obj.ToString() : string.Empty; - }); + public ICommand GridGroupPropertyMenuItemClicked => new RelayCommand(obj => GridGroupPropertyName = (obj != null) ? obj.ToString() : string.Empty); public ICommand SelectedProjectOpenContainingFolderAction => new RelayCommand(obj => OpenContainingFolder(), canExecute: obj => (SelectedProjectItem != null && !string.IsNullOrEmpty(SelectedProjectItem.FullName))); @@ -368,71 +344,4 @@ private void CopyErrorMessageToClipboard(ProjectItem projectItem) public event Action ShowOptionPage; } - - public class SortOrderFactory - { - public static ProjectItemColumnSorter GetProjectItemSorter(SortDescription sortDescription) - { - var sortOrder = sortDescription.Order; - string sortPropertyName = sortDescription.Property; - if (sortOrder != SortOrder.None && !string.IsNullOrEmpty(sortPropertyName)) - { - ListSortDirection? sortDirection = sortOrder.ToSystem(); - Debug.Assert(sortDirection != null); - - switch (sortPropertyName) - { - case nameof(ProjectItem.BuildElapsedTime): - return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.BuildElapsedTime); - case nameof(ProjectItem.BuildFinishTime): - return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.BuildFinishTime); - case nameof(ProjectItem.BuildOrder): - return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.BuildOrder); - case nameof(ProjectItem.CommonType): - return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.CommonType); - case nameof(ProjectItem.Configuration): - return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.Configuration); - case nameof(ProjectItem.ErrorsCount): - return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.ErrorsCount); - case nameof(ProjectItem.ExtenderNames): - return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.ExtenderNames); - case nameof(ProjectItem.FlavourType): - return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.FlavourType); - case nameof(ProjectItem.Framework): - return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.Framework); - case nameof(ProjectItem.FullName): - return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.FullName); - case nameof(ProjectItem.FullPath): - return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.FullPath); - case nameof(ProjectItem.IsBatchBuildProject): - return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.IsBatchBuildProject); - case nameof(ProjectItem.Language): - return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.Language); - case nameof(ProjectItem.MainFlavourType): - return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.MainFlavourType); - case nameof(ProjectItem.MessagesCount): - return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.MessagesCount); - case nameof(ProjectItem.Name): - return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.Name); - case nameof(ProjectItem.OutputType): - return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.OutputType); - case nameof(ProjectItem.Platform): - return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.Platform); - case nameof(ProjectItem.RootNamespace): - return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.RootNamespace); - case nameof(ProjectItem.SolutionFolder): - return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.SolutionFolder); - case nameof(ProjectItem.State): - return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.State); - case nameof(ProjectItem.Success): - return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.Success); - case nameof(ProjectItem.UniqueName): - return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.UniqueName); - case nameof(ProjectItem.WarningsCount): - return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.WarningsCount); - } - } - return null; - } - } } diff --git a/src/BuildVision.UI/ViewModels/SortOrderFactory.cs b/src/BuildVision.UI/ViewModels/SortOrderFactory.cs new file mode 100644 index 00000000..fb67c930 --- /dev/null +++ b/src/BuildVision.UI/ViewModels/SortOrderFactory.cs @@ -0,0 +1,75 @@ +using System.ComponentModel; +using System.Diagnostics; +using BuildVision.UI.Helpers; +using BuildVision.UI.Models; +using SortDescription = BuildVision.UI.Settings.Models.Sorting.SortDescription; + +namespace BuildVision.UI.ViewModels +{ + public class SortOrderFactory + { + public static ProjectItemColumnSorter GetProjectItemSorter(SortDescription sortDescription) + { + var sortOrder = sortDescription.Order; + string sortPropertyName = sortDescription.Property; + if (sortOrder != SortOrder.None && !string.IsNullOrEmpty(sortPropertyName)) + { + ListSortDirection? sortDirection = sortOrder.ToSystem(); + Debug.Assert(sortDirection != null); + + switch (sortPropertyName) + { + case nameof(ProjectItem.BuildElapsedTime): + return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.BuildElapsedTime); + case nameof(ProjectItem.BuildFinishTime): + return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.BuildFinishTime); + case nameof(ProjectItem.BuildOrder): + return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.BuildOrder); + case nameof(ProjectItem.CommonType): + return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.CommonType); + case nameof(ProjectItem.Configuration): + return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.Configuration); + case nameof(ProjectItem.ErrorsCount): + return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.ErrorsCount); + case nameof(ProjectItem.ExtenderNames): + return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.ExtenderNames); + case nameof(ProjectItem.FlavourType): + return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.FlavourType); + case nameof(ProjectItem.Framework): + return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.Framework); + case nameof(ProjectItem.FullName): + return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.FullName); + case nameof(ProjectItem.FullPath): + return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.FullPath); + case nameof(ProjectItem.IsBatchBuildProject): + return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.IsBatchBuildProject); + case nameof(ProjectItem.Language): + return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.Language); + case nameof(ProjectItem.MainFlavourType): + return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.MainFlavourType); + case nameof(ProjectItem.MessagesCount): + return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.MessagesCount); + case nameof(ProjectItem.Name): + return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.Name); + case nameof(ProjectItem.OutputType): + return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.OutputType); + case nameof(ProjectItem.Platform): + return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.Platform); + case nameof(ProjectItem.RootNamespace): + return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.RootNamespace); + case nameof(ProjectItem.SolutionFolder): + return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.SolutionFolder); + case nameof(ProjectItem.State): + return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.State); + case nameof(ProjectItem.Success): + return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.Success); + case nameof(ProjectItem.UniqueName): + return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.UniqueName); + case nameof(ProjectItem.WarningsCount): + return new ProjectItemColumnSorter(sortDirection.Value, prop => prop.WarningsCount); + } + } + return null; + } + } +} From 3ea37b705bd4240a9e5c2da6f481b4302ae72dec Mon Sep 17 00:00:00 2001 From: Stefan Kert Date: Mon, 21 Oct 2019 07:28:35 +0200 Subject: [PATCH 100/100] Fixed errorlist --- src/BuildVision.UI/App.xaml.cs | 3 ++- src/BuildVision.UI/Components/ErrorsGrid.xaml | 5 +++-- src/BuildVision.UI/Components/ProjectGrid.xaml | 4 ++-- src/BuildVision.UI/Models/SortDescription.cs | 4 ++-- src/BuildVision.UI/Models/WindowStateAction.cs | 4 ++-- src/BuildVision/BuildVision.csproj | 3 +++ src/BuildVision/Core/BuildVisionPackage.cs | 5 +++++ 7 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/BuildVision.UI/App.xaml.cs b/src/BuildVision.UI/App.xaml.cs index e979785d..33db04d2 100644 --- a/src/BuildVision.UI/App.xaml.cs +++ b/src/BuildVision.UI/App.xaml.cs @@ -1,4 +1,5 @@ -using System.Windows; +using System.Diagnostics; +using System.Windows; namespace BuildVision.UI { diff --git a/src/BuildVision.UI/Components/ErrorsGrid.xaml b/src/BuildVision.UI/Components/ErrorsGrid.xaml index ed393b41..dd2e0f4e 100644 --- a/src/BuildVision.UI/Components/ErrorsGrid.xaml +++ b/src/BuildVision.UI/Components/ErrorsGrid.xaml @@ -7,6 +7,7 @@ xmlns:contracts="clr-namespace:BuildVision.Contracts;assembly=BuildVision.Contracts" xmlns:componentModel="clr-namespace:System.ComponentModel;assembly=WindowsBase" xmlns:models="clr-namespace:BuildVision.UI.Models" + xmlns:vsfx="clr-namespace:Microsoft.VisualStudio.Shell;assembly=Microsoft.VisualStudio.Shell.14.0" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300" @@ -53,8 +54,8 @@ - - + + diff --git a/src/BuildVision.UI/Components/ProjectGrid.xaml b/src/BuildVision.UI/Components/ProjectGrid.xaml index f2d19bcd..d22a9f44 100644 --- a/src/BuildVision.UI/Components/ProjectGrid.xaml +++ b/src/BuildVision.UI/Components/ProjectGrid.xaml @@ -128,7 +128,7 @@ - + @@ -161,7 +161,7 @@ - + diff --git a/src/BuildVision.UI/Models/SortDescription.cs b/src/BuildVision.UI/Models/SortDescription.cs index df2cf1c5..1a9aa29b 100644 --- a/src/BuildVision.UI/Models/SortDescription.cs +++ b/src/BuildVision.UI/Models/SortDescription.cs @@ -8,12 +8,12 @@ public class SortDescription public string Property { get; set; } + public SortDescription() { } + public SortDescription(SortOrder order, string property) { Order = order; Property = property; } - - public SortDescription() { } } } diff --git a/src/BuildVision.UI/Models/WindowStateAction.cs b/src/BuildVision.UI/Models/WindowStateAction.cs index df24bff9..2c2f04c6 100644 --- a/src/BuildVision.UI/Models/WindowStateAction.cs +++ b/src/BuildVision.UI/Models/WindowStateAction.cs @@ -6,11 +6,11 @@ public class WindowStateAction { public WindowState State { get; set; } + public WindowStateAction() { } + public WindowStateAction(WindowState state) { State = state; } - - public WindowStateAction() { } } } diff --git a/src/BuildVision/BuildVision.csproj b/src/BuildVision/BuildVision.csproj index 4fe3e216..f976a08a 100644 --- a/src/BuildVision/BuildVision.csproj +++ b/src/BuildVision/BuildVision.csproj @@ -247,6 +247,9 @@ runtime; build; native; contentfiles; analyzers all + + 3.2.0 + true diff --git a/src/BuildVision/Core/BuildVisionPackage.cs b/src/BuildVision/Core/BuildVisionPackage.cs index 966c43c3..74587ddf 100644 --- a/src/BuildVision/Core/BuildVisionPackage.cs +++ b/src/BuildVision/Core/BuildVisionPackage.cs @@ -21,6 +21,7 @@ using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; using Serilog; +using SerilogTraceListener; using Task = System.Threading.Tasks.Task; using ui = Microsoft.VisualStudio.VSConstants.UICONTEXT; @@ -64,6 +65,10 @@ public BuildVisionPackage() { _logger.Information("Starting {ProductName} with Version {PackageVersion}", Resources.ProductName, ApplicationInfo.GetPackageVersion(this)); + PresentationTraceSources.Refresh(); + PresentationTraceSources.DataBindingSource.Listeners.Add(new SerilogTraceListener.SerilogTraceListener(_logger)); + PresentationTraceSources.DataBindingSource.Switch.Level = SourceLevels.Error | SourceLevels.Critical | SourceLevels.Warning; + if (Application.Current != null) { Application.Current.DispatcherUnhandledException += Current_DispatcherUnhandledException;