use crate::cmd::{Command, MountKind, Runnable, SandboxBuilder};
use crate::prepare::Prepare;
use crate::{Crate, Toolchain, Workspace};
use failure::Error;
use remove_dir_all::remove_dir_all;
use std::path::PathBuf;
use std::vec::Vec;
#[derive(Clone)]
pub(crate) struct CratePatch {
pub(crate) name: String,
pub(crate) uri: String,
pub(crate) branch: String,
}
pub struct BuildDirectory {
workspace: Workspace,
name: String,
}
pub struct BuildBuilder<'a> {
build_dir: &'a mut BuildDirectory,
toolchain: &'a Toolchain,
krate: &'a Crate,
sandbox: SandboxBuilder,
patches: Vec<CratePatch>,
}
impl<'a> BuildBuilder<'a> {
pub fn patch_with_git(mut self, name: &str, uri: &str, branch: &str) -> Self {
self.patches.push(CratePatch {
name: name.into(),
uri: uri.into(),
branch: branch.into(),
});
self
}
pub fn run<R, F: FnOnce(&Build) -> Result<R, Error>>(self, f: F) -> Result<R, Error> {
self.build_dir
.run(self.toolchain, self.krate, self.sandbox, self.patches, f)
}
}
impl BuildDirectory {
pub(crate) fn new(workspace: Workspace, name: &str) -> Self {
Self {
workspace,
name: name.into(),
}
}
pub fn build<'a>(
&'a mut self,
toolchain: &'a Toolchain,
krate: &'a Crate,
sandbox: SandboxBuilder,
) -> BuildBuilder {
BuildBuilder {
build_dir: self,
toolchain,
krate,
sandbox,
patches: Vec::new(),
}
}
pub(crate) fn run<R, F: FnOnce(&Build) -> Result<R, Error>>(
&mut self,
toolchain: &Toolchain,
krate: &Crate,
sandbox: SandboxBuilder,
patches: Vec<CratePatch>,
f: F,
) -> Result<R, Error> {
let source_dir = self.source_dir();
if source_dir.exists() {
remove_dir_all(&source_dir)?;
}
let mut prepare = Prepare::new(&self.workspace, toolchain, krate, &source_dir, patches);
prepare.prepare()?;
std::fs::create_dir_all(self.target_dir())?;
let res = f(&Build {
dir: self,
toolchain,
sandbox,
})?;
remove_dir_all(&source_dir)?;
Ok(res)
}
pub fn purge(&mut self) -> Result<(), Error> {
let build_dir = self.build_dir();
if build_dir.exists() {
remove_dir_all(build_dir)?;
}
Ok(())
}
fn build_dir(&self) -> PathBuf {
self.workspace.builds_dir().join(&self.name)
}
fn source_dir(&self) -> PathBuf {
self.build_dir().join("source")
}
fn target_dir(&self) -> PathBuf {
self.build_dir().join("target")
}
}
pub struct Build<'b> {
dir: &'b BuildDirectory,
toolchain: &'b Toolchain,
sandbox: SandboxBuilder,
}
impl Build<'_> {
pub fn cmd<R: Runnable>(&self, bin: R) -> Command {
let container_dir = &*crate::cmd::container_dirs::TARGET_DIR;
Command::new_sandboxed(
&self.dir.workspace,
self.sandbox
.clone()
.mount(&self.dir.target_dir(), container_dir, MountKind::ReadWrite),
bin,
)
.cd(self.dir.source_dir())
.env("CARGO_TARGET_DIR", container_dir)
}
pub fn cargo(&self) -> Command {
self.cmd(self.toolchain.cargo())
}
pub fn host_source_dir(&self) -> PathBuf {
self.dir.source_dir()
}
pub fn host_target_dir(&self) -> PathBuf {
self.dir.target_dir()
}
}