mirror of
https://github.com/facebook/sapling.git
synced 2024-10-06 14:58:03 +03:00
configs: version dynamic configs
Summary: If we release a new version of Mercurial, we want to ensure that it's builtin configs are used immediately. To do so, let's write a version number into the generated config file, and if the version number doesn't match, we force a synchronous regeneration of the config file. For now, if regeneration fails, we just log it. In the future we'll probably throw an exception and block the user since we want to ensure people are running with modern configuration. Reviewed By: quark-zju Differential Revision: D21651317 fbshipit-source-id: 3edbaf6777f4ca2363d8617fad03c21204b468a2
This commit is contained in:
parent
cd92c10363
commit
9f6f200a08
@ -165,7 +165,6 @@ coreconfigitem("commit", "description-size-limit", default=None)
|
||||
coreconfigitem("commit", "extras-size-limit", default=None)
|
||||
coreconfigitem("committemplate", ".*", default=None, generic=True)
|
||||
coreconfigitem("connectionpool", "lifetime", default=None)
|
||||
coreconfigitem("configs", "autogeneratedynamicconfig", default=False)
|
||||
coreconfigitem("configs", "generationtime", default=-1)
|
||||
coreconfigitem("configs", "loaddynamicconfig", default=False)
|
||||
coreconfigitem("configs", "mismatchsampling", default=10000)
|
||||
|
@ -13,6 +13,7 @@ from __future__ import absolute_import
|
||||
import contextlib
|
||||
import os
|
||||
import random
|
||||
import re
|
||||
import subprocess
|
||||
import time
|
||||
from typing import List, Optional, Tuple
|
||||
@ -562,15 +563,33 @@ def loaddynamicconfig(ui, path):
|
||||
|
||||
hgrcdyn = os.path.join(path, "hgrc.dynamic")
|
||||
|
||||
if ui.configbool("configs", "autogeneratedynamicconfig"):
|
||||
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
|
||||
)
|
||||
# Check the version of the existing generated config. If it doesn't
|
||||
# match the current version, regenerate it immediately.
|
||||
try:
|
||||
with open(hgrcdyn, "r") as f:
|
||||
content = f.read()
|
||||
matches = re.search("^# version=(.*)$", content, re.MULTILINE)
|
||||
version = matches.group(1) if matches else None
|
||||
except IOError:
|
||||
version = None
|
||||
|
||||
if version is None or version != util.version():
|
||||
try:
|
||||
ui.debug(
|
||||
"synchronously generating dynamic config - new version %s, old version %s\n"
|
||||
% (util.version(), version)
|
||||
)
|
||||
reponame = ui.config("remotefilelog", "reponame") or ""
|
||||
generatedynamicconfig(ui, reponame, path)
|
||||
except Exception as ex:
|
||||
# TODO: Eventually this should throw an exception, once we're
|
||||
# confident it's reliable.
|
||||
ui.log(
|
||||
"exceptions",
|
||||
"unable to generate dynamicconfig",
|
||||
exception_type="DynamicconfigGeneration",
|
||||
exception_msg="unable to generate dynamicconfig: %s" % str(ex),
|
||||
)
|
||||
|
||||
ui.readconfig(hgrcdyn, path)
|
||||
|
||||
@ -617,15 +636,14 @@ def validatedynamicconfig(ui):
|
||||
]
|
||||
# Configs that are allowed to be different, usually because they must come
|
||||
# from external configuration (like hotfixes).
|
||||
whitelist = [
|
||||
("extensions", "hotfix"),
|
||||
]
|
||||
whitelist = [("extensions", "hotfix")]
|
||||
|
||||
testrcs = ui.configlist("configs", "testdynamicconfigsubset")
|
||||
if testrcs:
|
||||
originalrcs.extend(testrcs)
|
||||
issues = ui._uiconfig._rcfg.ensure_location_supersets("hgrc.dynamic",
|
||||
originalrcs, whitelist)
|
||||
issues = ui._uiconfig._rcfg.ensure_location_supersets(
|
||||
"hgrc.dynamic", originalrcs, whitelist
|
||||
)
|
||||
|
||||
for section, key, dynamic_value, file_value in issues:
|
||||
msg = _("Config mismatch: %s.%s has '%s' (dynamic) vs '%s' (file)\n") % (
|
||||
@ -639,20 +657,24 @@ def validatedynamicconfig(ui):
|
||||
|
||||
samplerate = ui.configint("configs", "mismatchsampling")
|
||||
if random.randint(1, samplerate) == 1:
|
||||
reponame = ui.config("remotefilelog", "reponame")
|
||||
ui.log(
|
||||
"config_mismatch",
|
||||
msg,
|
||||
config="%s.%s" % (section, key),
|
||||
expected=file_value,
|
||||
actual=dynamic_value,
|
||||
repo=reponame or "unknown",
|
||||
)
|
||||
|
||||
|
||||
def applydynamicconfig(ui, reponame):
|
||||
if ui.configbool("configs", "loaddynamicconfig"):
|
||||
dynamicconfig.applydynamicconfig(ui._uiconfig._rcfg._rcfg, reponame)
|
||||
|
||||
validatedynamicconfig(ui)
|
||||
|
||||
|
||||
def generatedynamicconfig(ui, reponame, sharedpath):
|
||||
if ui.configbool("configs", "loaddynamicconfig"):
|
||||
dynamicconfig.generatedynamicconfig(reponame, sharedpath)
|
||||
|
@ -10,6 +10,7 @@ cpython-ext = { path = "../../../../lib/cpython-ext", default-features = false }
|
||||
dynamicconfig = { path = "../../../../lib/dynamicconfig" }
|
||||
configparser = { path = "../../../../lib/configparser" }
|
||||
pyconfigparser = { path = "../pyconfigparser" }
|
||||
version = { path = "../../../../lib/version" }
|
||||
|
||||
[features]
|
||||
python2 = ["cpython/python27-sys", "cpython-ext/python2"]
|
||||
|
@ -9,7 +9,6 @@
|
||||
|
||||
use std::fs;
|
||||
|
||||
use anyhow::{format_err, Error};
|
||||
use cpython::*;
|
||||
use cpython_ext::{error::ResultPyErrExt, PyNone, PyPathBuf};
|
||||
|
||||
@ -68,7 +67,8 @@ fn generatedynamicconfig(
|
||||
.map_pyerr(py)?;
|
||||
let config_str = config.to_string();
|
||||
let config_str = format!(
|
||||
"# Generated by `hg debugdynamicconfig` - DO NOT MODIFY\n{}",
|
||||
"# version={}\n# Generated by `hg debugdynamicconfig` - DO NOT MODIFY\n{}",
|
||||
::version::VERSION,
|
||||
config_str
|
||||
);
|
||||
|
||||
|
@ -298,7 +298,8 @@ pub fn debugdynamicconfig(_opts: NoOpts, _io: &mut IO, repo: Repo) -> Result<u8>
|
||||
let config = Generator::new(repo_name)?.execute()?;
|
||||
let config_str = config.to_string();
|
||||
let config_str = format!(
|
||||
"# Generated by `hg debugdynamicconfig` - DO NOT MODIFY\n{}",
|
||||
"# version={}\n# Generated by `hg debugdynamicconfig` - DO NOT MODIFY\n{}",
|
||||
::version::VERSION,
|
||||
config_str
|
||||
);
|
||||
|
||||
|
@ -16,6 +16,7 @@ Verify it can be manually generated
|
||||
|
||||
$ hg debugdynamicconfig
|
||||
$ cat .hg/hgrc.dynamic
|
||||
# version=4.4.2* (glob)
|
||||
# Generated by `hg debugdynamicconfig` - DO NOT MODIFY
|
||||
[section]
|
||||
key=value
|
||||
@ -27,10 +28,9 @@ 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
|
||||
# version=4.4.2* (glob)
|
||||
# Generated by `hg debugdynamicconfig` - DO NOT MODIFY
|
||||
[section]
|
||||
key=value
|
||||
@ -51,6 +51,7 @@ Verify it can be automatically asynchronously regenerated
|
||||
$ hg config section2.key2
|
||||
value2
|
||||
$ cat .hg/hgrc.dynamic
|
||||
# version=4.4.2* (glob)
|
||||
# Generated by `hg debugdynamicconfig` - DO NOT MODIFY
|
||||
[section]
|
||||
key=value
|
||||
@ -83,6 +84,7 @@ Verify we generate and load from a shared repo
|
||||
$ test -f .hg/hgrc.dynamic
|
||||
[1]
|
||||
$ cat ../shared/.hg/hgrc.dynamic
|
||||
# version=4.4.2* (glob)
|
||||
# Generated by `hg debugdynamicconfig` - DO NOT MODIFY
|
||||
[section]
|
||||
key=value
|
||||
@ -93,6 +95,33 @@ Verify we generate and load from a shared repo
|
||||
$ hg config section.key
|
||||
value
|
||||
|
||||
Verify we regenerate configs if the Mercurial version differs
|
||||
$ cat > ../shared/.hg/hgrc.dynamic <<EOF
|
||||
> # version=1
|
||||
> [section3]
|
||||
> key3=value3
|
||||
> EOF
|
||||
$ hg config section3.key3
|
||||
[1]
|
||||
$ hg config section.key
|
||||
value
|
||||
$ cat ../shared/.hg/hgrc.dynamic
|
||||
# version=4.4.2* (glob)
|
||||
# Generated by `hg debugdynamicconfig` - DO NOT MODIFY
|
||||
[section]
|
||||
key=value
|
||||
|
||||
[section2]
|
||||
key2=value2
|
||||
|
||||
Verify we don't regenerate configs if the Mercurial version hasn't changed
|
||||
$ cat >> ../shared/.hg/hgrc.dynamic <<EOF
|
||||
> [section3]
|
||||
> key3=value3
|
||||
> EOF
|
||||
$ hg config section3.key3
|
||||
value3
|
||||
|
||||
Verify we load dynamicconfigs during clone
|
||||
$ newserver server
|
||||
$ cd $TESTTMP
|
||||
@ -109,6 +138,7 @@ Verify we load dynamicconfigs during clone
|
||||
Hook ran!
|
||||
Hook ran!
|
||||
$ cat client2/.hg/hgrc.dynamic
|
||||
# version=4.4.2* (glob)
|
||||
# Generated by `hg debugdynamicconfig` - DO NOT MODIFY
|
||||
[hooks]
|
||||
pretxnclose=echo "Hook ran!"
|
||||
|
Loading…
Reference in New Issue
Block a user