Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Download and install packages via .tar.gz URLs and improve installation error message #3416

Merged
merged 18 commits into from
Dec 12, 2022
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 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 Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -549,7 +549,7 @@ test-examples:
$(CARGO_BINARY) test $(CARGO_TARGET) --release $(compiler_features) --features wasi --examples

test-integration-cli:
$(CARGO_BINARY) test $(CARGO_TARGET) --features webc_runner --no-fail-fast -p wasmer-integration-tests-cli -- --nocapture
$(CARGO_BINARY) test $(CARGO_TARGET) --features webc_runner --no-fail-fast -p wasmer-integration-tests-cli -- --nocapture --test-threads=1

test-integration-ios:
$(CARGO_BINARY) test $(CARGO_TARGET) --features webc_runner -p wasmer-integration-tests-ios
Expand Down
1 change: 1 addition & 0 deletions lib/cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ webc = { version = "3.0.1", optional = true }
isatty = "0.1.9"
dialoguer = "0.10.2"
tldextract = "0.6.0"
hex = "0.4.3"

[build-dependencies]
chrono = { version = "^0.4", default-features = false, features = [ "std", "clock" ] }
Expand Down
210 changes: 0 additions & 210 deletions lib/cli/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ use crate::commands::{
};
use crate::error::PrettyError;
use clap::{CommandFactory, ErrorKind, Parser};
use std::{fmt, str::FromStr};

#[derive(Parser, Debug)]
#[cfg_attr(
Expand Down Expand Up @@ -243,218 +242,9 @@ fn wasmer_main_inner() -> Result<(), anyhow::Error> {
}
};

// Check if the file is a package name
if let WasmerCLIOptions::Run(r) = &options {
#[cfg(not(feature = "debug"))]
let debug = false;
#[cfg(feature = "debug")]
let debug = r.options.debug;
return crate::commands::try_run_package_or_file(&args, r, debug);
}

options.execute()
}

#[derive(Debug, Clone, PartialEq, Default)]
pub(crate) struct SplitVersion {
pub(crate) original: String,
pub(crate) registry: Option<String>,
pub(crate) package: String,
pub(crate) version: Option<String>,
pub(crate) command: Option<String>,
}

impl fmt::Display for SplitVersion {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let version = self.version.as_deref().unwrap_or("latest");
let command = self
.command
.as_ref()
.map(|s| format!(":{s}"))
.unwrap_or_default();
write!(f, "{}@{version}{command}", self.package)
}
}

#[test]
fn test_split_version() {
assert_eq!(
SplitVersion::parse("registry.wapm.io/graphql/python/python").unwrap(),
SplitVersion {
original: "registry.wapm.io/graphql/python/python".to_string(),
registry: Some("https://registry.wapm.io/graphql".to_string()),
package: "python/python".to_string(),
version: None,
command: None,
}
);
assert_eq!(
SplitVersion::parse("registry.wapm.io/python/python").unwrap(),
SplitVersion {
original: "registry.wapm.io/python/python".to_string(),
registry: Some("https://registry.wapm.io/graphql".to_string()),
package: "python/python".to_string(),
version: None,
command: None,
}
);
assert_eq!(
SplitVersion::parse("namespace/name@version:command").unwrap(),
SplitVersion {
original: "namespace/name@version:command".to_string(),
registry: None,
package: "namespace/name".to_string(),
version: Some("version".to_string()),
command: Some("command".to_string()),
}
);
assert_eq!(
SplitVersion::parse("namespace/name@version").unwrap(),
SplitVersion {
original: "namespace/name@version".to_string(),
registry: None,
package: "namespace/name".to_string(),
version: Some("version".to_string()),
command: None,
}
);
assert_eq!(
SplitVersion::parse("namespace/name").unwrap(),
SplitVersion {
original: "namespace/name".to_string(),
registry: None,
package: "namespace/name".to_string(),
version: None,
command: None,
}
);
assert_eq!(
SplitVersion::parse("registry.wapm.io/namespace/name").unwrap(),
SplitVersion {
original: "registry.wapm.io/namespace/name".to_string(),
registry: Some("https://registry.wapm.io/graphql".to_string()),
package: "namespace/name".to_string(),
version: None,
command: None,
}
);
assert_eq!(
format!("{}", SplitVersion::parse("namespace").unwrap_err()),
"Invalid package version: \"namespace\"".to_string(),
);
}

impl SplitVersion {
pub fn parse(s: &str) -> Result<SplitVersion, anyhow::Error> {
s.parse()
}
}

impl FromStr for SplitVersion {
type Err = anyhow::Error;

fn from_str(s: &str) -> Result<Self, Self::Err> {
let command = WasmerCLIOptions::command();
let mut prohibited_package_names = command.get_subcommands().map(|s| s.get_name());

let re1 = regex::Regex::new(r#"(.*)/(.*)@(.*):(.*)"#).unwrap();
let re2 = regex::Regex::new(r#"(.*)/(.*)@(.*)"#).unwrap();
let re3 = regex::Regex::new(r#"(.*)/(.*)"#).unwrap();
let re4 = regex::Regex::new(r#"(.*)/(.*):(.*)"#).unwrap();

let mut no_version = false;

let captures = if re1.is_match(s) {
re1.captures(s)
.map(|c| {
c.iter()
.flatten()
.map(|m| m.as_str().to_owned())
.collect::<Vec<_>>()
})
.unwrap_or_default()
} else if re2.is_match(s) {
re2.captures(s)
.map(|c| {
c.iter()
.flatten()
.map(|m| m.as_str().to_owned())
.collect::<Vec<_>>()
})
.unwrap_or_default()
} else if re4.is_match(s) {
no_version = true;
re4.captures(s)
.map(|c| {
c.iter()
.flatten()
.map(|m| m.as_str().to_owned())
.collect::<Vec<_>>()
})
.unwrap_or_default()
} else if re3.is_match(s) {
re3.captures(s)
.map(|c| {
c.iter()
.flatten()
.map(|m| m.as_str().to_owned())
.collect::<Vec<_>>()
})
.unwrap_or_default()
} else {
return Err(anyhow::anyhow!("Invalid package version: {s:?}"));
};

let mut namespace = match captures.get(1).cloned() {
Some(s) => s,
None => {
return Err(anyhow::anyhow!(
"Invalid package version: {s:?}: no namespace"
))
}
};

let name = match captures.get(2).cloned() {
Some(s) => s,
None => return Err(anyhow::anyhow!("Invalid package version: {s:?}: no name")),
};

let mut registry = None;
if namespace.contains('/') {
let (r, n) = namespace.rsplit_once('/').unwrap();
let mut real_registry = r.to_string();
if !real_registry.ends_with("graphql") {
real_registry = format!("{real_registry}/graphql");
}
if !real_registry.contains("://") {
real_registry = format!("https://{real_registry}");
}
registry = Some(real_registry);
namespace = n.to_string();
}

let sv = SplitVersion {
original: s.to_string(),
registry,
package: format!("{namespace}/{name}"),
version: if no_version {
None
} else {
captures.get(3).cloned()
},
command: captures.get(if no_version { 3 } else { 4 }).cloned(),
};

let svp = sv.package.clone();
anyhow::ensure!(
!prohibited_package_names.any(|s| s == sv.package.trim()),
"Invalid package name {svp:?}"
);

Ok(sv)
}
}

fn print_help(verbose: bool) -> Result<(), anyhow::Error> {
let mut cmd = WasmerCLIOptions::command();
if verbose {
Expand Down
8 changes: 3 additions & 5 deletions lib/cli/src/commands/add.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ use anyhow::{Context, Error};
use clap::Parser;
use wasmer_registry::{Bindings, PartialWapmConfig, ProgrammingLanguage};

use crate::cli::SplitVersion;

/// Add a WAPM package's bindings to your application.
#[derive(Debug, Parser)]
pub struct Add {
Expand All @@ -26,7 +24,7 @@ pub struct Add {
pip: bool,
/// The packages to add (e.g. "wasmer/[email protected]" or "python/python")
#[clap(parse(try_from_str))]
packages: Vec<SplitVersion>,
packages: Vec<wasmer_registry::Package>,
}

impl Add {
Expand Down Expand Up @@ -103,11 +101,11 @@ impl Add {

fn lookup_bindings_for_package(
registry: &str,
pkg: &SplitVersion,
pkg: &wasmer_registry::Package,
language: &ProgrammingLanguage,
) -> Result<Bindings, Error> {
let all_bindings =
wasmer_registry::list_bindings(registry, &pkg.package, pkg.version.as_deref())?;
wasmer_registry::list_bindings(registry, &pkg.package(), pkg.version.as_deref())?;

match all_bindings.iter().find(|b| b.language == *language) {
Some(b) => {
Expand Down
Loading