Skip to content

Commit

Permalink
Add filesystem mappings to the resolver
Browse files Browse the repository at this point in the history
  • Loading branch information
Michael-F-Bryan committed Jun 6, 2023
1 parent e85be59 commit 330c33e
Show file tree
Hide file tree
Showing 7 changed files with 220 additions and 12 deletions.
1 change: 1 addition & 0 deletions lib/wasi/src/runtime/package_loader/builtin_loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,7 @@ mod tests {
dependencies: Vec::new(),
commands: Vec::new(),
entrypoint: Some("asdf".to_string()),
filesystem: Vec::new(),
},
dist: DistributionInfo {
webc: "https://wapm.io/python/python".parse().unwrap(),
Expand Down
1 change: 1 addition & 0 deletions lib/wasi/src/runtime/resolver/in_memory_source.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ mod tests {
name: "bash".to_string(),
}],
entrypoint: Some("bash".to_string()),
filesystem: Vec::new(),
},
dist: DistributionInfo {
webc: crate::runtime::resolver::utils::url_from_file_path(
Expand Down
26 changes: 26 additions & 0 deletions lib/wasi/src/runtime/resolver/inputs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ pub struct PackageInfo {
pub entrypoint: Option<String>,
/// Any dependencies this package may have.
pub dependencies: Vec<Dependency>,
pub filesystem: Vec<FileSystemMapping>,
}

impl PackageInfo {
Expand Down Expand Up @@ -209,12 +210,15 @@ impl PackageInfo {
})
.collect();

let filesystem = filesystem_mapping_from_manifest(manifest);

Ok(PackageInfo {
name,
version: version.parse()?,
dependencies,
commands,
entrypoint: manifest.entrypoint.clone(),
filesystem,
})
}

Expand All @@ -226,6 +230,28 @@ impl PackageInfo {
}
}

fn filesystem_mapping_from_manifest(_manifest: &Manifest) -> Vec<FileSystemMapping> {
// FIXME(Michael-F-Bryan): wapm2pirita never added filesystem mappings to the manifest
// That means we need to
// - Figure out whether filesystem mappings belong to the whole package or
// if each command has their own set of mappings
// - Update wapm-targz-to-pirita to copy the [fs] table across
// - Re-generate all packages on WAPM
// - Update this function to copy metadata into our internal datastructures
Vec::new()
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FileSystemMapping {
/// The volume to be mounted.
pub volume_name: String,
/// Where the volume should be mounted within the resulting filesystem.
pub mount_path: String,
/// The name of the package this volume comes from (current package if
/// `None`).
pub dependency_name: Option<String>,
}

fn url_or_manifest_to_specifier(value: &UrlOrManifest) -> Result<PackageSpecifier, Error> {
match value {
UrlOrManifest::Url(url) => Ok(PackageSpecifier::Url(url.clone())),
Expand Down
3 changes: 2 additions & 1 deletion lib/wasi/src/runtime/resolver/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ pub use self::{
},
multi_source_registry::MultiSource,
outputs::{
DependencyGraph, FileSystemMapping, ItemLocation, PackageId, Resolution, ResolvedPackage,
DependencyGraph, ItemLocation, PackageId, Resolution, ResolvedFileSystemMapping,
ResolvedPackage,
},
resolve::resolve,
source::Source,
Expand Down
5 changes: 3 additions & 2 deletions lib/wasi/src/runtime/resolver/outputs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ impl DependencyGraph {
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FileSystemMapping {
pub struct ResolvedFileSystemMapping {
// TODO: Change this to a new type that isn't coupled to the OS
pub mount_path: PathBuf,
pub volume_name: String,
pub package: PackageId,
Expand All @@ -75,5 +76,5 @@ pub struct ResolvedPackage {
pub commands: BTreeMap<String, ItemLocation>,
pub entrypoint: Option<String>,
/// A mapping from paths to the volumes that should be mounted there.
pub filesystem: Vec<FileSystemMapping>,
pub filesystem: Vec<ResolvedFileSystemMapping>,
}
195 changes: 186 additions & 9 deletions lib/wasi/src/runtime/resolver/resolve.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use std::collections::{BTreeMap, HashMap, HashSet, VecDeque};
use std::{
collections::{BTreeMap, HashMap, HashSet, VecDeque},
path::PathBuf,
};

use semver::Version;

Expand All @@ -7,7 +10,7 @@ use crate::runtime::resolver::{
ResolvedPackage, Source,
};

use super::FileSystemMapping;
use super::ResolvedFileSystemMapping;

/// Given the [`PackageInfo`] for a root package, resolve its dependency graph
/// and figure out how it could be executed.
Expand Down Expand Up @@ -293,18 +296,33 @@ fn resolve_package(dependency_graph: &DependencyGraph) -> Result<ResolvedPackage
}

fn resolve_filesystem_mapping(
_dependency_graph: &DependencyGraph,
) -> Result<Vec<FileSystemMapping>, ResolveError> {
// TODO: Add filesystem mappings to summary and figure out the final mapping
// for this dependency graph.
// See <https://github.com/wasmerio/wasmer/issues/3744> for more.
Ok(Vec::new())
graph: &DependencyGraph,
) -> Result<Vec<ResolvedFileSystemMapping>, ResolveError> {
let mut mappings = Vec::new();

for (id, pkg) in &graph.package_info {
for mapping in &pkg.filesystem {
let dep = match &mapping.dependency_name {
Some(name) => graph.dependencies[id].get(name).unwrap(),
None => id,
};
mappings.push(ResolvedFileSystemMapping {
mount_path: PathBuf::from(&mapping.mount_path),
volume_name: mapping.volume_name.clone(),
package: dep.clone(),
})
}
}

Ok(mappings)
}

#[cfg(test)]
mod tests {
use std::path::PathBuf;

use crate::runtime::resolver::{
inputs::{DistributionInfo, PackageInfo},
inputs::{DistributionInfo, FileSystemMapping, PackageInfo},
Dependency, InMemorySource, MultiSource, PackageSpecifier,
};

Expand All @@ -324,6 +342,7 @@ mod tests {
dependencies: Vec::new(),
commands: Vec::new(),
entrypoint: None,
filesystem: Vec::new(),
};
let dist = DistributionInfo {
webc: format!("http://localhost/{name}@{version}")
Expand Down Expand Up @@ -402,6 +421,29 @@ mod tests {
self.summary.pkg.entrypoint = Some(name.to_string());
self
}

fn with_fs_mapping(&mut self, volume_name: &str, mount_path: &str) -> &mut Self {
self.summary.pkg.filesystem.push(FileSystemMapping {
volume_name: volume_name.to_string(),
mount_path: mount_path.to_string(),
dependency_name: None,
});
self
}

fn with_fs_mapping_from_dependency(
&mut self,
volume_name: &str,
mount_path: &str,
dependency: &str,
) -> &mut Self {
self.summary.pkg.filesystem.push(FileSystemMapping {
volume_name: volume_name.to_string(),
mount_path: mount_path.to_string(),
dependency_name: Some(dependency.to_string()),
});
self
}
}

impl<'builder> Drop for AddPackageVersion<'builder> {
Expand Down Expand Up @@ -897,4 +939,139 @@ mod tests {

assert_eq!(message, "[email protected][email protected][email protected]");
}

#[test]
fn filesystem_with_one_package_and_no_fs_tables() {
let mut builder = RegistryBuilder::new();
builder.register("root", "1.0.0");
let mut dep_builder = builder.start_dependency_graph();
dep_builder.insert("root", "1.0.0");
let PackageSummary { pkg, dist } = builder.get("root", "1.0.0").clone();
let root_id = pkg.id();
let graph = DependencyGraph {
root: root_id.clone(),
dependencies: dep_builder.finish(),
package_info: vec![(root_id.clone(), pkg)].into_iter().collect(),
distribution: vec![(root_id, dist)].into_iter().collect(),
};

let mappings = resolve_filesystem_mapping(&graph).unwrap();
assert_eq!(mappings, Vec::new());
}

#[test]
fn filesystem_with_one_package_and_one_fs_tables() {
let mut builder = RegistryBuilder::new();
builder
.register("root", "1.0.0")
.with_fs_mapping("lib", "/lib");
let mut dep_builder = builder.start_dependency_graph();
dep_builder.insert("root", "1.0.0");
let PackageSummary { pkg, dist } = builder.get("root", "1.0.0").clone();
let root_id = pkg.id();
let graph = DependencyGraph {
root: root_id.clone(),
dependencies: dep_builder.finish(),
package_info: vec![(root_id.clone(), pkg)].into_iter().collect(),
distribution: vec![(root_id, dist)].into_iter().collect(),
};

let mappings = resolve_filesystem_mapping(&graph).unwrap();
assert_eq!(
mappings,
vec![ResolvedFileSystemMapping {
mount_path: PathBuf::from("/lib"),
volume_name: "lib".to_string(),
package: builder.get("root", "1.0.0").package_id(),
}]
);
}

#[test]
fn merge_fs_mappings_from_multiple_packages() {
let mut builder = RegistryBuilder::new();
builder
.register("root", "1.0.0")
.with_dependency("first", "=1.0.0")
.with_dependency("second", "=1.0.0")
.with_fs_mapping("lib", "/root");
builder
.register("first", "1.0.0")
.with_fs_mapping("main", "/usr/local/lib/first");
builder
.register("second", "1.0.0")
.with_fs_mapping("main", "/usr/local/lib/second");
let mut dep_builder = builder.start_dependency_graph();
dep_builder
.insert("root", "1.0.0")
.with_dependency("first", "1.0.0")
.with_dependency("second", "1.0.0");
dep_builder.insert("first", "1.0.0");
dep_builder.insert("second", "1.0.0");
let PackageSummary { pkg, dist } = builder.get("root", "1.0.0").clone();
let root_id = pkg.id();
let graph = DependencyGraph {
root: root_id.clone(),
dependencies: dep_builder.finish(),
package_info: vec![(root_id.clone(), pkg)].into_iter().collect(),
distribution: vec![(root_id, dist)].into_iter().collect(),
};

let mappings = resolve_filesystem_mapping(&graph).unwrap();

assert_eq!(
mappings,
vec![
ResolvedFileSystemMapping {
mount_path: PathBuf::from("/usr/local/lib/second"),
volume_name: "main".to_string(),
package: builder.get("second", "1.0.0").package_id(),
},
ResolvedFileSystemMapping {
mount_path: PathBuf::from("/usr/local/lib/first"),
volume_name: "main".to_string(),
package: builder.get("first", "1.0.0").package_id(),
},
ResolvedFileSystemMapping {
mount_path: PathBuf::from("/root"),
volume_name: "lib".to_string(),
package: builder.get("root", "1.0.0").package_id(),
}
]
);
}

#[test]
fn use_fs_mapping_from_dependency() {
let mut builder = RegistryBuilder::new();
builder
.register("root", "1.0.0")
.with_dependency("dep", "=1.0.0")
.with_fs_mapping_from_dependency("dep-volume", "/root", "dep");
builder.register("dep", "1.0.0");
let mut dep_builder = builder.start_dependency_graph();
dep_builder
.insert("root", "1.0.0")
.with_dependency("dep", "1.0.0");
dep_builder.insert("dep", "1.0.0");
let PackageSummary { pkg, dist } = builder.get("root", "1.0.0").clone();
let root_id = pkg.id();
let graph = DependencyGraph {
root: root_id.clone(),
dependencies: dep_builder.finish(),
package_info: vec![(root_id.clone(), pkg)].into_iter().collect(),
distribution: vec![(root_id, dist)].into_iter().collect(),
};

let mappings = resolve_filesystem_mapping(&graph).unwrap();

assert_eq!(
mappings,
vec![ResolvedFileSystemMapping {
mount_path: PathBuf::from("/root"),
volume_name: "dep-volume".to_string(),
package: builder.get("dep", "1.0.0").package_id(),
}]
);
}
}
1 change: 1 addition & 0 deletions lib/wasi/src/runtime/resolver/wapm_source.rs
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,7 @@ mod tests {
},
],
entrypoint: Some("wasmer-pack".to_string()),
filesystem: Vec::new(),
},
dist: DistributionInfo {
webc: "https://registry-cdn.wapm.io/packages/wasmer/wasmer-pack-cli/wasmer-pack-cli-0.6.0-654a2ed8-875f-11ed-90e2-c6aeb50490de.webc".parse().unwrap(),
Expand Down

0 comments on commit 330c33e

Please sign in to comment.