entrenar/cli/commands/research/
export.rs1use crate::cli::logging::log;
4use crate::cli::LogLevel;
5use crate::config::{ExportArgs, ExportFormat};
6use crate::research::{AnonymizationConfig, LiterateDocument, NotebookExporter, ResearchArtifact};
7use std::path::Path;
8
9pub fn run_research_export(args: ExportArgs, level: LogLevel) -> Result<(), String> {
10 log(
11 level,
12 LogLevel::Normal,
13 &format!("Exporting: {} -> {}", args.input.display(), args.output.display()),
14 );
15
16 match args.format {
17 ExportFormat::Notebook => export_notebook(&args.input, &args.output, level),
18 ExportFormat::Html => export_html(&args.input, &args.output, level),
19 ExportFormat::AnonymizedJson => export_anonymized_json(&args, level),
20 ExportFormat::RoCrate => {
21 Err("Use 'entrenar research bundle' for RO-Crate export".to_string())
22 }
23 }
24}
25
26fn export_notebook(input: &Path, output: &Path, level: LogLevel) -> Result<(), String> {
28 let content =
29 std::fs::read_to_string(input).map_err(|e| format!("Failed to read input: {e}"))?;
30
31 let doc = LiterateDocument::parse_markdown(&content);
32 let notebook = NotebookExporter::from_literate(&doc);
33
34 let ipynb = notebook.to_ipynb();
35 std::fs::write(output, &ipynb).map_err(|e| format!("Failed to write notebook: {e}"))?;
36
37 log(level, LogLevel::Normal, &format!("Notebook exported: {} cells", notebook.cell_count()));
38 Ok(())
39}
40
41fn export_html(input: &Path, output: &Path, level: LogLevel) -> Result<(), String> {
43 let content =
44 std::fs::read_to_string(input).map_err(|e| format!("Failed to read input: {e}"))?;
45
46 let doc = LiterateDocument::parse_markdown(&content);
47 let html = doc.to_html();
48
49 std::fs::write(output, &html).map_err(|e| format!("Failed to write HTML: {e}"))?;
50
51 log(level, LogLevel::Normal, "HTML exported successfully");
52 Ok(())
53}
54
55fn export_anonymized_json(args: &ExportArgs, level: LogLevel) -> Result<(), String> {
57 if !args.anonymize {
58 return Err("--anonymize flag required for anonymized export".to_string());
59 }
60
61 let salt = args.anon_salt.as_ref().ok_or("--anon-salt required for anonymization")?;
62
63 let yaml = std::fs::read_to_string(&args.input)
64 .map_err(|e| format!("Failed to read artifact: {e}"))?;
65
66 let artifact: ResearchArtifact =
67 serde_yaml::from_str(&yaml).map_err(|e| format!("Failed to parse artifact: {e}"))?;
68
69 let config = AnonymizationConfig::new(salt);
70 let anon = config.anonymize(&artifact);
71
72 let json = serde_json::to_string_pretty(&anon).map_err(|e| format!("JSON error: {e}"))?;
73
74 std::fs::write(&args.output, &json).map_err(|e| format!("Failed to write JSON: {e}"))?;
75
76 log(level, LogLevel::Normal, &format!("Anonymized artifact: {}", anon.anonymous_id));
77 Ok(())
78}