diff --git a/crates/ide-run/src/import/jetbrains.rs b/crates/ide-run/src/import/jetbrains.rs index 327ce6399..ea94f7dbb 100644 --- a/crates/ide-run/src/import/jetbrains.rs +++ b/crates/ide-run/src/import/jetbrains.rs @@ -4,8 +4,8 @@ //! than one place is taken from the first, in that order. //! //! Python, Django server, Django tests, pytest, npm, Jest, Vitest, Node.js, Shell Script, -//! Application, Spring Boot and compound configurations become the matching kinds; other types -//! are skipped with their type. +//! Application, Spring Boot, Go Application / Go Test and compound configurations become the +//! matching kinds; other types are skipped with their type. //! `$PROJECT_DIR$` (and `$MODULE_DIR$`, `$MODULE_WORKING_DIR$`, `$ContentRoot$`, //! `$ProjectFileDir$`, all the project directory here) and `$USER_HOME$` are replaced; another //! path variable skips the configuration. @@ -165,6 +165,8 @@ const SHELL: &str = "ShConfigurationType"; const COMPOUND: &str = "CompoundRunConfigurationType"; const APPLICATION: &str = "Application"; const SPRING_BOOT: &str = "SpringBootApplicationConfigurationType"; +const GO_APPLICATION: &str = "GoApplicationRunConfiguration"; +const GO_TEST: &str = "GoTestRunConfiguration"; type Res = Result; @@ -343,6 +345,8 @@ impl Cx<'_> { SHELL => self.shell(name, c)?, APPLICATION => self.java_app(name, c, false, &mut ignored)?, SPRING_BOOT => self.java_app(name, c, true, &mut ignored)?, + GO_APPLICATION => self.go_config(name, c, false, &mut ignored)?, + GO_TEST => self.go_config(name, c, true, &mut ignored)?, COMPOUND => { members = c.children_named("toRun").filter_map(|t| t.attr("name")).map(str::to_owned).collect(); config(name, "compound", String::new(), Vec::new(), None) @@ -353,6 +357,84 @@ impl Cx<'_> { Ok(Found { config, members, ignored }) } + /// A Go Application (`GoApplicationRunConfiguration`) or Go Test configuration. Both share + /// the kind (package / file / directory), the target node, `go_parameters` (go tool + /// arguments) and envs; a test adds a `pattern` and program arguments go after `-args`. + fn go_config(&self, name: &str, c: &El, test: bool, _ignored: &mut Vec) -> Res { + let (dir, cwd) = self.cwd(c.value("working_directory"))?; + let scope = match c.value("kind").unwrap_or("PACKAGE") { + "FILE" => "file", + "DIRECTORY" => "directory", + _ => "package", + }; + let path_target = |value: Option<&str>| -> Res> { + Ok(self.path(value)?.map(|p| path_from(self.root, p, &dir)).filter(|p| !p.is_empty())) + }; + let target = match scope { + "file" => path_target(c.value("filePath"))? + .or(self.text(c.value("package"))?) + .filter(|t| !t.is_empty()) + .unwrap_or_else(|| ".".to_owned()), + "directory" => path_target(c.value("directory"))?.unwrap_or_else(|| ".".to_owned()), + _ => self.text(c.value("package"))?.filter(|t| !t.is_empty()).unwrap_or_else(|| ".".to_owned()), + }; + let raw_tool = self.text(c.value("go_parameters"))?.unwrap_or_default(); + let tool_args = parse_params(&raw_tool, Quotes::Double); + let raw_program = self.text(c.value("parameters"))?.unwrap_or_default(); + let program_args = parse_params(&raw_program, Quotes::Double); + let pattern = self.text(c.value("pattern"))?.unwrap_or_default(); + let output_dir = + self.path(c.value("output_directory"))?.map(|p| path_from(self.root, p, self.root)).unwrap_or_default(); + // The form's module is the working directory relative to the project root. + let module = cwd.as_ref().map(|d| d.to_string_lossy().replace('\\', "/")).unwrap_or_default(); + let run_after_build = c.option("run") != Some("false"); + let targets: Vec = if scope == "file" { + target.split('|').map(|t| t.trim().to_owned()).filter(|t| !t.is_empty()).collect() + } else { + vec![target.clone()] + }; + let mut args = vec![if test { "test".to_owned() } else { "build".to_owned() }]; + args.extend(tool_args.clone()); + if test { + if !pattern.is_empty() { + args.extend(["-run".to_owned(), pattern.clone()]); + } + args.extend(targets); + if !program_args.is_empty() { + args.push("-args".to_owned()); + args.extend(program_args.clone()); + } + } else { + args.extend(targets); + } + let mut rc = config(name, "go", "go".into(), args, Some("delve")); + rc.cwd = cwd.map(Into::into); + rc.is_test = test; + let mut params = BTreeMap::from([ + ("goKind".to_owned(), if test { "test" } else { "build" }.to_owned()), + ("scope".to_owned(), scope.to_owned()), + ("target".to_owned(), target), + ("toolArgs".to_owned(), raw_tool), + ("programArgs".to_owned(), raw_program), + ("module".to_owned(), module), + ]); + if test { + if !pattern.is_empty() { + params.insert("pattern".to_owned(), pattern); + } + } else { + params.insert("outputDir".to_owned(), output_dir); + params.insert("runAfterBuild".to_owned(), run_after_build.to_string()); + } + if !program_args.is_empty() { + params.insert("programArgv".to_owned(), serde_json::to_string(&program_args).unwrap_or_default()); + } + params.retain(|_, value| !value.is_empty()); + rc.extras.params = params; + self.envs(c, &mut rc); + Ok(rc) + } + // ------------------------------------------------------------- Python /// The interpreter (`SDK_HOME` when the configuration doesn't use the module's), its diff --git a/crates/ide-run/tests/import_jetbrains.rs b/crates/ide-run/tests/import_jetbrains.rs index 97473927b..b5fc65724 100644 --- a/crates/ide-run/tests/import_jetbrains.rs +++ b/crates/ide-run/tests/import_jetbrains.rs @@ -1007,3 +1007,74 @@ fn file_urls_expand_module_and_home_macros() { assert_eq!(cwd(home), Some(PathBuf::from("jobs dir"))); assert!(home.extras.local); } + +#[test] +fn imports_go_application_and_test_configurations() { + let dir = tempfile::tempdir().unwrap(); + write( + dir.path(), + ".run/build-linux-amd64.run.xml", + &run_file( + "build-linux-amd64", + r#" + + + + + + + + + + + + + + "#, + ), + ); + write( + dir.path(), + ".run/Test.run.xml", + &run_file( + "Run tests", + r#" + + + + + + + + + "#, + ), + ); + let r = import_from(dir.path(), &[]); + + let app = get(&r, "build-linux-amd64"); + assert_eq!(app.kind, "go"); + assert_eq!(app.command, "go"); + assert_eq!(app.args, s(&["build", "-ldflags", "-s -w", "-o", "bin/goproject.linux-amd64", "goproject"])); + assert_eq!(app.env["GOOS"], "linux"); + assert_eq!(app.extras.params["goKind"], "build"); + assert_eq!(app.extras.params["scope"], "package"); + assert_eq!(app.extras.params["target"], "goproject"); + assert_eq!(app.extras.params["outputDir"], "bin"); + assert_eq!(app.extras.params["runAfterBuild"], "false"); + assert_eq!(app.extras.folder.as_deref(), Some("go-build")); + + let test = get(&r, "Run tests"); + assert!(test.is_test); + assert_eq!(test.kind, "go"); + assert_eq!( + test.args, + s(&["test", "-tags", "integration", "-run", "TestLogin", "example.com/pkg", "-args", "-v", "-count=1"]) + ); + assert_eq!(cwd(test), Some(PathBuf::from("pkg"))); + assert_eq!(test.extras.params["goKind"], "test"); + assert_eq!(test.extras.params["pattern"], "TestLogin"); + assert_eq!(test.extras.params["module"], "pkg"); +}