Skip to content

Commit

Permalink
Added constructors to BinaryPackage and re-worked resolution so the r…
Browse files Browse the repository at this point in the history
…oot package doesn't need to be in the registry
  • Loading branch information
Michael-F-Bryan committed May 17, 2023
1 parent 2bfd39f commit c6b70d8
Show file tree
Hide file tree
Showing 11 changed files with 195 additions and 126 deletions.
61 changes: 49 additions & 12 deletions lib/wasi/src/bin_factory/binary_package.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
use std::sync::{Arc, RwLock};
use std::sync::Arc;

use derivative::*;
use once_cell::sync::OnceCell;
use semver::Version;
use virtual_fs::FileSystem;
use webc::{compat::SharedBytes, Container};

use crate::{runtime::module_cache::ModuleHash, WasiRuntime};
use crate::{
runtime::{
module_cache::ModuleHash,
resolver::{PackageId, PackageInfo, PackageSpecifier, SourceId, SourceKind},
},
WasiRuntime,
};

#[derive(Derivative, Clone)]
#[derivative(Debug)]
Expand Down Expand Up @@ -53,7 +59,7 @@ pub struct BinaryPackage {
pub entry: Option<SharedBytes>,
pub hash: OnceCell<ModuleHash>,
pub webc_fs: Arc<dyn FileSystem + Send + Sync>,
pub commands: Arc<RwLock<Vec<BinaryPackageCommand>>>,
pub commands: Vec<BinaryPackageCommand>,
pub uses: Vec<String>,
pub version: Version,
pub module_memory_footprint: u64,
Expand All @@ -64,16 +70,47 @@ impl BinaryPackage {
/// Load a [`webc::Container`] and all its dependencies into a
/// [`BinaryPackage`].
pub async fn from_webc(
_container: &Container,
_rt: &dyn WasiRuntime,
container: &Container,
rt: &dyn WasiRuntime,
) -> Result<Self, anyhow::Error> {
// let summary = crate::runtime::resolver::extract_summary_from_manifest(
// container.manifest(),
// source,
// url,
// webc_sha256,
// )?;
todo!();
let registry = rt.registry();
let root = PackageInfo::from_manifest(container.manifest())?;
let root_id = PackageId {
package_name: root.name.clone(),
version: root.version.clone(),
source: SourceId::new(
SourceKind::LocalRegistry,
"http://localhost/".parse().unwrap(),
),
};

let resolution = crate::runtime::resolver::resolve(&root_id, &root, &*registry).await?;
let pkg = rt
.load_package_tree(container, &resolution)
.await
.map_err(|e| anyhow::anyhow!(e))?;

Ok(pkg)
}

/// Load a [`BinaryPackage`] and all its dependencies from a registry.
pub async fn from_specifier(
specifier: &PackageSpecifier,
runtime: &dyn WasiRuntime,
) -> Result<Self, anyhow::Error> {
let registry = runtime.registry();
let root_summary = registry.latest(specifier).await?;
let root = runtime.package_loader().load(&root_summary).await?;
let id = root_summary.package_id();

let resolution =
crate::runtime::resolver::resolve(&id, &root_summary.pkg, &registry).await?;
let pkg = runtime
.load_package_tree(&root, &resolution)
.await
.map_err(|e| anyhow::anyhow!(e))?;

Ok(pkg)
}

pub fn hash(&self) -> ModuleHash {
Expand Down
15 changes: 3 additions & 12 deletions lib/wasi/src/os/command/builtins/cmd_wasmer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ impl CmdWasmer {
state.args = args;
env.state = Arc::new(state);

if let Ok(binary) = self.get_package(what.clone()).await {
if let Ok(binary) = self.get_package(&what).await {
// Now run the module
spawn_exec(binary, name, store, env, &self.runtime).await
} else {
Expand All @@ -91,18 +91,9 @@ impl CmdWasmer {
}
}

pub async fn get_package(&self, name: String) -> Result<BinaryPackage, anyhow::Error> {
let registry = self.runtime.registry();
pub async fn get_package(&self, name: &str) -> Result<BinaryPackage, anyhow::Error> {
let specifier = name.parse()?;
let root_package = registry.latest(&specifier).await?;
let resolution = crate::runtime::resolver::resolve(&root_package, &registry).await?;
let pkg = self
.runtime
.load_package_tree(&resolution)
.await
.map_err(|e| anyhow::anyhow!(e))?;

Ok(pkg)
BinaryPackage::from_specifier(&specifier, &*self.runtime).await
}
}

Expand Down
15 changes: 2 additions & 13 deletions lib/wasi/src/os/console/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,8 @@ impl Console {
}
};

let resolved_package = tasks.block_on(load_package(&webc_ident, env.runtime()));
let resolved_package =
tasks.block_on(BinaryPackage::from_specifier(&webc_ident, env.runtime()));

let binary = match resolved_package {
Ok(pkg) => pkg,
Expand Down Expand Up @@ -278,15 +279,3 @@ impl Console {
.ok();
}
}

async fn load_package(
specifier: &PackageSpecifier,
runtime: &dyn WasiRuntime,
) -> Result<BinaryPackage, Box<dyn std::error::Error + Send + Sync>> {
let registry = runtime.registry();
let root_package = registry.latest(specifier).await?;
let resolution = crate::runtime::resolver::resolve(&root_package, &registry).await?;
let pkg = runtime.load_package_tree(&resolution).await?;

Ok(pkg)
}
11 changes: 6 additions & 5 deletions lib/wasi/src/runners/wasi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,12 +135,13 @@ impl crate::runners::Runner for WasiRunner {
let wasi = metadata
.annotation("wasi")?
.unwrap_or_else(|| Wasi::new(command_name));
let atom = pkg
.entry
.as_deref()
.context("The package doesn't contain an entrpoint")?;
let cmd = pkg
.commands
.iter()
.find(|cmd| cmd.name() == command_name)
.with_context(|| format!("The package doesn't contain a \"{command_name}\" command"))?;

let module = crate::runners::compile_module(atom, &*runtime)?;
let module = crate::runners::compile_module(cmd.atom(), &*runtime)?;
let mut store = runtime.new_store();

self.prepare_webc_env(command_name, &wasi, Arc::clone(&pkg.webc_fs), runtime)?
Expand Down
27 changes: 3 additions & 24 deletions lib/wasi/src/runtime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use std::{
use derivative::Derivative;
use futures::future::BoxFuture;
use virtual_net::{DynVirtualNetworking, VirtualNetworking};
use webc::Container;

use crate::{
bin_factory::BinaryPackage,
Expand All @@ -28,29 +29,6 @@ use crate::{

/// Represents an implementation of the WASI runtime - by default everything is
/// unimplemented.
///
/// # Loading Packages
///
/// Loading a package, complete with dependencies, can feel a bit involved
/// because it requires several non-trivial components.
///
/// ```rust
/// use wasmer_wasix::{
/// runtime::{
/// WasiRuntime,
/// resolver::{PackageSpecifier, resolve},
/// },
/// bin_factory::BinaryPackage,
/// };
///
/// async fn with_runtime(runtime: &dyn WasiRuntime) -> Result<(), Box<dyn std::error::Error + Send +Sync>> {
/// let registry = runtime.registry();
/// let specifier: PackageSpecifier = "python/[email protected]".parse()?;
/// let root_package = registry.latest(&specifier).await?;
/// let resolution = resolve(&root_package, &registry).await?;
/// let pkg: BinaryPackage = runtime.load_package_tree(&resolution).await?;
/// Ok(())
/// }
#[allow(unused_variables)]
pub trait WasiRuntime
where
Expand Down Expand Up @@ -108,12 +86,13 @@ where
/// should be good enough for most applications.
fn load_package_tree<'a>(
&'a self,
root: &'a Container,
resolution: &'a Resolution,
) -> BoxFuture<'a, Result<BinaryPackage, Box<dyn std::error::Error + Send + Sync>>> {
let package_loader = self.package_loader();

Box::pin(async move {
let pkg = package_loader::load_package_tree(&package_loader, resolution).await?;
let pkg = package_loader::load_package_tree(root, &package_loader, resolution).await?;
Ok(pkg)
})
}
Expand Down
27 changes: 19 additions & 8 deletions lib/wasi/src/runtime/package_loader/load_package_tree.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::{
collections::{BTreeMap, HashMap, HashSet},
path::Path,
sync::{Arc, RwLock},
sync::Arc,
};

use anyhow::{Context, Error};
Expand All @@ -14,17 +14,20 @@ use crate::{
bin_factory::{BinaryPackage, BinaryPackageCommand},
runtime::{
package_loader::PackageLoader,
resolver::{ItemLocation, PackageId, Resolution, ResolvedPackage, Summary},
resolver::{
DependencyGraph, ItemLocation, PackageId, Resolution, ResolvedPackage, Summary,
},
},
};

/// Given a fully resolved package, load it into memory for execution.
pub async fn load_package_tree(
root: &Container,
loader: &impl PackageLoader,
resolution: &Resolution,
) -> Result<BinaryPackage, Error> {
let containers =
used_packages(loader, &resolution.package, &resolution.graph.summaries).await?;
let mut containers = used_packages(loader, &resolution.package, &resolution.graph).await?;
containers.insert(resolution.package.root_package.clone(), root.clone());
let fs = filesystem(&containers, &resolution.package)?;

let root = &resolution.package.root_package;
Expand Down Expand Up @@ -53,7 +56,7 @@ pub async fn load_package_tree(
.map(|cmd| cmd.atom.clone())
}),
webc_fs: Arc::new(fs),
commands: Arc::new(RwLock::new(commands)),
commands,
uses: Vec::new(),
module_memory_footprint,
file_system_memory_footprint,
Expand Down Expand Up @@ -191,10 +194,9 @@ fn legacy_atom_hack(webc: &Container, command_name: &str) -> Option<BinaryPackag
async fn used_packages(
loader: &impl PackageLoader,
pkg: &ResolvedPackage,
summaries: &HashMap<PackageId, Summary>,
graph: &DependencyGraph,
) -> Result<HashMap<PackageId, Container>, Error> {
let mut packages = HashSet::new();
packages.insert(pkg.root_package.clone());

for loc in pkg.commands.values() {
packages.insert(loc.package.clone());
Expand All @@ -204,9 +206,18 @@ async fn used_packages(
packages.insert(mapping.package.clone());
}

// We don't need to download the root package
packages.remove(&pkg.root_package);

let packages: FuturesUnordered<_> = packages
.into_iter()
.map(|id| async { loader.load(&summaries[&id]).await.map(|webc| (id, webc)) })
.map(|id| async {
let summary = Summary {
pkg: graph.package_info[&id].clone(),
dist: graph.distribution[&id].clone(),
};
loader.load(&summary).await.map(|webc| (id, webc))
})
.collect();

let packages: HashMap<PackageId, Container> = packages.try_collect().await?;
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 @@ -6,7 +6,7 @@ use std::{

use semver::Version;

use crate::runtime::resolver::{SourceId, Summary};
use crate::runtime::resolver::{DistributionInfo, PackageInfo, SourceId};

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Resolution {
Expand Down Expand Up @@ -58,7 +58,8 @@ impl Display for PackageId {
pub struct DependencyGraph {
pub root: PackageId,
pub dependencies: HashMap<PackageId, HashMap<String, PackageId>>,
pub summaries: HashMap<PackageId, Summary>,
pub package_info: HashMap<PackageId, PackageInfo>,
pub distribution: HashMap<PackageId, DistributionInfo>,
}

#[derive(Debug, Clone, PartialEq, Eq)]
Expand Down
Loading

0 comments on commit c6b70d8

Please sign in to comment.