build_helper/
util.rs

1use std::fs::File;
2use std::io::{BufRead, BufReader};
3use std::path::Path;
4use std::process::Command;
5
6/// Invokes `build_helper::util::detail_exit` with `cfg!(test)`
7///
8/// This is a macro instead of a function so that it uses `cfg(test)` in the *calling* crate, not in build helper.
9#[macro_export]
10macro_rules! exit {
11    ($code:expr) => {
12        $crate::util::detail_exit($code, cfg!(test));
13    };
14}
15
16/// If code is not 0 (successful exit status), exit status is 101 (rust's default error code.)
17/// If `is_test` true and code is an error code, it will cause a panic.
18pub fn detail_exit(code: i32, is_test: bool) -> ! {
19    // if in test and code is an error code, panic with status code provided
20    if is_test {
21        panic!("status code: {}", code);
22    } else {
23        // otherwise,exit with provided status code
24        std::process::exit(code);
25    }
26}
27
28pub fn fail(s: &str) -> ! {
29    eprintln!("\n\n{}\n\n", s);
30    detail_exit(1, cfg!(test));
31}
32
33pub fn try_run(cmd: &mut Command, print_cmd_on_fail: bool) -> Result<(), ()> {
34    let status = match cmd.status() {
35        Ok(status) => status,
36        Err(e) => fail(&format!("failed to execute command: {:?}\nerror: {}", cmd, e)),
37    };
38    if !status.success() {
39        if print_cmd_on_fail {
40            println!(
41                "\n\ncommand did not execute successfully: {:?}\n\
42                 expected success, got: {}\n\n",
43                cmd, status
44            );
45        }
46        Err(())
47    } else {
48        Ok(())
49    }
50}
51
52/// Returns the submodule paths from the `.gitmodules` file in the given directory.
53pub fn parse_gitmodules(target_dir: &Path) -> Vec<String> {
54    let gitmodules = target_dir.join(".gitmodules");
55    assert!(gitmodules.exists(), "'{}' file is missing.", gitmodules.display());
56
57    let file = File::open(gitmodules).unwrap();
58
59    let mut submodules_paths = vec![];
60    for line in BufReader::new(file).lines().map_while(Result::ok) {
61        let line = line.trim();
62        if line.starts_with("path") {
63            let actual_path = line.split(' ').last().expect("Couldn't get value of path");
64            submodules_paths.push(actual_path.to_owned());
65        }
66    }
67
68    submodules_paths
69}