1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
use std::env;
use std::path::PathBuf;
use std::process::Command;

use serde::Deserialize;

#[derive(Deserialize)]
struct MetaData {
    target_directory: PathBuf,
}

fn primary_target_dir() -> PathBuf {
    // the target dir is explicitly set and exists
    if let Some(target_dir) = env::var_os("CARGO_TARGET_DIR") {
        let target_dir = PathBuf::from(target_dir);
        if target_dir.is_dir() {
            println!("first out");
            return target_dir;
        };
    }

    // try to guess it from the current exe
    env::current_exe()
        .ok()
        .map(|mut path| {
            path.pop();
            if path.ends_with("deps") || path.ends_with("examples") {
                path.pop();
            }
            path
        })
        .unwrap()
}

fn cargo_inferred_target_dir() -> PathBuf {
    let metadata = Command::new(env::var("CARGO").ok().unwrap_or_else(|| "cargo".into()))
        .arg("metadata")
        .output()
        .unwrap();
    let meta: MetaData = serde_json::from_slice(&metadata.stdout).unwrap();
    let mut rv = meta.target_directory;
    if cfg!(debug_assertions) {
        rv.push("debug");
    } else {
        rv.push("release");
    }
    rv
}

fn find_exe(name: &str) -> PathBuf {
    let mut first = primary_target_dir();
    first.push(name);
    if first.is_file() {
        return first;
    }

    let mut alt = cargo_inferred_target_dir();
    alt.push(name);
    if alt.is_file() {
        return alt;
    }
    panic!("Cannot determine path to executable '{}'", name);
}

/// Helper function to return the path to an executable that cargo is building.
pub fn get_cargo_bin(name: &str) -> PathBuf {
    let env_var = format!("CARGO_BIN_EXE_{}", name);
    env::var_os(&env_var)
        .map(|p| p.into())
        .unwrap_or_else(|| find_exe(&format!("{}{}", name, env::consts::EXE_SUFFIX)))
}

/// Helper function to return the path to an example that cargo is building.
pub fn get_cargo_example(name: &str) -> PathBuf {
    find_exe(&format!("examples/{}{}", name, env::consts::EXE_SUFFIX))
}