Skip to content

Commit

Permalink
Added a proxy wasmer_wasix::Runtime implementation that'll show progr…
Browse files Browse the repository at this point in the history
…ess on startup
  • Loading branch information
Michael-F-Bryan committed Jun 9, 2023
1 parent f93f083 commit 79190f8
Show file tree
Hide file tree
Showing 3 changed files with 162 additions and 90 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

86 changes: 16 additions & 70 deletions lib/cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ clap-verbosity-flag = "2"
async-trait = "0.1.68"
tokio = { version = "1.28.1", features = ["macros", "rt-multi-thread"] }
once_cell = "1.17.1"
indicatif = "0.17.5"

# NOTE: Must use different features for clap because the "color" feature does not
# work on wasi due to the anstream dependency not compiling.
Expand Down Expand Up @@ -126,84 +127,29 @@ unix_mode = "0.1.3"
[features]
# Don't add the compiler features in default, please add them on the Makefile
# since we might want to autoconfigure them depending on the availability on the host.
default = [
"sys",
"wat",
"wast",
"compiler",
"wasmer-artifact-create",
"static-artifact-create",
]
default = ["sys", "wat", "wast", "compiler", "wasmer-artifact-create", "static-artifact-create"]
backend = []
coredump = [
"wasm-coredump-builder",
]
sys = [
"compiler",
"wasmer-vm",
]
jsc = [
"backend",
"wasmer/jsc",
"wasmer/std"
]
coredump = ["wasm-coredump-builder"]
sys = ["compiler", "wasmer-vm"]
jsc = ["backend", "wasmer/jsc", "wasmer/std"]
wast = ["wasmer-wast"]
host-net = [ "virtual-net/host-net" ]
host-net = ["virtual-net/host-net"]
wat = ["wasmer/wat"]
compiler = [
"backend",
"wasmer/compiler",
"wasmer-compiler/translator",
"wasmer-compiler/compiler"
]
wasmer-artifact-create = ["compiler",
"wasmer/wasmer-artifact-load",
"wasmer/wasmer-artifact-create",
"wasmer-compiler/wasmer-artifact-load",
"wasmer-compiler/wasmer-artifact-create",
"wasmer-object",
]
static-artifact-create = ["compiler",
"wasmer/static-artifact-load",
"wasmer/static-artifact-create",
"wasmer-compiler/static-artifact-load",
"wasmer-compiler/static-artifact-create",
"wasmer-object",
]
wasmer-artifact-load = ["compiler",
"wasmer/wasmer-artifact-load",
"wasmer-compiler/wasmer-artifact-load",
]
static-artifact-load = ["compiler",
"wasmer/static-artifact-load",
"wasmer-compiler/static-artifact-load",
]
experimental-io-devices = [
"wasmer-wasix-experimental-io-devices",
]
singlepass = [
"wasmer-compiler-singlepass",
"compiler",
]
cranelift = [
"wasmer-compiler-cranelift",
"compiler",
]
llvm = [
"wasmer-compiler-llvm",
"compiler",
]
compiler = ["backend", "wasmer/compiler", "wasmer-compiler/translator", "wasmer-compiler/compiler"]
wasmer-artifact-create = ["compiler", "wasmer/wasmer-artifact-load", "wasmer/wasmer-artifact-create", "wasmer-compiler/wasmer-artifact-load", "wasmer-compiler/wasmer-artifact-create", "wasmer-object"]
static-artifact-create = ["compiler", "wasmer/static-artifact-load", "wasmer/static-artifact-create", "wasmer-compiler/static-artifact-load", "wasmer-compiler/static-artifact-create", "wasmer-object"]
wasmer-artifact-load = ["compiler", "wasmer/wasmer-artifact-load", "wasmer-compiler/wasmer-artifact-load"]
static-artifact-load = ["compiler", "wasmer/static-artifact-load", "wasmer-compiler/static-artifact-load"]
experimental-io-devices = ["wasmer-wasix-experimental-io-devices"]
singlepass = ["wasmer-compiler-singlepass", "compiler"]
cranelift = ["wasmer-compiler-cranelift", "compiler"]
llvm = ["wasmer-compiler-llvm", "compiler"]
disable-all-logging = ["wasmer-wasix/disable-all-logging", "log/release_max_level_off"]
headless = []
headless-minimal = ["headless", "disable-all-logging"]

# Optional
enable-serde = [
"wasmer/enable-serde",
"wasmer-vm/enable-serde",
"wasmer-compiler/enable-serde",
"wasmer-wasix/enable-serde",
]
enable-serde = ["wasmer/enable-serde", "wasmer-vm/enable-serde", "wasmer-compiler/enable-serde", "wasmer-wasix/enable-serde"]

[target.'cfg(target_os = "windows")'.dependencies]
colored = "2.0.0"
Expand Down
165 changes: 145 additions & 20 deletions lib/cli/src/commands/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use std::{
use anyhow::{Context, Error};
use clap::Parser;
use clap_verbosity_flag::WarnLevel;
use indicatif::{MultiProgress, ProgressBar};
use once_cell::sync::Lazy;
use sha2::{Digest, Sha256};
use tempfile::NamedTempFile;
Expand All @@ -33,7 +34,7 @@ use wasmer_registry::Package;
use wasmer_wasix::{
bin_factory::BinaryPackage,
runners::{MappedDirectory, Runner},
runtime::resolver::PackageSpecifier,
runtime::{package_loader::PackageLoader, resolver::PackageSpecifier},
WasiError,
};
use wasmer_wasix::{
Expand All @@ -48,6 +49,8 @@ use webc::{metadata::Manifest, Container};

use crate::{commands::run::wasi::Wasi, error::PrettyError, store::StoreOptions};

const TICK: Duration = Duration::from_millis(250);

static WASMER_HOME: Lazy<PathBuf> = Lazy::new(|| {
wasmer_registry::WasmerConfig::get_wasmer_dir()
.ok()
Expand Down Expand Up @@ -93,6 +96,7 @@ impl Run {

fn execute_inner(&self) -> Result<(), Error> {
crate::logging::set_up_logging(self.verbosity.log_level_filter());

let runtime = tokio::runtime::Builder::new_multi_thread()
.enable_all()
.build()?;
Expand All @@ -108,12 +112,23 @@ impl Run {
self.wasi
.prepare_runtime(store.engine().clone(), &self.wasmer_dir, handle)?;

let progress = MultiProgress::new();

// This is a slow operation, so let's temporarily wrap the runtime with
// something that displays progress
let monitoring_runtime = MonitoringRuntime::new(runtime, progress.clone());
let pb = progress.add(ProgressBar::new_spinner().with_message("Getting Ready..."));
pb.enable_steady_tick(TICK);

let target = self
.input
.resolve_target(&runtime)
.resolve_target(&monitoring_runtime, &monitoring_runtime.progress)
.with_context(|| format!("Unable to resolve \"{}\"", self.input))?;

let runtime: Arc<dyn Runtime + Send + Sync> = Arc::new(runtime);
pb.finish_and_clear();

let runtime: Arc<dyn Runtime + Send + Sync> = Arc::new(monitoring_runtime.runtime);

let result = {
match target {
ExecutableTarget::WebAssembly { module, path } => {
Expand All @@ -130,20 +145,6 @@ impl Run {
result
}

fn execute_target(
&self,
executable_target: ExecutableTarget,
runtime: Arc<dyn Runtime + Send + Sync>,
store: Store,
) -> Result<(), Error> {
match executable_target {
ExecutableTarget::WebAssembly { module, path } => {
self.execute_wasm(&path, &module, store, runtime)
}
ExecutableTarget::Package(pkg) => self.execute_webc(&pkg, runtime),
}
}

#[tracing::instrument(skip_all)]
fn execute_wasm(
&self,
Expand Down Expand Up @@ -469,10 +470,14 @@ impl PackageSource {
///
/// This will try to automatically download and cache any resources from the
/// internet.
fn resolve_target(&self, rt: &dyn Runtime) -> Result<ExecutableTarget, Error> {
fn resolve_target(
&self,
rt: &dyn Runtime,
progress: &MultiProgress,
) -> Result<ExecutableTarget, Error> {
match self {
PackageSource::File(path) => ExecutableTarget::from_file(path, rt),
PackageSource::Dir(d) => ExecutableTarget::from_dir(d, rt),
PackageSource::Dir(d) => ExecutableTarget::from_dir(d, rt, progress),
PackageSource::Package(pkg) => {
let pkg = rt
.task_manager()
Expand Down Expand Up @@ -549,10 +554,23 @@ enum ExecutableTarget {
impl ExecutableTarget {
/// Try to load a Wasmer package from a directory containing a `wasmer.toml`
/// file.
fn from_dir(dir: &Path, runtime: &dyn Runtime) -> Result<Self, Error> {
fn from_dir(
dir: &Path,
runtime: &dyn Runtime,
progress: &MultiProgress,
) -> Result<Self, Error> {
let pb = progress.add(
ProgressBar::new_spinner()
.with_message(format!("Loading \"{}\" into memory", dir.display())),
);
pb.enable_steady_tick(TICK);

let webc = construct_webc_in_memory(dir)?;
let container = Container::from_bytes(webc)?;

pb.finish_and_clear();
progress.remove(&pb);

let pkg = runtime
.task_manager()
.block_on(BinaryPackage::from_webc(&container, runtime))?;
Expand Down Expand Up @@ -757,3 +775,110 @@ fn get_exit_code(

None
}

#[derive(Debug)]
struct MonitoringRuntime<R> {
runtime: R,
progress: MultiProgress,
}

impl<R> MonitoringRuntime<R> {
fn new(runtime: R, progress: MultiProgress) -> Self {
MonitoringRuntime { runtime, progress }
}
}

impl<R: wasmer_wasix::Runtime + Send + Sync> wasmer_wasix::Runtime for MonitoringRuntime<R> {
fn networking(&self) -> &virtual_net::DynVirtualNetworking {
self.runtime.networking()
}

fn task_manager(&self) -> &Arc<dyn wasmer_wasix::VirtualTaskManager> {
self.runtime.task_manager()
}

fn package_loader(
&self,
) -> Arc<dyn wasmer_wasix::runtime::package_loader::PackageLoader + Send + Sync> {
let inner = self.runtime.package_loader();
Arc::new(MonitoringPackageLoader {
inner,
progress: self.progress.clone(),
})
}

fn module_cache(
&self,
) -> Arc<dyn wasmer_wasix::runtime::module_cache::ModuleCache + Send + Sync> {
self.runtime.module_cache()
}

fn source(&self) -> Arc<dyn wasmer_wasix::runtime::resolver::Source + Send + Sync> {
let inner = self.runtime.source();
Arc::new(MonitoringSource {
inner,
progress: self.progress.clone(),
})
}
}

#[derive(Debug)]
struct MonitoringSource {
inner: Arc<dyn wasmer_wasix::runtime::resolver::Source + Send + Sync>,
progress: MultiProgress,
}

#[async_trait::async_trait]
impl wasmer_wasix::runtime::resolver::Source for MonitoringSource {
async fn query(
&self,
package: &PackageSpecifier,
) -> Result<Vec<wasmer_wasix::runtime::resolver::PackageSummary>, Error> {
let pb = self
.progress
.add(ProgressBar::new_spinner().with_message(format!("Looking up {package}")));
pb.enable_steady_tick(TICK);

let result = self.inner.query(package).await;

pb.finish_and_clear();
self.progress.remove(&pb);

result
}
}

#[derive(Debug)]
struct MonitoringPackageLoader {
inner: Arc<dyn wasmer_wasix::runtime::package_loader::PackageLoader + Send + Sync>,
progress: MultiProgress,
}

#[async_trait::async_trait]
impl wasmer_wasix::runtime::package_loader::PackageLoader for MonitoringPackageLoader {
async fn load(
&self,
summary: &wasmer_wasix::runtime::resolver::PackageSummary,
) -> Result<Container, Error> {
let pkg_id = summary.package_id();
let pb = self
.progress
.add(ProgressBar::new_spinner().with_message(format!("Downloading {pkg_id}")));
pb.enable_steady_tick(TICK);

let result = self.inner.load(summary).await;

pb.finish_and_clear();
self.progress.remove(&pb);

result
}

async fn load_package_tree(
&self,
root: &Container,
resolution: &wasmer_wasix::runtime::resolver::Resolution,
) -> Result<BinaryPackage, Error> {
self.inner.load_package_tree(root, resolution).await
}
}

0 comments on commit 79190f8

Please sign in to comment.