diff --git a/rewrite-csharp/src/main/java/org/openrewrite/csharp/rpc/CSharpRewriteRpc.java b/rewrite-csharp/src/main/java/org/openrewrite/csharp/rpc/CSharpRewriteRpc.java index a24deddc6a9..87f04ff3291 100644 --- a/rewrite-csharp/src/main/java/org/openrewrite/csharp/rpc/CSharpRewriteRpc.java +++ b/rewrite-csharp/src/main/java/org/openrewrite/csharp/rpc/CSharpRewriteRpc.java @@ -295,10 +295,11 @@ public CSharpRewriteRpc get() { ); } } else { - // Run via dotnet tool exec with the pinned version from the build + // Install and run the tool from a persistent tool-path, bypassing + // dotnet tool exec which has auth issues with private feeds (dotnet/sdk#51375) String version = StringUtils.readFully( CSharpRewriteRpc.class.getResourceAsStream("/META-INF/rewrite-csharp-version.txt")).trim(); - cmd = buildToolExecCommand(version); + cmd = buildToolPathCommand(version); } return startProcess(cmd); @@ -351,29 +352,74 @@ private CSharpRewriteRpc startProcess(Stream<@Nullable String> cmd) { ); } - private Stream<@Nullable String> buildToolExecCommand(String version) { - // When the tool package exists in the NuGet global cache (e.g. from pTML), - // add it as a source so dotnet tool exec can resolve it without remote feeds - Path globalCachePath = Paths.get(System.getProperty("user.home"), - ".nuget", "packages", NUGET_PACKAGE_ID.toLowerCase(), version); - String addSource = Files.isDirectory(globalCachePath) ? globalCachePath.toString() : null; + /** + * Ensures the tool is installed at a persistent tool-path and returns a command + * to run it directly. This bypasses {@code dotnet tool exec} entirely, working + * around https://github.com/dotnet/sdk/issues/51375 where {@code dotnet tool exec} + * fails to authenticate against private NuGet feeds. + *
+ * Uses {@code dotnet tool install --tool-path} which handles authentication
+ * correctly. The tool-path is version-specific so multiple versions can coexist
+ * without file-lock conflicts during parallel execution.
+ */
+ private Stream<@Nullable String> buildToolPathCommand(String version) {
+ Path toolPath = Paths.get(System.getProperty("user.home"),
+ ".dotnet", "rewrite-tools", version);
+ Path toolExecutable = toolPath.resolve(TOOL_COMMAND);
+
+ if (!Files.isRegularFile(toolExecutable)) {
+ installTool(version, toolPath);
+ }
return Stream.of(
- dotnetPath.toString(),
- "tool", "exec",
- NUGET_PACKAGE_ID + "@" + version,
- "-y",
- "--allow-roll-forward",
- addSource != null ? "--add-source" : null,
- addSource,
- "--ignore-failed-sources",
- // Suppress NuGet informational messages (e.g. "Skipping NuGet package
- // signature verification") that would corrupt the RPC stdout channel.
- "-v", "q",
- "--",
+ toolExecutable.toAbsolutePath().normalize().toString(),
log == null ? null : "--log-file=" + log.toAbsolutePath().normalize(),
traceRpcMessages ? "--trace-rpc-messages" : null
);
}
+
+ private void installTool(String version, Path toolPath) {
+ try {
+ Files.createDirectories(toolPath);
+
+ List