From cd248a59ea0bf0927730ec8892e5d82b3ba4e4a6 Mon Sep 17 00:00:00 2001 From: Robert Bragg Date: Sat, 7 Nov 2020 21:25:16 +0000 Subject: [PATCH] Read project environment vars from config Some custom build scripts (especially for -sys packages) expect to query environment variables to locate build resources (such as pre-built binaries) but these cause lots of trouble when considering the numerous different ways in which cargo may be invoked. For example each editor that invokes cargo as part of providing development diagnostics needs to offer some way to configure environment variables or users need to find their own way of controlling the environment variables of these different tools which is burdensome and can lead to an inconsistent duplication of state across tools. This introduces support for reading an (optional) environment.json found at the root of the current workspace that may contain a map of environment variable key, value pairs. These variables will be exported to all build scripts run under the workspace. The removes any need to configure tools and editors independently. The configuration is separate from any Config.toml since it's likely that the state shouldn't be under version control in many situations (generally locating resources for the project within a specific user's development environment). Fixes: rust-lang/cargo/issues/4121 Fixes: rust-lang/rls/issues/915 Fixes: rust-lang/vscode-rust/issues/791 Fixes: rust-analyzer/rust-analyzer/pull/6099 Fixes: intellij-rust/intellij-rust/issues/1569 --- src/cargo/core/compiler/custom_build.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/cargo/core/compiler/custom_build.rs b/src/cargo/core/compiler/custom_build.rs index 7e02008c8a1..2102134176f 100644 --- a/src/cargo/core/compiler/custom_build.rs +++ b/src/cargo/core/compiler/custom_build.rs @@ -9,9 +9,11 @@ use crate::util::{self, internal, paths, profile}; use cargo_platform::Cfg; use std::collections::hash_map::{Entry, HashMap}; use std::collections::{BTreeSet, HashSet}; +use std::fs; use std::path::{Path, PathBuf}; use std::str; use std::sync::{Arc, Mutex}; +use serde_json::Value; const CARGO_WARNING: &str = "cargo:warning="; @@ -208,6 +210,23 @@ fn build_work(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult { cmd.env("CARGO_MANIFEST_LINKS", links); } + // Re-export environment variables declared in the project's environment.json + let env_path = Path::new(bcx.ws.root()).join("environment.json"); + // TODO: cache the environment.json state with the Workspace so it doesn't + // need to be repeatedly read + parsed for each build script + if let Ok(env) = fs::read_to_string(env_path) { + let env: Value = serde_json::from_str(&env).expect("Failed to parse environment.json"); + if let Some(env_map) = env.as_object() { + for key in env_map.keys() { + if let Some(env_value) = env[key].as_str() { + // Simply re-export as an actual environment variables so build scripts + // may continue to take their configuration from environment variables + cmd.env(key, env_value); + } + } + } + } + // Be sure to pass along all enabled features for this package, this is the // last piece of statically known information that we have. for feat in &unit.features {