diff --git a/Cargo.lock b/Cargo.lock index 4ac3ae5..ad1628d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2702,7 +2702,6 @@ name = "pesde" version = "0.5.0-dev.0" dependencies = [ "anyhow", - "cfg-if", "chrono", "clap", "colored", diff --git a/Cargo.toml b/Cargo.toml index bdad770..1b79c87 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,8 +10,8 @@ repository = "https://github.com/daimond113/pesde" include = ["src/**/*", "Cargo.toml", "Cargo.lock", "README.md", "LICENSE", "CHANGELOG.md"] [features] -bin = ["clap", "directories", "pretty_env_logger", "reqwest/json", "reqwest/multipart", "indicatif", "indicatif-log-bridge", "inquire", "toml_edit", "colored", "anyhow", "keyring", "open", "gix/worktree-mutation"] -wally-compat = ["zip", "roblox"] +bin = ["clap", "directories", "pretty_env_logger", "reqwest/json", "reqwest/multipart", "indicatif", "indicatif-log-bridge", "inquire", "toml_edit", "colored", "anyhow", "keyring", "open", "gix/worktree-mutation", "serde_json"] +wally-compat = ["zip", "serde_json", "roblox"] roblox = [] lune = [] luau = [] @@ -28,7 +28,6 @@ uninlined_format_args = "warn" [dependencies] serde = { version = "1.0.204", features = ["derive"] } toml = "0.8.15" -serde_json = "1.0.120" serde_with = "3.9.0" gix = { version = "0.64.0", default-features = false, features = ["blocking-http-transport-reqwest-rust-tls", "revparse-regex", "credentials"] } semver = { version = "1.0.23", features = ["serde"] } @@ -42,7 +41,6 @@ thiserror = "1.0.63" threadpool = "1.8.1" full_moon = { version = "1.0.0-rc.5", features = ["luau"] } url = { version = "2.5.2", features = ["serde"] } -cfg-if = "1.0.0" # TODO: reevaluate whether to use this # secrecy = "0.8.0" chrono = { version = "0.4.38", features = ["serde"] } @@ -51,6 +49,7 @@ chrono = { version = "0.4.38", features = ["serde"] } git2 = { version = "0.19.0", optional = true } zip = { version = "2.1.5", optional = true } +serde_json = { version = "1.0.120", optional = true } anyhow = { version = "1.0.86", optional = true } open = { version = "5.3.0", optional = true } diff --git a/src/cli/auth/login.rs b/src/cli/auth/login.rs index 7c10e0b..3bddb52 100644 --- a/src/cli/auth/login.rs +++ b/src/cli/auth/login.rs @@ -61,8 +61,8 @@ impl LoginCommand { }, }; - let index_url = match &self.index { - Some(index) => match index.parse() { + let index_url = match self.index.as_deref() { + Some(index) => match index.try_into() { Ok(url) => Some(url), Err(_) => None, }, @@ -84,12 +84,7 @@ impl LoginCommand { } }; - let source = PesdePackageSource::new( - index_url - .as_str() - .try_into() - .context("cannot parse URL to git URL")?, - ); + let source = PesdePackageSource::new(index_url); source.refresh(project).context("failed to refresh index")?; let config = source diff --git a/src/cli/config/default_index.rs b/src/cli/config/default_index.rs index 9b3483c..65de195 100644 --- a/src/cli/config/default_index.rs +++ b/src/cli/config/default_index.rs @@ -5,8 +5,8 @@ use pesde::Project; #[derive(Debug, Args)] pub struct DefaultIndexCommand { /// The new index URL to set as default, don't pass any value to check the current default index - #[arg(index = 1)] - index: Option, + #[arg(index = 1, value_parser = crate::cli::parse_gix_url)] + index: Option, /// Resets the default index to the default value #[arg(short, long, conflicts_with = "index")] diff --git a/src/cli/config/scripts_repo.rs b/src/cli/config/scripts_repo.rs index 320cb83..5a88f46 100644 --- a/src/cli/config/scripts_repo.rs +++ b/src/cli/config/scripts_repo.rs @@ -5,8 +5,8 @@ use pesde::Project; #[derive(Debug, Args)] pub struct ScriptsRepoCommand { /// The new repo URL to set as default, don't pass any value to check the current default repo - #[arg(index = 1)] - repo: Option, + #[arg(index = 1, value_parser = crate::cli::parse_gix_url)] + repo: Option, /// Resets the default repo to the default value #[arg(short, long, conflicts_with = "repo")] diff --git a/src/cli/init.rs b/src/cli/init.rs index 561a41c..836bd50 100644 --- a/src/cli/init.rs +++ b/src/cli/init.rs @@ -144,8 +144,12 @@ impl InitCommand { )); } - manifest["indices"][DEFAULT_INDEX_NAME] = - toml_edit::value(read_config(project.data_dir())?.default_index.as_str()); + manifest["indices"][DEFAULT_INDEX_NAME] = toml_edit::value( + read_config(project.data_dir())? + .default_index + .to_bstring() + .to_string(), + ); project.write_manifest(manifest.to_string())?; diff --git a/src/cli/install.rs b/src/cli/install.rs index 91af59f..e23cf39 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -7,9 +7,9 @@ use std::{collections::HashSet, sync::Arc, time::Duration}; #[derive(Debug, Args)] pub struct InstallCommand { - /// The amount of threads to use for downloading, defaults to 6 - #[arg(short, long)] - threads: Option, + /// The amount of threads to use for downloading + #[arg(short, long, default_value_t = 6, value_parser = clap::value_parser!(u64).range(1..=128))] + threads: u64, } impl InstallCommand { @@ -92,7 +92,7 @@ impl InstallCommand { &graph, &mut refreshed_sources, &reqwest_client(project.data_dir())?, - self.threads.unwrap_or(6).max(1), + self.threads as usize, ) .context("failed to download dependencies")?; diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 9b35d89..64bbb6f 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -21,8 +21,16 @@ mod self_install; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct CliConfig { - pub default_index: url::Url, - pub scripts_repo: url::Url, + #[serde( + serialize_with = "crate::util::serialize_gix_url", + deserialize_with = "crate::util::deserialize_gix_url" + )] + pub default_index: gix::Url, + #[serde( + serialize_with = "crate::util::serialize_gix_url", + deserialize_with = "crate::util::deserialize_gix_url" + )] + pub scripts_repo: gix::Url, #[serde(default, skip_serializing_if = "Option::is_none")] pub token: Option, } @@ -30,9 +38,11 @@ pub struct CliConfig { impl Default for CliConfig { fn default() -> Self { Self { - default_index: "https://github.com/daimond113/pesde-index".parse().unwrap(), + default_index: "https://github.com/daimond113/pesde-index" + .try_into() + .unwrap(), scripts_repo: "https://github.com/daimond113/pesde-scripts" - .parse() + .try_into() .unwrap(), token: None, } @@ -221,7 +231,7 @@ pub fn update_scripts_folder(project: &Project) -> anyhow::Result<()> { let cli_config = read_config(project.data_dir())?; - gix::prepare_clone(cli_config.scripts_repo.as_str(), &scripts_dir) + gix::prepare_clone(cli_config.scripts_repo, &scripts_dir) .context("failed to prepare scripts repository clone")? .fetch_then_checkout(gix::progress::Discard, &false.into()) .context("failed to fetch and checkout scripts repository")? @@ -333,6 +343,10 @@ impl VersionedPackageName { } } +pub fn parse_gix_url(s: &str) -> Result { + s.try_into() +} + #[derive(Debug, clap::Subcommand)] pub enum Subcommand { /// Authentication-related commands diff --git a/src/manifest/mod.rs b/src/manifest/mod.rs index 56c4dc8..371a549 100644 --- a/src/manifest/mod.rs +++ b/src/manifest/mod.rs @@ -30,11 +30,20 @@ pub struct Manifest { pub private: bool, #[serde(default, skip_serializing)] pub scripts: BTreeMap, - #[serde(default)] - pub indices: BTreeMap, + #[serde( + default, + serialize_with = "crate::util::serialize_gix_url_map", + deserialize_with = "crate::util::deserialize_gix_url_map" + )] + pub indices: BTreeMap, #[cfg(feature = "wally-compat")] - #[serde(default, skip_serializing_if = "BTreeMap::is_empty")] - pub wally_indices: BTreeMap, + #[serde( + default, + skip_serializing_if = "BTreeMap::is_empty", + serialize_with = "crate::util::serialize_gix_url_map", + deserialize_with = "crate::util::deserialize_gix_url_map" + )] + pub wally_indices: BTreeMap, #[serde(default, skip_serializing)] pub overrides: BTreeMap, #[serde(default)] diff --git a/src/resolver.rs b/src/resolver.rs index a503ce4..b535f3e 100644 --- a/src/resolver.rs +++ b/src/resolver.rs @@ -128,26 +128,22 @@ impl Project { DependencySpecifiers::Pesde(specifier) => { let index_url = if depth == 0 || overridden { let index_name = specifier.index.as_deref().unwrap_or(DEFAULT_INDEX_NAME); - let index_url = manifest.indices.get(index_name).ok_or( - errors::DependencyGraphError::IndexNotFound(index_name.to_string()), - )?; - match index_url.as_str().try_into() { - Ok(url) => url, - Err(e) => { - return Err(Box::new(errors::DependencyGraphError::UrlParse( - index_url.clone(), - e, - ))) - } - } + manifest + .indices + .get(index_name) + .ok_or(errors::DependencyGraphError::IndexNotFound( + index_name.to_string(), + ))? + .clone() } else { let index_url = specifier.index.clone().unwrap(); index_url .clone() .try_into() - .map_err(|e| errors::DependencyGraphError::InvalidIndex(index_url, e))? + // specifiers in indices store the index url in this field + .unwrap() }; PackageSources::Pesde(PesdePackageSource::new(index_url)) @@ -309,12 +305,6 @@ pub mod errors { #[error("index named {0} not found in manifest")] IndexNotFound(String), - #[error("error parsing url {0} into git url")] - UrlParse(url::Url, #[source] gix::url::parse::Error), - - #[error("index {0} cannot be parsed as a git url")] - InvalidIndex(String, #[source] gix::url::parse::Error), - #[error("error refreshing package source")] Refresh(#[from] crate::source::errors::RefreshError), diff --git a/src/util.rs b/src/util.rs index fe93afb..594ba00 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,6 +1,7 @@ use crate::AuthConfig; use gix::bstr::BStr; -use serde::{Deserialize, Deserializer, Serializer}; +use serde::{ser::SerializeMap, Deserialize, Deserializer, Serializer}; +use std::collections::BTreeMap; pub fn authenticate_conn( conn: &mut gix::remote::Connection< @@ -28,9 +29,33 @@ pub fn serialize_gix_url(url: &gix::Url, serializer: S) -> Result serializer.serialize_str(&url.to_bstring().to_string()) } +pub fn serialize_gix_url_map( + url: &BTreeMap, + serializer: S, +) -> Result { + let mut map = serializer.serialize_map(Some(url.len()))?; + for (k, v) in url { + map.serialize_entry(k, &v.to_bstring().to_string())?; + } + map.end() +} + pub fn deserialize_gix_url<'de, D: Deserializer<'de>>( deserializer: D, ) -> Result { let s = String::deserialize(deserializer)?; gix::Url::from_bytes(BStr::new(&s)).map_err(serde::de::Error::custom) } + +pub fn deserialize_gix_url_map<'de, D: Deserializer<'de>>( + deserializer: D, +) -> Result, D::Error> { + BTreeMap::::deserialize(deserializer)? + .into_iter() + .map(|(k, v)| { + gix::Url::from_bytes(BStr::new(&v)) + .map(|v| (k, v)) + .map_err(serde::de::Error::custom) + }) + .collect() +}