mirror of
https://github.com/facebook/sapling.git
synced 2024-10-07 07:17:55 +03:00
config: load .hg/hgrc.dynamic
Summary: Adds .hg/hgrc.dynamic to the default load path, before .hg/hgrc though, so it can be override. Reviewed By: quark-zju Differential Revision: D21310921 fbshipit-source-id: 288a2a2ba671943a9f8532489c29e819f9d891e1
This commit is contained in:
parent
dc90e2ca04
commit
6e7f85b949
@ -46,6 +46,7 @@ from . import (
|
||||
registrar,
|
||||
scmutil,
|
||||
ui as uimod,
|
||||
uiconfig,
|
||||
util,
|
||||
)
|
||||
from .i18n import _
|
||||
@ -943,12 +944,15 @@ def _log_exception(lui, e):
|
||||
pass
|
||||
|
||||
|
||||
def _getlocal(ui, rpath, wd=None):
|
||||
def _getlocal(ui, rpath):
|
||||
"""Return (path, local ui object) for the given target path.
|
||||
|
||||
Takes paths in [cwd]/.hg/hgrc into account."
|
||||
"""
|
||||
if wd is None:
|
||||
if rpath:
|
||||
path = ui.expandpath(rpath)
|
||||
lui = ui.copy()
|
||||
else:
|
||||
try:
|
||||
wd = pycompat.getcwd()
|
||||
except OSError as e:
|
||||
@ -964,16 +968,17 @@ def _getlocal(ui, rpath, wd=None):
|
||||
_("error getting current working directory: %s")
|
||||
% encoding.strtolocal(e.strerror)
|
||||
)
|
||||
path = cmdutil.findrepo(wd) or ""
|
||||
if not path:
|
||||
lui = ui
|
||||
else:
|
||||
lui = ui.copy()
|
||||
lui.readconfig(os.path.join(path, ".hg", "hgrc"), path)
|
||||
path = cmdutil.findrepo(wd) or ""
|
||||
|
||||
if rpath:
|
||||
path = lui.expandpath(rpath)
|
||||
lui = ui.copy()
|
||||
if not path:
|
||||
lui = ui
|
||||
else:
|
||||
lui = ui.copy()
|
||||
|
||||
if path:
|
||||
uiconfig.loaddynamicconfig(lui, path)
|
||||
|
||||
# Load the primary config after the dynamic one, so it overwrites it
|
||||
lui.readconfig(os.path.join(path, ".hg", "hgrc"), path)
|
||||
|
||||
return path, lui
|
||||
|
@ -66,6 +66,7 @@ from . import (
|
||||
transaction,
|
||||
treestate,
|
||||
txnutil,
|
||||
uiconfig,
|
||||
util,
|
||||
vfs as vfsmod,
|
||||
visibility,
|
||||
@ -439,6 +440,8 @@ class localrepository(object):
|
||||
# This list it to be filled by extension during repo setup
|
||||
self._phasedefaults = []
|
||||
try:
|
||||
uiconfig.loaddynamicconfig(self.ui, self.root)
|
||||
# Load the primary config after the dynamic one, so it overwrites it
|
||||
self.ui.readconfig(self.localvfs.join("hgrc"), self.root)
|
||||
self._loadextensions()
|
||||
except IOError:
|
||||
|
@ -12,10 +12,13 @@ from __future__ import absolute_import
|
||||
|
||||
import contextlib
|
||||
import os
|
||||
import subprocess
|
||||
import time
|
||||
from typing import List, Optional, Tuple
|
||||
|
||||
from bindings import configparser
|
||||
|
||||
from ..hgext.extutil import runbgcommand
|
||||
from . import configitems, error, pycompat, util
|
||||
from .encoding import unifromlocal, unitolocal
|
||||
from .i18n import _
|
||||
@ -544,3 +547,29 @@ def parselist(value):
|
||||
return [unitolocal(v) for v in configparser.parselist(unifromlocal(value))]
|
||||
else:
|
||||
return value
|
||||
|
||||
|
||||
def loaddynamicconfig(ui, path):
|
||||
if ui.configbool("configs", "loaddynamicconfig", False):
|
||||
hgrcdyn = os.path.join(path, ".hg", "hgrc.dynamic")
|
||||
|
||||
if ui.configbool("configs", "autogeneratedynamicconfig", False):
|
||||
if not os.path.exists(hgrcdyn):
|
||||
try:
|
||||
ui.debug("synchronously generating dynamic config\n")
|
||||
subprocess.check_call(["hg", "debugdynamicconfig"])
|
||||
except Exception as ex:
|
||||
raise error.Abort(
|
||||
_("unable to generate dynamic Mercurial config: %s") % ex
|
||||
)
|
||||
|
||||
ui.readconfig(hgrcdyn, path)
|
||||
|
||||
generationtime = ui.configint("configs", "generationtime", -1)
|
||||
if generationtime != -1:
|
||||
mtimelimit = time.time() - generationtime
|
||||
if not os.path.exists(hgrcdyn) or os.lstat(hgrcdyn).st_mtime < mtimelimit:
|
||||
# TODO: some how prevent kicking off the background process if
|
||||
# the file is read-only or if the previous kick offs failed.
|
||||
ui.debug("background generating dynamic config\n")
|
||||
runbgcommand(["hg", "debugdynamicconfig"], os.environ.copy())
|
||||
|
@ -8,6 +8,7 @@ anyhow = "1.0.19"
|
||||
configparser = { path = "../configparser" }
|
||||
hgtime = { path = "../hgtime" }
|
||||
hostname = "0.3"
|
||||
minibytes = { path = "../minibytes" }
|
||||
os_info = "2.0.1"
|
||||
|
||||
[dev-dependencies]
|
||||
|
@ -14,6 +14,7 @@ use std::path::Path;
|
||||
|
||||
use anyhow::{anyhow, bail, Result};
|
||||
use hostname;
|
||||
use minibytes::Text;
|
||||
|
||||
use configparser::config::ConfigSet;
|
||||
use hgtime::HgTime;
|
||||
@ -196,12 +197,16 @@ impl Generator {
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn load_hgrc(&mut self, value: &'static str) -> Result<()> {
|
||||
pub(crate) fn load_hgrc(
|
||||
&mut self,
|
||||
value: impl Into<Text> + Clone + std::fmt::Display,
|
||||
) -> Result<()> {
|
||||
let value_copy = value.clone();
|
||||
let errors = self.config.parse(value, &"dynamicconfigs".into());
|
||||
if !errors.is_empty() {
|
||||
bail!(
|
||||
"invalid dynamic config blob: '{}'\nerrors: '{:?}'",
|
||||
value,
|
||||
value_copy,
|
||||
errors
|
||||
);
|
||||
}
|
||||
@ -209,8 +214,12 @@ impl Generator {
|
||||
}
|
||||
|
||||
pub fn execute(mut self) -> Result<ConfigSet> {
|
||||
#[cfg(feature = "fb")]
|
||||
self._execute(fb::fb_rules)?;
|
||||
if std::env::var("HG_TEST_DYNAMICCONFIG").is_ok() {
|
||||
self._execute(test_rules)?;
|
||||
} else {
|
||||
#[cfg(feature = "fb")]
|
||||
self._execute(fb::fb_rules)?;
|
||||
}
|
||||
Ok(self.config)
|
||||
}
|
||||
|
||||
@ -254,6 +263,16 @@ fn get_hg_group(tiers: &HashSet<String>, shard: u8) -> HgGroup {
|
||||
}
|
||||
}
|
||||
|
||||
/// Rules used in our integration test environment
|
||||
fn test_rules(gen: &mut Generator) -> Result<()> {
|
||||
if let Ok(path) = std::env::var("HG_TEST_DYNAMICCONFIG") {
|
||||
let hgrc = std::fs::read_to_string(path).unwrap();
|
||||
gen.load_hgrc(hgrc).unwrap();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) mod tests {
|
||||
use super::*;
|
||||
|
57
eden/scm/tests/test-debugdynamicconfig.t
Normal file
57
eden/scm/tests/test-debugdynamicconfig.t
Normal file
@ -0,0 +1,57 @@
|
||||
#chg-compatible
|
||||
|
||||
$ configure modern
|
||||
|
||||
$ setconfig configs.loaddynamicconfig=True
|
||||
$ export HG_TEST_DYNAMICCONFIG="$TESTTMP/test_hgrc"
|
||||
$ cat > test_hgrc <<EOF
|
||||
> [section]
|
||||
> key=value
|
||||
> EOF
|
||||
|
||||
$ hg init client
|
||||
$ cd client
|
||||
|
||||
Verify it can be manually generated
|
||||
|
||||
$ hg debugdynamicconfig
|
||||
$ cat .hg/hgrc.dynamic
|
||||
[section]
|
||||
key=value
|
||||
|
||||
$ hg config section.key
|
||||
value
|
||||
|
||||
Verify it can be automatically synchronously generated
|
||||
|
||||
$ rm .hg/hgrc.dynamic
|
||||
$ hg config section.key
|
||||
[1]
|
||||
$ hg config section.key --config configs.autogeneratedynamicconfig=True
|
||||
value
|
||||
$ cat .hg/hgrc.dynamic
|
||||
[section]
|
||||
key=value
|
||||
|
||||
Verify it can be automatically asynchronously regenerated
|
||||
|
||||
$ cat > $TESTTMP/test_hgrc <<EOF
|
||||
> [section]
|
||||
> key=value
|
||||
> [section2]
|
||||
> key2=value2
|
||||
> EOF
|
||||
$ hg config section2.key2 --config configs.generationtime=30 # No regen, because too soon
|
||||
[1]
|
||||
$ sleep 1
|
||||
$ hg status --config configs.generationtime=1 # Regen, because lower time limit
|
||||
$ sleep 0.5 # Time for background process to complete
|
||||
$ hg config section2.key2
|
||||
value2
|
||||
$ cat .hg/hgrc.dynamic
|
||||
[section]
|
||||
key=value
|
||||
|
||||
[section2]
|
||||
key2=value2
|
||||
|
Loading…
Reference in New Issue
Block a user