feat: drive Preview automation through AutoCAD script
This commit is contained in:
@@ -16,7 +16,14 @@ public sealed class StartupScriptBuilder : IStartupScriptBuilder
|
|||||||
{
|
{
|
||||||
public string BuildNetloadScript(string root, string entry)
|
public string BuildNetloadScript(string root, string entry)
|
||||||
{ var full = Path.GetFullPath(Path.Combine(root, entry)); if (!full.StartsWith(Path.GetFullPath(root) + Path.DirectorySeparatorChar, StringComparison.OrdinalIgnoreCase) || !File.Exists(full)) throw new InvalidOperationException("UNTRUSTED_ENTRY_PATH"); return $"_.NETLOAD\n\"{full.Replace("\"", "\\\"")}\"\n"; }
|
{ var full = Path.GetFullPath(Path.Combine(root, entry)); if (!full.StartsWith(Path.GetFullPath(root) + Path.DirectorySeparatorChar, StringComparison.OrdinalIgnoreCase) || !File.Exists(full)) throw new InvalidOperationException("UNTRUSTED_ENTRY_PATH"); return $"_.NETLOAD\n\"{full.Replace("\"", "\\\"")}\"\n"; }
|
||||||
public string BuildAutomationScript(string root, string entry) => BuildNetloadScript(root, entry) + "PHP_REC_AUTOMATION_START\n";
|
public string BuildAutomationScript(string root, string entry, string fixtureOrthoDwg)
|
||||||
|
{
|
||||||
|
var fixture = Path.GetFullPath(fixtureOrthoDwg);
|
||||||
|
if (!File.Exists(fixture)) throw new InvalidOperationException("AUTOMATION_FIXTURE_NOT_FOUND");
|
||||||
|
var quote = (string value) => "\"" + value.Replace("\"", "\\\"") + "\"";
|
||||||
|
return "_.OPEN\n" + quote(fixture) + "\n" + BuildNetloadScript(root, entry) +
|
||||||
|
"PHP_REC_AUTOMATION_PREPARE\nPXP-OA\nPXP-OA\nPHP_REC_AUTOMATION_FINALIZE\n";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
public sealed class DryRunAutodeskProcessLauncher : IAutodeskProcessLauncher
|
public sealed class DryRunAutodeskProcessLauncher : IAutodeskProcessLauncher
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ public interface ILocalPackageStore { Task<string?> GetCurrentVersionAsync(strin
|
|||||||
public interface IPackageActivator { Task<ActivationResult> ActivateAsync(string packageId, string version, CancellationToken cancellationToken); }
|
public interface IPackageActivator { Task<ActivationResult> ActivateAsync(string packageId, string version, CancellationToken cancellationToken); }
|
||||||
public interface IRollbackManager { Task<string?> RollbackAsync(string packageId, CancellationToken cancellationToken); }
|
public interface IRollbackManager { Task<string?> RollbackAsync(string packageId, CancellationToken cancellationToken); }
|
||||||
public interface IAutodeskProcessLauncher { PreparedLaunch Prepare(LaunchRequest request); }
|
public interface IAutodeskProcessLauncher { PreparedLaunch Prepare(LaunchRequest request); }
|
||||||
public interface IStartupScriptBuilder { string BuildNetloadScript(string validatedPackageRoot, string entryAssembly); string BuildAutomationScript(string validatedPackageRoot, string entryAssembly); }
|
public interface IStartupScriptBuilder { string BuildNetloadScript(string validatedPackageRoot, string entryAssembly); string BuildAutomationScript(string validatedPackageRoot, string entryAssembly, string fixtureOrthoDwg); }
|
||||||
public interface ILauncherConfigurationProvider { LauncherMode GetMode(); }
|
public interface ILauncherConfigurationProvider { LauncherMode GetMode(); }
|
||||||
public interface ILauncherTelemetry { void Write(string eventType, IReadOnlyDictionary<string, object?>? fields = null); }
|
public interface ILauncherTelemetry { void Write(string eventType, IReadOnlyDictionary<string, object?>? fields = null); }
|
||||||
public interface IClock { DateTimeOffset UtcNow { get; } }
|
public interface IClock { DateTimeOffset UtcNow { get; } }
|
||||||
|
|||||||
@@ -40,9 +40,10 @@ public sealed class PilotExecutionService(
|
|||||||
if (!safety.IsAllowed) return new(null, safety);
|
if (!safety.IsAllowed) return new(null, safety);
|
||||||
|
|
||||||
var futureEntry = Path.Combine(request.PilotRoot, "packages", request.Manifest.PackageId, "versions", request.Manifest.Version, request.Manifest.EntryAssembly);
|
var futureEntry = Path.Combine(request.PilotRoot, "packages", request.Manifest.PackageId, "versions", request.Manifest.Version, request.Manifest.EntryAssembly);
|
||||||
|
var fixture = request.Configuration.AutomationMode is null ? null : ReadFixtureOrtho(request.Configuration.AutomationConfigurationPath);
|
||||||
var content = request.Configuration.AutomationMode is null
|
var content = request.Configuration.AutomationMode is null
|
||||||
? $"_.NETLOAD\n\"{futureEntry.Replace("\"", "\\\"")}\"\n"
|
? $"_.NETLOAD\n\"{futureEntry.Replace("\"", "\\\"")}\"\n"
|
||||||
: $"_.NETLOAD\n\"{futureEntry.Replace("\"", "\\\"")}\"\nPHP_REC_AUTOMATION_START\n";
|
: $"_.OPEN\n\"{fixture!.Replace("\"", "\\\"")}\"\n_.NETLOAD\n\"{futureEntry.Replace("\"", "\\\"")}\"\nPHP_REC_AUTOMATION_PREPARE\nPXP-OA\nPXP-OA\nPHP_REC_AUTOMATION_FINALIZE\n";
|
||||||
var scriptHash = Convert.ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes(content)));
|
var scriptHash = Convert.ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes(content)));
|
||||||
var plan = PilotPlanFactory.Create(request.Product, profile, request.Manifest, request.ManifestHash, request.PilotRoot, request.StartupScriptPath, scriptHash, safety);
|
var plan = PilotPlanFactory.Create(request.Product, profile, request.Manifest, request.ManifestHash, request.PilotRoot, request.StartupScriptPath, scriptHash, safety);
|
||||||
var environment = new Dictionary<string, string> { ["P_REC_ANNOT_RUNTIME_MODE"] = request.Configuration.PluginExecutionMode.ToString() };
|
var environment = new Dictionary<string, string> { ["P_REC_ANNOT_RUNTIME_MODE"] = request.Configuration.PluginExecutionMode.ToString() };
|
||||||
@@ -50,6 +51,7 @@ public sealed class PilotExecutionService(
|
|||||||
environment["P_REC_ANNOT_APPLY_PERMIT_PATH"] = request.Configuration.ApplyPermitPath;
|
environment["P_REC_ANNOT_APPLY_PERMIT_PATH"] = request.Configuration.ApplyPermitPath;
|
||||||
if (request.Configuration.AutomationMode is not null)
|
if (request.Configuration.AutomationMode is not null)
|
||||||
{
|
{
|
||||||
|
environment["P_REC_ANNOT_LAUNCHER_MODE"] = "NextPilot";
|
||||||
environment["P_REC_ANNOT_AUTOMATION"] = request.Configuration.AutomationMode;
|
environment["P_REC_ANNOT_AUTOMATION"] = request.Configuration.AutomationMode;
|
||||||
environment["P_REC_ANNOT_AUTOMATION_CONFIG"] = request.Configuration.AutomationConfigurationPath!;
|
environment["P_REC_ANNOT_AUTOMATION_CONFIG"] = request.Configuration.AutomationConfigurationPath!;
|
||||||
}
|
}
|
||||||
@@ -104,7 +106,7 @@ public sealed class PilotExecutionService(
|
|||||||
Directory.CreateDirectory(Path.GetDirectoryName(scriptPath)!);
|
Directory.CreateDirectory(Path.GetDirectoryName(scriptPath)!);
|
||||||
var script = request.Preparation.Configuration.AutomationMode is null
|
var script = request.Preparation.Configuration.AutomationMode is null
|
||||||
? scriptBuilder.BuildNetloadScript(versionDirectory, request.Preparation.Manifest.EntryAssembly)
|
? scriptBuilder.BuildNetloadScript(versionDirectory, request.Preparation.Manifest.EntryAssembly)
|
||||||
: scriptBuilder.BuildAutomationScript(versionDirectory, request.Preparation.Manifest.EntryAssembly);
|
: scriptBuilder.BuildAutomationScript(versionDirectory, request.Preparation.Manifest.EntryAssembly, ReadFixtureOrtho(request.Preparation.Configuration.AutomationConfigurationPath));
|
||||||
await File.WriteAllTextAsync(scriptPath, script, cancellationToken);
|
await File.WriteAllTextAsync(scriptPath, script, cancellationToken);
|
||||||
await WriteSession(plan.PilotRoot, (await ReadSession(plan.PilotRoot, cancellationToken))! with { State = "ProcessStarting", UpdatedAtUtc = DateTimeOffset.UtcNow }, cancellationToken);
|
await WriteSession(plan.PilotRoot, (await ReadSession(plan.PilotRoot, cancellationToken))! with { State = "ProcessStarting", UpdatedAtUtc = DateTimeOffset.UtcNow }, cancellationToken);
|
||||||
var result = new GuardedAutodeskProcessLauncher(gate, probe, invoker).Start(context, plan with { StartupScriptPath = scriptPath, Process = plan.Process with { Arguments = ["/product", "PLNT3D", "/language", "ru-RU", "/b", scriptPath], WorkingDirectory = plan.PilotRoot } }, request.Permit, permits);
|
var result = new GuardedAutodeskProcessLauncher(gate, probe, invoker).Start(context, plan with { StartupScriptPath = scriptPath, Process = plan.Process with { Arguments = ["/product", "PLNT3D", "/language", "ru-RU", "/b", scriptPath], WorkingDirectory = plan.PilotRoot } }, request.Permit, permits);
|
||||||
@@ -124,6 +126,14 @@ public sealed class PilotExecutionService(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string ReadFixtureOrtho(string? automationConfigurationPath)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(automationConfigurationPath) || !File.Exists(automationConfigurationPath)) throw new InvalidOperationException("AUTOMATION_CONFIG_MISSING");
|
||||||
|
using var json = JsonDocument.Parse(File.ReadAllText(automationConfigurationPath));
|
||||||
|
if (!json.RootElement.TryGetProperty("orthoDrawingPath", out var value) || string.IsNullOrWhiteSpace(value.GetString())) throw new InvalidOperationException("AUTOMATION_ORTHO_PATH_REQUIRED");
|
||||||
|
return Path.GetFullPath(value.GetString()!);
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<PilotRollbackResult> RollbackAsync(PilotRollbackRequest request, CancellationToken cancellationToken)
|
public async Task<PilotRollbackResult> RollbackAsync(PilotRollbackRequest request, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
|||||||
Reference in New Issue
Block a user