Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dcf95d7e3a | ||
|
|
c733a27cbb | ||
|
|
9a7a6cd678 |
@@ -1,4 +1,6 @@
|
|||||||
artifacts/
|
artifacts/
|
||||||
|
.local-dotnet-sdk/
|
||||||
|
.local-tools/
|
||||||
bin/
|
bin/
|
||||||
obj/
|
obj/
|
||||||
.vs/
|
.vs/
|
||||||
|
|||||||
@@ -6,6 +6,8 @@
|
|||||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||||
<Deterministic>true</Deterministic>
|
<Deterministic>true</Deterministic>
|
||||||
<DebugType>portable</DebugType>
|
<DebugType>portable</DebugType>
|
||||||
<Plant3D2026InstallDir Condition="'$(Plant3D2026InstallDir)' == ''">$(ProgramFiles)\Autodesk\AutoCAD 2026</Plant3D2026InstallDir>
|
<AutoCAD2026ManagedDir Condition="'$(AutoCAD2026ManagedDir)' == '' and '$(Plant3D2026InstallDir)' != ''">$(Plant3D2026InstallDir)</AutoCAD2026ManagedDir>
|
||||||
|
<Plant3D2026ManagedDir Condition="'$(Plant3D2026ManagedDir)' == '' and '$(Plant3D2026InstallDir)' != ''">$(Plant3D2026InstallDir)\PLNT3D</Plant3D2026ManagedDir>
|
||||||
|
<Plant3D2026InstallDir Condition="'$(Plant3D2026InstallDir)' == '' and '$(AutoCAD2026ManagedDir)' != ''">$(AutoCAD2026ManagedDir)</Plant3D2026InstallDir>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -1,3 +1,29 @@
|
|||||||
# Build
|
# Build
|
||||||
|
|
||||||
SDK 8.0.423 is installed. Plant 3D 2026 is not installed on the audit machine, so Autodesk references are currently absent and the adapter is a deliberate blocker. Build Core/tests independently first; after installation pass `Plant3D2026InstallDir` and validate exact assembly/member compatibility. No Autodesk DLL is copied to Git or bundle. `SeriesMin`, `SeriesMax` and the exact platform token are intentionally absent from the manifest until verified against the installed product and official package contract.
|
The workstation has .NET SDK 8.0.423 and Autodesk AutoCAD Plant 3D 2026 installed. The paths are deliberately supplied at build time; no machine-specific Autodesk path is stored in project files.
|
||||||
|
|
||||||
|
Detected assembly inventory:
|
||||||
|
|
||||||
|
| Assembly | Assembly version | Build input |
|
||||||
|
|---|---:|---|
|
||||||
|
| AcMgd.dll | 25.1.0.0 | `AutoCAD2026ManagedDir` |
|
||||||
|
| AcDbMgd.dll | 25.1.0.0 | `AutoCAD2026ManagedDir` |
|
||||||
|
| AcCoreMgd.dll | 25.1.0.0 | `AutoCAD2026ManagedDir` |
|
||||||
|
| AdWindows.dll | 5.2.1.1 | `AutoCAD2026ManagedDir` |
|
||||||
|
| PnP3dObjectsMgd.dll | 17.0.60.1 | `Plant3D2026ManagedDir` |
|
||||||
|
| PnPProjectManagerMgd.dll | 17.0.60.1 | `Plant3D2026ManagedDir` |
|
||||||
|
|
||||||
|
The actual build used:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
dotnet restore .\Plant3D2026\P_Rec_Annot\PRecAnnot2026.sln
|
||||||
|
dotnet build .\Plant3D2026\P_Rec_Annot\PRecAnnot2026.sln --configuration Release `
|
||||||
|
/p:AutoCAD2026ManagedDir="<AutoCAD managed directory>" `
|
||||||
|
/p:Plant3D2026ManagedDir="<Plant 3D managed directory>"
|
||||||
|
```
|
||||||
|
|
||||||
|
`PRecAnnot.Plant3D2026` now compiles against the real AutoCAD/Plant 3D 2026 metadata. The adapter has real `IExtensionApplication`, `CommandMethod`, `PlantApplication.CurrentProject`, `Document`, `Editor`, and `Autodesk.Windows` Ribbon references. The previous conditional foundation-only adapter was removed. Autodesk references are `Private=false` and `CopyLocal=false`.
|
||||||
|
|
||||||
|
Release emits one non-fatal WindowsBase reference conflict caused by Autodesk's legacy reference surface versus the .NET 8 reference pack. It does not copy Autodesk assemblies to output. Autodesk DLLs are excluded from Git, NuGet, bundle, and publish output.
|
||||||
|
|
||||||
|
The local smoke bundle is created at `Plant3D2026\P_Rec_Annot\artifacts\P_Rec_Annot.bundle`. Deploy is NOT PERFORMED.
|
||||||
|
|||||||
@@ -1,3 +1,16 @@
|
|||||||
# Migration dashboard
|
# Migration dashboard
|
||||||
|
|
||||||
The active command set is mapped in `command-migration-matrix.md`; all currently published target descriptors are `BLOCKED_WITH_REASON` because Plant 3D 2026 assemblies/runtime are unavailable. Coverage is not reported as a percentage until every active use case has a runtime result. Current status: mapped 3 foundation descriptors, implemented Core planning/registry/telemetry contracts, runtime verified 0, native replacements approved 0, retirements approved 0, blockers 3.
|
The first real Plant 3D 2026 build is complete against the workstation assemblies (AutoCAD managed 25.1.0.0; Plant managed 17.0.60.1; AdWindows 5.2.1.1). Core remains Autodesk-free.
|
||||||
|
|
||||||
|
| Area | Status |
|
||||||
|
|---|---|
|
||||||
|
| `PHP_REC_ANNOT` | Registered real `CommandMethod`; primary diagnostic entry point |
|
||||||
|
| `PXP-AAV` | Registered real `CommandMethod`; diagnostic alias |
|
||||||
|
| `PXP-OA` | Registered real `CommandMethod`; diagnostic alias |
|
||||||
|
| Ribbon | Implemented with `Autodesk.Windows`; idempotent tab/panel guard |
|
||||||
|
| Adapter | Compiled against real 2026 assemblies |
|
||||||
|
| Bundle | Local smoke package built and checked for Autodesk DLL exclusion |
|
||||||
|
| Runtime | Not executed in AutoCAD/Plant process |
|
||||||
|
| Production deploy | NOT PERFORMED |
|
||||||
|
|
||||||
|
Fixed API assumptions: foundation-only lifecycle became `IExtensionApplication`; command descriptors became actual `CommandMethod` registrations; Plant project detection uses `PlantApplication.CurrentProject`; Ribbon uses `ComponentManager.Ribbon`, `RibbonTab`, `RibbonPanelSource`, and `RibbonButton`. Remaining blockers are runtime loading, Ortho API/data-link mapping, safe DWG transaction implementation, and golden fixture validation.
|
||||||
|
|||||||
@@ -1,3 +1,14 @@
|
|||||||
# Runtime test plan
|
# Runtime test plan
|
||||||
|
|
||||||
On a controlled Plant 3D 2026 test machine: install the bundle outside production, start Plant, verify exactly one Ribbon tab/panel, open a test project and Ortho DWG, run `PHP_REC_ANNOT`, inspect dry-run counts, confirm one transaction, save/reopen/audit, repeat command, test no duplicates and Undo, then compare entities/text/layers/positions/links with the 2019 golden sample. This plan is prepared but not executed.
|
Runtime smoke is ready but has not been executed in AutoCAD. The local package is `Plant3D2026\P_Rec_Annot\artifacts\P_Rec_Annot.bundle`.
|
||||||
|
|
||||||
|
Next-step installation command (intentionally not executed):
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
Copy-Item -Recurse -Force .\Plant3D2026\P_Rec_Annot\artifacts\P_Rec_Annot.bundle `
|
||||||
|
"$env:APPDATA\Autodesk\ApplicationPlugins\P_Rec_Annot.bundle"
|
||||||
|
```
|
||||||
|
|
||||||
|
In a controlled Plant 3D 2026 session, verify that the entry assembly loads, the `Промхимпроект` tab and `Аннотации` panel occur once, and the `Аннотировать` button invokes `PHP_REC_ANNOT`. Open a Plant project and active DWG, run all three commands, verify the project guard and diagnostic-only behavior, and confirm no unhandled exception. Repeat initialization and confirm no Ribbon duplicate. DWG mutation, Ortho viewport/data-link behavior, undo, repeat-run idempotence, and golden-DWG comparison remain runtime blockers for the implementation wave.
|
||||||
|
|
||||||
|
Deploy status: NOT PERFORMED.
|
||||||
|
|||||||
@@ -0,0 +1,80 @@
|
|||||||
|
using Autodesk.AutoCAD.ApplicationServices;
|
||||||
|
using Autodesk.AutoCAD.EditorInput;
|
||||||
|
using Autodesk.AutoCAD.Runtime;
|
||||||
|
using Autodesk.ProcessPower.PlantInstance;
|
||||||
|
using Autodesk.Windows;
|
||||||
|
using AcadApplication = Autodesk.AutoCAD.ApplicationServices.Application;
|
||||||
|
|
||||||
|
namespace PRecAnnot.Plant3D2026;
|
||||||
|
|
||||||
|
public sealed class EntryPoint : IExtensionApplication
|
||||||
|
{
|
||||||
|
public void Initialize() => RibbonIntegration.Register();
|
||||||
|
|
||||||
|
public void Terminate() { }
|
||||||
|
|
||||||
|
[CommandMethod("PHP_REC_ANNOT")]
|
||||||
|
public void PrimaryCommand() => RunDiagnostic("PHP_REC_ANNOT");
|
||||||
|
|
||||||
|
[CommandMethod("PXP-AAV")]
|
||||||
|
public void AutoAnnotateViewCommand() => RunDiagnostic("PXP-AAV");
|
||||||
|
|
||||||
|
[CommandMethod("PXP-OA")]
|
||||||
|
public void OrthoAnnotateCommand() => RunDiagnostic("PXP-OA");
|
||||||
|
|
||||||
|
private static void RunDiagnostic(string commandName)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Document? document = AcadApplication.DocumentManager.MdiActiveDocument;
|
||||||
|
if (document is null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Editor editor = document.Editor;
|
||||||
|
if (PlantApplication.CurrentProject is null)
|
||||||
|
{
|
||||||
|
editor.WriteMessage("\nP_Rec_Annot: активный Plant 3D project не найден; DWG не изменён.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
editor.WriteMessage($"\nP_Rec_Annot {commandName}: Plant 3D project '{PlantApplication.CurrentProject.Name}' найден; diagnostic-only, DWG не изменён.");
|
||||||
|
}
|
||||||
|
catch (System.Exception exception)
|
||||||
|
{
|
||||||
|
try { AcadApplication.DocumentManager.MdiActiveDocument?.Editor.WriteMessage($"\nP_Rec_Annot: безопасная диагностика завершилась ошибкой: {exception.Message}"); }
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static class RibbonIntegration
|
||||||
|
{
|
||||||
|
private const string TabId = "PRecAnnot.Plant3D2026";
|
||||||
|
private const string Command = "PHP_REC_ANNOT ";
|
||||||
|
|
||||||
|
public static void Register()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
RibbonControl? ribbon = ComponentManager.Ribbon;
|
||||||
|
if (ribbon is null) return;
|
||||||
|
|
||||||
|
RibbonTab? tab = ribbon.Tabs.FirstOrDefault(item => string.Equals(item.Id, TabId, StringComparison.OrdinalIgnoreCase));
|
||||||
|
if (tab is null)
|
||||||
|
{
|
||||||
|
tab = new RibbonTab { Id = TabId, Title = "Промхимпроект" };
|
||||||
|
ribbon.Tabs.Add(tab);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tab.Panels.Any(panel => string.Equals(panel.Source?.Title, "Аннотации", StringComparison.OrdinalIgnoreCase))) return;
|
||||||
|
|
||||||
|
RibbonPanelSource source = new() { Title = "Аннотации" };
|
||||||
|
source.Items.Add(new RibbonButton { Text = "Аннотировать", ShowText = true, CommandParameter = Command });
|
||||||
|
tab.Panels.Add(new RibbonPanel { Source = source });
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// Ribbon is optional; command-line registration remains available.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
namespace PRecAnnot.Plant3D2026;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Autodesk-facing composition-root lifecycle. The concrete IExtensionApplication
|
|
||||||
/// implementation is enabled only after the Plant 3D 2026 SDK reference contract
|
|
||||||
/// is verified on the target installation.
|
|
||||||
/// </summary>
|
|
||||||
public sealed class EntryPointLifecycle : IDisposable
|
|
||||||
{
|
|
||||||
private int _initialized;
|
|
||||||
public bool IsInitialized => Volatile.Read(ref _initialized) == 1;
|
|
||||||
public bool Initialize() => Interlocked.Exchange(ref _initialized, 1) == 0;
|
|
||||||
public void Terminate() => Interlocked.Exchange(ref _initialized, 0);
|
|
||||||
public void Dispose() => Terminate();
|
|
||||||
}
|
|
||||||
@@ -1,15 +1,17 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup><TargetFramework>net8.0-windows</TargetFramework><PlatformTarget>x64</PlatformTarget><UseWindowsForms>true</UseWindowsForms></PropertyGroup>
|
<PropertyGroup><TargetFramework>net8.0-windows</TargetFramework><PlatformTarget>x64</PlatformTarget><UseWindowsForms>true</UseWindowsForms><EnableDefaultApplicationDefinition>false</EnableDefaultApplicationDefinition></PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\PRecAnnot.Abstractions\PRecAnnot.Abstractions.csproj" />
|
<ProjectReference Include="..\PRecAnnot.Abstractions\PRecAnnot.Abstractions.csproj" />
|
||||||
<ProjectReference Include="..\PRecAnnot.Application\PRecAnnot.Application.csproj" />
|
<ProjectReference Include="..\PRecAnnot.Application\PRecAnnot.Application.csproj" />
|
||||||
<ProjectReference Include="..\PRecAnnot.Core\PRecAnnot.Core.csproj" />
|
<ProjectReference Include="..\PRecAnnot.Core\PRecAnnot.Core.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup Condition="Exists('$(Plant3D2026InstallDir)')">
|
<ItemGroup Condition="Exists('$(AutoCAD2026ManagedDir)') and Exists('$(Plant3D2026ManagedDir)')">
|
||||||
<Reference Include="AcMgd"><HintPath>$(Plant3D2026InstallDir)\AcMgd.dll</HintPath><Private>false</Private></Reference>
|
<Reference Include="AcMgd"><HintPath>$(AutoCAD2026ManagedDir)\AcMgd.dll</HintPath><Private>false</Private><CopyLocal>false</CopyLocal></Reference>
|
||||||
<Reference Include="AcDbMgd"><HintPath>$(Plant3D2026InstallDir)\AcDbMgd.dll</HintPath><Private>false</Private></Reference>
|
<Reference Include="AcDbMgd"><HintPath>$(AutoCAD2026ManagedDir)\AcDbMgd.dll</HintPath><Private>false</Private><CopyLocal>false</CopyLocal></Reference>
|
||||||
<Reference Include="AcCoreMgd"><HintPath>$(Plant3D2026InstallDir)\AcCoreMgd.dll</HintPath><Private>false</Private></Reference>
|
<Reference Include="AcCoreMgd"><HintPath>$(AutoCAD2026ManagedDir)\AcCoreMgd.dll</HintPath><Private>false</Private><CopyLocal>false</CopyLocal></Reference>
|
||||||
<Reference Include="PnPProjectManagerMgd"><HintPath>$(Plant3D2026InstallDir)\PLNT3D\PnPProjectManagerMgd.dll</HintPath><Private>false</Private></Reference>
|
<Reference Include="AdWindows"><HintPath>$(AutoCAD2026ManagedDir)\AdWindows.dll</HintPath><Private>false</Private><CopyLocal>false</CopyLocal></Reference>
|
||||||
<Reference Include="PnPDataLinks"><HintPath>$(Plant3D2026InstallDir)\PLNT3D\PnPDataLinks.dll</HintPath><Private>false</Private></Reference>
|
<Reference Include="PnPDataLinks"><HintPath>$(AutoCAD2026ManagedDir)\PnPDataLinks.dll</HintPath><Private>false</Private><CopyLocal>false</CopyLocal></Reference>
|
||||||
|
<Reference Include="PnPProjectManagerMgd"><HintPath>$(Plant3D2026ManagedDir)\PnPProjectManagerMgd.dll</HintPath><Private>false</Private><CopyLocal>false</CopyLocal></Reference>
|
||||||
|
<Reference Include="PnP3dObjectsMgd"><HintPath>$(Plant3D2026ManagedDir)\PnP3dObjectsMgd.dll</HintPath><Private>false</Private><CopyLocal>false</CopyLocal></Reference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ public sealed record Plant3D2026Availability(bool IsAvailable, string InstallDir
|
|||||||
{
|
{
|
||||||
public static Plant3D2026Availability Detect(string installDirectory)
|
public static Plant3D2026Availability Detect(string installDirectory)
|
||||||
{
|
{
|
||||||
var expected = new[] { "AcMgd.dll", "AcDbMgd.dll", "AcCoreMgd.dll", Path.Combine("PLNT3D", "PnPProjectManagerMgd.dll"), Path.Combine("PLNT3D", "PnPDataLinks.dll") };
|
var expected = new[] { "AcMgd.dll", "AcDbMgd.dll", "AcCoreMgd.dll", "PnPDataLinks.dll", Path.Combine("PLNT3D", "PnPProjectManagerMgd.dll"), Path.Combine("PLNT3D", "PnP3dObjectsMgd.dll") };
|
||||||
var missing = expected.Where(x => !File.Exists(Path.Combine(installDirectory, x))).ToArray();
|
var missing = expected.Where(x => !File.Exists(Path.Combine(installDirectory, x))).ToArray();
|
||||||
return new(missing.Length == 0, installDirectory, missing);
|
return new(missing.Length == 0, installDirectory, missing);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,16 @@ namespace PRecAnnot.Core.Tests;
|
|||||||
|
|
||||||
public sealed class FoundationTests
|
public sealed class FoundationTests
|
||||||
{
|
{
|
||||||
|
private static string ProjectRoot
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var directory = new DirectoryInfo(AppContext.BaseDirectory);
|
||||||
|
while (directory is not null && !File.Exists(Path.Combine(directory.FullName, "PRecAnnot2026.sln"))) directory = directory.Parent;
|
||||||
|
return directory?.FullName ?? throw new DirectoryNotFoundException("PRecAnnot2026.sln was not found.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[Fact] public void Plan_IsDeterministic()
|
[Fact] public void Plan_IsDeterministic()
|
||||||
{
|
{
|
||||||
var engine = new AnnotationRuleEngine();
|
var engine = new AnnotationRuleEngine();
|
||||||
@@ -34,4 +44,46 @@ public sealed class FoundationTests
|
|||||||
var ribbon = new RibbonRegistration(); var registry = CommandRegistry.Foundation();
|
var ribbon = new RibbonRegistration(); var registry = CommandRegistry.Foundation();
|
||||||
Assert.True(ribbon.Register(registry)); Assert.False(ribbon.Register(registry)); Assert.Equal(3, ribbon.RegisteredCount);
|
Assert.True(ribbon.Register(registry)); Assert.False(ribbon.Register(registry)); Assert.Equal(3, ribbon.RegisteredCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact] public void PlantAdapter_LoadsAgainst2026Assemblies()
|
||||||
|
{
|
||||||
|
var adapter = Path.Combine(ProjectRoot, "src", "PRecAnnot.Plant3D2026", "bin", "Release", "net8.0-windows", "PRecAnnot.Plant3D2026.dll");
|
||||||
|
var assembly = System.Reflection.AssemblyName.GetAssemblyName(adapter);
|
||||||
|
var project = File.ReadAllText(Path.Combine(ProjectRoot, "src", "PRecAnnot.Plant3D2026", "PRecAnnot.Plant3D2026.csproj"));
|
||||||
|
Assert.NotNull(assembly);
|
||||||
|
Assert.Contains("AcMgd", project);
|
||||||
|
Assert.Contains("PnPProjectManagerMgd", project);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact] public void CommandClass_HasCommandMethodAttributes()
|
||||||
|
{
|
||||||
|
var source = File.ReadAllText(Path.Combine(ProjectRoot, "src", "PRecAnnot.Plant3D2026", "EntryPoint.cs"));
|
||||||
|
Assert.Contains("[CommandMethod(\"PHP_REC_ANNOT\")]", source);
|
||||||
|
Assert.Contains("[CommandMethod(\"PXP-AAV\")]", source);
|
||||||
|
Assert.Contains("[CommandMethod(\"PXP-OA\")]", source);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact] public void PrimaryCommand_IsRegistered() => Assert.Contains("[CommandMethod(\"PHP_REC_ANNOT\")]", File.ReadAllText(Path.Combine(ProjectRoot, "src", "PRecAnnot.Plant3D2026", "EntryPoint.cs")));
|
||||||
|
[Fact] public void LegacyAliases_AreRegistered() => Assert.True(File.ReadAllText(Path.Combine(ProjectRoot, "src", "PRecAnnot.Plant3D2026", "EntryPoint.cs")).Contains("PXP-AAV") && File.ReadAllText(Path.Combine(ProjectRoot, "src", "PRecAnnot.Plant3D2026", "EntryPoint.cs")).Contains("PXP-OA"));
|
||||||
|
[Fact] public void RibbonCommand_ReferencesRegisteredCommand() => Assert.Contains("PHP_REC_ANNOT ", File.ReadAllText(Path.Combine(ProjectRoot, "src", "PRecAnnot.Plant3D2026", "EntryPoint.cs")));
|
||||||
|
|
||||||
|
[Fact] public void AutodeskReferences_AreNotCopyLocal()
|
||||||
|
{
|
||||||
|
var project = File.ReadAllText(Path.Combine(ProjectRoot, "src", "PRecAnnot.Plant3D2026", "PRecAnnot.Plant3D2026.csproj"));
|
||||||
|
Assert.DoesNotContain("<Private>true</Private>", project);
|
||||||
|
Assert.DoesNotContain("<CopyLocal>true</CopyLocal>", project);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact] public void Bundle_DoesNotContainAutodeskAssemblies()
|
||||||
|
{
|
||||||
|
var root = Path.Combine(ProjectRoot, "artifacts", "P_Rec_Annot.bundle");
|
||||||
|
if (!Directory.Exists(root)) return;
|
||||||
|
Assert.DoesNotContain(Directory.EnumerateFiles(root, "*.dll", SearchOption.AllDirectories), path => Path.GetFileName(path).StartsWith("PnP", StringComparison.OrdinalIgnoreCase) || new[] { "AcMgd.dll", "AcDbMgd.dll", "AcCoreMgd.dll", "AdWindows.dll" }.Contains(Path.GetFileName(path), StringComparer.OrdinalIgnoreCase));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact] public void Core_HasNoAutodeskReferences()
|
||||||
|
{
|
||||||
|
var references = typeof(AnnotationRequest).Assembly.GetReferencedAssemblies();
|
||||||
|
Assert.DoesNotContain(references, x => x.Name?.StartsWith("Autodesk", StringComparison.OrdinalIgnoreCase) == true || x.Name?.StartsWith("Ac", StringComparison.OrdinalIgnoreCase) == true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,11 @@
|
|||||||
param([ValidateSet('Debug','Release')][string]$Configuration='Release',[string]$Plant3D2026InstallDir)
|
param([ValidateSet('Debug','Release')][string]$Configuration='Release',[Parameter(Mandatory=$true)][string]$AutoCAD2026ManagedDir,[Parameter(Mandatory=$true)][string]$Plant3D2026ManagedDir)
|
||||||
$ErrorActionPreference='Stop'
|
$ErrorActionPreference='Stop'
|
||||||
dotnet build (Join-Path $PSScriptRoot '..\PRecAnnot2026.sln') --configuration $Configuration /p:Plant3D2026InstallDir=$Plant3D2026InstallDir
|
dotnet build (Join-Path $PSScriptRoot '..\PRecAnnot2026.sln') --configuration $Configuration /p:AutoCAD2026ManagedDir=$AutoCAD2026ManagedDir /p:Plant3D2026ManagedDir=$Plant3D2026ManagedDir
|
||||||
|
if($LASTEXITCODE -ne 0){ throw "Build failed: $LASTEXITCODE" }
|
||||||
|
$bundleRoot=Join-Path $PSScriptRoot '..\artifacts\P_Rec_Annot.bundle'
|
||||||
|
$contents=Join-Path $bundleRoot 'Contents\Windows'
|
||||||
|
New-Item -ItemType Directory -Force -Path $contents | Out-Null
|
||||||
|
$output=Join-Path $PSScriptRoot "..\src\PRecAnnot.Plant3D2026\bin\$Configuration\net8.0-windows"
|
||||||
|
Get-ChildItem $output -File -Filter '*.dll' | Copy-Item -Destination $contents -Force
|
||||||
|
Copy-Item (Join-Path $PSScriptRoot '..\bundle\P_Rec_Annot.bundle\PackageContents.xml') $bundleRoot -Force
|
||||||
Write-Host 'Bundle assembly build completed; deployment is intentionally not performed.'
|
Write-Host 'Bundle assembly build completed; deployment is intentionally not performed.'
|
||||||
|
|||||||
@@ -1,8 +1,13 @@
|
|||||||
|
param([string]$BundleRoot=(Join-Path $PSScriptRoot '..\artifacts\P_Rec_Annot.bundle'))
|
||||||
$ErrorActionPreference='Stop'
|
$ErrorActionPreference='Stop'
|
||||||
$package=Join-Path $PSScriptRoot '..\bundle\P_Rec_Annot.bundle\PackageContents.xml'
|
$package=Join-Path $BundleRoot 'PackageContents.xml'
|
||||||
[xml]$xml=Get-Content -LiteralPath $package
|
[xml]$xml=Get-Content -LiteralPath $package
|
||||||
$entry=$xml.ApplicationPackage.Components.ComponentEntry
|
$entry=$xml.ApplicationPackage.Components.ComponentEntry
|
||||||
if(@($entry).Count -ne 1){throw 'Bundle must have exactly one entry assembly.'}
|
if(@($entry).Count -ne 1){throw 'Bundle must have exactly one entry assembly.'}
|
||||||
if($entry.ModuleName -match '_netload|OrthoLoader|Settings.xml'){throw 'Legacy loading chain is forbidden.'}
|
if($entry.ModuleName -match '_netload|OrthoLoader|Settings.xml'){throw 'Legacy loading chain is forbidden.'}
|
||||||
if($entry.ModuleName -notmatch 'PRecAnnot\.Plant3D2026\.dll'){throw 'Unexpected entry assembly.'}
|
if($entry.ModuleName -notmatch 'PRecAnnot\.Plant3D2026\.dll'){throw 'Unexpected entry assembly.'}
|
||||||
|
if(-not (Test-Path (Join-Path $BundleRoot 'Contents\Windows\PRecAnnot.Plant3D2026.dll'))){throw 'Entry assembly is missing.'}
|
||||||
|
$forbidden='^(AcMgd|AcDbMgd|AcCoreMgd|AdWindows|PnP.*)\.dll$'
|
||||||
|
$forbiddenFiles=Get-ChildItem $BundleRoot -Recurse -File | Where-Object { $_.Name -match $forbidden -or $_.Extension -in '.pdb','.cs' -or $_.FullName -match '\\(bin|obj)\\' }
|
||||||
|
if($forbiddenFiles){throw "Bundle contains forbidden files: $($forbiddenFiles.FullName -join ', ')"}
|
||||||
Write-Host 'Bundle manifest is structurally valid.'
|
Write-Host 'Bundle manifest is structurally valid.'
|
||||||
|
|||||||
Reference in New Issue
Block a user