Skip to content

Instantly share code, notes, and snippets.

@Cyberboss
Created October 3, 2018 00:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Cyberboss/d1928b63d20afd878ee44d881c821cfd to your computer and use it in GitHub Desktop.
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
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