Skip to content

Commit

Permalink
Added a WasmerDir abstraction
Browse files Browse the repository at this point in the history
  • Loading branch information
Michael-F-Bryan committed Jun 20, 2023
1 parent 95c4352 commit 1dd7068
Show file tree
Hide file tree
Showing 10 changed files with 287 additions and 165 deletions.
28 changes: 8 additions & 20 deletions lib/cli/src/commands/add.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@ use std::process::{Command, Stdio};

use anyhow::{Context, Error};
use clap::Parser;
use wasmer_registry::{Bindings, ProgrammingLanguage, WasmerConfig};
use wasmer_registry::{Bindings, ProgrammingLanguage};

use crate::WasmerDir;

/// Add a Wasmer package's bindings to your application.
#[derive(Debug, Parser)]
pub struct Add {
/// The registry to fetch bindings from.
#[clap(long, env = "WASMER_REGISTRY")]
registry: Option<String>,
#[clap(flatten)]
wasmer_dir: WasmerDir,
/// Add the JavaScript bindings using "npm install".
#[clap(long, groups = &["bindings", "js"])]
npm: bool,
Expand All @@ -32,10 +33,11 @@ impl Add {
anyhow::ensure!(!self.packages.is_empty(), "No packages specified");

let registry = self
.registry()
.wasmer_dir
.registry_endpoint()
.context("Unable to determine which registry to use")?;

let bindings = self.lookup_bindings(&registry)?;
let bindings = self.lookup_bindings(registry.as_str())?;

let mut cmd = self.target()?.command(&bindings)?;
cmd.stdin(Stdio::null())
Expand Down Expand Up @@ -71,20 +73,6 @@ impl Add {
Ok(bindings_to_add)
}

fn registry(&self) -> Result<String, Error> {
match &self.registry {
Some(r) => Ok(r.clone()),
None => {
let wasmer_dir =
WasmerConfig::get_wasmer_dir().map_err(|e| anyhow::anyhow!("{e}"))?;
let cfg = WasmerConfig::from_file(&wasmer_dir)
.map_err(Error::msg)
.context("Unable to load Wasmer config file")?;
Ok(cfg.registry.get_current_registry())
}
}
}

fn target(&self) -> Result<Target, Error> {
match (self.pip, self.npm, self.yarn) {
(false, false, false) => Err(anyhow::anyhow!(
Expand Down
46 changes: 11 additions & 35 deletions lib/cli/src/commands/config.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
use crate::VERSION;
use crate::{WasmerDir, VERSION};
use anyhow::{Context, Result};
use clap::Parser;
use std::env;
use std::path::PathBuf;
use std::str::ParseBoolError;
use wasmer_registry::WasmerConfig;

#[derive(Debug, Parser)]
/// The options for the `wasmer config` subcommand: `wasmer config get --OPTION` or `wasmer config set [FLAG]`
pub struct Config {
#[clap(flatten)]
wasmer_dir: WasmerDir,

#[clap(flatten)]
flags: Flags,
/// Subcommand for `wasmer config get | set`
Expand Down Expand Up @@ -168,29 +169,12 @@ impl Config {

fn inner_execute(&self) -> Result<()> {
if let Some(s) = self.set.as_ref() {
return s.execute();
return s.execute(&self.wasmer_dir);
}

let flags = &self.flags;

let key = "WASMER_DIR";
let wasmer_dir = env::var(key)
.ok()
.or_else(|| option_env!("WASMER_INSTALL_PREFIX").map(str::to_string))
.or_else(|| {
// Allowing deprecated function home_dir since it works fine,
// and will never be removed from std.
#[allow(deprecated)]
let dir = std::env::home_dir()?.join(".wasmer").to_str()?.to_string();

Some(dir)
})
.context(format!(
"failed to retrieve the {} environment variables",
key
))?;

let prefix = PathBuf::from(wasmer_dir);
let prefix = self.wasmer_dir.dir();

let prefixdir = prefix.display().to_string();
let bindir = prefix.join("bin").display().to_string();
Expand Down Expand Up @@ -233,9 +217,7 @@ impl Config {
}

if flags.config_path {
let wasmer_dir = WasmerConfig::get_wasmer_dir()
.map_err(|e| anyhow::anyhow!("could not find wasmer dir: {e}"))?;
let path = WasmerConfig::get_file_location(&wasmer_dir);
let path = WasmerConfig::get_file_location(self.wasmer_dir.dir());
println!("{}", path.display());
}

Expand All @@ -244,16 +226,10 @@ impl Config {
}

impl GetOrSet {
fn execute(&self) -> Result<()> {
let wasmer_dir = WasmerConfig::get_wasmer_dir()
.map_err(|e| anyhow::anyhow!("could not find wasmer dir: {e}"))?;
let config_file = WasmerConfig::get_file_location(&wasmer_dir);
let mut config = WasmerConfig::from_file(&wasmer_dir).map_err(|e| {
anyhow::anyhow!(
"could not find config file {e} at {}",
config_file.display()
)
})?;
fn execute(&self, wasmer_dir: &WasmerDir) -> Result<()> {
let config_file = WasmerConfig::get_file_location(wasmer_dir.dir());
let mut config = wasmer_dir.config()?;

match self {
GetOrSet::Get(g) => match g {
RetrievableConfigField::RegistryUrl => {
Expand Down
11 changes: 8 additions & 3 deletions lib/cli/src/commands/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ use indexmap::IndexMap;
use std::collections::HashMap;
use std::path::Path;
use std::path::PathBuf;
use wasmer_registry::WasmerConfig;

use crate::WasmerDir;

static NOTE: &str = "# See more keys and definitions at https://docs.wasmer.io/registry/manifest";

Expand All @@ -14,6 +15,9 @@ const NEWLINE: &str = if cfg!(windows) { "\r\n" } else { "\n" };
/// CLI args for the `wasmer init` command
#[derive(Debug, Parser)]
pub struct Init {
#[clap(flatten)]
wasmer_dir: WasmerDir,

/// Initialize wasmer.toml for a library package
#[clap(long, group = "crate-type")]
pub lib: bool,
Expand Down Expand Up @@ -136,6 +140,7 @@ impl Init {
self.template.as_ref(),
self.include.as_slice(),
self.quiet,
self.wasmer_dir.dir(),
)?;

if let Some(parent) = target_file.parent() {
Expand Down Expand Up @@ -347,6 +352,7 @@ fn construct_manifest(
template: Option<&Template>,
include_fs: &[String],
quiet: bool,
wasmer_dir: &Path,
) -> Result<wasmer_toml::Manifest, anyhow::Error> {
if let Some(ct) = cargo_toml.as_ref() {
let msg = format!(
Expand All @@ -365,9 +371,8 @@ fn construct_manifest(
.map(|p| &p.name)
.unwrap_or(fallback_package_name)
});
let wasmer_dir = WasmerConfig::get_wasmer_dir().map_err(|e| anyhow::anyhow!("{e}"))?;
let namespace = namespace.or_else(|| {
wasmer_registry::whoami(&wasmer_dir, None, None)
wasmer_registry::whoami(wasmer_dir, None, None)
.ok()
.map(|o| o.1)
});
Expand Down
148 changes: 92 additions & 56 deletions lib/cli/src/commands/login.rs
Original file line number Diff line number Diff line change
@@ -1,86 +1,122 @@
use std::path::PathBuf;

use clap::Parser;
#[cfg(not(test))]
use dialoguer::Input;
use wasmer_registry::WasmerConfig;

use crate::{Registry, WasmerDir};

/// Subcommand for listing packages
#[derive(Debug, Clone, Parser)]
pub struct Login {
/// Registry to log into (default: wasmer.io)
#[clap(long, default_value = "wasmer.io")]
pub registry: String,
/// Login token
#[clap(name = "TOKEN")]
/// Set Wasmer's home directory
#[clap(long, env = "WASMER_DIR", default_value = crate::WASMER_DIR.as_os_str())]
pub wasmer_dir: PathBuf,
/// The registry to fetch packages from (inferred from the environment by
/// default)
#[clap(long, env = "WASMER_REGISTRY")]
pub registry: Option<Registry>,
/// The API token to use when communicating with the registry (inferred from
/// the environment by default)
pub token: Option<String>,
}

impl Login {
fn get_token_or_ask_user(&self) -> Result<String, std::io::Error> {
match self.token.as_ref() {
Some(s) => Ok(s.clone()),
None => {
let registry_host = wasmer_registry::format_graphql(&self.registry);
let registry_tld = tldextract::TldExtractor::new(tldextract::TldOption::default())
.extract(&registry_host)
.map_err(|e| {
std::io::Error::new(
std::io::ErrorKind::Other,
format!("Invalid registry for login {}: {e}", self.registry),
)
})?;
let login_prompt = match (
registry_tld.domain.as_deref(),
registry_tld.suffix.as_deref(),
) {
(Some(d), Some(s)) => {
format!("Please paste the login token from https://{d}.{s}/settings/access-tokens")
}
_ => "Please paste the login token".to_string(),
};
#[cfg(test)]
{
Ok(login_prompt)
}
#[cfg(not(test))]
{
Input::new().with_prompt(&login_prompt).interact_text()
}
fn get_token_or_ask_user(&self, wasmer_dir: &WasmerDir) -> Result<String, anyhow::Error> {
if let Some(token) = &self.token {
return Ok(token.clone());
}

let registry_host = wasmer_dir.registry_endpoint()?;
let registry_tld = tldextract::TldExtractor::new(tldextract::TldOption::default())
.extract(registry_host.as_str())
.map_err(|e| {
std::io::Error::new(
std::io::ErrorKind::Other,
format!("Invalid registry for login {}: {e}", registry_host),
)
})?;
let login_prompt = match (
registry_tld.domain.as_deref(),
registry_tld.suffix.as_deref(),
) {
(Some(d), Some(s)) => {
format!("Please paste the login token from https://{d}.{s}/settings/access-tokens")
}
_ => "Please paste the login token".to_string(),
};
#[cfg(test)]
{
Ok(login_prompt)
}
#[cfg(not(test))]
{
let token = Input::new().with_prompt(&login_prompt).interact_text()?;
Ok(token)
}
}

fn wasmer_dir(&self) -> WasmerDir {
WasmerDir::new(
self.wasmer_dir.clone(),
self.registry.clone(),
self.token.clone(),
)
}

/// execute [List]
pub fn execute(&self) -> Result<(), anyhow::Error> {
let token = self.get_token_or_ask_user()?;
let wasmer_dir =
WasmerConfig::get_wasmer_dir().map_err(|e| anyhow::anyhow!("no wasmer dir: {e}"))?;
match wasmer_registry::login::login_and_save_token(&wasmer_dir, &self.registry, &token)? {
let wasmer_dir = self.wasmer_dir();
let token = self.get_token_or_ask_user(&wasmer_dir)?;

let registry = wasmer_dir.registry_endpoint()?;
match wasmer_registry::login::login_and_save_token(
wasmer_dir.dir(),
registry.as_str(),
&token,
)? {
Some(s) => println!("Login for Wasmer user {:?} saved", s),
None => println!(
"Error: no user found on registry {:?} with token {:?}. Token saved regardless.",
self.registry, token
registry, token
),
}
Ok(())
}
}

#[test]
fn test_login_2() {
let login = Login {
registry: "wasmer.wtf".to_string(),
token: None,
};
#[cfg(test)]
mod tests {
use tempfile::TempDir;

use super::*;

assert_eq!(
login.get_token_or_ask_user().unwrap(),
"Please paste the login token from https://wasmer.wtf/settings/access-tokens"
);
#[test]
fn interactive_login() {
let temp = TempDir::new().unwrap();
let login = Login {
registry: Some("wasmer.wtf".into()),
wasmer_dir: temp.path().to_path_buf(),
token: None,
};
let wasmer_dir = login.wasmer_dir();

let login = Login {
registry: "wasmer.wtf".to_string(),
token: Some("abc".to_string()),
};
assert_eq!(
login.get_token_or_ask_user(&wasmer_dir).unwrap(),
"Please paste the login token from https://wasmer.wtf/settings/access-tokens"
);
}

#[test]
fn login_with_token() {
let temp = TempDir::new().unwrap();
let login = Login {
registry: Some("wasmer.wtf".into()),
wasmer_dir: temp.path().to_path_buf(),
token: Some("abc".to_string()),
};
let wasmer_dir = login.wasmer_dir();

assert_eq!(login.get_token_or_ask_user().unwrap(), "abc");
assert_eq!(login.get_token_or_ask_user(&wasmer_dir).unwrap(), "abc");
}
}
Loading

0 comments on commit 1dd7068

Please sign in to comment.