|
1 | | -use error_stack::Report; |
2 | | -use crate::command_utils::{run_command_by_shell, run_command_line, CommandOutput}; |
| 1 | +use crate::command_utils::{run_command_by_shell, run_command_with_env_vars, CommandOutput}; |
3 | 2 | use crate::errors::KeeperError; |
4 | 3 | use crate::models::Task; |
5 | 4 | use crate::task; |
| 5 | +use error_stack::Report; |
6 | 6 | use jsonc_parser::parse_to_serde_value; |
7 | 7 | use serde::{Deserialize, Serialize}; |
| 8 | +use std::collections::HashMap; |
| 9 | +use std::env; |
8 | 10 |
|
9 | 11 | #[derive(Serialize, Deserialize, Debug, Default)] |
10 | 12 | struct TasksJson { |
11 | 13 | pub version: String, |
12 | 14 | pub tasks: Option<Vec<VSTask>>, |
13 | 15 | } |
14 | 16 |
|
15 | | -#[derive(Serialize, Deserialize, Debug, Default)] |
| 17 | +impl TasksJson { |
| 18 | + pub fn find_task(&self, task_name: &str) -> Option<VSTask> { |
| 19 | + if let Some(tasks) = &self.tasks { |
| 20 | + let result = tasks.iter().find(|task| { |
| 21 | + if let Some(label) = &task.label { |
| 22 | + label == task_name |
| 23 | + } else { |
| 24 | + false |
| 25 | + } |
| 26 | + }); |
| 27 | + if let Some(task) = result { |
| 28 | + return Some(task.clone()); |
| 29 | + } |
| 30 | + } |
| 31 | + None |
| 32 | + } |
| 33 | +} |
| 34 | + |
| 35 | +// Command options |
| 36 | +#[derive(Serialize, Deserialize, Debug, Default, Clone)] |
| 37 | +struct CommandOptions { |
| 38 | + // current working directory |
| 39 | + cwd: Option<String>, |
| 40 | + // environment variables passed to the task |
| 41 | + env: Option<HashMap<String, String>>, |
| 42 | +} |
| 43 | + |
| 44 | +// --- Platform-specific configuration --- |
| 45 | +#[derive(Serialize, Deserialize, Debug, Default, Clone)] |
| 46 | +struct PlatformConfig { |
| 47 | + command: Option<String>, |
| 48 | + args: Option<Vec<String>>, |
| 49 | + options: Option<CommandOptions>, |
| 50 | +} |
| 51 | + |
| 52 | +#[derive(Serialize, Deserialize, Debug, Default, Clone)] |
16 | 53 | struct VSTask { |
17 | 54 | pub label: Option<String>, |
18 | 55 | #[serde(rename = "type")] |
19 | 56 | pub task_type: String, |
20 | 57 | pub command: Option<String>, |
| 58 | + options: Option<CommandOptions>, |
| 59 | + args: Option<Vec<String>>, |
| 60 | + // Platform-specific configurations |
| 61 | + #[allow(dead_code)] |
| 62 | + windows: Option<PlatformConfig>, |
| 63 | + #[allow(dead_code)] |
| 64 | + linux: Option<PlatformConfig>, |
| 65 | + #[allow(dead_code)] |
| 66 | + osx: Option<PlatformConfig>, |
| 67 | +} |
| 68 | + |
| 69 | +impl VSTask { |
| 70 | + pub fn get_command(&self) -> Option<String> { |
| 71 | + // Determine current platform |
| 72 | + #[cfg(target_os = "windows")] |
| 73 | + let platform_config = &self.windows; |
| 74 | + |
| 75 | + #[cfg(target_os = "linux")] |
| 76 | + let platform_config = &self.linux; |
| 77 | + |
| 78 | + #[cfg(target_os = "macos")] |
| 79 | + let platform_config = &self.osx; |
| 80 | + if let Some(config) = platform_config { |
| 81 | + if let Some(cmd) = &config.command { |
| 82 | + return Some(cmd.clone()); |
| 83 | + } |
| 84 | + } |
| 85 | + self.command.clone() |
| 86 | + } |
| 87 | + |
| 88 | + pub fn get_command_options(&self) -> Option<CommandOptions> { |
| 89 | + // Determine current platform |
| 90 | + #[cfg(target_os = "windows")] |
| 91 | + let platform_config = &self.windows; |
| 92 | + |
| 93 | + #[cfg(target_os = "linux")] |
| 94 | + let platform_config = &self.linux; |
| 95 | + |
| 96 | + #[cfg(target_os = "macos")] |
| 97 | + let platform_config = &self.osx; |
| 98 | + if let Some(config) = platform_config { |
| 99 | + if let Some(option) = &config.options { |
| 100 | + return Some(option.clone()); |
| 101 | + } |
| 102 | + } |
| 103 | + self.options.clone() |
| 104 | + } |
21 | 105 | } |
22 | 106 |
|
23 | 107 | pub fn is_available() -> bool { |
@@ -68,20 +152,46 @@ fn parse_run_json() -> TasksJson { |
68 | 152 | } |
69 | 153 |
|
70 | 154 | pub fn run_task( |
71 | | - task: &str, |
| 155 | + task_name: &str, |
72 | 156 | _task_args: &[&str], |
73 | 157 | _global_args: &[&str], |
74 | 158 | verbose: bool, |
75 | 159 | ) -> Result<CommandOutput, Report<KeeperError>> { |
76 | | - let tasks = list_tasks()?; |
77 | | - let task = tasks |
78 | | - .iter() |
79 | | - .find(|t| t.name == task) |
80 | | - .ok_or_else(|| KeeperError::TaskNotFound(task.to_string()))?; |
81 | | - if let Some(_runner2) = &task.runner2 { |
82 | | - run_command_by_shell(&task.description, verbose) |
| 160 | + let tasks_json = parse_run_json(); |
| 161 | + let task = tasks_json |
| 162 | + .find_task(task_name) |
| 163 | + .ok_or_else(|| KeeperError::TaskNotFound(task_name.to_string()))?; |
| 164 | + let command = task.command.clone().unwrap(); |
| 165 | + if task.task_type == "shell" { |
| 166 | + run_command_by_shell(&command, verbose) |
83 | 167 | } else { |
84 | | - run_command_line(&task.description, verbose) |
| 168 | + let mut workspace_root = env::current_dir().unwrap().to_str().unwrap().to_string(); |
| 169 | + let mut command_env_vars: Option<HashMap<String, String>> = None; |
| 170 | + let command = task.get_command().unwrap(); |
| 171 | + let options = task.get_command_options(); |
| 172 | + if let Some(options) = &options { |
| 173 | + if let Some(cwd) = &options.cwd { |
| 174 | + workspace_root = cwd.to_string(); |
| 175 | + } |
| 176 | + if let Some(env_vars) = &options.env { |
| 177 | + command_env_vars = Some(env_vars.clone()); |
| 178 | + } |
| 179 | + } |
| 180 | + let command_and_args = shlex::split(&command).unwrap(); |
| 181 | + let command_name = command_and_args.get(0).unwrap(); |
| 182 | + let mut command_args: Vec<&str> = command_and_args[1..].iter().map(AsRef::as_ref).collect(); |
| 183 | + if let Some(args) = &task.args { |
| 184 | + for arg in args { |
| 185 | + command_args.push(arg); |
| 186 | + } |
| 187 | + } |
| 188 | + run_command_with_env_vars( |
| 189 | + command_name, |
| 190 | + &command_args, |
| 191 | + &Some(workspace_root), |
| 192 | + &command_env_vars, |
| 193 | + verbose, |
| 194 | + ) |
85 | 195 | } |
86 | 196 | } |
87 | 197 |
|
|
0 commit comments