diff --git a/src/core/file.rs b/src/core/file.rs index 1ccdcd6..7ef918c 100644 --- a/src/core/file.rs +++ b/src/core/file.rs @@ -1,10 +1,8 @@ -use std::{ - fs::File, - io::{BufReader, Read}, -}; +use std::io::{BufReader, Read}; use super::constant::{APPIMAGE_MAGIC_BYTES, ELF_MAGIC_BYTES, FLATIMAGE_MAGIC_BYTES}; +#[derive(PartialEq, Eq)] pub enum FileType { AppImage, FlatImage, @@ -12,7 +10,10 @@ pub enum FileType { Unknown, } -pub fn get_file_type(file: &mut BufReader) -> FileType { +pub fn get_file_type(file: &mut BufReader) -> FileType +where + T: std::io::Read, +{ let mut magic_bytes = [0u8; 12]; if file.read_exact(&mut magic_bytes).is_ok() { if magic_bytes[8..] == APPIMAGE_MAGIC_BYTES { diff --git a/src/core/util.rs b/src/core/util.rs index d6fe94a..5ead3b5 100644 --- a/src/core/util.rs +++ b/src/core/util.rs @@ -1,5 +1,7 @@ use std::{ - env, mem, + env, + io::Write, + mem, path::{Path, PathBuf}, }; @@ -13,6 +15,8 @@ use tokio::{ io::{AsyncReadExt, AsyncWriteExt}, }; +use crate::warn; + use super::{ color::{Color, ColorExt}, constant::{BIN_PATH, CACHE_PATH, INSTALL_TRACK_PATH, PACKAGES_PATH, REGISTRY_PATH}, @@ -88,9 +92,12 @@ pub fn parse_size(size_str: &str) -> Option { let size_str = size_str.trim(); let units = [ ("B", 1u64), - ("KB", 1024u64), - ("MB", 1024u64 * 1024), - ("GB", 1024u64 * 1024 * 1024), + ("KB", 1000u64), + ("MB", 1000u64 * 1000), + ("GB", 1000u64 * 1000 * 1000), + ("KiB", 1024u64), + ("MiB", 1024u64 * 1024), + ("GiB", 1024u64 * 1024 * 1024), ]; for (unit, multiplier) in &units { @@ -348,3 +355,24 @@ pub fn download_progress_style(with_msg: bool) -> ProgressStyle { ) .progress_chars("━━") } + +#[derive(PartialEq, Eq)] +pub enum AskType { + Warn, + Normal, +} + +pub fn interactive_ask(ques: &str, ask_type: AskType) -> Result { + if ask_type == AskType::Warn { + warn!("{ques}"); + } else { + println!("{ques}"); + } + + std::io::stdout().flush()?; + + let mut response = String::new(); + std::io::stdin().read_line(&mut response)?; + + Ok(response.trim().to_owned()) +} diff --git a/src/package/appimage.rs b/src/package/appimage.rs index 3dcdc8a..1a5bc37 100644 --- a/src/package/appimage.rs +++ b/src/package/appimage.rs @@ -161,9 +161,9 @@ pub async fn integrate_appimage( match resolve_and_extract(&squashfs, node, &output_path, &mut HashSet::new()) { Ok(()) => { if extension == "png" { - process_icon(&output_path, &package.bin_name, data_path).await?; + process_icon(&output_path, &package.pkg_name, data_path).await?; } else { - process_desktop(&output_path, &package.bin_name, &package.name, data_path) + process_desktop(&output_path, &package.pkg_name, &package.pkg, data_path) .await?; } } @@ -315,8 +315,8 @@ pub async fn integrate_using_remote_files(package: &Package, file_path: &Path) - let desktop_content = match desktop_content { Some(content) => content, None => create_default_desktop_entry( - &package.bin_name, - &package.name, + &package.pkg_name, + &package.pkg, &package.category.replace(',', ";"), ), }; @@ -324,11 +324,11 @@ pub async fn integrate_using_remote_files(package: &Package, file_path: &Path) - fs::write(&desktop_output_path, &desktop_content).await?; try_join!( - process_icon(&icon_output_path, &package.bin_name, data_path), + process_icon(&icon_output_path, &package.pkg_name, data_path), process_desktop( &desktop_output_path, - &package.bin_name, - &package.name, + &package.pkg_name, + &package.pkg, data_path ) )?; diff --git a/src/package/install.rs b/src/package/install.rs index b54ab79..56639a4 100644 --- a/src/package/install.rs +++ b/src/package/install.rs @@ -9,7 +9,12 @@ use std::{ use anyhow::{Context, Result}; use futures::StreamExt; use indicatif::{MultiProgress, ProgressBar, ProgressStyle}; -use tokio::{fs, io::AsyncWriteExt, sync::Mutex}; +use reqwest::Url; +use tokio::{ + fs, + io::{AsyncReadExt, AsyncWriteExt}, + sync::Mutex, +}; use crate::{ core::{ @@ -19,7 +24,6 @@ use crate::{ util::{calculate_checksum, download_progress_style, validate_checksum}, }, registry::installed::InstalledPackages, - warn, }; use super::{ @@ -34,14 +38,14 @@ pub struct Installer { } impl Installer { - pub fn new(package: &ResolvedPackage, install_path: PathBuf) -> Self { + pub fn new(package: &ResolvedPackage) -> Self { let temp_path = PACKAGES_PATH .join("tmp") .join(package.package.full_name('-')) .with_extension("part"); Self { resolved_package: package.to_owned(), - install_path, + install_path: Path::new("").to_path_buf(), temp_path, } } @@ -55,7 +59,6 @@ impl Installer { portable_home: Option, portable_config: Option, multi_progress: Arc, - yes: bool, ) -> Result<()> { let package = &self.resolved_package.package; @@ -74,87 +77,15 @@ impl Installer { ))?; } - let temp_path = &self.temp_path; - let client = reqwest::Client::new(); - let downloaded_bytes = if temp_path.exists() { - let meta = fs::metadata(&temp_path).await?; - meta.len() + if Url::parse(&package.download_url).is_ok() { + self.download_remote_package(multi_progress.clone(), &prefix) + .await?; } else { - 0 - }; - - let response = client - .get(&package.download_url) - .header("Range", format!("bytes={}-", downloaded_bytes)) - .send() - .await - .context(format!("{}: Failed to download package", prefix))?; - let total_size = response - .content_length() - .map(|cl| cl + downloaded_bytes) - .unwrap_or(0); - - let download_progress = multi_progress.insert_from_back(1, ProgressBar::new(0)); - download_progress.set_style(download_progress_style(true)); - - download_progress.set_length(total_size); - download_progress.set_message(prefix.clone()); - - if !response.status().is_success() { - return Err(anyhow::anyhow!( - "{} Download failed {:?}", - prefix, - response.status().color(Color::Red), - )); - } - - { - let mut file = fs::OpenOptions::new() - .write(true) - .create(true) - .append(true) - .open(&temp_path) - .await - .context(format!("{}: Failed to open temp file for writing", prefix))?; - let mut stream = response.bytes_stream(); - - while let Some(chunk) = stream.next().await { - let chunk = chunk.context(format!("{}: Failed to read chunk", prefix))?; - file.write_all(&chunk).await?; - download_progress.inc(chunk.len() as u64); - } - download_progress.finish(); - file.flush().await?; + self.copy_local_package(multi_progress.clone(), &prefix) + .await?; } - if package.bsum == "null" { - warn!( - "Missing checksum for {}. Installing anyway.", - package.full_name('/').color(Color::BrightBlue) - ); - } else { - let result = validate_checksum(&package.bsum, &self.temp_path).await; - if result.is_err() { - if yes { - warn!("Checksum verification failed. Installing anyway."); - } else { - eprint!( - "\n{}: Checksum verification failed. Do you want to remove the package? (y/n): ", - prefix - ); - std::io::stdout().flush()?; - - let mut response = String::new(); - std::io::stdin().read_line(&mut response)?; - - if response.trim().eq_ignore_ascii_case("y") { - tokio::fs::remove_file(&temp_path).await?; - return Err(anyhow::anyhow!("Checksum verification failed.")); - } - } - } - } - let checksum = calculate_checksum(temp_path).await?; + let checksum = calculate_checksum(&self.temp_path).await?; self.install_path = package.get_install_path(&checksum); if let Some(parent) = self.install_path.parent() { @@ -171,6 +102,8 @@ impl Installer { let mut file = BufReader::new(File::open(&self.install_path)?); let file_type = get_file_type(&mut file); + let warn = multi_progress.insert(1, ProgressBar::new(0)); + warn.set_style(ProgressStyle::default_bar().template("{msg}").unwrap()); match file_type { FileType::AppImage => { if integrate_appimage(&mut file, package, &self.install_path) @@ -178,7 +111,7 @@ impl Installer { .is_ok() { setup_portable_dir( - &package.bin_name, + &package.pkg_name, &self.install_path, portable, portable_home, @@ -186,7 +119,11 @@ impl Installer { ) .await?; } else { - warn!("{}: Failed to integrate AppImage", prefix); + warn.finish_with_message(format!( + "{}: {}", + prefix, + "Failed to integrate AppImage".color(Color::BrightYellow) + )); }; } FileType::FlatImage => { @@ -195,7 +132,7 @@ impl Installer { .is_ok() { setup_portable_dir( - &package.bin_name, + &package.pkg_name, Path::new(&format!(".{}", self.install_path.display())), None, None, @@ -203,7 +140,11 @@ impl Installer { ) .await?; } else { - warn!("{}: Failed to integrate FlatImage", prefix); + warn.finish_with_message(format!( + "{}: {}", + prefix, + "Failed to integrate FlatImage".color(Color::BrightYellow) + )); }; } _ => {} @@ -217,12 +158,7 @@ impl Installer { } let installed_progress = multi_progress.insert_from_back(1, ProgressBar::new(0)); - installed_progress.set_style( - ProgressStyle::default_bar() - .template("{msg}") - .unwrap() - .progress_chars("##-"), - ); + installed_progress.set_style(ProgressStyle::default_bar().template("{msg}").unwrap()); installed_progress.finish_with_message(format!( "[{}/{}] Installed {}", (idx + 1).color(Color::Green), @@ -232,9 +168,8 @@ impl Installer { if !package.note.is_empty() { println!( - "{}: [{}] {}", + "{}: {}", prefix, - "Note".color(Color::Magenta), package .note .replace("
", "\n ") @@ -245,6 +180,124 @@ impl Installer { Ok(()) } + async fn download_remote_package( + &self, + multi_progress: Arc, + prefix: &str, + ) -> Result<()> { + let prefix = prefix.to_owned(); + let package = &self.resolved_package.package; + let temp_path = &self.temp_path; + let client = reqwest::Client::new(); + let downloaded_bytes = if temp_path.exists() { + let meta = fs::metadata(&temp_path).await?; + meta.len() + } else { + 0 + }; + + let response = client + .get(&package.download_url) + .header("Range", format!("bytes={}-", downloaded_bytes)) + .send() + .await + .context(format!("{}: Failed to download package", prefix))?; + let total_size = response + .content_length() + .map(|cl| cl + downloaded_bytes) + .unwrap_or(0); + + let download_progress = multi_progress.insert_from_back(1, ProgressBar::new(0)); + download_progress.set_style(download_progress_style(true)); + + download_progress.set_length(total_size); + download_progress.set_message(prefix.clone()); + + if !response.status().is_success() { + return Err(anyhow::anyhow!( + "{} Download failed {:?}", + prefix, + response.status().color(Color::Red), + )); + } + + let mut file = fs::OpenOptions::new() + .create(true) + .append(true) + .open(&temp_path) + .await + .context(format!("{}: Failed to open temp file for writing", prefix))?; + let mut stream = response.bytes_stream(); + + while let Some(chunk) = stream.next().await { + let chunk = chunk.context(format!("{}: Failed to read chunk", prefix))?; + file.write_all(&chunk).await?; + download_progress.inc(chunk.len() as u64); + } + download_progress.finish(); + file.flush().await?; + + let warn_bar = multi_progress.insert_from_back(1, ProgressBar::new(0)); + warn_bar.set_style(ProgressStyle::default_bar().template("{msg}").unwrap()); + if package.bsum == "null" { + warn_bar.finish_with_message(format!( + "{}: {}", + prefix, + "Missing checksum. Installing anyway.".color(Color::BrightYellow) + )); + } else { + let result = validate_checksum(&package.bsum, &self.temp_path).await; + if result.is_err() { + warn_bar.finish_with_message(format!( + "{}: {}", + prefix, + "Checksum verification failed. Installing anyway.".color(Color::BrightYellow) + )); + } + } + + Ok(()) + } + + async fn copy_local_package( + &self, + multi_progress: Arc, + prefix: &str, + ) -> Result<()> { + let temp_path = &self.temp_path; + let prefix = prefix.to_owned(); + let package = &self.resolved_package.package; + + let download_progress = multi_progress.insert_from_back(1, ProgressBar::new(0)); + download_progress.set_style(download_progress_style(true)); + + let total_size = package.size.parse::().unwrap_or_default(); + download_progress.set_length(total_size); + download_progress.set_message(prefix.clone()); + + let mut file = fs::OpenOptions::new() + .create(true) + .append(true) + .open(&temp_path) + .await + .context(format!("{}: Failed to open temp file for writing", prefix))?; + let mut source = fs::File::open(&package.download_url).await?; + let mut buffer = vec![0u8; 8096]; + + while let Ok(n) = source.read(&mut buffer).await { + if n == 0 { + break; + } + + file.write_all(&buffer[..n]).await?; + download_progress.inc(n as u64); + } + download_progress.finish(); + file.flush().await?; + + Ok(()) + } + async fn save_file(&self) -> Result<()> { let install_path = &self.install_path; let temp_path = &self.temp_path; @@ -261,36 +314,16 @@ impl Installer { async fn symlink_bin(&self) -> Result<()> { let package = &self.resolved_package.package; let install_path = &self.install_path; - let symlink_path = &BIN_PATH.join(&package.bin_name); + let symlink_path = &BIN_PATH.join(&package.pkg_name); if symlink_path.exists() { if let Ok(link) = symlink_path.read_link() { - if &link != install_path { - if let Ok(parent) = link.strip_prefix(&*PACKAGES_PATH) { - let package_name = - parent.parent().unwrap().to_string_lossy()[9..].replacen("-", "/", 1); - - if package_name == package.full_name('-') { - fs::remove_dir_all(link.parent().unwrap()).await?; - } else { - warn!( - "The package {} owns the binary {}", - package_name, &package.bin_name - ); - print!( - "Do you want to switch to {} (y/N)? ", - package.full_name('/').color(Color::Blue) - ); - std::io::stdout().flush()?; - - let mut response = String::new(); - std::io::stdin().read_line(&mut response)?; - - if !response.trim().eq_ignore_ascii_case("y") { - return Ok(()); - } - } - }; - } + if let Ok(parent) = link.strip_prefix(&*PACKAGES_PATH) { + let package_name = &parent.parent().unwrap().to_string_lossy()[9..]; + + if package_name == package.full_name('-') { + fs::remove_dir_all(link.parent().unwrap()).await?; + } + }; } fs::remove_file(symlink_path).await?; } diff --git a/src/package/mod.rs b/src/package/mod.rs index 51a0271..916c826 100644 --- a/src/package/mod.rs +++ b/src/package/mod.rs @@ -5,7 +5,10 @@ pub mod remove; pub mod run; pub mod update; -use std::{path::PathBuf, sync::Arc}; +use std::{ + path::{Path, PathBuf}, + sync::Arc, +}; use anyhow::Result; use indicatif::MultiProgress; @@ -13,12 +16,18 @@ use install::Installer; use serde::{Deserialize, Serialize}; use tokio::sync::Mutex; -use crate::{core::constant::PACKAGES_PATH, registry::installed::InstalledPackages}; +use crate::{ + core::{ + constant::PACKAGES_PATH, + util::{interactive_ask, AskType}, + }, + registry::installed::InstalledPackages, +}; #[derive(Debug, Default, Clone, Deserialize, Serialize)] pub struct Package { - pub name: String, - pub bin_name: String, + pub pkg: String, + pub pkg_name: String, pub description: String, pub note: String, pub version: String, @@ -27,14 +36,14 @@ pub struct Package { pub bsum: String, pub build_date: String, pub src_url: String, - pub web_url: String, + pub homepage: String, pub build_script: String, pub build_log: String, pub category: String, pub extra_bins: String, pub icon: String, pub desktop: Option, - pub bin_id: Option, + pub pkg_id: Option, pub family: Option, } @@ -55,10 +64,8 @@ impl ResolvedPackage { portable_home: Option, portable_config: Option, multi_progress: Arc, - yes: bool, ) -> Result<()> { - let install_path = self.package.get_install_path(&self.package.bsum[..8]); - let mut installer = Installer::new(self, install_path); + let mut installer = Installer::new(self); installer .execute( idx, @@ -68,7 +75,6 @@ impl ResolvedPackage { portable_home, portable_config, multi_progress, - yes, ) .await?; Ok(()) @@ -81,7 +87,7 @@ impl Package { } pub fn get_install_path(&self, checksum: &str) -> PathBuf { - self.get_install_dir(checksum).join(&self.bin_name) + self.get_install_dir(checksum).join(&self.pkg_name) } pub fn full_name(&self, join_char: char) -> String { @@ -90,7 +96,7 @@ impl Package { .to_owned() .map(|family| format!("{}{}", family, join_char)) .unwrap_or_default(); - format!("{}{}", family_prefix, self.name) + format!("{}{}", family_prefix, self.pkg) } } @@ -118,3 +124,24 @@ pub fn parse_package_query(query: &str) -> PackageQuery { collection, } } + +#[inline] +pub fn ask_package_info(name: &str, path: &Path, size: u64) -> Result { + let bin_name = interactive_ask("Binary Name:", AskType::Normal)?; + + let package = Package { + pkg: name.to_owned(), + pkg_name: bin_name, + size: size.to_string(), + download_url: path.to_string_lossy().to_string(), + ..Default::default() + }; + + let resolved_package = ResolvedPackage { + repo_name: "local".to_owned(), + collection: "local".to_string(), + package, + }; + + Ok(resolved_package) +} diff --git a/src/package/update.rs b/src/package/update.rs index 20056df..d0cba21 100644 --- a/src/package/update.rs +++ b/src/package/update.rs @@ -91,7 +91,6 @@ impl Updater { None, None, multi_progress.clone(), - true, ) .await?; update_count += 1; diff --git a/src/registry/fetcher.rs b/src/registry/fetcher.rs index d65df2d..80cfe16 100644 --- a/src/registry/fetcher.rs +++ b/src/registry/fetcher.rs @@ -49,7 +49,7 @@ impl MetadataFetcher { .map(|(key, packages)| { let package_map: HashMap> = packages.iter().fold(HashMap::new(), |mut acc, package| { - acc.entry(package.name.clone()).or_default().push(Package { + acc.entry(package.pkg.clone()).or_default().push(Package { family: package .download_url .split('/') diff --git a/src/registry/installed.rs b/src/registry/installed.rs index 50e0daa..9cdf7d3 100644 --- a/src/registry/installed.rs +++ b/src/registry/installed.rs @@ -91,9 +91,9 @@ impl InstalledPackages { let new_installed = InstalledPackage { repo_name: resolved_package.repo_name.to_owned(), collection: resolved_package.collection.to_string().to_owned(), - name: package.name, + name: package.pkg, family: package.family, - bin_name: package.bin_name, + bin_name: package.pkg_name, version: package.version, checksum: checksum.to_owned(), size: parse_size(&package.size).unwrap_or_default(), diff --git a/src/registry/mod.rs b/src/registry/mod.rs index 5f98b0f..08a88ad 100644 --- a/src/registry/mod.rs +++ b/src/registry/mod.rs @@ -151,7 +151,7 @@ impl PackageRegistry { let formatted_name = format!( "{} ({}#{})", - package.bin_name.clone().color(Color::BrightGreen), + package.pkg_name.clone().color(Color::BrightGreen), package.clone().full_name('/').color(Color::BrightCyan), pkg.collection.clone().color(Color::BrightRed) ); @@ -161,7 +161,10 @@ impl PackageRegistry { "Description", package.description.clone().color(Color::BrightYellow), ), - ("Homepage", package.web_url.clone().color(Color::BrightBlue)), + ( + "Homepage", + package.homepage.clone().color(Color::BrightBlue), + ), ("Source", package.src_url.clone().color(Color::BrightBlue)), ( "Version", @@ -278,7 +281,7 @@ impl PackageRegistry { install_prefix.color(Color::Red), resolved_package.collection.color(Color::BrightGreen), package.full_name('/').color(Color::Blue), - package.name.color(Color::Blue), + package.pkg.color(Color::Blue), package.version.color(Color::Green), package.size.color(Color::Magenta) ); @@ -335,7 +338,7 @@ impl PackageRegistry { pub fn select_single_package(packages: &[ResolvedPackage]) -> Result<&ResolvedPackage> { info!( "Multiple packages available for {}", - packages[0].package.name.clone().color(Color::Blue) + packages[0].package.pkg.clone().color(Color::Blue) ); for (i, package) in packages.iter().enumerate() { println!( diff --git a/src/registry/storage.rs b/src/registry/storage.rs index a7d6e55..ba1b965 100644 --- a/src/registry/storage.rs +++ b/src/registry/storage.rs @@ -1,6 +1,7 @@ use std::{ collections::HashMap, - io::Write, + fs::File, + io::BufReader, sync::{ atomic::{AtomicU64, Ordering}, Arc, @@ -21,10 +22,13 @@ use crate::{ color::{Color, ColorExt}, config::CONFIG, constant::CACHE_PATH, - util::format_bytes, + file::{get_file_type, FileType}, + util::{build_path, format_bytes, interactive_ask, AskType}, }, error, - package::{parse_package_query, run::Runner, Package, PackageQuery, ResolvedPackage}, + package::{ + ask_package_info, parse_package_query, run::Runner, Package, PackageQuery, ResolvedPackage, + }, registry::installed::InstalledPackages, warn, }; @@ -80,7 +84,30 @@ impl PackageStorage { ) -> Result<()> { let resolved_packages: Result> = package_names .iter() - .map(|package_name| self.resolve_package(package_name, yes)) + .map(|package_name| { + if let Ok(package) = self.resolve_package(package_name, yes) { + Ok(package) + } else { + // check if a local package is provided instead + let package_path = build_path(package_name)?; + if package_path.is_file() { + let realpath = if package_path.is_symlink() { + package_path.read_link()? + } else { + package_path + }; + let file = File::open(&realpath)?; + let mut buf_reader = BufReader::new(&file); + if get_file_type(&mut buf_reader) != FileType::Unknown { + let package_name = realpath.file_name().unwrap().to_string_lossy(); + let size = file.metadata()?.len(); + let package = ask_package_info(&package_name, &realpath, size)?; + return Ok(package); + }; + }; + Err(anyhow::anyhow!("Package {} not found.", package_name)) + } + }) .collect(); let resolved_packages = resolved_packages?; @@ -150,7 +177,6 @@ impl PackageStorage { portable_home, portable_config, multi_progress, - yes, ) .await { @@ -179,7 +205,6 @@ impl PackageStorage { portable_home.clone(), portable_config.clone(), multi_progress.clone(), - yes, ) .await { @@ -300,7 +325,7 @@ impl PackageStorage { .flat_map(|(collection_key, map)| { map.get(pkg_name).into_iter().flat_map(|pkgs| { pkgs.iter().filter_map(|pkg| { - if pkg.name == pkg_name + if pkg.pkg == pkg_name && (query.family.is_none() || pkg.family.as_ref() == query.family.as_ref()) { @@ -342,9 +367,9 @@ impl PackageStorage { packages.iter().filter_map(|pkg| { let mut score = 0; let found_pkg_name = if case_sensitive { - pkg.name.clone() + pkg.pkg.clone() } else { - pkg.name.to_lowercase() + pkg.pkg.to_lowercase() }; if found_pkg_name == pkg_name { @@ -418,16 +443,11 @@ impl PackageStorage { let content_length = response.content_length().unwrap_or_default(); if content_length > 1_048_576 { - warn!( + let response = interactive_ask(&format!( "The build {} file is too large ({}). Do you really want to download and view it (y/N)? ", inspect_type, format_bytes(content_length).color(Color::Magenta) - ); - - std::io::stdout().flush()?; - let mut response = String::new(); - - std::io::stdin().read_line(&mut response)?; + ), AskType::Warn)?; if !response.trim().eq_ignore_ascii_case("y") { return Err(anyhow::anyhow!("")); @@ -465,13 +485,13 @@ impl PackageStorage { &[] }; let runner = if let Ok(resolved_pkg) = self.resolve_package(package_name, yes) { - let package_path = CACHE_PATH.join(&resolved_pkg.package.bin_name); + let package_path = CACHE_PATH.join(&resolved_pkg.package.pkg_name); Runner::new(&resolved_pkg, package_path, args) } else { let query = parse_package_query(package_name); let package_path = CACHE_PATH.join(&query.name); let mut resolved_pkg = ResolvedPackage::default(); - resolved_pkg.package.name = query.name; + resolved_pkg.package.pkg = query.name; resolved_pkg.package.family = query.family; // TODO: check all the repo for package instead of choosing the first