Patchwork D2937: fancyopts: prevent mutation of the default value in customopts

login
register
mail settings
Submitter phabricator
Date March 24, 2018, 3:07 a.m.
Message ID <ca9dbc5e2b0241aca7a0f27b625ce054@localhost.localdomain>
Download mbox | patch
Permalink /patch/29805/
State Not Applicable
Headers show

Comments

phabricator - March 24, 2018, 3:07 a.m.
This revision was automatically updated to reflect the committed changes.
Closed by commit rHGef6215df2402: fancyopts: prevent mutation of the default value in customopts (authored by dploch, committed by ).

CHANGED PRIOR TO COMMIT
  https://phab.mercurial-scm.org/D2937?vs=7258&id=7264#toc

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D2937?vs=7258&id=7264

REVISION DETAIL
  https://phab.mercurial-scm.org/D2937

AFFECTED FILES
  mercurial/fancyopts.py
  mercurial/help.py

CHANGE DETAILS




To: dploch, #hg-reviewers, yuja
Cc: mercurial-devel

Patch

diff --git a/mercurial/help.py b/mercurial/help.py
--- a/mercurial/help.py
+++ b/mercurial/help.py
@@ -87,7 +87,7 @@ 
         lo = '--' + longopt
 
         if isinstance(default, fancyopts.customopt):
-            default = default.defaultvalue
+            default = default.getdefaultvalue()
         if default and not callable(default):
             # default is of unknown type, and in Python 2 we abused
             # the %s-shows-repr property to handle integers etc. To
diff --git a/mercurial/fancyopts.py b/mercurial/fancyopts.py
--- a/mercurial/fancyopts.py
+++ b/mercurial/fancyopts.py
@@ -208,20 +208,27 @@ 
     __metaclass__ = abc.ABCMeta
 
     def __init__(self, defaultvalue):
-        self.defaultvalue = defaultvalue
+        self._defaultvalue = defaultvalue
 
     def _isboolopt(self):
         return False
 
+    def getdefaultvalue(self):
+        """Returns the default value for this opt.
+
+        Subclasses should override this to return a new value if the value type
+        is mutable."""
+        return self._defaultvalue
+
     @abc.abstractmethod
     def newstate(self, oldstate, newparam, abort):
         """Adds newparam to oldstate and returns the new state.
 
         On failure, abort can be called with a string error message."""
 
 class _simpleopt(customopt):
     def _isboolopt(self):
-        return isinstance(self.defaultvalue, (bool, type(None)))
+        return isinstance(self._defaultvalue, (bool, type(None)))
 
     def newstate(self, oldstate, newparam, abort):
         return newparam
@@ -235,6 +242,9 @@ 
         return self.callablefn(newparam)
 
 class _listopt(customopt):
+    def getdefaultvalue(self):
+        return self._defaultvalue[:]
+
     def newstate(self, oldstate, newparam, abort):
         oldstate.append(newparam)
         return oldstate
@@ -313,7 +323,7 @@ 
         defmap[name] = _defaultopt(default)
 
         # copy defaults to state
-        state[name] = defmap[name].defaultvalue
+        state[name] = defmap[name].getdefaultvalue()
 
         # does it take a parameter?
         if not defmap[name]._isboolopt():