refactor: use iteration over recursion

Replaces the recursive implementation of fallback
Wally registries with an iterative approach.
This commit is contained in:
daimond113 2025-02-02 14:06:38 +01:00
parent 6856746ae2
commit f0e69a08e2
No known key found for this signature in database
GPG key ID: 640DC95EC1190354
3 changed files with 101 additions and 98 deletions

View file

@ -306,7 +306,7 @@ impl PruneCommand {
if removed_hashes.contains(&hash) { if removed_hashes.contains(&hash) {
let cas_dir = project.cas_dir().to_path_buf(); let cas_dir = project.cas_dir().to_path_buf();
tasks.spawn(async move { tasks.spawn(async move {
fs::remove_file(dbg!(&path)) fs::remove_file(&path)
.await .await
.context("failed to remove unused file")?; .context("failed to remove unused file")?;

View file

@ -466,8 +466,7 @@ pub struct IndexFileEntry {
/// The target for this package /// The target for this package
pub target: Target, pub target: Target,
/// When this package was published /// When this package was published
#[serde(default = "chrono::Utc::now")] pub published_at: jiff::Timestamp,
pub published_at: chrono::DateTime<chrono::Utc>,
/// The engines this package supports /// The engines this package supports
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")] #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
pub engines: BTreeMap<EngineKind, VersionReq>, pub engines: BTreeMap<EngineKind, VersionReq>,

View file

@ -1,6 +1,6 @@
use crate::{ use crate::{
manifest::target::{Target, TargetKind}, manifest::target::{Target, TargetKind},
names::PackageNames, names::{wally::WallyPackageName, PackageNames},
reporters::{response_to_async_read, DownloadProgressReporter}, reporters::{response_to_async_read, DownloadProgressReporter},
source::{ source::{
fs::{store_in_cas, FsEntry, PackageFs}, fs::{store_in_cas, FsEntry, PackageFs},
@ -84,6 +84,26 @@ impl WallyPackageSource {
.await .await
.unwrap() .unwrap()
} }
pub(crate) async fn read_index_file(
&self,
project: &Project,
name: &WallyPackageName,
) -> Result<Option<String>, errors::ResolveError> {
let path = self.path(project);
let pkg_name = name.clone();
spawn_blocking(move || {
let repo = gix::open(&path).map_err(Box::new)?;
let tree = root_tree(&repo).map_err(Box::new)?;
let (scope, name) = pkg_name.as_str();
read_file(&tree, [scope, name])
.map_err(|e| errors::ResolveError::Read(pkg_name.to_string(), Box::new(e)))
})
.await
.unwrap()
}
} }
impl PackageSource for WallyPackageSource { impl PackageSource for WallyPackageSource {
@ -105,110 +125,94 @@ impl PackageSource for WallyPackageSource {
specifier: &Self::Specifier, specifier: &Self::Specifier,
options: &ResolveOptions, options: &ResolveOptions,
) -> Result<ResolveResult<Self::Ref>, Self::ResolveError> { ) -> Result<ResolveResult<Self::Ref>, Self::ResolveError> {
async fn inner( let ResolveOptions {
source: &WallyPackageSource, project,
specifier: &specifier::WallyDependencySpecifier, refreshed_sources,
options: &ResolveOptions, ..
) -> Result<ResolveResult<WallyPackageRef>, errors::ResolveError> { } = options;
let ResolveOptions {
project,
refreshed_sources,
..
} = options;
let Some(string) = ({ let mut string = self.read_index_file(project, &specifier.name).await?;
let repo = gix::open(source.path(project)).map_err(Box::new)?; let mut index_url = self.repo_url.clone();
let tree = root_tree(&repo).map_err(Box::new)?;
let (scope, name) = specifier.name.as_str();
match read_file(&tree, [scope, name]) {
Ok(string) => string,
Err(e) => {
return Err(errors::ResolveError::Read(
specifier.name.to_string(),
Box::new(e),
))
}
}
}) else {
tracing::debug!(
"{} not found in wally registry. searching in backup registries",
specifier.name
);
let config = source.config(project).await.map_err(Box::new)?;
for registry in config.fallback_registries {
let source = WallyPackageSource::new(registry);
match refreshed_sources
.refresh(
&PackageSources::Wally(source.clone()),
&RefreshOptions {
project: project.clone(),
},
)
.await
{
Ok(()) => {}
Err(super::errors::RefreshError::Wally(e)) => {
return Err(errors::ResolveError::Refresh(Box::new(e)));
}
Err(e) => panic!("unexpected error: {e:?}"),
}
match Box::pin(inner(&source, specifier, options)).await { if string.is_none() {
Ok((name, results)) => { tracing::debug!(
tracing::debug!("found {name} in backup registry {}", source.repo_url); "{} not found in Wally registry. searching in backup registries",
return Ok((name, results)); specifier.name
} );
Err(errors::ResolveError::NotFound(_)) => { let config = self.config(project).await.map_err(Box::new)?;
continue;
} for url in config.fallback_registries {
Err(e) => { let source = WallyPackageSource::new(url);
return Err(e);
} match refreshed_sources
.refresh(
&PackageSources::Wally(source.clone()),
&RefreshOptions {
project: project.clone(),
},
)
.await
{
Ok(()) => {}
Err(super::errors::RefreshError::Wally(e)) => {
return Err(errors::ResolveError::Refresh(Box::new(e)));
} }
Err(e) => panic!("unexpected error: {e:?}"),
} }
return Err(errors::ResolveError::NotFound(specifier.name.to_string())); match source.read_index_file(project, &specifier.name).await {
}; Ok(Some(res)) => {
string = Some(res);
index_url = source.repo_url;
break;
}
Ok(None) => {
tracing::debug!("{} not found in {}", specifier.name, source.repo_url);
continue;
}
Err(e) => return Err(e),
}
}
};
let entries: Vec<WallyManifest> = string let Some(string) = string else {
.lines() return Err(errors::ResolveError::NotFound(specifier.name.to_string()));
.map(serde_json::from_str) };
.collect::<Result<_, _>>()
.map_err(|e| errors::ResolveError::Parse(specifier.name.to_string(), e))?;
tracing::debug!("{} has {} possible entries", specifier.name, entries.len()); let entries: Vec<WallyManifest> = string
.lines()
.map(serde_json::from_str)
.collect::<Result<_, _>>()
.map_err(|e| errors::ResolveError::Parse(specifier.name.to_string(), e))?;
Ok(( tracing::debug!("{} has {} possible entries", specifier.name, entries.len());
PackageNames::Wally(specifier.name.clone()),
entries
.into_iter()
.filter(|manifest| {
version_matches(&specifier.version, &manifest.package.version)
})
.map(|manifest| {
let dependencies = manifest.all_dependencies().map_err(|e| {
errors::ResolveError::AllDependencies(specifier.to_string(), e)
})?;
Ok(( Ok((
VersionId( PackageNames::Wally(specifier.name.clone()),
manifest.package.version, entries
match manifest.package.realm { .into_iter()
Realm::Server => TargetKind::RobloxServer, .filter(|manifest| version_matches(&specifier.version, &manifest.package.version))
_ => TargetKind::Roblox, .map(|manifest| {
}, let dependencies = manifest.all_dependencies().map_err(|e| {
), errors::ResolveError::AllDependencies(specifier.to_string(), e)
WallyPackageRef { })?;
index_url: source.repo_url.clone(),
dependencies, Ok((
VersionId(
manifest.package.version,
match manifest.package.realm {
Realm::Server => TargetKind::RobloxServer,
_ => TargetKind::Roblox,
}, },
)) ),
}) WallyPackageRef {
.collect::<Result<_, errors::ResolveError>>()?, index_url: index_url.clone(),
)) dependencies,
} },
))
inner(self, specifier, options).await })
.collect::<Result<_, errors::ResolveError>>()?,
))
} }
#[instrument(skip_all, level = "debug")] #[instrument(skip_all, level = "debug")]