diff --git a/crates/ide-host/src/ops/run/commands.rs b/crates/ide-host/src/ops/run/commands.rs index 6d2ba830c..b1a6c867d 100644 --- a/crates/ide-host/src/ops/run/commands.rs +++ b/crates/ide-host/src/ops/run/commands.rs @@ -142,6 +142,21 @@ pub async fn run_gradle_jvm_args_script(_host: &Host, _window: &str, jvm_args: V .map_err(|e| IdeError::internal(e.to_string()))? } +/// Writes one of the IDE's Gradle init scripts (`text`; the file is named `-`) on +/// the machine that runs the build, for `--init-script`, and returns its path. +pub async fn run_gradle_init_script(_host: &Host, _window: &str, name: String, text: String) -> IdeResult { + if name.is_empty() || !name.bytes().all(|b| b.is_ascii_alphanumeric() || b == b'-') { + return Err(IdeError::invalid(format!("invalid init script name {name:?}"))); + } + tokio::task::spawn_blocking(move || { + ide_run::gradle_jvm::write_script(&ide_run::gradle_jvm::default_dir(), &name, &text) + .map(|p| p.to_string_lossy().into_owned()) + .map_err(|e| IdeError::internal(format!("cannot write the Gradle init script: {e}"))) + }) + .await + .map_err(|e| IdeError::internal(e.to_string()))? +} + /// Results from the JUnit XML reports (Surefire, Failsafe, Gradle) of the module at /// `module` (relative to the project root) written since `since_ms` (Unix epoch, ms). pub async fn run_test_reports( @@ -308,6 +323,9 @@ pub(crate) fn register(d: &mut Dispatcher) { d.add("run_gradle_jvm_args_script", |c| async move { run_gradle_jvm_args_script(&c.host, &c.window, c.arg("jvmArgs")?).await }); + d.add("run_gradle_init_script", |c| async move { + run_gradle_init_script(&c.host, &c.window, c.arg("name")?, c.arg("text")?).await + }); d.add("run_test_reports", |c| async move { run_test_reports(&c.host, &c.window, c.arg("module")?, c.arg("sinceMs")?).await }); diff --git a/crates/ide-host/tests/run_configs.rs b/crates/ide-host/tests/run_configs.rs index c45bccdaf..dbec2bc7b 100644 --- a/crates/ide-host/tests/run_configs.rs +++ b/crates/ide-host/tests/run_configs.rs @@ -141,3 +141,19 @@ async fn workspace_cmake_before_launch_tasks_resolve_in_the_member() { assert!(configs.iter().any(|c| c.id == task.target && c.cwd == build.cwd)); } } + +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn gradle_init_scripts_are_written_by_the_host_that_runs_the_build() { + let tmp = tempfile::tempdir().unwrap(); + let host = host(tmp.path()); + let text = "allprojects { }\n".to_string(); + let path = + ops::run::run_gradle_init_script(&host, "main", "openidea-gradle-tests".into(), text.clone()).await.unwrap(); + assert!(path.contains("openidea-gradle-tests-"), "{path}"); + assert_eq!(std::fs::read_to_string(&path).unwrap(), text); + let again = ops::run::run_gradle_init_script(&host, "main", "openidea-gradle-tests".into(), text).await.unwrap(); + assert_eq!(again, path); + // A name is not a path. + let escaped = ops::run::run_gradle_init_script(&host, "main", "../escape".into(), String::new()).await; + assert!(escaped.is_err(), "{escaped:?}"); +} diff --git a/src-tauri/src/commands/mod.rs b/src-tauri/src/commands/mod.rs index d4832c86b..036b93c06 100644 --- a/src-tauri/src/commands/mod.rs +++ b/src-tauri/src/commands/mod.rs @@ -343,6 +343,7 @@ pub fn builder() -> tauri_specta::Builder { run::run_close_stdin, run::run_resize, run::run_gradle_jvm_args_script, + run::run_gradle_init_script, run::run_tomcat_home, run::run_tomcat_artifacts, run::run_tomcat_build, diff --git a/src-tauri/src/commands/run.rs b/src-tauri/src/commands/run.rs index fe4990c80..d53b89a14 100644 --- a/src-tauri/src/commands/run.rs +++ b/src-tauri/src/commands/run.rs @@ -189,6 +189,18 @@ pub async fn run_gradle_jvm_args_script( ide_host::ops::run::run_gradle_jvm_args_script(&state.host, window.label(), jvm_args).await } +/// Writes one of the IDE's Gradle init scripts where the build runs; returns its path. +#[tauri::command] +#[specta::specta] +pub async fn run_gradle_init_script( + window: Window, + state: State<'_, AppState>, + name: String, + text: String, +) -> IdeResult { + ide_host::ops::run::run_gradle_init_script(&state.host, window.label(), name, text).await +} + /// Results from the JUnit XML reports (Surefire, Failsafe, Gradle) of the module at /// `module` (relative to the project root) written since `since_ms` (Unix epoch, ms). #[tauri::command] diff --git a/src/bindings.ts b/src/bindings.ts index 06828b5ea..364df910d 100644 --- a/src/bindings.ts +++ b/src/bindings.ts @@ -630,6 +630,8 @@ export const commands = { runResize: (id: RunId, cols: number, rows: number) => typedError(__TAURI_INVOKE("run_resize", { id, cols, rows })), /** Writes the Gradle init script adding `jvm_args` to the JVMs the build forks; returns its path. */ runGradleJvmArgsScript: (jvmArgs: string[]) => typedError(__TAURI_INVOKE("run_gradle_jvm_args_script", { jvmArgs })), + /** Writes one of the IDE's Gradle init scripts where the build runs; returns its path. */ + runGradleInitScript: (name: string, text: string) => typedError(__TAURI_INVOKE("run_gradle_init_script", { name, text })), runTomcatHome: (home: string) => typedError(__TAURI_INVOKE("run_tomcat_home", { home })), runTomcatArtifacts: () => typedError(__TAURI_INVOKE("run_tomcat_artifacts")), runTomcatBuild: (config: RunConfig_Deserialize) => typedError<({ diff --git a/src/features/run/gradleRun.ts b/src/features/run/gradleRun.ts index 1b1024b71..f17082838 100644 --- a/src/features/run/gradleRun.ts +++ b/src/features/run/gradleRun.ts @@ -85,18 +85,15 @@ export function delegatedGradleConfig(config: RunConfig, module: string, ctx: De }; } -/** Writes an init script where Gradle can read it; it never changes, so once per session. */ +/** + * Writes an init script where Gradle reads it: on the machine that runs the build (the + * remote host in remote development). It never changes, so once per session. + */ const scriptPaths = new Map>(); function writeScript(name: string, text: string): Promise { let written = scriptPaths.get(name); if (!written) { - written = (async () => { - const { tempDir, join } = await import("@tauri-apps/api/path"); - const path = await join(await tempDir(), name); - await call(commands.fsDelete(path)).catch(() => {}); - await call(commands.fsCreateFileBytes(path, Array.from(new TextEncoder().encode(text)))); - return path; - })().catch((e) => { + written = call(commands.runGradleInitScript(name, text)).catch((e) => { scriptPaths.delete(name); throw e; }); @@ -121,7 +118,7 @@ export function withTestEvents(config: T): Promise { if (!isTauri() || !config.isTest || !isGradleCommand(config)) return config; try { - return withTestEvents(config, await writeScript("openidea-gradle-tests.gradle", TESTS_SCRIPT)); + return withTestEvents(config, await writeScript("openidea-gradle-tests", TESTS_SCRIPT)); } catch (e) { console.warn("Gradle test init script not written", e); return config; @@ -150,7 +147,7 @@ export async function gradleDelegation(config: RunConfig): Promise