mirror of
https://github.com/tgstation/tgstation-server.git
synced 2026-08-27 15:07:03 +01:00
Merge pull request #1317 from tgstation/CompileProcess
Support for describing a job's current stage
This commit is contained in:
+3
-3
@@ -5,9 +5,9 @@
|
||||
<PropertyGroup>
|
||||
<TgsCoreVersion>4.15.0</TgsCoreVersion>
|
||||
<TgsConfigVersion>4.0.0</TgsConfigVersion>
|
||||
<TgsApiVersion>9.2.0</TgsApiVersion>
|
||||
<TgsApiLibraryVersion>9.2.0</TgsApiLibraryVersion>
|
||||
<TgsClientVersion>10.2.0</TgsClientVersion>
|
||||
<TgsApiVersion>9.3.0</TgsApiVersion>
|
||||
<TgsApiLibraryVersion>9.3.0</TgsApiLibraryVersion>
|
||||
<TgsClientVersion>10.3.0</TgsClientVersion>
|
||||
<TgsDmapiVersion>6.0.4</TgsDmapiVersion>
|
||||
<TgsInteropVersion>5.3.0</TgsInteropVersion>
|
||||
<TgsHostWatchdogVersion>1.1.1</TgsHostWatchdogVersion>
|
||||
|
||||
@@ -21,5 +21,11 @@
|
||||
/// </summary>
|
||||
[ResponseOptions]
|
||||
public int? Progress { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Optional description of the job's current .
|
||||
/// </summary>
|
||||
[ResponseOptions]
|
||||
public string? Stage { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,6 +113,11 @@ namespace Tgstation.Server.Host.Components.Deployment
|
||||
/// </summary>
|
||||
string currentDreamMakerOutput;
|
||||
|
||||
/// <summary>
|
||||
/// Current stage to report on the job.
|
||||
/// </summary>
|
||||
string currentStage;
|
||||
|
||||
/// <summary>
|
||||
/// If a compile job is running.
|
||||
/// </summary>
|
||||
@@ -178,7 +183,7 @@ namespace Tgstation.Server.Host.Components.Deployment
|
||||
public async Task DeploymentProcess(
|
||||
Models.Job job,
|
||||
IDatabaseContextFactory databaseContextFactory,
|
||||
Action<int> progressReporter,
|
||||
JobProgressReporter progressReporter,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
if (job == null)
|
||||
@@ -450,7 +455,7 @@ namespace Tgstation.Server.Host.Components.Deployment
|
||||
/// <param name="apiValidateTimeout">The API validation timeout.</param>
|
||||
/// <param name="repository">The <see cref="IRepository"/>.</param>
|
||||
/// <param name="remoteDeploymentManager">The <see cref="IRemoteDeploymentManager"/>.</param>
|
||||
/// <param name="progressReporter">The progress reporting <see cref="Action{T}"/>.</param>
|
||||
/// <param name="progressReporter">The <see cref="JobProgressReporter"/> to report progress of the operation.</param>
|
||||
/// <param name="estimatedDuration">The optional estimated <see cref="TimeSpan"/> of the compilation.</param>
|
||||
/// <param name="localCommitExistsOnRemote">Whether or not the <paramref name="repository"/>'s current commit exists on the remote repository.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
|
||||
@@ -461,7 +466,7 @@ namespace Tgstation.Server.Host.Components.Deployment
|
||||
uint apiValidateTimeout,
|
||||
IRepository repository,
|
||||
IRemoteDeploymentManager remoteDeploymentManager,
|
||||
Action<int> progressReporter,
|
||||
JobProgressReporter progressReporter,
|
||||
TimeSpan? estimatedDuration,
|
||||
bool localCommitExistsOnRemote,
|
||||
CancellationToken cancellationToken)
|
||||
@@ -469,7 +474,9 @@ namespace Tgstation.Server.Host.Components.Deployment
|
||||
logger.LogTrace("Begin Compile");
|
||||
|
||||
using var progressCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
|
||||
var progressTask = estimatedDuration.HasValue ? ProgressTask(progressReporter, estimatedDuration.Value, progressCts.Token) : Task.CompletedTask;
|
||||
|
||||
currentStage = "Reserving BYOND version";
|
||||
var progressTask = ProgressTask(progressReporter, estimatedDuration, progressCts.Token);
|
||||
try
|
||||
{
|
||||
using var byondLock = await byond.UseExecutables(null, cancellationToken).ConfigureAwait(false);
|
||||
@@ -490,6 +497,7 @@ namespace Tgstation.Server.Host.Components.Deployment
|
||||
RepositoryOrigin = repository.Origin.ToString(),
|
||||
};
|
||||
|
||||
currentStage = "Creating remote deployment notification";
|
||||
await remoteDeploymentManager.StartDeployment(
|
||||
repository,
|
||||
job,
|
||||
@@ -525,6 +533,7 @@ namespace Tgstation.Server.Host.Components.Deployment
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
// DCT: Cancellation token is for job, delaying here is fine
|
||||
currentStage = "Running CompileCancelled event";
|
||||
await eventConsumer.HandleEvent(EventType.CompileCancelled, Enumerable.Empty<string>(), default).ConfigureAwait(false);
|
||||
throw;
|
||||
}
|
||||
@@ -561,7 +570,8 @@ namespace Tgstation.Server.Host.Components.Deployment
|
||||
try
|
||||
{
|
||||
// copy the repository
|
||||
logger.LogTrace("Copying repository to game directory...");
|
||||
logger.LogTrace("Copying repository to game directory");
|
||||
currentStage = "Copying repository";
|
||||
var resolvedOutputDirectory = ioManager.ResolvePath(outputDirectory);
|
||||
var repoOrigin = repository.Origin;
|
||||
using (repository)
|
||||
@@ -570,6 +580,7 @@ namespace Tgstation.Server.Host.Components.Deployment
|
||||
// repository closed now
|
||||
|
||||
// run precompile scripts
|
||||
currentStage = "Running PreCompile event";
|
||||
await eventConsumer.HandleEvent(
|
||||
EventType.CompileStart,
|
||||
new List<string>
|
||||
@@ -582,9 +593,10 @@ namespace Tgstation.Server.Host.Components.Deployment
|
||||
.ConfigureAwait(false);
|
||||
|
||||
// determine the dme
|
||||
currentStage = "Determining .dme";
|
||||
if (job.DmeName == null)
|
||||
{
|
||||
logger.LogTrace("Searching for available .dmes...");
|
||||
logger.LogTrace("Searching for available .dmes");
|
||||
var foundPaths = await ioManager.GetFilesWithExtension(resolvedOutputDirectory, DmeExtension, true, cancellationToken).ConfigureAwait(false);
|
||||
var foundPath = foundPaths.FirstOrDefault();
|
||||
if (foundPath == default)
|
||||
@@ -603,9 +615,11 @@ namespace Tgstation.Server.Host.Components.Deployment
|
||||
|
||||
logger.LogDebug("Selected {0}.dme for compilation!", job.DmeName);
|
||||
|
||||
currentStage = "Modifying .dme";
|
||||
await ModifyDme(job, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
// run precompile scripts
|
||||
currentStage = "Running PreDreamMaker event";
|
||||
await eventConsumer.HandleEvent(
|
||||
EventType.PreDreamMaker,
|
||||
new List<string>
|
||||
@@ -618,6 +632,7 @@ namespace Tgstation.Server.Host.Components.Deployment
|
||||
.ConfigureAwait(false);
|
||||
|
||||
// run compiler
|
||||
currentStage = "Running DreamMaker";
|
||||
var exitCode = await RunDreamMaker(byondLock.DreamMakerPath, job, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
// verify api
|
||||
@@ -628,6 +643,7 @@ namespace Tgstation.Server.Host.Components.Deployment
|
||||
ErrorCode.DreamMakerExitCode,
|
||||
new JobException($"Exit code: {exitCode}{Environment.NewLine}{Environment.NewLine}{job.Output}"));
|
||||
|
||||
currentStage = "Validating DMAPI";
|
||||
await VerifyApi(
|
||||
apiValidateTimeout,
|
||||
dreamMakerSettings.ApiValidationSecurityLevel.Value,
|
||||
@@ -641,6 +657,7 @@ namespace Tgstation.Server.Host.Components.Deployment
|
||||
catch (JobException)
|
||||
{
|
||||
// DD never validated or compile failed
|
||||
currentStage = "Running CompileFailure event";
|
||||
await eventConsumer.HandleEvent(
|
||||
EventType.CompileFailure,
|
||||
new List<string>
|
||||
@@ -654,6 +671,7 @@ namespace Tgstation.Server.Host.Components.Deployment
|
||||
throw;
|
||||
}
|
||||
|
||||
currentStage = "Running CompileComplete event";
|
||||
await eventConsumer.HandleEvent(
|
||||
EventType.CompileComplete,
|
||||
new List<string>
|
||||
@@ -665,6 +683,7 @@ namespace Tgstation.Server.Host.Components.Deployment
|
||||
.ConfigureAwait(false);
|
||||
|
||||
logger.LogTrace("Applying static game file symlinks...");
|
||||
currentStage = "Symlinking GameStaticFiles";
|
||||
|
||||
// symlink in the static data
|
||||
await configuration.SymlinkStaticFilesTo(resolvedOutputDirectory, cancellationToken).ConfigureAwait(false);
|
||||
@@ -673,6 +692,7 @@ namespace Tgstation.Server.Host.Components.Deployment
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
currentStage = "Cleaning output directory";
|
||||
await CleanupFailedCompile(job, remoteDeploymentManager, ex).ConfigureAwait(false);
|
||||
throw;
|
||||
}
|
||||
@@ -681,22 +701,22 @@ namespace Tgstation.Server.Host.Components.Deployment
|
||||
/// <summary>
|
||||
/// Gradually triggers a given <paramref name="progressReporter"/> over a given <paramref name="estimatedDuration"/>.
|
||||
/// </summary>
|
||||
/// <param name="progressReporter">The <see cref="Action{T1}"/> to report progress.</param>
|
||||
/// <param name="estimatedDuration">A <see cref="TimeSpan"/> representing the duration to give progress over.</param>
|
||||
/// <param name="progressReporter">The <see cref="JobProgressReporter"/> to report progress of the operation.</param>
|
||||
/// <param name="estimatedDuration">A <see cref="TimeSpan"/> representing the duration to give progress over if any.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
|
||||
/// <returns>A <see cref="Task"/> representing the running operation.</returns>
|
||||
async Task ProgressTask(Action<int> progressReporter, TimeSpan estimatedDuration, CancellationToken cancellationToken)
|
||||
async Task ProgressTask(JobProgressReporter progressReporter, TimeSpan? estimatedDuration, CancellationToken cancellationToken)
|
||||
{
|
||||
progressReporter(0);
|
||||
var sleepInterval = estimatedDuration / 100;
|
||||
progressReporter(currentStage, estimatedDuration.HasValue ? (int?)0 : null);
|
||||
var sleepInterval = estimatedDuration.HasValue ? estimatedDuration.Value / 100 : TimeSpan.FromMilliseconds(250);
|
||||
|
||||
logger.LogDebug("Compile is expected to take: {0}", estimatedDuration);
|
||||
try
|
||||
{
|
||||
for (var iteration = 0; iteration < 99; ++iteration)
|
||||
for (var iteration = 0; iteration < (estimatedDuration.HasValue ? 99 : Int32.MaxValue); ++iteration)
|
||||
{
|
||||
await Task.Delay(sleepInterval, cancellationToken).ConfigureAwait(false);
|
||||
progressReporter(iteration + 1);
|
||||
progressReporter(currentStage, estimatedDuration.HasValue ? (int?)(iteration + 1) : null);
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Tgstation.Server.Host.Database;
|
||||
using Tgstation.Server.Host.Jobs;
|
||||
using Tgstation.Server.Host.Models;
|
||||
|
||||
namespace Tgstation.Server.Host.Components.Deployment
|
||||
@@ -13,17 +13,17 @@ namespace Tgstation.Server.Host.Components.Deployment
|
||||
public interface IDreamMaker
|
||||
{
|
||||
/// <summary>
|
||||
/// Create and a compile job and insert it into the database. Meant to be called by a <see cref="Jobs.IJobManager"/>.
|
||||
/// Create and a compile job and insert it into the database. Meant to be called by a <see cref="IJobManager"/>.
|
||||
/// </summary>
|
||||
/// <param name="job">The running <see cref="Job"/>.</param>
|
||||
/// <param name="databaseContextFactory">The <see cref="IDatabaseContextFactory"/> for the operation.</param>
|
||||
/// <param name="progressReporter">The <see cref="Action{T1}"/> to report compilation progress.</param>
|
||||
/// <param name="progressReporter">The <see cref="JobProgressReporter"/> to report compilation progress.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
|
||||
/// <returns>A <see cref="Task"/> representing the running operation.</returns>
|
||||
Task DeploymentProcess(
|
||||
Job job,
|
||||
IDatabaseContextFactory databaseContextFactory,
|
||||
Action<int> progressReporter,
|
||||
JobProgressReporter progressReporter,
|
||||
CancellationToken cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -256,7 +256,7 @@ namespace Tgstation.Server.Host.Components
|
||||
IInstanceCore core,
|
||||
IDatabaseContextFactory databaseContextFactory,
|
||||
Job job,
|
||||
Action<int> progressReporter,
|
||||
JobProgressReporter progressReporter,
|
||||
CancellationToken cancellationToken)
|
||||
=> databaseContextFactory.UseContext(
|
||||
async databaseContext =>
|
||||
@@ -277,11 +277,11 @@ namespace Tgstation.Server.Host.Components
|
||||
const int NumSteps = 3;
|
||||
var doneSteps = 0;
|
||||
|
||||
Action<int> NextProgressReporter()
|
||||
JobProgressReporter NextProgressReporter()
|
||||
{
|
||||
var tmpDoneSteps = doneSteps;
|
||||
++doneSteps;
|
||||
return progress => progressReporter((progress + (100 * tmpDoneSteps)) / NumSteps);
|
||||
return (status, progress) => progressReporter(status, (progress + (100 * tmpDoneSteps)) / NumSteps);
|
||||
}
|
||||
|
||||
using var repo = await RepositoryManager.LoadRepository(cancellationToken).ConfigureAwait(false);
|
||||
@@ -466,7 +466,7 @@ namespace Tgstation.Server.Host.Components
|
||||
throw;
|
||||
}
|
||||
|
||||
progressReporter(5 * ProgressStep);
|
||||
progressReporter(null, 5 * ProgressStep);
|
||||
});
|
||||
#pragma warning restore CA1502 // Cyclomatic complexity
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Tgstation.Server.Api.Models;
|
||||
using Tgstation.Server.Host.Jobs;
|
||||
|
||||
namespace Tgstation.Server.Host.Components.Repository
|
||||
{
|
||||
@@ -46,7 +47,7 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
/// <param name="username">The username used for fetching from submodule repositories.</param>
|
||||
/// <param name="password">The password used for fetching from submodule repositories.</param>
|
||||
/// <param name="updateSubmodules">If a submodule update should be attempted after the merge.</param>
|
||||
/// <param name="progressReporter"><see cref="Action{T1}"/> to report 0-100 <see cref="int"/> progress of the operation.</param>
|
||||
/// <param name="progressReporter">The <see cref="JobProgressReporter"/> to report progress of the operation.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
|
||||
/// <returns>A <see cref="Task"/> representing the running operation.</returns>
|
||||
Task CheckoutObject(
|
||||
@@ -54,7 +55,7 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
string username,
|
||||
string password,
|
||||
bool updateSubmodules,
|
||||
Action<int> progressReporter,
|
||||
JobProgressReporter progressReporter,
|
||||
CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
@@ -66,7 +67,7 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
/// <param name="username">The username used to fetch from the origin and submodule repositories.</param>
|
||||
/// <param name="password">The password used to fetch from the origin and submodule repositories.</param>
|
||||
/// <param name="updateSubmodules">If a submodule update should be attempted after the merge.</param>
|
||||
/// <param name="progressReporter"><see cref="Action{T1}"/> to report 0-100 <see cref="int"/> progress of the operation.</param>
|
||||
/// <param name="progressReporter">The <see cref="JobProgressReporter"/> to report progress of the operation.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
|
||||
/// <returns>A <see cref="Task{TResult}"/> resulting in a <see cref="Nullable{T}"/> <see cref="bool"/> representing the merge result that is <see langword="true"/> after a fast forward or up to date, <see langword="false"/> on a non-fast-forward, <see langword="null"/> on a conflict.</returns>
|
||||
Task<bool?> AddTestMerge(
|
||||
@@ -76,7 +77,7 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
string username,
|
||||
string password,
|
||||
bool updateSubmodules,
|
||||
Action<int> progressReporter,
|
||||
JobProgressReporter progressReporter,
|
||||
CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
@@ -84,10 +85,14 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
/// </summary>
|
||||
/// <param name="username">The username to fetch from the origin repository.</param>
|
||||
/// <param name="password">The password to fetch from the origin repository.</param>
|
||||
/// <param name="progressReporter"><see cref="Action{T1}"/> to report 0-100 <see cref="int"/> progress of the operation.</param>
|
||||
/// <param name="progressReporter">The <see cref="JobProgressReporter"/> to report progress of the operation.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
|
||||
/// <returns>A <see cref="Task"/> representing the running operation.</returns>
|
||||
Task FetchOrigin(string username, string password, Action<int> progressReporter, CancellationToken cancellationToken);
|
||||
Task FetchOrigin(
|
||||
string username,
|
||||
string password,
|
||||
JobProgressReporter progressReporter,
|
||||
CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Requires the current HEAD to be a tracked reference. Hard resets the reference to what it tracks on the origin repository.
|
||||
@@ -95,34 +100,34 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
/// <param name="username">The username used for fetching from submodule repositories.</param>
|
||||
/// <param name="password">The password used for fetching from submodule repositories.</param>
|
||||
/// <param name="updateSubmodules">If a submodule update should be attempted after the merge.</param>
|
||||
/// <param name="progressReporter"><see cref="Action{T1}"/> to report 0-100 <see cref="int"/> progress of the operation.</param>
|
||||
/// <param name="progressReporter">The <see cref="JobProgressReporter"/> to report progress of the operation.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
|
||||
/// <returns>A <see cref="Task{TResult}"/> resulting in the SHA of the new HEAD.</returns>
|
||||
Task ResetToOrigin(
|
||||
string username,
|
||||
string password,
|
||||
bool updateSubmodules,
|
||||
Action<int> progressReporter,
|
||||
JobProgressReporter progressReporter,
|
||||
CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Requires the current HEAD to be a reference. Hard resets the reference to the given sha.
|
||||
/// </summary>
|
||||
/// <param name="sha">The sha hash to reset to.</param>
|
||||
/// <param name="progressReporter"><see cref="Action{T1}"/> to report 0-100 <see cref="int"/> progress of the operation.</param>
|
||||
/// <param name="progressReporter">The <see cref="JobProgressReporter"/> to report progress of the operation.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
|
||||
/// <returns>A <see cref="Task{TResult}"/> resulting in the SHA of the new HEAD.</returns>
|
||||
Task ResetToSha(string sha, Action<int> progressReporter, CancellationToken cancellationToken);
|
||||
Task ResetToSha(string sha, JobProgressReporter progressReporter, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Requires the current HEAD to be a tracked reference. Merges the reference to what it tracks on the origin repository.
|
||||
/// </summary>
|
||||
/// <param name="committerName">The name of the merge committer.</param>
|
||||
/// <param name="committerEmail">The e-mail of the merge committer.</param>
|
||||
/// <param name="progressReporter"><see cref="Action{T1}"/> to report 0-100 <see cref="int"/> progress of the operation.</param>
|
||||
/// <param name="progressReporter">The <see cref="JobProgressReporter"/> to report progress of the operation.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
|
||||
/// <returns>A <see cref="Task{TResult}"/> resulting in a <see cref="Nullable{T}"/> <see cref="bool"/> representing the merge result that is <see langword="true"/> after a fast forward, <see langword="false"/> on a merge or up to date, <see langword="null"/> on a conflict.</returns>
|
||||
Task<bool?> MergeOrigin(string committerName, string committerEmail, Action<int> progressReporter, CancellationToken cancellationToken);
|
||||
Task<bool?> MergeOrigin(string committerName, string committerEmail, JobProgressReporter progressReporter, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Runs the synchronize event script and attempts to push any changes made to the <see cref="IRepository"/> if on a tracked branch.
|
||||
@@ -131,11 +136,18 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
/// <param name="password">The password to fetch from the origin repository.</param>
|
||||
/// <param name="committerName">The name of the potential committer.</param>
|
||||
/// <param name="committerEmail">The e-mail of the potential committer.</param>
|
||||
/// <param name="progressReporter"><see cref="Action{T1}"/> to report 0-100 <see cref="int"/> progress of the operation.</param>
|
||||
/// <param name="progressReporter">The <see cref="JobProgressReporter"/> to report progress of the operation.</param>
|
||||
/// <param name="synchronizeTrackedBranch">If the synchronizations should be made to the tracked reference as opposed to a temporary branch.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
|
||||
/// <returns>A <see cref="Task{TResult}"/> resulting in <see langword="true"/> if commits were pushed to the tracked origin reference, <see langword="false"/> otherwise.</returns>
|
||||
Task<bool> Sychronize(string username, string password, string committerName, string committerEmail, Action<int> progressReporter, bool synchronizeTrackedBranch, CancellationToken cancellationToken);
|
||||
Task<bool> Sychronize(
|
||||
string username,
|
||||
string password,
|
||||
string committerName,
|
||||
string committerEmail,
|
||||
JobProgressReporter progressReporter,
|
||||
bool synchronizeTrackedBranch,
|
||||
CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Copies the current working directory to a given <paramref name="path"/>.
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Tgstation.Server.Host.Jobs;
|
||||
|
||||
namespace Tgstation.Server.Host.Components.Repository
|
||||
{
|
||||
/// <summary>
|
||||
@@ -15,7 +17,7 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
bool InUse { get; }
|
||||
|
||||
/// <summary>
|
||||
/// If a <see cref="CloneRepository(Uri, string, string, string, Action{int}, bool, CancellationToken)"/> operation is in progress.
|
||||
/// If a <see cref="CloneRepository(Uri, string, string, string, JobProgressReporter, bool, CancellationToken)"/> operation is in progress.
|
||||
/// </summary>
|
||||
bool CloneInProgress { get; }
|
||||
|
||||
@@ -33,7 +35,7 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
/// <param name="initialBranch">The branch to clone.</param>
|
||||
/// <param name="username">The username to clone from <paramref name="url"/>.</param>
|
||||
/// <param name="password">The password to clone from <paramref name="url"/>.</param>
|
||||
/// <param name="progressReporter">A function to report 0-100 progress of the clone.</param>
|
||||
/// <param name="progressReporter">The <see cref="JobProgressReporter"/> for progress of the clone.</param>
|
||||
/// <param name="recurseSubmodules">If submodules should be recusively cloned and initialized.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
|
||||
/// <returns>The newly cloned <see cref="IRepository"/>, <see langword="null"/> if one already exists.</returns>
|
||||
@@ -42,7 +44,7 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
string initialBranch,
|
||||
string username,
|
||||
string password,
|
||||
Action<int> progressReporter,
|
||||
JobProgressReporter progressReporter,
|
||||
bool recurseSubmodules,
|
||||
CancellationToken cancellationToken);
|
||||
|
||||
|
||||
@@ -114,20 +114,22 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
/// <summary>
|
||||
/// Converts a given <paramref name="progressReporter"/> to a <see cref="LibGit2Sharp.Handlers.CheckoutProgressHandler"/>.
|
||||
/// </summary>
|
||||
/// <param name="progressReporter"><see cref="Action{T1}"/> to report 0-100 <see cref="int"/> progress of the operation.</param>
|
||||
/// <param name="progressReporter">The <see cref="JobProgressReporter"/> of the operation.</param>
|
||||
/// <param name="stage">The stage argument for <paramref name="progressReporter"/>.</param>
|
||||
/// <returns>A <see cref="LibGit2Sharp.Handlers.CheckoutProgressHandler"/> based on <paramref name="progressReporter"/>.</returns>
|
||||
static CheckoutProgressHandler CheckoutProgressHandler(Action<int> progressReporter) => (a, completedSteps, totalSteps) => progressReporter((int)(((float)completedSteps) / totalSteps * 100));
|
||||
static CheckoutProgressHandler CheckoutProgressHandler(JobProgressReporter progressReporter, string stage) => (a, completedSteps, totalSteps) => progressReporter(stage, (int)(((float)completedSteps) / totalSteps * 100));
|
||||
|
||||
/// <summary>
|
||||
/// Generate a <see cref="LibGit2Sharp.Handlers.TransferProgressHandler"/> from a given <paramref name="progressReporter"/> and <paramref name="cancellationToken"/>.
|
||||
/// </summary>
|
||||
/// <param name="progressReporter"><see cref="Action{T1}"/> to report 0-100 <see cref="int"/> progress of the operation.</param>
|
||||
/// <param name="progressReporter">The <see cref="JobProgressReporter"/> of the operation.</param>
|
||||
/// <param name="stage">The stage argument for <paramref name="progressReporter"/>.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
|
||||
/// <returns>A new <see cref="LibGit2Sharp.Handlers.TransferProgressHandler"/> based on <paramref name="progressReporter"/>.</returns>
|
||||
static TransferProgressHandler TransferProgressHandler(Action<int> progressReporter, CancellationToken cancellationToken) => (transferProgress) =>
|
||||
static TransferProgressHandler TransferProgressHandler(JobProgressReporter progressReporter, string stage, CancellationToken cancellationToken) => (transferProgress) =>
|
||||
{
|
||||
var percentage = 100 * (((float)transferProgress.IndexedObjects + transferProgress.ReceivedObjects) / (transferProgress.TotalObjects * 2));
|
||||
progressReporter((int)percentage);
|
||||
progressReporter(stage, (int)percentage);
|
||||
return !cancellationToken.IsCancellationRequested;
|
||||
};
|
||||
|
||||
@@ -204,7 +206,7 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
string username,
|
||||
string password,
|
||||
bool updateSubmodules,
|
||||
Action<int> progressReporter,
|
||||
JobProgressReporter progressReporter,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
if (testMergeParameters == null)
|
||||
@@ -258,7 +260,8 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
logger.LogTrace("Fetching refspec {0}...", refSpec);
|
||||
|
||||
var remote = libGitRepo.Network.Remotes.First();
|
||||
progressReporter(0);
|
||||
var stage = $"Fetch {refSpec}";
|
||||
progressReporter(stage, 0);
|
||||
commands.Fetch(
|
||||
libGitRepo,
|
||||
refSpecList,
|
||||
@@ -267,7 +270,10 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
{
|
||||
Prune = true,
|
||||
OnProgress = (a) => !cancellationToken.IsCancellationRequested,
|
||||
OnTransferProgress = TransferProgressHandler(percentage => progressReporter(percentage / 2), cancellationToken),
|
||||
OnTransferProgress = TransferProgressHandler(
|
||||
(lambdaStage, progress) => progressReporter(lambdaStage, progress / 2),
|
||||
stage,
|
||||
cancellationToken),
|
||||
OnUpdateTips = (a, b, c) => !cancellationToken.IsCancellationRequested,
|
||||
CredentialsProvider = credentialsProvider.GenerateCredentialsHandler(username, password),
|
||||
},
|
||||
@@ -299,7 +305,9 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
FailOnConflict = true,
|
||||
FastForwardStrategy = FastForwardStrategy.NoFastForward,
|
||||
SkipReuc = true,
|
||||
OnCheckoutProgress = CheckoutProgressHandler(percentage => progressReporter(50 + (percentage / 2))),
|
||||
OnCheckoutProgress = CheckoutProgressHandler(
|
||||
(lambdaStage, progress) => progressReporter(lambdaStage, 50 + (progress / 2)),
|
||||
$"Merge {testMergeParameters.TargetCommitSha}"),
|
||||
});
|
||||
}
|
||||
finally
|
||||
@@ -354,7 +362,11 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
.ConfigureAwait(false);
|
||||
|
||||
if (updateSubmodules)
|
||||
await UpdateSubmodules(percentage => progressReporter(66 + (percentage / 3)), username, password, cancellationToken).ConfigureAwait(false);
|
||||
await UpdateSubmodules(
|
||||
(stage, progress) => progressReporter(stage, 66 + (progress.Value / 3)),
|
||||
username,
|
||||
password,
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
await eventConsumer.HandleEvent(
|
||||
@@ -378,7 +390,7 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
string username,
|
||||
string password,
|
||||
bool updateSubmodules,
|
||||
Action<int> progressReporter,
|
||||
JobProgressReporter progressReporter,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
if (committish == null)
|
||||
@@ -391,7 +403,10 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
() =>
|
||||
{
|
||||
libGitRepo.RemoveUntrackedFiles();
|
||||
RawCheckout(committish, percentage => progressReporter(percentage * (updateSubmodules ? 2 : 3) / 3), cancellationToken);
|
||||
RawCheckout(
|
||||
committish,
|
||||
(stage, progress) => progressReporter(stage, progress * (updateSubmodules ? 2 : 3) / 3),
|
||||
cancellationToken);
|
||||
},
|
||||
cancellationToken,
|
||||
DefaultIOManager.BlockingTaskCreationOptions,
|
||||
@@ -399,11 +414,15 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
.ConfigureAwait(false);
|
||||
|
||||
if (updateSubmodules)
|
||||
await UpdateSubmodules(percentage => progressReporter(66 + (percentage / 3)), username, password, cancellationToken).ConfigureAwait(false);
|
||||
await UpdateSubmodules(
|
||||
(stage, progress) => progressReporter(stage, 66 + (progress / 3)),
|
||||
username,
|
||||
password,
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task FetchOrigin(string username, string password, Action<int> progressReporter, CancellationToken cancellationToken)
|
||||
public async Task FetchOrigin(string username, string password, JobProgressReporter progressReporter, CancellationToken cancellationToken)
|
||||
{
|
||||
if (progressReporter == null)
|
||||
throw new ArgumentNullException(nameof(progressReporter));
|
||||
@@ -425,7 +444,7 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
{
|
||||
Prune = true,
|
||||
OnProgress = (a) => !cancellationToken.IsCancellationRequested,
|
||||
OnTransferProgress = TransferProgressHandler(progressReporter, cancellationToken),
|
||||
OnTransferProgress = TransferProgressHandler(progressReporter, "Fetch Origin", cancellationToken),
|
||||
OnUpdateTips = (a, b, c) => !cancellationToken.IsCancellationRequested,
|
||||
CredentialsProvider = credentialsProvider.GenerateCredentialsHandler(username, password),
|
||||
},
|
||||
@@ -447,7 +466,12 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task ResetToOrigin(string username, string password, bool updateSubmodules, Action<int> progressReporter, CancellationToken cancellationToken)
|
||||
public async Task ResetToOrigin(
|
||||
string username,
|
||||
string password,
|
||||
bool updateSubmodules,
|
||||
JobProgressReporter progressReporter,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
if (progressReporter == null)
|
||||
throw new ArgumentNullException(nameof(progressReporter));
|
||||
@@ -458,16 +482,16 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
await eventConsumer.HandleEvent(EventType.RepoResetOrigin, new List<string> { trackedBranch.FriendlyName, trackedBranch.Tip.Sha }, cancellationToken).ConfigureAwait(false);
|
||||
await ResetToSha(
|
||||
trackedBranch.Tip.Sha,
|
||||
percentage => progressReporter(percentage / (updateSubmodules ? 2 : 1)),
|
||||
(stage, progress) => progressReporter(stage, progress / (updateSubmodules ? 2 : 1)),
|
||||
cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
if (updateSubmodules)
|
||||
await UpdateSubmodules(percentage => progressReporter(50 + (percentage / 2)), username, password, cancellationToken).ConfigureAwait(false);
|
||||
await UpdateSubmodules((stage, progress) => progressReporter(stage, 50 + (progress / 2)), username, password, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task ResetToSha(string sha, Action<int> progressReporter, CancellationToken cancellationToken) => Task.Factory.StartNew(
|
||||
public Task ResetToSha(string sha, JobProgressReporter progressReporter, CancellationToken cancellationToken) => Task.Factory.StartNew(
|
||||
() =>
|
||||
{
|
||||
if (sha == null)
|
||||
@@ -488,7 +512,7 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
|
||||
libGitRepo.Reset(ResetMode.Hard, gitObject.Peel<Commit>(), new CheckoutOptions
|
||||
{
|
||||
OnCheckoutProgress = CheckoutProgressHandler(progressReporter),
|
||||
OnCheckoutProgress = CheckoutProgressHandler(progressReporter, $"Reset to {gitObject.Sha}"),
|
||||
});
|
||||
},
|
||||
cancellationToken,
|
||||
@@ -520,7 +544,11 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
TaskScheduler.Current);
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<bool?> MergeOrigin(string committerName, string committerEmail, Action<int> progressReporter, CancellationToken cancellationToken)
|
||||
public async Task<bool?> MergeOrigin(
|
||||
string committerName,
|
||||
string committerEmail,
|
||||
JobProgressReporter progressReporter,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
if (progressReporter == null)
|
||||
throw new ArgumentNullException(nameof(progressReporter));
|
||||
@@ -553,7 +581,7 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
FailOnConflict = true,
|
||||
FastForwardStrategy = FastForwardStrategy.Default,
|
||||
SkipReuc = true,
|
||||
OnCheckoutProgress = CheckoutProgressHandler(progressReporter),
|
||||
OnCheckoutProgress = CheckoutProgressHandler(progressReporter, "Merge Origin"),
|
||||
});
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
@@ -563,7 +591,7 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
logger.LogDebug("Merge conflict, aborting and reverting to {0}", oldHead.FriendlyName);
|
||||
libGitRepo.Reset(ResetMode.Hard, oldTip, new CheckoutOptions
|
||||
{
|
||||
OnCheckoutProgress = CheckoutProgressHandler(progressReporter),
|
||||
OnCheckoutProgress = CheckoutProgressHandler(progressReporter, $"Hard Reset to {oldHead.FriendlyName}"),
|
||||
});
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
}
|
||||
@@ -590,7 +618,7 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
string password,
|
||||
string committerName,
|
||||
string committerEmail,
|
||||
Action<int> progressReporter,
|
||||
JobProgressReporter progressReporter,
|
||||
bool synchronizeTrackedBranch,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
@@ -648,7 +676,7 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
{
|
||||
libGitRepo.Reset(ResetMode.Hard, libGitRepo.Head.Tip, new CheckoutOptions
|
||||
{
|
||||
OnCheckoutProgress = CheckoutProgressHandler(progress => progressReporter(progress / 10)),
|
||||
OnCheckoutProgress = CheckoutProgressHandler((stage, progress) => progressReporter(stage, progress / 10), "Hard reset and remove untracked files"),
|
||||
});
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
libGitRepo.RemoveUntrackedFiles();
|
||||
@@ -659,7 +687,7 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
void FinalReporter(int progress) => progressReporter((int)(((float)progress) / 100 * 90));
|
||||
void FinalReporter(string stage, int? progress) => progressReporter(stage, (int)(((float)progress) / 100 * 90));
|
||||
|
||||
if (!synchronizeTrackedBranch)
|
||||
{
|
||||
@@ -803,19 +831,20 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
/// Runs a blocking force checkout to <paramref name="committish"/>.
|
||||
/// </summary>
|
||||
/// <param name="committish">The committish to checkout.</param>
|
||||
/// <param name="progressReporter">Progress reporter <see cref="Action{T}"/>.</param>
|
||||
/// <param name="progressReporter">The <see cref="JobProgressReporter"/> for the operation.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
|
||||
void RawCheckout(string committish, Action<int> progressReporter, CancellationToken cancellationToken)
|
||||
void RawCheckout(string committish, JobProgressReporter progressReporter, CancellationToken cancellationToken)
|
||||
{
|
||||
logger.LogTrace("Checkout: {0}", committish);
|
||||
|
||||
progressReporter(0);
|
||||
var stage = $"Checkout {committish}";
|
||||
progressReporter(stage, 0);
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var checkoutOptions = new CheckoutOptions
|
||||
{
|
||||
CheckoutModifiers = CheckoutModifiers.Force,
|
||||
OnCheckoutProgress = CheckoutProgressHandler(progressReporter),
|
||||
OnCheckoutProgress = CheckoutProgressHandler(progressReporter, stage),
|
||||
};
|
||||
|
||||
void RunCheckout() => commands.Checkout(
|
||||
@@ -855,10 +884,10 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
/// </summary>
|
||||
/// <param name="username">The username to fetch from the origin repository.</param>
|
||||
/// <param name="password">The password to fetch from the origin repository.</param>
|
||||
/// <param name="progressReporter"><see cref="Action{T1}"/> to report 0-100 <see cref="int"/> progress of the operation.</param>
|
||||
/// <param name="progressReporter"><see cref="JobProgressReporter"/> of the operation.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
|
||||
/// <returns>A <see cref="Task"/> representing the running operation.</returns>
|
||||
Task PushHeadToTemporaryBranch(string username, string password, Action<int> progressReporter, CancellationToken cancellationToken) => Task.Factory.StartNew(
|
||||
Task PushHeadToTemporaryBranch(string username, string password, JobProgressReporter progressReporter, CancellationToken cancellationToken) => Task.Factory.StartNew(
|
||||
() =>
|
||||
{
|
||||
logger.LogInformation("Pushing changes to temporary remote branch...");
|
||||
@@ -870,9 +899,9 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
try
|
||||
{
|
||||
var forcePushString = String.Format(CultureInfo.InvariantCulture, "+{0}:{0}", branch.CanonicalName);
|
||||
libGitRepo.Network.Push(remote, forcePushString, GeneratePushOptions(progress => progressReporter((int)(0.9f * progress)), username, password, cancellationToken));
|
||||
libGitRepo.Network.Push(remote, forcePushString, GeneratePushOptions((stage, progress) => progressReporter(stage, (int)(0.9f * progress)), username, password, cancellationToken));
|
||||
var removalString = String.Format(CultureInfo.InvariantCulture, ":{0}", branch.CanonicalName);
|
||||
libGitRepo.Network.Push(remote, removalString, GeneratePushOptions(progress => progressReporter(90 + (int)(0.1f * progress)), username, password, cancellationToken));
|
||||
libGitRepo.Network.Push(remote, removalString, GeneratePushOptions((stage, progress) => progressReporter(stage, 90 + (int)(0.1f * progress)), username, password, cancellationToken));
|
||||
}
|
||||
catch (UserCancelledException)
|
||||
{
|
||||
@@ -895,23 +924,23 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
/// <summary>
|
||||
/// Generate a standard set of <see cref="PushOptions"/>.
|
||||
/// </summary>
|
||||
/// <param name="progressReporter"><see cref="Action{T1}"/> to report 0-100 <see cref="int"/> progress of the operation.</param>
|
||||
/// <param name="progressReporter"><see cref="JobProgressReporter"/> of the operation.</param>
|
||||
/// <param name="username">The username for the <see cref="credentialsProvider"/>.</param>
|
||||
/// <param name="password">The password for the <see cref="credentialsProvider"/>.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
|
||||
/// <returns>A new set of <see cref="PushOptions"/>.</returns>
|
||||
PushOptions GeneratePushOptions(Action<int> progressReporter, string username, string password, CancellationToken cancellationToken) => new PushOptions
|
||||
PushOptions GeneratePushOptions(JobProgressReporter progressReporter, string username, string password, CancellationToken cancellationToken) => new PushOptions
|
||||
{
|
||||
OnPackBuilderProgress = (stage, current, total) =>
|
||||
{
|
||||
var baseProgress = stage == PackBuilderStage.Counting ? 0 : 25;
|
||||
progressReporter(baseProgress + ((int)(25 * ((float)current) / total)));
|
||||
progressReporter("Push", baseProgress + ((int)(25 * ((float)current) / total)));
|
||||
return !cancellationToken.IsCancellationRequested;
|
||||
},
|
||||
OnNegotiationCompletedBeforePush = (a) => !cancellationToken.IsCancellationRequested,
|
||||
OnPushTransferProgress = (a, sentBytes, totalBytes) =>
|
||||
{
|
||||
progressReporter(50 + ((int)(50 * ((float)sentBytes) / totalBytes)));
|
||||
progressReporter("Push", 50 + ((int)(50 * ((float)sentBytes) / totalBytes)));
|
||||
return !cancellationToken.IsCancellationRequested;
|
||||
},
|
||||
CredentialsProvider = credentialsProvider.GenerateCredentialsHandler(username, password),
|
||||
@@ -920,12 +949,12 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
/// <summary>
|
||||
/// Recusively update all <see cref="Submodule"/>s in the <see cref="libGitRepo"/>.
|
||||
/// </summary>
|
||||
/// <param name="progressReporter"><see cref="Action{T1}"/> to report 0-100 <see cref="int"/> progress of the operation.</param>
|
||||
/// <param name="progressReporter"><see cref="JobProgressReporter"/> of the operation.</param>
|
||||
/// <param name="username">The username for the <see cref="credentialsProvider"/>.</param>
|
||||
/// <param name="password">The password for the <see cref="credentialsProvider"/>.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
|
||||
/// <returns>A <see cref="Task"/> representing the running operation.</returns>
|
||||
async Task UpdateSubmodules(Action<int> progressReporter, string username, string password, CancellationToken cancellationToken)
|
||||
async Task UpdateSubmodules(JobProgressReporter progressReporter, string username, string password, CancellationToken cancellationToken)
|
||||
{
|
||||
var submoduleCount = libGitRepo.Submodules.Count();
|
||||
if (submoduleCount == 0)
|
||||
@@ -940,15 +969,20 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
var factor = 100 / submoduleCount;
|
||||
foreach (var submodule in libGitRepo.Submodules)
|
||||
{
|
||||
void LocalProgressReporter(int percentage) => progressReporter((iteration * factor) + (percentage / submoduleCount));
|
||||
void LocalProgressReporter(string stage, int percentage) => progressReporter(stage, (iteration * factor) + (percentage / submoduleCount));
|
||||
var submoduleUpdateOptions = new SubmoduleUpdateOptions
|
||||
{
|
||||
Init = true,
|
||||
OnTransferProgress = TransferProgressHandler(percentage => LocalProgressReporter(percentage / 2), cancellationToken),
|
||||
OnTransferProgress = TransferProgressHandler(
|
||||
(stage, progress) => LocalProgressReporter(stage, progress.Value / 2),
|
||||
$"Fetch submodule {submodule.Name}",
|
||||
cancellationToken),
|
||||
OnProgress = output => !cancellationToken.IsCancellationRequested,
|
||||
OnUpdateTips = (a, b, c) => !cancellationToken.IsCancellationRequested,
|
||||
CredentialsProvider = credentialsProvider.GenerateCredentialsHandler(username, password),
|
||||
OnCheckoutProgress = CheckoutProgressHandler(percentage => LocalProgressReporter(50 + (percentage / 2))),
|
||||
OnCheckoutProgress = CheckoutProgressHandler(
|
||||
(stage, progress) => LocalProgressReporter(stage, 50 + (progress.Value / 2)),
|
||||
$"Checkout submodule {submodule.Name}"),
|
||||
};
|
||||
|
||||
logger.LogDebug("Updating submodule {0}...", submodule.Name);
|
||||
|
||||
@@ -104,7 +104,7 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
string initialBranch,
|
||||
string username,
|
||||
string password,
|
||||
Action<int> progressReporter,
|
||||
JobProgressReporter progressReporter,
|
||||
bool recurseSubmodules,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
@@ -136,7 +136,7 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
OnTransferProgress = (a) =>
|
||||
{
|
||||
var percentage = 100 * (((float)a.IndexedObjects + a.ReceivedObjects) / (a.TotalObjects * 2));
|
||||
progressReporter((int)percentage);
|
||||
progressReporter("Cloning", (int)percentage);
|
||||
return !cancellationToken.IsCancellationRequested;
|
||||
},
|
||||
RecurseSubmodules = recurseSubmodules,
|
||||
|
||||
@@ -167,7 +167,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
if (job == default)
|
||||
return NotFound();
|
||||
var api = job.ToApi();
|
||||
api.Progress = jobManager.JobProgress(job);
|
||||
jobManager.SetJobProgress(api);
|
||||
return Json(api);
|
||||
}
|
||||
|
||||
@@ -178,7 +178,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
/// <returns>A <see cref="Task"/> representing the running operation.</returns>
|
||||
private Task AddJobProgressResponseTransformer(JobResponse jobResponse)
|
||||
{
|
||||
jobResponse.Progress = jobManager.JobProgress(jobResponse);
|
||||
jobManager.SetJobProgress(jobResponse);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -452,7 +452,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
async Task<IActionResult> RepositoryUpdateJobOhGodPleaseSomeoneRefactorThisItsTooFuckingBig(
|
||||
IInstanceCore instance,
|
||||
IDatabaseContextFactory databaseContextFactory,
|
||||
Action<int> progressReporter,
|
||||
JobProgressReporter progressReporter,
|
||||
CancellationToken ct)
|
||||
{
|
||||
var repoManager = instance.RepositoryManager;
|
||||
@@ -478,14 +478,14 @@ namespace Tgstation.Server.Host.Controllers
|
||||
var numSteps = (model.NewTestMerges?.Count ?? 0) + (model.UpdateFromOrigin == true ? 1 : 0) + (!modelHasShaOrReference ? 2 : (hardResettingToOriginReference ? 3 : 1));
|
||||
var doneSteps = 0;
|
||||
|
||||
Action<int> NextProgressReporter()
|
||||
JobProgressReporter NextProgressReporter()
|
||||
{
|
||||
var tmpDoneSteps = doneSteps;
|
||||
++doneSteps;
|
||||
return progress => progressReporter((progress + (100 * tmpDoneSteps)) / numSteps);
|
||||
return (status, progress) => progressReporter(status, (progress + (100 * tmpDoneSteps)) / numSteps);
|
||||
}
|
||||
|
||||
progressReporter(0);
|
||||
progressReporter(null, 0);
|
||||
|
||||
// get a base line for where we are
|
||||
Models.RevisionInformation lastRevisionInfo = null;
|
||||
@@ -577,7 +577,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
postUpdateSha = repo.Head;
|
||||
}
|
||||
else
|
||||
NextProgressReporter()(100);
|
||||
NextProgressReporter()(null, 100);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -612,7 +612,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
await CallLoadRevInfo().ConfigureAwait(false); // we've either seen origin before or what we're checking out is on origin
|
||||
}
|
||||
else
|
||||
NextProgressReporter()(100);
|
||||
NextProgressReporter()(null, 100);
|
||||
|
||||
if (hardResettingToOriginReference)
|
||||
{
|
||||
@@ -882,7 +882,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
if (startReference != null && repo.Head != startSha)
|
||||
await repo.ResetToSha(startSha, NextProgressReporter(), default).ConfigureAwait(false);
|
||||
else
|
||||
progressReporter(100);
|
||||
progressReporter(null, 100);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
||||
using Tgstation.Server.Api.Models.Response;
|
||||
using Tgstation.Server.Host.Models;
|
||||
|
||||
namespace Tgstation.Server.Host.Jobs
|
||||
@@ -13,11 +13,10 @@ namespace Tgstation.Server.Host.Jobs
|
||||
public interface IJobManager : IHostedService
|
||||
{
|
||||
/// <summary>
|
||||
/// Get the <see cref="Api.Models.Response.JobResponse.Progress"/> for a <paramref name="job"/>.
|
||||
/// Set the <see cref="JobResponse.Progress"/> and <see cref="JobResponse.Stage"/> for a given <paramref name="apiResponse"/>.
|
||||
/// </summary>
|
||||
/// <param name="job">The <see cref="Api.Models.Internal.Job"/> to get <see cref="Api.Models.Response.JobResponse.Progress"/> for.</param>
|
||||
/// <returns>The <see cref="Api.Models.Response.JobResponse.Progress"/> of <paramref name="job"/>.</returns>
|
||||
int? JobProgress(Api.Models.Internal.Job job);
|
||||
/// <param name="apiResponse">The <see cref="JobResponse"/> to update.</param>
|
||||
void SetJobProgress(JobResponse apiResponse);
|
||||
|
||||
/// <summary>
|
||||
/// Registers a given <see cref="Job"/> and begins running it.
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Tgstation.Server.Host.Components;
|
||||
@@ -14,13 +13,13 @@ namespace Tgstation.Server.Host.Jobs
|
||||
/// <param name="instance">The <see cref="IInstanceCore"/> the job is running on. <see langword="null"/> only when performing an instance move operation.</param>
|
||||
/// <param name="databaseContextFactory">The <see cref="IDatabaseContextFactory"/> for the operation.</param>
|
||||
/// <param name="job">The running <see cref="Job"/>.</param>
|
||||
/// <param name="progressReporter">A <see cref="Action{T1}"/> that will update the progress of the job.</param>
|
||||
/// <param name="progressReporter">The <see cref="JobProgressReporter"/> for the job.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
|
||||
/// <returns>A <see cref="Task"/> representing the running operation.</returns>
|
||||
public delegate Task JobEntrypoint(
|
||||
IInstanceCore instance,
|
||||
IDatabaseContextFactory databaseContextFactory,
|
||||
Job job,
|
||||
Action<int> progressReporter,
|
||||
JobProgressReporter progressReporter,
|
||||
CancellationToken cancellationToken);
|
||||
}
|
||||
|
||||
@@ -44,6 +44,11 @@ namespace Tgstation.Server.Host.Jobs
|
||||
/// </summary>
|
||||
public int? Progress { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The stage of the job.
|
||||
/// </summary>
|
||||
public string Stage { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Wait for <see cref="task"/> to complete.
|
||||
/// </summary>
|
||||
|
||||
@@ -7,7 +7,7 @@ using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Serilog.Context;
|
||||
|
||||
using Tgstation.Server.Api.Models.Response;
|
||||
using Tgstation.Server.Host.Components;
|
||||
using Tgstation.Server.Host.Database;
|
||||
using Tgstation.Server.Host.Extensions;
|
||||
@@ -221,15 +221,16 @@ namespace Tgstation.Server.Host.Jobs
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public int? JobProgress(Api.Models.Internal.Job job)
|
||||
public void SetJobProgress(JobResponse apiResponse)
|
||||
{
|
||||
if (job == null)
|
||||
throw new ArgumentNullException(nameof(job));
|
||||
if (apiResponse == null)
|
||||
throw new ArgumentNullException(nameof(apiResponse));
|
||||
lock (synchronizationLock)
|
||||
{
|
||||
if (!jobs.TryGetValue(job.Id.Value, out var handler))
|
||||
return null;
|
||||
return handler.Progress;
|
||||
if (!jobs.TryGetValue(apiResponse.Id.Value, out var handler))
|
||||
return;
|
||||
apiResponse.Progress = handler.Progress;
|
||||
apiResponse.Stage = handler.Stage;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -293,11 +294,18 @@ namespace Tgstation.Server.Host.Jobs
|
||||
var oldJob = job;
|
||||
job = new Job { Id = oldJob.Id };
|
||||
|
||||
void UpdateProgress(int progress)
|
||||
void UpdateProgress(string stage, int? progress)
|
||||
{
|
||||
if (progress.HasValue
|
||||
&& (progress.Value < 0 || progress.Value > 100))
|
||||
throw new ArgumentOutOfRangeException(nameof(progress), "Progress must be a value from 0-100!");
|
||||
|
||||
lock (synchronizationLock)
|
||||
if (jobs.TryGetValue(oldJob.Id.Value, out var handler))
|
||||
{
|
||||
handler.Stage = stage;
|
||||
handler.Progress = progress;
|
||||
}
|
||||
}
|
||||
|
||||
await activationTcs.Task.WithToken(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
using Tgstation.Server.Host.Models;
|
||||
|
||||
namespace Tgstation.Server.Host.Jobs
|
||||
{
|
||||
/// <summary>
|
||||
/// Progress reporter for a <see cref="Job"/>.
|
||||
/// </summary>
|
||||
/// <param name="stage">A description of what the job is currently doing.</param>
|
||||
/// <param name="progress">The progress of the job on a scale from 0-100.</param>
|
||||
public delegate void JobProgressReporter(
|
||||
string stage,
|
||||
int? progress);
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
<Import Project="../../build/Version.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
@@ -26,7 +26,7 @@
|
||||
<DockerfileContext>..\..</DockerfileContext>
|
||||
</PropertyGroup>
|
||||
|
||||
<Target Name="ClientInstall" Inputs="../../build/ControlPanelVersion.props" Outputs="$(NpmInstallStampFile)">
|
||||
<Target Name="ClientInstall" BeforeTargets="ResolveAssemblyReferences" Inputs="../../build/ControlPanelVersion.props" Outputs="$(NpmInstallStampFile)">
|
||||
<Message Text="Pulling web control panel..." Importance="high" />
|
||||
<RemoveDir Directories="ClientApp" />
|
||||
<Exec Command="git clone https://github.com/tgstation/tgstation-server-webpanel --branch v$(TgsControlPanelVersion) --depth 1 ClientApp" />
|
||||
|
||||
@@ -1061,7 +1061,7 @@ namespace Tgstation.Server.Tests
|
||||
() => { });
|
||||
|
||||
const string StartSha = "af4da8beb9f9b374b04a3cc4d65acca662e8cc1a";
|
||||
await repo.CheckoutObject(StartSha, null, null, true, progress => { }, default);
|
||||
await repo.CheckoutObject(StartSha, null, null, true, (stage, progress) => { }, default);
|
||||
var result = await repo.ShaIsParent("2f8588a3ca0f6b027704a2a04381215619de3412", default);
|
||||
Assert.IsTrue(result);
|
||||
Assert.AreEqual(StartSha, repo.Head);
|
||||
|
||||
Reference in New Issue
Block a user