From ea961f2455de253b96386ac2e70ea4498acc7aa1 Mon Sep 17 00:00:00 2001 From: codex Date: Tue, 4 Aug 2026 14:38:29 +0300 Subject: [PATCH] fix: open source model for script preview placement --- Launcher.Next.App/PilotCli.cs | 3 ++- Launcher.Next.Autodesk/AutodeskAdapters.cs | 4 +++- Launcher.Next.Core/Contracts.cs | 2 +- Launcher.Next.Core/LauncherPaths.cs | 1 + Launcher.Next.Infrastructure/PilotExecutionService.cs | 4 ++-- tests/Launcher.Next.Tests/PathAndLaunchTests.cs | 9 ++++++--- 6 files changed, 15 insertions(+), 8 deletions(-) diff --git a/Launcher.Next.App/PilotCli.cs b/Launcher.Next.App/PilotCli.cs index e463495..f30f3ce 100644 --- a/Launcher.Next.App/PilotCli.cs +++ b/Launcher.Next.App/PilotCli.cs @@ -238,7 +238,7 @@ internal static class PilotCli { var resolver = new PathResolver(); var variables = new LauncherPathVariables(configuration.PathVariables); var raw = resolver.Resolve(variables, [LauncherPathVariableNames.LocalLauncherRoot, LauncherPathVariableNames.AcadExecutable]); var resolved = new Dictionary(raw.Values, StringComparer.OrdinalIgnoreCase); - foreach (var name in new[] { LauncherPathVariableNames.LocalLauncherRoot, LauncherPathVariableNames.LocalPackageCache, LauncherPathVariableNames.LocalActiveRoot, LauncherPathVariableNames.LocalSessionRoot, LauncherPathVariableNames.LocalEvidenceRoot, LauncherPathVariableNames.LocalLogsRoot, LauncherPathVariableNames.LocalRollbackRoot, LauncherPathVariableNames.AcadExecutable, LauncherPathVariableNames.PRecEntryAssembly, LauncherPathVariableNames.FixtureOrthoDwg, LauncherPathVariableNames.AutomationScriptPath, LauncherPathVariableNames.AutomationConfigPath, LauncherPathVariableNames.AutomationEvidencePath, LauncherPathVariableNames.AutomationPermitPath, LauncherPathVariableNames.AutomationTranscriptPath }) + foreach (var name in new[] { LauncherPathVariableNames.LocalLauncherRoot, LauncherPathVariableNames.LocalPackageCache, LauncherPathVariableNames.LocalActiveRoot, LauncherPathVariableNames.LocalSessionRoot, LauncherPathVariableNames.LocalEvidenceRoot, LauncherPathVariableNames.LocalLogsRoot, LauncherPathVariableNames.LocalRollbackRoot, LauncherPathVariableNames.AcadExecutable, LauncherPathVariableNames.PRecEntryAssembly, LauncherPathVariableNames.FixtureOrthoDwg, LauncherPathVariableNames.FixtureModelDwg, LauncherPathVariableNames.AutomationScriptPath, LauncherPathVariableNames.AutomationConfigPath, LauncherPathVariableNames.AutomationEvidencePath, LauncherPathVariableNames.AutomationPermitPath, LauncherPathVariableNames.AutomationTranscriptPath }) if (raw.Get(name) is { Length: > 0 } value) resolved[name] = resolver.ResolvePath(value, variables); paths = new(resolved); error = null; return true; } @@ -255,6 +255,7 @@ internal static class PilotCli [LauncherPathVariableNames.AutomationPermitPath] = permitPath, [LauncherPathVariableNames.AutomationTranscriptPath] = Path.Combine(options.EvidenceRoot, phase + "-transcript.log"), [LauncherPathVariableNames.FixtureOrthoDwg] = options.OrthoDrawing, + [LauncherPathVariableNames.FixtureModelDwg] = options.ModelDrawing, [LauncherPathVariableNames.PRecEntryAssembly] = Path.Combine(options.PackageSource, options.EntryAssembly) }; return config with { PathVariables = variables }; diff --git a/Launcher.Next.Autodesk/AutodeskAdapters.cs b/Launcher.Next.Autodesk/AutodeskAdapters.cs index c8fd14f..5f86cfc 100644 --- a/Launcher.Next.Autodesk/AutodeskAdapters.cs +++ b/Launcher.Next.Autodesk/AutodeskAdapters.cs @@ -19,7 +19,9 @@ public sealed class StartupScriptBuilder : IStartupScriptBuilder public string BuildAutomationScript(ResolvedAutomationScriptPaths paths) { var fixture = Path.GetFullPath(paths.FixtureOrthoDwg); + var model = Path.GetFullPath(paths.FixtureModelDwg); if (!File.Exists(fixture)) throw new InvalidOperationException("AUTOMATION_FIXTURE_NOT_FOUND"); + if (!File.Exists(model)) throw new InvalidOperationException("AUTOMATION_SOURCE_MODEL_NOT_FOUND"); var quote = (string value) => "\"" + value.Replace("\"", "\\\"") + "\""; var diagnostic = paths.Diagnostic ? "_.FILEDIA\n0\n_.CMDDIA\n0\n_.CMDECHO\n1\n_.NOMUTT\n0\n_.LOGFILEMODE\n1\n" @@ -27,7 +29,7 @@ public sealed class StartupScriptBuilder : IStartupScriptBuilder var commands = paths.Diagnostic ? "PHP_REC_AUTOMATION_BEFORE_PXP_1\nPXP-OA\nPHP_REC_AUTOMATION_AFTER_PXP_1\nPHP_REC_AUTOMATION_BEFORE_PXP_2\nPXP-OA\nPHP_REC_AUTOMATION_AFTER_PXP_2\n" : "PXP-OA\nPXP-OA\n"; - return "_.OPEN\n" + quote(fixture) + "\n" + diagnostic + BuildNetloadScript(paths.ValidatedPackageRoot, paths.EntryAssembly) + + return "_.OPEN\n" + quote(model) + "\n_.OPEN\n" + quote(fixture) + "\n" + diagnostic + BuildNetloadScript(paths.ValidatedPackageRoot, paths.EntryAssembly) + "PHP_REC_AUTOMATION_PREPARE\n" + commands + "PHP_REC_AUTOMATION_FINALIZE\n"; } } diff --git a/Launcher.Next.Core/Contracts.cs b/Launcher.Next.Core/Contracts.cs index 912fb45..606c1cb 100644 --- a/Launcher.Next.Core/Contracts.cs +++ b/Launcher.Next.Core/Contracts.cs @@ -28,7 +28,7 @@ public interface ILocalPackageStore { Task GetCurrentVersionAsync(strin public interface IPackageActivator { Task ActivateAsync(string packageId, string version, CancellationToken cancellationToken); } public interface IRollbackManager { Task RollbackAsync(string packageId, CancellationToken cancellationToken); } public interface IAutodeskProcessLauncher { PreparedLaunch Prepare(LaunchRequest request); } -public sealed record ResolvedAutomationScriptPaths(string ValidatedPackageRoot, string EntryAssembly, string FixtureOrthoDwg, string AutomationScriptPath, bool Diagnostic); +public sealed record ResolvedAutomationScriptPaths(string ValidatedPackageRoot, string EntryAssembly, string FixtureOrthoDwg, string FixtureModelDwg, string AutomationScriptPath, bool Diagnostic); public interface IStartupScriptBuilder { string BuildNetloadScript(string validatedPackageRoot, string entryAssembly); string BuildAutomationScript(ResolvedAutomationScriptPaths paths); } public interface ILauncherConfigurationProvider { LauncherMode GetMode(); } public interface ILauncherTelemetry { void Write(string eventType, IReadOnlyDictionary? fields = null); } diff --git a/Launcher.Next.Core/LauncherPaths.cs b/Launcher.Next.Core/LauncherPaths.cs index aa88777..5d2f529 100644 --- a/Launcher.Next.Core/LauncherPaths.cs +++ b/Launcher.Next.Core/LauncherPaths.cs @@ -123,6 +123,7 @@ public static class LauncherPathVariableNames public const string AcadExecutable = "AcadExecutable"; public const string PRecEntryAssembly = "PRecEntryAssembly"; public const string FixtureOrthoDwg = "FixtureOrthoDwg"; + public const string FixtureModelDwg = "FixtureModelDwg"; public const string AutomationScriptPath = "AutomationScriptPath"; public const string AutomationConfigPath = "AutomationConfigPath"; public const string AutomationEvidencePath = "AutomationEvidencePath"; diff --git a/Launcher.Next.Infrastructure/PilotExecutionService.cs b/Launcher.Next.Infrastructure/PilotExecutionService.cs index 47727ee..4dcfb1d 100644 --- a/Launcher.Next.Infrastructure/PilotExecutionService.cs +++ b/Launcher.Next.Infrastructure/PilotExecutionService.cs @@ -112,11 +112,11 @@ public sealed class PilotExecutionService( var automation = request.Preparation.Configuration.LaunchMode is AcadLaunchMode.NextPilotPreview or AcadLaunchMode.NextPilotApply or AcadLaunchMode.LifecycleProbe; if (automation) { - var paths = resolver.Resolve(new LauncherPathVariables(request.Preparation.Configuration.PathVariables), [LauncherPathVariableNames.AutomationScriptPath, LauncherPathVariableNames.FixtureOrthoDwg, LauncherPathVariableNames.LocalSessionRoot]); + var paths = resolver.Resolve(new LauncherPathVariables(request.Preparation.Configuration.PathVariables), [LauncherPathVariableNames.AutomationScriptPath, LauncherPathVariableNames.FixtureOrthoDwg, LauncherPathVariableNames.FixtureModelDwg, LauncherPathVariableNames.LocalSessionRoot]); scriptPath = paths.Require(LauncherPathVariableNames.AutomationScriptPath); if (!Path.GetFullPath(scriptPath).StartsWith(Path.GetFullPath(paths.Require(LauncherPathVariableNames.LocalSessionRoot)).TrimEnd(Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar, StringComparison.OrdinalIgnoreCase)) throw new InvalidOperationException("AUTOMATION_SCRIPT_OUTSIDE_SESSION_ROOT"); Directory.CreateDirectory(Path.GetDirectoryName(scriptPath)!); - var script = scriptBuilder.BuildAutomationScript(new(versionDirectory, request.Preparation.Manifest.EntryAssembly, paths.Require(LauncherPathVariableNames.FixtureOrthoDwg), scriptPath, request.Preparation.Configuration.AutomationDiagnostic)); + var script = scriptBuilder.BuildAutomationScript(new(versionDirectory, request.Preparation.Manifest.EntryAssembly, paths.Require(LauncherPathVariableNames.FixtureOrthoDwg), paths.Require(LauncherPathVariableNames.FixtureModelDwg), scriptPath, request.Preparation.Configuration.AutomationDiagnostic)); await File.WriteAllTextAsync(scriptPath, script, cancellationToken); } var arguments = new AcadArgumentBuilder().Build(request.Preparation.Configuration.LaunchMode, automation ? scriptPath : null); diff --git a/tests/Launcher.Next.Tests/PathAndLaunchTests.cs b/tests/Launcher.Next.Tests/PathAndLaunchTests.cs index 3dbe05f..71d7892 100644 --- a/tests/Launcher.Next.Tests/PathAndLaunchTests.cs +++ b/tests/Launcher.Next.Tests/PathAndLaunchTests.cs @@ -17,6 +17,7 @@ public sealed class PathAndLaunchTests [LauncherPathVariableNames.LocalSessionRoot] = "${LocalLauncherRoot}\\sessions", [LauncherPathVariableNames.AcadExecutable] = "C:\\Plant 3D 2026\\acad.exe", [LauncherPathVariableNames.FixtureOrthoDwg] = "C:\\Fixture Space\\Тест.dwg", + [LauncherPathVariableNames.FixtureModelDwg] = "C:\\Fixture Space\\model.dwg", [LauncherPathVariableNames.AutomationScriptPath] = "${LocalSessionRoot}\\preview.scr", [LauncherPathVariableNames.AutomationConfigPath] = "${LocalSessionRoot}\\preview.json" }; @@ -63,9 +64,11 @@ public sealed class PathAndLaunchTests var entry = "PRecAnnot.dll"; var fixture = Path.Combine(root, "Fixture Орто.dwg"); File.WriteAllText(Path.Combine(root, entry), string.Empty); File.WriteAllText(fixture, string.Empty); try { - var paths = new ResolvedAutomationScriptPaths(root, entry, fixture, Path.Combine(root, "preview.scr"), false); + var model = Path.Combine(root, "model.dwg"); File.WriteAllText(model, string.Empty); + var paths = new ResolvedAutomationScriptPaths(root, entry, fixture, model, Path.Combine(root, "preview.scr"), false); var first = new StartupScriptBuilder().BuildAutomationScript(paths); var second = new StartupScriptBuilder().BuildAutomationScript(paths); Assert.Equal(first, second); Assert.EndsWith("\n", first); Assert.Equal(2, System.Text.RegularExpressions.Regex.Matches(first, "PXP-OA").Count); + Assert.True(first.IndexOf(model, StringComparison.Ordinal) < first.IndexOf(fixture, StringComparison.Ordinal)); Assert.True(first.IndexOf("PHP_REC_AUTOMATION_PREPARE", StringComparison.Ordinal) < first.IndexOf("PXP-OA", StringComparison.Ordinal)); Assert.True(first.LastIndexOf("PXP-OA", StringComparison.Ordinal) < first.IndexOf("PHP_REC_AUTOMATION_FINALIZE", StringComparison.Ordinal)); } @@ -73,8 +76,8 @@ public sealed class PathAndLaunchTests } [Fact] public void DiagnosticScript_BracketsBothPxpOaCommands() { - var root = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N")); Directory.CreateDirectory(root); var entry = "P.dll"; var fixture = Path.Combine(root, "fixture.dwg"); File.WriteAllText(Path.Combine(root, entry), ""); File.WriteAllText(fixture, ""); - try { var script = new StartupScriptBuilder().BuildAutomationScript(new(root, entry, fixture, Path.Combine(root, "diagnostic.scr"), true)); Assert.Contains("PHP_REC_AUTOMATION_BEFORE_PXP_1\nPXP-OA\nPHP_REC_AUTOMATION_AFTER_PXP_1", script); Assert.Contains("PHP_REC_AUTOMATION_BEFORE_PXP_2\nPXP-OA\nPHP_REC_AUTOMATION_AFTER_PXP_2", script); } + var root = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N")); Directory.CreateDirectory(root); var entry = "P.dll"; var fixture = Path.Combine(root, "fixture.dwg"); var model = Path.Combine(root, "model.dwg"); File.WriteAllText(Path.Combine(root, entry), ""); File.WriteAllText(fixture, ""); File.WriteAllText(model, ""); + try { var script = new StartupScriptBuilder().BuildAutomationScript(new(root, entry, fixture, model, Path.Combine(root, "diagnostic.scr"), true)); Assert.Contains("PHP_REC_AUTOMATION_BEFORE_PXP_1\nPXP-OA\nPHP_REC_AUTOMATION_AFTER_PXP_1", script); Assert.Contains("PHP_REC_AUTOMATION_BEFORE_PXP_2\nPXP-OA\nPHP_REC_AUTOMATION_AFTER_PXP_2", script); } finally { Directory.Delete(root, true); } } [Fact] public void DiagnosticScript_RecordsExactBytes() { var text = "PXP-OA\n"; Assert.Equal(Convert.ToHexString(System.Security.Cryptography.SHA256.HashData(System.Text.Encoding.UTF8.GetBytes(text))), Convert.ToHexString(System.Security.Cryptography.SHA256.HashData(System.Text.Encoding.UTF8.GetBytes(text)))); }