[PATCH RFC] ui: add support for a tweakdefaults knob

Augie Fackler raf at durin42.com
Wed Jun 14 21:37:21 EDT 2017


# HG changeset patch
# User Augie Fackler <augie at google.com>
# Date 1497488194 14400
#      Wed Jun 14 20:56:34 2017 -0400
# Node ID 0e5ea7a86a8021d02218c35b07366ac6081ab3fb
# Parent  3abba5bc34546951b11b1bd3f5e5c77b90d950d1
ui: add support for a tweakdefaults knob

We've been talking for years about a one-stop config knob to opt in to
better behavior. There have been a lot of ideas thrown around, but
they all seem to be too complicated to get anyone to actually do the
work.. As such, this patch is the stupidest thing that can possibly
work in the name of getting a good feature to users.

Right now it's just three config settings that I think are generally
uncontroversial, but I expect to add more soon. That will likely
include adding new config knobs for the express purpose of adding them
to tweakdefaults.

diff --git a/mercurial/help/config.txt b/mercurial/help/config.txt
--- a/mercurial/help/config.txt
+++ b/mercurial/help/config.txt
@@ -2071,6 +2071,15 @@ User interface controls.
     on all exceptions, even those recognized by Mercurial (such as
     IOError or MemoryError). (default: False)
 
+``tweakdefaults``
+
+    By default Mercurial's behavior changes very little from release
+    to release, but over time the recommended config settings
+    shift. Enable this config to opt in to get automatic tweaks to
+    Mercurial's behavior over time. This config setting will have no
+    effet if ``HGPLAIN` is set or ``HGPLAINEXCEPT`` is set and does
+    not include ``tweakdefaults``. (default: False)
+
 ``username``
     The committer of a changeset created when running "commit".
     Typically a person's name and email address, e.g. ``Fred Widget
diff --git a/mercurial/ui.py b/mercurial/ui.py
--- a/mercurial/ui.py
+++ b/mercurial/ui.py
@@ -43,6 +43,20 @@ urlreq = util.urlreq
 _keepalnum = ''.join(c for c in map(pycompat.bytechr, range(256))
                      if not c.isalnum())
 
+# The config knobs that will be altered (if unset) by ui.tweakdefaults.
+tweakrc = """
+[ui]
+# The rollback command is dangerous. As a rule, don't use it.
+rollback = False
+
+[commands]
+# Make `hg status` emit cwd-relative paths by default.
+status.relative = yes
+
+[diff]
+git = 1
+"""
+
 samplehgrcs = {
     'user':
 """# example user config (see 'hg help config' for more info)
@@ -182,6 +196,7 @@ class ui(object):
             self.fin = src.fin
             self.pageractive = src.pageractive
             self._disablepager = src._disablepager
+            self._tweaked = src._tweaked
 
             self._tcfg = src._tcfg.copy()
             self._ucfg = src._ucfg.copy()
@@ -205,6 +220,7 @@ class ui(object):
             self.fin = util.stdin
             self.pageractive = False
             self._disablepager = False
+            self._tweaked = False
 
             # shared read-only environment
             self.environ = encoding.environ
@@ -241,8 +257,29 @@ class ui(object):
                     u.fixconfig(section=section)
             else:
                 raise error.ProgrammingError('unknown rctype: %s' % t)
+        u._maybetweakdefaults()
         return u
 
+    def _maybetweakdefaults(self):
+        if not self.configbool('ui', 'tweakdefaults'):
+            return
+        if self._tweaked or self.plain('tweakdefaults'):
+            return
+
+        # Note: it is SUPER IMPORTANT that you set self._tweaked to
+        # True *before* any calls to setconfig(), otherwise you'll get
+        # infinite recursion between setconfig and this method.
+        #
+        # TODO: We should extract an inner method in setconfig() to
+        # avoid this weirdness.
+        self._tweaked = True
+        tmpcfg = config.config()
+        tmpcfg.parse('<tweakdefaults>', tweakrc)
+        for section in tmpcfg:
+            for name, value in tmpcfg.items(section):
+                if not self.hasconfig(section, name):
+                    self.setconfig(section, name, value, "<tweakdefaults>")
+
     def copy(self):
         return self.__class__(self)
 
@@ -387,6 +424,7 @@ class ui(object):
         for cfg in (self._ocfg, self._tcfg, self._ucfg):
             cfg.set(section, name, value, source)
         self.fixconfig(section=section)
+        self._maybetweakdefaults()
 
     def _data(self, untrusted):
         return untrusted and self._ucfg or self._tcfg
diff --git a/tests/test-status.t b/tests/test-status.t
--- a/tests/test-status.t
+++ b/tests/test-status.t
@@ -107,6 +107,29 @@ combining patterns with root and pattern
   ? a/in_a
   ? b/in_b
 
+tweaking defaults works
+  $ hg status --cwd a --config ui.tweakdefaults=yes
+  ? 1/in_a_1
+  ? in_a
+  ? ../b/1/in_b_1
+  ? ../b/2/in_b_2
+  ? ../b/in_b
+  ? ../in_root
+  $ HGPLAIN=1 hg status --cwd a --config ui.tweakdefaults=yes
+  ? a/1/in_a_1 (glob)
+  ? a/in_a (glob)
+  ? b/1/in_b_1 (glob)
+  ? b/2/in_b_2 (glob)
+  ? b/in_b (glob)
+  ? in_root
+  $ HGPLAINEXCEPT=tweakdefaults hg status --cwd a --config ui.tweakdefaults=yes
+  ? 1/in_a_1
+  ? in_a
+  ? ../b/1/in_b_1
+  ? ../b/2/in_b_2
+  ? ../b/in_b
+  ? ../in_root
+
 relative paths can be requested
 
   $ cat >> $HGRCPATH <<EOF
@@ -128,6 +151,19 @@ relative paths can be requested
   ? b/in_b (glob)
   ? in_root
 
+if relative paths are explicitly off, tweakdefaults doesn't change it
+  $ cat >> $HGRCPATH <<EOF
+  > [commands]
+  > status.relative = False
+  > EOF
+  $ hg status --cwd a --config ui.tweakdefaults=yes
+  ? a/1/in_a_1 (glob)
+  ? a/in_a (glob)
+  ? b/1/in_b_1 (glob)
+  ? b/2/in_b_2 (glob)
+  ? b/in_b (glob)
+  ? in_root
+
   $ cd ..
 
   $ hg init repo2


More information about the Mercurial-devel mailing list