use config::Config;
use walkdir::WalkDir;
use toml;
use errors::*;
use std::process::Command;
use std::env;
use std::path::{Path, PathBuf};
use std::fs::File;
use std::io::Read;
fn rustc() -> Command {
Command::new(env::var("RUSTC").as_ref().map(|s| &s[..]).unwrap_or("rustc"))
}
pub fn target_list() -> Result<Vec<String>> {
let stdout = rustc().args(&["--print", "target-list"]).output()?.stdout;
let stdout = String::from_utf8_lossy(&stdout);
Ok(stdout.split('\n')
.filter_map(|s| if s.is_empty() {
None
} else {
Some(s.to_owned())
})
.collect())
}
#[inline]
fn get_crate_name() -> Result<String> {
let mut toml_fd = File::open("Cargo.toml")?;
let mut toml = String::new();
let _ = toml_fd.read_to_string(&mut toml);
let value: toml::Value = toml.parse().unwrap();
let package_name = match value.lookup("package.name") {
Some(package_name) => {
package_name.as_str()
.unwrap()
.to_owned()
}
None => Err(Error::MissingPackageName)?,
};
Ok(package_name)
}
fn find_target(crate_name: &str, config: &Config) -> Result<PathBuf> {
let target_list = target_list()?;
let mut target = Path::new("target").to_path_buf();
match config.target {
Some(t) => {
target = target.join(t);
if t != config.base_target {
target = target.join(&config.base_target);
}
if config.example.is_some() {
target = target.join("examples");
}
}
None => {
for entry in WalkDir::new("target").max_depth(1) {
let entry = entry?;
let filename: String = entry.file_name().to_str().unwrap().to_string();
if target_list.contains(&filename) {
target = entry.path().to_path_buf();
break;
}
}
let base_target = if config.example.is_some() {
Path::new(&config.base_target).join(&"examples")
} else {
Path::new(&config.base_target).to_path_buf()
};
target = target.join(base_target);
}
}
let names = [crate_name.to_string(),
format!("lib{}.so", &crate_name),
format!("lib{}.rlib", &crate_name),
format!("lib{}.a", &crate_name)];
let targets: Vec<PathBuf> = names.iter()
.map(|name| target.join(&name))
.collect();
for target in &targets {
if target.exists() {
return Ok(target.clone());
}
}
Err(Error::NoTargetFoundFor(target_list))
}
pub struct Marksman {
pub crate_name: String,
target: PathBuf,
}
impl Marksman {
pub fn crate_name(&self) -> &str {
&self.crate_name
}
pub fn new(config: &Config) -> Result<Self> {
let crate_name = match config.crate_name {
Some(crate_name) => crate_name.to_owned(),
None => get_crate_name()?,
};
let target = match config.file {
Some(binary) => Path::new(binary).to_path_buf(),
None => {
let target_name = match config.example {
Some(example) => example,
None => &crate_name,
};
find_target(&target_name, &config)?
}
};
println!("target : {:?}", target);
Ok(Marksman {
crate_name: crate_name,
target: target,
})
}
pub fn take_aim(&self) -> Result<File> {
Ok(File::open(&self.target)?)
}
}