From f104e6fcbd73f85e7ed40452c302802e4295229a Mon Sep 17 00:00:00 2001 From: Erik Edespong Date: Tue, 19 Dec 2017 23:13:23 +0100 Subject: [PATCH 1/3] Removed references causing compile error. Also removed the VS upgrade log, which seems unnecessary. --- .../BuildMonitorPackage.csproj | 23 +----------------- UpgradeLog.htm | Bin 54634 -> 0 bytes 2 files changed, 1 insertion(+), 22 deletions(-) delete mode 100644 UpgradeLog.htm diff --git a/BuildMonitorPackage/BuildMonitorPackage.csproj b/BuildMonitorPackage/BuildMonitorPackage.csproj index f749cee..e25ebc1 100644 --- a/BuildMonitorPackage/BuildMonitorPackage.csproj +++ b/BuildMonitorPackage/BuildMonitorPackage.csproj @@ -63,10 +63,7 @@ - True - - - True + False @@ -158,24 +155,6 @@ - - {1A31287A-4D7D-413E-8E32-3B374931BD89} - 8 - 0 - 0 - primary - False - False - - - {2CE2370E-D744-4936-A090-3FFFE667B0E1} - 9 - 0 - 0 - primary - False - False - {1CBA492E-7263-47BB-87FE-639000619B15} 8 diff --git a/UpgradeLog.htm b/UpgradeLog.htm deleted file mode 100644 index 2b63597387825afc467283751e6000561cbfeb3b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 54634 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 Z^bi%(f3b;1$@BPs$w^X9ux)#k`+uT@rS<>- From 53c86bf0b13cecdd72ec0c8e6acfd2b2b7331b9e Mon Sep 17 00:00:00 2001 From: Erik Edespong Date: Thu, 21 Dec 2017 15:01:10 +0100 Subject: [PATCH 2/3] Added options page with output file path Settings is no longer a static class in order to be able to create it with a WritableSettingsStore to persist data. Instead, it has a static instance. --- .../AnalyseBuildTimesCommand.cs | 2 +- BuildMonitorPackage/BuildMonitorPackage.cs | 29 ++--- .../BuildMonitorPackage.csproj | 3 + BuildMonitorPackage/Settings.cs | 109 ++++++++++++++++-- BuildMonitorPackage/SettingsPage.cs | 24 ++++ .../source.extension.vsixmanifest | 6 +- 6 files changed, 146 insertions(+), 27 deletions(-) create mode 100644 BuildMonitorPackage/SettingsPage.cs diff --git a/BuildMonitorPackage/AnalyseBuildTimesCommand.cs b/BuildMonitorPackage/AnalyseBuildTimesCommand.cs index 307e86e..8481763 100644 --- a/BuildMonitorPackage/AnalyseBuildTimesCommand.cs +++ b/BuildMonitorPackage/AnalyseBuildTimesCommand.cs @@ -101,7 +101,7 @@ public static void Initialize(Package package) /// Event args. private void MenuItemCallback(object sender, EventArgs e) { - var form = new AnalyseBuildTimes(new BuildMonitor.LocalData.AnalyseBuildTimes().Calculate(File.ReadAllText(Settings.RepositoryPath)).SolutionMonthTable()); + var form = new AnalyseBuildTimes(new BuildMonitor.LocalData.AnalyseBuildTimes().Calculate(File.ReadAllText(Settings.Instance.RepositoryPath)).SolutionMonthTable()); form.ShowDialog(); } diff --git a/BuildMonitorPackage/BuildMonitorPackage.cs b/BuildMonitorPackage/BuildMonitorPackage.cs index 1e65b41..1e08668 100644 --- a/BuildMonitorPackage/BuildMonitorPackage.cs +++ b/BuildMonitorPackage/BuildMonitorPackage.cs @@ -1,4 +1,5 @@ using System; +using System.ComponentModel; using System.ComponentModel.Design; using System.Runtime.InteropServices; using BuildMonitor; @@ -11,20 +12,22 @@ using System.Data.SqlClient; using System.Data; using System.Security.Principal; -using System.Threading.Tasks; +using Microsoft.VisualStudio.Settings; +using Microsoft.VisualStudio.Shell.Settings; namespace BuildMonitorPackage { [InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)] [Guid(GuidList.guidBuildMonitorPackagePkgString)] [PackageRegistration(UseManagedResourcesOnly = true)] - [ProvideAutoLoad("{f1536ef8-92ec-443c-9ed7-fdadf150da82}")] + [ProvideAutoLoad(VSConstants.UICONTEXT.SolutionExists_string)] [ProvideMenuResource("Menus.ctmenu", 1)] + [ProvideOptionPage(typeof(SettingsPage), "Build Monitor", "General", 0, 0, true)] sealed class BuildMonitorPackage : Package, IVsUpdateSolutionEvents2 { private DTE dte; - private readonly Monitor monitor; - private readonly DataAdjusterWithLogging dataAdjuster; + private Monitor monitor; + private DataAdjusterWithLogging dataAdjuster; private BuildMonitor.Domain.Solution solution; private IVsSolutionBuildManager2 sbm; @@ -33,24 +36,24 @@ sealed class BuildMonitorPackage : Package, IVsUpdateSolutionEvents2 private SolutionEvents events; private IVsSolution2 vsSolution; - public BuildMonitorPackage() + protected override void Initialize() { - Settings.CreateApplicationFolderIfNotExist(); + base.Initialize(); + + SettingsManager settingsManager = new ShellSettingsManager(ServiceProvider.GlobalProvider); + WritableSettingsStore settingsStore = settingsManager.GetWritableSettingsStore(SettingsScope.UserSettings); + Settings.Instance = new Settings(settingsStore); var factory = new BuildFactory(); - var repository = new BuildRepository(Settings.RepositoryPath); + var repository = new BuildRepository(Settings.Instance.RepositoryPath); monitor = new Monitor(factory, repository); dataAdjuster = new DataAdjusterWithLogging(repository, PrintLine); - } - - protected override void Initialize() - { - base.Initialize(); //if invalid data, adjust it dataAdjuster.Adjust(); + // Get solution build manager sbm = ServiceProvider.GlobalProvider.GetService(typeof(SVsSolutionBuildManager)) as IVsSolutionBuildManager2; if (sbm != null) @@ -64,7 +67,7 @@ protected override void Initialize() GetDTE().Events.BuildEvents.OnBuildBegin += Build_Begin; PrintLine("Build monitor initialized"); - PrintLine("Path to persist data: {0}", Settings.RepositoryPath); + PrintLine("Path to persist data: {0}", Settings.Instance.RepositoryPath); monitor.SolutionBuildFinished = b => { diff --git a/BuildMonitorPackage/BuildMonitorPackage.csproj b/BuildMonitorPackage/BuildMonitorPackage.csproj index e25ebc1..d055732 100644 --- a/BuildMonitorPackage/BuildMonitorPackage.csproj +++ b/BuildMonitorPackage/BuildMonitorPackage.csproj @@ -191,6 +191,9 @@ + + Component + diff --git a/BuildMonitorPackage/Settings.cs b/BuildMonitorPackage/Settings.cs index 372846d..cf38544 100644 --- a/BuildMonitorPackage/Settings.cs +++ b/BuildMonitorPackage/Settings.cs @@ -1,5 +1,7 @@ using System; +using System.Diagnostics; using System.IO; +using Microsoft.VisualStudio.Settings; // ReSharper disable InconsistentNaming namespace BuildMonitorPackage @@ -9,27 +11,114 @@ public static class OptionKey public const string SolutionId = "bm_solution_id"; } - public static class Settings - { - public static string RepositoryPath = string.Format("{0}\\{1}\\{2}", Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), ApplicationFolderName, JsonFileName); + public class Settings { + + private static readonly string DefaultRepositoryPath = Path.Combine("%ApplicationData%", ApplicationFolderName, JsonFileName); - private static string ApplicationFolder = string.Format("{0}\\{1}", Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), ApplicationFolderName); + private string rawRepositoryPath = DefaultRepositoryPath; private const string ApplicationFolderName = "Build Monitor"; + private const string JsonFileName = "buildtimes.json"; - - public static void CreateApplicationFolderIfNotExist() + private readonly WritableSettingsStore settingsStore; + + private const string CollectionPath = "BuildMonitor"; + + public static Settings Instance { get; set; } + + public Settings(WritableSettingsStore settingsStore) { + this.settingsStore = settingsStore; + LoadSettings(); + CreateApplicationFolderIfNotExist(); + } + + public string RawRepositoryPath + { + get => rawRepositoryPath; + set + { + if (rawRepositoryPath != value) + { + rawRepositoryPath = value; + SaveSettings(); + } + } + } + + public string RepositoryPath => ExpandPath(rawRepositoryPath); + + private void CreateApplicationFolderIfNotExist() { - if(!Directory.Exists(ApplicationFolder)) + string folder = Path.GetDirectoryName(RepositoryPath); + if (!Directory.Exists(folder)) + { + Directory.CreateDirectory(folder); + } + if (!File.Exists(RepositoryPath)) + { + using (var f = File.Create(RepositoryPath)){} + } + } + + private void LoadSettings() { + try { - Directory.CreateDirectory(ApplicationFolder); + RawRepositoryPath = settingsStore.GetString(CollectionPath, "RepositoryPath", DefaultRepositoryPath); } - if(!File.Exists(RepositoryPath)) + catch (Exception ex) { - using(var f = File.Create(RepositoryPath)){} + Debug.Fail(ex.Message); } } + + private void SaveSettings() { + try + { + if (!settingsStore.CollectionExists(CollectionPath)) + { + settingsStore.CreateCollection(CollectionPath); + } + + settingsStore.SetString(CollectionPath, "RepositoryPath", rawRepositoryPath); + } + catch (Exception ex) + { + Debug.Fail(ex.Message); + } + } + + /// + /// Expands a path possibly starting with a + /// to a full path. + /// + private static string ExpandPath(string path) + { + if (!path.StartsWith("%")) + { + return path; + } + + int splitIndex = path.IndexOf("%", 1, StringComparison.InvariantCulture) + 1; + string maybeSpecialFolder = path.Substring(0, splitIndex).Trim('%'); + string rest = path.Substring(splitIndex); + while (rest.StartsWith(Path.DirectorySeparatorChar.ToString())) + { + // The remaining path cannot start with a rooted path as that + // will "break" Path.Combine. + rest = rest.Substring(1); + } + + foreach (var @enum in Enum.GetNames(typeof(Environment.SpecialFolder))) + { + if (@enum.Equals(maybeSpecialFolder, StringComparison.InvariantCultureIgnoreCase)) + { + return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), rest); + } + } + + return path; + } } } // ReSharper restore InconsistentNaming \ No newline at end of file diff --git a/BuildMonitorPackage/SettingsPage.cs b/BuildMonitorPackage/SettingsPage.cs new file mode 100644 index 0000000..bfdb54c --- /dev/null +++ b/BuildMonitorPackage/SettingsPage.cs @@ -0,0 +1,24 @@ +using System.ComponentModel; +using Microsoft.VisualStudio.Shell; + +namespace BuildMonitorPackage +{ + public class SettingsPage : DialogPage + { + [Category("Build Monitor")] + [DisplayName("Output File Path")] + [Description("Specifies the path to the file to which data is persisted. Can contain special folders, see https://msdn.microsoft.com/en-us/library/system.environment.specialfolder(v=vs.110).aspx, enclosed in %. Example: %ApplicationData%\\Build Monitor\\buildtimes.json (default)")] + public string RepositoryPath { get; set; } + + public SettingsPage() + { + RepositoryPath = Settings.Instance.RawRepositoryPath; + } + + protected override void OnApply(PageApplyEventArgs args) + { + base.OnApply(args); + Settings.Instance.RawRepositoryPath = RepositoryPath; + } + } +} diff --git a/BuildMonitorPackage/source.extension.vsixmanifest b/BuildMonitorPackage/source.extension.vsixmanifest index a2a1e17..be5fb88 100644 --- a/BuildMonitorPackage/source.extension.vsixmanifest +++ b/BuildMonitorPackage/source.extension.vsixmanifest @@ -13,9 +13,9 @@ - - - + + + From afa22a1bc0ac935cf05d196539ebe341794501ca Mon Sep 17 00:00:00 2001 From: Erik Edespong Date: Thu, 21 Dec 2017 17:39:58 +0100 Subject: [PATCH 3/3] Write to output when changing settings Broke out the output window code to separate class. Also removed the IntExtension which can be replaced by a standard string constructor. --- BuildMonitor/BuildMonitor.csproj | 1 - BuildMonitor/IntExtensions.cs | 13 ----- BuildMonitorPackage/BuildMonitorPackage.cs | 47 +++++-------------- .../BuildMonitorPackage.csproj | 1 + BuildMonitorPackage/OutputWindowWrapper.cs | 45 ++++++++++++++++++ BuildMonitorPackage/SettingsPage.cs | 3 ++ 6 files changed, 61 insertions(+), 49 deletions(-) delete mode 100644 BuildMonitor/IntExtensions.cs create mode 100644 BuildMonitorPackage/OutputWindowWrapper.cs diff --git a/BuildMonitor/BuildMonitor.csproj b/BuildMonitor/BuildMonitor.csproj index 9cdd5bf..3697980 100644 --- a/BuildMonitor/BuildMonitor.csproj +++ b/BuildMonitor/BuildMonitor.csproj @@ -62,7 +62,6 @@ - diff --git a/BuildMonitor/IntExtensions.cs b/BuildMonitor/IntExtensions.cs deleted file mode 100644 index 9d17ba9..0000000 --- a/BuildMonitor/IntExtensions.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Linq; -using System.Collections.Generic; - -namespace BuildMonitor -{ - public static class IntExtensions - { - public static string Times(this int i, string s) - { - return string.Join("", Enumerable.Range(0, i).Select(d => s)); - } - } -} \ No newline at end of file diff --git a/BuildMonitorPackage/BuildMonitorPackage.cs b/BuildMonitorPackage/BuildMonitorPackage.cs index 1e08668..be89730 100644 --- a/BuildMonitorPackage/BuildMonitorPackage.cs +++ b/BuildMonitorPackage/BuildMonitorPackage.cs @@ -1,5 +1,4 @@ using System; -using System.ComponentModel; using System.ComponentModel.Design; using System.Runtime.InteropServices; using BuildMonitor; @@ -32,14 +31,16 @@ sealed class BuildMonitorPackage : Package, IVsUpdateSolutionEvents2 private IVsSolutionBuildManager2 sbm; private uint updateSolutionEventsCookie; - private OutputWindowPane outputWindowPane; private SolutionEvents events; private IVsSolution2 vsSolution; + private OutputWindowWrapper output; protected override void Initialize() { base.Initialize(); + output = new OutputWindowWrapper(this); + SettingsManager settingsManager = new ShellSettingsManager(ServiceProvider.GlobalProvider); WritableSettingsStore settingsStore = settingsManager.GetWritableSettingsStore(SettingsScope.UserSettings); Settings.Instance = new Settings(settingsStore); @@ -48,7 +49,7 @@ protected override void Initialize() var repository = new BuildRepository(Settings.Instance.RepositoryPath); monitor = new Monitor(factory, repository); - dataAdjuster = new DataAdjusterWithLogging(repository, PrintLine); + dataAdjuster = new DataAdjusterWithLogging(repository, output.WriteLine); //if invalid data, adjust it dataAdjuster.Adjust(); @@ -66,18 +67,18 @@ protected override void Initialize() events.Opened += Solution_Opened; GetDTE().Events.BuildEvents.OnBuildBegin += Build_Begin; - PrintLine("Build monitor initialized"); - PrintLine("Path to persist data: {0}", Settings.Instance.RepositoryPath); + output.WriteLine("Build monitor initialized"); + output.WriteLine("Path to persist data: {0}", Settings.Instance.RepositoryPath); monitor.SolutionBuildFinished = b => { - Print("[{0}] Time Elapsed: {1} \t\t", b.SessionBuildCount, b.SolutionBuildTime.ToTime()); - PrintLine("Session build time: {0}\n", b.SessionMillisecondsElapsed.ToTime()); - PrintLine("Rebuild All: {0}\n", b.SolutionBuild.IsRebuildAll); + output.Write("[{0}] Time Elapsed: {1} \t\t", b.SessionBuildCount, b.SolutionBuildTime.ToTime()); + output.WriteLine("Session build time: {0}\n", b.SessionMillisecondsElapsed.ToTime()); + output.WriteLine("Rebuild All: {0}\n", b.SolutionBuild.IsRebuildAll); System.Threading.Tasks.Task.Factory.StartNew(() => SaveToDatabase(b)); }; - monitor.ProjectBuildFinished = b => PrintLine(" - {0}\t-- {1} --", b.MillisecondsElapsed.ToTime(), b.ProjectName); + monitor.ProjectBuildFinished = b => output.WriteLine(" - {0}\t-- {1} --", b.MillisecondsElapsed.ToTime(), b.ProjectName); AnalyseBuildTimesCommand.Initialize(this); } @@ -104,34 +105,10 @@ private void SaveToDatabase(SolutionBuildData b) private void Solution_Opened() { solution = new BuildMonitor.Domain.Solution { Name = GetSolutionName() }; - PrintLine("\nSolution loaded: \t{0}", solution.Name); - PrintLine("{0}", 60.Times("-")); - } - - #region Print to output window pane - - private OutputWindowPane GetOutputWindowPane() - { - if (outputWindowPane == null) - { - var outputWindow = (OutputWindow)GetDTE().Windows.Item(EnvDTEConstants.vsWindowKindOutput).Object; - outputWindowPane = outputWindow.OutputWindowPanes.Add("Build monitor"); - } - return outputWindowPane; + output.WriteLine("\nSolution loaded: \t{0}", solution.Name); + output.WriteLine(new string('-', 60)); } - private void Print(string format, params object[] args) - { - GetOutputWindowPane().OutputString(string.Format(format, args)); - } - - private void PrintLine(string format, params object[] args) - { - Print(format + Environment.NewLine, args); - } - - #endregion - #region Get objects from vs private DTE GetDTE() diff --git a/BuildMonitorPackage/BuildMonitorPackage.csproj b/BuildMonitorPackage/BuildMonitorPackage.csproj index d055732..06c2cd5 100644 --- a/BuildMonitorPackage/BuildMonitorPackage.csproj +++ b/BuildMonitorPackage/BuildMonitorPackage.csproj @@ -182,6 +182,7 @@ + True True diff --git a/BuildMonitorPackage/OutputWindowWrapper.cs b/BuildMonitorPackage/OutputWindowWrapper.cs new file mode 100644 index 0000000..8f0e3ec --- /dev/null +++ b/BuildMonitorPackage/OutputWindowWrapper.cs @@ -0,0 +1,45 @@ +using System; +using EnvDTE; +using Microsoft.VisualStudio.Shell.Interop; + +namespace BuildMonitorPackage { + internal class OutputWindowWrapper { + private readonly OutputWindowPane outputWindowPane; + + public OutputWindowWrapper(IServiceProvider serviceContainer) + { + var dte = serviceContainer.GetService(typeof(SDTE)) as DTE; + var outputWindow = (OutputWindow)dte.Windows.Item(EnvDTEConstants.vsWindowKindOutput).Object; + + foreach (OutputWindowPane pane in outputWindow.OutputWindowPanes) + { + if (pane.Name == "Build monitor") + { + outputWindowPane = pane; + } + } + + if (outputWindowPane == null) + { + outputWindowPane = outputWindow.OutputWindowPanes.Add("Build monitor"); + } + } + + public void Write(string text) { + outputWindowPane.OutputString(text); + } + + public void Write(string format, params object[] args) { + outputWindowPane.OutputString(string.Format(format, args)); + } + + public void WriteLine(string text) { + Write(text + Environment.NewLine); + } + + public void WriteLine(string format, params object[] args) + { + Write(format + Environment.NewLine, args); + } + } +} diff --git a/BuildMonitorPackage/SettingsPage.cs b/BuildMonitorPackage/SettingsPage.cs index bfdb54c..afb75c1 100644 --- a/BuildMonitorPackage/SettingsPage.cs +++ b/BuildMonitorPackage/SettingsPage.cs @@ -19,6 +19,9 @@ protected override void OnApply(PageApplyEventArgs args) { base.OnApply(args); Settings.Instance.RawRepositoryPath = RepositoryPath; + + var output = new OutputWindowWrapper(ServiceProvider.GlobalProvider); + output.WriteLine("New path to persist data: {0}", Settings.Instance.RepositoryPath); } } }