Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 70 additions & 0 deletions src/Files.App/Services/Git/LibGit2Service.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using LibGit2Sharp;
using Microsoft.Extensions.Logging;
using Sentry;
using System.Security.Cryptography.Xml;
using System.Text;
using System.Text.RegularExpressions;

Expand Down Expand Up @@ -401,6 +402,75 @@ await DoGitOperationAsync<GitOperationResult>(() =>
});
}

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));
Expand Down
59 changes: 3 additions & 56 deletions src/Files.App/Utils/Git/GitHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ internal static partial class GitHelpers
/// <inheritdoc cref="IVersionControlService.FetchOrigin(string?, CancellationToken)"/>
public static async void FetchOrigin(string? repositoryPath, CancellationToken cancellationToken = default) => _implementation.FetchOrigin(repositoryPath, cancellationToken);

/// <inheritdoc cref="IVersionControlService.CloneRepoAsync(string, string, string)"/>
public static Task CloneRepoAsync(string repoUrl, string repoName, string targetDirectory) => _implementation.CloneRepoAsync(repoUrl, repoName, targetDirectory);

/// <inheritdoc cref="IVersionControlService.IsExecutingGitAction"/>
public static bool IsExecutingGitAction => _implementation.IsExecutingGitAction;

Expand Down Expand Up @@ -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\.)?(?<domain>github|gitlab)\.com\/(?<user>[^\/]+)\/(?<repo>[^\/]+?)(?=\.git|\/|$)(?:\.git)?(?:\/)?", RegexOptions.IgnoreCase)]
private static partial Regex GitHubRepositoryRegex();
Expand Down
Loading