fix(run): write Gradle init scripts on the host that runs the build (#1377)

The test-events and delegated-run init scripts were written to a path built from the desktop's temporary directory, which doesn't exist on a remote host. A new `run_gradle_init_script` command writes a script under the host's own temporary directory, named by its content, and returns the path Gradle reads it from.
Цей коміт міститься в:
l0ng-ai authored and GitHub committed 2026-11-05 07:25:53 +08:00
1 джерело 8021a8ccca
коміт e17e59ce7d
6 files changed
+56 -10

No files matched your search

+18
Переглянути файл
@@ -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 `<name>-<hash>`) 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<String> {
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
});
+16
Переглянути файл
@@ -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:?}");
}
+1
Переглянути файл
@@ -343,6 +343,7 @@ pub fn builder() -> tauri_specta::Builder<tauri::Wry> {
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,
+12
Переглянути файл
@@ -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<String> {
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]
+2
Переглянути файл
@@ -630,6 +630,8 @@ export const commands = {
runResize: (id: RunId, cols: number, rows: number) => typedError<null, IdeError>(__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<string, IdeError>(__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<string, IdeError>(__TAURI_INVOKE("run_gradle_init_script", { name, text })),
runTomcatHome: (home: string) => typedError<TomcatHome, IdeError>(__TAURI_INVOKE("run_tomcat_home", { home })),
runTomcatArtifacts: () => typedError<WebArtifact[], IdeError>(__TAURI_INVOKE("run_tomcat_artifacts")),
runTomcatBuild: (config: RunConfig_Deserialize) => typedError<({
+7 -10
Переглянути файл
@@ -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<string, Promise<string>>();
function writeScript(name: string, text: string): Promise<string> {
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<T extends Pick<RunConfig, "kind" | "command" | "a
export async function gradleTestLaunch<T extends RunConfig>(config: T): Promise<T> {
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<RunConfig | n
};
if (!delegatedGradleConfig(config, module, ctx)) return null;
const [script, configurationCache] = await Promise.all([
writeScript("openidea-gradle-run.gradle", RUN_SCRIPT),
writeScript("openidea-gradle-run", RUN_SCRIPT),
supportsConfigurationCache(ctx),
]);
return delegatedGradleConfig(config, module, { ...ctx, script, configurationCache });