rhg: centralize PlainInfo
authorArseniy Alekseyev <aalekseyev@janestreet.com>
Thu, 22 Sep 2022 17:16:54 -0400
changeset 49513 467d9df98c68
parent 49512 6939d5ed20e0
child 49514 e37416d432e9
rhg: centralize PlainInfo
rust/hg-core/src/config.rs
rust/hg-core/src/config/config.rs
rust/hg-core/src/config/plain_info.rs
rust/rhg/src/main.rs
rust/rhg/src/ui.rs
--- a/rust/hg-core/src/config.rs	Tue Sep 20 18:16:50 2022 -0400
+++ b/rust/hg-core/src/config.rs	Thu Sep 22 17:16:54 2022 -0400
@@ -11,6 +11,8 @@
 
 mod config;
 mod layer;
+mod plain_info;
 mod values;
-pub use config::{Config, ConfigSource, ConfigValueParseError, PlainInfo};
+pub use config::{Config, ConfigSource, ConfigValueParseError};
 pub use layer::{ConfigError, ConfigOrigin, ConfigParseError};
+pub use plain_info::PlainInfo;
--- a/rust/hg-core/src/config/config.rs	Tue Sep 20 18:16:50 2022 -0400
+++ b/rust/hg-core/src/config/config.rs	Thu Sep 22 17:16:54 2022 -0400
@@ -12,6 +12,7 @@
 use crate::config::layer::{
     ConfigError, ConfigLayer, ConfigOrigin, ConfigValue,
 };
+use crate::config::plain_info::PlainInfo;
 use crate::utils::files::get_bytes_from_os_str;
 use format_bytes::{write_bytes, DisplayBytes};
 use std::collections::HashSet;
@@ -22,14 +23,6 @@
 
 use crate::errors::{HgResultExt, IoResultExt};
 
-#[derive(Clone)]
-pub struct PlainInfo {
-    pub plain: bool,
-    pub plainalias: bool,
-    pub plainrevsetalias: bool,
-    pub plaintemplatealias: bool,
-}
-
 /// Holds the config values for the current repository
 /// TODO update this docstring once we support more sources
 #[derive(Clone)]
@@ -92,21 +85,21 @@
     }
 }
 
+/// Returns true if the config item is disabled by PLAIN or PLAINEXCEPT
 fn should_ignore(plain: &PlainInfo, section: &[u8], item: &[u8]) -> bool {
     // duplication with [_applyconfig] in [ui.py],
-    if !plain.plain {
+    if !plain.is_plain() {
         return false;
     }
     if section == b"alias" {
-        return plain.plainalias;
+        return plain.plainalias();
     }
     if section == b"revsetalias" {
-        return plain.plainrevsetalias;
+        return plain.plainrevsetalias();
     }
     if section == b"templatealias" {
-        return plain.plaintemplatealias;
+        return plain.plaintemplatealias();
     }
-
     if section == b"ui" {
         let to_delete: &[&[u8]] = &[
             b"debug",
@@ -127,16 +120,6 @@
     return sections_to_delete.contains(&section);
 }
 
-impl PlainInfo {
-    pub fn empty() -> Self {
-        Self {
-            plain: false,
-            plainalias: false,
-            plainrevsetalias: false,
-            plaintemplatealias: false,
-        }
-    }
-}
 impl Config {
     /// The configuration to use when printing configuration-loading errors
     pub fn empty() -> Self {
@@ -478,6 +461,8 @@
         section: &[u8],
         item: &[u8],
     ) -> Option<(&ConfigLayer, &ConfigValue)> {
+        // Filter out the config items that are hidden by [PLAIN].
+        // This differs from python hg where we delete them from the config.
         if should_ignore(&self.plain, &section, &item) {
             return None;
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rust/hg-core/src/config/plain_info.rs	Thu Sep 22 17:16:54 2022 -0400
@@ -0,0 +1,79 @@
+use crate::utils::files::get_bytes_from_os_string;
+use std::env;
+
+/// Keeps information on whether plain mode is active.
+///
+/// Plain mode means that all configuration variables which affect
+/// the behavior and output of Mercurial should be
+/// ignored. Additionally, the output should be stable,
+/// reproducible and suitable for use in scripts or applications.
+///
+/// The only way to trigger plain mode is by setting either the
+/// `HGPLAIN' or `HGPLAINEXCEPT' environment variables.
+///
+/// The return value can either be
+/// - False if HGPLAIN is not set, or feature is in HGPLAINEXCEPT
+/// - False if feature is disabled by default and not included in HGPLAIN
+/// - True otherwise
+#[derive(Clone)]
+pub struct PlainInfo {
+    is_plain: bool,
+    except: Vec<Vec<u8>>,
+}
+
+impl PlainInfo {
+    fn plain_except(except: Vec<Vec<u8>>) -> Self {
+        PlainInfo {
+            is_plain: true,
+            except,
+        }
+    }
+
+    pub fn empty() -> PlainInfo {
+        PlainInfo {
+            is_plain: false,
+            except: vec![],
+        }
+    }
+
+    pub fn from_env() -> PlainInfo {
+        if let Some(except) = env::var_os("HGPLAINEXCEPT") {
+            PlainInfo::plain_except(
+                get_bytes_from_os_string(except)
+                    .split(|&byte| byte == b',')
+                    .map(|x| x.to_vec())
+                    .collect(),
+            )
+        } else {
+            PlainInfo {
+                is_plain: env::var_os("HGPLAIN").is_some(),
+                except: vec![],
+            }
+        }
+    }
+
+    pub fn is_feature_plain(&self, feature: &str) -> bool {
+        return self.is_plain
+            && !self
+                .except
+                .iter()
+                .any(|exception| exception.as_slice() == feature.as_bytes());
+    }
+
+    pub fn is_plain(&self) -> bool {
+        self.is_plain
+    }
+
+    pub fn plainalias(&self) -> bool {
+        self.is_feature_plain("alias")
+    }
+    pub fn plainrevsetalias(&self) -> bool {
+        self.is_feature_plain("revsetalias")
+    }
+    pub fn plaintemplatealias(&self) -> bool {
+        self.is_feature_plain("templatealias")
+    }
+    pub fn plaintweakdefaults(&self) -> bool {
+        self.is_feature_plain("tweakdefaults")
+    }
+}
--- a/rust/rhg/src/main.rs	Tue Sep 20 18:16:50 2022 -0400
+++ b/rust/rhg/src/main.rs	Thu Sep 22 17:16:54 2022 -0400
@@ -329,14 +329,7 @@
     };
 
     let mut config_cow = Cow::Borrowed(config);
-    if ui::plain(None) {
-        config_cow.to_mut().apply_plain(PlainInfo {
-            plain: true,
-            plainalias: ui::plain(Some("alias")),
-            plainrevsetalias: ui::plain(Some("revsetalias")),
-            plaintemplatealias: ui::plain(Some("templatealias")),
-        })
-    };
+    config_cow.to_mut().apply_plain(PlainInfo::from_env());
     let config = config_cow.as_ref();
 
     let ui = Ui::new(&config).unwrap_or_else(|error| {
--- a/rust/rhg/src/ui.rs	Tue Sep 20 18:16:50 2022 -0400
+++ b/rust/rhg/src/ui.rs	Thu Sep 22 17:16:54 2022 -0400
@@ -3,10 +3,9 @@
 use format_bytes::format_bytes;
 use format_bytes::write_bytes;
 use hg::config::Config;
+use hg::config::PlainInfo;
 use hg::errors::HgError;
-use hg::utils::files::get_bytes_from_os_string;
 use std::borrow::Cow;
-use std::env;
 use std::io;
 use std::io::{ErrorKind, Write};
 
@@ -129,29 +128,13 @@
     }
 }
 
-/// Return whether plain mode is active.
-///
-/// Plain mode means that all configuration variables which affect
-/// the behavior and output of Mercurial should be
-/// ignored. Additionally, the output should be stable,
-/// reproducible and suitable for use in scripts or applications.
-///
-/// The only way to trigger plain mode is by setting either the
-/// `HGPLAIN' or `HGPLAINEXCEPT' environment variables.
-///
-/// The return value can either be
-/// - False if HGPLAIN is not set, or feature is in HGPLAINEXCEPT
-/// - False if feature is disabled by default and not included in HGPLAIN
-/// - True otherwise
+// TODO: pass the PlainInfo to call sites directly and
+// delete this function
 pub fn plain(opt_feature: Option<&str>) -> bool {
-    if let Some(except) = env::var_os("HGPLAINEXCEPT") {
-        opt_feature.map_or(true, |feature| {
-            get_bytes_from_os_string(except)
-                .split(|&byte| byte == b',')
-                .all(|exception| exception != feature.as_bytes())
-        })
-    } else {
-        env::var_os("HGPLAIN").is_some()
+    let plain_info = PlainInfo::from_env();
+    match opt_feature {
+        None => plain_info.is_plain(),
+        Some(feature) => plain_info.is_feature_plain(feature),
     }
 }