use crate::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)]
pub struct Config {
#[clap(flatten)]
flags: Flags,
#[clap(subcommand)]
set: Option<GetOrSet>,
}
#[derive(Debug, Parser)]
pub struct Flags {
#[clap(long, conflicts_with = "pkg_config")]
prefix: bool,
#[clap(long, conflicts_with = "pkg_config")]
bindir: bool,
#[clap(long, conflicts_with = "pkg_config")]
includedir: bool,
#[clap(long, conflicts_with = "pkg_config")]
libdir: bool,
#[clap(long, conflicts_with = "pkg_config")]
libs: bool,
#[clap(long, conflicts_with = "pkg_config")]
cflags: bool,
#[clap(long, conflicts_with = "pkg_config")]
config_path: bool,
#[clap(long)]
pkg_config: bool,
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Parser)]
pub enum GetOrSet {
#[clap(subcommand)]
Get(RetrievableConfigField),
#[clap(subcommand)]
Set(StorableConfigField),
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Parser)]
pub enum RetrievableConfigField {
#[clap(name = "registry.url")]
RegistryUrl,
#[clap(name = "registry.token")]
RegistryToken,
#[clap(name = "telemetry.enabled")]
TelemetryEnabled,
#[clap(name = "update-notifications.enabled")]
UpdateNotificationsEnabled,
#[clap(name = "proxy.url")]
ProxyUrl,
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Parser)]
pub enum StorableConfigField {
#[clap(name = "registry.url")]
RegistryUrl(SetRegistryUrl),
#[clap(name = "registry.token")]
RegistryToken(SetRegistryToken),
#[clap(name = "telemetry.enabled")]
TelemetryEnabled(SetTelemetryEnabled),
#[clap(name = "update-notifications.enabled")]
UpdateNotificationsEnabled(SetUpdateNotificationsEnabled),
#[clap(name = "proxy.url")]
ProxyUrl(SetProxyUrl),
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Parser)]
pub struct SetRegistryUrl {
#[clap(name = "URL")]
pub url: String,
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Parser)]
pub struct SetRegistryToken {
#[clap(name = "TOKEN")]
pub token: String,
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Parser)]
pub struct SetUpdateNotificationsEnabled {
#[clap(name = "ENABLED")]
pub enabled: BoolString,
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct BoolString(pub bool);
impl std::str::FromStr for BoolString {
type Err = ParseBoolError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Self(bool::from_str(s)?))
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Parser)]
pub struct SetTelemetryEnabled {
#[clap(name = "ENABLED")]
pub enabled: BoolString,
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Parser)]
pub struct SetProxyUrl {
#[clap(name = "URL")]
pub url: String,
}
impl Config {
pub fn execute(&self) -> Result<()> {
self.inner_execute()
.context("failed to retrieve the wasmer config".to_string())
}
fn inner_execute(&self) -> Result<()> {
if let Some(s) = self.set.as_ref() {
return s.execute();
}
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(|| {
#[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 prefixdir = prefix.display().to_string();
let bindir = prefix.join("bin").display().to_string();
let includedir = prefix.join("include").display().to_string();
let libdir = prefix.join("lib").display().to_string();
let cflags = format!("-I{}", includedir);
let libs = format!("-L{} -lwasmer", libdir);
if flags.pkg_config {
println!("prefix={}", prefixdir);
println!("exec_prefix={}", bindir);
println!("includedir={}", includedir);
println!("libdir={}", libdir);
println!();
println!("Name: wasmer");
println!("Description: The Wasmer library for running WebAssembly");
println!("Version: {}", VERSION);
println!("Cflags: {}", cflags);
println!("Libs: {}", libs);
return Ok(());
}
if flags.prefix {
println!("{}", prefixdir);
}
if flags.bindir {
println!("{}", bindir);
}
if flags.includedir {
println!("{}", includedir);
}
if flags.libdir {
println!("{}", libdir);
}
if flags.libs {
println!("{}", libs);
}
if flags.cflags {
println!("{}", cflags);
}
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);
println!("{}", path.display());
}
Ok(())
}
}
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()
)
})?;
match self {
GetOrSet::Get(g) => match g {
RetrievableConfigField::RegistryUrl => {
println!("{}", config.registry.get_current_registry());
}
RetrievableConfigField::RegistryToken => {
if let Some(s) = config
.registry
.get_login_token_for_registry(&config.registry.get_current_registry())
{
println!("{s}");
}
}
RetrievableConfigField::TelemetryEnabled => {
println!("{:?}", config.telemetry_enabled);
}
RetrievableConfigField::UpdateNotificationsEnabled => {
println!("{:?}", config.update_notifications_enabled);
}
RetrievableConfigField::ProxyUrl => {
if let Some(s) = config.proxy.url.as_ref() {
println!("{s}");
} else {
println!("none");
}
}
},
GetOrSet::Set(s) => {
match s {
StorableConfigField::RegistryUrl(s) => {
config.registry.set_current_registry(&s.url);
let current_registry = config.registry.get_current_registry();
if let Some(u) = wasmer_registry::utils::get_username(¤t_registry)
.ok()
.and_then(|o| o)
{
println!(
"Successfully logged into registry {current_registry:?} as user {u:?}"
);
}
}
StorableConfigField::RegistryToken(t) => {
config.registry.set_login_token_for_registry(
&config.registry.get_current_registry(),
&t.token,
wasmer_registry::config::UpdateRegistry::LeaveAsIs,
);
}
StorableConfigField::TelemetryEnabled(t) => {
config.telemetry_enabled = t.enabled.0;
}
StorableConfigField::ProxyUrl(p) => {
if p.url == "none" || p.url.is_empty() {
config.proxy.url = None;
} else {
config.proxy.url = Some(p.url.clone());
}
}
StorableConfigField::UpdateNotificationsEnabled(u) => {
config.update_notifications_enabled = u.enabled.0;
}
}
config
.save(config_file)
.with_context(|| anyhow::anyhow!("could not save config file"))?;
}
}
Ok(())
}
}