diff --git a/GitPull.sln b/GitPull.sln index fff43c1..7a2d889 100644 --- a/GitPull.sln +++ b/GitPull.sln @@ -1,9 +1,9 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.28412.107 +# Visual Studio 15 +VisualStudioVersion = 15.0.28307.106 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GitPull", "src\GitPull.csproj", "{F03208D5-DA79-4B47-9A04-B802562AB242}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GitPull", "src\GitPull\GitPull.csproj", "{F03208D5-DA79-4B47-9A04-B802562AB242}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{0958FFB6-1CAA-4D59-973B-55CBE43745A3}" ProjectSection(SolutionItems) = preProject @@ -11,6 +11,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution README.md = README.md EndProjectSection EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GitPull.Services.15.0", "src\GitPull.Services.15.0\GitPull.Services.15.0.csproj", "{6CC39D34-677A-4474-AF19-E63CB343D2EE}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GitPull.Services", "src\GitPull.Services\GitPull.Services.csproj", "{BAFFF30C-FE61-4B1F-B5B6-D28520AC777D}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GitPull.Services.16.0", "src\GitPull.Services.16.0\GitPull.Services.16.0.csproj", "{5A441C17-A176-4DEF-A00E-DCC1662747EC}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -21,6 +27,18 @@ Global {F03208D5-DA79-4B47-9A04-B802562AB242}.Debug|Any CPU.Build.0 = Debug|Any CPU {F03208D5-DA79-4B47-9A04-B802562AB242}.Release|Any CPU.ActiveCfg = Release|Any CPU {F03208D5-DA79-4B47-9A04-B802562AB242}.Release|Any CPU.Build.0 = Release|Any CPU + {6CC39D34-677A-4474-AF19-E63CB343D2EE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6CC39D34-677A-4474-AF19-E63CB343D2EE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6CC39D34-677A-4474-AF19-E63CB343D2EE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6CC39D34-677A-4474-AF19-E63CB343D2EE}.Release|Any CPU.Build.0 = Release|Any CPU + {BAFFF30C-FE61-4B1F-B5B6-D28520AC777D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BAFFF30C-FE61-4B1F-B5B6-D28520AC777D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BAFFF30C-FE61-4B1F-B5B6-D28520AC777D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BAFFF30C-FE61-4B1F-B5B6-D28520AC777D}.Release|Any CPU.Build.0 = Release|Any CPU + {5A441C17-A176-4DEF-A00E-DCC1662747EC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5A441C17-A176-4DEF-A00E-DCC1662747EC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5A441C17-A176-4DEF-A00E-DCC1662747EC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5A441C17-A176-4DEF-A00E-DCC1662747EC}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/appveyor.yml b/appveyor.yml index 2fb5f19..66d36ea 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -5,7 +5,7 @@ install: before_build: - ps: Vsix-IncrementVsixVersion | Vsix-UpdateBuildVersion - - ps: Vsix-TokenReplacement src\source.extension.cs 'Version = "([0-9\\.]+)"' 'Version = "{version}"' + - ps: Vsix-TokenReplacement src\GitPull\source.extension.cs 'Version = "([0-9\\.]+)"' 'Version = "{version}"' build_script: - nuget restore -Verbosity quiet diff --git a/lib/15.0/Microsoft.TeamFoundation.Common.dll b/lib/15.0/Microsoft.TeamFoundation.Common.dll new file mode 100644 index 0000000..51c1717 Binary files /dev/null and b/lib/15.0/Microsoft.TeamFoundation.Common.dll differ diff --git a/lib/15.0/Microsoft.TeamFoundation.Controls.dll b/lib/15.0/Microsoft.TeamFoundation.Controls.dll new file mode 100644 index 0000000..d014e7a Binary files /dev/null and b/lib/15.0/Microsoft.TeamFoundation.Controls.dll differ diff --git a/lib/15.0/Microsoft.TeamFoundation.Git.Controls.dll b/lib/15.0/Microsoft.TeamFoundation.Git.Controls.dll new file mode 100644 index 0000000..93556f9 Binary files /dev/null and b/lib/15.0/Microsoft.TeamFoundation.Git.Controls.dll differ diff --git a/lib/15.0/Microsoft.TeamFoundation.Git.CoreServices.dll b/lib/15.0/Microsoft.TeamFoundation.Git.CoreServices.dll new file mode 100644 index 0000000..4acf299 Binary files /dev/null and b/lib/15.0/Microsoft.TeamFoundation.Git.CoreServices.dll differ diff --git a/lib/15.0/Microsoft.TeamFoundation.Git.Provider.dll b/lib/15.0/Microsoft.TeamFoundation.Git.Provider.dll new file mode 100644 index 0000000..4e62949 Binary files /dev/null and b/lib/15.0/Microsoft.TeamFoundation.Git.Provider.dll differ diff --git a/lib/15.0/Microsoft.TeamFoundation.SourceControl.WebApi.dll b/lib/15.0/Microsoft.TeamFoundation.SourceControl.WebApi.dll new file mode 100644 index 0000000..bcf1ddb Binary files /dev/null and b/lib/15.0/Microsoft.TeamFoundation.SourceControl.WebApi.dll differ diff --git a/lib/16.0/Microsoft.TeamFoundation.Common.dll b/lib/16.0/Microsoft.TeamFoundation.Common.dll new file mode 100644 index 0000000..3b81a01 Binary files /dev/null and b/lib/16.0/Microsoft.TeamFoundation.Common.dll differ diff --git a/lib/16.0/Microsoft.TeamFoundation.Controls.dll b/lib/16.0/Microsoft.TeamFoundation.Controls.dll new file mode 100644 index 0000000..742b7c6 Binary files /dev/null and b/lib/16.0/Microsoft.TeamFoundation.Controls.dll differ diff --git a/lib/16.0/Microsoft.TeamFoundation.Git.Controls.dll b/lib/16.0/Microsoft.TeamFoundation.Git.Controls.dll new file mode 100644 index 0000000..c6b7150 Binary files /dev/null and b/lib/16.0/Microsoft.TeamFoundation.Git.Controls.dll differ diff --git a/lib/16.0/Microsoft.TeamFoundation.Git.CoreServices.dll b/lib/16.0/Microsoft.TeamFoundation.Git.CoreServices.dll new file mode 100644 index 0000000..5e8388f Binary files /dev/null and b/lib/16.0/Microsoft.TeamFoundation.Git.CoreServices.dll differ diff --git a/lib/16.0/Microsoft.TeamFoundation.Git.Provider.dll b/lib/16.0/Microsoft.TeamFoundation.Git.Provider.dll new file mode 100644 index 0000000..f09a00a Binary files /dev/null and b/lib/16.0/Microsoft.TeamFoundation.Git.Provider.dll differ diff --git a/lib/16.0/Microsoft.TeamFoundation.SourceControl.WebApi.dll b/lib/16.0/Microsoft.TeamFoundation.SourceControl.WebApi.dll new file mode 100644 index 0000000..118a9c9 Binary files /dev/null and b/lib/16.0/Microsoft.TeamFoundation.SourceControl.WebApi.dll differ diff --git a/src/Commands/PullCommand.cs b/src/Commands/PullCommand.cs deleted file mode 100644 index b060245..0000000 --- a/src/Commands/PullCommand.cs +++ /dev/null @@ -1,140 +0,0 @@ -using System; -using System.ComponentModel.Design; -using System.Diagnostics; -using System.IO; -using System.Reflection; -using EnvDTE; -using Microsoft; -using Microsoft.VisualStudio.Shell; -using Microsoft.VisualStudio.Shell.Interop; -using Process = System.Diagnostics.Process; -using Task = System.Threading.Tasks.Task; - -namespace GitPull -{ - internal sealed class PullCommand - { - public static async Task InitializeAsync(AsyncPackage package) - { - await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(package.DisposalToken); - - var commandService = await package.GetServiceAsync((typeof(IMenuCommandService))) as OleMenuCommandService; - Assumes.Present(commandService); - - var cmdId = new CommandID(PackageGuids.guidGitPullPackageCmdSet, PackageIds.PullCommandId); - var cmd = new MenuCommand((s, e) => Execute(package), cmdId) - { - Supported = false - }; - - commandService.AddCommand(cmd); - } - - public static void Execute(AsyncPackage package) - { - ThreadHelper.ThrowIfNotOnUIThread(); - - try - { - var serviceProvider = package as IServiceProvider; - Assumes.Present(serviceProvider); - var dte = serviceProvider.GetService(typeof(DTE)) as DTE; - Assumes.Present(dte); - - string solutionDir = FindSolutionDirectory(dte); - if (solutionDir == null) - { - return; - } - - var pane = new Lazy(() => - { - ThreadHelper.ThrowIfNotOnUIThread(); - Window window = dte.Windows.Item(EnvDTE.Constants.vsWindowKindOutput); - window.Activate(); - return package.GetOutputPane(Guid.NewGuid(), "Git Pull"); - }); - - ExecuteAsync(dte, solutionDir, pane).FileAndForget("madskristensen/gitpull"); - } - catch (Exception ex) - { - Debug.Write(ex); - } - } - - static async Task ExecuteAsync(DTE dte, string solutionDir, Lazy pane) - { - await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); - - bool outputText = false; - var progress = new Progress(line => - { - ThreadHelper.ThrowIfNotOnUIThread(); - pane.Value.OutputString(line + Environment.NewLine); - outputText = true; - }); - - await SyncRepositoryAsync(solutionDir, progress); - - if (!outputText) - { - dte.StatusBar.Text = "No branches require syncing"; - } - } - - static async Task SyncRepositoryAsync(string solutionDir, Progress progress) - { - string dir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); - string exeFile = Path.Combine(dir, "hub.exe"); - var startInfo = new ProcessStartInfo - { - FileName = exeFile, - Arguments = "sync", - WorkingDirectory = solutionDir, - UseShellExecute = false, - CreateNoWindow = true, - RedirectStandardError = true, - RedirectStandardOutput = true - }; - - var process = Process.Start(startInfo); - - await Task.WhenAll( - ReadAllAsync(process.StandardOutput, progress), - ReadAllAsync(process.StandardError, progress)); - } - - static async Task ReadAllAsync(StreamReader reader, IProgress progress) - { - while (true) - { - string line = await reader.ReadLineAsync(); - if (line == null || line == "fatal: Not a git repository") - { - break; - } - - progress.Report(line); - } - } - - static string FindSolutionDirectory(DTE dte) - { - ThreadHelper.ThrowIfNotOnUIThread(); - - string path = dte.Solution.FileName; - if (Directory.Exists(path)) - { - return path; - } - - if (File.Exists(path)) - { - return Path.GetDirectoryName(path); - } - - return null; - } - } -} diff --git a/src/GitPull.Services.15.0/GitPull.Services.15.0.csproj b/src/GitPull.Services.15.0/GitPull.Services.15.0.csproj new file mode 100644 index 0000000..d277775 --- /dev/null +++ b/src/GitPull.Services.15.0/GitPull.Services.15.0.csproj @@ -0,0 +1,39 @@ + + + + net46 + GitPull.Services + ..\..\lib\15.0 + + + + + + + + + + + + + + $(TeamExploerPath)\Microsoft.TeamFoundation.Git.Controls.dll + + + $(TeamExploerPath)\Microsoft.TeamFoundation.Git.CoreServices.dll + + + $(TeamExploerPath)\Microsoft.TeamFoundation.Git.Provider.dll + + + $(TeamExploerPath)\Microsoft.TeamFoundation.Controls.dll + + + + + + Microsoft.TeamFoundation.Git.Controls;Microsoft.TeamFoundation.Git.CoreServices;Microsoft.TeamFoundation.Git.Provider;Microsoft.TeamFoundation.Controls + + + + diff --git a/src/GitPull.Services.15.0/TeamExplorerService15.cs b/src/GitPull.Services.15.0/TeamExplorerService15.cs new file mode 100644 index 0000000..e072530 --- /dev/null +++ b/src/GitPull.Services.15.0/TeamExplorerService15.cs @@ -0,0 +1,9 @@ +using System; + +namespace GitPull.Services +{ + public class TeamExplorerService15 : TeamExplorerServiceBase + { + public TeamExplorerService15(IServiceProvider serviceProvider) : base(serviceProvider) { } + } +} diff --git a/src/GitPull.Services.15.0/TeamExplorerServiceBase.cs b/src/GitPull.Services.15.0/TeamExplorerServiceBase.cs new file mode 100644 index 0000000..a6327ee --- /dev/null +++ b/src/GitPull.Services.15.0/TeamExplorerServiceBase.cs @@ -0,0 +1,59 @@ +using System; +using System.Threading.Tasks; +using Microsoft; +using Microsoft.TeamFoundation.Controls; +using Microsoft.TeamFoundation.Git.Controls.Commits; +using Microsoft.TeamFoundation.Git.CoreServices; +using Microsoft.TeamFoundation.Git.Provider; +using Microsoft.VisualStudio.TeamFoundation.Git.Extensibility; + +namespace GitPull.Services +{ + // This needs to be compiled against TeamFoundation assemblies for the target Visual Studio version + public abstract class TeamExplorerServiceBase : ITeamExplorerService + { + readonly IServiceProvider serviceProvider; + + public TeamExplorerServiceBase(IServiceProvider serviceProvider) + { + this.serviceProvider = serviceProvider; + } + + public async Task PullAsync(string repositoryPath) + { + Assumes.Present(repositoryPath); + var service = serviceProvider.GetService(typeof(SccService)) as SccService; + Assumes.Present(service); + var teamExplorer = service.GetSccService(); + Assumes.NotNull(teamExplorer); + var page = await NavigateToPageAsync(teamExplorer, new Guid(TeamExplorerPageIds.GitCommits)); + Assumes.NotNull(page); + var gitCommitsPageView = page.PageContent as GitCommitsPageView; + Assumes.NotNull(gitCommitsPageView); + var gitCommitsPageViewModel = gitCommitsPageView.ViewModel as GitCommitsPageViewModel; + Assumes.NotNull(gitCommitsPageViewModel); + await gitCommitsPageViewModel.PullAsync(repositoryPath); + } + + static async Task NavigateToPageAsync(ITeamExplorer teamExplorer, Guid pageId) + { + // Page sometimes returns null so we need to wait for CurrentPage to change + var page = teamExplorer.NavigateToPage(pageId, null); + while (page?.GetId() != pageId) + { + await Task.Delay(1000); + page = teamExplorer.CurrentPage; + } + + return page; + } + + public string FindActiveRepositoryPath() + { + return + serviceProvider.GetService(typeof(IGitExt)) is IGitExt gitExt && + gitExt.ActiveRepositories is var repos && + repos.Count > 0 ? repos[0].RepositoryPath : null; + } + } +} diff --git a/src/GitPull.Services.16.0/GitPull.Services.16.0.csproj b/src/GitPull.Services.16.0/GitPull.Services.16.0.csproj new file mode 100644 index 0000000..d964a09 --- /dev/null +++ b/src/GitPull.Services.16.0/GitPull.Services.16.0.csproj @@ -0,0 +1,42 @@ + + + + net46 + GitPull.Services + ..\..\lib\16.0 + + + + + + + + + + + + + + + + + + $(TeamExploerPath)\Microsoft.TeamFoundation.Git.Controls.dll + + + $(TeamExploerPath)\Microsoft.TeamFoundation.Git.CoreServices.dll + + + $(TeamExploerPath)\Microsoft.TeamFoundation.Git.Provider.dll + + + $(TeamExploerPath)\Microsoft.TeamFoundation.Controls.dll + + + + + Microsoft.TeamFoundation.Git.Controls;Microsoft.TeamFoundation.Git.CoreServices;Microsoft.TeamFoundation.Git.Provider;Microsoft.TeamFoundation.Controls + + + + diff --git a/src/GitPull.Services.16.0/TeamExplorerService16.cs b/src/GitPull.Services.16.0/TeamExplorerService16.cs new file mode 100644 index 0000000..583287f --- /dev/null +++ b/src/GitPull.Services.16.0/TeamExplorerService16.cs @@ -0,0 +1,9 @@ +using System; + +namespace GitPull.Services +{ + public class TeamExplorerService16 : TeamExplorerServiceBase + { + public TeamExplorerService16(IServiceProvider serviceProvider) : base(serviceProvider) { } + } +} diff --git a/src/GitPull.Services/GitPull.Services.csproj b/src/GitPull.Services/GitPull.Services.csproj new file mode 100644 index 0000000..4091b07 --- /dev/null +++ b/src/GitPull.Services/GitPull.Services.csproj @@ -0,0 +1,11 @@ + + + + net46 + + + + + + + diff --git a/src/GitPull.Services/GitPullUIService.cs b/src/GitPull.Services/GitPullUIService.cs new file mode 100644 index 0000000..006963c --- /dev/null +++ b/src/GitPull.Services/GitPullUIService.cs @@ -0,0 +1,71 @@ +using System; +using EnvDTE; +using Microsoft.VisualStudio.Shell; +using Microsoft.VisualStudio.Shell.Interop; +using Task = System.Threading.Tasks.Task; + +namespace GitPull.Services +{ + public class GitPullUIService : IGitPullUIService + { + readonly Guid GitPaneGuid = new Guid("FBC10BF4-C9F8-4F0D-9CDE-69304226A68F"); + readonly Package package; + readonly ITeamExplorerService teamExplorerService; + readonly IHubService hubService; + readonly DTE dte; + + public GitPullUIService(Package package, DTE dte, + IHubService hubService, ITeamExplorerService teamExplorerService) + { + this.package = package; + this.teamExplorerService = teamExplorerService; + this.hubService = hubService; + this.dte = dte; + } + + public async Task SyncAndPullAsync() + { + await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); + + var repositoryPath = teamExplorerService.FindActiveRepositoryPath(); + if (repositoryPath == null) + { + dte.StatusBar.Text = "Not a git repository"; + return; + } + + var pane = new Lazy(() => + { + ThreadHelper.ThrowIfNotOnUIThread(); + Window window = dte.Windows.Item(EnvDTE.Constants.vsWindowKindOutput); + window.Activate(); + return package.GetOutputPane(GitPaneGuid, "Source Control - Git"); + }); + + bool outputText = false; + var outputProgress = new Progress(line => + { + ThreadHelper.ThrowIfNotOnUIThread(); + pane.Value.OutputString(line + Environment.NewLine); + outputText = true; + }); + + var statusProgress = new Progress(line => + { + ThreadHelper.ThrowIfNotOnUIThread(); + dte.StatusBar.Text = line; + }); + + await hubService.SyncRepositoryAsync(repositoryPath, outputProgress, statusProgress); + + if (!outputText) + { + dte.StatusBar.Text = "No branches require syncing"; + } + else + { + await teamExplorerService.PullAsync(repositoryPath); + } + } + } +} diff --git a/src/GitPull.Services/HubService.cs b/src/GitPull.Services/HubService.cs new file mode 100644 index 0000000..5191b8e --- /dev/null +++ b/src/GitPull.Services/HubService.cs @@ -0,0 +1,42 @@ +using System; +using System.IO; +using System.Reflection; +using System.Diagnostics; +using System.Threading.Tasks; + +namespace GitPull.Services +{ + public class HubService : IHubService + { + public async Task SyncRepositoryAsync(string repositoryPath, + Progress outputProgress, Progress statusProgress) + { + string dir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + string exeFile = Path.Combine(dir, "hub.exe"); + var startInfo = new ProcessStartInfo + { + FileName = exeFile, + Arguments = "sync", + WorkingDirectory = repositoryPath, + UseShellExecute = false, + CreateNoWindow = true, + RedirectStandardError = true, + RedirectStandardOutput = true + }; + + var process = Process.Start(startInfo); + + await Task.WhenAll( + ReadAllAsync(process.StandardOutput, outputProgress), + ReadAllAsync(process.StandardError, statusProgress)); + } + + static async Task ReadAllAsync(StreamReader reader, IProgress progress) + { + while (await reader.ReadLineAsync() is string line) + { + progress.Report(line); + } + } + } +} diff --git a/src/GitPull.Services/IGitPullUIService.cs b/src/GitPull.Services/IGitPullUIService.cs new file mode 100644 index 0000000..4ec8c8c --- /dev/null +++ b/src/GitPull.Services/IGitPullUIService.cs @@ -0,0 +1,9 @@ +using System.Threading.Tasks; + +namespace GitPull.Services +{ + public interface IGitPullUIService + { + Task SyncAndPullAsync(); + } +} \ No newline at end of file diff --git a/src/GitPull.Services/IHubService.cs b/src/GitPull.Services/IHubService.cs new file mode 100644 index 0000000..6cf2f11 --- /dev/null +++ b/src/GitPull.Services/IHubService.cs @@ -0,0 +1,10 @@ +using System; +using System.Threading.Tasks; + +namespace GitPull.Services +{ + public interface IHubService + { + Task SyncRepositoryAsync(string solutionDir, Progress outputProgress, Progress statusProgress); + } +} \ No newline at end of file diff --git a/src/GitPull.Services/ITeamExplorerService.cs b/src/GitPull.Services/ITeamExplorerService.cs new file mode 100644 index 0000000..f54873d --- /dev/null +++ b/src/GitPull.Services/ITeamExplorerService.cs @@ -0,0 +1,11 @@ +using System.Threading.Tasks; + +namespace GitPull.Services +{ + public interface ITeamExplorerService + { + Task PullAsync(string repositoryPath); + + string FindActiveRepositoryPath(); + } +} diff --git a/src/GitPull/Commands/PullCommand.cs b/src/GitPull/Commands/PullCommand.cs new file mode 100644 index 0000000..fe843c4 --- /dev/null +++ b/src/GitPull/Commands/PullCommand.cs @@ -0,0 +1,31 @@ +using System.ComponentModel.Design; +using GitPull.Services; +using Microsoft; +using Microsoft.VisualStudio.Shell; +using Task = System.Threading.Tasks.Task; + +namespace GitPull +{ + internal sealed class PullCommand + { + public static async Task InitializeAsync(AsyncPackage package) + { + await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(package.DisposalToken); + + var commandService = await package.GetServiceAsync((typeof(IMenuCommandService))) as OleMenuCommandService; + Assumes.Present(commandService); + + var service = await package.GetServiceAsync(typeof(IGitPullUIService)) as IGitPullUIService; + Assumes.Present(service); + + var cmdId = new CommandID(PackageGuids.guidGitPullPackageCmdSet, PackageIds.PullCommandId); + var cmd = new MenuCommand( + (s, e) => service.SyncAndPullAsync().FileAndForget("madskristensen/gitpull"), cmdId) + { + Supported = false + }; + + commandService.AddCommand(cmd); + } + } +} diff --git a/src/GitPull.csproj b/src/GitPull/GitPull.csproj similarity index 86% rename from src/GitPull.csproj rename to src/GitPull/GitPull.csproj index 795d802..b589f5e 100644 --- a/src/GitPull.csproj +++ b/src/GitPull/GitPull.csproj @@ -66,7 +66,7 @@ - + Resources\LICENSE true @@ -82,25 +82,16 @@ - - 8.0.2 + + 15.6.81-pre 1.0.10 - - 15.9.28307 - - - 15.8.192 - runtime; build; native; contentfiles; analyzers all - - 9.0.1 - @@ -109,7 +100,20 @@ VSCommandTable.cs - + + + {6cc39d34-677a-4474-af19-e63cb343d2ee} + GitPull.Services.15.0 + + + {5a441c17-a176-4def-a00e-dcc1662747ec} + GitPull.Services.16.0 + + + {bafff30c-fe61-4b1f-b5b6-d28520ac777d} + GitPull.Services + + true diff --git a/src/GitPullAutoloadPackage.cs b/src/GitPull/GitPullAutoloadPackage.cs similarity index 92% rename from src/GitPullAutoloadPackage.cs rename to src/GitPull/GitPullAutoloadPackage.cs index 860b662..f0b8385 100644 --- a/src/GitPullAutoloadPackage.cs +++ b/src/GitPull/GitPullAutoloadPackage.cs @@ -3,6 +3,7 @@ using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; +using GitPull.Services; using Microsoft; using Microsoft.VisualStudio; using Microsoft.VisualStudio.Shell; @@ -64,7 +65,9 @@ private async Task HandleOpenSolutionAsync(object sender = null, EventArgs e = n await JoinableTaskFactory.SwitchToMainThreadAsync(); - PullCommand.Execute(this); + var service = await GetServiceAsync(typeof(IGitPullUIService)) as IGitPullUIService; + Assumes.Present(service); + service.SyncAndPullAsync().FileAndForget("madskristensen/gitpull"); } catch (Exception ex) { diff --git a/src/GitPull/GitPullPackage.cs b/src/GitPull/GitPullPackage.cs new file mode 100644 index 0000000..19abcc1 --- /dev/null +++ b/src/GitPull/GitPullPackage.cs @@ -0,0 +1,74 @@ +using System; +using System.Runtime.InteropServices; +using System.Threading; +using System.Threading.Tasks; +using EnvDTE; +using GitPull.Services; +using Microsoft; +using Microsoft.VisualStudio.Shell; +using Microsoft.VisualStudio.Shell.Interop; +using Task = System.Threading.Tasks.Task; + +namespace GitPull +{ + [PackageRegistration(UseManagedResourcesOnly = true, AllowsBackgroundLoading = true)] + [InstalledProductRegistration(Vsix.Name, Vsix.Description, Vsix.Version)] + [Guid(PackageGuids.guidGitPullPackageString)] + [ProvideMenuResource("Menus.ctmenu", 1)] + [ProvideService(typeof(IGitPullUIService), IsAsyncQueryable = true)] + public sealed class GitPullPackage : AsyncPackage + { + protected override async Task InitializeAsync(CancellationToken cancellationToken, IProgress progress) + { + AddService(typeof(IHubService), CreateHubServiceAsync); + AddService(typeof(ITeamExplorerService), CreateTeamExplorerServiceAsync); + AddService(typeof(IGitPullUIService), CreateGitPullUIServiceAsync, true); + + await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); + await PullCommand.InitializeAsync(this); + } + + async Task CreateGitPullUIServiceAsync(IAsyncServiceContainer container, CancellationToken cancellationToken, Type serviceType) + { + await JoinableTaskFactory.SwitchToMainThreadAsync(); + + var dte = await GetServiceAsync(typeof(DTE)) as DTE; + Assumes.Present(dte); + var hubService = await GetServiceAsync(typeof(IHubService)) as IHubService; + Assumes.Present(hubService); + var teamExplorerService = await GetServiceAsync(typeof(ITeamExplorerService)) as ITeamExplorerService; + Assumes.Present(teamExplorerService); + + return new GitPullUIService(this, dte, hubService, teamExplorerService); + } + + Task CreateHubServiceAsync(IAsyncServiceContainer container, CancellationToken cancellationToken, Type serviceType) + { + var service = new HubService(); + return Task.FromResult(service); + } + + async Task CreateTeamExplorerServiceAsync(IAsyncServiceContainer container, CancellationToken cancellationToken, Type serviceType) + { + await JoinableTaskFactory.SwitchToMainThreadAsync(); + + var dte = await GetServiceAsync(typeof(DTE)) as DTE; + Assumes.Present(dte); + Lazy teamExplorerService; + switch (dte.Version) + { + case "15.0": + teamExplorerService = new Lazy(() => new TeamExplorerService15(this)); + break; + case "16.0": + teamExplorerService = new Lazy(() => new TeamExplorerService16(this)); + break; + default: + throw new NotImplementedException($"ITeamExplorerService not implemented for Visual Studio {dte.Version}"); + } + + return teamExplorerService.Value; + } + + } +} diff --git a/src/Options/BaseOptionModel.cs b/src/GitPull/Options/BaseOptionModel.cs similarity index 100% rename from src/Options/BaseOptionModel.cs rename to src/GitPull/Options/BaseOptionModel.cs diff --git a/src/Options/BaseOptionPage.cs b/src/GitPull/Options/BaseOptionPage.cs similarity index 100% rename from src/Options/BaseOptionPage.cs rename to src/GitPull/Options/BaseOptionPage.cs diff --git a/src/Options/GeneralOptions.cs b/src/GitPull/Options/GeneralOptions.cs similarity index 100% rename from src/Options/GeneralOptions.cs rename to src/GitPull/Options/GeneralOptions.cs diff --git a/src/Properties/AssemblyInfo.cs b/src/GitPull/Properties/AssemblyInfo.cs similarity index 100% rename from src/Properties/AssemblyInfo.cs rename to src/GitPull/Properties/AssemblyInfo.cs diff --git a/src/Resources/Icon.png b/src/GitPull/Resources/Icon.png similarity index 100% rename from src/Resources/Icon.png rename to src/GitPull/Resources/Icon.png diff --git a/src/VSCommandTable.cs b/src/GitPull/VSCommandTable.cs similarity index 100% rename from src/VSCommandTable.cs rename to src/GitPull/VSCommandTable.cs diff --git a/src/VSCommandTable.vsct b/src/GitPull/VSCommandTable.vsct similarity index 100% rename from src/VSCommandTable.vsct rename to src/GitPull/VSCommandTable.vsct diff --git a/src/hub.exe b/src/GitPull/hub.exe similarity index 100% rename from src/hub.exe rename to src/GitPull/hub.exe diff --git a/src/source.extension.cs b/src/GitPull/source.extension.cs similarity index 100% rename from src/source.extension.cs rename to src/GitPull/source.extension.cs diff --git a/src/source.extension.vsixmanifest b/src/GitPull/source.extension.vsixmanifest similarity index 97% rename from src/source.extension.vsixmanifest rename to src/GitPull/source.extension.vsixmanifest index 10b2740..48a67fe 100644 --- a/src/source.extension.vsixmanifest +++ b/src/GitPull/source.extension.vsixmanifest @@ -10,7 +10,7 @@ git - + diff --git a/src/GitPullPackage.cs b/src/GitPullPackage.cs deleted file mode 100644 index c01711d..0000000 --- a/src/GitPullPackage.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using System.Runtime.InteropServices; -using System.Threading; -using Microsoft.VisualStudio.Shell; -using Task = System.Threading.Tasks.Task; - -namespace GitPull -{ - [PackageRegistration(UseManagedResourcesOnly = true, AllowsBackgroundLoading = true)] - [InstalledProductRegistration(Vsix.Name, Vsix.Description, Vsix.Version)] - [Guid(PackageGuids.guidGitPullPackageString)] - [ProvideMenuResource("Menus.ctmenu", 1)] - public sealed class GitPullPackage : AsyncPackage - { - protected override async Task InitializeAsync(CancellationToken cancellationToken, IProgress progress) - { - await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); - await PullCommand.InitializeAsync(this); - } - } -}