From da8f5513a21703209e0ad5d21434e9191810a75d Mon Sep 17 00:00:00 2001 From: Dexter Lowe Date: Wed, 29 Apr 2026 22:39:38 +0100 Subject: [PATCH 1/2] Pre-resolve copy dlls reqs to support gradle caching --- build.gradle.kts | 78 +++++++++++++++++++++++------------------------- 1 file changed, 37 insertions(+), 41 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 137a6b3..3184523 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -155,58 +155,54 @@ tasks.runIde { } } +// The Rider SDK archive omits certain DLLs that are present in a full Rider installation. +// Copy the missing Unity plugin DotFiles DLLs from the local Rider installation so the sandbox can load them. +// Configured as a real Copy task (rather than a `doLast` on prepareSandbox) so it works with the configuration cache: +// every value the task action needs is captured into locals at configuration time, and no Project APIs are referenced +// at execution time. if (!isWindows) { - tasks.register("copyRiderDlls") { - notCompatibleWithConfigurationCache("Uses local Rider install") - - // The Rider SDK archive omits certain DLLs that are present in a full Rider installation. - // Copy the missing Unity plugin DotFiles DLL from the local Rider installation so the sandbox can load it. - if (!isWindows) { - val riderInstallCandidates = if (Os.isFamily(Os.FAMILY_MAC)) { - listOf(file("/Applications/Rider.app/Contents")) - } else { - // Linux: check JetBrains Toolbox and common standalone install paths - val toolboxBase = file("${System.getProperty("user.home")}/.local/share/JetBrains/Toolbox/apps/Rider") - val toolboxInstalls = if (toolboxBase.exists()) { - toolboxBase.walkTopDown() - .filter { it.name == "plugins" && it.parentFile?.name?.startsWith("2") == true } - .map { it.parentFile } - .toList() - } else emptyList() - toolboxInstalls + listOf(file("/opt/rider"), file("/usr/share/rider")) - } - - val missingDotFileDlls = listOf( - "JetBrains.ReSharper.Plugins.Unity.Rider.Debugger.PausePoint.Helper.dll", - "JetBrains.ReSharper.Plugins.Unity.Rider.Debugger.Presentation.Texture.dll", - ) - - val destDir = intellijPlatform.platformPath.resolve("plugins/rider-unity/DotFiles").toFile() - destDir.mkdirs() - - for (dllName in missingDotFileDlls) { - val dllRelPath = "plugins/rider-unity/DotFiles/$dllName" - val srcDll = riderInstallCandidates - .map { file("${it}/${dllRelPath}") } - .firstOrNull { it.exists() } + val riderInstallCandidates: List = if (Os.isFamily(Os.FAMILY_MAC)) { + listOf(File("/Applications/Rider.app/Contents")) + } else { + // Linux: check JetBrains Toolbox and common standalone install paths + val userHome = providers.systemProperty("user.home").get() + val toolboxBase = File("$userHome/.local/share/JetBrains/Toolbox/apps/Rider") + val toolboxInstalls = if (toolboxBase.exists()) { + toolboxBase.walkTopDown() + .filter { it.name == "plugins" && it.parentFile?.name?.startsWith("2") == true } + .map { it.parentFile } + .toList() + } else emptyList() + toolboxInstalls + listOf(File("/opt/rider"), File("/usr/share/rider")) + } - if (srcDll != null) { - // Copy into the extracted SDK location (platformPath) — that's where Rider loads plugins from at runtime - srcDll.copyTo(file("${destDir}/${srcDll.name}"), overwrite = true) - } - } + val missingDotFileDlls = listOf( + "JetBrains.ReSharper.Plugins.Unity.Rider.Debugger.PausePoint.Helper.dll", + "JetBrains.ReSharper.Plugins.Unity.Rider.Debugger.Presentation.Texture.dll", + ) + + val copyRiderDlls = tasks.register("copyRiderDlls") { + missingDotFileDlls.forEach { dllName -> + val rel = "plugins/rider-unity/DotFiles/$dllName" + riderInstallCandidates + .map { File(it, rel) } + .firstOrNull { it.exists() } + ?.let { from(it) } } + + // platformPath is a Path resolved at configuration time — captured here so the task action doesn't touch the extension. + into(intellijPlatform.platformPath.resolve("plugins/rider-unity/DotFiles").toFile()) } - tasks.named("prepareSandbox") { - dependsOn("copyRiderDlls") + tasks.prepareSandbox { + dependsOn(copyRiderDlls) } } tasks.prepareSandbox { dependsOn(compileDotNet) - val outputFolder = layout.projectDirectory.dir("/src/dotnet/${DotnetPluginId}/bin/${DotnetPluginId}.Rider/${BuildConfiguration}") + val outputFolder = layout.projectDirectory.dir("src/dotnet/${DotnetPluginId}/bin/${DotnetPluginId}.Rider/${BuildConfiguration}") val dllFiles = listOf( "$outputFolder/${DotnetPluginId}.dll", From b593eed5dfbd48ced9f4faea71450515fc7f6c3a Mon Sep 17 00:00:00 2001 From: Dexter Lowe Date: Wed, 29 Apr 2026 23:17:29 +0100 Subject: [PATCH 2/2] Missed a few references needing caches --- build.gradle.kts | 46 +++++++++++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 3184523..346e201 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -105,11 +105,15 @@ val buildResharperPlugin by tasks.registering(Exec::class) { } tasks.buildPlugin { + // Capture providers/files at configuration time so the doLast doesn't touch Project APIs + // (project.copy(), project.buildDir, project.rootDir) — required for the configuration cache. + val pluginZip = layout.buildDirectory.file("distributions/${rootProject.name}-${version}.zip") + val outputDir = layout.projectDirectory.dir("output").asFile + doLast { - copy { - from("${buildDir}/distributions/${rootProject.name}-${version}.zip") - into("${rootDir}/output") - } + val zipFile = pluginZip.get().asFile + outputDir.mkdirs() + zipFile.copyTo(outputDir.resolve(zipFile.name), overwrite = true) } } @@ -157,9 +161,14 @@ tasks.runIde { // The Rider SDK archive omits certain DLLs that are present in a full Rider installation. // Copy the missing Unity plugin DotFiles DLLs from the local Rider installation so the sandbox can load them. -// Configured as a real Copy task (rather than a `doLast` on prepareSandbox) so it works with the configuration cache: -// every value the task action needs is captured into locals at configuration time, and no Project APIs are referenced -// at execution time. +// +// This is a side-effect on the extracted SDK (intellijPlatform.platformPath) — *not* a declared task output — because +// other tasks (patchPluginXml, buildPlugin, etc.) read from that same directory. Declaring it as an OutputDirectory +// would make Gradle complain about implicit dependencies. Hooking it as a `doLast` on prepareSandbox keeps it as a +// transparent mutation of the SDK that runs before any consumer. +// +// All Project-API access (file(), intellijPlatform.platformPath, system properties) is hoisted to configuration time +// and captured into locals so the action stays compatible with the configuration cache. if (!isWindows) { val riderInstallCandidates: List = if (Os.isFamily(Os.FAMILY_MAC)) { listOf(File("/Applications/Rider.app/Contents")) @@ -181,21 +190,20 @@ if (!isWindows) { "JetBrains.ReSharper.Plugins.Unity.Rider.Debugger.Presentation.Texture.dll", ) - val copyRiderDlls = tasks.register("copyRiderDlls") { - missingDotFileDlls.forEach { dllName -> - val rel = "plugins/rider-unity/DotFiles/$dllName" - riderInstallCandidates - .map { File(it, rel) } - .firstOrNull { it.exists() } - ?.let { from(it) } - } - - // platformPath is a Path resolved at configuration time — captured here so the task action doesn't touch the extension. - into(intellijPlatform.platformPath.resolve("plugins/rider-unity/DotFiles").toFile()) + val resolvedRiderDllSources: List = missingDotFileDlls.mapNotNull { dllName -> + val rel = "plugins/rider-unity/DotFiles/$dllName" + riderInstallCandidates.map { File(it, rel) }.firstOrNull { it.exists() } } + val riderDllDestDir = intellijPlatform.platformPath.resolve("plugins/rider-unity/DotFiles").toFile() + tasks.prepareSandbox { - dependsOn(copyRiderDlls) + doLast { + riderDllDestDir.mkdirs() + resolvedRiderDllSources.forEach { src -> + src.copyTo(File(riderDllDestDir, src.name), overwrite = true) + } + } } }