Add support for additional compiler arguments

Closes #1807
This commit is contained in:
Jordan Dominion
2024-04-20 12:20:28 -04:00
parent 94ca8d38d1
commit 3da68fe323
26 changed files with 4606 additions and 23 deletions
+3 -3
View File
@@ -5,10 +5,10 @@
<PropertyGroup>
<TgsCoreVersion>6.4.1</TgsCoreVersion>
<TgsConfigVersion>5.1.0</TgsConfigVersion>
<TgsApiVersion>10.2.0</TgsApiVersion>
<TgsApiVersion>10.3.0</TgsApiVersion>
<TgsCommonLibraryVersion>7.0.0</TgsCommonLibraryVersion>
<TgsApiLibraryVersion>13.2.0</TgsApiLibraryVersion>
<TgsClientVersion>15.2.0</TgsClientVersion>
<TgsApiLibraryVersion>13.3.0</TgsApiLibraryVersion>
<TgsClientVersion>15.3.0</TgsClientVersion>
<TgsDmapiVersion>7.1.2</TgsDmapiVersion>
<TgsInteropVersion>5.9.0</TgsInteropVersion>
<TgsHostWatchdogVersion>1.4.1</TgsHostWatchdogVersion>
@@ -39,5 +39,12 @@ namespace Tgstation.Server.Api.Models.Internal
/// </summary>
[Required]
public TimeSpan? Timeout { get; set; }
/// <summary>
/// Additional arguments added to the compiler command line.
/// </summary>
[StringLength(Limits.MaximumStringLength)]
[ResponseOptions]
public string? CompilerAdditionalArguments { get; set; }
}
}
@@ -57,5 +57,10 @@ namespace Tgstation.Server.Api.Rights
/// User may modify <see cref="Models.Internal.DreamMakerSettings.Timeout"/>.
/// </summary>
SetTimeout = 1 << 8,
/// <summary>
/// User may modify <see cref="Models.Internal.DreamMakerSettings.CompilerAdditionalArguments"/>.
/// </summary>
SetCompilerArguments = 1 << 9,
}
}
@@ -632,7 +632,7 @@ namespace Tgstation.Server.Host.Components.Deployment
// run compiler
progressReporter.StageName = "Running Compiler";
var compileSuceeded = await RunDreamMaker(engineLock, job, cancellationToken);
var compileSuceeded = await RunDreamMaker(engineLock, job, dreamMakerSettings.CompilerAdditionalArguments, cancellationToken);
// Session takes ownership of the lock and Disposes it so save this for later
var engineVersion = engineLock.Version;
@@ -850,12 +850,17 @@ namespace Tgstation.Server.Host.Components.Deployment
/// </summary>
/// <param name="engineLock">The <see cref="IEngineExecutableLock"/> to use.</param>
/// <param name="job">The <see cref="CompileJob"/> for the operation.</param>
/// <param name="additionalCompilerArguments">Additional arguments to be added to the compiler.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
/// <returns>A <see cref="ValueTask{TResult}"/> resulting in <see langword="true"/> if compilation succeeded, <see langword="false"/> otherwise.</returns>
async ValueTask<bool> RunDreamMaker(IEngineExecutableLock engineLock, Models.CompileJob job, CancellationToken cancellationToken)
async ValueTask<bool> RunDreamMaker(
IEngineExecutableLock engineLock,
Models.CompileJob job,
string? additionalCompilerArguments,
CancellationToken cancellationToken)
{
var environment = await engineLock.LoadEnv(logger, true, cancellationToken);
var arguments = engineLock.FormatCompilerArguments($"{job.DmeName}.{DmeExtension}");
var arguments = engineLock.FormatCompilerArguments($"{job.DmeName}.{DmeExtension}", additionalCompilerArguments);
await using var dm = await processExecutor.LaunchProcess(
engineLock.CompilerExePath,
@@ -147,7 +147,14 @@ namespace Tgstation.Server.Host.Components.Engine
}
/// <inheritdoc />
public override string FormatCompilerArguments(string dmePath)
=> $"-clean \"{dmePath ?? throw new ArgumentNullException(nameof(dmePath))}\"";
public override string FormatCompilerArguments(string dmePath, string? additionalArguments)
{
if (String.IsNullOrWhiteSpace(additionalArguments))
additionalArguments = String.Empty;
else
additionalArguments = $"{additionalArguments.Trim()} ";
return $"-clean {additionalArguments}\"{dmePath ?? throw new ArgumentNullException(nameof(dmePath))}\"";
}
}
}
@@ -55,7 +55,7 @@ namespace Tgstation.Server.Host.Components.Engine
logFilePath);
/// <inheritdoc />
public string FormatCompilerArguments(string dmePath) => Instance.FormatCompilerArguments(dmePath);
public string FormatCompilerArguments(string dmePath, string? additionalArguments) => Instance.FormatCompilerArguments(dmePath, additionalArguments);
/// <inheritdoc />
public ValueTask StopServerProcess(ILogger logger, IProcess process, string accessIdentifier, ushort port, CancellationToken cancellationToken)
@@ -78,7 +78,7 @@ namespace Tgstation.Server.Host.Components.Engine
}
/// <inheritdoc />
public abstract string FormatCompilerArguments(string dmePath);
public abstract string FormatCompilerArguments(string dmePath, string? additionalArguments);
/// <inheritdoc />
public abstract string FormatServerArguments(
@@ -74,8 +74,9 @@ namespace Tgstation.Server.Host.Components.Engine
/// Return the command line arguments for compiling a given <paramref name="dmePath"/> if compilation is necessary.
/// </summary>
/// <param name="dmePath">The full path to the .dme to compile.</param>
/// <param name="additionalArguments">Optional additional arguments provided to the compiler.</param>
/// <returns>The formatted arguments <see cref="string"/>.</returns>
string FormatCompilerArguments(string dmePath);
string FormatCompilerArguments(string dmePath, string? additionalArguments);
/// <summary>
/// Kills a given engine server <paramref name="process"/>.
@@ -112,8 +112,15 @@ namespace Tgstation.Server.Host.Components.Engine
}
/// <inheritdoc />
public override string FormatCompilerArguments(string dmePath)
=> $"--suppress-unimplemented --notices-enabled \"{dmePath ?? throw new ArgumentNullException(nameof(dmePath))}\"";
public override string FormatCompilerArguments(string dmePath, string? additionalArguments)
{
if (String.IsNullOrWhiteSpace(additionalArguments))
additionalArguments = String.Empty;
else
additionalArguments = $"{additionalArguments.Trim()} ";
return $"--suppress-unimplemented --notices-enabled {additionalArguments}\"{dmePath ?? throw new ArgumentNullException(nameof(dmePath))}\"";
}
/// <inheritdoc />
public override async ValueTask StopServerProcess(
@@ -171,7 +171,8 @@ namespace Tgstation.Server.Host.Controllers
| DreamMakerRights.SetApiValidationPort
| DreamMakerRights.SetSecurityLevel
| DreamMakerRights.SetApiValidationRequirement
| DreamMakerRights.SetTimeout)]
| DreamMakerRights.SetTimeout
| DreamMakerRights.SetCompilerArguments)]
[ProducesResponseType(typeof(DreamMakerResponse), 200)]
[ProducesResponseType(204)]
[ProducesResponseType(typeof(ErrorMessageResponse), 410)]
@@ -196,7 +197,8 @@ namespace Tgstation.Server.Host.Controllers
{
if (!dreamMakerRights.HasFlag(DreamMakerRights.SetDme))
return Forbid();
if (model.ProjectName.Length == 0)
if (model.ProjectName.Length == 0) // can't use isnullorwhitespace because linux memes
hostModel.ProjectName = null;
else
hostModel.ProjectName = model.ProjectName;
@@ -230,6 +232,7 @@ namespace Tgstation.Server.Host.Controllers
{
if (!dreamMakerRights.HasFlag(DreamMakerRights.SetSecurityLevel))
return Forbid();
hostModel.ApiValidationSecurityLevel = model.ApiValidationSecurityLevel;
}
@@ -237,6 +240,7 @@ namespace Tgstation.Server.Host.Controllers
{
if (!dreamMakerRights.HasFlag(DreamMakerRights.SetApiValidationRequirement))
return Forbid();
hostModel.RequireDMApiValidation = model.RequireDMApiValidation;
}
@@ -244,9 +248,22 @@ namespace Tgstation.Server.Host.Controllers
{
if (!dreamMakerRights.HasFlag(DreamMakerRights.SetTimeout))
return Forbid();
hostModel.Timeout = model.Timeout;
}
if (model.CompilerAdditionalArguments != null)
{
if (!dreamMakerRights.HasFlag(DreamMakerRights.SetCompilerArguments))
return Forbid();
var sanitizedArguments = model.CompilerAdditionalArguments.Trim();
if (sanitizedArguments.Length == 0)
hostModel.CompilerAdditionalArguments = null;
else
hostModel.CompilerAdditionalArguments = sanitizedArguments;
}
await DatabaseContext.Save(cancellationToken);
if (!dreamMakerRights.HasFlag(DreamMakerRights.Read))
@@ -740,6 +740,7 @@ namespace Tgstation.Server.Host.Controllers
ApiValidationSecurityLevel = DreamDaemonSecurity.Safe,
RequireDMApiValidation = true,
Timeout = TimeSpan.FromHours(1),
CompilerAdditionalArguments = null,
},
Name = initialSettings.Name,
Online = false,
@@ -375,22 +375,22 @@ namespace Tgstation.Server.Host.Database
/// <summary>
/// Used by unit tests to remind us to setup the correct MSSQL migration downgrades.
/// </summary>
internal static readonly Type MSLatestMigration = typeof(MSAddMinidumpsOption);
internal static readonly Type MSLatestMigration = typeof(MSAddCompilerAdditionalArguments);
/// <summary>
/// Used by unit tests to remind us to setup the correct MYSQL migration downgrades.
/// </summary>
internal static readonly Type MYLatestMigration = typeof(MYAddMinidumpsOption);
internal static readonly Type MYLatestMigration = typeof(MYAddCompilerAdditionalArguments);
/// <summary>
/// Used by unit tests to remind us to setup the correct PostgresSQL migration downgrades.
/// </summary>
internal static readonly Type PGLatestMigration = typeof(PGAddMinidumpsOption);
internal static readonly Type PGLatestMigration = typeof(PGAddCompilerAdditionalArguments);
/// <summary>
/// Used by unit tests to remind us to setup the correct SQLite migration downgrades.
/// </summary>
internal static readonly Type SLLatestMigration = typeof(SLAddMinidumpsOption);
internal static readonly Type SLLatestMigration = typeof(SLAddCompilerAdditionalArguments);
/// <inheritdoc />
#pragma warning disable CA1502 // Cyclomatic complexity
@@ -419,6 +419,16 @@ namespace Tgstation.Server.Host.Database
string BadDatabaseType() => throw new ArgumentException($"Invalid DatabaseType: {currentDatabaseType}", nameof(currentDatabaseType));
if (targetVersion < new Version(6, 5, 0))
targetMigration = currentDatabaseType switch
{
DatabaseType.MySql => nameof(MYAddMinidumpsOption),
DatabaseType.PostgresSql => nameof(PGAddMinidumpsOption),
DatabaseType.SqlServer => nameof(MSAddMinidumpsOption),
DatabaseType.Sqlite => nameof(SLAddMinidumpsOption),
_ => BadDatabaseType(),
};
if (targetVersion < new Version(6, 2, 0))
targetMigration = currentDatabaseType switch
{
@@ -0,0 +1,33 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
namespace Tgstation.Server.Host.Database.Migrations
{
/// <inheritdoc />
public partial class MSAddCompilerAdditionalArguments : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
ArgumentNullException.ThrowIfNull(migrationBuilder);
migrationBuilder.AddColumn<string>(
name: "CompilerAdditionalArguments",
table: "DreamMakerSettings",
type: "nvarchar(max)",
maxLength: 10000,
nullable: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
ArgumentNullException.ThrowIfNull(migrationBuilder);
migrationBuilder.DropColumn(
name: "CompilerAdditionalArguments",
table: "DreamMakerSettings");
}
}
}
@@ -0,0 +1,34 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
namespace Tgstation.Server.Host.Database.Migrations
{
/// <inheritdoc />
public partial class MYAddCompilerAdditionalArguments : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
ArgumentNullException.ThrowIfNull(migrationBuilder);
migrationBuilder.AddColumn<string>(
name: "CompilerAdditionalArguments",
table: "DreamMakerSettings",
type: "varchar(10000)",
maxLength: 10000,
nullable: true)
.Annotation("MySql:CharSet", "utf8mb4");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
ArgumentNullException.ThrowIfNull(migrationBuilder);
migrationBuilder.DropColumn(
name: "CompilerAdditionalArguments",
table: "DreamMakerSettings");
}
}
}
@@ -0,0 +1,33 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
namespace Tgstation.Server.Host.Database.Migrations
{
/// <inheritdoc />
public partial class PGAddCompilerAdditionalArguments : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
ArgumentNullException.ThrowIfNull(migrationBuilder);
migrationBuilder.AddColumn<string>(
name: "CompilerAdditionalArguments",
table: "DreamMakerSettings",
type: "character varying(10000)",
maxLength: 10000,
nullable: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
ArgumentNullException.ThrowIfNull(migrationBuilder);
migrationBuilder.DropColumn(
name: "CompilerAdditionalArguments",
table: "DreamMakerSettings");
}
}
}
@@ -0,0 +1,33 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
namespace Tgstation.Server.Host.Database.Migrations
{
/// <inheritdoc />
public partial class SLAddCompilerAdditionalArguments : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
ArgumentNullException.ThrowIfNull(migrationBuilder);
migrationBuilder.AddColumn<string>(
name: "CompilerAdditionalArguments",
table: "DreamMakerSettings",
type: "TEXT",
maxLength: 10000,
nullable: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
ArgumentNullException.ThrowIfNull(migrationBuilder);
migrationBuilder.DropColumn(
name: "CompilerAdditionalArguments",
table: "DreamMakerSettings");
}
}
}
@@ -278,6 +278,10 @@ namespace Tgstation.Server.Host.Database.Migrations
b.Property<int>("ApiValidationSecurityLevel")
.HasColumnType("int");
b.Property<string>("CompilerAdditionalArguments")
.HasMaxLength(10000)
.HasColumnType("varchar(10000)");
b.Property<long>("InstanceId")
.HasColumnType("bigint");
@@ -13,7 +13,7 @@ namespace Tgstation.Server.Host.Database.Migrations
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "8.0.1")
.HasAnnotation("ProductVersion", "8.0.4")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
@@ -254,6 +254,10 @@ namespace Tgstation.Server.Host.Database.Migrations
b.Property<int>("ApiValidationSecurityLevel")
.HasColumnType("integer");
b.Property<string>("CompilerAdditionalArguments")
.HasMaxLength(10000)
.HasColumnType("character varying(10000)");
b.Property<long>("InstanceId")
.HasColumnType("bigint");
@@ -13,7 +13,7 @@ namespace Tgstation.Server.Host.Database.Migrations
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "8.0.1")
.HasAnnotation("ProductVersion", "8.0.4")
.HasAnnotation("Relational:MaxIdentifierLength", 128);
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
@@ -256,6 +256,10 @@ namespace Tgstation.Server.Host.Database.Migrations
b.Property<int>("ApiValidationSecurityLevel")
.HasColumnType("int");
b.Property<string>("CompilerAdditionalArguments")
.HasMaxLength(10000)
.HasColumnType("nvarchar(max)");
b.Property<long>("InstanceId")
.HasColumnType("bigint");
@@ -12,7 +12,7 @@ namespace Tgstation.Server.Host.Database.Migrations
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "8.0.1");
modelBuilder.HasAnnotation("ProductVersion", "8.0.4");
modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b =>
{
@@ -248,6 +248,10 @@ namespace Tgstation.Server.Host.Database.Migrations
b.Property<int>("ApiValidationSecurityLevel")
.HasColumnType("INTEGER");
b.Property<string>("CompilerAdditionalArguments")
.HasMaxLength(10000)
.HasColumnType("TEXT");
b.Property<long>("InstanceId")
.HasColumnType("INTEGER");
@@ -31,6 +31,7 @@ namespace Tgstation.Server.Host.Models
ApiValidationSecurityLevel = ApiValidationSecurityLevel,
RequireDMApiValidation = RequireDMApiValidation,
Timeout = Timeout,
CompilerAdditionalArguments = CompilerAdditionalArguments,
};
}
}
@@ -125,17 +125,24 @@ namespace Tgstation.Server.Tests.Live.Instance
{
ProjectName = "tests/DMAPI/ApiFree/api_free",
ApiValidationPort = dmPort,
CompilerAdditionalArguments = " ",
}, cancellationToken);
Assert.AreEqual(dmPort, updatedDM.ApiValidationPort);
Assert.AreEqual("tests/DMAPI/ApiFree/api_free", updatedDM.ProjectName);
Assert.IsNull(updatedDM.CompilerAdditionalArguments);
}
else
{
var updatedDM = await dreamMakerClient.Update(new DreamMakerRequest
{
ApiValidationPort = dmPort
ApiValidationPort = dmPort,
CompilerAdditionalArguments = testEngine == EngineType.Byond ? " -DBABABOOEY" : " ",
}, cancellationToken);
Assert.AreEqual(dmPort, updatedDM.ApiValidationPort);
if (testEngine == EngineType.Byond)
Assert.AreEqual("-DBABABOOEY", updatedDM.CompilerAdditionalArguments);
else
Assert.IsNull(updatedDM.CompilerAdditionalArguments);
}
Console.WriteLine($"PORT REUSE BUG 1: Setting I-{instanceClient.Metadata.Id} DD to {ddPort}");