From ea196fe916dd95b33a015f3b396eaf34f917695a Mon Sep 17 00:00:00 2001 From: beeb <703631+beeb@users.noreply.github.com> Date: Thu, 22 Aug 2024 08:27:21 +0200 Subject: [PATCH] refactor: url helper --- Cargo.lock | 11 +++++++++++ Cargo.toml | 1 + src/auth.rs | 6 +++--- src/push.rs | 4 ++-- src/registry.rs | 27 ++++++++++----------------- src/utils.rs | 46 +++++++++++++++++++++++++--------------------- 6 files changed, 52 insertions(+), 43 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0d6b61e..63a0a1a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1802,6 +1802,7 @@ dependencies = [ "serial_test", "sha2", "simple-home-dir", + "temp-env", "thiserror", "tokio", "toml_edit", @@ -1849,6 +1850,16 @@ dependencies = [ "futures-core", ] +[[package]] +name = "temp-env" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96374855068f47402c3121c6eed88d29cb1de8f3ab27090e273e420bdabcf050" +dependencies = [ + "futures", + "parking_lot", +] + [[package]] name = "textwrap" version = "0.16.1" diff --git a/Cargo.toml b/Cargo.toml index eee06a2..3178476 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -56,6 +56,7 @@ env_logger = "0.11.3" mockito = "1.4.0" rand = "0.8.5" serial_test = "3.1.1" +temp-env = { version = "0.3.6", features = ["async_closure"] } [lib] name = "soldeer" diff --git a/src/auth.rs b/src/auth.rs index ef6e386..9dabb12 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -1,6 +1,6 @@ use crate::{ errors::AuthError, - utils::{get_base_url, security_file_path}, + utils::{api_url, security_file_path}, }; use cliclack::log::{info, remark, success}; use email_address_parser::{EmailAddress, ParsingOptions}; @@ -55,9 +55,9 @@ pub fn get_token() -> Result { async fn execute_login(login: &Login) -> Result<()> { let security_file = security_file_path()?; - let url = format!("{}/api/v1/auth/login", get_base_url()); + let url = api_url("auth/login", &[]); let client = Client::new(); - let res = client.post(&url).json(login).send().await?; + let res = client.post(url).json(login).send().await?; match res.status() { s if s.is_success() => { success("Login successful")?; diff --git a/src/push.rs b/src/push.rs index 3ebefa4..7eca4bc 100644 --- a/src/push.rs +++ b/src/push.rs @@ -2,7 +2,7 @@ use crate::{ auth::get_token, errors::{AuthError, PublishError}, registry::get_project_id, - utils::{get_base_url, read_file}, + utils::{api_url, read_file}, }; use cliclack::log::{info, remark, success}; use ignore::{WalkBuilder, WalkState}; @@ -147,7 +147,7 @@ async fn push_to_repo( let token = get_token()?; let client = Client::new(); - let url = format!("{}/api/v1/revision/upload", get_base_url()); + let url = api_url("revision/upload", &[]); let mut headers: HeaderMap = HeaderMap::new(); diff --git a/src/registry.rs b/src/registry.rs index a3bbf21..f7cdf05 100644 --- a/src/registry.rs +++ b/src/registry.rs @@ -1,7 +1,7 @@ use crate::{ config::{Dependency, HttpDependency}, errors::RegistryError, - utils::get_base_url, + utils::api_url, }; use chrono::{DateTime, Utc}; use semver::{Version, VersionReq}; @@ -49,12 +49,9 @@ pub struct ProjectResponse { } pub async fn get_dependency_url_remote(dependency: &Dependency, version: &str) -> Result { - let url = format!( - "{}/api/v1/revision-cli?project_name={}&revision={}", - get_base_url(), - dependency.name(), - version - ); + let url = + api_url("revision-cli", &[("project_name", dependency.name()), ("revision", version)]); + let res = reqwest::get(url).await?; let res = res.error_for_status()?; let revision: RevisionResponse = res.json().await?; @@ -65,7 +62,7 @@ pub async fn get_dependency_url_remote(dependency: &Dependency, version: &str) - } pub async fn get_project_id(dependency_name: &str) -> Result { - let url = format!("{}/api/v1/project?project_name={}", get_base_url(), dependency_name); + let url = api_url("project", &[("project_name", dependency_name)]); let res = reqwest::get(url).await?; let res = res.error_for_status()?; let project: ProjectResponse = res.json().await?; @@ -77,11 +74,8 @@ pub async fn get_project_id(dependency_name: &str) -> Result { pub async fn get_latest_forge_std() -> Result { let dependency_name = "forge-std"; - let url = format!( - "{}/api/v1/revision?project_name={}&offset=0&limit=1", - get_base_url(), - dependency_name - ); + let url = + api_url("revision", &[("project_name", dependency_name), ("offset", "0"), ("limit", "1")]); let res = reqwest::get(url).await?; let res = res.error_for_status()?; let revision: RevisionResponse = res.json().await?; @@ -106,10 +100,9 @@ pub enum Versions { pub async fn get_all_versions_descending(dependency_name: &str) -> Result { // TODO: provide a more efficient endpoint which already sorts by descending semver if possible // and only returns the version strings - let url = format!( - "{}/api/v1/revision?project_name={}&offset=0&limit=10000", - get_base_url(), - dependency_name + let url = api_url( + "revision", + &[("project_name", dependency_name), ("offset", "0"), ("limit", "10000")], ); let res = reqwest::get(url).await?; let res = res.error_for_status()?; diff --git a/src/utils.rs b/src/utils.rs index 2d89fa6..1959783 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -5,9 +5,11 @@ use crate::{ use ignore::{WalkBuilder, WalkState}; use once_cell::sync::Lazy; use regex::Regex; +use reqwest::Url; use sha2::{Digest, Sha256}; use simple_home_dir::home_dir; use std::{ + borrow::Cow, env, ffi::OsStr, fs, @@ -25,6 +27,17 @@ static GIT_SSH_REGEX: Lazy = Lazy::new(|| { Regex::new(r"^(?:git@github\.com|git@gitlab)").expect("git ssh regex should compile") }); +pub static API_BASE_URL: Lazy = Lazy::new(|| { + let url = env::var("SOLDEER_API_URL").unwrap_or("https://api.soldeer.xyz".to_string()); + Url::parse(&url).expect("SOLDEER_API_URL is invalid") +}); + +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum UrlType { + Git, + Http, +} + /// Get the current working directory pub fn get_current_working_dir() -> PathBuf { env::current_dir().expect("could not get current working directory") @@ -52,15 +65,9 @@ pub fn read_file(path: impl AsRef) -> Result, std::io::Error> { /// setting the `SOLDEER_LOGIN_FILE` environment variable. /// For login, the custom path will only be used if the file already exists. pub fn security_file_path() -> Result { - let custom_security_file = if cfg!(test) { - return Ok(PathBuf::from("./test_save_jwt")); - } else { - env::var("SOLDEER_LOGIN_FILE").ok() - }; - - if let Some(file) = custom_security_file { - if !file.is_empty() && Path::new(&file).exists() { - return Ok(file.into()); + if let Ok(file_path) = env::var("SOLDEER_LOGIN_FILE") { + if !file_path.is_empty() && Path::new(&file_path).exists() { + return Ok(file_path.into()); } } @@ -74,12 +81,11 @@ pub fn security_file_path() -> Result { Ok(security_file) } -pub fn get_base_url() -> String { - if cfg!(test) { - env::var("base_url").unwrap_or("http://0.0.0.0".to_string()) - } else { - "https://api.soldeer.xyz".to_string() - } +pub fn api_url(path: &str, params: &[(&str, &str)]) -> Url { + let mut url = API_BASE_URL.clone(); + url.set_path(&format!("api/v1/{path}")); + url.query_pairs_mut().extend_pairs(params.iter()); + url } /// Check if any file starts with a period @@ -87,12 +93,6 @@ pub fn check_dotfiles(files: &[PathBuf]) -> bool { files.iter().any(|file| file.file_name().unwrap_or_default().to_string_lossy().starts_with('.')) } -#[derive(Debug, Clone, Copy, PartialEq)] -pub enum UrlType { - Git, - Http, -} - pub fn get_url_type(dependency_url: &str) -> Result { if GIT_SSH_REGEX.is_match(dependency_url) { return Ok(UrlType::Git); @@ -262,6 +262,10 @@ where Ok(String::from_utf8(forge.stdout).expect("forge command output should be valid utf-8")) } +fn get_api_base_url() -> String { + env::var("SOLDEER_API_URL").unwrap_or("https://api.soldeer.xyz".to_string()) +} + #[cfg(test)] mod tests { use rand::{distributions::Alphanumeric, Rng as _};