1use anyhow::{Result, anyhow};
2use colored::*;
3use std::path::PathBuf;
4use zoi_core::cache;
5use zoi_install::resolver::resolve_dependency_graph;
6use zoi_install::util;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9pub enum DownloadType {
10 Archive,
11 Source,
12}
13
14pub fn run(
15 package_source: String,
16 download_type: DownloadType,
17 output_dir: Option<PathBuf>,
18) -> Result<()> {
19 println!(
20 "{} Resolving package '{}' for download...",
21 "::".bold().blue(),
22 package_source.cyan()
23 );
24
25 let (graph, _) = resolve_dependency_graph(
26 std::slice::from_ref(&package_source),
27 None,
28 false,
29 true,
30 false,
31 None,
32 true,
33 )?;
34
35 if graph.nodes.is_empty() {
36 return Err(anyhow!("Could not resolve package '{}'", package_source));
37 }
38
39 let node = graph
41 .nodes
42 .values()
43 .find(|n| matches!(n.reason, zoi_core::types::InstallReason::Direct))
44 .ok_or_else(|| anyhow!("Could not find target package in resolution graph"))?;
45
46 println!(
47 "{} Resolved to {} v{}",
48 "::".bold().green(),
49 node.pkg.name.cyan(),
50 node.version.yellow()
51 );
52
53 let info = if download_type == DownloadType::Source {
54 util::find_source_bundle_info(node)?.ok_or_else(|| {
55 anyhow!("No source bundle (.zsa) information found for this package in the registry.")
56 })?
57 } else {
58 util::find_prebuilt_info(node)?.ok_or_else(|| {
59 anyhow!(
60 "No pre-built archive (.zpa) information found for this package in the registry."
61 )
62 })?
63 };
64
65 let filename = info
66 .final_url
67 .split('/')
68 .next_back()
69 .unwrap_or("package.archive");
70
71 let dest_path = if let Some(dir) = output_dir {
72 std::fs::create_dir_all(&dir)?;
73 dir.join(filename)
74 } else {
75 let cache_root = cache::get_archive_cache_root()?;
76 std::fs::create_dir_all(&cache_root)?;
77 cache_root.join(filename)
78 };
79
80 println!(
81 "{} Downloading to: {}",
82 "::".bold().blue(),
83 dest_path.display()
84 );
85
86 let (down_size, _) = util::get_package_sizes(&node.pkg, &node.registry_handle, &node.version);
87
88 util::download_file_with_progress(&info.final_url, &dest_path, None, Some(down_size))?;
89
90 println!(
91 "{} Successfully downloaded: {}",
92 "::".bold().green(),
93 dest_path.display()
94 );
95
96 Ok(())
97}