<html>
<head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
</head>
<body text="#000000" bgcolor="#FFFFFF">
<p>Thanks for sending this out and sorry for not paying attention to
it for so long.</p>
<p>The relevant parts of the sprint discussion, I think, are in the
sections "Friendly HG Breakout" and "
<meta charset="utf-8">
Experimental as a Tag instead of a Name" (those are the two places
where "registry" came up. There's also some related discussion in
the "
<meta charset="utf-8">
Flags and defaults breakout" breakout, but that stuff has mostly
been sent in patches by Rodrigo and myself already.<br>
</p>
<p>I have to take a closer look at this patch and at Jun's immutable
config stuff to see if these interact at all. I also think that
David SP was thinking about some config registry stuff as well. I
may play with this idea during the freeze to see if I can come up
with a nice incremental conversion as well.</p>
<p>Again, thanks for the RFC. I'll try to dive in deeper soon.</p>
<p>~Ryan<br>
</p>
<p><br>
</p>
<div class="moz-cite-prefix">On 3/24/17 5:41 PM, Gregory Szorc
wrote:<br>
</div>
<blockquote
cite="mid:CAKQoGakNEYQywsatqpJXLtkr8AUL0aLETW2jhXndDsgLxdzM+w@mail.gmail.com"
type="cite">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<div dir="ltr">On Fri, Mar 24, 2017 at 10:24 AM, Martin von
Zweigbergk <span dir="ltr"><<a moz-do-not-send="true"
href="mailto:martinvonz@google.com" target="_blank">martinvonz@google.com</a>></span>
wrote:<br>
<div class="gmail_extra">
<div class="gmail_quote">
<blockquote class="gmail_quote" style="margin:0 0 0
.8ex;border-left:1px #ccc solid;padding-left:1ex"><span
class="">On Sun, Mar 12, 2017 at 12:18 PM, Gregory Szorc
<<a moz-do-not-send="true"
href="mailto:gregory.szorc@gmail.com">gregory.szorc@gmail.com</a>>
wrote:<br>
> # HG changeset patch<br>
> # User Gregory Szorc <<a moz-do-not-send="true"
href="mailto:gregory.szorc@gmail.com">gregory.szorc@gmail.com</a>><br>
> # Date 1489346234 25200<br>
> # Sun Mar 12 12:17:14 2017 -0700<br>
> # Node ID dd26bc2a3056879181851aaa3ff4ac<wbr>cbfc42e1ad<br>
> # Parent 62939e0148f170b67ca8c7374f36c4<wbr>13b67fd387<br>
> configoptions: introduce registrar for config
options<br>
<br>
</span>I like the direction. I missed the discussion at
the sprint. Was the<br>
consensus that this is the way to go?<br>
</blockquote>
<div><br>
</div>
<div>There were some side discussions. Not anything formal
IIRC.<br>
</div>
<div> </div>
<blockquote class="gmail_quote" style="margin:0 0 0
.8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
What's the next step? Will you send a non-RFC series
adding a few<br>
users as well? I'm also curious to see the "Actually
hooking it up to<br>
config loading" step.<br>
</blockquote>
<div><br>
</div>
<div>I have no plans to work on this.<br>
<br>
I put the RFC out there because there were a number of
conversations around overhauling configs and I wanted a
tangible prototype for a formal config declaration
mechanism to be in people's minds so they could consider
benefits that a more formal config mechanism would have.
(I think it can solve a lot of problems around things like
environment variable mappings, config aliases, stronger
type checking, mapping configs to command arguments, etc.)<br>
</div>
<div> </div>
<blockquote class="gmail_quote" style="margin:0 0 0
.8ex;border-left:1px #ccc solid;padding-left:1ex">
<div>
<div class="h5"><br>
><br>
> Various talks at the sprint have revolved around
establishing more<br>
> formalization around config options. Specific
problems we'd like<br>
> to solve or are thinking about solving include:<br>
><br>
> * Experimental config options not documented and
are not discoverable<br>
> to end-users.<br>
> * Config options aren't strongly typed (it
depends how they are<br>
> accessed).<br>
> * Config options for extensions don't appear in
`hg help config`.<br>
> * There is no formal mechanism to map a config
option to command<br>
> argument behavior. e.g. have a config option
imply a command<br>
> argument. Instead, logic is done in the command
implementation,<br>
> which results in inconsistent behavior, error
messages, weird<br>
> `hg help <command>` output.<br>
> * Config option validation is done at the call
site and not as part<br>
> of config loading or command dispatching.<br>
> * Config options are declared by side-effect all
over the repo. It<br>
> might be nicer to have a single "registry" so
the full context of<br>
> all options is easily referenced.<br>
> * No mechanism to "alias" an old config option to
a new one. e.g.<br>
> carrying over "experimental.feature" to its
final value.<br>
><br>
> This patch introduces a very eary proof of
concept for improving<br>
> the situation. It adds config options to the
"registrar" mechanism,<br>
> which allows their declaration to be formalized
and recorded in<br>
> a central location. This is conceptually similar
to populating a<br>
> central dict with the data. I chose to use
decorators and (for now)<br>
> empty functions for declaring config options.
This allows docstrings<br>
> to be used for writing the config help.<br>
><br>
> In the future, one could imagine actually calling
the function<br>
> declaring the config option. It could receive a
ui instance and<br>
> an object defining the command being invoked. The
function could<br>
> then look for conflicting options, adjust command
arguments, etc.<br>
> It could do so in a way that is consistent across
commands. e.g.<br>
> a ConfigOptionConflict exception could be raised
and the ui or<br>
> dispatcher could consistently format that error
condition rather<br>
> than leaving it to individual command functions
to raise on their<br>
> own.<br>
><br>
> It's worth noting that we need all the *core*
options defined in<br>
> a central file because of lazy module loading. If
a module isn't<br>
> loaded, the config option declarations wouldn't
be called!<br>
><br>
> There are several things missing from this patch
and open issues to<br>
> resolve:<br>
><br>
> * i18n of help text<br>
> * Actually using docstrings in `hg help`<br>
> * Hooking up strong typing or hinted typing<br>
> * Figuring out how to declare config options with
sub-options<br>
> * Better solution for declaring config options
that have both global<br>
> options and per-item sub-options (like
hostsecurity.ciphers)<br>
> * Actually hooking it up to config loading<br>
> * Mechanism for declaring config options in
extensions<br>
><br>
> diff --git a/mercurial/configoptions.py
b/mercurial/configoptions.py<br>
> new file mode 100644<br>
> --- /dev/null<br>
> +++ b/mercurial/configoptions.py<br>
> @@ -0,0 +1,102 @@<br>
> +# configoptions.py -- Declaration of
configuration options<br>
> +#<br>
> +# Copyright 2017 Gregory Szorc <<a
moz-do-not-send="true"
href="mailto:gregory.szorc@gmail.com">gregory.szorc@gmail.com</a>><br>
> +#<br>
> +# This software may be used and distributed
according to the terms of the<br>
> +# GNU General Public License version 2 or any
later version.<br>
> +<br>
> +from . import (<br>
> + registrar,<br>
> +)<br>
> +<br>
> +configoption = registrar.configoption()<br>
> +<br>
> +@configoption('hostsecurity.<wbr>ciphers')<br>
> +def optionciphers():<br>
> + """Defines the cryptographic ciphers to use
for connections.<br>
> +<br>
> + Value must be a valid OpenSSL Cipher List
Format as documented at<br>
> + <a moz-do-not-send="true"
href="https://urldefense.proofpoint.com/v2/url?u=https-3A__www.openssl.org_docs_manmaster_apps_ciphers.html-23CIPHER-2DLIST-2DFORMAT&d=DwMFaQ&c=5VD0RTtNlTh3ycd41b3MUw&r=Jw8rundaE7TbmqBYd1txIQ&m=6FYVT5Po5N2vyslmzAdZmMlUq8oQi1a-uYeozyLWArw&s=JbBgutXmiKYWcHYWQaz5_9SUBel8KfUtwNVbTj_RPRA&e="
rel="noreferrer" target="_blank">https://www.openssl.org/docs/<wbr>manmaster/apps/ciphers.html#<wbr>CIPHER-LIST-FORMAT</a>.<br>
> +<br>
> + This setting is for advanced users only.
Setting to incorrect values<br>
> + can significantly lower connection security
or decrease performance.<br>
> + You have been warned.<br>
> +<br>
> + This option requires Python 2.7.<br>
> + """<br>
> +<br>
> +@configoption('hostsecurity.<wbr>minimumprotocol')<br>
> +def optionminimumprotocol():<br>
> + """Defines the minimum channel encryption
protocol to use.<br>
> +<br>
> + By default, the highest version of TLS
supported by both client and<br>
> + server is used.<br>
> +<br>
> + Allowed values are: ``tls1.0``, ``tls1.1``,
``tls1.2``.<br>
> +<br>
> + When running on an old Python version, only
``tls1.0`` is allowed since<br>
> + old versions of Python only support up to
TLS 1.0.<br>
> +<br>
> + When running a Python that supports modern
TLS versions, the default is<br>
> + ``tls1.1``. ``tls1.0`` can still be used to
allow TLS 1.0. However, this<br>
> + weakens security and should only be used as
a feature of last resort if<br>
> + a server does not support TLS 1.1+.<br>
> + """<br>
> +<br>
> +@configoption('hostsecurity.*<wbr>:ciphers')<br>
> +def perhostciphers():<br>
> + """Per host version of
``hostsecurity.ciphers``."""<br>
> +<br>
> +@configoption('hostsecurity.*<wbr>:fingerprints')<br>
> +def perhostfingerprints():<br>
> + """A list of hashes of the DER encoded
peer/remote certificate. Values<br>
> + have the form ``algorithm``:``fingerprint``.
e.g.<br>
> + ``sha256:<wbr>c3ab8ff13720e8ad9047dd39466b3c<wbr>8974e592c2fa383d4a3960714caef0<wbr>c4f2``.<br>
> +<br>
> + The following algorithms/prefixes are
supported: ``sha1``, ``sha256``,<br>
> + ``sha512``.<br>
> +<br>
> + Use of ``sha256`` or ``sha512`` is
preferred.<br>
> +<br>
> + If a fingerprint is specified, the CA chain
is not validated for this<br>
> + host and Mercurial will require the remote
certificate to match one<br>
> + of the fingerprints specified. This means if
the server updates its<br>
> + certificate, Mercurial will abort until a
new fingerprint is defined.<br>
> + This can provide stronger security than
traditional CA-based validation<br>
> + at the expense of convenience.<br>
> +<br>
> + This option takes precedence over
``verifycertsfile``.<br>
> + """<br>
> +<br>
> +@configoption('hostsecurity.*<wbr>:minimumprotocol')<br>
> +def perhostminimumprotocol():<br>
> + """This behaves like ``minimumprotocol`` as
described above except it<br>
> + only applies to the host on which it is
defined.<br>
> + """<br>
> +<br>
> +@configoption('hostsecurity.*<wbr>:verifycertsfile')<br>
> +def perhostverifycertsfile():<br>
> + """Path to file a containing a list of PEM
encoded certificates used to<br>
> + verify the server certificate. Environment
variables and ``~user``<br>
> + constructs are expanded in the filename.<br>
> +<br>
> + The server certificate or the certificate's
certificate authority (CA)<br>
> + must match a certificate from this file or
certificate verification<br>
> + will fail and connections to the server will
be refused.<br>
> +<br>
> + If defined, only certificates provided by
this file will be used:<br>
> + ``web.cacerts`` and any system/default
certificates will not be<br>
> + used.<br>
> +<br>
> + This option has no effect if the per-host
``fingerprints`` option<br>
> + is set.<br>
> +<br>
> + The format of the file is as follows::<br>
> +<br>
> + -----BEGIN CERTIFICATE-----<br>
> + ... (certificate in base64 PEM encoding)
...<br>
> + -----END CERTIFICATE-----<br>
> + -----BEGIN CERTIFICATE-----<br>
> + ... (certificate in base64 PEM encoding)
...<br>
> + -----END CERTIFICATE-----<br>
> + """<br>
> diff --git a/mercurial/registrar.py
b/mercurial/registrar.py<br>
> --- a/mercurial/registrar.py<br>
> +++ b/mercurial/registrar.py<br>
> @@ -251,4 +251,20 @@ class templatefunc(_<wbr>templateregistrarbas<br>
><br>
> Otherwise, explicit
'templater.loadfunction()' is needed.<br>
> """<br>
> _getname = _funcregistrarbase._<wbr>parsefuncdecl<br>
> +<br>
> +class configoption(_<wbr>funcregistrarbase):<br>
> + """Decorator to register a config option."""<br>
> + def _getname(self, decl):<br>
> + return decl<br>
> +<br>
> + def _formatdoc(self, decl, doc):<br>
> + return pycompat.sysstr('.'.join(decl)<wbr>)<br>
> +<br>
> + def _extrasetup(self, name, func, *args,
**kwargs):<br>
> + section, option = name.split('.', 1)<br>
> +<br>
> + self._section = section<br>
> + self._name = name<br>
> +<br>
> + self._extra = kwargs<br>
> diff --git a/mercurial/ui.py b/mercurial/ui.py<br>
> --- a/mercurial/ui.py<br>
> +++ b/mercurial/ui.py<br>
> @@ -27,8 +27,9 @@ from .node import hex<br>
><br>
> from . import (<br>
> color,<br>
> config,<br>
> + configoptions,<br>
> encoding,<br>
> error,<br>
> formatter,<br>
> progress,<br>
> @@ -135,8 +136,11 @@ class ui(object):<br>
> Use uimod.ui.load() to create a ui which
knows global and user configs.<br>
> In most cases, you should use ui.copy()
to create a copy of an existing<br>
> ui object.<br>
> """<br>
> + # Ensure config options are imported as
a side-effect.<br>
> + options = configoptions.configoption<br>
> +<br>
> # _buffers: used for temporary capture
of output<br>
> self._buffers = []<br>
> # 3-tuple describing how each buffer in
the stack behaves.<br>
> # Values are (capture stderr, capture
subprocesses, apply labels).<br>
</div>
</div>
<br>
</blockquote>
</div>
</div>
</div>
</blockquote>
<br>
</body>
</html>