diff --git a/eden/scm/edenscm/ext/tweakdefaults.py b/eden/scm/edenscm/ext/tweakdefaults.py index 726cc123e2..01a843b13b 100644 --- a/eden/scm/edenscm/ext/tweakdefaults.py +++ b/eden/scm/edenscm/ext/tweakdefaults.py @@ -671,7 +671,7 @@ def statuscmd(orig, ui, repo, *pats, **opts): message = _("--root-relative not supported with patterns") hint = _("run from the repo root instead") raise error.Abort(message, hint=hint) - elif encoding.environ.get("HGPLAIN"): # don't break automation + elif ui.plain(): pass # Here's an ugly hack! If users are passing "re:" to make status relative, # hgwatchman will never refresh the full state and status will become and diff --git a/eden/scm/edenscm/i18n.py b/eden/scm/edenscm/i18n.py index 6700a6ba8b..cf27dc8237 100644 --- a/eden/scm/edenscm/i18n.py +++ b/eden/scm/edenscm/i18n.py @@ -17,6 +17,8 @@ import locale import os import sys +import bindings + from . import encoding, identity, pycompat @@ -146,9 +148,12 @@ _plain = True def _getplain(): - if "HGPLAIN" not in encoding.environ and "HGPLAINEXCEPT" not in encoding.environ: + plain = bindings.identity.envvar("PLAIN") + plainexcept = bindings.identity.envvar("PLAINEXCEPT") + + if plain is None and plainexcept is None: return False - exceptions = encoding.environ.get("HGPLAINEXCEPT", "").strip().split(",") + exceptions = (plainexcept or "").strip().split(",") return "i18n" not in exceptions diff --git a/eden/scm/edenscm/ui.py b/eden/scm/edenscm/ui.py index 6f47d1854e..2e700fc58a 100644 --- a/eden/scm/edenscm/ui.py +++ b/eden/scm/edenscm/ui.py @@ -558,11 +558,13 @@ class ui(object): - False if feature is disabled by default and not included in HGPLAIN - True otherwise """ - if "HGPLAIN" not in os.environ and "HGPLAINEXCEPT" not in os.environ: + plain = bindings.identity.envvar("PLAIN") + plainexcept = bindings.identity.envvar("PLAINEXCEPT") + if plain is None and plainexcept is None: return False - exceptions = encoding.environ.get("HGPLAINEXCEPT", "").strip().split(",") + exceptions = (plainexcept or "").strip().split(",") # TODO: add support for HGPLAIN=+feature,-feature syntax - if "+strictflags" not in encoding.environ.get("HGPLAIN", "").split(","): + if "+strictflags" not in (plain or "").split(","): exceptions.append("strictflags") if feature and exceptions: return feature not in exceptions diff --git a/eden/scm/edenscmnative/bindings/modules/pyidentity/src/lib.rs b/eden/scm/edenscmnative/bindings/modules/pyidentity/src/lib.rs index 70db9f6e52..f5bf8f8ea7 100644 --- a/eden/scm/edenscmnative/bindings/modules/pyidentity/src/lib.rs +++ b/eden/scm/edenscmnative/bindings/modules/pyidentity/src/lib.rs @@ -21,6 +21,7 @@ pub fn init_module(py: Python, package: &str) -> PyResult { m.add(py, "sniffenv", py_fn!(py, sniff_env()))?; m.add(py, "sniffroot", py_fn!(py, sniff_root(path: PyPathBuf)))?; m.add(py, "sniffdir", py_fn!(py, sniff_dir(path: PyPathBuf)))?; + m.add(py, "envvar", py_fn!(py, try_env_var(suffix: PyString)))?; Ok(m) } @@ -53,3 +54,9 @@ fn sniff_dir(py: Python, path: PyPathBuf) -> PyResult> { Some(ident) => Some(identity::create_instance(py, ident)?), }) } + +fn try_env_var(py: Python, suffix: PyString) -> PyResult> { + rsident::env_var(suffix.to_string(py)?.as_ref()) + .transpose() + .map_pyerr(py) +} diff --git a/eden/scm/lib/commitcloudsubscriber/Cargo.toml b/eden/scm/lib/commitcloudsubscriber/Cargo.toml index 37b91e52f8..b40108d606 100644 --- a/eden/scm/lib/commitcloudsubscriber/Cargo.toml +++ b/eden/scm/lib/commitcloudsubscriber/Cargo.toml @@ -22,6 +22,7 @@ anyhow = "1.0.65" eventsource = "0.5" filetime = "0.2.9" hostcaps = { version = "0.1.0", git = "https://github.com/facebookexperimental/rust-shed.git", branch = "main" } +identity = { version = "0.1.0", path = "../identity" } lazy_static = "1.4" log = { version = "0.4.14", features = ["kv_unstable", "kv_unstable_std"] } regex = "1.5.4" diff --git a/eden/scm/lib/commitcloudsubscriber/src/action.rs b/eden/scm/lib/commitcloudsubscriber/src/action.rs index 647a9287e9..55ebe60963 100644 --- a/eden/scm/lib/commitcloudsubscriber/src/action.rs +++ b/eden/scm/lib/commitcloudsubscriber/src/action.rs @@ -38,7 +38,7 @@ impl CloudSyncTrigger { let now = Instant::now(); let child = Command::new("hg") .current_dir(&path) - .env("HGPLAIN", "hint") + .env(identity::try_env_var("PLAIN")?, "hint") .args(vec!["cloud", "sync"]) .arg("--check-autosync-enabled") .arg("--use-bgssh") diff --git a/eden/scm/lib/config/parser/src/hg.rs b/eden/scm/lib/config/parser/src/hg.rs index 7ac00a0eb0..c90d081643 100644 --- a/eden/scm/lib/config/parser/src/hg.rs +++ b/eden/scm/lib/config/parser/src/hg.rs @@ -23,8 +23,7 @@ use std::path::PathBuf; use anyhow::Result; use configmodel::Config; use configmodel::ConfigExt; -use hgplain::HGPLAIN; -use hgplain::HGPLAINEXCEPT; +use hgplain; use minibytes::Text; use url::Url; use util::path::expand_path; @@ -134,15 +133,9 @@ pub fn load( impl OptionsHgExt for Options { fn process_hgplain(self) -> Self { - let plain_set = env::var(HGPLAIN).is_ok(); - let plain_except = env::var(HGPLAINEXCEPT); - if plain_set || plain_except.is_ok() { + if hgplain::is_plain(None) { let (section_exclude_list, ui_exclude_list) = { - let plain_exceptions: HashSet = plain_except - .unwrap_or_else(|_| "".to_string()) - .split(',') - .map(|s| s.to_string()) - .collect(); + let plain_exceptions = hgplain::exceptions(); // [defaults] and [commands] are always excluded. let mut section_exclude_list: HashSet = @@ -874,6 +867,9 @@ mod tests { use crate::config::tests::write_file; use crate::lock_env; + const HGPLAIN: &str = "HGPLAIN"; + const HGPLAINEXCEPT: &str = "HGPLAINEXCEPT"; + #[test] fn test_basic_hgplain() { let mut env = lock_env(); diff --git a/eden/scm/lib/identity/src/lib.rs b/eden/scm/lib/identity/src/lib.rs index 1d8073c13d..9ce9f6afab 100644 --- a/eden/scm/lib/identity/src/lib.rs +++ b/eden/scm/lib/identity/src/lib.rs @@ -24,6 +24,8 @@ pub struct Identity { dot_dir: &'static str, env_prefix: &'static str, config_name: &'static str, + scripting_env_var: &'static str, + scripting_except_env_var: &'static str, } impl Identity { @@ -47,8 +49,12 @@ impl Identity { self.env_prefix } - fn env_var(&self, suffix: &str) -> Option> { - let var_name = format!("{}{}", self.env_prefix, suffix); + pub fn env_var(&self, suffix: &str) -> Option> { + let var_name = match suffix { + "PLAIN" => self.scripting_env_var.to_string(), + "PLAINEXCEPT" => self.scripting_except_env_var.to_string(), + _ => format!("{}{}", self.env_prefix, suffix), + }; match std::env::var(var_name) { Err(err) if err == VarError::NotPresent => None, Err(err) => Some(Err(err)), @@ -69,6 +75,8 @@ const HG: Identity = Identity { dot_dir: ".hg", env_prefix: "HG", config_name: "hgrc", + scripting_env_var: "HGPLAIN", + scripting_except_env_var: "HGPLAINEXCEPT", }; const SL: Identity = Identity { @@ -77,6 +85,8 @@ const SL: Identity = Identity { dot_dir: ".sl", env_prefix: "SL", config_name: "slconfig", + scripting_env_var: "SL_AUTOMATION", + scripting_except_env_var: "SL_AUTOMATION_EXCEPT", }; #[cfg(test)] @@ -86,6 +96,8 @@ const TEST: Identity = Identity { dot_dir: ".test", env_prefix: "TEST", config_name: "testrc", + scripting_env_var: "TEST_SCRIPT", + scripting_except_env_var: "TEST_SCRIPT_EXCEPT", }; #[cfg(all(not(feature = "sl_only"), not(test)))] @@ -169,12 +181,12 @@ pub fn sniff_root(path: &Path) -> Result> { Ok(None) } -fn try_env_var(var_suffix: &str) -> Result { +pub fn env_var(var_suffix: &str) -> Option> { let current_id = IDENTITY.read(); // Always prefer current identity. if let Some(res) = current_id.env_var(var_suffix) { - return res; + return Some(res); } // Backwards compat for old env vars. @@ -184,11 +196,18 @@ fn try_env_var(var_suffix: &str) -> Result { } if let Some(res) = id.env_var(var_suffix) { - return res; + return Some(res); } } - Err(VarError::NotPresent) + None +} + +pub fn try_env_var(var_suffix: &str) -> Result { + match env_var(var_suffix) { + Some(result) => result, + None => Err(VarError::NotPresent), + } } pub fn sniff_env() -> Identity { diff --git a/eden/scm/lib/util/hgplain/Cargo.toml b/eden/scm/lib/util/hgplain/Cargo.toml index e11561a559..c1c2f355a3 100644 --- a/eden/scm/lib/util/hgplain/Cargo.toml +++ b/eden/scm/lib/util/hgplain/Cargo.toml @@ -5,3 +5,6 @@ name = "hgplain" version = "0.1.0" authors = ["Facebook Source Control Team "] edition = "2021" + +[dependencies] +identity = { version = "0.1.0", path = "../../identity" } diff --git a/eden/scm/lib/util/hgplain/src/lib.rs b/eden/scm/lib/util/hgplain/src/lib.rs index 503095dc82..b1bd444c90 100644 --- a/eden/scm/lib/util/hgplain/src/lib.rs +++ b/eden/scm/lib/util/hgplain/src/lib.rs @@ -5,15 +5,12 @@ * GNU General Public License version 2. */ -use std::env; - -pub const HGPLAIN: &str = "HGPLAIN"; -pub const HGPLAINEXCEPT: &str = "HGPLAINEXCEPT"; +use std::collections::HashSet; /// Return whether plain mode is active, similar to python ui.plain(). pub fn is_plain(feature: Option<&str>) -> bool { - let plain = env::var(HGPLAIN); - let plain_except = env::var(HGPLAINEXCEPT); + let plain = identity::try_env_var("PLAIN"); + let plain_except = identity::try_env_var("PLAINEXCEPT"); if plain.is_err() && plain_except.is_err() { return false; @@ -28,3 +25,10 @@ pub fn is_plain(feature: Option<&str>) -> bool { true } } + +pub fn exceptions() -> HashSet { + match identity::try_env_var("PLAINEXCEPT") { + Ok(value) => value.split(',').map(|s| s.to_string()).collect(), + Err(_) => HashSet::new(), + } +}