##// END OF EJS Templates
show: fix corrupt json output with no bookmarks
Ryan McElroy -
r31859:8e282aa3 default
parent child Browse files
Show More
@@ -1,136 +1,140 b''
1 # show.py - Extension implementing `hg show`
1 # show.py - Extension implementing `hg show`
2 #
2 #
3 # Copyright 2017 Gregory Szorc <gregory.szorc@gmail.com>
3 # Copyright 2017 Gregory Szorc <gregory.szorc@gmail.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 """unified command to show various repository information (EXPERIMENTAL)
8 """unified command to show various repository information (EXPERIMENTAL)
9
9
10 This extension provides the :hg:`show` command, which provides a central
10 This extension provides the :hg:`show` command, which provides a central
11 command for displaying commonly-accessed repository data and views of that
11 command for displaying commonly-accessed repository data and views of that
12 data.
12 data.
13 """
13 """
14
14
15 from __future__ import absolute_import
15 from __future__ import absolute_import
16
16
17 from mercurial.i18n import _
17 from mercurial.i18n import _
18 from mercurial import (
18 from mercurial import (
19 cmdutil,
19 cmdutil,
20 commands,
20 commands,
21 error,
21 error,
22 formatter,
22 pycompat,
23 pycompat,
23 registrar,
24 registrar,
24 )
25 )
25
26
26 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
27 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
27 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
28 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
28 # be specifying the version(s) of Mercurial they are tested with, or
29 # be specifying the version(s) of Mercurial they are tested with, or
29 # leave the attribute unspecified.
30 # leave the attribute unspecified.
30 testedwith = 'ships-with-hg-core'
31 testedwith = 'ships-with-hg-core'
31
32
32 cmdtable = {}
33 cmdtable = {}
33 command = cmdutil.command(cmdtable)
34 command = cmdutil.command(cmdtable)
34
35
35 class showcmdfunc(registrar._funcregistrarbase):
36 class showcmdfunc(registrar._funcregistrarbase):
36 """Register a function to be invoked for an `hg show <thing>`."""
37 """Register a function to be invoked for an `hg show <thing>`."""
37
38
38 # Used by _formatdoc().
39 # Used by _formatdoc().
39 _docformat = '%s -- %s'
40 _docformat = '%s -- %s'
40
41
41 def _extrasetup(self, name, func, fmtopic=None):
42 def _extrasetup(self, name, func, fmtopic=None):
42 """Called with decorator arguments to register a show view.
43 """Called with decorator arguments to register a show view.
43
44
44 ``name`` is the sub-command name.
45 ``name`` is the sub-command name.
45
46
46 ``func`` is the function being decorated.
47 ``func`` is the function being decorated.
47
48
48 ``fmtopic`` is the topic in the style that will be rendered for
49 ``fmtopic`` is the topic in the style that will be rendered for
49 this view.
50 this view.
50 """
51 """
51 func._fmtopic = fmtopic
52 func._fmtopic = fmtopic
52
53
53 showview = showcmdfunc()
54 showview = showcmdfunc()
54
55
55 @command('show', commands.formatteropts, _('VIEW'))
56 @command('show', commands.formatteropts, _('VIEW'))
56 def show(ui, repo, view=None, template=None):
57 def show(ui, repo, view=None, template=None):
57 """show various repository information
58 """show various repository information
58
59
59 A requested view of repository data is displayed.
60 A requested view of repository data is displayed.
60
61
61 If no view is requested, the list of available views is shown and the
62 If no view is requested, the list of available views is shown and the
62 command aborts.
63 command aborts.
63
64
64 .. note::
65 .. note::
65
66
66 There are no backwards compatibility guarantees for the output of this
67 There are no backwards compatibility guarantees for the output of this
67 command. Output may change in any future Mercurial release.
68 command. Output may change in any future Mercurial release.
68
69
69 Consumers wanting stable command output should specify a template via
70 Consumers wanting stable command output should specify a template via
70 ``-T/--template``.
71 ``-T/--template``.
71
72
72 List of available views:
73 List of available views:
73
74
74 """
75 """
75 if ui.plain() and not template:
76 if ui.plain() and not template:
76 hint = _('invoke with -T/--template to control output format')
77 hint = _('invoke with -T/--template to control output format')
77 raise error.Abort(_('must specify a template in plain mode'), hint=hint)
78 raise error.Abort(_('must specify a template in plain mode'), hint=hint)
78
79
79 views = showview._table
80 views = showview._table
80
81
81 if not view:
82 if not view:
82 ui.pager('show')
83 ui.pager('show')
83 # TODO consider using formatter here so available views can be
84 # TODO consider using formatter here so available views can be
84 # rendered to custom format.
85 # rendered to custom format.
85 ui.write(_('available views:\n'))
86 ui.write(_('available views:\n'))
86 ui.write('\n')
87 ui.write('\n')
87
88
88 for name, func in sorted(views.items()):
89 for name, func in sorted(views.items()):
89 ui.write(('%s\n') % func.__doc__)
90 ui.write(('%s\n') % func.__doc__)
90
91
91 ui.write('\n')
92 ui.write('\n')
92 raise error.Abort(_('no view requested'),
93 raise error.Abort(_('no view requested'),
93 hint=_('use "hg show VIEW" to choose a view'))
94 hint=_('use "hg show VIEW" to choose a view'))
94
95
95 # TODO use same logic as dispatch to perform prefix matching.
96 # TODO use same logic as dispatch to perform prefix matching.
96 if view not in views:
97 if view not in views:
97 raise error.Abort(_('unknown view: %s') % view,
98 raise error.Abort(_('unknown view: %s') % view,
98 hint=_('run "hg show" to see available views'))
99 hint=_('run "hg show" to see available views'))
99
100
100 template = template or 'show'
101 template = template or 'show'
101 fmtopic = 'show%s' % views[view]._fmtopic
102 fmtopic = 'show%s' % views[view]._fmtopic
102
103
103 ui.pager('show')
104 ui.pager('show')
104 with ui.formatter(fmtopic, {'template': template}) as fm:
105 with ui.formatter(fmtopic, {'template': template}) as fm:
105 return views[view](ui, repo, fm)
106 return views[view](ui, repo, fm)
106
107
107 @showview('bookmarks', fmtopic='bookmarks')
108 @showview('bookmarks', fmtopic='bookmarks')
108 def showbookmarks(ui, repo, fm):
109 def showbookmarks(ui, repo, fm):
109 """bookmarks and their associated changeset"""
110 """bookmarks and their associated changeset"""
110 marks = repo._bookmarks
111 marks = repo._bookmarks
111 if not len(marks):
112 if not len(marks):
112 # TODO json output is corrupted; consider using formatter
113 # This is a bit hacky. Ideally, templates would have a way to
114 # specify an empty output, but we shouldn't corrupt JSON while
115 # waiting for this functionality.
116 if not isinstance(fm, formatter.jsonformatter):
113 ui.write(_('(no bookmarks set)\n'))
117 ui.write(_('(no bookmarks set)\n'))
114 return
118 return
115
119
116 active = repo._activebookmark
120 active = repo._activebookmark
117 longestname = max(len(b) for b in marks)
121 longestname = max(len(b) for b in marks)
118 # TODO consider exposing longest shortest(node).
122 # TODO consider exposing longest shortest(node).
119
123
120 for bm, node in sorted(marks.items()):
124 for bm, node in sorted(marks.items()):
121 fm.startitem()
125 fm.startitem()
122 fm.context(ctx=repo[node])
126 fm.context(ctx=repo[node])
123 fm.write('bookmark', '%s', bm)
127 fm.write('bookmark', '%s', bm)
124 fm.write('node', fm.hexfunc(node), fm.hexfunc(node))
128 fm.write('node', fm.hexfunc(node), fm.hexfunc(node))
125 fm.data(active=bm == active,
129 fm.data(active=bm == active,
126 longestbookmarklen=longestname)
130 longestbookmarklen=longestname)
127
131
128 # Adjust the docstring of the show command so it shows all registered views.
132 # Adjust the docstring of the show command so it shows all registered views.
129 # This is a bit hacky because it runs at the end of module load. When moved
133 # This is a bit hacky because it runs at the end of module load. When moved
130 # into core or when another extension wants to provide a view, we'll need
134 # into core or when another extension wants to provide a view, we'll need
131 # to do this more robustly.
135 # to do this more robustly.
132 # TODO make this more robust.
136 # TODO make this more robust.
133 longest = max(map(len, showview._table.keys()))
137 longest = max(map(len, showview._table.keys()))
134 for key in sorted(showview._table.keys()):
138 for key in sorted(showview._table.keys()):
135 cmdtable['show'][0].__doc__ += pycompat.sysstr(' %s %s\n' % (
139 cmdtable['show'][0].__doc__ += pycompat.sysstr(' %s %s\n' % (
136 key.ljust(longest), showview._table[key]._origdoc))
140 key.ljust(longest), showview._table[key]._origdoc))
@@ -1,117 +1,125 b''
1 $ cat >> $HGRCPATH << EOF
1 $ cat >> $HGRCPATH << EOF
2 > [extensions]
2 > [extensions]
3 > show =
3 > show =
4 > EOF
4 > EOF
5
5
6 No arguments shows available views
6 No arguments shows available views
7
7
8 $ hg init empty
8 $ hg init empty
9 $ cd empty
9 $ cd empty
10 $ hg show
10 $ hg show
11 available views:
11 available views:
12
12
13 bookmarks -- bookmarks and their associated changeset
13 bookmarks -- bookmarks and their associated changeset
14
14
15 abort: no view requested
15 abort: no view requested
16 (use "hg show VIEW" to choose a view)
16 (use "hg show VIEW" to choose a view)
17 [255]
17 [255]
18
18
19 `hg help show` prints available views
19 `hg help show` prints available views
20
20
21 $ hg help show
21 $ hg help show
22 hg show VIEW
22 hg show VIEW
23
23
24 show various repository information
24 show various repository information
25
25
26 A requested view of repository data is displayed.
26 A requested view of repository data is displayed.
27
27
28 If no view is requested, the list of available views is shown and the
28 If no view is requested, the list of available views is shown and the
29 command aborts.
29 command aborts.
30
30
31 Note:
31 Note:
32 There are no backwards compatibility guarantees for the output of this
32 There are no backwards compatibility guarantees for the output of this
33 command. Output may change in any future Mercurial release.
33 command. Output may change in any future Mercurial release.
34
34
35 Consumers wanting stable command output should specify a template via
35 Consumers wanting stable command output should specify a template via
36 "-T/--template".
36 "-T/--template".
37
37
38 List of available views:
38 List of available views:
39
39
40 bookmarks bookmarks and their associated changeset
40 bookmarks bookmarks and their associated changeset
41
41
42 (use 'hg help -e show' to show help for the show extension)
42 (use 'hg help -e show' to show help for the show extension)
43
43
44 options:
44 options:
45
45
46 (some details hidden, use --verbose to show complete help)
46 (some details hidden, use --verbose to show complete help)
47
47
48 Unknown view prints error
48 Unknown view prints error
49
49
50 $ hg show badview
50 $ hg show badview
51 abort: unknown view: badview
51 abort: unknown view: badview
52 (run "hg show" to see available views)
52 (run "hg show" to see available views)
53 [255]
53 [255]
54
54
55 HGPLAIN results in abort
55 HGPLAIN results in abort
56
56
57 $ HGPLAIN=1 hg show bookmarks
57 $ HGPLAIN=1 hg show bookmarks
58 abort: must specify a template in plain mode
58 abort: must specify a template in plain mode
59 (invoke with -T/--template to control output format)
59 (invoke with -T/--template to control output format)
60 [255]
60 [255]
61
61
62 But not if a template is specified
62 But not if a template is specified
63
63
64 $ HGPLAIN=1 hg show bookmarks -T '{bookmark}\n'
64 $ HGPLAIN=1 hg show bookmarks -T '{bookmark}\n'
65 (no bookmarks set)
65 (no bookmarks set)
66
66
67 $ cd ..
67 $ cd ..
68
68
69 bookmarks view with no bookmarks prints empty message
69 bookmarks view with no bookmarks prints empty message
70
70
71 $ hg init books
71 $ hg init books
72 $ cd books
72 $ cd books
73 $ touch f0
73 $ touch f0
74 $ hg -q commit -A -m initial
74 $ hg -q commit -A -m initial
75
75
76 $ hg show bookmarks
76 $ hg show bookmarks
77 (no bookmarks set)
77 (no bookmarks set)
78
78
79 bookmarks view shows bookmarks in an aligned table
79 bookmarks view shows bookmarks in an aligned table
80
80
81 $ echo book1 > f0
81 $ echo book1 > f0
82 $ hg commit -m 'commit for book1'
82 $ hg commit -m 'commit for book1'
83 $ echo book2 > f0
83 $ echo book2 > f0
84 $ hg commit -m 'commit for book2'
84 $ hg commit -m 'commit for book2'
85
85
86 $ hg bookmark -r 1 book1
86 $ hg bookmark -r 1 book1
87 $ hg bookmark a-longer-bookmark
87 $ hg bookmark a-longer-bookmark
88
88
89 $ hg show bookmarks
89 $ hg show bookmarks
90 * a-longer-bookmark 7b570
90 * a-longer-bookmark 7b570
91 book1 b757f
91 book1 b757f
92
92
93 A custom bookmarks template works
93 A custom bookmarks template works
94
94
95 $ hg show bookmarks -T '{node} {bookmark} {active}\n'
95 $ hg show bookmarks -T '{node} {bookmark} {active}\n'
96 7b5709ab64cbc34da9b4367b64afff47f2c4ee83 a-longer-bookmark True
96 7b5709ab64cbc34da9b4367b64afff47f2c4ee83 a-longer-bookmark True
97 b757f780b8ffd71267c6ccb32e0882d9d32a8cc0 book1 False
97 b757f780b8ffd71267c6ccb32e0882d9d32a8cc0 book1 False
98
98
99 bookmarks JSON works
99 bookmarks JSON works
100
100
101 $ hg show bookmarks -T json
101 $ hg show bookmarks -T json
102 [
102 [
103 {
103 {
104 "active": true,
104 "active": true,
105 "bookmark": "a-longer-bookmark",
105 "bookmark": "a-longer-bookmark",
106 "longestbookmarklen": 17,
106 "longestbookmarklen": 17,
107 "node": "7b5709ab64cbc34da9b4367b64afff47f2c4ee83"
107 "node": "7b5709ab64cbc34da9b4367b64afff47f2c4ee83"
108 },
108 },
109 {
109 {
110 "active": false,
110 "active": false,
111 "bookmark": "book1",
111 "bookmark": "book1",
112 "longestbookmarklen": 17,
112 "longestbookmarklen": 17,
113 "node": "b757f780b8ffd71267c6ccb32e0882d9d32a8cc0"
113 "node": "b757f780b8ffd71267c6ccb32e0882d9d32a8cc0"
114 }
114 }
115 ]
115 ]
116
116
117 JSON works with no bookmarks
118
119 $ hg book -d a-longer-bookmark
120 $ hg book -d book1
121 $ hg show bookmarks -T json
122 [
123 ]
124
117 $ cd ..
125 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now