Skip to content

Commit

Permalink
feat(cli): Add package build/download/unpack commands
Browse files Browse the repository at this point in the history
Adds a new CLI command for working with packages:

* package download: download a package from a registry
* build: build a package from a wasmer.toml manifest
* unpack: extract package contents
  • Loading branch information
theduke committed Nov 2, 2023
1 parent bfeab2b commit dcaa2c1
Show file tree
Hide file tree
Showing 11 changed files with 462 additions and 56 deletions.
6 changes: 4 additions & 2 deletions Cargo.lock

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

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ rust-version = "1.70"
version = "4.2.3"

[workspace.dependencies]
webc = { version = "5.5.1", default-features = false, features = ["package"] }
webc = { version = "5.8.0", default-features = false, features = ["package"] }
wasmer-toml = "0.8.0"

[build-dependencies]
Expand Down
60 changes: 10 additions & 50 deletions lib/cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,8 @@ once_cell = "1.17.1"
indicatif = "0.17.5"
opener = "0.6.1"
hyper = { version = "0.14.27", features = ["server"] }
http = "0.2.9"
futures = "0.3.29"

# 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 @@ -155,71 +157,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"]
wast = ["wasmer-wast"]
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",
]
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",
]
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"]

[dev-dependencies]
assert_cmd = "2.0.11"
Expand Down
13 changes: 11 additions & 2 deletions lib/cli/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ use crate::commands::CreateExe;
#[cfg(feature = "wast")]
use crate::commands::Wast;
use crate::commands::{
Add, Cache, Config, Init, Inspect, Login, Publish, Run, SelfUpdate, Validate, Whoami,
Add, Cache, CmdPackage, Config, Init, Inspect, Login, Publish, Run, SelfUpdate, Validate,
Whoami,
};
#[cfg(feature = "static-artifact-create")]
use crate::commands::{CreateObj, GenCHeader};
Expand Down Expand Up @@ -108,6 +109,11 @@ impl Args {
Some(Cmd::Init(init)) => init.execute(),
Some(Cmd::Login(login)) => login.execute(),
Some(Cmd::Publish(publish)) => publish.execute(),
Some(Cmd::Package(cmd)) => match cmd {
CmdPackage::Download(cmd) => cmd.execute(),
CmdPackage::Unpack(cmd) => cmd.execute(),
CmdPackage::Build(cmd) => cmd.execute(),
},
/*
Some(Cmd::Connect(connect)) => connect.execute(),
*/
Expand Down Expand Up @@ -258,7 +264,10 @@ enum Cmd {
#[clap(alias = "run-unstable")]
Run(Run),

// DEPLOY commands
#[clap(subcommand)]
Package(crate::commands::CmdPackage),

// Edge commands
/// Deploy apps to the Wasmer Edge.
Deploy(wasmer_deploy_cli::cmd::deploy::CmdDeploy),

Expand Down
3 changes: 2 additions & 1 deletion lib/cli/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ mod gen_c_header;
mod init;
mod inspect;
mod login;
mod package;
mod publish;
mod run;
mod self_update;
Expand All @@ -32,7 +33,7 @@ pub use create_exe::*;
#[cfg(feature = "wast")]
pub use wast::*;
pub use {
add::*, cache::*, config::*, init::*, inspect::*, login::*, publish::*, run::Run,
add::*, cache::*, config::*, init::*, inspect::*, login::*, package::*, publish::*, run::Run,
self_update::*, validate::*, whoami::*,
};
#[cfg(feature = "static-artifact-create")]
Expand Down
131 changes: 131 additions & 0 deletions lib/cli/src/commands/package/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
use std::path::PathBuf;

use anyhow::Context;

/// Extract contents from a package file to a directory.
#[derive(clap::Parser, Debug)]
pub struct CmdPackageBuild {
/// Path of the package or wasmer.toml manifest.
///
/// Defaults to current directory.
#[clap(short = 'p', long)]
package: Option<PathBuf>,

/// Output path for the package file.
/// Defaults to current directory + [name]-[version].webc.
#[clap(short = 'o', long)]
out: Option<PathBuf>,
}

impl CmdPackageBuild {
pub(crate) fn execute(&self) -> Result<(), anyhow::Error> {
let manifest_path = if let Some(p) = &self.package {
if p.is_dir() {
let manifest_path = p.join("wasmer.toml");
if !manifest_path.is_file() {
anyhow::bail!(
"Specified directory '{}' does not contain a wasmer.toml manifest",
p.display()
);
}
manifest_path
} else if p.is_file() {
p.clone()
} else {
anyhow::bail!(
"Specified path '{}' is not a file or directory",
p.display()
);
}
} else {
let dir = std::env::current_dir().context("could not get current directory")?;
let manifest_path = dir.join("wasmer.toml");
if !manifest_path.is_file() {
anyhow::bail!(
"Current directory '{}' does not contain a wasmer.toml manifest - specify a path with --package-dir",
dir.display()
);
}
manifest_path
};

let pkg = webc::wasmer_package::Package::from_manifest(&manifest_path)?;

let manifest = pkg
.manifest()
.package_annotation::<webc::metadata::annotations::Wapm>("wapm")
.context("could not load package metadata")?
.context("could not find package metadata")?;

let pkgname = manifest.name.replace("/", "-");
let name = format!("{}-{}.webc", pkgname, manifest.version,);
let out_path = if let Some(p) = &self.out {
if p.is_dir() {
p.join(name)
} else {
if let Some(parent) = p.parent() {
std::fs::create_dir_all(parent).context("could not create output directory")?;
}

p.to_owned()
}
} else {
std::env::current_dir()
.context("could not determine current directory")?
.join(name)
};

if out_path.exists() {
anyhow::bail!(
"Output path '{}' already exists - specify a different path with -o/--out",
out_path.display()
);
}

let data = pkg.serialize()?;
std::fs::write(&out_path, &data)
.with_context(|| format!("could not write contents to '{}'", out_path.display()))?;

eprintln!("Package written to '{}'", out_path.display());

Ok(())
}
}

#[cfg(test)]
mod tests {
use super::*;

/// Download a package from the dev registry.
#[test]
fn test_cmd_package_build() {
let dir = tempfile::tempdir().unwrap();
let path = dir.path();

std::fs::write(
path.join("wasmer.toml"),
r#"
[package]
name = "wasmer/hello"
version = "0.1.0"
description = "hello"
[fs]
"data" = "data"
"#,
)
.unwrap();

std::fs::create_dir(path.join("data")).unwrap();
std::fs::write(path.join("data").join("hello.txt"), "Hello, world!").unwrap();

let cmd = CmdPackageBuild {
package: Some(path.to_owned()),
out: Some(path.to_owned()),
};

cmd.execute().unwrap();

webc::Container::from_disk(path.join("wasmer-hello-0.1.0.webc")).unwrap();
}
}
Loading

0 comments on commit dcaa2c1

Please sign in to comment.