[PATCH 1 of 3 STABLE] config: fix -Tjson to not crash due to unsupported defaultvalue types

Yuya Nishihara yuya at tcha.org
Sun Oct 27 04:12:53 UTC 2019


# HG changeset patch
# User Yuya Nishihara <yuya at tcha.org>
# Date 1572147059 -32400
#      Sun Oct 27 12:30:59 2019 +0900
# Branch stable
# Node ID 94624c0871a1a5f0ece06302a14dff6b9635d722
# Parent  8fda98a6842709c26b61747c7420b28cd874755e
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.

diff --git a/mercurial/commands.py b/mercurial/commands.py
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -2267,7 +2267,9 @@ def config(ui, repo, *values, **opts):
             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:
diff --git a/mercurial/formatter.py b/mercurial/formatter.py
--- a/mercurial/formatter.py
+++ b/mercurial/formatter.py
@@ -136,6 +136,16 @@ from .utils import (
 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'''
 
diff --git a/tests/test-config.t b/tests/test-config.t
--- a/tests/test-config.t
+++ b/tests/test-config.t
@@ -87,6 +87,170 @@ Test case sensitive configuration
    }
   ]
 
+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


More information about the Mercurial-devel mailing list