use crate::{
vyper::{Vyper, Vypers},
vyper_errors::VyperErrors,
};
use std::{
path::{Path, PathBuf},
process::Command,
};
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
pub struct NotInitialized;
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
pub struct Initialized;
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
pub struct Skip;
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
pub struct Ready;
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
pub struct Complete;
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
pub struct Venv<'a, State = NotInitialized> {
venv_path: &'a Path,
state: std::marker::PhantomData<State>,
}
impl<'a> Default for Venv<'a, NotInitialized> {
fn default() -> Self {
Self {
venv_path: Path::new("./venv"),
state: std::marker::PhantomData::<NotInitialized>,
}
}
}
impl<'a> Venv<'a, NotInitialized> {
pub fn new(venv_path: &'a Path) -> Venv<'a, NotInitialized> {
Self {
venv_path,
state: std::marker::PhantomData::<NotInitialized>,
}
}
pub fn init(self) -> Result<Venv<'a, Initialized>, VyperErrors> {
match self.venv_path.exists() {
true => Ok(Venv {
venv_path: self.venv_path,
state: std::marker::PhantomData::<Initialized>,
}),
false => {
let a = Command::new("mkdir").arg(self.venv_path).output()?;
if !a.status.success() {
Err(VyperErrors::DirError(
String::from_utf8_lossy(&a.stderr).to_string(),
))?
}
let b = Command::new("python3")
.arg("-m")
.arg("venv")
.arg(self.venv_path)
.output()?;
if !b.status.success() {
Err(VyperErrors::VenvError(
String::from_utf8_lossy(&b.stderr).to_string(),
))?
}
Ok(Venv {
venv_path: self.venv_path,
state: std::marker::PhantomData::<Initialized>,
})
}
}
}
pub fn skip() -> Venv<'a, Skip> {
Venv {
venv_path: Path::new("./venv"),
state: std::marker::PhantomData::<Skip>,
}
}
}
impl<'a> Venv<'a, Initialized> {
pub fn ivyper_venv(self, ver: Option<&'a str>) -> Result<Venv<'a, Ready>, VyperErrors> {
match ver {
Some(version) => {
if cfg!(target_os = "windows") {
let c = Command::new("./venv/scripts/pip3")
.arg("install")
.arg(format!("vyper=={}", version))
.output()?;
if !c.status.success() {
Err(VyperErrors::CompilerError(
String::from_utf8_lossy(&c.stderr).to_string(),
))?
}
println!("Version {} of Vyper has been installed", version);
} else {
let c = Command::new("./venv/bin/pip3")
.arg("install")
.arg(format!("vyper=={}", version))
.output()?;
if !c.status.success() {
Err(VyperErrors::PipError(
String::from_utf8_lossy(&c.stderr).to_string(),
))?
}
println!("Version {} of Vyper has been installed", version);
}
Ok(Venv {
venv_path: self.venv_path,
state: std::marker::PhantomData::<Ready>,
})
}
None => {
if cfg!(target_os = "windows") {
let c = Command::new("./venv/scripts/pip3")
.arg("install")
.arg("vyper")
.output()?;
if !c.status.success() {
Err(VyperErrors::PipError(
String::from_utf8_lossy(&c.stderr).to_string(),
))?
}
println!("The latest version of vyper has been installed");
} else {
let c = Command::new("./venv/bin/pip3")
.arg("install")
.arg("vyper")
.output()?;
if !c.status.success() {
Err(VyperErrors::PipError(
String::from_utf8_lossy(&c.stderr).to_string(),
))?
}
println!("The latest version of vyper has been installed");
}
Ok(Venv {
venv_path: self.venv_path,
state: std::marker::PhantomData::<Ready>,
})
}
}
}
pub fn try_ready(self) -> Result<Venv<'a, Ready>, VyperErrors> {
if cfg!(target_os = "windows") {
match self.venv_path.join("scripts/vyper").exists() {
true => Ok(Venv {
venv_path: self.venv_path,
state: std::marker::PhantomData::<Ready>,
}),
false => Err(VyperErrors::CompilerError(
"Vyper was not installed in venv".to_owned(),
))?,
}
} else {
match self.venv_path.join("bin/vyper").exists() {
true => Ok(Venv {
venv_path: self.venv_path,
state: std::marker::PhantomData::<Ready>,
}),
false => Err(VyperErrors::CompilerError(
"Vyper was not installed in venv".to_owned(),
))?,
}
}
}
}
impl<'a> Venv<'a, Skip> {
pub fn ivyper_pip(self, ver: Option<&'a str>) -> Result<Venv<Complete>, VyperErrors> {
match ver {
Some(version) => {
let c = Command::new("pip3")
.arg("install")
.arg(format!("vyper=={}", version))
.output()?;
if !c.status.success() {
Err(VyperErrors::PipError(
String::from_utf8_lossy(&c.stderr).to_string(),
))?
}
println!("Version {} of Vyper has been installed", version);
}
None => {
let c = Command::new("pip3").arg("install").arg("vyper").output()?;
if !c.status.success() {
Err(VyperErrors::PipError(
String::from_utf8_lossy(&c.stderr).to_string(),
))?
}
println!("The Latest Version of Vyper has been installed");
}
}
Ok(Venv {
venv_path: self.venv_path,
state: std::marker::PhantomData::<Complete>,
})
}
pub fn global_exists() -> bool {
Command::new("vyper").arg("-h").output().is_ok()
}
pub fn try_ready(self) -> Result<Venv<'a, Complete>, VyperErrors> {
match Self::global_exists() {
true => Ok(Venv {
venv_path: self.venv_path,
state: std::marker::PhantomData::<Complete>,
}),
false => Err(VyperErrors::CompilerError("Vyper not installed".to_owned()))?,
}
}
}
impl<'a> Venv<'a, Complete> {
pub fn vyper(self, path_to_contract: &'a Path) -> Vyper<'a> {
Vyper::new(path_to_contract)
}
pub fn vypers(self, paths: Vec<PathBuf>) -> Vypers {
Vypers::new(paths)
}
pub fn vyper_with_abi(self, path: &'a Path, abi: PathBuf) -> Vyper<'a> {
Vyper::with_abi(path, abi)
}
pub fn vypers_from_dir(self, path: PathBuf) -> Option<Vypers> {
Vypers::in_dir(path)
}
pub async fn vypers_from_workspace(self, path: PathBuf) -> Option<Vypers> {
Vypers::in_workspace(path).await
}
}
impl<'a> Venv<'a, Ready> {
pub fn vyper(self, path_to_contract: &'a Path) -> Vyper<'a> {
Vyper::with_venv(path_to_contract, self.venv_path)
}
pub fn vypers(self, paths: Vec<PathBuf>) -> Vypers {
Vypers::with_venv(paths, self.venv_path)
}
pub fn vyper_with_abi(self, path: &'a Path, abi: PathBuf) -> Vyper<'a> {
Vyper::with_venv_and_abi(path, self.venv_path, abi)
}
pub fn vypers_from_dir(self, path: PathBuf) -> Option<Vypers> {
let vyps = Vypers::in_dir(path);
vyps.map(|e| e.set_venv(self.venv_path.to_path_buf()))
}
pub async fn vypers_from_workspace(self, path: PathBuf) -> Option<Vypers> {
let vyps = Vypers::in_workspace(path).await;
vyps.map(|e| e.set_venv(self.venv_path.to_path_buf()))
}
}