diff --git a/src/GitHub.App/Services/RepositoryCloneService.cs b/src/GitHub.App/Services/RepositoryCloneService.cs index 8e9f62f9bb..f1df35a486 100644 --- a/src/GitHub.App/Services/RepositoryCloneService.cs +++ b/src/GitHub.App/Services/RepositoryCloneService.cs @@ -114,7 +114,8 @@ public async Task ReadViewerRepositories(HostAddress ad /// public async Task CloneOrOpenRepository( CloneDialogResult cloneDialogResult, - object progress = null) + object progress = null, + CancellationToken? cancellationToken = null) { Guard.ArgumentNotNull(cloneDialogResult, nameof(cloneDialogResult)); @@ -147,7 +148,7 @@ public async Task CloneOrOpenRepository( else { var cloneUrl = repositoryUrl.ToString(); - await CloneRepository(cloneUrl, repositoryPath, progress).ConfigureAwait(true); + await CloneRepository(cloneUrl, repositoryPath, progress, cancellationToken).ConfigureAwait(true); if (isDotCom) { @@ -197,7 +198,8 @@ bool IsSolutionInRepository(string repositoryPath) public async Task CloneRepository( string cloneUrl, string repositoryPath, - object progress = null) + object progress = null, + CancellationToken? cancellationToken = null) { Guard.ArgumentNotEmptyString(cloneUrl, nameof(cloneUrl)); Guard.ArgumentNotEmptyString(repositoryPath, nameof(repositoryPath)); @@ -210,7 +212,7 @@ public async Task CloneRepository( try { - await vsGitServices.Clone(cloneUrl, repositoryPath, true, progress); + await vsGitServices.Clone(cloneUrl, repositoryPath, true, progress, cancellationToken); await usageTracker.IncrementCounter(x => x.NumberOfClones); if (repositoryPath.StartsWith(DefaultClonePath, StringComparison.OrdinalIgnoreCase)) diff --git a/src/GitHub.Exports.Reactive/Services/IRepositoryCloneService.cs b/src/GitHub.Exports.Reactive/Services/IRepositoryCloneService.cs index a4810bf742..365902c98a 100644 --- a/src/GitHub.Exports.Reactive/Services/IRepositoryCloneService.cs +++ b/src/GitHub.Exports.Reactive/Services/IRepositoryCloneService.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Threading; using System.Threading.Tasks; using GitHub.Models; using GitHub.Primitives; @@ -27,11 +26,13 @@ public interface IRepositoryCloneService /// System.IProgress<Microsoft.VisualStudio.Shell.ServiceProgressData>, but /// as that type is only available in VS2017+ it is typed as here. /// + /// A cancellation token. /// Task CloneRepository( string cloneUrl, string repositoryPath, - object progress = null); + object progress = null, + CancellationToken? cancellationToken = null); /// /// Clones the specified repository into the specified directory or opens it if the directory already exists. @@ -45,7 +46,8 @@ Task CloneRepository( /// Task CloneOrOpenRepository( CloneDialogResult cloneDialogResult, - object progress = null); + object progress = null, + CancellationToken? cancellationToken = null); /// /// Checks whether the specified destination directory already exists. diff --git a/src/GitHub.Exports/Services/IVSGitServices.cs b/src/GitHub.Exports/Services/IVSGitServices.cs index 8343ac92b2..a2b0b5fd10 100644 --- a/src/GitHub.Exports/Services/IVSGitServices.cs +++ b/src/GitHub.Exports/Services/IVSGitServices.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Threading; using System.Threading.Tasks; using GitHub.Models; @@ -20,13 +21,15 @@ public interface IVSGitServices /// System.IProgress<Microsoft.VisualStudio.Shell.ServiceProgressData>, but /// as that type is only available in VS2017+ it is typed as here. /// + /// A cancellation token. /// /// Task Clone( string cloneUrl, string clonePath, bool recurseSubmodules, - object progress = null); + object progress = null, + CancellationToken? cancellationToken = null); string GetActiveRepoPath(); LibGit2Sharp.IRepository GetActiveRepo(); diff --git a/src/GitHub.StartPage/StartPagePackage.cs b/src/GitHub.StartPage/StartPagePackage.cs index bfc7ee04a4..935075e9d4 100644 --- a/src/GitHub.StartPage/StartPagePackage.cs +++ b/src/GitHub.StartPage/StartPagePackage.cs @@ -57,7 +57,7 @@ async Task RunAcquisition(IProgress download try { var uiProvider = await Task.Run(() => Package.GetGlobalService(typeof(IGitHubServiceProvider)) as IGitHubServiceProvider); - request = await ShowCloneDialog(uiProvider, downloadProgress, repository); + request = await ShowCloneDialog(uiProvider, downloadProgress, cancellationToken, repository); } catch (Exception e) { @@ -81,9 +81,10 @@ async Task RunAcquisition(IProgress download lastAccessed: DateTimeOffset.UtcNow); } - async Task ShowCloneDialog( + static async Task ShowCloneDialog( IGitHubServiceProvider gitHubServiceProvider, IProgress progress, + CancellationToken cancellationToken, RepositoryModel repository = null) { var dialogService = gitHubServiceProvider.GetService(); @@ -110,7 +111,7 @@ async Task ShowCloneDialog( { try { - await cloneService.CloneOrOpenRepository(result, progress); + await cloneService.CloneOrOpenRepository(result, progress, cancellationToken); usageTracker.IncrementCounter(x => x.NumberOfStartPageClones).Forget(); } catch diff --git a/src/GitHub.TeamFoundation.14/Services/VSGitServices.cs b/src/GitHub.TeamFoundation.14/Services/VSGitServices.cs index d17a2f95b0..f27e693e34 100644 --- a/src/GitHub.TeamFoundation.14/Services/VSGitServices.cs +++ b/src/GitHub.TeamFoundation.14/Services/VSGitServices.cs @@ -1,4 +1,5 @@ using System; +using System.Threading; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.ComponentModel.Composition; @@ -74,7 +75,8 @@ public async Task Clone( string cloneUrl, string clonePath, bool recurseSubmodules, - object progress = null) + object progress = null, + CancellationToken? cancellationToken = null) { var teamExplorer = serviceProvider.TryGetService(); Assumes.Present(teamExplorer); @@ -84,13 +86,13 @@ public async Task Clone( NavigateToHomePage(teamExplorer); // Show progress on Team Explorer - Home await WaitForCloneOnHomePageAsync(teamExplorer); #elif TEAMEXPLORER15 || TEAMEXPLORER16 - // The ServiceProgressData type is in a Visual Studio 2019 assembly that we don't currently have access to. - // Using reflection to call the CloneAsync in order to avoid conflicts with the Visual Studio 2017 version. - // Progress won't be displayed on the status bar, but it appears prominently on the Team Explorer Home view. + // The progress parameter uses the ServiceProgressData type which is defined in + // Microsoft.VisualStudio.Shell.Framework. Referencing this assembly directly + // would cause type conflicts, so we're using reflection to call CloneAsync. var gitExt = serviceProvider.GetService(); var cloneAsyncMethod = typeof(IGitActionsExt).GetMethod(nameof(IGitActionsExt.CloneAsync)); Assumes.NotNull(cloneAsyncMethod); - var cloneParameters = new object[] { cloneUrl, clonePath, recurseSubmodules, null, null }; + var cloneParameters = new object[] { cloneUrl, clonePath, recurseSubmodules, cancellationToken, progress }; var cloneTask = (Task)cloneAsyncMethod.Invoke(gitExt, cloneParameters); NavigateToHomePage(teamExplorer); // Show progress on Team Explorer - Home