Skip to content

Commit 3e84ee9

Browse files
committed
interim commit
1 parent dca7d50 commit 3e84ee9

8 files changed

Lines changed: 141 additions & 76 deletions

File tree

crates/wasm-pkg-client/src/caching/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ pub trait Cache {
4646
/// A client that caches response data using the given cache implementation. Can be used without an
4747
/// underlying client to be used as a read-only cache.
4848
pub struct CachingClient<T> {
49-
client: Option<Client>,
49+
pub client: Option<Client>,
5050
cache: Arc<T>,
5151
}
5252

crates/wasm-pkg-client/src/local.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@ use std::{
1010
use anyhow::anyhow;
1111
use async_trait::async_trait;
1212
use futures_util::{StreamExt, TryStreamExt};
13-
use serde::Deserialize;
13+
use serde::{Deserialize, Serialize};
1414
use sha2::{Digest, Sha256};
15+
use tempfile::TempDir;
1516
use tokio_util::io::ReaderStream;
1617
use wasm_pkg_common::{
1718
config::RegistryConfig,
@@ -27,12 +28,13 @@ use crate::{
2728
ContentStream, PublishingSource,
2829
};
2930

30-
#[derive(Clone, Debug, Deserialize)]
31+
#[derive(Clone, Debug, Deserialize, Serialize)]
3132
pub struct LocalConfig {
3233
pub root: PathBuf,
3334
}
3435

35-
pub(crate) struct LocalBackend {
36+
#[derive(Clone)]
37+
pub struct LocalBackend {
3638
pub(crate) root: PathBuf,
3739
}
3840

@@ -60,6 +62,13 @@ impl LocalBackend {
6062
fn version_path(&self, package: &PackageRef, version: &Version) -> PathBuf {
6163
self.package_dir(package).join(format!("{version}.wasm"))
6264
}
65+
66+
pub fn temp_dir() -> Result<(Self, TempDir), Error> {
67+
let handle = TempDir::new()?;
68+
let root = handle.path().to_owned();
69+
tracing::debug!(registry_dir=%root.display(), "created temporary directory");
70+
Ok((Self { root }, handle))
71+
}
6372
}
6473

6574
#[async_trait]

crates/wasm-pkg-client/src/overlay/mod.rs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,7 @@ pub(crate) struct OverlayBackend {
2020

2121
impl OverlayBackend {
2222
fn new(remotes: HashMap<PackageRef, InnerClient>) -> Result<Self, Error> {
23-
let handle = TempDir::new()?;
24-
let root = handle.path().to_owned();
25-
let local = LocalBackend { root };
23+
let (local, handle) = LocalBackend::temp_dir()?;
2624
Ok(Self {
2725
local,
2826
remotes,
@@ -41,10 +39,14 @@ impl OverlayBackend {
4139
impl PackageLoader for OverlayBackend {
4240
async fn list_all_versions(&self, package: &PackageRef) -> Result<Vec<VersionInfo>, Error> {
4341
let mut versions = self.local.list_all_versions(package).await?;
44-
let mut remote_versions = self.remote(package)?.list_all_versions(package).await?;
45-
versions.append(&mut remote_versions);
46-
versions.sort();
47-
versions.dedup();
42+
43+
if let Some(remote) = self.remotes.get(package) {
44+
let mut remote_versions = remote.list_all_versions(package).await?;
45+
versions.append(&mut remote_versions);
46+
versions.sort();
47+
versions.dedup();
48+
}
49+
4850
Ok(versions)
4951
}
5052

crates/wasm-pkg-common/src/package.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ impl std::fmt::Display for PackageSpec {
7979
}
8080

8181
/// A package spec combines a [`PackageRef`] with an optional version.
82-
#[derive(Clone, Debug)]
82+
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
8383
pub struct PackageSpec {
8484
pub package: PackageRef,
8585
pub version: Option<Version>,

crates/wasm-pkg-common/src/registry.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,4 @@ impl TryFrom<String> for Registry {
5757
}
5858
}
5959

60-
/// Represents a directed edge in a package dependency graph.
61-
#[derive(Clone, Debug)]
62-
pub struct DependencyOf;
63-
64-
pub type DependencyGraph<N> = Acyclic<DiGraph<N, DependencyOf>>;
60+
pub type DependencyGraph<N> = Acyclic<DiGraph<N, petgraph::Direction>>;

crates/wasm-pkg-core/src/resolver.rs

Lines changed: 42 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,16 @@ use indexmap::{IndexMap, IndexSet};
1515
use petgraph::{
1616
acyclic::Acyclic,
1717
graph::{DiGraph, NodeIndex},
18+
Direction,
1819
};
1920
use semver::{Comparator, Op, Version, VersionReq};
2021
use tokio::io::{AsyncRead, AsyncReadExt};
22+
use tracing::Level;
2123
use wasm_pkg_client::{
2224
caching::{CachingClient, FileCache},
2325
Client, Config, ContentDigest, Error as WasmPkgError, PackageRef, Release, VersionInfo,
2426
};
25-
use wasm_pkg_common::registry::{DependencyGraph, DependencyOf};
27+
use wasm_pkg_common::{package::PackageSpec, registry::DependencyGraph};
2628
use wit_component::DecodedWasm;
2729
use wit_parser::{PackageId, PackageName, Resolve, UnresolvedPackageGroup, WorldId};
2830

@@ -171,32 +173,6 @@ pub struct LocalResolution {
171173
pub path: PathBuf,
172174
}
173175

174-
pub struct LocalDependencies {
175-
pub packages: HashMap<PackageRef, LocalResolution>,
176-
pub graph: DiGraph<PackageRef, DependencyOf>,
177-
}
178-
179-
impl LocalDependencies {
180-
pub fn sort(&self) -> Result<Vec<PackageRef>> {
181-
// sort our packages topologically
182-
let acyclic_graph = Acyclic::try_from(self.graph.clone()).map_err(|e| {
183-
anyhow::anyhow!(
184-
"detected cyclical dependencies with package: {}",
185-
self.graph[e.node_id()]
186-
)
187-
})?;
188-
189-
Ok(acyclic_graph
190-
.nodes_iter()
191-
.map(|id| self.graph[id].clone())
192-
.collect())
193-
}
194-
195-
pub fn has_no_dependencies(&self) -> bool {
196-
self.graph.raw_edges().is_empty()
197-
}
198-
}
199-
200176
/// Represents a resolution of a dependency.
201177
#[derive(Debug, Clone)]
202178
#[allow(clippy::large_enum_variant)]
@@ -872,11 +848,11 @@ fn visit<'a>(
872848
/// State for tracking dependencies during upload.
873849
pub struct PublishPlan {
874850
/// Graph of publishable packages where the edges are `(dependency -DependencyOf->) dependent)`
875-
dependents: DependencyGraph<PackageRef>,
851+
dependents: DependencyGraph<PackageSpec>,
876852
/// Mapping [`PackageRef`]s to the respective index inside the dependency graph.
877853
// TODO look at using cargo's `InternedString` type for `PackageRef`:
878854
// https://docs.rs/cargo/latest/cargo/util/interning/struct.InternedString.html
879-
indices: HashMap<PackageRef, NodeIndex>,
855+
indices: HashMap<PackageRef, (NodeIndex, PathBuf)>,
880856
}
881857

882858
impl PublishPlan {
@@ -894,8 +870,32 @@ impl PublishPlan {
894870
})
895871
}
896872

897-
pub fn iter<'a>(&'a self) -> impl Iterator<Item = &'a PackageRef> + 'a {
898-
self.indices.iter().map(|(pkg, _)| pkg)
873+
pub fn iter<'a>(&'a self) -> impl Iterator<Item = &'a PackageSpec> + 'a {
874+
self.dependents.nodes_iter().map(|id| &self.dependents[id])
875+
}
876+
877+
pub fn iter_edges<'a>(&'a self) -> impl Iterator<Item = &'a PackageSpec> + 'a {
878+
use petgraph::visit::IntoNeighborsDirected;
879+
self.dependents.nodes_iter().map(|id| {
880+
let dep = &self.dependents[id];
881+
tracing::warn!("ITER {dep}");
882+
let mut neighbors = self
883+
.dependents
884+
.neighbors_directed(id, Direction::Outgoing)
885+
.peekable();
886+
if neighbors.peek().is_none() {
887+
tracing::debug!("{dep} has no dependents");
888+
}
889+
890+
if tracing::enabled!(Level::DEBUG) {
891+
while let Some(id) = neighbors.next() {
892+
let pkg = &self.dependents[id];
893+
tracing::debug!("{dep} -(DependencyOF)-> {pkg}");
894+
}
895+
}
896+
897+
dep
898+
})
899899
}
900900

901901
pub fn is_empty(&self) -> bool {
@@ -909,30 +909,35 @@ impl PublishPlan {
909909
/// Returns the set of packages that are ready for publishing (i.e. have no outstanding dependencies).
910910
///
911911
/// These will not be returned in future calls.
912-
pub fn take_ready(&mut self) -> BTreeSet<PackageRef> {
912+
pub fn take_ready(&mut self) -> BTreeSet<PackageSpec> {
913913
self.dependents
914914
.nodes_iter()
915915
// there are no dependents on `self.dendents[id]`
916916
.filter(|id| self.dependents.neighbors(*id).count() == 0)
917917
.map(|id| {
918918
let pkg = &self.dependents[id];
919-
self.indices.remove(&pkg);
919+
self.indices.remove(&pkg.package);
920920
pkg.clone()
921921
})
922922
.collect()
923923
}
924924

925+
///
926+
pub fn get_path(&self, pkg: &PackageRef) -> Option<&Path> {
927+
self.indices.get(pkg).map(|(_, p)| p.as_ref())
928+
}
929+
925930
/// Packages confirmed to be available in the registry, potentially allowing additional
926931
/// packages to be "ready".
927932
pub fn mark_confirmed(&mut self, published: impl IntoIterator<Item = PackageRef>) {
928933
for pkg in published {
929-
let id = self
934+
let (id, _) = self
930935
.indices
931936
.remove(&pkg)
932-
.expect("PackageRef has no associated index");
937+
.expect("PackageSpec has no associated index");
933938
self.dependents
934939
.remove_node(id)
935-
.expect("index has no associated PackageRef");
940+
.expect("index has no associated PackageSpec");
936941
}
937942
}
938943
}
@@ -942,7 +947,7 @@ impl PublishPlan {
942947
/// e.g. "foo:a@0.1.0, bar:b@0.2.0, and baz:c@0.3.0".
943948
///
944949
/// Note: the final separator (e.g. "and" in the previous example) can be chosen.
945-
pub fn package_list(pkgs: impl IntoIterator<Item = PackageRef>, final_sep: &str) -> String {
950+
pub fn package_list(pkgs: impl IntoIterator<Item = PackageSpec>, final_sep: &str) -> String {
946951
let mut names: Vec<_> = pkgs.into_iter().map(|pkg| pkg.to_string()).collect();
947952
names.sort();
948953

crates/wasm-pkg-core/src/wit.rs

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,19 @@
22
33
use std::{
44
collections::{HashMap, HashSet},
5-
path::Path,
5+
path::{Path, PathBuf},
66
str::FromStr,
77
};
88

99
use anyhow::{Context, Result};
10-
use petgraph::{data::Build, graph::NodeIndex};
10+
use petgraph::{data::Build, graph::NodeIndex, Direction};
1111
use semver::{Version, VersionReq};
1212
use wasm_metadata::{AddMetadata, AddMetadataField};
1313
use wasm_pkg_client::{
1414
caching::{CachingClient, FileCache},
1515
PackageRef,
1616
};
17-
use wasm_pkg_common::{
18-
package::PackageSpec,
19-
registry::{DependencyGraph, DependencyOf},
20-
};
17+
use wasm_pkg_common::{package::PackageSpec, registry::DependencyGraph};
2118
use wit_component::WitPrinter;
2219
use wit_parser::{PackageId, PackageName, Resolve};
2320

@@ -182,25 +179,45 @@ pub fn get_packages(
182179

183180
pub fn get_local_dependencies(
184181
paths: &[impl AsRef<Path>],
185-
) -> Result<(DependencyGraph<PackageRef>, HashMap<PackageRef, NodeIndex>)> {
182+
) -> Result<(
183+
DependencyGraph<PackageSpec>,
184+
HashMap<PackageRef, (NodeIndex, PathBuf)>,
185+
)> {
186186
let pkg_trees = paths
187187
.into_iter()
188-
.map(|p| get_packages(p))
188+
.map(|path| get_packages(path).map(|(pkg, deps)| ((pkg, path), deps)))
189189
.collect::<Result<Vec<_>, _>>()?;
190190
let mut graph = DependencyGraph::new();
191191
let mut indices = HashMap::new();
192192
// establish all nodes
193-
for (spec, _) in &pkg_trees {
194-
let id = graph.add_node(spec.package());
195-
if indices.insert(spec.package(), id).is_some() {
193+
for ((spec, path), _) in &pkg_trees {
194+
let id = graph.add_node(spec.clone());
195+
if indices
196+
.insert(spec.package(), (id, path.as_ref().to_owned()))
197+
.is_some()
198+
{
196199
anyhow::bail!("duplicate references to package detected: {spec}");
197200
}
198201
}
199-
for (spec, deps) in pkg_trees {
202+
for ((spec, _), deps) in pkg_trees {
200203
// TODO handle version matching for dependencies
201204
for (dep, _version) in deps {
202-
if let Some(&dep_id) = indices.get(&dep) {
203-
graph.add_edge(dep_id, indices[&spec.package], DependencyOf);
205+
if let Some(&(dep, _)) = indices.get(&dep) {
206+
let (pkg, _) = indices[&spec.package];
207+
// // dep -(DependencyOF)-> pkg
208+
// graph.try_update_edge(dep, pkg, Direction::Outgoing);
209+
// // pkg -(DependsOn)-> dep
210+
graph
211+
.try_update_edge(pkg, dep, Direction::Outgoing)
212+
.map_err(|e| match e {
213+
petgraph::acyclic::AcyclicEdgeError::Cycle(cycle) => {
214+
anyhow::anyhow!("cyclical depndency detected")
215+
.context(format!("package {}", graph[cycle.node_id()]))
216+
.context(format!("package {}", graph[pkg]))
217+
}
218+
petgraph::acyclic::AcyclicEdgeError::SelfLoop => todo!(),
219+
petgraph::acyclic::AcyclicEdgeError::InvalidEdge => todo!(),
220+
})?;
204221
}
205222
}
206223
}

0 commit comments

Comments
 (0)