Untitled
unknown
rust
a year ago
3.2 kB
2
Indexable
Never
use reqwest; use reqwest::Client; use semver_rs::{Range, Version}; use serde::{Deserialize, Serialize}; use serde_json::Value; use std::collections::HashMap; mod error; use error::CustomError; pub type Result<T> = std::result::Result<T, CustomError>; use anyhow::anyhow; use std::collections::HashSet; use std::collections::VecDeque; use std::sync::Arc; #[macro_use] extern crate time_test; use tokio::sync::Mutex; #[derive(Serialize, Deserialize, Debug, Clone)] pub struct PackageVersion { pub versions: Value, } #[derive(Serialize, Deserialize, Debug, Clone)] pub struct PackageDependencies { pub dependencies: Option<HashMap<String, String>>, } pub async fn resolve_dependency( client: Client, dependencies: HashMap<String, String>, ) -> Result<()> { let context: Arc<Mutex<HashSet<String>>> = Arc::new(Mutex::new(HashSet::new())); let queue: Arc<Mutex<VecDeque<(String, String)>>> = Arc::new(Mutex::new(VecDeque::new())); for (p, v) in dependencies { queue.lock().await.push_back((p, v)); } loop { if !queue.lock().await.is_empty() { let (package, version) = queue.lock().await.pop_front().unwrap(); let queue = queue.clone(); let context = context.clone(); let client = client.clone(); tokio::spawn(async move { let mut queue = queue.lock().await; println!("{} {}", package, version); let mut available_versions = Vec::new(); let range: Range = Range::new(&version).parse().unwrap(); let package_url = format!("https://registry.npmjs.org/{}", package); let resp = client.get(package_url).send().await.unwrap(); let version_info: PackageVersion = resp.json().await.unwrap(); for key in version_info.versions.as_object().unwrap().keys() { let version = Version::new(key).parse().unwrap(); if range.test(&version) { available_versions.push(version); } } let target = match available_versions.iter().max() { Some(version) => version.to_string(), None => return Err(CustomError::Other(anyhow!("version missing"))), }; let ident = format!("{}+{}", package, target); let mut context = context.lock().await; if context.get(&ident).is_none() { context.insert(ident); let package_version_url = format!("https://registry.npmjs.org/{}/{}", package, version); let resp = client.get(package_version_url).send().await?; let dependency_info: PackageDependencies = resp.json().await?; if let Some(dependencies) = dependency_info.dependencies { for (p, v) in dependencies { queue.push_back((p, v)); } } } Ok(()) }); } } println!("{:?}", context); Ok(()) }