rgen_cli_lib/cmds/
show.rs

1use clap::Args;
2use rgen_core::template::Template;
3use std::path::Path;
4use rgen_utils::error::Result;
5
6#[derive(Args, Debug)]
7pub struct ShowArgs {
8    #[arg(
9        value_name = "TEMPLATE",
10        help = "Template file path or pack_id:template_path"
11    )]
12    pub template: String,
13
14    #[arg(short = 'v', long = "vars", help = "Variables (key=value pairs)")]
15    pub vars: Vec<String>,
16}
17
18pub fn run(args: &ShowArgs) -> Result<()> {
19    // Parse template path
20    let template_path = if args.template.contains(':') {
21        // Pack-based template reference
22        return Err(
23            anyhow::anyhow!("Pack-based templates not yet supported in show command").into(),
24        );
25    } else {
26        // Direct file path
27        Path::new(&args.template)
28    };
29
30    if !template_path.exists() {
31        return Err(anyhow::anyhow!("Template file not found: {}", template_path.display()).into());
32    }
33
34    // Read and parse template
35    let content = std::fs::read_to_string(template_path)?;
36    let mut template = Template::parse(&content)?;
37
38    // Parse variables
39    let mut vars = std::collections::BTreeMap::new();
40    for var in &args.vars {
41        if let Some((key, value)) = var.split_once('=') {
42            vars.insert(key.to_string(), value.to_string());
43        }
44    }
45
46    // Create context and render frontmatter
47    let ctx = tera::Context::from_serialize(&vars)?;
48    let mut pipeline = rgen_core::pipeline::PipelineBuilder::new().build()?;
49
50    // Access tera through a helper method since it's pub(crate)
51    render_template_frontmatter(&mut template, &mut pipeline, &ctx)?;
52
53    // Display template metadata
54    println!("📄 Template: {}", template_path.display());
55    println!("{}", "=".repeat(50));
56
57    // Show frontmatter
58    if let Some(to) = &template.front.to {
59        println!("Output: {}", to);
60    }
61
62    if !template.front.vars.is_empty() {
63        println!("\nVariables:");
64        for (key, value) in &template.front.vars {
65            println!("  {}: {}", key, value);
66        }
67    }
68
69    if template.front.inject {
70        println!("\nInjection Mode: Enabled");
71        if template.front.prepend {
72            println!("  Mode: prepend");
73        } else if template.front.append {
74            println!("  Mode: append");
75        } else if let Some(before) = &template.front.before {
76            println!("  Mode: before '{}'", before);
77        } else if let Some(after) = &template.front.after {
78            println!("  Mode: after '{}'", after);
79        } else if let Some(line) = template.front.at_line {
80            println!("  Mode: at line {}", line);
81        }
82
83        if let Some(skip_if) = &template.front.skip_if {
84            println!("  Skip if: {}", skip_if);
85        }
86
87        if template.front.idempotent {
88            println!("  Idempotent: true");
89        }
90
91        if template.front.backup.unwrap_or(false) {
92            println!("  Backup: true");
93        }
94    }
95
96    if !template.front.rdf_inline.is_empty() {
97        println!("\nInline RDF blocks: {}", template.front.rdf_inline.len());
98    }
99
100    if !template.front.rdf.is_empty() {
101        println!("\nRDF files: {}", template.front.rdf.len());
102        for rdf_file in &template.front.rdf {
103            println!("  - {}", rdf_file);
104        }
105    }
106
107    if !template.front.sparql.is_empty() {
108        println!("\nSPARQL queries: {}", template.front.sparql.len());
109        for (name, query) in &template.front.sparql {
110            println!("  {}: {}", name, query);
111        }
112    }
113
114    if let Some(sh_before) = &template.front.sh_before {
115        println!("\nShell hook (before): {}", sh_before);
116    }
117
118    if let Some(sh_after) = &template.front.sh_after {
119        println!("\nShell hook (after): {}", sh_after);
120    }
121
122    // Show template body preview
123    println!("\nTemplate Body Preview:");
124    println!("{}", "-".repeat(30));
125    let body_lines: Vec<&str> = template.body.lines().take(10).collect();
126    for line in body_lines {
127        println!("{}", line);
128    }
129    if template.body.lines().count() > 10 {
130        println!("... ({} more lines)", template.body.lines().count() - 10);
131    }
132
133    Ok(())
134}
135
136// Helper function to render template frontmatter
137fn render_template_frontmatter(
138    template: &mut Template, pipeline: &mut rgen_core::pipeline::Pipeline, ctx: &tera::Context,
139) -> Result<()> {
140    // Since tera is pub(crate), we can access it from within the crate
141    template
142        .render_frontmatter(pipeline.tera_mut(), ctx)
143        .map_err(|e| anyhow::anyhow!("Template rendering error: {}", e).into())
144}