mirror of
https://github.com/tgstation/tgstation-server.git
synced 2026-08-22 20:47:28 +01:00
More OpenDream engine implementation
This commit is contained in:
@@ -9,6 +9,7 @@ using Microsoft.Extensions.Logging;
|
||||
using Tgstation.Server.Api.Models;
|
||||
using Tgstation.Server.Api.Models.Internal;
|
||||
using Tgstation.Server.Host.IO;
|
||||
using Tgstation.Server.Host.Jobs;
|
||||
using Tgstation.Server.Host.Utils;
|
||||
|
||||
namespace Tgstation.Server.Host.Components.Engine
|
||||
@@ -66,15 +67,21 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
/// </summary>
|
||||
protected abstract string ByondRevisionsUrlTemplate { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="IFileDownloader"/> for the <see cref="ByondInstallerBase"/>.
|
||||
/// </summary>
|
||||
readonly IFileDownloader fileDownloader;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ByondInstallerBase"/> class.
|
||||
/// </summary>
|
||||
/// <param name="ioManager">The <see cref="IIOManager"/> for the <see cref="EngineInstallerBase"/>.</param>
|
||||
/// <param name="fileDownloader">The <see cref="IFileDownloader"/> for the <see cref="EngineInstallerBase"/>.</param>
|
||||
/// <param name="logger">The <see cref="ILogger"/> for the <see cref="EngineInstallerBase"/>.</param>
|
||||
protected ByondInstallerBase(IIOManager ioManager, IFileDownloader fileDownloader, ILogger<ByondInstallerBase> logger)
|
||||
: base(ioManager, fileDownloader, logger)
|
||||
/// <param name="fileDownloader">The value of <see cref="fileDownloader"/>.</param>
|
||||
protected ByondInstallerBase(IIOManager ioManager, ILogger<ByondInstallerBase> logger, IFileDownloader fileDownloader)
|
||||
: base(ioManager, logger)
|
||||
{
|
||||
this.fileDownloader = fileDownloader ?? throw new ArgumentNullException(nameof(fileDownloader));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -184,11 +191,29 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override ValueTask<Uri> GetDownloadZipUrl(ByondVersion version, CancellationToken cancellationToken)
|
||||
public override async ValueTask<IEngineInstallationData> DownloadVersion(ByondVersion version, JobProgressReporter progressReporter, CancellationToken cancellationToken)
|
||||
{
|
||||
CheckVersionValidity(version);
|
||||
var url = String.Format(CultureInfo.InvariantCulture, ByondRevisionsUrlTemplate, version.Version.Major, version.Version.Minor);
|
||||
return ValueTask.FromResult(new Uri(url));
|
||||
|
||||
var url = await GetDownloadZipUrl(version, cancellationToken);
|
||||
Logger.LogTrace("Downloading {engineType} version {version} from {url}...", TargetEngineType, version, url);
|
||||
|
||||
await using var download = fileDownloader.DownloadFile(url, null);
|
||||
await using var buffer = new BufferedFileStreamProvider(
|
||||
await download.GetResult(cancellationToken));
|
||||
|
||||
var stream = await buffer.GetOwnedResult(cancellationToken);
|
||||
try
|
||||
{
|
||||
return new ZipStreamEngineInstallationData(
|
||||
IOManager,
|
||||
stream);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await stream.DisposeAsync();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -198,5 +223,18 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
/// <param name="supportsCli">Whether or not the returned path supports being run as a command-line application.</param>
|
||||
/// <returns>The file name of the DreamDaemon executable.</returns>
|
||||
protected abstract string GetDreamDaemonName(Version byondVersion, out bool supportsCli);
|
||||
|
||||
/// <summary>
|
||||
/// Create a <see cref="Uri"/> pointing to the location of the download for a given <paramref name="version"/>.
|
||||
/// </summary>
|
||||
/// <param name="version">The <see cref="ByondVersion"/> to create a <see cref="Uri"/> for.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
|
||||
/// <returns>A <see cref="ValueTask{TResult}"/> resulting in a new <see cref="Uri"/> pointing to the version download location.</returns>
|
||||
ValueTask<Uri> GetDownloadZipUrl(ByondVersion version, CancellationToken cancellationToken)
|
||||
{
|
||||
CheckVersionValidity(version);
|
||||
var url = String.Format(CultureInfo.InvariantCulture, ByondRevisionsUrlTemplate, version.Version.Major, version.Version.Minor);
|
||||
return ValueTask.FromResult(new Uri(url));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -8,6 +7,7 @@ using Microsoft.Extensions.Logging;
|
||||
using Tgstation.Server.Api.Models;
|
||||
using Tgstation.Server.Api.Models.Internal;
|
||||
using Tgstation.Server.Host.IO;
|
||||
using Tgstation.Server.Host.Jobs;
|
||||
|
||||
namespace Tgstation.Server.Host.Components.Engine
|
||||
{
|
||||
@@ -29,21 +29,14 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
/// </summary>
|
||||
protected ILogger<EngineInstallerBase> Logger { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="IFileDownloader"/> for the <see cref="EngineInstallerBase"/>.
|
||||
/// </summary>
|
||||
readonly IFileDownloader fileDownloader;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="EngineInstallerBase"/> class.
|
||||
/// </summary>
|
||||
/// <param name="ioManager">The value of <see cref="IOManager"/>.</param>
|
||||
/// <param name="fileDownloader">The value of <see cref="fileDownloader"/>.</param>
|
||||
/// <param name="logger">The value of <see cref="Logger"/>.</param>
|
||||
protected EngineInstallerBase(IIOManager ioManager, IFileDownloader fileDownloader, ILogger<EngineInstallerBase> logger)
|
||||
protected EngineInstallerBase(IIOManager ioManager, ILogger<EngineInstallerBase> logger)
|
||||
{
|
||||
IOManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager));
|
||||
this.fileDownloader = fileDownloader ?? throw new ArgumentNullException(nameof(fileDownloader));
|
||||
Logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
}
|
||||
|
||||
@@ -60,30 +53,11 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
public abstract ValueTask UpgradeInstallation(ByondVersion version, string path, CancellationToken cancellationToken);
|
||||
|
||||
/// <inheritdoc />
|
||||
public async ValueTask<MemoryStream> DownloadVersion(ByondVersion version, CancellationToken cancellationToken)
|
||||
{
|
||||
CheckVersionValidity(version);
|
||||
|
||||
var url = await GetDownloadZipUrl(version, cancellationToken);
|
||||
Logger.LogTrace("Downloading {engineType} version {version} from {url}...", TargetEngineType, version, url);
|
||||
|
||||
await using var download = fileDownloader.DownloadFile(url, null);
|
||||
await using var buffer = new BufferedFileStreamProvider(
|
||||
await download.GetResult(cancellationToken));
|
||||
return await buffer.GetOwnedResult(cancellationToken);
|
||||
}
|
||||
public abstract ValueTask<IEngineInstallationData> DownloadVersion(ByondVersion version, JobProgressReporter jobProgressReporter, CancellationToken cancellationToken);
|
||||
|
||||
/// <inheritdoc />
|
||||
public abstract ValueTask TrustDmbPath(string fullDmbPath, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Create a <see cref="Uri"/> pointing to the location of the download for a given <paramref name="version"/>.
|
||||
/// </summary>
|
||||
/// <param name="version">The <see cref="ByondVersion"/> to create a <see cref="Uri"/> for.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
|
||||
/// <returns>A <see cref="ValueTask{TResult}"/> resulting in a new <see cref="Uri"/> pointing to the version download location.</returns>
|
||||
protected abstract ValueTask<Uri> GetDownloadZipUrl(ByondVersion version, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Check that a given <paramref name="version"/> is of type <see cref="EngineType.Byond"/>.
|
||||
/// </summary>
|
||||
|
||||
@@ -497,18 +497,24 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
var directoryCleanupTask = DirectoryCleanup();
|
||||
try
|
||||
{
|
||||
Stream versionZipStream;
|
||||
IEngineInstallationData engineInstallationData;
|
||||
if (customVersionStream == null)
|
||||
{
|
||||
if (progressReporter != null)
|
||||
progressReporter.StageName = "Downloading version";
|
||||
|
||||
versionZipStream = await engineInstaller.DownloadVersion(version, cancellationToken);
|
||||
engineInstallationData = await engineInstaller.DownloadVersion(version, progressReporter, cancellationToken);
|
||||
|
||||
progressReporter.ReportProgress(null);
|
||||
}
|
||||
else
|
||||
versionZipStream = customVersionStream;
|
||||
#pragma warning disable CA2000 // Dispose objects before losing scope, false positive
|
||||
engineInstallationData = new ZipStreamEngineInstallationData(
|
||||
ioManager,
|
||||
customVersionStream);
|
||||
#pragma warning restore CA2000 // Dispose objects before losing scope
|
||||
|
||||
await using (versionZipStream)
|
||||
await using (engineInstallationData)
|
||||
{
|
||||
if (progressReporter != null)
|
||||
progressReporter.StageName = "Cleaning target directory";
|
||||
@@ -516,10 +522,10 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
await directoryCleanupTask;
|
||||
|
||||
if (progressReporter != null)
|
||||
progressReporter.StageName = "Extracting zip";
|
||||
progressReporter.StageName = "Extracting data";
|
||||
|
||||
logger.LogTrace("Extracting downloaded BYOND zip to {extractPath}...", installFullPath);
|
||||
await ioManager.ZipToDirectory(installFullPath, versionZipStream, cancellationToken);
|
||||
logger.LogTrace("Extracting engine to {extractPath}...", installFullPath);
|
||||
await engineInstallationData.ExtractToPath(installFullPath, cancellationToken);
|
||||
}
|
||||
|
||||
if (progressReporter != null)
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Tgstation.Server.Host.Components.Engine
|
||||
{
|
||||
/// <summary>
|
||||
/// Wraps data containing an engine installation.
|
||||
/// </summary>
|
||||
interface IEngineInstallationData : IAsyncDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Extracts the installation to a given path.
|
||||
/// </summary>
|
||||
/// <param name="path">The full path to extract to.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
|
||||
/// <returns>A <see cref="Task"/> representing the running operation.</returns>
|
||||
Task ExtractToPath(string path, CancellationToken cancellationToken);
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Tgstation.Server.Api.Models.Internal;
|
||||
using Tgstation.Server.Host.Jobs;
|
||||
|
||||
namespace Tgstation.Server.Host.Components.Engine
|
||||
{
|
||||
@@ -22,10 +22,11 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
/// <summary>
|
||||
/// Download a given engine <paramref name="version"/>.
|
||||
/// </summary>
|
||||
/// <param name="version">The <see cref="ByondVersion"/> of BYOND to download.</param>
|
||||
/// <param name="version">The <see cref="ByondVersion"/> of the engine to download.</param>
|
||||
/// <param name="jobProgressReporter">The optional <see cref="JobProgressReporter"/> for the operation.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
|
||||
/// <returns>A <see cref="ValueTask{TResult}"/> resulting in a <see cref="MemoryStream"/> of the zipfile.</returns>
|
||||
ValueTask<MemoryStream> DownloadVersion(ByondVersion version, CancellationToken cancellationToken);
|
||||
/// <returns>A <see cref="ValueTask{TResult}"/> resulting in the <see cref="IEngineInstallationData"/> for the download.</returns>
|
||||
ValueTask<IEngineInstallationData> DownloadVersion(ByondVersion version, JobProgressReporter jobProgressReporter, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Does actions necessary to get an extracted installation working.
|
||||
|
||||
@@ -4,14 +4,16 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
using Tgstation.Server.Api.Models;
|
||||
using Tgstation.Server.Api.Models.Internal;
|
||||
using Tgstation.Server.Host.Common;
|
||||
using Tgstation.Server.Host.Components.Repository;
|
||||
using Tgstation.Server.Host.Configuration;
|
||||
using Tgstation.Server.Host.IO;
|
||||
using Tgstation.Server.Host.Jobs;
|
||||
using Tgstation.Server.Host.System;
|
||||
using Tgstation.Server.Host.Utils.GitHub;
|
||||
|
||||
namespace Tgstation.Server.Host.Components.Engine
|
||||
{
|
||||
@@ -20,6 +22,11 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
/// </summary>
|
||||
sealed class OpenDreamInstaller : EngineInstallerBase
|
||||
{
|
||||
/// <summary>
|
||||
/// The name of the subdirectory used for the <see cref="RepositoryEngineInstallationData"/>'s copy.
|
||||
/// </summary>
|
||||
private const string InstallationRepositorySubDirectory = "SourceRepo";
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override EngineType TargetEngineType => EngineType.OpenDream;
|
||||
|
||||
@@ -28,37 +35,43 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
/// </summary>
|
||||
readonly IPlatformIdentifier platformIdentifier;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="IGitHubService"/> for the <see cref="OpenDreamInstaller"/>.
|
||||
/// </summary>
|
||||
readonly IGitHubService gitHubService;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="IProcessExecutor"/> for the <see cref="OpenDreamInstaller"/>.
|
||||
/// </summary>
|
||||
readonly IProcessExecutor processExecutor;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="IRepositoryManager"/> for the OpenDream repository.
|
||||
/// </summary>
|
||||
readonly IRepositoryManager repositoryManager;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="GeneralConfiguration"/> for the <see cref="OpenDreamInstaller"/>.
|
||||
/// </summary>
|
||||
readonly GeneralConfiguration generalConfiguration;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="OpenDreamInstaller"/> class.
|
||||
/// </summary>
|
||||
/// <param name="ioManager">The <see cref="IIOManager"/> for the <see cref="EngineInstallerBase"/>.</param>
|
||||
/// <param name="fileDownloader">The <see cref="IFileDownloader"/> for the <see cref="EngineInstallerBase"/>.</param>
|
||||
/// <param name="logger">The <see cref="ILogger"/> for the <see cref="EngineInstallerBase"/>.</param>
|
||||
/// <param name="platformIdentifier">The value of <see cref="platformIdentifier"/>.</param>
|
||||
/// <param name="gitHubService">The value of <see cref="gitHubService"/>.</param>
|
||||
/// <param name="processExecutor">The value of <see cref="processExecutor"/>.</param>
|
||||
/// <param name="repositoryManager">The value of <see cref="repositoryManager"/>.</param>
|
||||
/// <param name="generalConfigurationOptions">The <see cref="IOptions{TOptions}"/> containing value of <see cref="generalConfiguration"/>.</param>
|
||||
public OpenDreamInstaller(
|
||||
IIOManager ioManager,
|
||||
IFileDownloader fileDownloader,
|
||||
ILogger<OpenDreamInstaller> logger,
|
||||
IPlatformIdentifier platformIdentifier,
|
||||
IGitHubService gitHubService,
|
||||
IProcessExecutor processExecutor)
|
||||
: base(ioManager, fileDownloader, logger)
|
||||
IProcessExecutor processExecutor,
|
||||
IRepositoryManager repositoryManager,
|
||||
IOptions<GeneralConfiguration> generalConfigurationOptions)
|
||||
: base(ioManager, logger)
|
||||
{
|
||||
this.platformIdentifier = platformIdentifier ?? throw new ArgumentNullException(nameof(platformIdentifier));
|
||||
this.gitHubService = gitHubService ?? throw new ArgumentNullException(nameof(gitHubService));
|
||||
this.processExecutor = processExecutor ?? throw new ArgumentNullException(nameof(processExecutor));
|
||||
this.repositoryManager = repositoryManager ?? throw new ArgumentNullException(nameof(repositoryManager));
|
||||
generalConfiguration = generalConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(generalConfigurationOptions));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -72,10 +85,63 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async ValueTask Install(ByondVersion version, string path, CancellationToken cancellationToken)
|
||||
public override async ValueTask<IEngineInstallationData> DownloadVersion(ByondVersion version, JobProgressReporter jobProgressReporter, CancellationToken cancellationToken)
|
||||
{
|
||||
CheckVersionValidity(version);
|
||||
ArgumentNullException.ThrowIfNull(path);
|
||||
|
||||
// get a lock on a system wide OD repo
|
||||
Logger.LogTrace("Cloning OD repo...");
|
||||
|
||||
var progressSection1 = jobProgressReporter.CreateSection("Updating OpenDream git repository", 0.5f);
|
||||
|
||||
var repo = await repositoryManager.CloneRepository(
|
||||
generalConfiguration.OpenDreamGitUrl,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
progressSection1,
|
||||
true,
|
||||
cancellationToken);
|
||||
|
||||
try
|
||||
{
|
||||
if (repo == null)
|
||||
{
|
||||
Logger.LogTrace("OD repo seems to already exist, attempting load and fetch...");
|
||||
repo = await repositoryManager.LoadRepository(cancellationToken);
|
||||
|
||||
await repo.FetchOrigin(
|
||||
progressSection1,
|
||||
null,
|
||||
null,
|
||||
false,
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
var progressSection2 = jobProgressReporter.CreateSection("Checking out OpenDream version", 0.5f);
|
||||
|
||||
await repo.CheckoutObject(
|
||||
version.SourceCommittish,
|
||||
null,
|
||||
null,
|
||||
true,
|
||||
progressSection2,
|
||||
cancellationToken);
|
||||
|
||||
return new RepositoryEngineInstallationData(IOManager, repo, InstallationRepositorySubDirectory);
|
||||
}
|
||||
catch
|
||||
{
|
||||
repo?.Dispose();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async ValueTask Install(ByondVersion version, string installPath, CancellationToken cancellationToken)
|
||||
{
|
||||
CheckVersionValidity(version);
|
||||
ArgumentNullException.ThrowIfNull(installPath);
|
||||
|
||||
var dotnetPaths = DotnetHelper.GetPotentialDotnetPaths(platformIdentifier.IsWindows)
|
||||
.ToList();
|
||||
@@ -92,8 +158,33 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
|
||||
var dotnetPath = dotnetPaths[selectedPathIndex];
|
||||
|
||||
await Task.Yield();
|
||||
throw new NotImplementedException();
|
||||
var repositoryPath = IOManager.ConcatPath(installPath, InstallationRepositorySubDirectory);
|
||||
|
||||
await using (var buildProcess = processExecutor.LaunchProcess(
|
||||
dotnetPath,
|
||||
repositoryPath,
|
||||
"build -c Release",
|
||||
null,
|
||||
true,
|
||||
true))
|
||||
{
|
||||
var buildExitCode = await buildProcess.Lifetime;
|
||||
if (buildExitCode != 0)
|
||||
throw new JobException("OpenDream build failed!");
|
||||
}
|
||||
|
||||
const string BinDirectory = "bin";
|
||||
await IOManager.MoveDirectory(
|
||||
IOManager.ConcatPath(
|
||||
repositoryPath,
|
||||
BinDirectory,
|
||||
"Content.Server"),
|
||||
IOManager.ConcatPath(
|
||||
installPath,
|
||||
BinDirectory),
|
||||
cancellationToken);
|
||||
|
||||
await IOManager.DeleteDirectory(repositoryPath, cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -110,21 +201,5 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
ArgumentNullException.ThrowIfNull(fullDmbPath);
|
||||
return ValueTask.CompletedTask;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override async ValueTask<Uri> GetDownloadZipUrl(ByondVersion version, CancellationToken cancellationToken)
|
||||
{
|
||||
throw new NotImplementedException("This won't work because of the goddamn fucking robust toolbox submodule");
|
||||
var fullCommit = await gitHubService.GetCommit("OpenDreamProject", "OpenDream", version.SourceCommittish, cancellationToken);
|
||||
|
||||
if (fullCommit.Sha != version.SourceCommittish)
|
||||
{
|
||||
Logger.LogInformation("Replacing committish {committish} with full SHA {sha}...", version.SourceCommittish, fullCommit.Sha);
|
||||
version.SourceCommittish = fullCommit.Sha;
|
||||
}
|
||||
|
||||
var gitHubDownloadUrlString = $"https://codeload.github.com/OpenDreamProject/OpenDream/zip/{version.SourceCommittish}";
|
||||
return new Uri(gitHubDownloadUrlString);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
IIOManager ioManager,
|
||||
IFileDownloader fileDownloader,
|
||||
ILogger<PosixByondInstaller> logger)
|
||||
: base(ioManager, fileDownloader, logger)
|
||||
: base(ioManager, logger, fileDownloader)
|
||||
{
|
||||
this.postWriteHandler = postWriteHandler ?? throw new ArgumentNullException(nameof(postWriteHandler));
|
||||
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Tgstation.Server.Host.Components.Repository;
|
||||
using Tgstation.Server.Host.IO;
|
||||
|
||||
namespace Tgstation.Server.Host.Components.Engine
|
||||
{
|
||||
/// <summary>
|
||||
/// Implementation of <see cref="IEngineInstallationData"/> using a <see cref="IRepository"/>.
|
||||
/// </summary>
|
||||
sealed class RepositoryEngineInstallationData : IEngineInstallationData
|
||||
{
|
||||
/// <summary>
|
||||
/// The <see cref="IIOManager"/> for the <see cref="RepositoryEngineInstallationData"/>.
|
||||
/// </summary>
|
||||
readonly IIOManager ioManager;
|
||||
|
||||
/// <summary>
|
||||
/// The backing <see cref="IRepository"/>.
|
||||
/// </summary>
|
||||
readonly IRepository repository;
|
||||
|
||||
/// <summary>
|
||||
/// The name of the subdirectory the <see cref="repository"/> is copied to.
|
||||
/// </summary>
|
||||
readonly string targetSubDirectory;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RepositoryEngineInstallationData"/> class.
|
||||
/// </summary>
|
||||
/// <param name="ioManager">The value of <see cref="ioManager"/>.</param>
|
||||
/// <param name="repository">The value of <see cref="repository"/>.</param>
|
||||
/// <param name="targetSubDirectory">The value of <see cref="targetSubDirectory"/>.</param>
|
||||
public RepositoryEngineInstallationData(IIOManager ioManager, IRepository repository, string targetSubDirectory)
|
||||
{
|
||||
this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager));
|
||||
this.repository = repository ?? throw new ArgumentNullException(nameof(repository));
|
||||
this.targetSubDirectory = targetSubDirectory ?? throw new ArgumentNullException(nameof(targetSubDirectory));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ValueTask DisposeAsync()
|
||||
{
|
||||
repository.Dispose();
|
||||
return ValueTask.CompletedTask;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task ExtractToPath(string path, CancellationToken cancellationToken)
|
||||
=> repository.CopyTo(
|
||||
ioManager.ConcatPath(
|
||||
path,
|
||||
targetSubDirectory),
|
||||
cancellationToken)
|
||||
.AsTask();
|
||||
}
|
||||
}
|
||||
@@ -96,7 +96,7 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
IFileDownloader fileDownloader,
|
||||
IOptions<GeneralConfiguration> generalConfigurationOptions,
|
||||
ILogger<WindowsByondInstaller> logger)
|
||||
: base(ioManager, fileDownloader, logger)
|
||||
: base(ioManager, logger, fileDownloader)
|
||||
{
|
||||
this.processExecutor = processExecutor ?? throw new ArgumentNullException(nameof(processExecutor));
|
||||
generalConfiguration = generalConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(generalConfigurationOptions));
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Tgstation.Server.Host.IO;
|
||||
|
||||
namespace Tgstation.Server.Host.Components.Engine
|
||||
{
|
||||
/// <summary>
|
||||
/// Implementation of <see cref="IEngineInstallationData"/> for a zip file in a <see cref="Stream"/>.
|
||||
/// </summary>
|
||||
sealed class ZipStreamEngineInstallationData : IEngineInstallationData
|
||||
{
|
||||
/// <summary>
|
||||
/// The <see cref="IIOManager"/> for the <see cref="ZipStreamEngineInstallationData"/>.
|
||||
/// </summary>
|
||||
readonly IIOManager ioManager;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="MemoryStream"/> containing the zip data of the engine.
|
||||
/// </summary>
|
||||
readonly Stream zipStream;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ZipStreamEngineInstallationData"/> class.
|
||||
/// </summary>
|
||||
/// <param name="ioManager">The value of <see cref="ioManager"/>.</param>
|
||||
/// <param name="zipStream">The value of <see cref="zipStream"/>.</param>
|
||||
public ZipStreamEngineInstallationData(IIOManager ioManager, Stream zipStream)
|
||||
{
|
||||
this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager));
|
||||
this.zipStream = zipStream ?? throw new ArgumentNullException(nameof(zipStream));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ValueTask DisposeAsync() => zipStream.DisposeAsync();
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task ExtractToPath(string path, CancellationToken cancellationToken)
|
||||
=> ioManager.ZipToDirectory(path, zipStream, cancellationToken);
|
||||
}
|
||||
}
|
||||
@@ -61,6 +61,11 @@ namespace Tgstation.Server.Host.Configuration
|
||||
/// </summary>
|
||||
const uint DefaultShutdownTimeoutMinutes = 300;
|
||||
|
||||
/// <summary>
|
||||
/// The default value for <see cref="OpenDreamGitUrl"/>.
|
||||
/// </summary>
|
||||
const string DefaultOpenDreamGitUrl = "https://github.com/OpenDreamProject/OpenDream";
|
||||
|
||||
/// <summary>
|
||||
/// The current <see cref="ConfigVersion"/>.
|
||||
/// </summary>
|
||||
@@ -122,6 +127,11 @@ namespace Tgstation.Server.Host.Configuration
|
||||
/// </summary>
|
||||
public uint? DeploymentDirectoryCopyTasksPerCore { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Location of a publically accessible OpenDream repository.
|
||||
/// </summary>
|
||||
public Uri OpenDreamGitUrl { get; set; } = new Uri(DefaultOpenDreamGitUrl);
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="GeneralConfiguration"/> class.
|
||||
/// </summary>
|
||||
|
||||
@@ -4,6 +4,7 @@ using Moq;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Tgstation.Server.Api.Models;
|
||||
@@ -51,7 +52,7 @@ namespace Tgstation.Server.Host.Components.Engine.Tests
|
||||
var mockFileDownloader = new Mock<IFileDownloader>();
|
||||
var installer = new PosixByondInstaller(mockPostWriteHandler.Object, mockIOManager.Object, mockFileDownloader.Object, mockLogger.Object);
|
||||
|
||||
await Assert.ThrowsExceptionAsync<ArgumentNullException>(() => installer.DownloadVersion(null, default).AsTask());
|
||||
await Assert.ThrowsExceptionAsync<ArgumentNullException>(() => installer.DownloadVersion(null, null, default).AsTask());
|
||||
|
||||
var ourArray = Array.Empty<byte>();
|
||||
mockFileDownloader
|
||||
@@ -64,15 +65,20 @@ namespace Tgstation.Server.Host.Components.Engine.Tests
|
||||
new MemoryStream(ourArray)))
|
||||
.Verifiable();
|
||||
|
||||
var result = await installer.DownloadVersion(new ByondVersion
|
||||
var result = ExtractMemoryStreamFromInstallationData(await installer.DownloadVersion(new ByondVersion
|
||||
{
|
||||
Engine = EngineType.Byond,
|
||||
Version = new Version(123, 252345),
|
||||
}, default);
|
||||
}, null, default));
|
||||
|
||||
Assert.IsTrue(ourArray.SequenceEqual(result.ToArray()));
|
||||
mockIOManager.Verify();
|
||||
}
|
||||
static MemoryStream ExtractMemoryStreamFromInstallationData(IEngineInstallationData engineInstallationData)
|
||||
{
|
||||
var zipStreamData = (ZipStreamEngineInstallationData)engineInstallationData;
|
||||
return (MemoryStream)zipStreamData.GetType().GetField("stream", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(zipStreamData);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task TestInstallByond()
|
||||
|
||||
@@ -254,7 +254,7 @@ namespace Tgstation.Server.Tests.Live.Instance
|
||||
using var windowsByondInstaller = byondInstaller as WindowsByondInstaller;
|
||||
|
||||
// get the bytes for stable
|
||||
using var stableBytesMs = await byondInstaller.DownloadVersion(testVersion, cancellationToken);
|
||||
using var stableBytesMs = TestingUtils.ExtractMemoryStreamFromInstallationData(await byondInstaller.DownloadVersion(testVersion, null, cancellationToken));
|
||||
|
||||
var test = await byondClient.SetActiveVersion(
|
||||
new ByondVersionRequest
|
||||
|
||||
@@ -158,7 +158,7 @@ namespace Tgstation.Server.Tests.Live.Instance
|
||||
|
||||
// get the bytes for stable
|
||||
ByondInstallResponse installJob2;
|
||||
using (var stableBytesMs = await byondInstaller.DownloadVersion(compatVersion, cancellationToken))
|
||||
using (var stableBytesMs = TestingUtils.ExtractMemoryStreamFromInstallationData(await byondInstaller.DownloadVersion(compatVersion, null, cancellationToken)))
|
||||
{
|
||||
installJob2 = await instanceClient.Byond.SetActiveVersion(new ByondVersionRequest
|
||||
{
|
||||
|
||||
@@ -127,13 +127,15 @@ namespace Tgstation.Server.Tests
|
||||
|
||||
const string ArchiveEntryPath = "byond/bin/dd.exe";
|
||||
var hasEntry = ArchiveHasFileEntry(
|
||||
await byondInstaller.DownloadVersion(
|
||||
new ByondVersion
|
||||
{
|
||||
Engine = EngineType.Byond,
|
||||
Version = WindowsByondInstaller.DDExeVersion
|
||||
},
|
||||
default),
|
||||
TestingUtils.ExtractMemoryStreamFromInstallationData(
|
||||
await byondInstaller.DownloadVersion(
|
||||
new ByondVersion
|
||||
{
|
||||
Engine = EngineType.Byond,
|
||||
Version = WindowsByondInstaller.DDExeVersion
|
||||
},
|
||||
null,
|
||||
default)),
|
||||
ArchiveEntryPath);
|
||||
|
||||
Assert.IsTrue(hasEntry);
|
||||
@@ -218,13 +220,15 @@ namespace Tgstation.Server.Tests
|
||||
Engine = EngineType.Byond,
|
||||
Version = MapThreadsVersion(),
|
||||
},
|
||||
await byondInstaller.DownloadVersion(
|
||||
new ByondVersion
|
||||
{
|
||||
Engine = EngineType.Byond,
|
||||
Version = MapThreadsVersion()
|
||||
},
|
||||
default),
|
||||
TestingUtils.ExtractMemoryStreamFromInstallationData(
|
||||
await byondInstaller.DownloadVersion(
|
||||
new ByondVersion
|
||||
{
|
||||
Engine = EngineType.Byond,
|
||||
Version = MapThreadsVersion()
|
||||
},
|
||||
null,
|
||||
default)),
|
||||
byondInstaller,
|
||||
ioManager,
|
||||
processExecutor,
|
||||
@@ -400,7 +404,7 @@ namespace Tgstation.Server.Tests
|
||||
Assert.AreEqual(latestMigrationSL, DatabaseContext.SLLatestMigration);
|
||||
}
|
||||
|
||||
static async Task<Tuple<MemoryStream, ByondVersion>> GetByondVersionPriorTo(IEngineInstaller byondInstaller, Version version)
|
||||
static async Task<Tuple<MemoryStream, ByondVersion>> GetByondVersionPriorTo(ByondInstallerBase byondInstaller, Version version)
|
||||
{
|
||||
var minusOneMinor = new Version(version.Major, version.Minor - 1);
|
||||
var byondVersion = new ByondVersion
|
||||
@@ -410,17 +414,19 @@ namespace Tgstation.Server.Tests
|
||||
};
|
||||
try
|
||||
{
|
||||
return Tuple.Create(await byondInstaller.DownloadVersion(
|
||||
return Tuple.Create(TestingUtils.ExtractMemoryStreamFromInstallationData(await byondInstaller.DownloadVersion(
|
||||
byondVersion,
|
||||
CancellationToken.None), byondVersion);
|
||||
null,
|
||||
CancellationToken.None)), byondVersion);
|
||||
}
|
||||
catch (HttpRequestException)
|
||||
{
|
||||
var minusOneMajor = new Version(minusOneMinor.Major - 1, minusOneMinor.Minor);
|
||||
byondVersion.Version = minusOneMajor;
|
||||
return Tuple.Create(await byondInstaller.DownloadVersion(
|
||||
return Tuple.Create(TestingUtils.ExtractMemoryStreamFromInstallationData(await byondInstaller.DownloadVersion(
|
||||
byondVersion,
|
||||
CancellationToken.None), byondVersion);
|
||||
null,
|
||||
CancellationToken.None)), byondVersion);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
using Moq;
|
||||
|
||||
using Tgstation.Server.Host.Components.Engine;
|
||||
|
||||
namespace Tgstation.Server.Tests
|
||||
{
|
||||
static class TestingUtils
|
||||
@@ -25,5 +28,11 @@ namespace Tgstation.Server.Tests
|
||||
.Verifiable();
|
||||
return mockLoggerFactory.Object;
|
||||
}
|
||||
|
||||
public static MemoryStream ExtractMemoryStreamFromInstallationData(IEngineInstallationData engineInstallationData)
|
||||
{
|
||||
var zipStreamData = (ZipStreamEngineInstallationData)engineInstallationData;
|
||||
return (MemoryStream)zipStreamData.GetType().GetField("stream", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(zipStreamData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user