vibranium 0.1.0

A library that offers APIs to build tools for creating decentralized applications.
Documentation
pub mod error;
pub mod support;

use std::process::{Child, Command, Stdio};
use crate::config;
use crate::utils;
use support::SupportedCompilers;
use glob::glob;

#[derive(Debug)]
pub struct CompilerConfig {
  pub compiler: Option<String>,
  pub compiler_options: Option<Vec<String>>,
}

pub struct Compiler<'a> {
  config: &'a config::Config,
}

impl<'a> Compiler<'a> {
  pub fn new(config: &config::Config) -> Compiler {
    Compiler {
      config
    }
  }

  pub fn compile(&self, config: CompilerConfig) -> Result<Child, error::CompilerError> {
    let project_config = self.config.read().map_err(error::CompilerError::InvalidConfig)?;
    let artifacts_dir = self.config.project_path.join(&project_config.sources.artifacts);

    let compiler = config.compiler.unwrap_or_else(|| {
      match &project_config.compiler {
        Some(config) => config.cmd.clone().unwrap_or_else(|| SupportedCompilers::Solc.executable()),
        None => SupportedCompilers::Solc.executable(),
      }
    });

    let mut compiler_options = match &config.compiler_options {
      Some(options) => {
        match compiler.parse() {
          Ok(SupportedCompilers::Solc) => utils::merge_cli_options(
            support::default_options_from(SupportedCompilers::Solc),
            options.to_vec()
          ),
          Ok(SupportedCompilers::SolcJs) => utils::merge_cli_options(
            support::default_options_from(SupportedCompilers::SolcJs),
            options.to_vec()
          ),
          Err(_err) => options.to_vec(),
        }
      }
      None => {
        match project_config.compiler {
          Some(config) => config.options.unwrap_or_else(|| try_default_options_from(&compiler)),
          None => try_default_options_from(&compiler)
        }
      }
    };

    if compiler_options.is_empty() {
      if let Err(err) = compiler.parse::<SupportedCompilers>() {
        Err(err)?
      }
    }

    compiler_options.push(artifacts_dir.to_string_lossy().to_string());

    for pattern in &project_config.sources.smart_contracts {
      let mut full_pattern = self.config.project_path.clone();
      full_pattern.push(&pattern);
      for entry in glob(&full_pattern.to_str().unwrap()).unwrap().filter_map(Result::ok) {
        compiler_options.push(entry.to_string_lossy().to_string());
      }
    }

    compiler_options.insert(0, compiler.to_string());

    let (shell, shell_opt) = if cfg!(target_os = "windows") {
      ("cmd", "/C")
    } else {
      ("sh", "-c")
    };

    info!("Compiling project using command: {} {} {}", &shell, &shell_opt, compiler_options.join(" "));

    Command::new(shell)
      .arg(shell_opt)
      .arg(&compiler_options.join(" "))
      .stdout(Stdio::piped())
      .stderr(Stdio::piped())
      .spawn()
      .map_err(error::CompilerError::Io)
  }
}

fn try_default_options_from(compiler: &str) -> Vec<String> {
  match compiler.parse() {
    Ok(SupportedCompilers::Solc) => support::default_options_from(SupportedCompilers::Solc),
    Ok(SupportedCompilers::SolcJs) => support::default_options_from(SupportedCompilers::SolcJs),
    Err(_err) => vec![],
  }
}