Skip to content

Commit

Permalink
refactor: remove NpmResolutionSnapshotPendingResolver (#74)
Browse files Browse the repository at this point in the history
  • Loading branch information
dsherret authored Dec 2, 2024
1 parent cd4f3a4 commit 1e400f4
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 122 deletions.
2 changes: 1 addition & 1 deletion rust-toolchain.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[toolchain]
channel = "1.80.1"
channel = "1.83.0"
components = ["clippy", "rustfmt"]
profile = "minimal"
2 changes: 1 addition & 1 deletion src/registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ pub enum NpmPackageVersionDistInfoIntegrity<'a> {
LegacySha1Hex(&'a str),
}

impl<'a> NpmPackageVersionDistInfoIntegrity<'a> {
impl NpmPackageVersionDistInfoIntegrity<'_> {
pub fn for_lockfile(&self) -> String {
match self {
NpmPackageVersionDistInfoIntegrity::Integrity {
Expand Down
2 changes: 1 addition & 1 deletion src/resolution/collections.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ pub struct OneDirectionalLinkedList<'a, T> {
value: OneDirectionalLinkedListItem<'a, T>,
}

impl<'a, T> Default for OneDirectionalLinkedList<'a, T> {
impl<T> Default for OneDirectionalLinkedList<'_, T> {
fn default() -> Self {
Self {
parent: None,
Expand Down
3 changes: 1 addition & 2 deletions src/resolution/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,10 @@ pub use common::NpmPackageVersionResolutionError;
pub use graph::NpmResolutionError;
pub use snapshot::incomplete_snapshot_from_lockfile;
pub use snapshot::snapshot_from_lockfile;
pub use snapshot::AddPkgReqsOptions;
pub use snapshot::AddPkgReqsResult;
pub use snapshot::NpmPackagesPartitioned;
pub use snapshot::NpmResolutionSnapshot;
pub use snapshot::NpmResolutionSnapshotPendingResolver;
pub use snapshot::NpmResolutionSnapshotPendingResolverOptions;
pub use snapshot::PackageCacheFolderIdNotFoundError;
pub use snapshot::PackageIdNotFoundError;
pub use snapshot::PackageNotFoundFromReferrerError;
Expand Down
209 changes: 92 additions & 117 deletions src/resolution/snapshot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,15 @@ impl std::fmt::Debug for SerializedNpmResolutionSnapshot {
}
}

#[derive(Debug, Clone)]
pub struct AddPkgReqsOptions<'a> {
pub package_reqs: &'a [PackageReq],
/// Known good version requirement to use for the `@types/node` package
/// when the version is unspecified or "latest".
pub types_node_version_req: Option<VersionReq>,
}

#[derive(Debug)]
pub struct AddPkgReqsResult {
/// Results from adding the individual packages.
///
Expand Down Expand Up @@ -268,6 +277,89 @@ impl NpmResolutionSnapshot {
}
}

/// Resolves the provided package requirements adding them to the snapshot.
pub async fn add_pkg_reqs(
self,
api: &impl NpmRegistryApi,
options: AddPkgReqsOptions<'_>,
) -> AddPkgReqsResult {
enum InfoOrNv {
InfoResult(Result<Arc<NpmPackageInfo>, NpmRegistryPackageInfoLoadError>),
Nv(PackageNv),
}
// convert the snapshot to a traversable graph
let mut graph = Graph::from_snapshot(self);

let reqs_with_in_graph = options
.package_reqs
.iter()
.map(|req| (req, graph.get_req_nv(req).map(|r| r.as_ref().clone())));
let mut top_level_packages = FuturesOrdered::from_iter({
reqs_with_in_graph.map(|(req, maybe_nv)| async move {
let maybe_info = if let Some(nv) = maybe_nv {
InfoOrNv::Nv(nv)
} else {
InfoOrNv::InfoResult(api.package_info(&req.name).await)
};
(req, maybe_info)
})
});

let version_resolver = NpmVersionResolver {
types_node_version_req: options.types_node_version_req,
};
// go over the top level package names first (npm package reqs and pending unresolved),
// then down the tree one level at a time through all the branches
let mut resolver =
GraphDependencyResolver::new(&mut graph, api, &version_resolver);

// The package reqs and ids should already be sorted
// in the order they should be resolved in.
let mut results = Vec::with_capacity(options.package_reqs.len());
let mut first_resolution_error = None;
while let Some(result) = top_level_packages.next().await {
let (req, info_or_nv) = result;
match info_or_nv {
InfoOrNv::InfoResult(info_result) => {
match info_result
.map_err(|err| err.into())
.and_then(|info| resolver.add_package_req(req, &info))
{
Ok(nv) => {
results.push(Ok(nv.as_ref().clone()));
}
Err(err) => {
if first_resolution_error.is_none() {
first_resolution_error = Some(err.clone());
}
results.push(Err(err));
}
}
}
InfoOrNv::Nv(nv) => {
results.push(Ok(nv));
}
}
}
drop(top_level_packages); // stop borrow of api

let dep_graph_result = match first_resolution_error {
Some(err) => Err(err),
None => match resolver.resolve_pending().await {
Ok(()) => graph
.into_snapshot(api)
.await
.map_err(NpmResolutionError::Registry),
Err(err) => Err(err),
},
};

AddPkgReqsResult {
results,
dep_graph_result,
}
}

/// Returns a new snapshot made from a subset of this snapshot's package reqs.
/// Requirements not present in this snapshot will be ignored.
pub fn subset(&self, package_reqs: &[PackageReq]) -> Self {
Expand Down Expand Up @@ -698,123 +790,6 @@ impl SnapshotPackageCopyIndexResolver {
}
}

pub struct NpmResolutionSnapshotPendingResolverOptions<
'a,
TNpmRegistryApi: NpmRegistryApi,
> {
pub api: &'a TNpmRegistryApi,
/// Known good version requirement to use for the `@types/node` package
/// when the version is unspecified or "latest".
pub types_node_version_req: Option<VersionReq>,
}

/// Resolves pending packages in the npm snapshot.
pub struct NpmResolutionSnapshotPendingResolver<
'a,
TNpmRegistryApi: NpmRegistryApi,
> {
version_resolver: NpmVersionResolver,
api: &'a TNpmRegistryApi,
}

impl<'a, TNpmRegistryApi: NpmRegistryApi>
NpmResolutionSnapshotPendingResolver<'a, TNpmRegistryApi>
{
pub fn new(
options: NpmResolutionSnapshotPendingResolverOptions<'a, TNpmRegistryApi>,
) -> Self {
Self {
api: options.api,
version_resolver: NpmVersionResolver {
types_node_version_req: options.types_node_version_req,
},
}
}

/// Resolves the provided package requirements.
pub async fn add_pkg_reqs(
&self,
snapshot: NpmResolutionSnapshot,
package_reqs: &[PackageReq],
) -> AddPkgReqsResult {
enum InfoOrNv {
InfoResult(Result<Arc<NpmPackageInfo>, NpmRegistryPackageInfoLoadError>),
Nv(PackageNv),
}
// convert the snapshot to a traversable graph
let mut graph = Graph::from_snapshot(snapshot);

let api = &self.api;
let reqs_with_in_graph = package_reqs
.iter()
.map(|req| (req, graph.get_req_nv(req).map(|r| r.as_ref().clone())));
let mut top_level_packages = FuturesOrdered::from_iter({
reqs_with_in_graph.map(|(req, maybe_nv)| async move {
let maybe_info = if let Some(nv) = maybe_nv {
InfoOrNv::Nv(nv)
} else {
InfoOrNv::InfoResult(api.package_info(&req.name).await)
};
(req, maybe_info)
})
});

// go over the top level package names first (npm package reqs and pending unresolved),
// then down the tree one level at a time through all the branches
let mut resolver = GraphDependencyResolver::new(
&mut graph,
self.api,
&self.version_resolver,
);

// The package reqs and ids should already be sorted
// in the order they should be resolved in.
let mut results = Vec::with_capacity(package_reqs.len());
let mut first_resolution_error = None;
while let Some(result) = top_level_packages.next().await {
let (req, info_or_nv) = result;
match info_or_nv {
InfoOrNv::InfoResult(info_result) => {
match info_result
.map_err(|err| err.into())
.and_then(|info| resolver.add_package_req(req, &info))
{
Ok(nv) => {
results.push(Ok(nv.as_ref().clone()));
}
Err(err) => {
if first_resolution_error.is_none() {
first_resolution_error = Some(err.clone());
}
results.push(Err(err));
}
}
}
InfoOrNv::Nv(nv) => {
results.push(Ok(nv));
}
}
}
drop(top_level_packages); // stop borrow of api

let dep_graph_result = match first_resolution_error {
Some(err) => Err(err),
None => match resolver.resolve_pending().await {
Ok(()) => graph
.into_snapshot(self.api)
.await
.map_err(NpmResolutionError::Registry),
Err(err) => Err(err),
},
};

AddPkgReqsResult {
results,
dep_graph_result,
}
}
}

fn name_without_path(name: &str) -> &str {
let mut search_start_index = 0;
if name.starts_with('@') {
Expand Down

0 comments on commit 1e400f4

Please sign in to comment.