mirror of
https://github.com/facebook/sapling.git
synced 2024-12-25 22:11:52 +03:00
configs: add rust support for loading dynamic and repo configs
Summary: This threads the calls to load_dynamic and load_repo through the Rust layer up to the Python bindings. This diff does 2 notable things: 1. It adds a reload API for reloading configs in place, versus creating a new one. This will be used in localrepo.__init__ to construct a new config for the repo while still maintaining the old pinned values from the copied ui. 2. It threads a repo path and readonly config list from Python down to the Rust code. This allows load_dynamic and load_repo to operate on the repo path, and allows the readonly filter to applied to all configs during reloading. Reviewed By: quark-zju Differential Revision: D22712623 fbshipit-source-id: a0f372f4971c5feac2f20e89a0fb3fe6d4a65d6f
This commit is contained in:
parent
6b0014490c
commit
2da121cb60
@ -121,7 +121,7 @@ class uiconfig(object):
|
||||
"""Create a uiconfig and load global and user configs"""
|
||||
u = cls()
|
||||
try:
|
||||
rcfg = configparser.config.load()
|
||||
rcfg = configparser.config.load(None)
|
||||
except Exception as ex:
|
||||
raise error.ParseError(str(ex))
|
||||
u._rcfg = localrcfg(rcfg)
|
||||
|
@ -14,7 +14,7 @@ use cpython::*;
|
||||
use configparser::{
|
||||
config::{ConfigSet, Options},
|
||||
dynamicconfig::Generator,
|
||||
hg::{generate_dynamicconfig, load as hg_load, parse_list, OptionsHgExt},
|
||||
hg::{generate_dynamicconfig, parse_list, ConfigSetHgExt, OptionsHgExt},
|
||||
};
|
||||
use cpython_ext::{error::ResultPyErrExt, PyNone, PyPath, PyPathBuf, Str};
|
||||
|
||||
@ -147,11 +147,20 @@ py_class!(pub class config |py| {
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def load() -> PyResult<config> {
|
||||
let cfg = hg_load().map_pyerr(py)?;
|
||||
def load(repopath: Option<PyPathBuf>) -> PyResult<config> {
|
||||
let repopath = repopath.as_ref().map(|p| p.as_path());
|
||||
let mut cfg = ConfigSet::new();
|
||||
cfg.load::<String, String>(repopath, None).map_pyerr(py)?;
|
||||
config::create_instance(py, RefCell::new(cfg))
|
||||
}
|
||||
|
||||
def reload(&self, repopath: Option<PyPathBuf>, readonly_items: Option<Vec<(String, String)>>) -> PyResult<PyNone> {
|
||||
let repopath = repopath.as_ref().map(|p| p.as_path());
|
||||
let mut cfg = self.cfg(py).borrow_mut();
|
||||
cfg.load(repopath, readonly_items).map_pyerr(py)?;
|
||||
Ok(PyNone)
|
||||
}
|
||||
|
||||
def ensure_location_supersets(
|
||||
&self,
|
||||
superset_source: String,
|
||||
|
@ -9,7 +9,7 @@ use crate::remotestore::FakeRemoteStore;
|
||||
use crate::treecontentstore::TreeContentStore;
|
||||
use crate::utils::key_from_path_node_slice;
|
||||
use anyhow::Result;
|
||||
use configparser::config::ConfigSet;
|
||||
use configparser::config::{ConfigSet, Options};
|
||||
use configparser::hg::ConfigSetHgExt;
|
||||
use edenapi::{Builder as EdenApiBuilder, EdenApi};
|
||||
use log::warn;
|
||||
@ -31,9 +31,10 @@ pub struct BackingStore {
|
||||
impl BackingStore {
|
||||
pub fn new<P: AsRef<Path>>(repository: P, use_edenapi: bool) -> Result<Self> {
|
||||
let hg = repository.as_ref().join(".hg");
|
||||
let options = Options::new();
|
||||
let mut config = ConfigSet::new();
|
||||
config.load_system();
|
||||
config.load_user();
|
||||
config.load_system(options.clone());
|
||||
config.load_user(options.clone());
|
||||
config.load_hgrc(hg.join("hgrc"), "repository");
|
||||
|
||||
let store_path = hg.join("store");
|
||||
|
@ -40,7 +40,9 @@ impl OptionalRepo {
|
||||
let repo = Repo::from_raw_path(path)?;
|
||||
Ok(OptionalRepo::Some(repo))
|
||||
} else {
|
||||
Ok(OptionalRepo::None(configparser::hg::load()?))
|
||||
Ok(OptionalRepo::None(
|
||||
configparser::hg::load::<String, String>(None, None)?,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
@ -98,7 +100,7 @@ impl Repo {
|
||||
{
|
||||
let path = path.into();
|
||||
assert!(path.is_absolute());
|
||||
let mut config = configparser::hg::load()?;
|
||||
let mut config = configparser::hg::load::<String, String>(None, None)?;
|
||||
let mut errors = config.load_hgrc(path.join(".hg/hgrc"), "repository");
|
||||
if let Some(error) = errors.pop() {
|
||||
Err(error.into())
|
||||
|
@ -87,7 +87,7 @@ pub extern "C" fn hgrc_configset_load_system(cfg: *mut ConfigSet) -> *mut Text {
|
||||
// Forces datapath to be the empty string as it doesn't
|
||||
// appear to play a useful role in simply resolving config
|
||||
// settings for Eden.
|
||||
errors_to_bytes(cfg.load_system())
|
||||
errors_to_bytes(cfg.load_system(Options::new()))
|
||||
}
|
||||
|
||||
/// Load user config files
|
||||
@ -96,7 +96,7 @@ pub extern "C" fn hgrc_configset_load_user(cfg: *mut ConfigSet) -> *mut Text {
|
||||
debug_assert!(!cfg.is_null());
|
||||
let cfg = unsafe { &mut *cfg };
|
||||
|
||||
errors_to_bytes(cfg.load_user())
|
||||
errors_to_bytes(cfg.load_user(Options::new()))
|
||||
}
|
||||
|
||||
/// Returns a Text object holding the configuration value for the corresponding
|
||||
|
@ -51,21 +51,27 @@ pub trait OptionsHgExt {
|
||||
}
|
||||
|
||||
pub trait ConfigSetHgExt {
|
||||
fn load<S: Into<Text>, N: Into<Text>>(
|
||||
&mut self,
|
||||
repo_path: Option<&Path>,
|
||||
readonly_items: Option<Vec<(S, N)>>,
|
||||
) -> Result<()>;
|
||||
|
||||
/// Load system config files if `$HGRCPATH` is not set.
|
||||
/// Return errors parsing files.
|
||||
fn load_system(&mut self) -> Vec<Error>;
|
||||
fn load_system(&mut self, opts: Options) -> Vec<Error>;
|
||||
|
||||
/// Load the dynamic config files for the given repo path.
|
||||
/// Returns errors parsing, generating, or fetching the configs.
|
||||
fn load_dynamic(&mut self, repo_path: &Path) -> Result<Vec<Error>>;
|
||||
fn load_dynamic(&mut self, repo_path: &Path, opts: Options) -> Result<Vec<Error>>;
|
||||
|
||||
/// Load user config files (and environment variables). If `$HGRCPATH` is
|
||||
/// set, load files listed in that environment variable instead.
|
||||
/// Return errors parsing files.
|
||||
fn load_user(&mut self) -> Vec<Error>;
|
||||
fn load_user(&mut self, opts: Options) -> Vec<Error>;
|
||||
|
||||
/// Load repo config files.
|
||||
fn load_repo(&mut self, repo_path: &Path) -> Vec<Error>;
|
||||
fn load_repo(&mut self, repo_path: &Path, opts: Options) -> Vec<Error>;
|
||||
|
||||
/// Load a specified config file. Respect HGPLAIN environment variables.
|
||||
/// Return errors parsing files.
|
||||
@ -98,22 +104,13 @@ pub trait FromConfigValue: Sized {
|
||||
fn try_from_str(s: &str) -> Result<Self>;
|
||||
}
|
||||
|
||||
/// Load system, user config files.
|
||||
pub fn load() -> Result<ConfigSet> {
|
||||
let mut set = ConfigSet::new();
|
||||
let mut errors = vec![];
|
||||
|
||||
// Only load builtin configs if HGRCPATH is not set.
|
||||
if std::env::var(HGRCPATH).is_err() {
|
||||
errors.append(&mut set.parse(MERGE_TOOLS_CONFIG, &"merge-tools.rc".into()));
|
||||
}
|
||||
errors.append(&mut set.load_system());
|
||||
errors.append(&mut set.load_user());
|
||||
|
||||
if !errors.is_empty() {
|
||||
return Err(Errors(errors).into());
|
||||
}
|
||||
Ok(set)
|
||||
pub fn load<S: Into<Text>, N: Into<Text>>(
|
||||
repo_path: Option<&Path>,
|
||||
readonly_items: Option<Vec<(S, N)>>,
|
||||
) -> Result<ConfigSet> {
|
||||
let mut cfg = ConfigSet::new();
|
||||
cfg.load(repo_path, readonly_items)?;
|
||||
Ok(cfg)
|
||||
}
|
||||
|
||||
impl OptionsHgExt for Options {
|
||||
@ -240,8 +237,41 @@ impl OptionsHgExt for Options {
|
||||
}
|
||||
|
||||
impl ConfigSetHgExt for ConfigSet {
|
||||
fn load_system(&mut self) -> Vec<Error> {
|
||||
let opts = Options::new().source("system").process_hgplain();
|
||||
/// Load system, user config files.
|
||||
fn load<S: Into<Text>, N: Into<Text>>(
|
||||
&mut self,
|
||||
repo_path: Option<&Path>,
|
||||
readonly_items: Option<Vec<(S, N)>>,
|
||||
) -> Result<()> {
|
||||
let mut errors = vec![];
|
||||
|
||||
let mut opts = Options::new();
|
||||
if let Some(readonly_items) = readonly_items {
|
||||
opts = opts.readonly_items(readonly_items);
|
||||
}
|
||||
|
||||
// Only load builtin configs if HGRCPATH is not set.
|
||||
if std::env::var(HGRCPATH).is_err() {
|
||||
errors.append(&mut self.parse(MERGE_TOOLS_CONFIG, &"merge-tools.rc".into()));
|
||||
}
|
||||
errors.append(&mut self.load_system(opts.clone()));
|
||||
if let Some(repo_path) = repo_path {
|
||||
errors.append(&mut self.load_dynamic(&repo_path, opts.clone())?);
|
||||
}
|
||||
errors.append(&mut self.load_user(opts.clone()));
|
||||
|
||||
if let Some(repo_path) = repo_path {
|
||||
errors.append(&mut self.load_repo(&repo_path, opts.clone()));
|
||||
}
|
||||
|
||||
if !errors.is_empty() {
|
||||
return Err(Errors(errors).into());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn load_system(&mut self, opts: Options) -> Vec<Error> {
|
||||
let opts = opts.source("system").process_hgplain();
|
||||
let mut errors = Vec::new();
|
||||
|
||||
// If $HGRCPATH is set, use it instead.
|
||||
@ -279,7 +309,7 @@ impl ConfigSetHgExt for ConfigSet {
|
||||
errors
|
||||
}
|
||||
|
||||
fn load_dynamic(&mut self, repo_path: &Path) -> Result<Vec<Error>> {
|
||||
fn load_dynamic(&mut self, repo_path: &Path, opts: Options) -> Result<Vec<Error>> {
|
||||
let mut errors = Vec::new();
|
||||
|
||||
if self.get_or_default::<bool>("configs", "loaddynamicconfig")? {
|
||||
@ -317,10 +347,10 @@ impl ConfigSetHgExt for ConfigSet {
|
||||
// repo config ahead of time to read the name.
|
||||
let mut repo_hgrc_path = repo_path.join(".hg");
|
||||
repo_hgrc_path.push("hgrc");
|
||||
if !temp_config.load_user().is_empty() {
|
||||
if !temp_config.load_user(opts.clone()).is_empty() {
|
||||
bail!("unable to read user config to get user name");
|
||||
}
|
||||
let opts = Options::new().source("temp").process_hgplain();
|
||||
let opts = opts.clone().source("temp").process_hgplain();
|
||||
if !temp_config.load_path(repo_hgrc_path, &opts).is_empty() {
|
||||
bail!("unable to read repo config to get repo name");
|
||||
}
|
||||
@ -342,7 +372,7 @@ impl ConfigSetHgExt for ConfigSet {
|
||||
}
|
||||
|
||||
// Read hgrc.dynamic
|
||||
let opts = Options::new().source("dynamic").process_hgplain();
|
||||
let opts = opts.source("dynamic").process_hgplain();
|
||||
errors.append(&mut self.load_path(&dynamic_path, &opts));
|
||||
|
||||
// Log config ages
|
||||
@ -372,7 +402,7 @@ impl ConfigSetHgExt for ConfigSet {
|
||||
Ok(errors)
|
||||
}
|
||||
|
||||
fn load_user(&mut self) -> Vec<Error> {
|
||||
fn load_user(&mut self, opts: Options) -> Vec<Error> {
|
||||
let mut errors = Vec::new();
|
||||
|
||||
// Covert "$VISUAL", "$EDITOR" to "ui.editor".
|
||||
@ -391,7 +421,7 @@ impl ConfigSetHgExt for ConfigSet {
|
||||
"ui",
|
||||
"editor",
|
||||
Some(editor),
|
||||
&Options::new().source(format!("${}", name)),
|
||||
&opts.clone().source(format!("${}", name)),
|
||||
);
|
||||
break;
|
||||
}
|
||||
@ -402,7 +432,7 @@ impl ConfigSetHgExt for ConfigSet {
|
||||
self.set("profiling", "type", Some(profiling_type), &"$HGPROF".into());
|
||||
}
|
||||
|
||||
let opts = Options::new().source("user").process_hgplain();
|
||||
let opts = opts.source("user").process_hgplain();
|
||||
|
||||
// If HGRCPATH is set, don't load user configs
|
||||
if env::var("HGRCPATH").is_err() {
|
||||
@ -422,10 +452,10 @@ impl ConfigSetHgExt for ConfigSet {
|
||||
errors
|
||||
}
|
||||
|
||||
fn load_repo(&mut self, repo_path: &Path) -> Vec<Error> {
|
||||
fn load_repo(&mut self, repo_path: &Path, opts: Options) -> Vec<Error> {
|
||||
let mut errors = Vec::new();
|
||||
|
||||
let opts = Options::new().source("repo").process_hgplain();
|
||||
let opts = opts.source("repo").process_hgplain();
|
||||
|
||||
let hgrc_path = repo_path.join("hgrc");
|
||||
errors.append(&mut self.load_path(hgrc_path, &opts));
|
||||
@ -977,10 +1007,10 @@ mod tests {
|
||||
|
||||
let mut cfg = ConfigSet::new();
|
||||
|
||||
cfg.load_user();
|
||||
cfg.load_user(Options::new());
|
||||
assert!(cfg.sections().is_empty());
|
||||
|
||||
cfg.load_system();
|
||||
cfg.load_system(Options::new());
|
||||
assert_eq!(cfg.get("x", "a"), Some("1".into()));
|
||||
assert_eq!(cfg.get("y", "b"), Some("2".into()));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user