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 None,
34 )?;
35
36 if graph.nodes.is_empty() {
37 return Err(anyhow!("Could not resolve package '{}'", package_source));
38 }
39
40 let node = graph
42 .nodes
43 .values()
44 .find(|n| matches!(n.reason, zoi_core::types::InstallReason::Direct))
45 .ok_or_else(|| anyhow!("Could not find target package in resolution graph"))?;
46
47 println!(
48 "{} Resolved to {} v{}",
49 "::".bold().green(),
50 node.pkg.name.cyan(),
51 node.version.yellow()
52 );
53
54 let info = if download_type == DownloadType::Source {
55 util::find_source_bundle_info(node)?.ok_or_else(|| {
56 anyhow!("No source bundle (.zsa) information found for this package in the registry.")
57 })?
58 } else {
59 util::find_prebuilt_info(node)?.ok_or_else(|| {
60 anyhow!(
61 "No pre-built archive (.zpa) information found for this package in the registry."
62 )
63 })?
64 };
65
66 let filename = info
67 .final_url
68 .split('/')
69 .next_back()
70 .unwrap_or("package.archive");
71
72 let dest_path = if let Some(dir) = output_dir {
73 std::fs::create_dir_all(&dir)?;
74 dir.join(filename)
75 } else {
76 let cache_root = cache::get_archive_cache_root()?;
77 std::fs::create_dir_all(&cache_root)?;
78 cache_root.join(filename)
79 };
80
81 println!(
82 "{} Downloading to: {}",
83 "::".bold().blue(),
84 dest_path.display()
85 );
86
87 let (down_size, _) = util::get_package_sizes(&node.pkg, &node.registry_handle, &node.version);
88
89 util::download_file_with_progress(&info.final_url, &dest_path, None, Some(down_size))?;
90
91 println!(
92 "{} Successfully downloaded: {}",
93 "::".bold().green(),
94 dest_path.display()
95 );
96
97 Ok(())
98}