1use std::path::PathBuf;
4
5use anyhow::{Result, anyhow};
6use colored::Colorize;
7use zoi_core::cache;
8use zoi_install::resolver::resolve_dependency_graph;
9use zoi_install::util;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13pub enum DownloadType {
14 Archive,
16 Source
18}
19
20pub fn run(
30 package_source: &str,
31 download_type: DownloadType,
32 output_dir: Option<PathBuf>
33) -> Result<()> {
34 println!(
35 "{} Resolving package '{}' for download...",
36 "::".bold().blue(),
37 package_source.cyan()
38 );
39
40 let (graph, _) = resolve_dependency_graph(
41 &[package_source.to_string()],
42 None,
43 false,
44 true,
45 false,
46 None,
47 true,
48 None
49 )?;
50
51 if graph.nodes.is_empty() {
52 return Err(anyhow!("Could not resolve package '{package_source}'"));
53 }
54
55 let node = graph
57 .nodes
58 .values()
59 .find(|n| matches!(n.reason, zoi_core::types::InstallReason::Direct))
60 .ok_or_else(|| {
61 anyhow!("Could not find target package in resolution graph")
62 })?;
63
64 println!(
65 "{} Resolved to {} v{}",
66 "::".bold().green(),
67 node.pkg.name.cyan(),
68 node.version.yellow()
69 );
70
71 let info = if download_type == DownloadType::Source {
72 util::find_source_bundle_info(node)?.ok_or_else(|| {
73 anyhow!(
74 "No source bundle (.zsa) information found for this package \
75 in the registry."
76 )
77 })?
78 } else {
79 util::find_prebuilt_info(node)?.ok_or_else(|| {
80 anyhow!(
81 "No pre-built archive (.zpa) information found for this \
82 package in the registry."
83 )
84 })?
85 };
86
87 let filename = info
88 .final_url
89 .split('/')
90 .next_back()
91 .unwrap_or("package.archive");
92
93 let dest_path = if let Some(dir) = output_dir {
94 std::fs::create_dir_all(&dir)?;
95 dir.join(filename)
96 } else {
97 let cache_root = cache::get_archive_cache_root()?;
98 std::fs::create_dir_all(&cache_root)?;
99 cache_root.join(filename)
100 };
101
102 println!(
103 "{} Downloading to: {}",
104 "::".bold().blue(),
105 dest_path.display()
106 );
107
108 let (down_size, _) = util::get_package_sizes(
109 &node.pkg,
110 &node.registry_handle,
111 &node.version
112 );
113
114 util::download_file_with_progress(
115 &info.final_url,
116 &dest_path,
117 None,
118 Some(down_size)
119 )?;
120
121 println!(
122 "{} Successfully downloaded: {}",
123 "::".bold().green(),
124 dest_path.display()
125 );
126
127 Ok(())
128}