|
1 | 1 | use crate::args::{CliInput, parse_global_options, parse_with_onlyfile}; |
2 | | -use crate::compile::{compile_for_cli_input_in_dir, ensure_no_error_diagnostics}; |
| 2 | +use crate::compile::{ |
| 3 | + CliCompileResult, compile_for_cli_input_in_dir, ensure_no_error_diagnostics, resolve_target, |
| 4 | +}; |
3 | 5 | use crate::discover::discover_onlyfile; |
4 | 6 | use crate::error::{OnlyError, Result}; |
5 | 7 | use crate::render::{ |
6 | 8 | render_available_tasks, render_error_message, render_global_help, render_help_hint, |
7 | 9 | render_namespace_help, |
8 | 10 | }; |
9 | | -use only_engine::ExecutionPlan; |
10 | | -use only_semantic::DocumentAst; |
| 11 | +use only_engine::{ExecutionPlan, render_command, select_root_task_variant}; |
| 12 | +use only_semantic::{DocumentAst, GuardAst, TaskAst}; |
11 | 13 | use std::path::{Path, PathBuf}; |
12 | 14 | use std::process::ExitCode; |
13 | 15 |
|
@@ -75,6 +77,7 @@ pub fn run_with(cli: CliInput) -> Result<ExitCode> { |
75 | 77 | } |
76 | 78 |
|
77 | 79 | let compiled = compile_for_cli_input_in_dir(&discovered.contents, &cli, discovered.base_dir)?; |
| 80 | + render_preview_if_enabled(&compiled, &cli)?; |
78 | 81 | only_engine::run_plan(&compiled.plan).map_err(|error| OnlyError::runtime(error.to_string())) |
79 | 82 | } |
80 | 83 |
|
@@ -150,6 +153,58 @@ pub fn run_plan(plan: &ExecutionPlan) -> Result<ExitCode> { |
150 | 153 | only_engine::run_plan(plan).map_err(|error| OnlyError::runtime(error.to_string())) |
151 | 154 | } |
152 | 155 |
|
| 156 | +fn render_preview_if_enabled(compiled: &CliCompileResult, cli: &CliInput) -> Result<()> { |
| 157 | + if !compiled.plan.preview { |
| 158 | + return Ok(()); |
| 159 | + } |
| 160 | + |
| 161 | + let (target, _) = resolve_target(&compiled.compiled, cli)?; |
| 162 | + let variant = select_root_task_variant(&compiled.compiled.document, &target) |
| 163 | + .map_err(|error| OnlyError::runtime(error.to_string()))?; |
| 164 | + eprintln!("{}", render_plan_preview(&compiled.plan, variant)?); |
| 165 | + Ok(()) |
| 166 | +} |
| 167 | + |
| 168 | +fn render_plan_preview(plan: &ExecutionPlan, variant: &TaskAst) -> Result<String> { |
| 169 | + let mut output = String::from("Preview:\n"); |
| 170 | + output.push_str(" variant: "); |
| 171 | + output.push_str(&render_task_variant(variant)); |
| 172 | + output.push('\n'); |
| 173 | + output.push_str(" commands:\n"); |
| 174 | + |
| 175 | + for node in &plan.nodes { |
| 176 | + for command in &node.commands { |
| 177 | + let rendered = render_command(command, &node.params) |
| 178 | + .map_err(|error| OnlyError::runtime(error.to_string()))?; |
| 179 | + output.push_str(" ["); |
| 180 | + output.push_str(&node.name); |
| 181 | + output.push_str("] "); |
| 182 | + output.push_str(&rendered); |
| 183 | + output.push('\n'); |
| 184 | + } |
| 185 | + } |
| 186 | + |
| 187 | + Ok(output.trim_end().to_string()) |
| 188 | +} |
| 189 | + |
| 190 | +fn render_task_variant(task: &TaskAst) -> String { |
| 191 | + let mut variant = match &task.namespace { |
| 192 | + Some(namespace) => format!("{namespace}.{}", task.signature()), |
| 193 | + None => task.signature().to_string(), |
| 194 | + }; |
| 195 | + |
| 196 | + if let Some(guard) = &task.guard { |
| 197 | + variant.push_str(" ? "); |
| 198 | + variant.push_str(&render_guard(guard)); |
| 199 | + } |
| 200 | + |
| 201 | + variant |
| 202 | +} |
| 203 | + |
| 204 | +fn render_guard(guard: &GuardAst) -> String { |
| 205 | + format!("@{}(\"{}\")", guard.kind, guard.argument) |
| 206 | +} |
| 207 | + |
153 | 208 | fn run_inner() -> Result<ExitCode> { |
154 | 209 | let partial = parse_global_options()?; |
155 | 210 |
|
@@ -192,5 +247,6 @@ fn run_inner() -> Result<ExitCode> { |
192 | 247 | } |
193 | 248 |
|
194 | 249 | let compiled = compile_for_cli_input_in_dir(&discovered.contents, &cli, discovered.base_dir)?; |
| 250 | + render_preview_if_enabled(&compiled, &cli)?; |
195 | 251 | only_engine::run_plan(&compiled.plan).map_err(|error| OnlyError::runtime(error.to_string())) |
196 | 252 | } |
0 commit comments