diff --git a/.gitignore b/.gitignore index 93d7e05bba..ceffe048d7 100644 --- a/.gitignore +++ b/.gitignore @@ -225,3 +225,4 @@ test/SystemInJson # Icon resources /src/DynamoRevitIcons/*.resources +/DynamoRevitDA.bundle diff --git a/README.md b/README.md index f7d540e57d..be61213482 100644 --- a/README.md +++ b/README.md @@ -21,8 +21,6 @@ git clone https://github.com/DynamoDS/DynamoRevit.git - Make sure you have the following installed on your computer: - For Revit 2024 and older: [.Net Framework 4.8 SDK](https://dotnet.microsoft.com/download) - For Revit 2025 and newer: [.NET 8 SDK](https://dotnet.microsoft.com/en-us/download/dotnet/8.0) for Windows x64 -- Run `restorepackages.bat` from a command prompt with administrative privileges (Located in your _Github\DynamoRevit\src folder_) - Note: `restorepackages.bat` employs the use of a legacy tool `aget.exe`, which requires VC++ 2010 redistributable installed, before you can run it. When missing you will get an `msvcr100.dll not found` error. Make sure to install the x86 version, not the x64 version! - Copy `RevitAPI.dll`&`RevitAPIUI.dll` to the folder `DynamoRevit\lib\Revit Preview Release\net48`, these 2 dlls are in the folder same with `Revit.exe` installed on your computer (if you want to build other branch of DynamoRevit, but corresponding version of Revit is not installed locally, you can get these dlls from https://www.nuget.org/ ) - Set the `RevitVersionNumber` environment variable to the Revit version you're building against (e.g. `2020`) either in the system environment or in the [user_locals.props](https://github.com/DynamoDS/DynamoRevit/blob/Revit2017/src/Config/user_local.props) file in your build folder. @@ -80,9 +78,16 @@ where `` is the version of Revit for which the addin is built. Notice t Now you should be able to launch Revit and see the Dynamo and Dynamo Player icons on the Manage tab. If you experience issues, check the troubleshooting tips in the next section. -## Troubleshooting Build Issues +### Build dynamo revit against a local version of Dynamo + +1. Build Dynamo locally +2. Run the Dynamo nuget script (more info [here](https://github.com/DynamoDS/Dynamo/blob/master/tools/NuGet/README.md)) +```.\BuildPackages.bat "template-nuget" "...\GitHub\Dynamo\bin\AnyCPU\Release"``` +This will locally produce all the dynamo nugets. +3. In you Visual Studio editor, add/change the nuget sources to point to your local nuget folder (where the local nugets are). +![alt text](images/local_dynamo_nugets.png) -* Make sure you ran [restorepackages.bat](https://github.com/DynamoDS/DynamoRevit/blob/Revit2017/src/restorepackages.bat) in a command prompt with administrator privileges. It creates soft links for all the NuGet packages folder dropping the version information so that the projects files don't need to be changed when package versions are changed. The package versions are defined in the [packages-template.aget](https://github.com/DynamoDS/DynamoRevit/blob/Revit2017/src/Config/packages-template.aget) file. LatestBeta is used for Dynamo specific packages to automatically download the latest beta packages. +## Troubleshooting Build Issues * If you see errors like: diff --git a/images/local_dynamo_nugets.png b/images/local_dynamo_nugets.png new file mode 100644 index 0000000000..648e0a3fd3 Binary files /dev/null and b/images/local_dynamo_nugets.png differ diff --git a/src/AssemblySharedInfoGenerator/AssemblyInfoGenerator.csproj b/src/AssemblySharedInfoGenerator/AssemblyInfoGenerator.csproj index 51431227af..b0cf709a78 100644 --- a/src/AssemblySharedInfoGenerator/AssemblyInfoGenerator.csproj +++ b/src/AssemblySharedInfoGenerator/AssemblyInfoGenerator.csproj @@ -12,6 +12,7 @@ false None AssemblyInfoGenerator + bin\$(Configuration)\ false diff --git a/src/BUILDSYSTEM_TODO.md b/src/BUILDSYSTEM_TODO.md new file mode 100644 index 0000000000..26f553fe2f --- /dev/null +++ b/src/BUILDSYSTEM_TODO.md @@ -0,0 +1,167 @@ +# Build System Cleanup — Open Questions & TODOs + +These are known issues and open design questions in the build system that need +to be resolved, particularly for the `D4R_DA_2026` branch targeting Revit 2026 / net8. + +--- + +## 1. Platform naming is confusing and redundant + +`CS_SDK.props` defines three platforms: + +| Platform | TargetFramework | Notes | +|------------|---------------------|-------| +| `NET80` | `net8.0-windows` | Interactive Revit build | +| `NET80_DA` | `net8.0-windows` | **Same as NET80 — name implies net10 but it's net8** | +| `NET100` | `net10.0-windows` | Future Revit targeting net10 | + +For the `D4R_DA_2026` branch (Revit 2026), only `net8.0-windows` is relevant. +`NET100` adds noise and `NET80_DA` is actively misleading. + +**Important:** `_DA` in the platform name is a meaningful build profile — it is not just a +TFM alias. Any platform whose name contains `_DA` triggers these behaviours across multiple projects: + +| Project | What `_DA` removes | +|---|---| +| `CS_SDK.props` | Defines `DESIGN_AUTOMATION` compile constant | +| `DynamoRevit.csproj` | Removes `DynamoRevit.cs`, `DynamoRevitApp.cs`, entire `ViewModel/` (interactive startup + ribbon) | +| `RevitNodesUI.csproj` | Removes all WPF controls, selection dialogs, XAML pages | +| `RevitServices.csproj` | Removes `Threading/*.cs` (UI thread marshalling, not needed in headless DA) | + +So the `_DA` suffix carries real semantic weight. The problem is solely the `NET10` prefix, +which implies net10 when the TFM is actually net8. Renaming `NET80_DA` → `NET80_DA` everywhere +would fix the confusion without changing any build behaviour. + +**Questions:** +- Should `D4R_DA_2026` drop `NET100` entirely and only expose `NET80`? +- Was `NET80_DA` ever actually net10 and got downgraded, or has it always been net8? +- Should DA just use `NET80` with a separate property/flag to denote DA vs interactive, + rather than a separate platform name? +- If `NET80_DA` stays, should it be renamed (e.g. `NET80_DA`) to reflect actual TFM? + +--- + +## 2. Solution file responsibilities are unclear + +| Solution | Projects included | Typical build command | +|-----------------------|--------------------------------|-----------------------| +| `DynamoRevit.DA.sln` | DADynamoApp + deps only | `/p:Platform=NET80_DA` | +| `DynamoRevit.All.sln` | Everything incl. tests | `/p:Platform=NET80` or `NET100` | + +`DADynamoApp` is **not** listed explicitly in `All.sln` — it is pulled in as a +transitive project reference from `RevitSystemTests`. This causes the solution to +build it without a proper platform mapping, which leads to build errors under +`dotnet build` with .NET SDK 10 (see issue 3 below). + +A workaround was added: explicit `DADynamoApp` entry in `All.sln` mapping +`NET80`/`NET100` → `NET80_DA`. But this is a band-aid. + +**Questions:** +- Should `DADynamoApp` be a first-class explicit project in `All.sln`? +- Should `DA.sln` be a proper subset configuration of `All.sln`, or kept fully separate? +- Is there a reason DA uses `NET80_DA` platform instead of `NET80`? If not, unify them + and remove the extra platform. + +--- + +## 3. `dotnet build` vs VS MSBuild inconsistency + +`DynamoRevit.All.sln` builds cleanly with VS MSBuild: +``` +& "C:\Program Files\Microsoft Visual Studio\18\Professional\MSBuild\Current\Bin\MSBuild.exe" DynamoRevit.All.sln -p:Configuration=Debug -p:Platform=NET80 -m +``` + +But fails with `dotnet build` using .NET SDK 10: +``` +dotnet build DynamoRevit.All.sln -c Debug /p:Platform=NET80 +``` + +Two known `dotnet build`-only failures: + +**a) `DADynamoApp` — `MSB3992: 'RootElementName' is not set`** +- Root cause: `EnableDynamicLoading=true` causes SDK 10 to set + `UseAttributeForTargetFrameworkInfoPropertyNames=true`, which requires + `RootElementName` to be set explicitly. VS MSBuild does not have this requirement. +- Possible fixes: set `false`, + or set `DADynamoApp` explicitly. + +**b) `DynamoRevitIcons` — `ResGen.exe not supported on .NET Core MSBuild`** +- Pre-existing issue. The `.resx` code generation step uses ResGen.exe which is + not available in the .NET Core MSBuild toolchain. +- Possible fix: migrate resource generation to use `` without + ResGen, or exclude from `dotnet build` paths. + +**Question:** Is `dotnet build` a supported/required path in CI, or does CI always +use VS MSBuild? The `Jenkinsfile` delegates to `DynamoRevitUtils` — need to check +those build scripts to confirm. + +--- + +## 4. Build/Package the AppBundle + +The target bundle layout is: + +``` +DynamoRevitDA.bundle/ + PackageContents.xml + Contents/ + + + Revit/ + DynamoRevit.addin + +``` + +### What is automated (DADynamoApp.csproj `publish_bundle` target) + +Running a normal build of `DADynamoApp.csproj` with `Platform=NET80_DA` now: + +1. Compiles `DADynamoApp` and writes output to `$(OutputPath)` (`bin\\net8.0\`). +2. **`Copy dll`** — copies `GregRevitAuth.dll` into `$(OutputPath)`. +3. **`CopyDynamoPlayerFiles`** — copies `$(PkgDynamoPlayer)\bin\Release\net8.0\bin\**` into `$(OutputPath)\..` (the parent folder of the DADynamoApp OutputPath, aka where the DynamoCore dlls will be). +4. **`publish_bundle`** — assembles the bundle at `$(SolutionDir)\..\DynamoRevitDA.bundle\`: + - Creates the `Contents\Revit\` directory tree. + - Copies `PackageContents.xml` (template at `src/DADynamoApp/app_bundle_template/`) to the bundle root. + - Copies `DynamoRevit.addin` (same template) into `Contents\Revit\`. + - Copies all of `$(OutputPath)` into `Contents\Revit\`, preserving subdirectory structure. + +### What still requires a manual step (TODO) + +**DynamoCore** must be built separately from the [Dynamo](https://github.com/DynamoDS/Dynamo) repo (`DynamoCore.sln`) and its output copied into `Contents\` before the bundle is usable. There is currently no Windows CI pipeline for this — the existing pipeline produces a Linux/DAAS-targeted build only. + +The `publish_bundle` target has a commented-out stub (`TODO: copy DynamoCore contents`) that should be wired up once a reliable source for the Windows DynamoCore binaries exists. + +**Options to resolve:** +- Extend the existing Linux DAAS pipeline to produce an OS-agnostic DynamoCore NuGet/artifact that works for both DA and DAAS. +- Add a separate Windows CI pipeline for `DynamoCore.sln` and surface its output as a versioned artifact consumed here. +- For local development: build `DynamoCore.sln` locally and point `$(Pkgdynamovisualprogramming_servicecoreruntime)` (or an equivalent property) at the output before running `publish_bundle`. + + +--- + +## How to debug Design Automation locally + +There are two options depending on how closely you need to replicate the cloud environment: + +**Option 1 — Full Revit (with UI)** + +Use the [APS local debug tool](https://github.com/autodesk-platform-services/aps-automation-csharp-revit.local.debug.tool) against a standard Revit installation. This is the easiest way to validate general AppBundle functionality. + +**Option 2 — Headless Revit engine (matches cloud)** + +Download the exact Design Automation engine from Artifactory: +`https://art-bobcat.autodesk.com/ui/repos/tree/General/team-designautomation-generic/Revit/Engine` + +This is the same headless executable used on the cloud backend — it starts Revit without loading any UI. Before running it, edit `revitcoreconsole.dll.config` to point to your local Revit installation: + +```xml + +``` + +## 4. Research needed / action items + +- [ ] Check `DynamoRevitUtils` Jenkins scripts: which solution, which platform, `dotnet` or VS MSBuild? +- [ ] Confirm whether `NET100` is used in any CI job for this branch +- [ ] Decide on NET80_DA rename/merge with NET80 +- [ ] Decide whether All.sln should be the canonical "build everything" solution +- [ ] Fix `dotnet build` compatibility if CI requires it (MSB3992 + ResGen) diff --git a/src/Config/CS_SDK.props b/src/Config/CS_SDK.props index 5adf781211..0d6ea90254 100644 --- a/src/Config/CS_SDK.props +++ b/src/Config/CS_SDK.props @@ -1,11 +1,14 @@ + x64 false - NET100 + NET100;NET80_DA net10.0-windows - net10.0 + net8.0-windows + net8.0 + net8.0 17.0 2026 $(SolutionDir)packages @@ -39,4 +42,13 @@ true TRACE + + $(DefineConstants);DESIGN_AUTOMATION + + + + false + all + + diff --git a/src/Config/packages_versions.props b/src/Config/packages_versions.props new file mode 100644 index 0000000000..99c1e92155 --- /dev/null +++ b/src/Config/packages_versions.props @@ -0,0 +1,27 @@ + + + + + 3.6.2.11575 + + $(DYNAMOCORE_VERSION) + $(DYNAMOCORE_VERSION) + $(DYNAMOCORE_VERSION) + + + net8.0 + + 3.0.1.4707 + 3.0.8935.26399 + net8.0 + + + 1.2.2 + 2.5.1 + 13.0.1 + 3.13.3 + 3.13.2 + 5.0.0 + + + \ No newline at end of file diff --git a/src/DADynamoApp/DAApplication.cs b/src/DADynamoApp/DAApplication.cs new file mode 100644 index 0000000000..834c3415c8 --- /dev/null +++ b/src/DADynamoApp/DAApplication.cs @@ -0,0 +1,63 @@ + +using Autodesk.Revit.ApplicationServices; +using Autodesk.Revit.DB; +using System.Diagnostics; +using System.Reflection; + +namespace DADynamoApp +{ + [Autodesk.Revit.Attributes.Regeneration(Autodesk.Revit.Attributes.RegenerationOption.Manual)] + [Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)] + public class DAApplication : IExternalDBApplication + { + private string ParentPath; + private string CurrentDirectory; + private readonly string PythonDllFolder = "pythonDependencies"; + + private DAEntrypoint daEntryPoint; + + public ExternalDBApplicationResult OnShutdown(ControlledApplication application) + { + AppDomain.CurrentDomain.UnhandledException -= CurrentDomain_UnhandledException; + AppDomain.CurrentDomain.ProcessExit -= CurrentDomain_ProcessExit; + AppDomain.CurrentDomain.AssemblyResolve -= CurrentDomain_AssemblyResolve; + return daEntryPoint.OnShutdown(application); + } + + public ExternalDBApplicationResult OnStartup(ControlledApplication application) + { + AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; + AppDomain.CurrentDomain.ProcessExit += CurrentDomain_ProcessExit; + AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve; + + CurrentDirectory = Directory.GetCurrentDirectory(); + ParentPath = Directory.GetParent(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)).FullName; + + Console.WriteLine("<> Starting to load DAEntrypoint"); + + daEntryPoint ??= new DAEntrypoint(); + + return daEntryPoint.OnStartup(application); + } + + private static void CurrentDomain_ProcessExit(object? sender, EventArgs e) + { + Process proc = Process.GetCurrentProcess(); + Console.WriteLine($"Dynamo exiting with Peak physical memory {proc.PeakWorkingSet64} bytes"); + if (proc.HasExited) + { + Console.WriteLine($"Dynamo exiting with code {proc.ExitCode}"); + } + } + + private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) + { + Console.WriteLine($"Unhandled exception: {e}"); + } + + private Assembly? CurrentDomain_AssemblyResolve(object? sender, ResolveEventArgs args) + { + return DynamoRevitAssemblyResolver.ResolveDynamoAssembly(ParentPath, [Path.Combine(CurrentDirectory, PythonDllFolder)], args); + } + } +} \ No newline at end of file diff --git a/src/DADynamoApp/DADynamoApp.csproj b/src/DADynamoApp/DADynamoApp.csproj new file mode 100644 index 0000000000..2c55ead689 --- /dev/null +++ b/src/DADynamoApp/DADynamoApp.csproj @@ -0,0 +1,93 @@ + + + + + + + enable + enable + false + + + true + + + + + + + + + + + $(REVITAPI)\RevitAPI.dll + False + + + + + + + + + runtime + + + + + + + + + + $(PkgDynamoPlayer)\bin\Release\net8.0\bin\DynamoPlayer.Models.dll + False + + + $(PkgDynamoPlayer)\bin\Release\net8.0\bin\DynamoPlayer.Server.dll + False + + + $(PkgDynamoPlayer)\bin\Release\net8.0\bin\DynamoPlayer.Workflows.dll + False + + + + + + + + + + + + + + $(SolutionDir)\..\DynamoRevitDA.bundle\ + + + + + + + + + + $([System.IO.Path]::GetFullPath('$(OutputPath)..\')) + + + + + + + diff --git a/src/DADynamoApp/DAEntrypoint.cs b/src/DADynamoApp/DAEntrypoint.cs new file mode 100644 index 0000000000..bd56df1112 --- /dev/null +++ b/src/DADynamoApp/DAEntrypoint.cs @@ -0,0 +1,593 @@ +using Autodesk.Revit.ApplicationServices; +using Autodesk.Revit.DB; +using DesignAutomationFramework; +using DSCPython; +using Dynamo.Applications; +using Dynamo.Graph.Nodes; +using Dynamo.Graph.Workspaces; +using Dynamo.Models; +using Dynamo.PythonServices; +using Dynamo.Scheduler; +using DynamoPlayer; +using Greg.AuthProviders; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using RevitServices.Elements; +using RevitServices.Persistence; +using System.Reflection; +using System.Text.RegularExpressions; +using static Dynamo.Models.DynamoModel; +using DateTime = System.DateTime; + +namespace DADynamoApp +{ + public class DAEntrypoint + { + private DynamoModel model; + internal static DynamoPlayerLoggerConfiguration logConfig = new DynamoPlayerLoggerConfiguration() { DynamoLogLevel = Dynamo.Logging.LogLevel.Console, LogLevel = DynamoPlayer.LogLevel.Information }; + private string DynamoPath; + private string DynamoRevitPath; + private ControlledApplication controlledApplication; + + // Store event handler references for cleanup + private readonly Dictionary evaluationStartedHandler, + EventHandler evaluationCompletedHandler, + Dictionary[]> nodeHandlers)> + workspaceHandlers = []; + + private string LoadMessage; + private string WorkItemFolder; + private readonly string PythonDllFolder = "pythonDependencies"; + + + private List Updaters = []; + + public ExternalDBApplicationResult OnShutdown(ControlledApplication application) + { + model?.Dispose(); + + controlledApplication.DocumentClosing -= RevitServices.EventHandler.EventHandlerProxy.Instance.OnApplicationDocumentClosing; + controlledApplication.DocumentClosed -= RevitServices.EventHandler.EventHandlerProxy.Instance.OnApplicationDocumentClosed; + controlledApplication.DocumentOpened -= RevitServices.EventHandler.EventHandlerProxy.Instance.OnApplicationDocumentOpened; + + return ExternalDBApplicationResult.Succeeded; + } + + public ExternalDBApplicationResult OnStartup(ControlledApplication application) + { + controlledApplication = application; + + WorkItemFolder = Directory.GetCurrentDirectory(); + Console.WriteLine($"<> Work folder is '{WorkItemFolder}'"); + + DynamoRevitPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + DynamoPath = Directory.GetParent(DynamoRevitPath).FullName; + + var hostloc = typeof(Autodesk.Revit.ApplicationServices.Application).Assembly.Location; + var hostDir = Path.GetDirectoryName(hostloc); + + Console.WriteLine("<> Starting to load D4DA"); + + try + { + RevitServicesUpdater.Initialize(Updaters); + Console.WriteLine("<> D4DA Loaded"); + + RevitServices.Transactions.TransactionManager.SetupManager(new RevitServices.Transactions.AutomaticTransactionStrategy()); + // TODO: do we need element binding in Design Automations? + ElementBinder.IsEnabled = true; + + controlledApplication.DocumentClosing += RevitServices.EventHandler.EventHandlerProxy.Instance.OnApplicationDocumentClosing; + controlledApplication.DocumentClosed += RevitServices.EventHandler.EventHandlerProxy.Instance.OnApplicationDocumentClosed; + controlledApplication.DocumentOpened += RevitServices.EventHandler.EventHandlerProxy.Instance.OnApplicationDocumentOpened; + + DesignAutomationBridge.DesignAutomationReadyEvent += HandleDesignAutomationReadyEvent; + + return ExternalDBApplicationResult.Succeeded; + } + catch (Exception ex) + { + return ExternalDBApplicationResult.Failed; + } + } + + private static string GetRevitContext(Autodesk.Revit.ApplicationServices.Application app) + { + var r = new Regex(@"\b(Autodesk |Structure |MEP |Architecture )\b"); + return r.Replace(app.VersionName, ""); + } + + /// + /// Extracts the 'token' value from the work item JSON content. + /// This is robust to casing differences and supports BoundArguments as an object. + /// Returns null if token cannot be found. + /// + private string? ExtractTokenFromWorkItem(string workItemContent) + { + if (string.IsNullOrWhiteSpace(workItemContent)) return null; + + try + { + var job = JObject.Parse(workItemContent); + + // Find BoundArguments (case-insensitive) + JToken? boundToken = null; + if (!job.TryGetValue("BoundArguments", out boundToken)) + { + foreach (var prop in job.Properties()) + { + if (string.Equals(prop.Name, "BoundArguments", StringComparison.OrdinalIgnoreCase)) + { + boundToken = prop.Value; + break; + } + } + } + + if (boundToken == null) return null; + + // If it's an object, try direct lookup + if (boundToken.Type == JTokenType.Object) + { + var boundObj = (JObject)boundToken; + + // try exact key 'token' then case-insensitive + if (boundObj.TryGetValue("adsk3LeggedToken", out var tokVal)) + { + return tokVal.Type == JTokenType.String ? tokVal.Value() : tokVal.ToString(); + } + + foreach (var prop in boundObj.Properties()) + { + if (string.Equals(prop.Name, "adsk3LeggedToken", StringComparison.OrdinalIgnoreCase)) + { + return prop.Value.Type == JTokenType.String ? prop.Value.Value() : prop.Value.ToString(); + } + } + } + + // Fallback: convert to dictionary and search case-insensitively + var boundDict = boundToken.ToObject>(); + if (boundDict != null) + { + foreach (var kv in boundDict) + { + if (string.Equals(kv.Key, "adsk3LeggedToken", StringComparison.OrdinalIgnoreCase)) + { + return kv.Value.Type == JTokenType.String ? kv.Value.Value() : kv.Value.ToString(); + } + } + } + } + catch (Exception ex) + { + Console.WriteLine($"ExtractTokenFromWorkItem failed: {ex.Message}"); + } + + return null; + } + + public void HandleDesignAutomationReadyEvent(object sender, DesignAutomationReadyEventArgs e) + { + Console.WriteLine("<> DA event raised."); + + var workItemId = Environment.ExpandEnvironmentVariables("%DAS_WORKITEM_ID%"); + + Console.WriteLine($"<> WorkItemId is '{workItemId}'"); + + var workItemFileName = $"{workItemId}_job.das"; + var workItemExists = File.Exists(workItemFileName); + Console.WriteLine($"Looking for WorkItem file at '{workItemFileName}', exists: {workItemExists}"); + if (workItemExists) + { + var workItemContent = File.ReadAllText(workItemFileName); + + var token = ExtractTokenFromWorkItem(workItemContent); + if (!string.IsNullOrEmpty(token)) + { + Console.WriteLine($"<> Extracted token from workItem content."); + } + } + + // Local Change + //WorkItemFolder = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); + + var dynTempDir = Path.Combine(WorkItemFolder, "dyn_tmp"); + var app = e.DesignAutomationData?.RevitApp; + Console.WriteLine("<> Preparing Dynamo model. Vers 1"); + + SetupDARequest? setupReq = null; + var setupReqPath = Path.Combine(WorkItemFolder, "setup.json"); + if (File.Exists(setupReqPath)) + { + try + { + var setupRequest = File.ReadAllText(setupReqPath); + Console.WriteLine(setupRequest); + + setupReq = JsonConvert.DeserializeObject(setupRequest, new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.Auto }); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + } + + // Ensure we have a pre-built graph output folder. + var graphOutputFolder = Path.Combine(WorkItemFolder, "output"); + try + { + //The output folder is basically a feature that we provide to DAAS_DA users. + //It offers an out of the box place where graphs can produce data / content(ex.images, xml reports etc). + //If creation of the folder fails, then most likely the graph execution will have nodes that fail and will report those nodes back to the user. ALso the output.zip file will not be sent back to the user. + //This ootb "output" folder feature may be scrapped for something more generic in the future + Console.WriteLine("Checking for output folder"); + if (!Directory.Exists(graphOutputFolder)) + { + Console.WriteLine("Output folder does not exist. Creating.."); + Directory.CreateDirectory(graphOutputFolder); + } + } + catch (Exception ex) + { + Console.WriteLine($"Failed to create output folder. {ex.Message}"); + } + + Document? doc = null; + var cModel = setupReq?.OpenCloudModelLocation; + if (cModel != null) + { + try + { + Console.WriteLine($"Opening cloud model with Region: {cModel.Region}, Project: {cModel.ProjectGuid}, Model: {cModel.ModelGuid}"); + + var cloudModelPath = ModelPathUtils.ConvertCloudGUIDsToCloudPath(cModel.Region, cModel.ProjectGuid, cModel.ModelGuid); + Console.WriteLine(doc == null ? $"Cloud model path is {JsonConvert.SerializeObject(cloudModelPath)}" : "doc is not null before opening cloud model"); + doc = app?.OpenDocumentFile(cloudModelPath, new OpenOptions()); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + } + else if (setupReq?.LocalModelFileName != null) + { + try + { + var localModelPath = Path.Combine(WorkItemFolder, setupReq.LocalModelFileName); + Console.WriteLine($"Opening local model at {localModelPath}"); + doc = app?.OpenDocumentFile(localModelPath); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + } + else + { + doc = e.DesignAutomationData?.RevitDoc; + } + + // Startup a new project, maybe an option we can have ? + //app.NewProjectDocument(Autodesk.Revit.DB.UnitSystem.Metric); + + if (doc == null) throw new InvalidOperationException("Could not open revit document."); + + var hostloc = typeof(Autodesk.Revit.ApplicationServices.Application).Assembly.Location; + var asmLocation = controlledApplication.SharedComponentsLocation; + Console.WriteLine($"using asm at location {asmLocation}"); + Console.WriteLine($"Is Loaded {LoadMessage}"); + + // need this for cloud, does not work on local + var userDataFolder = Path.Combine(dynTempDir, "Dynamo Revit"); + var commonDataFolder = Path.Combine(dynTempDir, "Dynamo"); + + DocumentManager.Instance.PrepareForDesignAutomation(app); + + var loadedLibGVersion = ASMPrealoaderUtils.PreloadAsmFromRevit(asmLocation, DynamoPath); + var geometryFactoryPath = ASMPrealoaderUtils.GetGeometryFactoryPath(DynamoPath, loadedLibGVersion); + + PreInstallPythonDependencies(); + + model = Dynamo.Applications.Models.RevitDynamoModel.Start( + new DefaultStartConfiguration + { + DynamoCorePath = DynamoPath, + DynamoHostPath = DynamoRevitPath, + GeometryFactoryPath = geometryFactoryPath, + PathResolver = new RevitPathResolver(userDataFolder, commonDataFolder), + Context = GetRevitContext(app), + AuthProvider = new RevitOAuth2Provider(SynchronizationContext.Current ?? new SynchronizationContext()), + ProcessMode = TaskProcessMode.Synchronous, + CLIMode = true, + IsHeadless = true, + IsServiceMode = true + }); + + LoadMessage = model != null ? "loaded" : "no loaded"; + + SetupProfilingHandlers(model); + + var playerHost = new PlayerHostDynamoDefault(model, new DynamoPlayerLogger(logConfig)); + var workflows = new DynamoModelWorkflows( + playerHost, + new DynamoPlayerLogger(logConfig)); + + var controller = new DynamoControllerImplementation(playerHost, workflows, + new DynamoPlayerLogger(logConfig)); + + DynamoPlayerLogger.Initialize(playerHost); + + workflows.LoadDependencies(new GraphTarget() { DependenciesPath = WorkItemFolder }); + + var dynHandler = new Handler(playerHost, [new DARunGraphController(controller, model, WorkItemFolder)]); + + var runContent = File.ReadAllText(Path.Combine(WorkItemFolder, "run.json")); + var testFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + + var output = string.Empty; + try + { + var res = dynHandler.HandleRoute("POST", "/v1/graph/run", runContent); + output = res.Result; + + // Force transaction close for now. + // This is already called on RevitDynamoModel.OnEvaluationCompleted. + // TODO: figure out if this is required here (I noticed, a couple of times, saving the rvt failed after running a graph) + // ex. Operation is not permitted when there is any open sub-transaction, transaction, or transaction group. + // DYN-10310 + RevitServices.Transactions.TransactionManager.Instance?.ForceCloseTransaction(); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + + Console.WriteLine(output); + File.WriteAllText(Path.Combine(WorkItemFolder, "result.json"), output); + + // Default, save the rvt + bool saveRvt = setupReq?.GenerateOutputModel ?? true; + Console.WriteLine($"{nameof(saveRvt)} is set to {saveRvt}"); + if (saveRvt) + { + try + { + if (doc.IsModelInCloud) + { + Console.WriteLine("Document is in cloud."); + if (doc.IsWorkshared) // work-shared/C4R model + { + Console.WriteLine("Document is C4R."); + // Syncronize with central + //SynchronizeWithCentralOptions swc = new SynchronizeWithCentralOptions(); + //swc.SetRelinquishOptions(new RelinquishOptions(/*relinquishAll*/true));// Should this be configurable? + //doc.SynchronizeWithCentral(new TransactWithCentralOptions(), swc); + + // Save the project locally (this will detach the model from the cloud, but we will re-upload at a new location) + doc.SaveAs(Path.Combine(WorkItemFolder, setupReq.LocalModelFileName)); + } + else + {// Single user cloud model + Console.WriteLine("Document is single-user cloud model."); + + // Save the project locally (this will detach the model from the cloud, but we will re-upload at a new location) + doc.SaveAs(Path.Combine(WorkItemFolder, setupReq.LocalModelFileName)); + + /* TODO: figure out if we need to make this work and how. + + doc.SaveCloudModel(); + + Console.WriteLine($"uploading with token {token}"); + // TODO: For single-user cloud models, we need to publish the model after saving so that the changes are reflected in the cloud. + var cmPath = doc.GetCloudModelPath(); + var dmClient = new DataManagementClient(null, new StaticAuthenticationProvider(token)); + var projId = "b." + setupReq.SaveCloudModelLocation.AccountId; + + var publishTask = dmClient.ExecutePublishModelAsync(projId, new PublishModelPayload() + { + Type = TypeCommands.Commands, + Attributes = new PublishModelPayloadAttributes() + { + Extension = new PublishModelPayloadAttributesExtension() + { + Type = TypeCommandtypePublishmodel.CommandsautodeskBim360C4RModelPublish, + VarVersion = "1.0.0" + } + }, + Relationships = new PublishModelPayloadRelationships() + { + Resources = new PublishModelPayloadRelationshipsResources() + { + Data = new List + { + new PublishModelPayloadRelationshipsResourcesData() + { + Id = cmPath.GetModelGUID().ToString(), + Type = TypeItem.Items + } + } + } + } + }); + + publishTask.Wait(); + PublishModel respo = publishTask.Result; + Console.WriteLine($"Publish result: {JsonConvert.SerializeObject(respo)}"); + */ + } + } + else + { + /* TODO: Figure ou tif this is useful. + var newLoc = setupReq?.SaveCloudModelLocation; + if (newLoc != null) + { + Console.WriteLine($"Saving to new cloud model location with AccountId: {newLoc.AccountId}, ProjectId: {newLoc.ProjectId}, FolderId: {newLoc.FolderId}, ModelName: {newLoc.ModelName}"); + doc.SaveAsCloudModel(newLoc.AccountId, newLoc.ProjectId, newLoc.FolderId, newLoc.ModelName ?? Path.GetFileName(doc.PathName)); + }*/ + + // Save locally + doc.SaveAs(Path.Combine(WorkItemFolder, setupReq.LocalModelFileName), new SaveAsOptions() { OverwriteExistingFile = true }); + } + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + } + + try + { + // If the out put folder exists and is empty, then delete it so we don't generate empty output zip files. + if (Directory.Exists(graphOutputFolder) && !Directory.EnumerateFileSystemEntries(graphOutputFolder).Any()) + { + Console.WriteLine("The output folder is empty."); + Directory.Delete(graphOutputFolder); + } + } + catch (Exception ex) + { + Console.WriteLine($"Failed to delete the empty output folder. {ex.Message}"); + } + + e.Succeeded = true; + } + + internal void SetupProfilingHandlers(DynamoModel model) + { + model.WorkspaceOpened += ws => + { + if (ws is not HomeWorkspaceModel homeWorkspace) return; + + var nodeHandlers = new Dictionary[]>(); + + EventHandler evaluationStartedHandler = (sender, args) => + { + homeWorkspace.EngineController.EnableProfiling(true, homeWorkspace, homeWorkspace.Nodes); + Console.WriteLine($"{DateTime.UtcNow:u} : Profiling enabled for {homeWorkspace.Name} dynamo workspace"); + }; + + EventHandler evaluationCompletedHandler = (sender, args) => + { + if (workspaceHandlers.TryGetValue(homeWorkspace, out var handlers)) + { + CleanupWorkspaceHandlers(homeWorkspace, handlers.evaluationStartedHandler, handlers.evaluationCompletedHandler, handlers.nodeHandlers); + } + }; + + foreach (var node in homeWorkspace.Nodes) + { + Action beginHandler = nm => + { + Console.WriteLine($"{DateTime.UtcNow:u} : Node {nm.Name} started execution."); + }; + + Action endHandler = nm => + { + var outputSummary = DALogger.SerializeNodeOutputs(nm, homeWorkspace.EngineController); + if (!string.IsNullOrEmpty(outputSummary)) + Console.WriteLine($"{DateTime.UtcNow:u} : Node {nm.Name} outputs: {outputSummary}"); + + var runtimeStatus = homeWorkspace.EngineController.LiveRunnerRuntimeCore.RuntimeStatus; + var nodeMessages = DALogger.GetNodeMessages(runtimeStatus, nm.GUID); + if (!string.IsNullOrEmpty(nodeMessages)) + Console.WriteLine($"{DateTime.UtcNow:u} : Node {nm.Name} messages: {nodeMessages}"); + + Console.WriteLine($"{DateTime.UtcNow:u} : Node {nm.Name} finished execution."); + }; + + node.NodeExecutionBegin += beginHandler; + node.NodeExecutionEnd += endHandler; + + nodeHandlers[node] = [beginHandler, endHandler]; + } + + homeWorkspace.EvaluationStarted += evaluationStartedHandler; + homeWorkspace.EvaluationCompleted += evaluationCompletedHandler; + + workspaceHandlers[homeWorkspace] = (evaluationStartedHandler, evaluationCompletedHandler, nodeHandlers); + }; + } + + private void CleanupWorkspaceHandlers( + HomeWorkspaceModel workspace, + EventHandler? evaluationStartedHandler, + EventHandler? evaluationCompletedHandler, + Dictionary[]> nodeHandlers) + { + if (evaluationStartedHandler != null) + workspace.EvaluationStarted -= evaluationStartedHandler; + + if (evaluationCompletedHandler != null) + workspace.EvaluationCompleted -= evaluationCompletedHandler; + + foreach (var kvp in nodeHandlers) + { + var node = kvp.Key; + var nodeHandlerArray = kvp.Value; + + if (nodeHandlerArray.Length >= 2) + { + node.NodeExecutionBegin -= nodeHandlerArray[0]; + node.NodeExecutionEnd -= nodeHandlerArray[1]; + } + } + + workspaceHandlers.Remove(workspace); + } + + private void PreInstallPythonDependencies() + { + try + { + // Preload all python assemblies at the PythonDllFolder. + foreach (var pyDll in Directory.EnumerateFiles(Path.Combine(WorkItemFolder, PythonDllFolder), "*.dll")) + { + Assembly.LoadFrom(pyDll); + } + + var pyIncluded = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(x => x.GetName().Name == "Python.Included"); + if (pyIncluded == null) + { + throw new Exception("Could not find Python.Included assembly"); + } + var type = pyIncluded.GetType("Python.Included.Installer"); + if (type == null) + { + throw new Exception("null Installer type"); + } + var property = type.GetProperty("INSTALL_PATH", BindingFlags.Public | BindingFlags.Static); + if (property == null) + { + throw new Exception("null INSTALL_PATH property"); + } + + // Set the python install location to the DA workfolder (that is the only place we have wrie access) + property.SetValue(null, WorkItemFolder); + + // Dynamo's 'VerifyEngineReferences' wants all the PythonEngine's dependencies to be in the Dynamo folder. + // Temporary until we fix it on the Dynamo side. + if (PythonEngineManager.Instance.AvailableEngines.Count == 0) + { + PropertyInfo instanceProp = typeof(CPythonEvaluator).GetProperty("Instance", BindingFlags.NonPublic | BindingFlags.Static); + if (instanceProp != null) + { + PythonEngine engine = (PythonEngine)instanceProp.GetValue(null); + if (engine == null) + { + throw new Exception($"Could not get a valid PythonEngine instance"); + } + + PythonEngineManager.Instance.AvailableEngines.Add(engine); + } + } + } + catch (Exception ex) + { + Console.WriteLine("Could not setup python " + ex.Message); + } + } + } +} diff --git a/src/DADynamoApp/DALogger.cs b/src/DADynamoApp/DALogger.cs new file mode 100644 index 0000000000..7c901150b1 --- /dev/null +++ b/src/DADynamoApp/DALogger.cs @@ -0,0 +1,149 @@ +using Dynamo.Graph.Nodes; +using ProtoCore; +using System.Reflection; +using System.Text.Json; + +[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("RevitSystemTests")] + +namespace DADynamoApp; + +/// +/// Utility helpers for DynamoRevit Design Automation profiling output. +/// All Dynamo internal logging is already redirected to stdout by IsServiceMode=true. +/// This class provides node output serialization via reflection into DynamoPlayer. +/// +internal static class DALogger +{ + // Cached reflection members for Player's WatchNodeHandler methods + private static MethodInfo? getNodeValueMethod; + private static MethodInfo? processWatchTreeMethod; + + private static readonly JsonSerializerOptions jsonOptions = new JsonSerializerOptions + { + WriteIndented = true, + DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingDefault + }; + + /// + /// Serializes node output values by getting data from the runtime mirror + /// and using Player's serialization logic via reflection. + /// + public static string SerializeNodeOutputs(NodeModel node, Dynamo.Engine.EngineController engineController, int maxLength = 2000) + { + try + { + var variableName = node.AstIdentifierForPreview.Value; + if (string.IsNullOrEmpty(variableName)) return string.Empty; + + var runtimeMirror = engineController.GetMirror(variableName); + if (runtimeMirror == null) return string.Empty; + + var mirrorData = runtimeMirror.GetData(); + if (mirrorData == null) return string.Empty; + + var valueContainer = GetNodeValueStringFromMirrorData(mirrorData); + if (valueContainer == null) return string.Empty; + + var valueString = JsonSerializer.Serialize(valueContainer, jsonOptions); + if (string.IsNullOrEmpty(valueString)) return string.Empty; + + if (valueString.Length > maxLength) + valueString = valueString.Substring(0, maxLength) + $"... (truncated from {valueString.Length} chars)"; + + return valueString; + } + catch (Exception ex) + { + Console.WriteLine($"Error serializing node outputs: {ex}"); + return string.Empty; + } + } + + private static object? GetNodeValueStringFromMirrorData(object mirrorData) + { + try + { + var obj = GetNodeValueViaReflection(mirrorData); + if (obj == null) return null; + + if (obj is System.Collections.IList list && list.Count == 0) + return new { Value = "Empty List" }; + + if (obj is System.Collections.IDictionary dict && dict.Count == 0) + return new { Value = "Empty Dictionary" }; + + return ProcessWatchTreeViaReflection(obj); + } + catch (Exception ex) + { + Console.WriteLine($"Error in GetNodeValueStringFromMirrorData: {ex}"); + return null; + } + } + + private static object? GetNodeValueViaReflection(object mirrorData) + { + if (getNodeValueMethod == null) + { + var assembly = AppDomain.CurrentDomain.GetAssemblies() + .FirstOrDefault(a => a.GetName().Name == "DynamoPlayer.Workflows") + ?? throw new InvalidOperationException("DynamoPlayer.Workflows assembly not found"); + + var type = assembly.GetType("DynamoPlayer.WatchNodeHandler") + ?? throw new InvalidOperationException("WatchNodeHandler type not found"); + + getNodeValueMethod = type.GetMethod("GetNodeValue", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static) + ?? throw new InvalidOperationException("GetNodeValue method not found"); + } + + try + { + return getNodeValueMethod.Invoke(null, [mirrorData]); + } + catch (TargetInvocationException ex) + { + throw new InvalidOperationException($"GetNodeValue invocation failed: {ex.InnerException?.Message}", ex.InnerException); + } + } + + private static object? ProcessWatchTreeViaReflection(object obj) + { + if (processWatchTreeMethod == null) + { + var assembly = AppDomain.CurrentDomain.GetAssemblies() + .FirstOrDefault(a => a.GetName().Name == "DynamoPlayer.Workflows") + ?? throw new InvalidOperationException("DynamoPlayer.Workflows assembly not found"); + + var type = assembly.GetType("DynamoPlayer.WatchNodeHandler") + ?? throw new InvalidOperationException("WatchNodeHandler type not found"); + + processWatchTreeMethod = type.GetMethod("ProcessWatchTree", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static) + ?? throw new InvalidOperationException("ProcessWatchTree method not found"); + } + + try + { + return processWatchTreeMethod.Invoke(null, [obj, null]); + } + catch (TargetInvocationException ex) + { + throw new InvalidOperationException($"ProcessWatchTree invocation failed: {ex.InnerException?.Message}", ex.InnerException); + } + } + + /// + /// Gets runtime warnings for a specific node as a JSON string. + /// + public static string GetNodeMessages(RuntimeStatus runtimeStatus, Guid nodeId) + { + var warnings = new List(); + + foreach (var warning in runtimeStatus.Warnings) + { + if (warning.GraphNodeGuid == nodeId) + warnings.Add(warning.Message); + } + + return JsonSerializer.Serialize(new { warnings = warnings.Count > 0 ? warnings : null }, jsonOptions); + } +} diff --git a/src/DADynamoApp/DARunGraphController.cs b/src/DADynamoApp/DARunGraphController.cs new file mode 100644 index 0000000000..e061599b44 --- /dev/null +++ b/src/DADynamoApp/DARunGraphController.cs @@ -0,0 +1,33 @@ +using Dynamo.Models; +using DynamoPlayer; + +namespace DADynamoApp +{ + internal class DARunGraphController : DynamoController + { + IDynamoController implementation; + string workFolder = string.Empty; + DynamoModel model; + + public DARunGraphController(IDynamoController implementation, DynamoModel model, string workFolder) : base(implementation) + { + this.workFolder = workFolder; + this.implementation = implementation; + this.model = model; + } + + [Route("graph/run", Name = "post-graph-run")] + public new Task PostGraphRun([FromBody] RunGraph body) + { + if (body.Target is CurrentGraphTarget) + { + this.model.OpenFileFromPath(Path.Combine(workFolder, "run.dyn")); + } + else if (body.Target is PathGraphTarget pGraphTarget) + { + pGraphTarget.Path = Path.Combine(this.workFolder, pGraphTarget.Path); + } + return implementation.PostGraphRunAsync(body); + } + } +} \ No newline at end of file diff --git a/src/DADynamoApp/SetupDARequest.cs b/src/DADynamoApp/SetupDARequest.cs new file mode 100644 index 0000000000..ab16a6a8f7 --- /dev/null +++ b/src/DADynamoApp/SetupDARequest.cs @@ -0,0 +1,72 @@ +using Newtonsoft.Json; + +namespace DADynamoApp +{ + /// + /// Configuration details for a cloud model. + /// + internal class OpenCloudModelLocation + { + /// + /// Represents the region where the cloud model is hosted. + /// + public string Region; + + /// + /// Represents the unique identifier for a project. + /// + public Guid ProjectGuid; + + /// + /// Represents the unique identifier for the model. + /// + public Guid ModelGuid; + } + + /// + /// Represents the save location for the current DA work model. + /// + internal class SaveCloudModelLocation + { + /// + /// Gets or sets the unique identifier for the account. + /// + public Guid AccountId { get; set; } + + /// + /// Gets or sets the unique identifier for the project. + /// + public Guid ProjectId { get; set; } + + /// + /// Gets or sets the unique identifier for the folder. + /// + public string FolderId { get; set; } + + /// + /// Gets or sets the name of the model to be created on the save operation. + /// + public string ModelName { get; set; } = string.Empty; + } + + /// + /// Request body used to setup aspects of the Design Automation environment. + /// + internal class SetupDARequest + { + // + // Summary: + // Save the revit document to the default result.rvt file. + [JsonProperty(nameof(GenerateOutputModel), Required = Required.DisallowNull, NullValueHandling = NullValueHandling.Ignore)] + public bool GenerateOutputModel { get; set; } = false; + + /// + /// Gets or sets the name of the Revit model file. + /// + public string LocalModelFileName { get; set; } = string.Empty; + + public OpenCloudModelLocation? OpenCloudModelLocation { get; set; } = null; + + public SaveCloudModelLocation? SaveCloudModelLocation { get; set; } = null; + } +} diff --git a/src/DADynamoApp/app_bundle_template/DynamoRevitDA.bundle/Contents/Revit/DynamoRevit.addin b/src/DADynamoApp/app_bundle_template/DynamoRevitDA.bundle/Contents/Revit/DynamoRevit.addin new file mode 100644 index 0000000000..e044ae3c00 --- /dev/null +++ b/src/DADynamoApp/app_bundle_template/DynamoRevitDA.bundle/Contents/Revit/DynamoRevit.addin @@ -0,0 +1,13 @@ + + + + DynamoDesignAutomation + .\DADynamoApp.dll + d7fe1983-8f10-4983-98e2-c3cc332fc978 + DADynamoApp.DAApplication + "Run Dynamo in Design Automation" + Autodesk + + + + diff --git a/src/DADynamoApp/app_bundle_template/DynamoRevitDA.bundle/PackageContents.xml b/src/DADynamoApp/app_bundle_template/DynamoRevitDA.bundle/PackageContents.xml new file mode 100644 index 0000000000..1ba53e1a20 --- /dev/null +++ b/src/DADynamoApp/app_bundle_template/DynamoRevitDA.bundle/PackageContents.xml @@ -0,0 +1,15 @@ + + + + + + + diff --git a/src/DynamoRevit.All.sln b/src/DynamoRevit.All.sln index 0c88b9cf61..617c737787 100644 --- a/src/DynamoRevit.All.sln +++ b/src/DynamoRevit.All.sln @@ -50,6 +50,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AssemblyInfoGenerator", "As EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RevitSystemTests", "..\test\Libraries\RevitIntegrationTests\RevitSystemTests.csproj", "{9ADADC68-36A3-4A21-9B54-298154A88720}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DADynamoApp", "DADynamoApp\DADynamoApp.csproj", "{B3F7C2D1-4E8A-4B6C-A9D2-6F1E8C3B7A05}" +EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{4466E6F6-F644-43AB-96B3-5ECE1622E711}" ProjectSection(SolutionItems) = preProject ..\.version = ..\.version diff --git a/src/DynamoRevit.DA.sln b/src/DynamoRevit.DA.sln new file mode 100644 index 0000000000..5ef1122e35 --- /dev/null +++ b/src/DynamoRevit.DA.sln @@ -0,0 +1,99 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.1.32328.378 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Libraries", "Libraries", "{FA7BE306-A3B0-45FA-9D87-0C69E6932C13}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RevitNodes", "Libraries\RevitNodes\RevitNodes.csproj", "{0BC2A611-BD0E-4FCC-A1DE-81F14ED369B2}" + ProjectSection(ProjectDependencies) = postProject + {133FC760-5699-46D9-BEA6-E816B5F01016} = {133FC760-5699-46D9-BEA6-E816B5F01016} + EndProjectSection +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RevitNodesUI", "Libraries\RevitNodesUI\RevitNodesUI.csproj", "{75940ACC-3708-4526-8D91-7E3365BAF682}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RevitServices", "Libraries\RevitServices\RevitServices.csproj", "{E4701F9E-41AB-4044-8166-85D924FEB632}" + ProjectSection(ProjectDependencies) = postProject + {133FC760-5699-46D9-BEA6-E816B5F01016} = {133FC760-5699-46D9-BEA6-E816B5F01016} + EndProjectSection +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Migrations", "Libraries\Migrations\Migrations.csproj", "{06B9E5B0-7C50-4351-9D88-E159DC25755F}" + ProjectSection(ProjectDependencies) = postProject + {133FC760-5699-46D9-BEA6-E816B5F01016} = {133FC760-5699-46D9-BEA6-E816B5F01016} + EndProjectSection +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AssemblyInfoGenerator", "AssemblySharedInfoGenerator\AssemblyInfoGenerator.csproj", "{133FC760-5699-46D9-BEA6-E816B5F01016}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{4466E6F6-F644-43AB-96B3-5ECE1622E711}" + ProjectSection(SolutionItems) = preProject + ..\.version = ..\.version + ..\CHANGELOG.md = ..\CHANGELOG.md + ..\README.md = ..\README.md + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "config", "config", "{9568462D-249F-4494-856B-5B25751DB361}" + ProjectSection(SolutionItems) = preProject + Config.xml = Config.xml + Config\CS_SDK.props = Config\CS_SDK.props + Config\dynamo-nuget.config = Config\dynamo-nuget.config + Config\packages-template.aget = Config\packages-template.aget + Config\packages.aget = Config\packages.aget + Config\user_local.props = Config\user_local.props + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DADynamoApp", "DADynamoApp\DADynamoApp.csproj", "{66A0E1C8-2514-48B7-8406-536983F57F88}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DynamoRevit", "DynamoRevit\DynamoRevit.csproj", "{BD7126B6-E716-4024-854F-6DA2CFA25B84}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|NET80_DA = Debug|NET80_DA + Release|NET80_DA = Release|NET80_DA + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {0BC2A611-BD0E-4FCC-A1DE-81F14ED369B2}.Debug|NET80_DA.ActiveCfg = Debug|NET80_DA + {0BC2A611-BD0E-4FCC-A1DE-81F14ED369B2}.Debug|NET80_DA.Build.0 = Debug|NET80_DA + {0BC2A611-BD0E-4FCC-A1DE-81F14ED369B2}.Release|NET80_DA.ActiveCfg = Release|NET80_DA + {0BC2A611-BD0E-4FCC-A1DE-81F14ED369B2}.Release|NET80_DA.Build.0 = Release|NET80_DA + {75940ACC-3708-4526-8D91-7E3365BAF682}.Debug|NET80_DA.ActiveCfg = Debug|NET80_DA + {75940ACC-3708-4526-8D91-7E3365BAF682}.Debug|NET80_DA.Build.0 = Debug|NET80_DA + {75940ACC-3708-4526-8D91-7E3365BAF682}.Release|NET80_DA.ActiveCfg = Release|NET80_DA + {75940ACC-3708-4526-8D91-7E3365BAF682}.Release|NET80_DA.Build.0 = Release|NET80_DA + {E4701F9E-41AB-4044-8166-85D924FEB632}.Debug|NET80_DA.ActiveCfg = Debug|NET80_DA + {E4701F9E-41AB-4044-8166-85D924FEB632}.Debug|NET80_DA.Build.0 = Debug|NET80_DA + {E4701F9E-41AB-4044-8166-85D924FEB632}.Release|NET80_DA.ActiveCfg = Release|NET80_DA + {E4701F9E-41AB-4044-8166-85D924FEB632}.Release|NET80_DA.Build.0 = Release|NET80_DA + {06B9E5B0-7C50-4351-9D88-E159DC25755F}.Debug|NET80_DA.ActiveCfg = Debug|NET80_DA + {06B9E5B0-7C50-4351-9D88-E159DC25755F}.Debug|NET80_DA.Build.0 = Debug|NET80_DA + {06B9E5B0-7C50-4351-9D88-E159DC25755F}.Release|NET80_DA.ActiveCfg = Release|NET80_DA + {06B9E5B0-7C50-4351-9D88-E159DC25755F}.Release|NET80_DA.Build.0 = Release|NET80_DA + {133FC760-5699-46D9-BEA6-E816B5F01016}.Debug|NET80_DA.ActiveCfg = Debug|NET80_DA + {133FC760-5699-46D9-BEA6-E816B5F01016}.Debug|NET80_DA.Build.0 = Debug|NET80_DA + {133FC760-5699-46D9-BEA6-E816B5F01016}.Release|NET80_DA.ActiveCfg = Release|NET80_DA + {133FC760-5699-46D9-BEA6-E816B5F01016}.Release|NET80_DA.Build.0 = Release|NET80_DA + {66A0E1C8-2514-48B7-8406-536983F57F88}.Debug|NET80_DA.ActiveCfg = Debug|NET80_DA + {66A0E1C8-2514-48B7-8406-536983F57F88}.Debug|NET80_DA.Build.0 = Debug|NET80_DA + {66A0E1C8-2514-48B7-8406-536983F57F88}.Release|NET80_DA.ActiveCfg = Release|NET80_DA + {66A0E1C8-2514-48B7-8406-536983F57F88}.Release|NET80_DA.Build.0 = Release|NET80_DA + {BD7126B6-E716-4024-854F-6DA2CFA25B84}.Debug|NET80_DA.ActiveCfg = Debug|NET80_DA + {BD7126B6-E716-4024-854F-6DA2CFA25B84}.Debug|NET80_DA.Build.0 = Debug|NET80_DA + {BD7126B6-E716-4024-854F-6DA2CFA25B84}.Release|NET80_DA.ActiveCfg = Release|NET80_DA + {BD7126B6-E716-4024-854F-6DA2CFA25B84}.Release|NET80_DA.Build.0 = Release|NET80_DA + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {0BC2A611-BD0E-4FCC-A1DE-81F14ED369B2} = {FA7BE306-A3B0-45FA-9D87-0C69E6932C13} + {75940ACC-3708-4526-8D91-7E3365BAF682} = {FA7BE306-A3B0-45FA-9D87-0C69E6932C13} + {E4701F9E-41AB-4044-8166-85D924FEB632} = {FA7BE306-A3B0-45FA-9D87-0C69E6932C13} + {06B9E5B0-7C50-4351-9D88-E159DC25755F} = {FA7BE306-A3B0-45FA-9D87-0C69E6932C13} + {9568462D-249F-4494-856B-5B25751DB361} = {4466E6F6-F644-43AB-96B3-5ECE1622E711} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {757AAA40-191F-4673-9B04-8270A3370BCA} + EndGlobalSection + GlobalSection(SharedMSBuildProjectFiles) = preSolution + SharedUtilities\SharedUtilities.projitems*{66a0e1c8-2514-48b7-8406-536983f57f88}*SharedItemsImports = 5 + SharedUtilities\SharedUtilities.projitems*{bd7126b6-e716-4024-854f-6da2cfa25b84}*SharedItemsImports = 5 + EndGlobalSection +EndGlobal diff --git a/src/DynamoRevit/DynamoRevit.cs b/src/DynamoRevit/DynamoRevit.cs index 6cddc062bc..1da4c489ef 100644 --- a/src/DynamoRevit/DynamoRevit.cs +++ b/src/DynamoRevit/DynamoRevit.cs @@ -478,34 +478,6 @@ private static void UpdateSystemPathForProcess() #region Initialization - /// - /// DynamoShapeManager.dll is a companion assembly of Dynamo core components, - /// we do not want a static reference to it (since the Revit add-on can be - /// installed anywhere that's outside of Dynamo), we do not want a duplicated - /// reference to it. Here we use reflection to obtain GetGeometryFactoryPath - /// method, and call it to get the geometry factory assembly path. - /// - /// The path where DynamoShapeManager.dll can be - /// located. - /// The version of DynamoShapeManager.dll - /// Returns the full path to geometry factory assembly. - /// - public static string GetGeometryFactoryPath(string corePath, Version version) - { - var dynamoAsmPath = Path.Combine(corePath, "DynamoShapeManager.dll"); - var assembly = Assembly.LoadFrom(dynamoAsmPath); - if (assembly == null) - throw new FileNotFoundException("File not found", dynamoAsmPath); - - var utilities = assembly.GetType("DynamoShapeManager.Utilities"); - var getGeometryFactoryPath = utilities.GetMethod("GetGeometryFactoryPath2"); - - return (getGeometryFactoryPath.Invoke(null, - new object[] { corePath, version }) as string); - } - - - private static void PreloadDynamoCoreDlls() { // Assume Revit Install folder as look for root. Assembly name is compromised. @@ -564,15 +536,16 @@ private static RevitDynamoModel InitializeCoreModel(DynamoRevitCommandData comma // when Dynamo runs on top of Revit we must load the same version of ASM as revit // so tell Dynamo core we've loaded that version. - var loadedLibGVersion = PreloadAsmFromRevit(); + var asmLocation = DynamoRevitApp.ControlledApplication.SharedComponentsLocation; + var loadedLibGVersion = ASMPrealoaderUtils.PreloadAsmFromRevit(asmLocation, DynamoRevitApp.DynamoCorePath); return RevitDynamoModel.Start( new RevitDynamoModel.RevitStartConfiguration() { DynamoCorePath = corePath, DynamoHostPath = dynamoRevitRoot, - GeometryFactoryPath = GetGeometryFactoryPath(corePath, loadedLibGVersion), + GeometryFactoryPath = ASMPrealoaderUtils.GetGeometryFactoryPath(corePath, loadedLibGVersion), PathResolver = new RevitPathResolver(userDataFolder, commonDataFolder), Context = GetRevitContext(commandData), SchedulerThread = new RevitSchedulerThread(commandData.Application), @@ -584,61 +557,6 @@ private static RevitDynamoModel InitializeCoreModel(DynamoRevitCommandData comma }); } - internal static Version PreloadAsmFromRevit() - { - var asmLocation = DynamoRevitApp.ControlledApplication.SharedComponentsLocation; - - Version libGVersion = findRevitASMVersion(asmLocation); - var dynCorePath = DynamoRevitApp.DynamoCorePath; - // Get the corresponding libG preloader location for the target ASM loading version. - // If there is exact match preloader version to the target ASM version, use it, - // otherwise use the closest below. - var preloaderLocation = DynamoShapeManager.Utilities.GetLibGPreloaderLocation(libGVersion, dynCorePath); - - // [Tech Debt] (Will refactor the code later) - // The LibG version maybe different in Dynamo and Revit, using the one which is in Dynamo. - Version preLoadLibGVersion = PreloadLibGVersion(preloaderLocation); - DynamoShapeManager.Utilities.PreloadAsmFromPath(preloaderLocation, asmLocation); - return preLoadLibGVersion; - } - - // [Tech Debt] (Will refactor the code later) - /// - /// Return the preload version of LibG. - /// - /// - /// - internal static Version PreloadLibGVersion(string preloaderLocation) - { - preloaderLocation = new DirectoryInfo(preloaderLocation).Name; - var regExp = new Regex(@"^libg_(\d\d\d)_(\d)_(\d)$", RegexOptions.IgnoreCase); - - var match = regExp.Match(preloaderLocation); - if (match.Groups.Count == 4) - { - return new Version( - Convert.ToInt32(match.Groups[1].Value), - Convert.ToInt32(match.Groups[2].Value), - Convert.ToInt32(match.Groups[3].Value)); - } - - return new Version(); - } - - /// - /// Returns the version of ASM which is installed with Revit at the requested path. - /// This version number can be used to load the appropriate libG version. - /// - /// path where asm dlls are located, this is usually the product(Revit) install path - /// - internal static Version findRevitASMVersion(string asmLocation) - { - var lookup = new InstalledProductLookUp("Revit", "ASMAHL*.dll"); - var product = lookup.GetProductFromInstallPath(asmLocation); - var libGversion = new Version(product.VersionInfo.Item1, product.VersionInfo.Item2, product.VersionInfo.Item3); - return libGversion; - } - private static DynamoViewModel InitializeCoreViewModel(RevitDynamoModel revitDynamoModel) { var viewModel = DynamoRevitViewModel.Start( @@ -1106,96 +1024,4 @@ public static void AddIdleAction(Action a) } } } - - /// - /// Defines parameters used for loading internal Dynamo Revit packages - /// - [Serializable()] - public class InternalPackage - { - /// - /// keeps the path to the node file - /// - public string NodePath { get; set; } - - /// - /// keeps the path to the layoutSpecs.json file - /// - public string LayoutSpecsPath { get; set; } - } - internal static class DynamoRevitInternalNodes - { - private const string InternalNodesDir = "nodes"; - private static IEnumerable GetAllInternalPackageFiles() - { - string currentAssemblyPath = Assembly.GetExecutingAssembly().Location; - string currentAssemblyDir = Path.GetDirectoryName(currentAssemblyPath); - - string internalNodesDir = Path.Combine(currentAssemblyDir, InternalNodesDir); - if (false == Directory.Exists(internalNodesDir)) - { - return new List(); - } - - string[] internalNodesFolders = Directory.GetDirectories(internalNodesDir); - - List internalPackageFiles = new List(); - foreach (string dir in internalNodesFolders) - { - string internalPackageFile = Path.Combine(dir, "internalPackage.xml"); - if (true == File.Exists(internalPackageFile)) - { - internalPackageFiles.Add(internalPackageFile); - } - } - return internalPackageFiles; - } - private static IEnumerable ParseinternalPackageFiles(IEnumerable internalPackageFiles) - { - List internalPackages = new List(); - - foreach (string internalPackageFile in internalPackageFiles) - { - try - { - string internalPackageDir = Path.GetDirectoryName(internalPackageFile); - using (StreamReader reader = new StreamReader(internalPackageFile)) - { - XmlSerializer serializer = new XmlSerializer(typeof(InternalPackage)); - InternalPackage intPackage = serializer.Deserialize(reader) as InternalPackage; - - // convert to absolute path, if needed - if (false == Path.IsPathRooted(intPackage.NodePath)) - { - intPackage.NodePath = Path.Combine(internalPackageDir, intPackage.NodePath); - } - - // convert to absolute path, if needed - if (false == Path.IsPathRooted(intPackage.LayoutSpecsPath)) - { - intPackage.LayoutSpecsPath = Path.Combine(internalPackageDir, intPackage.LayoutSpecsPath); - } - - internalPackages.Add(intPackage); - } - } - catch (Exception) - { - Console.WriteLine(string.Format("Exception while trying to parse internalPackage file {0}", internalPackageFile)); - } - } - - return internalPackages; - } - internal static IEnumerable GetNodesToPreload() - { - IEnumerable internalPackageFiles = GetAllInternalPackageFiles(); - return ParseinternalPackageFiles(internalPackageFiles).Select(pkg => pkg.NodePath); - } - internal static IEnumerable GetLayoutSpecsFiles() - { - IEnumerable internalPackageFiles = GetAllInternalPackageFiles(); - return ParseinternalPackageFiles(internalPackageFiles).Select(pkg => pkg.LayoutSpecsPath); - } - } } \ No newline at end of file diff --git a/src/DynamoRevit/DynamoRevit.csproj b/src/DynamoRevit/DynamoRevit.csproj index 09d491cc40..546b822829 100644 --- a/src/DynamoRevit/DynamoRevit.csproj +++ b/src/DynamoRevit/DynamoRevit.csproj @@ -8,13 +8,9 @@ DynamoRevitDS + true - prompt - 3 - full $(NoWarn);618 - true - false MinimumRecommendedRules.ruleset false @@ -27,15 +23,6 @@ None - - false - TRACE;DEBUG - false - - - true - TRACE - true @@ -44,39 +31,9 @@ x64 - + - - $(PACKAGESPATH)\DynamoVisualProgramming.Core\lib\$(DCoreLibSubFolder)\DynamoApplications.dll - $(DYNAMOBUILDPATH)\DynamoApplications.dll - False - - - $(PACKAGESPATH)\DynamoVisualProgramming.DynamoServices\lib\netstandard2.0\DynamoServices.dll - $(DYNAMOBUILDPATH)\DynamoServices.dll - False - - - $(PACKAGESPATH)\Greg\lib\net8.0\Greg.dll - False - - - $(PACKAGESPATH)\GregRevitAuth\lib\net8.0\GregRevitAuth.dll - True - - - $(PACKAGESPATH)\Newtonsoft.Json\lib\netstandard2.0\Newtonsoft.Json.dll - False - - - $(PACKAGESPATH)\DynamoVisualProgramming.ZeroTouchLibrary\lib\$(DCoreLibSubFolder)\ProtoGeometry.dll - $(DYNAMOBUILDPATH)\ProtoGeometry.dll - False - $(REVITAPI)\RevitAPI.dll False @@ -110,38 +67,6 @@ Resources.en-US.Designer.cs - - - $(PACKAGESPATH)\DynamoVisualProgramming.Core\lib\$(DCoreLibSubFolder)\ProtoCore.dll - $(DYNAMOBUILDPATH)\ProtoCore.dll - False - - - $(PACKAGESPATH)\DynamoVisualProgramming.WpfUILibrary\lib\$(DCoreLibSubFolder)\DynamoCoreWpf.dll - $(DYNAMOBUILDPATH)\DynamoCoreWpf.dll - False - - - $(PACKAGESPATH)\DynamoVisualProgramming.Core\lib\$(DCoreLibSubFolder)\DynamoCore.dll - $(DYNAMOBUILDPATH)\DynamoCore.dll - False - - - $(PACKAGESPATH)\DynamoVisualProgramming.Core\lib\$(DCoreLibSubFolder)\DynamoUtilities.dll - $(DYNAMOBUILDPATH)\DynamoUtilities.dll - False - - - $(PACKAGESPATH)\DynamoVisualProgramming.Core\lib\$(DCoreLibSubFolder)\DynamoShapeManager.dll - $(DYNAMOBUILDPATH)\DynamoShapeManager.dll - False - - - $(PACKAGESPATH)\DynamoVisualProgramming.Core\lib\$(DCoreLibSubFolder)\DynamoInstallDetective.dll - $(DYNAMOBUILDPATH)\DynamoInstallDetective.dll - False - - @@ -155,4 +80,21 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/DynamoRevit/DynamoRevitApp.cs b/src/DynamoRevit/DynamoRevitApp.cs index 7f2366c671..9042c884f2 100644 --- a/src/DynamoRevit/DynamoRevitApp.cs +++ b/src/DynamoRevit/DynamoRevitApp.cs @@ -26,8 +26,6 @@ namespace Dynamo.Applications { - - [Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual), Regeneration(RegenerationOption.Manual)] public class DynamoRevitApp : IExternalApplication @@ -95,7 +93,6 @@ private static string GetDynamoRoot(string dynamoRevitRoot) private static string dynamopath; private static readonly Queue idleActionQueue = new Queue(10); - private static EventHandlerProxy proxy; private AddInCommandBinding dynamoCommand; private Result loadDependentComponents() @@ -253,9 +250,10 @@ public static void AddIdleAction(Action a) } } + [Obsolete("This property will be made internal")] public static EventHandlerProxy EventHandlerProxy { - get { return proxy; } + get { return EventHandlerProxy.Instance; } } // should be handled by the ModelUpdater class. But there are some @@ -286,28 +284,26 @@ private void SubscribeApplicationEvents() { UIControlledApplication.Idling += OnApplicationIdle; - proxy = new EventHandlerProxy(); - - UIControlledApplication.ViewActivated += proxy.OnApplicationViewActivated; - UIControlledApplication.ViewActivating += proxy.OnApplicationViewActivating; + UIControlledApplication.ViewActivated += EventHandlerProxy.Instance.OnApplicationViewActivated; + UIControlledApplication.ViewActivating += EventHandlerProxy.Instance.OnApplicationViewActivating; - ControlledApplication.DocumentClosing += proxy.OnApplicationDocumentClosing; - ControlledApplication.DocumentClosed += proxy.OnApplicationDocumentClosed; - ControlledApplication.DocumentOpened += proxy.OnApplicationDocumentOpened; + ControlledApplication.DocumentClosing += EventHandlerProxy.Instance.OnApplicationDocumentClosing; + ControlledApplication.DocumentClosed += EventHandlerProxy.Instance.OnApplicationDocumentClosed; + ControlledApplication.DocumentOpened += EventHandlerProxy.Instance.OnApplicationDocumentOpened; } private void UnsubscribeApplicationEvents() { UIControlledApplication.Idling -= OnApplicationIdle; - UIControlledApplication.ViewActivated -= proxy.OnApplicationViewActivated; - UIControlledApplication.ViewActivating -= proxy.OnApplicationViewActivating; + UIControlledApplication.ViewActivated -= EventHandlerProxy.Instance.OnApplicationViewActivated; + UIControlledApplication.ViewActivating -= EventHandlerProxy.Instance.OnApplicationViewActivating; - ControlledApplication.DocumentClosing -= proxy.OnApplicationDocumentClosing; - ControlledApplication.DocumentClosed -= proxy.OnApplicationDocumentClosed; - ControlledApplication.DocumentOpened -= proxy.OnApplicationDocumentOpened; + ControlledApplication.DocumentClosing -= EventHandlerProxy.Instance.OnApplicationDocumentClosing; + ControlledApplication.DocumentClosed -= EventHandlerProxy.Instance.OnApplicationDocumentClosed; + ControlledApplication.DocumentOpened -= EventHandlerProxy.Instance.OnApplicationDocumentOpened; - proxy = null; + EventHandlerProxy.Instance = null; } private void SubscribeAssemblyEvents() @@ -333,35 +329,7 @@ private void UnsubscribeAssemblyEvents() /// public static Assembly ResolveAssembly(object sender, ResolveEventArgs args) { - var assemblyPath = string.Empty; - var assemblyName = new AssemblyName(args.Name).Name + ".dll"; - - try - { - assemblyPath = Path.Combine(DynamoRevitApp.DynamoCorePath, assemblyName); - if(File.Exists(assemblyPath)) - { - return Assembly.LoadFrom(assemblyPath); - } - - var assemblyLocation = Assembly.GetExecutingAssembly().Location; - var assemblyDirectory = Path.GetDirectoryName(assemblyLocation); - - // Try "Dynamo 0.x\Revit_20xx" folder first... - assemblyPath = Path.Combine(assemblyDirectory, assemblyName); - if (!File.Exists(assemblyPath)) - { - // If assembly cannot be found, try in "Dynamo 0.x" folder. - var parentDirectory = Directory.GetParent(assemblyDirectory); - assemblyPath = Path.Combine(parentDirectory.FullName, assemblyName); - } - - return (File.Exists(assemblyPath) ? Assembly.LoadFrom(assemblyPath) : null); - } - catch (Exception ex) - { - throw new Exception(string.Format("The location of the assembly, {0} could not be resolved for loading.", assemblyPath), ex); - } + return DynamoRevitAssemblyResolver.ResolveDynamoAssembly(DynamoCorePath, null, args); } private void SubscribeDocumentChangedEvent() diff --git a/src/DynamoRevit/Models/RevitDynamoModel.cs b/src/DynamoRevit/Models/RevitDynamoModel.cs index bb5e59564f..5b227a711b 100644 --- a/src/DynamoRevit/Models/RevitDynamoModel.cs +++ b/src/DynamoRevit/Models/RevitDynamoModel.cs @@ -8,8 +8,11 @@ using System.Windows.Forms; using Autodesk.Revit.DB; using Autodesk.Revit.DB.Events; +#if !DESIGN_AUTOMATION using Autodesk.Revit.UI; using Autodesk.Revit.UI.Events; +using RevitServices.Threading; +#endif using Dynamo.Graph.Nodes; using Dynamo.Graph.Nodes.ZeroTouch; using Dynamo.Graph.Workspaces; @@ -27,7 +30,6 @@ using RevitServices.Elements; using RevitServices.Materials; using RevitServices.Persistence; -using RevitServices.Threading; using RevitServices.Transactions; using Category = Revit.Elements.Category; using Element = Autodesk.Revit.DB.Element; @@ -39,7 +41,9 @@ public class RevitDynamoModel : DynamoModel { public interface IRevitStartConfiguration : IStartConfiguration { +#if !DESIGN_AUTOMATION DynamoRevitCommandData ExternalCommandData { get; set; } +#endif } public struct RevitStartConfiguration : IRevitStartConfiguration @@ -55,7 +59,9 @@ public struct RevitStartConfiguration : IRevitStartConfiguration public string GeometryFactoryPath { get; set; } public IAuthProvider AuthProvider { get; set; } public string PackageManagerAddress { get; set; } +#if !DESIGN_AUTOMATION public DynamoRevitCommandData ExternalCommandData { get; set; } +#endif public IEnumerable Extensions { get; set; } public TaskProcessMode ProcessMode { get; set; } //the property will contain revit host information, to be passed on to Dynamo. @@ -69,9 +75,10 @@ public struct RevitStartConfiguration : IRevitStartConfiguration /// private bool updateCurrentUIDoc; +#if !DESIGN_AUTOMATION private readonly DynamoRevitCommandData externalCommandData; - - #region Events +#endif +#region Events public event EventHandler RevitDocumentChanged; @@ -155,7 +162,7 @@ protected override void OnWorkspaceAdded(WorkspaceModel workspace) var dm = DocumentManager.Instance; if (dm.CurrentDBDocument != null) { - SetRunEnabledBasedOnContext(dm.CurrentUIDocument.ActiveView); + SetRunEnabledBasedOnContext(dm.CurrentDBDocument.ActiveView); } } @@ -185,7 +192,7 @@ public bool IsInMatchingDocumentContext return false; // There's no current document stored. // Selection is not allowed in perspective view mode. - var view3D = dm.CurrentUIDocument.ActiveView as View3D; + var view3D = dm.CurrentDBDocument.ActiveView as View3D; if ((view3D != null) && view3D.IsPerspective) return false; // There's no view, or in perspective view. @@ -216,12 +223,12 @@ private RevitDynamoModel(IRevitStartConfiguration configuration) : base(configuration) { DisposeLogic.IsShuttingDown = false; - +#if !DESIGN_AUTOMATION externalCommandData = configuration.ExternalCommandData; - + SubscribeApplicationEvents(configuration.ExternalCommandData); +#endif SubscribeRevitServicesUpdaterEvents(); - SubscribeApplicationEvents(configuration.ExternalCommandData); InitializeDocumentManager(); SubscribeDocumentManagerEvents(); SubscribeTransactionManagerEvents(); @@ -230,7 +237,7 @@ private RevitDynamoModel(IRevitStartConfiguration configuration) : } - #endregion +#endregion #region trace reconciliation @@ -325,12 +332,14 @@ public override void PostTraceReconciliation(Dictionary> orph } else { +#if !DESIGN_AUTOMATION // Delete all the orphans. IdlePromise.ExecuteOnIdleAsync( () => { DeleteOrphanedElements(orphanedIds, Logger); }); +#endif } } @@ -422,7 +431,7 @@ private static void DeleteOrphanedElements(IEnumerable orphanedIds, ILog } } - #endregion +#endregion #region Initialization @@ -473,7 +482,7 @@ private void SetupPythonEngine(PythonEngine engine) engine.EvaluationStarted += OnPythonEvalStart; } - catch(FileNotFoundException ex) + catch (FileNotFoundException ex) { Logger.Log(ex); } @@ -540,6 +549,7 @@ private void SetupPython() internal void InitializeDocumentManager() { +#if !DESIGN_AUTOMATION // Set the intitial document. var activeUIDocument = DocumentManager.Instance.CurrentUIApplication.ActiveUIDocument; if (activeUIDocument != null) @@ -549,6 +559,7 @@ internal void InitializeDocumentManager() OnRevitDocumentChanged(); } +#endif } private static void InitializeMaterials() @@ -556,10 +567,14 @@ private static void InitializeMaterials() // Ensure that the current document has the needed materials // and graphic styles to support visualization in Revit. var mgr = MaterialsManager.Instance; +#if !DESIGN_AUTOMATION IdlePromise.ExecuteOnIdleAsync(mgr.InitializeForActiveDocumentOnIdle); +#else + mgr.InitializeForActiveDocumentOnIdle(); +#endif } - #endregion +#endregion #region Event subscribe/unsubscribe @@ -595,6 +610,7 @@ private void UnsubscribeDocumentManagerEvents() DocumentManager.OnLogError -= Logger.Log; } +#if !DESIGN_AUTOMATION private bool hasRegisteredApplicationEvents; private void SubscribeApplicationEvents(DynamoRevitCommandData commandData) { @@ -603,11 +619,11 @@ private void SubscribeApplicationEvents(DynamoRevitCommandData commandData) return; } - DynamoRevitApp.EventHandlerProxy.ViewActivating += OnApplicationViewActivating; - DynamoRevitApp.EventHandlerProxy.ViewActivated += OnApplicationViewActivated; - DynamoRevitApp.EventHandlerProxy.DocumentClosing += OnApplicationDocumentClosing; - DynamoRevitApp.EventHandlerProxy.DocumentClosed += OnApplicationDocumentClosed; - DynamoRevitApp.EventHandlerProxy.DocumentOpened += OnApplicationDocumentOpened; + RevitServices.EventHandler.EventHandlerProxy.Instance.ViewActivating += OnApplicationViewActivating; + RevitServices.EventHandler.EventHandlerProxy.Instance.ViewActivated += OnApplicationViewActivated; + RevitServices.EventHandler.EventHandlerProxy.Instance.DocumentClosing += OnApplicationDocumentClosing; + RevitServices.EventHandler.EventHandlerProxy.Instance.DocumentClosed += OnApplicationDocumentClosed; + RevitServices.EventHandler.EventHandlerProxy.Instance.DocumentOpened += OnApplicationDocumentOpened; hasRegisteredApplicationEvents = true; } @@ -619,16 +635,17 @@ private void UnsubscribeApplicationEvents(DynamoRevitCommandData commandData) return; } - DynamoRevitApp.EventHandlerProxy.ViewActivating -= OnApplicationViewActivating; - DynamoRevitApp.EventHandlerProxy.ViewActivated -= OnApplicationViewActivated; - DynamoRevitApp.EventHandlerProxy.DocumentClosing -= OnApplicationDocumentClosing; - DynamoRevitApp.EventHandlerProxy.DocumentClosed -= OnApplicationDocumentClosed; - DynamoRevitApp.EventHandlerProxy.DocumentOpened -= OnApplicationDocumentOpened; + RevitServices.EventHandler.EventHandlerProxy.Instance.ViewActivating -= OnApplicationViewActivating; + RevitServices.EventHandler.EventHandlerProxy.Instance.ViewActivated -= OnApplicationViewActivated; + RevitServices.EventHandler.EventHandlerProxy.Instance.DocumentClosing -= OnApplicationDocumentClosing; + RevitServices.EventHandler.EventHandlerProxy.Instance.DocumentClosed -= OnApplicationDocumentClosed; + RevitServices.EventHandler.EventHandlerProxy.Instance.DocumentOpened -= OnApplicationDocumentOpened; hasRegisteredApplicationEvents = false; } +#endif - #endregion +#endregion #region Application event handler /// @@ -666,6 +683,7 @@ private void OnApplicationDocumentClosed(object sender, DocumentClosedEventArgs HandleApplicationDocumentClosed(); } +#if !DESIGN_AUTOMATION /// /// Handler for Revit's ViewActivating event. /// Addins are not available in some views in Revit, notably perspective views. @@ -688,8 +706,8 @@ private void OnApplicationViewActivated(object sender, ViewActivatedEventArgs e) { HandleRevitViewActivated(); } - - #endregion +#endif +#endregion #region Public methods @@ -707,7 +725,11 @@ protected override void PreShutdownCore(bool shutdownHost) { if (shutdownHost) { +#if !DESIGN_AUTOMATION DynamoRevitApp.AddIdleAction(ShutdownRevitHostOnce); +#else + ShutdownRevitHostOnce(); +#endif } base.PreShutdownCore(shutdownHost); @@ -715,7 +737,6 @@ protected override void PreShutdownCore(bool shutdownHost) private static void ShutdownRevitHostOnce() { - var uiApplication = DocumentManager.Instance.CurrentUIApplication; ShutdownRevitHost(); } @@ -728,10 +749,13 @@ protected override void ShutDownCore(bool shutDownHost) // unsubscribe events RevitServicesUpdater.Instance.UnRegisterAllChangeHooks(); +#if !DESIGN_AUTOMATION UnsubscribeApplicationEvents(externalCommandData); +#endif UnsubscribeDocumentManagerEvents(); UnsubscribeRevitServicesUpdaterEvents(); UnsubscribeTransactionManagerEvents(); + PythonEngineManager.Instance.AvailableEngines.ToList().ForEach(engine => CleanUpPythonEngine(engine)); PythonEngineManager.Instance.AvailableEngines.CollectionChanged -= OnPythonEngineCollectionChanged; @@ -741,9 +765,11 @@ protected override void ShutDownCore(bool shutDownHost) protected override void PostShutdownCore(bool shutdownHost) { base.PostShutdownCore(shutdownHost); - + +#if !DESIGN_AUTOMATION // Always reset current UI document on shutdown DocumentManager.Instance.CurrentUIDocument = null; +#endif } /// @@ -830,7 +856,7 @@ var ws in Workspaces.OfType()) // If there is a current document, then set the run enabled // state based on whether the view just activated is // the same document. - if (DocumentManager.Instance.CurrentUIDocument != null) + if (DocumentManager.Instance.CurrentDBDocument != null) { var newEnabled = newView != null && newView.Document.Equals(DocumentManager.Instance.CurrentDBDocument); @@ -849,7 +875,7 @@ var ws in Workspaces.OfType()) } } - #endregion +#endregion #region Event handlers @@ -863,14 +889,15 @@ private void HandleApplicationDocumentOpened() // If the current document is null, for instance if there are // no documents open, then set the current document, and // present a message telling us where Dynamo is pointing. - if (DocumentManager.Instance.CurrentUIDocument == null) + if (DocumentManager.Instance.CurrentDBDocument == null) { +#if !DESIGN_AUTOMATION var activeUIDocument = DocumentManager.Instance.CurrentUIApplication.ActiveUIDocument; DocumentManager.Instance.CurrentUIDocument = activeUIDocument; if (activeUIDocument != null) DocumentManager.Instance.HandleDocumentActivation(activeUIDocument.ActiveView); - +#endif OnRevitDocumentChanged(); foreach (HomeWorkspaceModel ws in Workspaces.OfType()) @@ -901,7 +928,8 @@ private void HandleApplicationDocumentClosing(Document doc) /// private void HandleApplicationDocumentClosed() { - // If the active UI document is null, it means that all views have been +#if !DESIGN_AUTOMATION + // If the active UI document is null, it means that all views have been // closed from all document. Clear our reference, present a warning, // and disable running. if (DocumentManager.Instance.CurrentUIApplication.ActiveUIDocument == null) @@ -933,6 +961,7 @@ private void HandleApplicationDocumentClosed() { SetRunEnabledBasedOnContext(uiDoc.ActiveView); } +#endif } /// @@ -944,11 +973,12 @@ private void HandleRevitViewActivated() { // If there is no active document, then set it to whatever // document has just been activated - if (DocumentManager.Instance.CurrentUIDocument == null) + if (DocumentManager.Instance.CurrentDBDocument == null) { +#if !DESIGN_AUTOMATION DocumentManager.Instance.CurrentUIDocument = DocumentManager.Instance.CurrentUIApplication.ActiveUIDocument; - +#endif OnRevitDocumentChanged(); InitializeMaterials(); @@ -974,6 +1004,7 @@ private void ResetForNewDocument() private static void ShutdownRevitHost() { +#if !DESIGN_AUTOMATION // this method cannot be called without Revit 2014 var exitCommand = RevitCommandId.LookupPostableCommandId(PostableCommand.ExitRevit); var uiApplication = DocumentManager.Instance.CurrentUIApplication; @@ -986,6 +1017,7 @@ private static void ShutdownRevitHost() "A command in progress prevented Dynamo from " + "closing revit. Dynamo update will be cancelled."); } +#endif } private void TransactionManager_FailuresRaised(FailuresAccessor failuresAccessor) diff --git a/src/DynamoRevit/Properties/AssemblyInfo.cs b/src/DynamoRevit/Properties/AssemblyInfo.cs index 5996d78d11..58ea1f6a8b 100644 --- a/src/DynamoRevit/Properties/AssemblyInfo.cs +++ b/src/DynamoRevit/Properties/AssemblyInfo.cs @@ -9,4 +9,5 @@ [assembly: AssemblyCulture("")] [assembly: Guid("082cab33-cbc7-4e58-ae25-f0962f325d6e")] [assembly: InternalsVisibleTo("RevitTestServices")] -[assembly: InternalsVisibleTo("RevitSystemTests")] \ No newline at end of file +[assembly: InternalsVisibleTo("RevitSystemTests")] +[assembly: InternalsVisibleTo("DADynamoApp")] \ No newline at end of file diff --git a/src/DynamoRevit/Utilities/ASMPreloader.cs b/src/DynamoRevit/Utilities/ASMPreloader.cs new file mode 100644 index 0000000000..24c860cf06 --- /dev/null +++ b/src/DynamoRevit/Utilities/ASMPreloader.cs @@ -0,0 +1,91 @@ +using Autodesk.Revit.ApplicationServices; +using DynamoInstallDetective; +using System; +using System.IO; +using System.Reflection; +using System.Text.RegularExpressions; + +namespace Dynamo.Applications +{ + internal static class ASMPrealoaderUtils + { + /// + /// Returns the version of ASM which is installed with Revit at the requested path. + /// This version number can be used to load the appropriate libG version. + /// + /// path where asm dlls are located, this is usually the product(Revit) install path + /// + internal static Version findRevitASMVersion(string asmLocation) + { + var lookup = new InstalledProductLookUp("Revit", "ASMAHL*.dll"); + var product = lookup.GetProductFromInstallPath(asmLocation); + var libGversion = new Version(product.VersionInfo.Item1, product.VersionInfo.Item2, product.VersionInfo.Item3); + return libGversion; + } + + // [Tech Debt] (Will refactor the code later) + /// + /// Return the preload version of LibG. + /// + /// + /// + internal static Version PreloadLibGVersion(string preloaderLocation) + { + preloaderLocation = new DirectoryInfo(preloaderLocation).Name; + var regExp = new Regex(@"^libg_(\d\d\d)_(\d)_(\d)$", RegexOptions.IgnoreCase); + + var match = regExp.Match(preloaderLocation); + if (match.Groups.Count == 4) + { + return new Version( + Convert.ToInt32(match.Groups[1].Value), + Convert.ToInt32(match.Groups[2].Value), + Convert.ToInt32(match.Groups[3].Value)); + } + + return new Version(); + } + + internal static Version PreloadAsmFromRevit(string asmLocation, string dynamoCorePath) + { + Version libGVersion = findRevitASMVersion(asmLocation); + // Get the corresponding libG preloader location for the target ASM loading version. + // If there is exact match preloader version to the target ASM version, use it, + // otherwise use the closest below. + var preloaderLocation = DynamoShapeManager.Utilities.GetLibGPreloaderLocation(libGVersion, dynamoCorePath); + + // [Tech Debt] (Will refactor the code later) + // The LibG version maybe different in Dynamo and Revit, using the one which is in Dynamo. + Version preLoadLibGVersion = PreloadLibGVersion(preloaderLocation); + DynamoShapeManager.Utilities.PreloadAsmFromPath(preloaderLocation, asmLocation); + return preLoadLibGVersion; + } + + + /// + /// DynamoShapeManager.dll is a companion assembly of Dynamo core components, + /// we do not want a static reference to it (since the Revit add-on can be + /// installed anywhere that's outside of Dynamo), we do not want a duplicated + /// reference to it. Here we use reflection to obtain GetGeometryFactoryPath + /// method, and call it to get the geometry factory assembly path. + /// + /// The path where DynamoShapeManager.dll can be + /// located. + /// The version of DynamoShapeManager.dll + /// Returns the full path to geometry factory assembly. + /// + public static string GetGeometryFactoryPath(string corePath, Version version) + { + var dynamoAsmPath = Path.Combine(corePath, "DynamoShapeManager.dll"); + var assembly = Assembly.LoadFrom(dynamoAsmPath); + if (assembly == null) + throw new FileNotFoundException("File not found", dynamoAsmPath); + + var utilities = assembly.GetType("DynamoShapeManager.Utilities"); + var getGeometryFactoryPath = utilities.GetMethod("GetGeometryFactoryPath2"); + + return (getGeometryFactoryPath.Invoke(null, + new object[] { corePath, version }) as string); + } + } +} \ No newline at end of file diff --git a/src/DynamoRevit/Utilities/DynamoRevitInternalNodes.cs b/src/DynamoRevit/Utilities/DynamoRevitInternalNodes.cs new file mode 100644 index 0000000000..7b0460f5fa --- /dev/null +++ b/src/DynamoRevit/Utilities/DynamoRevitInternalNodes.cs @@ -0,0 +1,123 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Xml.Serialization; + +namespace Dynamo.Applications +{ + /// + /// Defines parameters used for loading internal Dynamo Revit packages + /// + [Serializable()] + public class InternalPackage + { + /// + /// keeps the path to the node file + /// + public string NodePath { get; set; } + + /// + /// keeps the path to the layoutSpecs.json file + /// + public string LayoutSpecsPath { get; set; } + + /// + /// keeps paths to additional assembly load paths + /// + public List AdditionalAssemblyLoadPaths { get; set; } + } + + internal static class DynamoRevitInternalNodes + { + private const string InternalNodesDir = "nodes"; + private static IEnumerable GetAllInternalPackageFiles() + { + string currentAssemblyPath = Assembly.GetExecutingAssembly().Location; + string currentAssemblyDir = Path.GetDirectoryName(currentAssemblyPath); + + string internalNodesDir = Path.Combine(currentAssemblyDir, InternalNodesDir); + if (false == Directory.Exists(internalNodesDir)) + { + return new List(); + } + + string[] internalNodesFolders = Directory.GetDirectories(internalNodesDir); + + List internalPackageFiles = new List(); + foreach (string dir in internalNodesFolders) + { + string internalPackageFile = Path.Combine(dir, "internalPackage.xml"); + if (true == File.Exists(internalPackageFile)) + { + internalPackageFiles.Add(internalPackageFile); + } + } + return internalPackageFiles; + } + private static IEnumerable ParseinternalPackageFiles(IEnumerable internalPackageFiles) + { + List internalPackages = new List(); + string basePath = Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName); + + foreach (string internalPackageFile in internalPackageFiles) + { + try + { + string internalPackageDir = Path.GetDirectoryName(internalPackageFile); + using (StreamReader reader = new StreamReader(internalPackageFile)) + { + XmlSerializer serializer = new XmlSerializer(typeof(InternalPackage)); + InternalPackage intPackage = serializer.Deserialize(reader) as InternalPackage; + + // convert to absolute path, if needed + if (false == Path.IsPathRooted(intPackage.NodePath)) + { + intPackage.NodePath = Path.Combine(internalPackageDir, intPackage.NodePath); + } + + // convert to absolute path, if needed + if (false == Path.IsPathRooted(intPackage.LayoutSpecsPath)) + { + intPackage.LayoutSpecsPath = Path.Combine(internalPackageDir, intPackage.LayoutSpecsPath); + } + + // convert to absolute paths, if needed + if (null != intPackage.AdditionalAssemblyLoadPaths && intPackage.AdditionalAssemblyLoadPaths.Count > 0) + { + intPackage.AdditionalAssemblyLoadPaths = intPackage.AdditionalAssemblyLoadPaths + .Select(p => !Path.IsPathRooted(p) ? Path.Combine(basePath, p) : p) + .Where(Path.Exists).ToList(); + } + + internalPackages.Add(intPackage); + } + } + catch (Exception) + { + Console.WriteLine(string.Format("Exception while trying to parse internalPackage file {0}", internalPackageFile)); + } + } + + return internalPackages; + } + internal static IEnumerable GetNodesToPreload() + { + IEnumerable internalPackageFiles = GetAllInternalPackageFiles(); + return ParseinternalPackageFiles(internalPackageFiles).Select(pkg => pkg.NodePath); + } + internal static IEnumerable GetLayoutSpecsFiles() + { + IEnumerable internalPackageFiles = GetAllInternalPackageFiles(); + return ParseinternalPackageFiles(internalPackageFiles).Select(pkg => pkg.LayoutSpecsPath); + } + + internal static IEnumerable GetAdditionalAssemblyLoadPaths() + { + IEnumerable internalPackageFiles = GetAllInternalPackageFiles(); + return ParseinternalPackageFiles(internalPackageFiles).SelectMany(pkg => pkg.AdditionalAssemblyLoadPaths); + } + } +} \ No newline at end of file diff --git a/src/DynamoRevit/Utilities/internal class DynamoRevitAssemblyResolver.cs b/src/DynamoRevit/Utilities/internal class DynamoRevitAssemblyResolver.cs new file mode 100644 index 0000000000..bd9f2acbab --- /dev/null +++ b/src/DynamoRevit/Utilities/internal class DynamoRevitAssemblyResolver.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; + +internal class DynamoRevitAssemblyResolver +{ + /// + /// Handler to the ApplicationDomain's AssemblyResolve event. + /// If an assembly's location cannot be resolved, an exception is + /// thrown. Failure to resolve an assembly will leave Dynamo in + /// a bad state, so we should throw an exception here which gets caught + /// by our unhandled exception handler and presents the crash dialogue. + /// + /// + /// + /// + internal static Assembly ResolveDynamoAssembly(string dynamoCorePath, List additionalPaths, ResolveEventArgs args) + { + var assemblyPath = string.Empty; + var assemblyName = new AssemblyName(args.Name).Name + ".dll"; + + try + { + assemblyPath = Path.Combine(dynamoCorePath, assemblyName); + if (File.Exists(assemblyPath)) + { + return Assembly.LoadFrom(assemblyPath); + } + + if (additionalPaths != null) + { + foreach (var additionalPath in additionalPaths) + { + assemblyPath = Path.Combine(additionalPath, assemblyName); + if (File.Exists(assemblyPath)) + { + return Assembly.LoadFrom(assemblyPath); + } + } + } + + var assemblyLocation = Assembly.GetExecutingAssembly().Location; + var assemblyDirectory = Path.GetDirectoryName(assemblyLocation); + + // Try "Dynamo 0.x\Revit_20xx" folder first... + assemblyPath = Path.Combine(assemblyDirectory, assemblyName); + if (!File.Exists(assemblyPath)) + { + // If assembly cannot be found, try in "Dynamo 0.x" folder. + var parentDirectory = Directory.GetParent(assemblyDirectory); + assemblyPath = Path.Combine(parentDirectory.FullName, assemblyName); + } + + return (File.Exists(assemblyPath) ? Assembly.LoadFrom(assemblyPath) : null); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message + ex.StackTrace); + throw new Exception(string.Format("The location of the assembly, {0} could not be resolved for loading.", assemblyPath), ex); + } + } +} diff --git a/src/DynamoRevitIcons/DynamoRevitIcons.csproj b/src/DynamoRevitIcons/DynamoRevitIcons.csproj index 91b60c8a34..d046825f2c 100644 --- a/src/DynamoRevitIcons/DynamoRevitIcons.csproj +++ b/src/DynamoRevitIcons/DynamoRevitIcons.csproj @@ -7,16 +7,6 @@ prompt 4 - - full - false - TRACE;DEBUG;ENABLE_DYNAMO_SCHEDULER - - - pdbonly - true - TRACE - true @@ -25,7 +15,7 @@ + AssemblyFiles="$(SolutionDir)\AssemblySharedInfoGenerator\bin\AssemblyInfoGenerator.dll"> diff --git a/src/Libraries/Migrations/Migrations.csproj b/src/Libraries/Migrations/Migrations.csproj index 919c885c3b..377b84b838 100644 --- a/src/Libraries/Migrations/Migrations.csproj +++ b/src/Libraries/Migrations/Migrations.csproj @@ -7,46 +7,16 @@ true true $(NoWarn);CS3001;CS3002 - prompt - 4 - false $(OutputPath)\nodes\ - - true - full - false - DEBUG;TRACE - - - pdbonly - true - TRACE - - - - $(PACKAGESPATH)\DynamoVisualProgramming.DynamoServices\lib\netstandard2.0\DynamoServices.dll - $(DYNAMOBUILDPATH)\DynamoServices.dll - False - - - - - $(PACKAGESPATH)\DynamoVisualProgramming.Core\lib\$(DCoreLibSubFolder)\DynamoCore.dll - $(DYNAMOBUILDPATH)\DynamoCore.dll - False - - - $(PACKAGESPATH)\DynamoVisualProgramming.ZeroTouchLibrary\lib\$(DCoreLibSubFolder)\DynamoUnits.dll - $(DYNAMOBUILDPATH)\DynamoUnits.dll - False - - + + + \ No newline at end of file diff --git a/src/Libraries/RevitNodes/Elements/AdaptiveComponent.cs b/src/Libraries/RevitNodes/Elements/AdaptiveComponent.cs index 41e8edaf8a..4922e38232 100644 --- a/src/Libraries/RevitNodes/Elements/AdaptiveComponent.cs +++ b/src/Libraries/RevitNodes/Elements/AdaptiveComponent.cs @@ -555,7 +555,7 @@ private static AdaptiveComponent[] InternalByPoints(Point[][] points, FamilyType int numOfPoints = remainingPoints[i].Length; var aPoints = remainingPoints[i].ToXyzs(); - var creationData = DocumentManager.Instance.CurrentUIApplication.Application.Create. + var creationData = DocumentManager.Instance.CurrentDBDocument.Application.Create. NewFamilyInstanceCreationData(familyType.InternalFamilySymbol, aPoints); if (creationData != null) diff --git a/src/Libraries/RevitNodes/Elements/Element.cs b/src/Libraries/RevitNodes/Elements/Element.cs index 4216eb78ba..6a349ff810 100644 --- a/src/Libraries/RevitNodes/Elements/Element.cs +++ b/src/Libraries/RevitNodes/Elements/Element.cs @@ -287,6 +287,7 @@ public virtual void Dispose() // Do not delete Revit owned elements if (!IsRevitOwned && remainingBindings == 0 && !didRevitDelete) { +#if !DESIGN_AUTOMATION if(this.InternalElement is View && InternalElement.IsValidObject) { Autodesk.Revit.UI.UIDocument uIDocument = new Autodesk.Revit.UI.UIDocument(Document); @@ -300,6 +301,7 @@ public virtual void Dispose() throw new InvalidOperationException(string.Format(Properties.Resources.CantCloseLastOpenView, this.ToString())); } } +#endif DocumentManager.Instance.DeleteElement(new ElementUUID(InternalUniqueId)); } else @@ -492,7 +494,7 @@ public Element SetParameterByName(string parameterName, object value) public Element OverrideColorInView(Color color) { TransactionManager.Instance.EnsureInTransaction(DocumentManager.Instance.CurrentDBDocument); - var view = DocumentManager.Instance.CurrentUIDocument.ActiveView; + var view = DocumentManager.Instance.CurrentDBDocument.ActiveView; var ogs = new Autodesk.Revit.DB.OverrideGraphicSettings(); var patternCollector = new FilteredElementCollector(DocumentManager.Instance.CurrentDBDocument); @@ -518,7 +520,7 @@ public Element OverrideColorInView(Color color) public Element OverrideInView(Revit.Filter.OverrideGraphicSettings overrides, bool hide = false) { TransactionManager.Instance.EnsureInTransaction(DocumentManager.Instance.CurrentDBDocument); - var view = DocumentManager.Instance.CurrentUIDocument.ActiveView; + var view = DocumentManager.Instance.CurrentDBDocument.ActiveView; view.SetElementOverrides(InternalElementId, overrides.InternalOverrideGraphicSettings); if (hide) view.HideElements(new List() { InternalElementId }); else view.UnhideElements(new List() { InternalElementId }); @@ -534,7 +536,7 @@ public Revit.Filter.OverrideGraphicSettings OverridesInView { get { - var view = DocumentManager.Instance.CurrentUIDocument.ActiveView; + var view = DocumentManager.Instance.CurrentDBDocument.ActiveView; return new Filter.OverrideGraphicSettings(view.GetElementOverrides(InternalElementId)); } diff --git a/src/Libraries/RevitNodes/Elements/LinkElement.cs b/src/Libraries/RevitNodes/Elements/LinkElement.cs index a74ee16244..bedb4c42b5 100644 --- a/src/Libraries/RevitNodes/Elements/LinkElement.cs +++ b/src/Libraries/RevitNodes/Elements/LinkElement.cs @@ -50,12 +50,12 @@ public static class LinkElement } return matchingLinkInstances; } - + // TODO: move to a UI library +#if !DESIGN_AUTOMATION // helper for zooming to clicked green Id internal static void ZoomToLinkedElement(Element element) { - UIDocument uiDoc = DocumentManager.Instance.CurrentUIDocument; Autodesk.Revit.DB.View activeView = uiDoc.ActiveView; // get active UI view to use @@ -65,12 +65,12 @@ internal static void ZoomToLinkedElement(Element element) // use the center of the BoundingBox as zoom center BoundingBoxXYZ bb = element.InternalElement.get_BoundingBox(null); // if the BBox cannot be found, attempt to find it using the active view - if (bb==null) + if (bb == null) { - bb=element.InternalElement.get_BoundingBox(activeView); + bb = element.InternalElement.get_BoundingBox(activeView); } // finally, if the BB cannot be found at all - if (bb==null) + if (bb == null) { TaskDialog.Show("Revit", "No good view can be found."); return; @@ -88,6 +88,7 @@ internal static void ZoomToLinkedElement(Element element) uiview.ZoomAndCenterRectangle(min, max); } } +#endif // helper to return element's location with transform internal static object GetLinkElementLocation(Element linkElement) diff --git a/src/Libraries/RevitNodes/Elements/Views/Sheet.cs b/src/Libraries/RevitNodes/Elements/Views/Sheet.cs index b28407d482..056bca97a9 100644 --- a/src/Libraries/RevitNodes/Elements/Views/Sheet.cs +++ b/src/Libraries/RevitNodes/Elements/Views/Sheet.cs @@ -773,6 +773,8 @@ public static Sheet DuplicateSheet(Sheet sheet, bool duplicateWithContents = fal } } } + +#if !DESIGN_AUTOMATION if(newSheet == null) { Autodesk.Revit.UI.UIDocument uIDocument = new Autodesk.Revit.UI.UIDocument(Document); @@ -789,7 +791,8 @@ public static Sheet DuplicateSheet(Sheet sheet, bool duplicateWithContents = fal } } Document.Delete(elementIds); - } + } +#endif } if (newSheet == null && TraceElements.Count == 0) @@ -842,7 +845,7 @@ public static Sheet DuplicateSheet(Sheet sheet, bool duplicateWithContents = fal return newSheet; } - #endregion +#endregion #region Internal static constructors diff --git a/src/Libraries/RevitNodes/Elements/Views/View.cs b/src/Libraries/RevitNodes/Elements/Views/View.cs index f8ab6d7cc6..cf27867df8 100644 --- a/src/Libraries/RevitNodes/Elements/Views/View.cs +++ b/src/Libraries/RevitNodes/Elements/Views/View.cs @@ -618,6 +618,8 @@ public static Revit.Elements.Views.View DuplicateView(View view, string viewDupl { newViewName = prefix + view.Name + suffix; } + +#if !DESIGN_AUTOMATION Autodesk.Revit.UI.UIDocument uIDocument = new Autodesk.Revit.UI.UIDocument(Document); var openedViews = uIDocument.GetOpenUIViews().ToList(); @@ -630,8 +632,9 @@ public static Revit.Elements.Views.View DuplicateView(View view, string viewDupl else count--; } - - if (count == 0) +#endif + + if (count == 0) { if (!CheckUniqueViewName(newViewName)) throw new ArgumentException(String.Format(Properties.Resources.ViewNameExists, newViewName)); @@ -651,6 +654,7 @@ public static Revit.Elements.Views.View DuplicateView(View view, string viewDupl var param = newView.InternalView.get_Parameter(BuiltInParameter.VIEW_NAME); param.Set(newViewName); } +#if !DESIGN_AUTOMATION if (viewElement != null) { var shouldClosedViews = openedViews.FindAll(x => viewElement.Id == x.ViewId); @@ -664,7 +668,8 @@ public static Revit.Elements.Views.View DuplicateView(View view, string viewDupl throw new InvalidOperationException(string.Format(Properties.Resources.CantCloseLastOpenView, viewElement.ToString())); } } - } + } +#endif } ElementBinder.CleanupAndSetElementForTrace(Document, newView.InternalElement); @@ -704,7 +709,7 @@ private static Boolean CheckUniqueViewName(String viewName) return IsUnique; } - #endregion +#endregion #region CropBox diff --git a/src/Libraries/RevitNodes/Properties/AssemblyInfo.cs b/src/Libraries/RevitNodes/Properties/AssemblyInfo.cs index 1d6207cd65..31666a56c9 100644 --- a/src/Libraries/RevitNodes/Properties/AssemblyInfo.cs +++ b/src/Libraries/RevitNodes/Properties/AssemblyInfo.cs @@ -6,3 +6,4 @@ [assembly: Guid("17f8f9d8-c00e-4c11-9eb1-06a716689de9")] [assembly: InternalsVisibleTo("RevitNodesTests")] [assembly: InternalsVisibleTo("DynamoRevitDS")] +[assembly: InternalsVisibleTo("DADynamoApp")] diff --git a/src/Libraries/RevitNodes/RevitNodes.csproj b/src/Libraries/RevitNodes/RevitNodes.csproj index a0c8a6317e..66a533314b 100644 --- a/src/Libraries/RevitNodes/RevitNodes.csproj +++ b/src/Libraries/RevitNodes/RevitNodes.csproj @@ -8,9 +8,6 @@ false $(OutputPath)\$(UICulture)\RevitNodes.xml $(NoWarn);1591;CA2200 - false - prompt - 4 DSRevitNodes true true @@ -18,30 +15,11 @@ None - - full - false - DEBUG;TRACE - - - pdbonly - true - TRACE - - - $(PACKAGESPATH)\Newtonsoft.Json\lib\netstandard2.0\Newtonsoft.Json.dll - False - - - $(PACKAGESPATH)\DynamoVisualProgramming.DynamoServices\lib\netstandard2.0\DynamoServices.dll - $(DYNAMOBUILDPATH)\DynamoServices.dll - False - $(REVITAPI)\RevitAPI.dll False @@ -50,11 +28,6 @@ $(REVITAPI)\RevitAPIUI.dll False - - $(PACKAGESPATH)\DynamoVisualProgramming.ZeroTouchLibrary\lib\$(DCoreLibSubFolder)\ProtoGeometry.dll - $(DYNAMOBUILDPATH)\ProtoGeometry.dll - False - @@ -69,30 +42,7 @@ Resources.en-US.resx - - - $(PACKAGESPATH)\DynamoVisualProgramming.Core\lib\$(DCoreLibSubFolder)\DynamoCore.dll - $(DYNAMOBUILDPATH)\DynamoCore.dll - False - - - $(PACKAGESPATH)\DynamoVisualProgramming.DynamoCoreNodes\lib\$(DCoreLibSubFolder)\Analysis.dll - $(DYNAMOBUILDPATH)\\Analysis.dll - False - - - $(PACKAGESPATH)\DynamoVisualProgramming.DynamoCoreNodes\lib\$(DCoreLibSubFolder)\DSCoreNodes.dll - $(DYNAMOBUILDPATH)\DSCoreNodes.dll - False - - - $(PACKAGESPATH)\DynamoVisualProgramming.ZeroTouchLibrary\lib\$(DCoreLibSubFolder)\DynamoUnits.dll - $(DYNAMOBUILDPATH)\DynamoUnits.dll - False - - - - + @@ -114,4 +64,8 @@ + + + + \ No newline at end of file diff --git a/src/Libraries/RevitNodes/Transaction/Transaction.cs b/src/Libraries/RevitNodes/Transaction/Transaction.cs index fbafb5faab..8d67caa323 100644 --- a/src/Libraries/RevitNodes/Transaction/Transaction.cs +++ b/src/Libraries/RevitNodes/Transaction/Transaction.cs @@ -30,7 +30,9 @@ public static object Start(object input) public static object End(object input) { TransactionManager.Instance.ForceCloseTransaction(); +#if !DESIGN_AUTOMATION DocumentManager.Instance.CurrentUIDocument.RefreshActiveView(); +#endif return input; } } diff --git a/src/Libraries/RevitNodesUI/Elements.cs b/src/Libraries/RevitNodesUI/Elements.cs index 43050bb310..5207504224 100644 --- a/src/Libraries/RevitNodesUI/Elements.cs +++ b/src/Libraries/RevitNodesUI/Elements.cs @@ -28,6 +28,7 @@ using BuiltinNodeCategories = Revit.Elements.BuiltinNodeCategories; using View = Revit.Elements.Views.View; using RevitServices.Transactions; +using Autodesk.Revit.ApplicationServices; namespace DSRevitNodesUI { @@ -281,8 +282,10 @@ public ElementsInView() OutPorts.Add(new PortModel(PortType.Output, this, new PortData("elements", Properties.Resources.PortDataAllVisibleElementsToolTip))); RegisterAllPorts(); - DynamoRevitApp.EventHandlerProxy.ViewActivated += RevitDynamoModel_RevitDocumentChanged; - DynamoRevitApp.EventHandlerProxy.DocumentOpened += RevitDynamoModel_RevitDocumentChanged; +#if !DESIGN_AUTOMATION + RevitServices.EventHandler.EventHandlerProxy.Instance.ViewActivated += RevitDynamoModel_RevitDocumentChanged; +#endif + RevitServices.EventHandler.EventHandlerProxy.Instance.DocumentOpened += RevitDynamoModel_RevitDocumentChanged; RevitServicesUpdater.Instance.ElementsUpdated += RevitServicesUpdaterOnElementsUpdated; RevitDynamoModel_RevitDocumentChanged(null, null); @@ -291,8 +294,10 @@ public ElementsInView() [JsonConstructor] public ElementsInView(IEnumerable inPorts, IEnumerable outPorts) : base(inPorts, outPorts) { - DynamoRevitApp.EventHandlerProxy.ViewActivated += RevitDynamoModel_RevitDocumentChanged; - DynamoRevitApp.EventHandlerProxy.DocumentOpened += RevitDynamoModel_RevitDocumentChanged; +#if !DESIGN_AUTOMATION + RevitServices.EventHandler.EventHandlerProxy.Instance.ViewActivated += RevitDynamoModel_RevitDocumentChanged; +#endif + RevitServices.EventHandler.EventHandlerProxy.Instance.DocumentOpened += RevitDynamoModel_RevitDocumentChanged; RevitServicesUpdater.Instance.ElementsUpdated += RevitServicesUpdaterOnElementsUpdated; RevitDynamoModel_RevitDocumentChanged(null, null); @@ -300,8 +305,10 @@ public ElementsInView(IEnumerable inPorts, IEnumerable out public override void Dispose() { - DynamoRevitApp.EventHandlerProxy.ViewActivated -= RevitDynamoModel_RevitDocumentChanged; - DynamoRevitApp.EventHandlerProxy.DocumentOpened -= RevitDynamoModel_RevitDocumentChanged; +#if !DESIGN_AUTOMATION + RevitServices.EventHandler.EventHandlerProxy.Instance.ViewActivated -= RevitDynamoModel_RevitDocumentChanged; +#endif + RevitServices.EventHandler.EventHandlerProxy.Instance.DocumentOpened -= RevitDynamoModel_RevitDocumentChanged; RevitServicesUpdater.Instance.ElementsUpdated -= RevitServicesUpdaterOnElementsUpdated; diff --git a/src/Libraries/RevitNodesUI/RevitDropDown.cs b/src/Libraries/RevitNodesUI/RevitDropDown.cs index 7d151fc264..272fc2ca34 100644 --- a/src/Libraries/RevitNodesUI/RevitDropDown.cs +++ b/src/Libraries/RevitNodesUI/RevitDropDown.cs @@ -48,14 +48,14 @@ public abstract class RevitDropDownBase : DSDropDownBase protected RevitDropDownBase(string value) : base(value) { RevitServicesUpdater.Instance.ElementsUpdated += Updater_ElementsUpdated; - DynamoRevitApp.EventHandlerProxy.DocumentOpened += Controller_RevitDocumentChanged; + RevitServices.EventHandler.EventHandlerProxy.Instance.DocumentOpened += Controller_RevitDocumentChanged; } [JsonConstructor] public RevitDropDownBase(string value, IEnumerable inPorts, IEnumerable outPorts) : base(value, inPorts, outPorts) { RevitServicesUpdater.Instance.ElementsUpdated += Updater_ElementsUpdated; - DynamoRevitApp.EventHandlerProxy.DocumentOpened += Controller_RevitDocumentChanged; + RevitServices.EventHandler.EventHandlerProxy.Instance.DocumentOpened += Controller_RevitDocumentChanged; } void Controller_RevitDocumentChanged(object sender, EventArgs e) @@ -90,7 +90,7 @@ private void Updater_ElementsUpdated(object sender, ElementUpdateEventArgs e) public override void Dispose() { RevitServicesUpdater.Instance.ElementsUpdated -= Updater_ElementsUpdated; - DynamoRevitApp.EventHandlerProxy.DocumentOpened -= Controller_RevitDocumentChanged; + RevitServices.EventHandler.EventHandlerProxy.Instance.DocumentOpened -= Controller_RevitDocumentChanged; base.Dispose(); } diff --git a/src/Libraries/RevitNodesUI/RevitNodesUI.csproj b/src/Libraries/RevitNodesUI/RevitNodesUI.csproj index ac4438f244..9c0b4dda18 100644 --- a/src/Libraries/RevitNodesUI/RevitNodesUI.csproj +++ b/src/Libraries/RevitNodesUI/RevitNodesUI.csproj @@ -6,47 +6,27 @@ DSRevitNodesUI DSRevitNodesUI $(OutputPath)\nodes\ - prompt - 4 - false true false - - true - full - false - DEBUG;TRACE - - - pdbonly - true - TRACE - + + + + + + + + + + + + + - - $(PACKAGESPATH)\DynamoVisualProgramming.Core\lib\$(DCoreLibSubFolder)\DynamoUtilities.dll - $(DYNAMOBUILDPATH)\DynamoUtilities.dll - False - - - $(PACKAGESPATH)\Newtonsoft.Json\lib\netstandard2.0\Newtonsoft.Json.dll - False - - - $(PACKAGESPATH)\DynamoVisualProgramming.ZeroTouchLibrary\lib\$(DCoreLibSubFolder)\ProtoGeometry.dll - $(DYNAMOBUILDPATH)\ProtoGeometry.dll - False - - - $(PACKAGESPATH)\DynamoVisualProgramming.DynamoServices\lib\netstandard2.0\DynamoServices.dll - $(DYNAMOBUILDPATH)\DynamoServices.dll - False - $(REVITAPI)\RevitAPI.dll False @@ -58,6 +38,8 @@ + + ComboControl.xaml @@ -70,43 +52,6 @@ Resources.resx - - - $(PACKAGESPATH)\DynamoVisualProgramming.WpfUILibrary\lib\$(DCoreLibSubFolder)\DynamoCoreWpf.dll - $(DYNAMOBUILDPATH)\DynamoCoreWpf.dll - False - - - $(PACKAGESPATH)\DynamoVisualProgramming.Core\lib\$(DCoreLibSubFolder)\ProtoCore.dll - $(DYNAMOBUILDPATH)\ProtoCore.dll - False - - - $(PACKAGESPATH)\DynamoVisualProgramming.WpfUILibrary\lib\$(DCoreLibSubFolder)\CoreNodeModelsWpf.dll - $(DYNAMOBUILDPATH)\nodes\CoreNodeModelsWpf.dll - False - - - $(PACKAGESPATH)\DynamoVisualProgramming.DynamoCoreNodes\lib\$(DCoreLibSubFolder)\CoreNodeModels.dll - $(DYNAMOBUILDPATH)\nodes\CoreNodeModels.dll - False - - - $(PACKAGESPATH)\DynamoVisualProgramming.Core\lib\$(DCoreLibSubFolder)\DynamoCore.dll - $(DYNAMOBUILDPATH)\DynamoCore.dll - False - - - $(PACKAGESPATH)\DynamoVisualProgramming.DynamoCoreNodes\lib\$(DCoreLibSubFolder)\DSCoreNodes.dll - $(DYNAMOBUILDPATH)\DSCoreNodes.dll - False - - - $(PACKAGESPATH)\DynamoVisualProgramming.ZeroTouchLibrary\lib\$(DCoreLibSubFolder)\DynamoUnits.dll - $(DYNAMOBUILDPATH)\DynamoUnits.dll - False - - @@ -119,4 +64,7 @@ Resources.Designer.cs + + + \ No newline at end of file diff --git a/src/Libraries/RevitNodesUI/RevitTypes.cs b/src/Libraries/RevitNodesUI/RevitTypes.cs index f4bc73c43a..7bbb3eb98f 100644 --- a/src/Libraries/RevitNodesUI/RevitTypes.cs +++ b/src/Libraries/RevitNodesUI/RevitTypes.cs @@ -1,20 +1,7 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; using Newtonsoft.Json; -using Autodesk.DesignScript.Geometry; -using Autodesk.DesignScript.Runtime; -using DSRevitNodesUI; -using RVT = Autodesk.Revit.DB; -using RevitServices.Persistence; -using RevitServices.Transactions; - -using Dynamo.Utilities; -using Dynamo.Models; -using Dynamo.Nodes; using ProtoCore.AST.AssociativeAST; -using CoreNodeModels.Properties; using Dynamo.Graph.Nodes; namespace DSRevitNodesUI diff --git a/src/Libraries/RevitNodesUI/Selection.cs b/src/Libraries/RevitNodesUI/Selection.cs index a2eecc2011..081ab4b91b 100644 --- a/src/Libraries/RevitNodesUI/Selection.cs +++ b/src/Libraries/RevitNodesUI/Selection.cs @@ -161,7 +161,7 @@ protected RevitSelection(SelectionType selectionType, : base(selectionType, selectionObjectType, message, prefix) { RevitServicesUpdater.Instance.ElementsUpdated += Updater_ElementsUpdated; - DynamoRevitApp.EventHandlerProxy.DocumentOpened += Controller_RevitDocumentChanged; + RevitServices.EventHandler.EventHandlerProxy.Instance.DocumentOpened += Controller_RevitDocumentChanged; } [JsonConstructor] @@ -171,7 +171,7 @@ public RevitSelection(SelectionType selectionType, : base(selectionType, selectionObjectType, message, prefix, selectionIdentifier, inPorts, outPorts) { RevitServicesUpdater.Instance.ElementsUpdated += Updater_ElementsUpdated; - DynamoRevitApp.EventHandlerProxy.DocumentOpened += Controller_RevitDocumentChanged; + RevitServices.EventHandler.EventHandlerProxy.Instance.DocumentOpened += Controller_RevitDocumentChanged; } #endregion @@ -192,7 +192,7 @@ public override void Dispose() base.Dispose(); RevitServicesUpdater.Instance.ElementsUpdated -= Updater_ElementsUpdated; - DynamoRevitApp.EventHandlerProxy.DocumentOpened -= Controller_RevitDocumentChanged; + RevitServices.EventHandler.EventHandlerProxy.Instance.DocumentOpened -= Controller_RevitDocumentChanged; if (revitDynamoModel != null) { diff --git a/src/Libraries/RevitNodesUI/SiteLocation.cs b/src/Libraries/RevitNodesUI/SiteLocation.cs index 4fa72b5ea6..37c720b03b 100644 --- a/src/Libraries/RevitNodesUI/SiteLocation.cs +++ b/src/Libraries/RevitNodesUI/SiteLocation.cs @@ -1,8 +1,10 @@ using Dynamo.Applications; using Dynamo.Applications.Models; +#if !DESIGN_AUTOMATION using Dynamo.Controls; -using Dynamo.Graph.Nodes; using Dynamo.Wpf; +#endif +using Dynamo.Graph.Nodes; using Newtonsoft.Json; using ProtoCore.AST.AssociativeAST; using Revit.GeometryConversion; @@ -15,7 +17,8 @@ namespace DSRevitNodesUI { - public class SiteLocationNodeViewCustomization : INodeViewCustomization +#if !DESIGN_AUTOMATION + public class SiteLocationNodeViewCustomization : INodeViewCustomization { public void CustomizeView(SiteLocation model, NodeView nodeView) { @@ -28,6 +31,7 @@ public void Dispose() } } +#endif [NodeName("SiteLocation"), NodeCategory(BuiltinNodeCategories.ANALYZE), NodeDescription("SiteLocationDescription", typeof(Properties.Resources)), IsDesignScriptCompatible] @@ -47,10 +51,12 @@ public SiteLocation() ArgumentLacing = LacingStrategy.Disabled; - DynamoRevitApp.EventHandlerProxy.DocumentOpened += model_RevitDocumentChanged; + RevitServices.EventHandler.EventHandlerProxy.Instance.DocumentOpened += model_RevitDocumentChanged; RevitServicesUpdater.Instance.ElementsUpdated += RevitServicesUpdater_ElementsUpdated; - + +#if !DESIGN_AUTOMATION DynamoRevitApp.AddIdleAction(() => Update()); +#endif } [JsonConstructor] @@ -61,17 +67,19 @@ public SiteLocation(IEnumerable inPorts, IEnumerable outPo ArgumentLacing = LacingStrategy.Disabled; - DynamoRevitApp.EventHandlerProxy.DocumentOpened += model_RevitDocumentChanged; + RevitServices.EventHandler.EventHandlerProxy.Instance.DocumentOpened += model_RevitDocumentChanged; RevitServicesUpdater.Instance.ElementsUpdated += RevitServicesUpdater_ElementsUpdated; +#if !DESIGN_AUTOMATION DynamoRevitApp.AddIdleAction(() => Update()); +#endif } #region public methods public override void Dispose() { - DynamoRevitApp.EventHandlerProxy.DocumentOpened -= model_RevitDocumentChanged; + RevitServices.EventHandler.EventHandlerProxy.Instance.DocumentOpened -= model_RevitDocumentChanged; RevitServicesUpdater.Instance.ElementsUpdated -= RevitServicesUpdater_ElementsUpdated; base.Dispose(); } diff --git a/src/Libraries/RevitNodesUI/SunPath.cs b/src/Libraries/RevitNodesUI/SunPath.cs index eee3f8fd9c..a88eee41fd 100644 --- a/src/Libraries/RevitNodesUI/SunPath.cs +++ b/src/Libraries/RevitNodesUI/SunPath.cs @@ -2,9 +2,9 @@ using System.Collections.Generic; using System.Linq; using Newtonsoft.Json; - +#if !DESIGN_AUTOMATION using Autodesk.Revit.UI.Events; - +#endif using Dynamo.Applications; using Dynamo.Applications.Models; using Dynamo.Graph.Nodes; @@ -32,32 +32,38 @@ public SunSettings() RegisterAllPorts(); RevitServicesUpdater.Instance.ElementsUpdated += Updater_ElementsUpdated; - DynamoRevitApp.EventHandlerProxy.ViewActivated += CurrentUIApplication_ViewActivated; +#if !DESIGN_AUTOMATION + RevitServices.EventHandler.EventHandlerProxy.Instance.ViewActivated += CurrentUIApplication_ViewActivated; DynamoRevitApp.AddIdleAction(() => CurrentUIApplicationOnViewActivated()); +#endif } [JsonConstructor] public SunSettings(IEnumerable inPorts, IEnumerable outPorts) : base(inPorts, outPorts) { RevitServicesUpdater.Instance.ElementsUpdated += Updater_ElementsUpdated; - DynamoRevitApp.EventHandlerProxy.ViewActivated += CurrentUIApplication_ViewActivated; - +#if !DESIGN_AUTOMATION + RevitServices.EventHandler.EventHandlerProxy.Instance.ViewActivated += CurrentUIApplication_ViewActivated; DynamoRevitApp.AddIdleAction(() => CurrentUIApplicationOnViewActivated()); +#endif } public override void Dispose() { RevitServicesUpdater.Instance.ElementsUpdated -= Updater_ElementsUpdated; - DynamoRevitApp.EventHandlerProxy.ViewActivated -= CurrentUIApplication_ViewActivated; - +#if !DESIGN_AUTOMATION + RevitServices.EventHandler.EventHandlerProxy.Instance.ViewActivated -= CurrentUIApplication_ViewActivated; +#endif base.Dispose(); } +#if !DESIGN_AUTOMATION private void CurrentUIApplication_ViewActivated(object sender, ViewActivatedEventArgs e) { CurrentUIApplicationOnViewActivated(); } +#endif private void CurrentUIApplicationOnViewActivated() { diff --git a/src/Libraries/RevitServices/Events/EventHandlerProxy.cs b/src/Libraries/RevitServices/Events/EventHandlerProxy.cs index 424765351a..e80e72b116 100644 --- a/src/Libraries/RevitServices/Events/EventHandlerProxy.cs +++ b/src/Libraries/RevitServices/Events/EventHandlerProxy.cs @@ -1,6 +1,5 @@ using System; using Autodesk.Revit.DB.Events; -using Autodesk.Revit.UI.Events; namespace RevitServices.EventHandler { @@ -8,13 +7,18 @@ namespace RevitServices.EventHandler /// This is a event handler proxy class to serve as a proxy between the event publisher and /// the event subscriber /// + [Obsolete("This class will be made internal")] public class EventHandlerProxy { public event EventHandler DocumentOpened; public event EventHandler DocumentClosing; public event EventHandler DocumentClosed; - public event EventHandler ViewActivating; - public event EventHandler ViewActivated; +#if !DESIGN_AUTOMATION + public event EventHandler ViewActivating; + public event EventHandler ViewActivated; +#endif + + internal static EventHandlerProxy Instance = new(); public void OnApplicationDocumentOpened(object sender, DocumentOpenedEventArgs args) { @@ -31,15 +35,17 @@ public void OnApplicationDocumentClosed(object sender, DocumentClosedEventArgs a InvokeEventHandler(DocumentClosed, sender, args); } - public void OnApplicationViewActivating(object sender, ViewActivatingEventArgs args) +#if !DESIGN_AUTOMATION + public void OnApplicationViewActivating(object sender, Autodesk.Revit.UI.Events.ViewActivatingEventArgs args) { InvokeEventHandler(ViewActivating, sender, args); } - public void OnApplicationViewActivated(object sender, ViewActivatedEventArgs args) + public void OnApplicationViewActivated(object sender, Autodesk.Revit.UI.Events.ViewActivatedEventArgs args) { InvokeEventHandler(ViewActivated, sender, args); } +#endif private void InvokeEventHandler(EventHandler eventHandler, object sender, T args) where T: EventArgs { diff --git a/src/Libraries/RevitServices/Persistence/DocumentManager.cs b/src/Libraries/RevitServices/Persistence/DocumentManager.cs index b92124e6a7..264e009154 100644 --- a/src/Libraries/RevitServices/Persistence/DocumentManager.cs +++ b/src/Libraries/RevitServices/Persistence/DocumentManager.cs @@ -1,8 +1,8 @@ using System; using System.Collections.Generic; using System.Linq; +using Autodesk.Revit.ApplicationServices; using Autodesk.Revit.DB; -using Autodesk.Revit.UI; using RevitServices.Elements; using RevitServices.Transactions; @@ -93,22 +93,22 @@ public IEnumerable ElementsOfType() where T : Element return fec.OfClass(typeof(T)).Cast(); } - public IEnumerable ElementsOfCategory(BuiltInCategory category) + public IEnumerable ElementsOfCategory(BuiltInCategory category) { var fec = new FilteredElementCollector(CurrentDBDocument); return fec.OfCategory(category); } /// - /// Handle document activation, closure. See ActiveDocumentHashCode + /// Handle document activation, closure. See ActiveDocumentHashCode /// for more details. /// - /// The Revit.DB.View object that is being - /// activated. This parameter will be null if the currently active - /// document is closed. If there is another document when the current - /// document is closed, the next document will be activated again + /// The Revit.DB.View object that is being + /// activated. This parameter will be null if the currently active + /// document is closed. If there is another document when the current + /// document is closed, the next document will be activated again /// after active document is invalidated here. - /// + /// public void HandleDocumentActivation(View revitView) { ActiveDocumentHashCode = 0; @@ -116,6 +116,8 @@ public void HandleDocumentActivation(View revitView) ActiveDocumentHashCode = revitView.Document.GetHashCode(); } + private Document currentDBDocument; + /// /// Provides the currently active DB document. /// This is based on the CurrentUIDocument @@ -123,37 +125,51 @@ public void HandleDocumentActivation(View revitView) public Document CurrentDBDocument { get { +#if !DESIGN_AUTOMATION var c = CurrentUIDocument; return c == null ? null : c.Document; +#else + return currentDBDocument; +#endif + } + set { + currentDBDocument = value; } } /// /// This property represents the hash code for the current active Revit - /// Document object. If there is no active document, this value will be + /// Document object. If there is no active document, this value will be /// set to zero. This property is made an 'int' because it is primarily - /// meant to indicate the active document for comparison purposes, no - /// Document specific operations should be allowed on it. This property + /// meant to indicate the active document for comparison purposes, no + /// Document specific operations should be allowed on it. This property /// is updated when a document switch or a document closure happens. The /// reason this property is needed because the following property cannot /// reliably indicate the current active document: - /// + /// /// DocumentManager.CurrentUIApplication.ActiveUIDocument.Document - /// + /// /// public int ActiveDocumentHashCode { get; private set; } + + /// + /// Provides the current Application + /// + internal Application CurrentApplication { get; set; } + +#if !DESIGN_AUTOMATION /// /// Provides the currently active UI document. /// This is the document to which Dynamo is bound. /// - public UIDocument CurrentUIDocument {get; set; } + public Autodesk.Revit.UI.UIDocument CurrentUIDocument {get; set; } /// /// Provides the current UIApplication /// - public UIApplication CurrentUIApplication { get; set; } - + public Autodesk.Revit.UI.UIApplication CurrentUIApplication { get; set; } +#endif /// /// Trigger a document regeneration in the idle context or without /// depending on the state of the transaction manager. @@ -171,5 +187,26 @@ public static void Regenerate() Instance.CurrentDBDocument.Regenerate(); } } + + /// + /// Setup the CurrentDBDocument and CurrentApplication. + /// + /// + internal void PrepareForDesignAutomation(Application app) + { + if (app == null) + { + return; + } + CurrentApplication = app; + foreach (Document d in app.Documents) + { + if (!d.IsLinked) + { + CurrentDBDocument = d; + break; + } + } + } } } diff --git a/src/Libraries/RevitServices/Properties/AssemblyInfo.cs b/src/Libraries/RevitServices/Properties/AssemblyInfo.cs index fa60dc9887..a2b96976cc 100644 --- a/src/Libraries/RevitServices/Properties/AssemblyInfo.cs +++ b/src/Libraries/RevitServices/Properties/AssemblyInfo.cs @@ -1,4 +1,5 @@ using System.Reflection; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following @@ -9,3 +10,7 @@ // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("026be738-81b6-4a11-bc14-36ee3f718921")] +[assembly: InternalsVisibleTo("DADynamoApp")] +[assembly: InternalsVisibleTo("RevitNodes")] +[assembly: InternalsVisibleTo("DSRevitNodesUI")] +[assembly: InternalsVisibleTo("DynamoRevitDS")] diff --git a/src/Libraries/RevitServices/RevitServices.csproj b/src/Libraries/RevitServices/RevitServices.csproj index f1d250f4bf..15d4015a59 100644 --- a/src/Libraries/RevitServices/RevitServices.csproj +++ b/src/Libraries/RevitServices/RevitServices.csproj @@ -20,39 +20,11 @@ limitations under the License. 8.0.30703 false - true true - - true - full - false - TRACE;DEBUG - prompt - 4 - false - - - full - true - TRACE - prompt - 4 - true - false - - - $(PACKAGESPATH)\DynamoVisualProgramming.DynamoServices\lib\netstandard2.0\DynamoServices.dll - $(DYNAMOBUILDPATH)\DynamoServices.dll - False - - - $(PACKAGESPATH)\Newtonsoft.Json\lib\netstandard2.0\Newtonsoft.Json.dll - False - $(REVITAPI)\RevitAPI.dll False @@ -75,18 +47,6 @@ limitations under the License. Resources.resx - - - $(PACKAGESPATH)\DynamoVisualProgramming.Core\lib\$(DCoreLibSubFolder)\DynamoCore.dll - $(DYNAMOBUILDPATH)\DynamoCore.dll - False - - - $(PACKAGESPATH)\DynamoVisualProgramming.Core\lib\$(DCoreLibSubFolder)\ProtoCore.dll - $(DYNAMOBUILDPATH)\ProtoCore.dll - False - - ResXFileCodeGenerator @@ -96,5 +56,9 @@ limitations under the License. + + + + \ No newline at end of file diff --git a/src/Tools/DynamoAddInGenerator/DynamoAddInGenerator.csproj b/src/Tools/DynamoAddInGenerator/DynamoAddInGenerator.csproj index a2720b0860..56df97c862 100644 --- a/src/Tools/DynamoAddInGenerator/DynamoAddInGenerator.csproj +++ b/src/Tools/DynamoAddInGenerator/DynamoAddInGenerator.csproj @@ -28,10 +28,6 @@ false - - $(PACKAGESPATH)\DynamoVisualProgramming.Core\lib\$(DCoreLibSubFolder)\DynamoInstallDetective.dll - $(DYNAMOBUILDPATH)\DynamoInstallDetective.dll - $(ProjectDir)\RevitAddinUtility.dll @@ -39,4 +35,7 @@ + + + diff --git a/test/Libraries/RevitIntegrationTests/DALoggerTests.cs b/test/Libraries/RevitIntegrationTests/DALoggerTests.cs new file mode 100644 index 0000000000..4387568d48 --- /dev/null +++ b/test/Libraries/RevitIntegrationTests/DALoggerTests.cs @@ -0,0 +1,68 @@ +using System; +using System.IO; +using DADynamoApp; +using NUnit.Framework; +using RevitTestServices; +using RTF.Framework; + +namespace RevitSystemTests +{ + [TestFixture] + class DALoggerTests : RevitSystemTestBase + { + private StringWriter capturedOutput; + private TextWriter originalOutput; + + [SetUp] + public override void Setup() + { + base.Setup(); + capturedOutput = new StringWriter(); + originalOutput = Console.Out; + Console.SetOut(capturedOutput); + } + + [TearDown] + public override void TearDown() + { + Console.SetOut(originalOutput); + capturedOutput?.Dispose(); + base.TearDown(); + } + + // TODO: Refactor DAEntrypoint so that all post-model-startup logic lives in a separate + // internal DAApp class that accepts a DynamoModel in its constructor. DAEntrypoint would + // just create the model and hand it to new DAApp(model). This test could then do: + // var app = new DAApp(ViewModel.Model); + // app.SetupProfilingHandlers(); + // ...which tests the actual DA code path without needing to create a DAEntrypoint at all, + // and makes it straightforward to test graph running too (pass a work item folder). + + /// + /// Verifies that DAEntrypoint.SetupProfilingHandlers wires up node execution events that + /// call DALogger.SerializeNodeOutputs and write profiling output to stdout. + /// + [Test] + [TestModel(@".\empty.rfa")] + public void SetupProfilingHandlers_WritesNodeOutputToStdout() + { + // Use the actual production method — SetupProfilingHandlers subscribes to WorkspaceOpened + // and wires all the profiling/serialization handlers on the model we already have. + var entrypoint = new DAEntrypoint(); + entrypoint.SetupProfilingHandlers(Model); + + string dynPath = Path.GetFullPath(Path.Combine(workingDirectory, @".\Core\SanityCheck.dyn")); + ViewModel.OpenCommand.Execute(dynPath); + RunCurrentModel(); + + var output = capturedOutput.ToString(); + + // Profiling start/end lines must appear + StringAssert.Contains("Node Point.ByCoordinates started execution.", output); + StringAssert.Contains("Node Point.ByCoordinates finished execution.", output); + + // DALogger.SerializeNodeOutputs must have returned something for the Point node + StringAssert.Contains("Node Point.ByCoordinates outputs:", output); + } + } +} diff --git a/test/Libraries/RevitIntegrationTests/RevitSystemTests.csproj b/test/Libraries/RevitIntegrationTests/RevitSystemTests.csproj index 5a11661365..8a8ef3ddaa 100644 --- a/test/Libraries/RevitIntegrationTests/RevitSystemTests.csproj +++ b/test/Libraries/RevitIntegrationTests/RevitSystemTests.csproj @@ -35,34 +35,6 @@ - - $(PACKAGESPATH)\Newtonsoft.Json\lib\netstandard2.0\Newtonsoft.Json.dll - False - - - $(PACKAGESPATH)\DynamoVisualProgramming.WpfUILibrary\lib\$(DCoreLibSubFolder)\DynamoCoreWpf.dll - $(DYNAMOBUILDPATH)\DynamoCoreWpf.dll - False - - - $(PACKAGESPATH)\DynamoVisualProgramming.Core\lib\$(DCoreLibSubFolder)\DynamoUtilities.dll - $(DYNAMOBUILDPATH)\DynamoUtilities.dll - False - - - $(PACKAGESPATH)\NUnit\lib\netstandard2.0\nunit.framework.dll - False - - - $(PACKAGESPATH)\DynamoVisualProgramming.ZeroTouchLibrary\lib\$(DCoreLibSubFolder)\ProtoGeometry.dll - $(DYNAMOBUILDPATH)\ProtoGeometry.dll - False - - - $(PACKAGESPATH)\DynamoVisualProgramming.DynamoServices\lib\netstandard2.0\DynamoServices.dll - $(DYNAMOBUILDPATH)\DynamoServices.dll - False - $(REVITAPI)\RevitAPI.dll False @@ -74,48 +46,19 @@ $(DynamoExternPath)\RevitTestFramework\RevitTestFrameworkTypes.dll - - $(PACKAGESPATH)\DynamoVisualProgramming.Tests\lib\$(DCoreLibSubFolder)\SystemTestServices.dll - $(DYNAMOBUILDPATH)\SystemTestServices.dll - False - - - $(PACKAGESPATH)\DynamoVisualProgramming.Tests\lib\$(DCoreLibSubFolder)\TestServices.dll - $(DYNAMOBUILDPATH)\TestServices.dll - False - - - - $(PACKAGESPATH)\DynamoVisualProgramming.Core\lib\$(DCoreLibSubFolder)\ProtoCore.dll - $(DYNAMOBUILDPATH)\ProtoCore.dll - False - - - $(PACKAGESPATH)\DynamoVisualProgramming.DynamoCoreNodes\lib\$(DCoreLibSubFolder)\CoreNodeModels.dll - $(DYNAMOBUILDPATH)\nodes\CoreNodeModels.dll - False - - - $(PACKAGESPATH)\DynamoVisualProgramming.ZeroTouchLibrary\lib\$(DCoreLibSubFolder)\DynamoUnits.dll - $(DYNAMOBUILDPATH)\DynamoUnits.dll - False - - - $(PACKAGESPATH)\DynamoVisualProgramming.Core\lib\$(DCoreLibSubFolder)\DynamoCore.dll - $(DYNAMOBUILDPATH)\DynamoCore.dll - False - + - + + diff --git a/test/Libraries/RevitNodesTests/RevitNodesTests.csproj b/test/Libraries/RevitNodesTests/RevitNodesTests.csproj index cc14ed9645..41e3163bda 100644 --- a/test/Libraries/RevitNodesTests/RevitNodesTests.csproj +++ b/test/Libraries/RevitNodesTests/RevitNodesTests.csproj @@ -28,25 +28,6 @@ false - - $(PACKAGESPATH)\DynamoVisualProgramming.DynamoCoreNodes\lib\$(DCoreLibSubFolder)\DSCoreNodes.dll - $(DYNAMOBUILDPATH)\DSCoreNodes.dll - False - - - $(PACKAGESPATH)\NUnit\lib\netstandard2.0\nunit.framework.dll - False - - - $(PACKAGESPATH)\DynamoVisualProgramming.ZeroTouchLibrary\lib\$(DCoreLibSubFolder)\ProtoGeometry.dll - $(DYNAMOBUILDPATH)\ProtoGeometry.dll - False - - - $(PACKAGESPATH)\DynamoVisualProgramming.DynamoServices\lib\netstandard2.0\DynamoServices.dll - $(DYNAMOBUILDPATH)\DynamoServices.dll - False - $(REVITAPI)\RevitAPI.dll False @@ -59,24 +40,10 @@ - - $(PACKAGESPATH)\DynamoVisualProgramming.Core\lib\$(DCoreLibSubFolder)\DynamoCore.dll - $(DYNAMOBUILDPATH)\DynamoCore.dll - False - - - $(PACKAGESPATH)\DynamoVisualProgramming.DynamoCoreNodes\lib\$(DCoreLibSubFolder)\Analysis.dll - $(DYNAMOBUILDPATH)\Analysis.dll - False - - - $(PACKAGESPATH)\DynamoVisualProgramming.Tests\lib\$(DCoreLibSubFolder)\TestServices.dll - $(DYNAMOBUILDPATH)\TestServices.dll - False - + diff --git a/test/Libraries/RevitServicesTests/RevitServicesTests.csproj b/test/Libraries/RevitServicesTests/RevitServicesTests.csproj index e1a36c6b11..bd942e58e6 100644 --- a/test/Libraries/RevitServicesTests/RevitServicesTests.csproj +++ b/test/Libraries/RevitServicesTests/RevitServicesTests.csproj @@ -25,34 +25,7 @@ limitations under the License. None - - true - full - false - DEBUG;TRACE - prompt - 4 - AnyCPU - false - - - pdbonly - true - TRACE - prompt - 4 - true - false - - - $(PACKAGESPATH)\Newtonsoft.Json\lib\netstandard2.0\Newtonsoft.Json.dll - False - - - $(PACKAGESPATH)\NUnit\lib\netstandard2.0\nunit.framework.dll - False - $(REVITAPI)\RevitAPI.dll False @@ -73,5 +46,6 @@ limitations under the License. + \ No newline at end of file diff --git a/test/Libraries/RevitTestServices/RevitNodeTestBase.cs b/test/Libraries/RevitTestServices/RevitNodeTestBase.cs index 1be498945d..360078c97f 100644 --- a/test/Libraries/RevitTestServices/RevitNodeTestBase.cs +++ b/test/Libraries/RevitTestServices/RevitNodeTestBase.cs @@ -43,7 +43,8 @@ public override void Setup() protected override TestSessionConfiguration GetTestSessionConfiguration() { var asmLocation = AppDomain.CurrentDomain.BaseDirectory; - return new TestSessionConfiguration(Dynamo.Applications.DynamoRevitApp.DynamoCorePath, DynamoRevit.PreloadAsmFromRevit()); + Version version = ASMPrealoaderUtils.PreloadAsmFromRevit(DynamoRevitApp.ControlledApplication.SharedComponentsLocation, DynamoRevitApp.DynamoCorePath); + return new TestSessionConfiguration(Dynamo.Applications.DynamoRevitApp.DynamoCorePath, version); } private static void SetupTransactionManager() diff --git a/test/Libraries/RevitTestServices/RevitSystemTestBase.cs b/test/Libraries/RevitTestServices/RevitSystemTestBase.cs index 998a0cf354..86a893f2ab 100644 --- a/test/Libraries/RevitTestServices/RevitSystemTestBase.cs +++ b/test/Libraries/RevitTestServices/RevitSystemTestBase.cs @@ -284,13 +284,13 @@ protected override void StartDynamo(TestSessionConfiguration testConfig) // Init DynamoTestPath to get DynamoSettings.xml which under user data folder PreferenceSettings.DynamoTestPath = string.Empty; //preload ASM and instruct dynamo to load that version of libG. - var requestedLibGVersion = DynamoRevit.PreloadAsmFromRevit(); + var requestedLibGVersion = ASMPrealoaderUtils.PreloadAsmFromRevit(DynamoRevitApp.ControlledApplication.SharedComponentsLocation, testConfig.DynamoCorePath); DynamoRevit.RevitDynamoModel = RevitDynamoModel.Start( new RevitDynamoModel.RevitStartConfiguration() { StartInTestMode = true, - GeometryFactoryPath = DynamoRevit.GetGeometryFactoryPath(testConfig.DynamoCorePath, requestedLibGVersion), + GeometryFactoryPath = ASMPrealoaderUtils.GetGeometryFactoryPath(testConfig.DynamoCorePath, requestedLibGVersion), DynamoCorePath = testConfig.DynamoCorePath, PathResolver = revitTestPathResolver, Context = DynamoRevit.GetRevitContext(commandData), diff --git a/test/Libraries/RevitTestServices/RevitTestServices.csproj b/test/Libraries/RevitTestServices/RevitTestServices.csproj index feb4bd71ea..aa2a091e53 100644 --- a/test/Libraries/RevitTestServices/RevitTestServices.csproj +++ b/test/Libraries/RevitTestServices/RevitTestServices.csproj @@ -31,22 +31,6 @@ - - $(PACKAGESPATH)\NUnit\lib\netstandard2.0\nunit.framework.dll - True - - - $(PACKAGESPATH)\NUnit.Engine\lib\netstandard2.0\NUnit.Engine.dll - True - - - $(PACKAGESPATH)\NUnit.Engine\lib\netstandard2.0\NUnit.Engine.Api.dll - True - - - $(PACKAGESPATH)\NUnit.Engine\lib\netstandard2.0\NUnit.Engine.Core.dll - True - $(REVITAPI)\RevitAPI.dll False @@ -67,37 +51,8 @@ - - $(PACKAGESPATH)\DynamoVisualProgramming.Core\lib\$(DCoreLibSubFolder)\DynamoCore.dll - $(DYNAMOBUILDPATH)\DynamoCore.dll - False - - - $(PACKAGESPATH)\DynamoVisualProgramming.WpfUILibrary\lib\$(DCoreLibSubFolder)\DynamoCoreWpf.dll - $(DYNAMOBUILDPATH)\DynamoCoreWpf.dll - False - + - - $(PACKAGESPATH)\DynamoVisualProgramming.Core\lib\$(DCoreLibSubFolder)\DynamoUtilities.dll - $(DYNAMOBUILDPATH)\DynamoUtilities.dll - False - - - $(PACKAGESPATH)\DynamoVisualProgramming.ZeroTouchLibrary\lib\$(DCoreLibSubFolder)\DynamoUnits.dll - $(DYNAMOBUILDPATH)\DynamoUnits.dll - False - - - $(PACKAGESPATH)\DynamoVisualProgramming.Tests\lib\$(DCoreLibSubFolder)\TestServices.dll - $(DYNAMOBUILDPATH)\TestServices.dll - False - - - $(PACKAGESPATH)\DynamoVisualProgramming.Tests\lib\$(DCoreLibSubFolder)\SystemTestServices.dll - $(DYNAMOBUILDPATH)\SystemTestServices.dll - False - \ No newline at end of file