Skip to main content

ferrum_cli/commands/
pull.rs

1//! Pull command - Download a model from HuggingFace Hub
2
3use crate::config::CliConfig;
4use clap::Args;
5use colored::*;
6use ferrum_types::Result;
7
8#[derive(Args)]
9pub struct PullCommand {
10    /// Model alias, owner/repository, or owner/repository:QUANT (for example :Q4_K_M).
11    pub model: String,
12    /// Exact repository-relative GGUF filename; MODEL may include @<40-hex-commit>.
13    #[arg(long, value_name = "FILE")]
14    pub gguf_file: Option<String>,
15}
16
17pub async fn execute(cmd: PullCommand, config: CliConfig) -> Result<()> {
18    let cache_dir = crate::source_resolver::hf_cache_dir(&config);
19    println!(
20        "{} {}",
21        "Pulling".cyan().bold(),
22        crate::source_resolver::resolve_model_alias(&cmd.model)
23    );
24    println!("{}", format!("Cache: {}", cache_dir.display()).dimmed());
25
26    let result = if let Some(filename) = cmd.gguf_file {
27        crate::source_resolver::resolve_model_source_with_product_sources(
28            &cmd.model,
29            &cache_dir,
30            crate::source_resolver::DownloadPolicy::AutoDownload,
31            None,
32            &crate::source_resolver::ProductSourceArgs {
33                gguf_file: Some(filename),
34                ..Default::default()
35            },
36        )
37        .await
38    } else {
39        crate::source_resolver::resolve_model_source(
40            &cmd.model,
41            &cache_dir,
42            crate::source_resolver::DownloadPolicy::AutoDownload,
43            None,
44        )
45        .await
46    };
47    match result {
48        Ok(resolved) => {
49            println!();
50            println!("{} Model ready at:", "✓".green().bold());
51            println!("  {}", resolved.local_path().display());
52            Ok(())
53        }
54        Err(error) => {
55            eprintln!();
56            eprintln!("{} Failed to pull model: {}", "✗".red().bold(), error);
57            Err(error)
58        }
59    }
60}