Skip to main content

datalab_cli/commands/
track_changes.rs

1use crate::cache::Cache;
2use crate::client::{add_form_field, build_form_with_file, DatalabClient};
3use crate::error::{DatalabError, Result};
4use crate::output::Progress;
5use clap::Args;
6use reqwest::multipart::Form;
7use serde_json::json;
8use std::fs;
9use std::path::PathBuf;
10
11#[derive(Args, Debug)]
12pub struct TrackChangesArgs {
13    /// DOCX file path or URL
14    #[arg(value_name = "FILE|URL")]
15    pub input: String,
16
17    /// Output format (comma-separated): html, markdown
18    #[arg(
19        long,
20        default_value = "html,markdown",
21        value_name = "FORMATS",
22        help_heading = "Output Options"
23    )]
24    pub output_format: String,
25
26    /// Add page markers to output
27    #[arg(long, help_heading = "Output Options")]
28    pub paginate: bool,
29
30    /// Skip local cache lookup
31    #[arg(long, help_heading = "Cache Options")]
32    pub skip_cache: bool,
33
34    /// Write result to file
35    #[arg(long, short, value_name = "FILE", help_heading = "Output Options")]
36    pub output: Option<PathBuf>,
37
38    /// Request timeout in seconds
39    #[arg(
40        long,
41        default_value = "300",
42        value_name = "SECS",
43        help_heading = "Advanced Options"
44    )]
45    pub timeout: u64,
46}
47
48impl TrackChangesArgs {
49    fn to_cache_params(&self) -> serde_json::Value {
50        json!({
51            "output_format": self.output_format,
52            "paginate": self.paginate,
53        })
54    }
55
56    fn add_to_form(&self, mut form: Form) -> Form {
57        form = add_form_field(form, "output_format", &self.output_format);
58
59        if self.paginate {
60            form = add_form_field(form, "paginate", "true");
61        }
62
63        form
64    }
65}
66
67pub async fn execute(args: TrackChangesArgs, progress: &Progress) -> Result<()> {
68    let client = DatalabClient::new(Some(args.timeout))?;
69    let cache = Cache::new()?;
70
71    let is_url = args.input.starts_with("http://") || args.input.starts_with("https://");
72    let file_path = if is_url {
73        None
74    } else {
75        Some(PathBuf::from(&args.input))
76    };
77
78    let file_str = file_path.as_ref().map(|p| p.to_string_lossy().to_string());
79    progress.start("track-changes", file_str.as_deref());
80
81    let file_hash = if let Some(ref path) = file_path {
82        if !path.exists() {
83            return Err(DatalabError::FileNotFound(path.clone()));
84        }
85        Some(Cache::hash_file(path)?)
86    } else {
87        None
88    };
89
90    let cache_params = args.to_cache_params();
91    let cache_key = Cache::generate_key(
92        file_hash.as_deref(),
93        if is_url { Some(&args.input) } else { None },
94        "track-changes",
95        &cache_params,
96    );
97
98    if !args.skip_cache {
99        if let Some(cached) = cache.get(&cache_key) {
100            progress.cache_hit(&cache_key);
101            output_result(&cached, args.output.as_ref())?;
102            return Ok(());
103        }
104    }
105
106    let form = if let Some(ref path) = file_path {
107        let (form, _) = build_form_with_file(path)?;
108        args.add_to_form(form)
109    } else {
110        let form = Form::new().text("file_url", args.input.clone());
111        args.add_to_form(form)
112    };
113
114    let result = client
115        .submit_and_poll("track-changes", form, progress)
116        .await?;
117
118    let file_path_str = file_path.as_ref().map(|p| p.to_string_lossy().to_string());
119    cache.set(
120        &cache_key,
121        &result,
122        "track-changes",
123        file_hash.as_deref(),
124        file_path_str.as_deref(),
125    )?;
126
127    output_result(&result, args.output.as_ref())?;
128
129    Ok(())
130}
131
132fn output_result(result: &serde_json::Value, output_file: Option<&PathBuf>) -> Result<()> {
133    let json_output = serde_json::to_string_pretty(result)?;
134
135    if let Some(path) = output_file {
136        fs::write(path, &json_output)?;
137    } else {
138        println!("{}", json_output);
139    }
140
141    Ok(())
142}