polyhorn_cli/core/
cargo_build.rs

1use cargo_metadata::MetadataCommand;
2use std::io::Result;
3use std::path::{Path, PathBuf};
4use std::process::Command;
5
6use super::change_crate_type;
7
8/// Builder for cargo build commands.
9#[derive(Default)]
10pub struct CargoBuild {
11    manifest_path: PathBuf,
12    crate_type: Option<String>,
13    target: Option<String>,
14    release: bool,
15}
16
17impl CargoBuild {
18    /// Returns a new builder for a cargo build command that operates on the
19    /// manifest residing at the given path.
20    pub fn new(manifest_path: &Path) -> CargoBuild {
21        CargoBuild {
22            manifest_path: manifest_path.to_owned(),
23            ..Default::default()
24        }
25    }
26
27    /// Builds a crate of the given type, overriding the type that is written in
28    /// the manifest.
29    pub fn crate_type(mut self, crate_type: &str) -> CargoBuild {
30        self.crate_type = Some(crate_type.to_owned());
31        self
32    }
33
34    /// Changes the profile of this build.
35    pub fn release(mut self, release: bool) -> CargoBuild {
36        self.release = release;
37        self
38    }
39
40    /// Changes the target of this build.
41    pub fn target(mut self, target: &str) -> CargoBuild {
42        self.target = Some(target.to_owned());
43        self
44    }
45
46    /// Executes the build and returns the crate name of the first target that
47    /// matches the requested crate type for this build.
48    pub fn build(self) -> Result<String> {
49        let mut guard = None;
50
51        if let Some(crate_type) = self.crate_type.as_ref() {
52            guard.replace(change_crate_type(&self.manifest_path, crate_type)?);
53        }
54
55        let metadata = MetadataCommand::new()
56            .manifest_path(&self.manifest_path)
57            .exec()
58            .unwrap();
59        let root_id = metadata.resolve.unwrap().root.unwrap();
60        let package = metadata
61            .packages
62            .iter()
63            .find(|package| package.id == root_id)
64            .unwrap();
65
66        let mut command = Command::new("cargo");
67        command.arg("build");
68        command.arg("--manifest-path");
69        command.arg(&self.manifest_path);
70
71        if let Some(target) = self.target.as_ref() {
72            command.arg("--target");
73            command.arg(target);
74        }
75
76        if self.release {
77            command.arg("--release");
78        }
79
80        match command.status()? {
81            status if status.success() => {}
82            status => {
83                std::process::exit(status.code().unwrap());
84            }
85        }
86
87        let mut targets = package.targets.iter();
88
89        let target = if let Some(crate_type) = self.crate_type.as_ref() {
90            targets.find(|target| target.kind == vec![crate_type.to_owned()])
91        } else {
92            targets.next()
93        };
94
95        Ok(target.unwrap().name.replace("-", "_"))
96    }
97}