1use lazy_static::lazy_static;
2use serde::Deserialize;
3use std::collections::BTreeMap;
4use std::collections::HashMap;
5use std::collections::HashSet;
6use std::env;
7use std::path::{Path, PathBuf};
8use std::sync::Mutex;
9
10lazy_static! {
11 static ref WORKSPACES: Mutex<BTreeMap<String, &'static Path>> = Mutex::new(BTreeMap::new());
12}
13
14fn get_cargo_workspace(manifest_dir: &str) -> Result<Option<&Path>, Box<dyn std::error::Error>> {
17 let mut workspaces = WORKSPACES.lock()?;
18 if let Some(rv) = workspaces.get(manifest_dir) {
19 Ok(Some(rv))
20 } else {
21 #[derive(Deserialize)]
22 struct Manifest {
23 workspace_root: String,
24 }
25 let output = std::process::Command::new(env!("CARGO"))
26 .arg("metadata")
27 .arg("--format-version=1")
28 .current_dir(manifest_dir)
29 .output()?;
30 let manifest: Manifest = serde_json::from_slice(&output.stdout)?;
31 let path = Box::leak(Box::new(PathBuf::from(manifest.workspace_root)));
32 workspaces.insert(manifest_dir.to_string(), path.as_path());
33 Ok(workspaces.get(manifest_dir).cloned())
34 }
35}
36
37#[derive(Deserialize)]
38struct Feature {
39 #[allow(unused)]
40 description: String,
41 enabled: bool,
42}
43
44pub fn build() -> Result<(), Box<dyn std::error::Error>> {
45 let input = env::var("CARGO_MANIFEST_DIR")?;
46
47 let all_on = env::var("NUSHELL_ENABLE_ALL_FLAGS").is_ok();
48 let flags: HashSet<String> = env::var("NUSHELL_ENABLE_FLAGS")
49 .map(|s| s.split(',').map(|s| s.to_string()).collect())
50 .unwrap_or_else(|_| HashSet::new());
51
52 if all_on && !flags.is_empty() {
53 println!(
54 "cargo:warning=Both NUSHELL_ENABLE_ALL_FLAGS and NUSHELL_ENABLE_FLAGS were set. You don't need both."
55 );
56 }
57
58 let workspace = match get_cargo_workspace(&input)? {
59 None => return Ok(()),
61 Some(workspace) => workspace,
62 };
63
64 let path = Path::new(&workspace).join("features.toml");
65
66 if !path.exists() {
68 return Ok(());
69 }
70
71 let toml: HashMap<String, Feature> = toml::from_str(&std::fs::read_to_string(path)?)?;
72
73 for (key, value) in toml.iter() {
74 if value.enabled || all_on || flags.contains(key) {
75 println!("cargo:rustc-cfg={}", key);
76 }
77 }
78
79 Ok(())
80}