Skip to content

Commit

Permalink
Merge pull request #5089 from wasmerio/run-433-cli-allow-synthesizing…
Browse files Browse the repository at this point in the history
…-a-wasmertoml-in-wasmer-package-unpack

feat(cli): Restore packages from webcs
  • Loading branch information
theduke authored Sep 16, 2024
2 parents e551595 + 6e81107 commit ec528e4
Show file tree
Hide file tree
Showing 15 changed files with 488 additions and 16 deletions.
24 changes: 19 additions & 5 deletions Cargo.lock

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

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ members = [
"lib/derive",
"lib/emscripten",
"lib/object",
"lib/package",
"lib/registry",
"lib/sys-utils",
"lib/types",
Expand Down Expand Up @@ -109,6 +110,7 @@ toml = {version = "0.5.9", features = ["preserve_order"]}
indexmap = "2"
serde_yaml = "0.9.34"
libc = { version = "^0.2", default-features = false }
pretty_assertions = "1.4.0"
base64 = "0.22.0"

[build-dependencies]
Expand Down
4 changes: 3 additions & 1 deletion lib/cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ wasmer-compiler-cranelift = { version = "=4.3.7", path = "../compiler-cranelift"
wasmer-compiler-singlepass = { version = "=4.3.7", path = "../compiler-singlepass", optional = true }
wasmer-compiler-llvm = { version = "=4.3.7", path = "../compiler-llvm", optional = true }
wasmer-emscripten = { version = "=4.3.7", path = "../emscripten" }
wasmer-package = { version = "=0.1.0", path = "../package" }

wasmer-vm = { version = "=4.3.7", path = "../vm", optional = true }
wasmer-wasix = { path = "../wasix", version = "=0.27.0", features = [
"logging",
Expand Down Expand Up @@ -276,7 +278,7 @@ unix_mode = "0.1.3"
[dev-dependencies]
assert_cmd = "2.0.11"
predicates = "3.0.3"
pretty_assertions = "1.3.0"
pretty_assertions.workspace = true

[target.'cfg(target_os = "windows")'.dependencies]
colored = "2.0.0"
Expand Down
45 changes: 40 additions & 5 deletions lib/cli/src/commands/package/unpack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,53 @@ use dialoguer::console::{style, Emoji};
use indicatif::ProgressBar;

/// Extract contents of a webc image to a directory.
///
/// See --format flag for available output formats.
#[derive(clap::Parser, Debug)]
pub struct PackageUnpack {
/// The output directory.
#[clap(short = 'o', long)]
out_dir: PathBuf,
pub out_dir: PathBuf,

/// Overwrite existing directories/files.
#[clap(long)]
overwrite: bool,
pub overwrite: bool,

/// Run the unpack command without any output
#[clap(long)]
pub quiet: bool,

/// Path to the package.
package_path: PathBuf,
pub package_path: PathBuf,

/// Output format.
///
/// * package
/// Restore a package directory with a wasmer.toml
/// NOTE: this conversion is lossy, because webcs don't store the original
/// wasmer.toml and the full contents can not be restored.
///
/// * webc
/// Directly unpack the webc contents.
/// - Volumes will be placed in subdirectories.
/// - atoms will be placed in the root directory
/// - the full webc manifest will be placed in a manifest.json file
#[clap(short, long, default_value = "package")]
pub format: Format,
}

static PACKAGE_EMOJI: Emoji<'_, '_> = Emoji("📦 ", "");
static EXTRACTED_TO_EMOJI: Emoji<'_, '_> = Emoji("📂 ", "");

/// Webc unpack format.
#[derive(clap::ValueEnum, Clone, Debug)]
pub enum Format {
/// See [`PackageUnpack::format`] for details.
Package,
/// See [`PackageUnpack::format`] for details.
Webc,
}

impl PackageUnpack {
pub(crate) fn execute(&self) -> Result<(), anyhow::Error> {
// Setup the progress bar
Expand All @@ -52,8 +78,16 @@ impl PackageUnpack {
std::fs::create_dir_all(outdir)
.with_context(|| format!("could not create output directory '{}'", outdir.display()))?;

pkg.unpack(outdir, self.overwrite)
.with_context(|| "could not extract package".to_string())?;
match self.format {
Format::Package => {
wasmer_package::convert::webc_to_package_dir(&pkg, outdir)
.with_context(|| "could not extract package")?;
}
Format::Webc => {
pkg.unpack(outdir, self.overwrite)
.with_context(|| "could not extract package".to_string())?;
}
}

pb.println(format!(
"{} {}Extracted package contents to '{}'",
Expand Down Expand Up @@ -89,6 +123,7 @@ mod tests {
overwrite: false,
package_path,
quiet: true,
format: Format::Webc,
};

cmd.execute().unwrap();
Expand Down
2 changes: 1 addition & 1 deletion lib/config/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,6 @@ hex = "0.4.3"
ciborium = "0.2.2"

[dev-dependencies]
pretty_assertions = "1.4.0"
pretty_assertions.workspace = true
serde_json = "1.0.116"
tempfile = "3.3.0"
14 changes: 14 additions & 0 deletions lib/config/src/package/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,10 @@ pub struct Package {
}

impl Package {
pub fn new_empty() -> Self {
PackageBuilder::default().build().unwrap()
}

/// Create a [`PackageBuilder`] populated with all mandatory fields.
pub fn builder(
name: impl Into<String>,
Expand Down Expand Up @@ -732,6 +736,16 @@ pub struct Manifest {
}

impl Manifest {
pub fn new_empty() -> Self {
Self {
package: None,
dependencies: HashMap::new(),
fs: IndexMap::new(),
modules: Vec::new(),
commands: Vec::new(),
}
}

/// Create a [`ManifestBuilder`] populated with all mandatory fields.
pub fn builder(package: Package) -> ManifestBuilder {
ManifestBuilder::new(package)
Expand Down
21 changes: 21 additions & 0 deletions lib/package/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
[package]
name = "wasmer-package"
version = "0.1.0"

authors.workspace = true
edition.workspace = true
homepage.workspace = true
license.workspace = true
repository.workspace = true
rust-version.workspace = true

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
webc.workspace = true
wasmer-config = { version = "0.8.0", path = "../config" }
toml = "0.8.0"

[dev-dependencies]
pretty_assertions.workspace = true
tempfile = "3.12.0"
47 changes: 47 additions & 0 deletions lib/package/src/convert/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
use std::sync::Arc;

#[derive(Clone, Debug)]
pub struct ConversionError {
message: String,
cause: Option<Arc<dyn std::error::Error + Send + Sync>>,
}

impl ConversionError {
pub fn msg(msg: impl Into<String>) -> Self {
Self {
message: msg.into(),
cause: None,
}
}

pub fn with_cause(
msg: impl Into<String>,
cause: impl std::error::Error + Send + Sync + 'static,
) -> Self {
Self {
message: msg.into(),
cause: Some(Arc::new(cause)),
}
}
}

impl std::fmt::Display for ConversionError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "could not convert manifest: {}", self.message)?;
if let Some(cause) = &self.cause {
write!(f, " (cause: {})", cause)?;
}

Ok(())
}
}

impl std::error::Error for ConversionError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
if let Some(e) = &self.cause {
Some(e)
} else {
None
}
}
}
4 changes: 4 additions & 0 deletions lib/package/src/convert/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
mod error;
mod webc_to_package;

pub use self::{error::ConversionError, webc_to_package::webc_to_package_dir};
Loading

0 comments on commit ec528e4

Please sign in to comment.