use std::{
env,
io::{self, Write},
mem,
path::{Display, Path, PathBuf},
process::ExitStatus,
};
use rustc_version::VersionMeta;
use toml::Value;
use crate::{
cargo,
cargo::{Config, Root, Rustflags, Subcommand},
cli::Args,
errors::*,
extensions::CommandExt,
flock::{FileLock, Filesystem},
util, CompilationMode,
};
pub fn run(
args: &Args,
cmode: &CompilationMode,
rustflags: Rustflags,
home: &Home,
meta: &VersionMeta,
config: Option<&Config>,
verbose: bool,
) -> Result<ExitStatus> {
let mut cmd = cargo::command();
cmd.args(args.all());
if args.subcommand() == Some(Subcommand::Doc) {
cmd.env(
"CARGO_ENCODED_RUSTDOCFLAGS",
cargo::rustdocflags(config, cmode.triple())?.encode(home),
);
}
if verbose {
writeln!(io::stderr(), "+ RUSTFLAGS={}", rustflags).ok();
}
cmd.env("CARGO_ENCODED_RUSTFLAGS", rustflags.encode(home));
let locks = (home.lock_ro(&meta.host), home.lock_ro(cmode.triple()));
let status = cmd.run_and_get_status(verbose)?;
mem::drop(locks);
Ok(status)
}
pub struct Home {
path: Filesystem,
}
impl Home {
pub fn display(&self) -> Display<'_> {
self.path.display()
}
fn path(&self, triple: &str) -> Filesystem {
self.path.join("lib").join("rustlib").join(triple)
}
pub fn lock_ro(&self, triple: &str) -> Result<FileLock> {
let fs = self.path(triple);
fs.open_ro(".sentinel", &format!("{}'s sysroot", triple))
.chain_err(|| format!("couldn't lock {}'s sysroot as read-only", triple))
}
pub fn lock_rw(&self, triple: &str) -> Result<FileLock> {
let fs = self.path(triple);
fs.open_rw(".sentinel", &format!("{}'s sysroot", triple))
.chain_err(|| format!("couldn't lock {}'s sysroot as read-only", triple))
}
}
pub fn home(cmode: &CompilationMode) -> Result<Home> {
let mut p = if let Some(h) = env::var_os("ZARGO_HOME") {
PathBuf::from(h)
} else {
dirs::home_dir()
.ok_or("couldn't find your home directory. Is $HOME set?")?
.join(".zargo")
};
if cmode.is_native() {
p.push("HOST");
}
Ok(Home {
path: Filesystem::new(p),
})
}
pub struct Toml {
table: Value,
}
impl Toml {
pub fn dependencies(&self) -> Option<&Value> {
self.table.get("dependencies")
}
pub fn target_dependencies(&self, target: &str) -> Option<&Value> {
self.table
.get("target")
.and_then(|t| t.get(target))
.and_then(|t| t.get("dependencies"))
}
pub fn patch(&self) -> Option<&Value> {
self.table.get("patch")
}
}
pub fn toml(root: &Root) -> Result<(Option<&Path>, Option<Toml>)> {
if let Some(p) = util::search(root.path(), "Zargo.toml") {
Ok((
Some(p),
util::parse(&p.join("Zargo.toml")).map(|t| Some(Toml { table: t }))?,
))
} else {
Ok((None, None))
}
}