config: fix -Tjson to not crash due to unsupported defaultvalue types stable
authorYuya Nishihara <yuya@tcha.org>
Sun, 27 Oct 2019 12:30:59 +0900
branchstable
changeset 43335 242ad45b60b3
parent 43334 4128ffba4431
child 43336 a71578ec6257
config: fix -Tjson to not crash due to unsupported defaultvalue types Maybe it isn't great to ignore unsupported types at all, but otherwise "hg config -Tjson" would crash.
mercurial/commands.py
mercurial/formatter.py
tests/test-config.t
--- a/mercurial/commands.py	Sun Oct 27 18:12:24 2019 +0100
+++ b/mercurial/commands.py	Sun Oct 27 12:30:59 2019 +0900
@@ -2267,7 +2267,9 @@
             fm.write(b'value', b'%s\n', value)
         else:
             fm.write(b'name value', b'%s=%s\n', entryname, value)
-        fm.data(defaultvalue=defaultvalue)
+        if formatter.isprintable(defaultvalue):
+            fm.data(defaultvalue=defaultvalue)
+        # TODO: no idea how to process unsupported defaultvalue types
         matched = True
     fm.end()
     if matched:
--- a/mercurial/formatter.py	Sun Oct 27 18:12:24 2019 +0100
+++ b/mercurial/formatter.py	Sun Oct 27 12:30:59 2019 +0900
@@ -136,6 +136,16 @@
 pickle = util.pickle
 
 
+def isprintable(obj):
+    """Check if the given object can be directly passed in to formatter's
+    write() and data() functions
+
+    Returns False if the object is unsupported or must be pre-processed by
+    formatdate(), formatdict(), or formatlist().
+    """
+    return isinstance(obj, (type(None), bool, int, pycompat.long, float, bytes))
+
+
 class _nullconverter(object):
     '''convert non-primitive data types to be processed by formatter'''
 
--- a/tests/test-config.t	Sun Oct 27 18:12:24 2019 +0100
+++ b/tests/test-config.t	Sun Oct 27 12:30:59 2019 +0900
@@ -87,6 +87,170 @@
    }
   ]
 
+Test config default of various types:
+
+ {"defaultvalue": ""} for -T'json(defaultvalue)' looks weird, but that's
+ how the templater works. Unknown keywords are evaluated to "".
+
+ dynamicdefault
+
+  $ hg config --config alias.foo= alias -Tjson
+  [
+   {
+    "name": "alias.foo",
+    "source": "--config",
+    "value": ""
+   }
+  ]
+  $ hg config --config alias.foo= alias -T'json(defaultvalue)'
+  [
+   {"defaultvalue": ""}
+  ]
+  $ hg config --config alias.foo= alias -T'{defaultvalue}\n'
+  
+
+ null
+
+  $ hg config --config auth.cookiefile= auth -Tjson
+  [
+   {
+    "defaultvalue": null,
+    "name": "auth.cookiefile",
+    "source": "--config",
+    "value": ""
+   }
+  ]
+  $ hg config --config auth.cookiefile= auth -T'json(defaultvalue)'
+  [
+   {"defaultvalue": ""}
+  ]
+  $ hg config --config auth.cookiefile= auth -T'{defaultvalue}\n'
+  
+
+ false
+
+  $ hg config --config commands.commit.post-status= commands -Tjson
+  [
+   {
+    "defaultvalue": false,
+    "name": "commands.commit.post-status",
+    "source": "--config",
+    "value": ""
+   }
+  ]
+  $ hg config --config commands.commit.post-status= commands -T'json(defaultvalue)'
+  [
+   {"defaultvalue": false}
+  ]
+  $ hg config --config commands.commit.post-status= commands -T'{defaultvalue}\n'
+  False
+
+ true
+
+  $ hg config --config format.dotencode= format -Tjson
+  [
+   {
+    "defaultvalue": true,
+    "name": "format.dotencode",
+    "source": "--config",
+    "value": ""
+   }
+  ]
+  $ hg config --config format.dotencode= format -T'json(defaultvalue)'
+  [
+   {"defaultvalue": true}
+  ]
+  $ hg config --config format.dotencode= format -T'{defaultvalue}\n'
+  True
+
+ bytes
+
+  $ hg config --config commands.resolve.mark-check= commands -Tjson
+  [
+   {
+    "defaultvalue": "none",
+    "name": "commands.resolve.mark-check",
+    "source": "--config",
+    "value": ""
+   }
+  ]
+  $ hg config --config commands.resolve.mark-check= commands -T'json(defaultvalue)'
+  [
+   {"defaultvalue": "none"}
+  ]
+  $ hg config --config commands.resolve.mark-check= commands -T'{defaultvalue}\n'
+  none
+
+ empty list
+
+  $ hg config --config commands.show.aliasprefix= commands -Tjson
+  [
+   {
+    "name": "commands.show.aliasprefix",
+    "source": "--config",
+    "value": ""
+   }
+  ]
+  $ hg config --config commands.show.aliasprefix= commands -T'json(defaultvalue)'
+  [
+   {"defaultvalue": ""}
+  ]
+  $ hg config --config commands.show.aliasprefix= commands -T'{defaultvalue}\n'
+  
+
+ nonempty list
+
+  $ hg config --config progress.format= progress -Tjson
+  [
+   {
+    "name": "progress.format",
+    "source": "--config",
+    "value": ""
+   }
+  ]
+  $ hg config --config progress.format= progress -T'json(defaultvalue)'
+  [
+   {"defaultvalue": ""}
+  ]
+  $ hg config --config progress.format= progress -T'{defaultvalue}\n'
+  
+
+ int
+
+  $ hg config --config profiling.freq= profiling -Tjson
+  [
+   {
+    "defaultvalue": 1000,
+    "name": "profiling.freq",
+    "source": "--config",
+    "value": ""
+   }
+  ]
+  $ hg config --config profiling.freq= profiling -T'json(defaultvalue)'
+  [
+   {"defaultvalue": 1000}
+  ]
+  $ hg config --config profiling.freq= profiling -T'{defaultvalue}\n'
+  1000
+
+ float
+
+  $ hg config --config profiling.showmax= profiling -Tjson
+  [
+   {
+    "defaultvalue": 0.999,
+    "name": "profiling.showmax",
+    "source": "--config",
+    "value": ""
+   }
+  ]
+  $ hg config --config profiling.showmax= profiling -T'json(defaultvalue)'
+  [
+   {"defaultvalue": 0.999}
+  ]
+  $ hg config --config profiling.showmax= profiling -T'{defaultvalue}\n'
+  0.999
+
 Test empty config source:
 
   $ cat <<EOF > emptysource.py