use async_trait::async_trait;
use clap::{Command, arg};
use cuenv_core::Result;
use cuenv_core::manifest::{Base, Project};
use std::path::Path;
use crate::commands::CommandExecutor;
use crate::commands::sync::functions;
use crate::commands::sync::provider::{SyncMode, SyncOptions, SyncProvider, SyncResult};
pub struct CodegenSyncProvider;
#[async_trait]
impl SyncProvider for CodegenSyncProvider {
fn name(&self) -> &'static str {
"codegen"
}
fn description(&self) -> &'static str {
"Sync files from CUE codegen configurations"
}
fn has_config(&self, _manifest: &Base) -> bool {
false }
fn build_command(&self) -> Command {
self.default_command()
.arg(arg!(--diff "Show diff for files that would change"))
}
async fn sync_path(
&self,
path: &Path,
package: &str,
options: &SyncOptions,
executor: &CommandExecutor,
) -> Result<SyncResult> {
let dry_run = options.mode == SyncMode::DryRun;
let check = options.mode == SyncMode::Check;
let codegen_options = functions::CodegenSyncOptions {
dry_run: dry_run.into(),
check,
diff: options.show_diff,
};
let request = functions::CodegenSyncRequest {
path: path.to_str().unwrap_or("."),
package,
options: codegen_options,
};
let output = functions::execute_sync_codegen(request, executor).await?;
Ok(SyncResult::success(output))
}
async fn sync_workspace(
&self,
package: &str,
options: &SyncOptions,
executor: &CommandExecutor,
) -> Result<SyncResult> {
let dry_run = options.mode == SyncMode::DryRun;
let check = options.mode == SyncMode::Check;
let cwd = std::env::current_dir().map_err(|e| {
cuenv_core::Error::configuration(format!("Failed to get current directory: {e}"))
})?;
let project_paths: Vec<(std::path::PathBuf, String)> = {
let module = executor.discover_all_modules(&cwd)?;
let mut paths = Vec::new();
for instance in module.projects() {
if let Ok(manifest) = instance.deserialize::<Project>()
&& manifest.codegen.is_some()
{
paths.push((
module.root.join(&instance.path),
instance.path.display().to_string(),
));
}
}
paths
};
let mut outputs = Vec::new();
let mut had_error = false;
for (full_path, display_path) in project_paths {
let codegen_options = functions::CodegenSyncOptions {
dry_run: dry_run.into(),
check,
diff: options.show_diff,
};
let request = functions::CodegenSyncRequest {
path: full_path.to_str().unwrap_or("."),
package,
options: codegen_options,
};
let result = functions::execute_sync_codegen(request, executor).await;
match result {
Ok(output) if !output.is_empty() => {
let display = if display_path.is_empty() {
"[root]".to_string()
} else {
display_path
};
outputs.push(format!("{display}:\n{output}"));
}
Ok(_) => {}
Err(e) => {
outputs.push(format!("{display_path}: Error: {e}"));
had_error = true;
}
}
}
if outputs.is_empty() {
Ok(SyncResult::success("No codegen configurations found."))
} else {
Ok(SyncResult {
output: outputs.join("\n\n"),
had_error,
})
}
}
}