Created
October 3, 2018 00:17
-
-
Save Cyberboss/d1928b63d20afd878ee44d881c821cfd to your computer and use it in GitHub Desktop.
A byond like interface for asyncrounously cloning or fetching a repo at a given path and checking out a given reference
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using LibGit2Sharp; | |
using System; | |
using System.Collections.Generic; | |
using System.IO; | |
using System.Linq; | |
using System.Threading; | |
using System.Threading.Tasks; | |
namespace GetRefExample | |
{ | |
sealed class GetRefExample | |
{ | |
const string Done = "DONE"; | |
const string NotDone = "NOTDONE"; | |
long jobCounter; | |
Dictionary<string, Task> jobs = new Dictionary<string, Task>(); | |
Dictionary<string, CancellationTokenSource> cancelTokens = new Dictionary<string, CancellationTokenSource>(); | |
Dictionary<string, Exception> errors = new Dictionary<string, Exception>(); | |
Task GetRefImpl(string jobName, string remoteUrl, string refName, string outputDirectory, CancellationToken cancellationToken) => Task.Factory.StartNew(() => | |
{ | |
Repository repo = null; | |
try | |
{ | |
string remoteName; | |
if (!Repository.IsValid(outputDirectory)) | |
{ | |
cancellationToken.ThrowIfCancellationRequested(); | |
Directory.Delete(outputDirectory, recursive: true); | |
cancellationToken.ThrowIfCancellationRequested(); | |
Repository.Clone(remoteUrl, outputDirectory); | |
cancellationToken.ThrowIfCancellationRequested(); | |
repo = new Repository(outputDirectory); | |
remoteName = "origin"; | |
} | |
else | |
{ | |
repo = new Repository(outputDirectory); | |
cancellationToken.ThrowIfCancellationRequested(); | |
repo.RemoveUntrackedFiles(); | |
cancellationToken.ThrowIfCancellationRequested(); | |
var remoteToUse = repo.Network.Remotes.First(); | |
remoteName = remoteToUse.Name; | |
cancellationToken.ThrowIfCancellationRequested(); | |
Commands.Fetch(repo, remoteName, remoteToUse.FetchRefSpecs.Select(x => x.Specification), new FetchOptions(), "Fetch"); | |
} | |
cancellationToken.ThrowIfCancellationRequested(); | |
Commands.Checkout(repo, remoteName + '/' + refName, new CheckoutOptions | |
{ | |
CheckoutModifiers = CheckoutModifiers.Force | |
}); | |
} | |
catch (OperationCanceledException) { } | |
catch (Exception e) | |
{ | |
lock (errors) | |
errors.Add(jobName, e); | |
} | |
finally | |
{ | |
repo?.Dispose(); | |
} | |
}, cancellationToken, TaskCreationOptions.LongRunning, TaskScheduler.Current); | |
public string Init() | |
{ | |
foreach (var I in cancelTokens) | |
{ | |
var cts = I.Value; | |
cts.Cancel(); | |
cts.Dispose(); | |
} | |
cancelTokens.Clear(); | |
foreach (var I in jobs) | |
I.Value.Wait(); | |
jobs.Clear(); | |
errors.Clear(); | |
return null; | |
} | |
public string CancelGetRef(string jobName) | |
{ | |
if (!cancelTokens.TryGetValue(jobName, out var cts)) | |
return null; | |
cancelTokens.Remove(jobName); | |
cts.Cancel(); | |
return Done; | |
} | |
public string GetRefFinished(string jobName) | |
{ | |
if (!jobs.TryGetValue(jobName, out var job)) | |
return null; | |
if (!job.IsCompleted) | |
return NotDone; | |
jobs.Remove(jobName); | |
var cts = cancelTokens[jobName]; | |
cancelTokens.Remove(jobName); | |
cts.Dispose(); | |
lock (errors) | |
if (errors.TryGetValue(jobName, out var exception)) | |
{ | |
errors.Remove(jobName); | |
return exception.Message; | |
} | |
return Done; | |
} | |
public string BeginGetRef(string remoteUrl, string refName, string outputDirectory) | |
{ | |
var jobName = (++jobCounter).ToString(); | |
var cts = new CancellationTokenSource(); | |
lock (cancelTokens) | |
cancelTokens.Add(jobName, cts); | |
lock(jobs) | |
jobs.Add(jobName, GetRefImpl(jobName, remoteUrl, refName, outputDirectory, cts.Token)); | |
return jobName; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment