diff --git a/src/Files.App/Services/Git/LibGit2Service.cs b/src/Files.App/Services/Git/LibGit2Service.cs index 625812bb877f..4acdbca06472 100644 --- a/src/Files.App/Services/Git/LibGit2Service.cs +++ b/src/Files.App/Services/Git/LibGit2Service.cs @@ -1,6 +1,7 @@ using LibGit2Sharp; using Microsoft.Extensions.Logging; using Sentry; +using System.Security.Cryptography.Xml; using System.Text; using System.Text.RegularExpressions; @@ -401,6 +402,75 @@ await DoGitOperationAsync(() => }); } + public async Task CloneRepoAsync(string repoUrl, string repoName, string targetDirectory) + { + var banner = StatusCenterHelper.AddCard_GitClone(repoName.CreateEnumerable(), targetDirectory.CreateEnumerable(), ReturnResult.InProgress); + var fsProgress = new StatusCenterItemProgressModel(banner.ProgressEventSource, enumerationCompleted: true, FileSystemStatusCode.InProgress); + var errorMessage = string.Empty; + + bool isSuccess = await Task.Run(() => + { + try + { + var cloneOptions = new CloneOptions + { + FetchOptions = + { + OnTransferProgress = progress => + { + banner.CancellationToken.ThrowIfCancellationRequested(); + fsProgress.ItemsCount = progress.TotalObjects; + fsProgress.SetProcessedSize(progress.ReceivedBytes); + fsProgress.AddProcessedItemsCount(1); + fsProgress.Report((int)((progress.ReceivedObjects / (double)progress.TotalObjects) * 100)); + return true; + }, + OnProgress = _ => !banner.CancellationToken.IsCancellationRequested, + }, + OnCheckoutProgress = (path, completed, total) => + banner.CancellationToken.ThrowIfCancellationRequested() + }; + + var token = CredentialsHelpers.GetPassword(GIT_RESOURCE_NAME, GIT_RESOURCE_USERNAME); + var signature = Configuration.BuildFrom(null, null).BuildSignature(DateTimeOffset.Now); + + if (signature is not null && !string.IsNullOrWhiteSpace(token)) + { + cloneOptions.FetchOptions.CredentialsProvider = (url, user, cred) + => new UsernamePasswordCredentials + { + Username = signature.Name, + Password = token + }; + } + + Repository.Clone(repoUrl, targetDirectory, cloneOptions); + return true; + } + catch (Exception ex) + { + errorMessage = ex.Message; + return false; + } + }, banner.CancellationToken); + + if (!string.IsNullOrEmpty(errorMessage)) + { + UIHelpers.CloseAllDialogs(); + await Task.Delay(500); + await DynamicDialogFactory.ShowFor_CannotCloneRepo(errorMessage); + } + + StatusCenterViewModel.RemoveItem(banner); + + StatusCenterHelper.AddCard_GitClone( + repoName.CreateEnumerable(), + targetDirectory.CreateEnumerable(), + isSuccess ? ReturnResult.Success : + banner.CancellationToken.IsCancellationRequested ? ReturnResult.Cancelled : + ReturnResult.Failed); + } + private static bool IsRepoValid(string path) { return SafetyExtensions.IgnoreExceptions(() => Repository.IsValid(path)); diff --git a/src/Files.App/Utils/Git/GitHelpers.cs b/src/Files.App/Utils/Git/GitHelpers.cs index db27fac7cd58..0ce9c5502ad7 100644 --- a/src/Files.App/Utils/Git/GitHelpers.cs +++ b/src/Files.App/Utils/Git/GitHelpers.cs @@ -45,6 +45,9 @@ internal static partial class GitHelpers /// public static async void FetchOrigin(string? repositoryPath, CancellationToken cancellationToken = default) => _implementation.FetchOrigin(repositoryPath, cancellationToken); + /// + public static Task CloneRepoAsync(string repoUrl, string repoName, string targetDirectory) => _implementation.CloneRepoAsync(repoUrl, repoName, targetDirectory); + /// public static bool IsExecutingGitAction => _implementation.IsExecutingGitAction; @@ -600,62 +603,6 @@ public static bool IsValidRepoUrl(string url) return GitHubRepositoryRegex().IsMatch(url); } - public static async Task CloneRepoAsync(string repoUrl, string repoName, string targetDirectory) - { - var banner = StatusCenterHelper.AddCard_GitClone(repoName.CreateEnumerable(), targetDirectory.CreateEnumerable(), ReturnResult.InProgress); - var fsProgress = new StatusCenterItemProgressModel(banner.ProgressEventSource, enumerationCompleted: true, FileSystemStatusCode.InProgress); - var errorMessage = string.Empty; - - bool isSuccess = await Task.Run(() => - { - try - { - var cloneOptions = new CloneOptions - { - FetchOptions = - { - OnTransferProgress = progress => - { - banner.CancellationToken.ThrowIfCancellationRequested(); - fsProgress.ItemsCount = progress.TotalObjects; - fsProgress.SetProcessedSize(progress.ReceivedBytes); - fsProgress.AddProcessedItemsCount(1); - fsProgress.Report((int)((progress.ReceivedObjects / (double)progress.TotalObjects) * 100)); - return true; - }, - OnProgress = _ => !banner.CancellationToken.IsCancellationRequested - }, - OnCheckoutProgress = (path, completed, total) => - banner.CancellationToken.ThrowIfCancellationRequested() - }; - - Repository.Clone(repoUrl, targetDirectory, cloneOptions); - return true; - } - catch (Exception ex) - { - errorMessage = ex.Message; - return false; - } - }, banner.CancellationToken); - - if (!string.IsNullOrEmpty(errorMessage)) - { - UIHelpers.CloseAllDialogs(); - await Task.Delay(500); - await DynamicDialogFactory.ShowFor_CannotCloneRepo(errorMessage); - } - - StatusCenterViewModel.RemoveItem(banner); - - StatusCenterHelper.AddCard_GitClone( - repoName.CreateEnumerable(), - targetDirectory.CreateEnumerable(), - isSuccess ? ReturnResult.Success : - banner.CancellationToken.IsCancellationRequested ? ReturnResult.Cancelled : - ReturnResult.Failed); - } - // Method already moved into abstraction [GeneratedRegex(@"^(?:https?:\/\/)?(?:www\.)?(?github|gitlab)\.com\/(?[^\/]+)\/(?[^\/]+?)(?=\.git|\/|$)(?:\.git)?(?:\/)?", RegexOptions.IgnoreCase)] private static partial Regex GitHubRepositoryRegex();