Skip to main content

aprender_contracts_cli/commands/
generate.rs

1use std::path::Path;
2
3use provable_contracts::binding::{parse_binding, BindingRegistry};
4use provable_contracts::generate::{generate_all, GeneratedFiles};
5use provable_contracts::readme_gen::{generate_ci_workflow, generate_readme};
6use provable_contracts::schema::{parse_contract, Contract};
7
8pub fn run(
9    contract: &Path,
10    output_dir: &Path,
11    binding_path: Option<&Path>,
12    readme: bool,
13    ci: bool,
14) -> Result<(), Box<dyn std::error::Error>> {
15    let c = parse_contract(contract)?;
16    let binding = load_binding(binding_path)?;
17    let stem = contract
18        .file_stem()
19        .and_then(|s| s.to_str())
20        .unwrap_or("contract");
21
22    let result = generate_all(&c, stem, output_dir, binding.as_ref())?;
23    print_generated_files(&result, output_dir);
24
25    if readme {
26        write_readme(&c, stem, output_dir, binding.as_ref())?;
27    }
28    if ci {
29        write_ci_workflow(output_dir, binding.as_ref())?;
30    }
31    Ok(())
32}
33
34fn load_binding(
35    binding_path: Option<&Path>,
36) -> Result<Option<BindingRegistry>, Box<dyn std::error::Error>> {
37    match binding_path {
38        Some(bp) => Ok(Some(parse_binding(bp)?)),
39        None => Ok(None),
40    }
41}
42
43fn print_generated_files(result: &GeneratedFiles, output_dir: &Path) {
44    println!(
45        "Generated {} files in {}:",
46        result.files.len(),
47        output_dir.display()
48    );
49    for f in &result.files {
50        println!(
51            "  {} ({}, {} bytes)",
52            f.relative_path.display(),
53            f.kind,
54            f.bytes
55        );
56    }
57}
58
59fn write_readme(
60    c: &Contract,
61    stem: &str,
62    output_dir: &Path,
63    binding: Option<&BindingRegistry>,
64) -> Result<(), Box<dyn std::error::Error>> {
65    let Some(reg) = binding else {
66        eprintln!("warning: --readme requires --binding to generate coverage report");
67        return Ok(());
68    };
69    let contracts = vec![(stem.to_string(), c)];
70    let readme_content = generate_readme(&contracts, reg);
71    let readme_path = output_dir.join("CONTRACT-README.md");
72    std::fs::write(&readme_path, &readme_content)?;
73    println!(
74        "  CONTRACT-README.md (readme, {} bytes)",
75        readme_content.len()
76    );
77    Ok(())
78}
79
80fn write_ci_workflow(
81    output_dir: &Path,
82    binding: Option<&BindingRegistry>,
83) -> Result<(), Box<dyn std::error::Error>> {
84    let project_name = binding.map_or("project", |b| b.target_crate.as_str());
85    let ci_content = generate_ci_workflow(project_name);
86    let ci_dir = output_dir.join(".github").join("workflows");
87    std::fs::create_dir_all(&ci_dir)?;
88    let ci_path = ci_dir.join("contracts.yml");
89    std::fs::write(&ci_path, &ci_content)?;
90    println!(
91        "  .github/workflows/contracts.yml (ci, {} bytes)",
92        ci_content.len()
93    );
94    Ok(())
95}