cat: add formatter support
This is an example showing how formatter can handle the --output option.
git subrepo isn't supported for now.
--- a/mercurial/cmdutil.py Sat May 27 17:58:36 2017 +0900
+++ b/mercurial/cmdutil.py Thu May 25 21:53:44 2017 +0900
@@ -2632,21 +2632,21 @@
return ret
-def cat(ui, repo, ctx, matcher, fntemplate, prefix, **opts):
+def cat(ui, repo, ctx, matcher, basefm, fntemplate, prefix, **opts):
err = 1
def write(path):
+ filename = None
if fntemplate:
filename = makefilename(repo, fntemplate, ctx.node(),
pathname=os.path.join(prefix, path))
- fp = open(filename, 'wb')
- else:
- fp = _unclosablefile(ui.fout)
- with fp:
+ with formatter.maybereopen(basefm, filename, opts) as fm:
data = ctx[path].data()
if opts.get('decode'):
data = repo.wwritedata(path, data)
- fp.write(data)
+ fm.startitem()
+ fm.write('data', '%s', data)
+ fm.data(abspath=path, path=matcher.rel(path))
# Automation often uses hg cat on single files, so special case it
# for performance to avoid the cost of parsing the manifest.
@@ -2670,7 +2670,7 @@
try:
submatch = matchmod.subdirmatcher(subpath, matcher)
- if not sub.cat(submatch, fntemplate,
+ if not sub.cat(submatch, basefm, fntemplate,
os.path.join(prefix, sub._path), **opts):
err = 0
except error.RepoLookupError:
--- a/mercurial/commands.py Sat May 27 17:58:36 2017 +0900
+++ b/mercurial/commands.py Thu May 25 21:53:44 2017 +0900
@@ -35,6 +35,7 @@
error,
exchange,
extensions,
+ formatter,
graphmod,
hbisect,
help,
@@ -1338,7 +1339,7 @@
_('print output to file with formatted name'), _('FORMAT')),
('r', 'rev', '', _('print the given revision'), _('REV')),
('', 'decode', None, _('apply any matching decode filter')),
- ] + walkopts,
+ ] + walkopts + formatteropts,
_('[OPTION]... FILE...'),
inferrepo=True)
def cat(ui, repo, file1, *pats, **opts):
@@ -1368,9 +1369,13 @@
if cmdutil.isstdiofilename(fntemplate):
fntemplate = ''
- if not fntemplate:
+ if fntemplate:
+ fm = formatter.nullformatter(ui, 'cat')
+ else:
ui.pager('cat')
- return cmdutil.cat(ui, repo, ctx, m, fntemplate, '', **opts)
+ fm = ui.formatter('cat', opts)
+ with fm:
+ return cmdutil.cat(ui, repo, ctx, m, fm, fntemplate, '', **opts)
@command('^clone',
[('U', 'noupdate', None, _('the clone will include an empty working '
--- a/mercurial/subrepo.py Sat May 27 17:58:36 2017 +0900
+++ b/mercurial/subrepo.py Thu May 25 21:53:44 2017 +0900
@@ -538,7 +538,7 @@
self.ui.warn("%s: %s" % (prefix, _("addremove is not supported")))
return 1
- def cat(self, match, fntemplate, prefix, **opts):
+ def cat(self, match, fm, fntemplate, prefix, **opts):
return 1
def status(self, rev2, **opts):
@@ -767,11 +767,11 @@
dry_run, similarity)
@annotatesubrepoerror
- def cat(self, match, fntemplate, prefix, **opts):
+ def cat(self, match, fm, fntemplate, prefix, **opts):
rev = self._state[1]
ctx = self._repo[rev]
- return cmdutil.cat(self.ui, self._repo, ctx, match, fntemplate, prefix,
- **opts)
+ return cmdutil.cat(self.ui, self._repo, ctx, match, fm, fntemplate,
+ prefix, **opts)
@annotatesubrepoerror
def status(self, rev2, **opts):
@@ -1833,7 +1833,7 @@
@annotatesubrepoerror
- def cat(self, match, fntemplate, prefix, **opts):
+ def cat(self, match, fm, fntemplate, prefix, **opts):
rev = self._state[1]
if match.anypats():
return 1 #No support for include/exclude yet
@@ -1841,6 +1841,7 @@
if not match.files():
return 1
+ # TODO: add support for non-plain formatter (see cmdutil.cat())
for f in match.files():
output = self._gitcommand(["show", "%s:%s" % (rev, f)])
fp = cmdutil.makefileobj(self._subparent, fntemplate,
--- a/tests/test-cat.t Sat May 27 17:58:36 2017 +0900
+++ b/tests/test-cat.t Thu May 25 21:53:44 2017 +0900
@@ -63,6 +63,46 @@
tmp/h_45116003780e
tmp/r_2
+Test template output
+
+ $ hg --cwd tmp cat ../b ../c -T '== {path} ({abspath}) ==\n{data}'
+ == ../b (b) == (glob)
+ 1
+ == ../c (c) == (glob)
+ 3
+
+ $ hg cat b c -Tjson --output -
+ [
+ {
+ "abspath": "b",
+ "data": "1\n",
+ "path": "b"
+ },
+ {
+ "abspath": "c",
+ "data": "3\n",
+ "path": "c"
+ }
+ ]
+
+ $ hg cat b c -Tjson --output 'tmp/%p.json'
+ $ cat tmp/b.json
+ [
+ {
+ "abspath": "b",
+ "data": "1\n",
+ "path": "b"
+ }
+ ]
+ $ cat tmp/c.json
+ [
+ {
+ "abspath": "c",
+ "data": "3\n",
+ "path": "c"
+ }
+ ]
+
Test working directory
$ echo b-wdir > b
--- a/tests/test-completion.t Sat May 27 17:58:36 2017 +0900
+++ b/tests/test-completion.t Thu May 25 21:53:44 2017 +0900
@@ -241,7 +241,7 @@
branch: force, clean
branches: active, closed, template
bundle: force, rev, branch, base, all, type, ssh, remotecmd, insecure
- cat: output, rev, decode, include, exclude
+ cat: output, rev, decode, include, exclude, template
config: untrusted, edit, local, global, template
copy: after, force, include, exclude, dry-run
debugancestor:
--- a/tests/test-hook.t Sat May 27 17:58:36 2017 +0900
+++ b/tests/test-hook.t Thu May 25 21:53:44 2017 +0900
@@ -99,9 +99,9 @@
abort: pre-identify hook exited with status 1
[255]
$ hg cat b
- pre-cat hook: HG_ARGS=cat b HG_HOOKNAME=pre-cat HG_HOOKTYPE=pre-cat HG_OPTS={'decode': None, 'exclude': [], 'include': [], 'output': '', 'rev': ''} HG_PATS=['b']
+ pre-cat hook: HG_ARGS=cat b HG_HOOKNAME=pre-cat HG_HOOKTYPE=pre-cat HG_OPTS={'decode': None, 'exclude': [], 'include': [], 'output': '', 'rev': '', 'template': ''} HG_PATS=['b']
b
- post-cat hook: HG_ARGS=cat b HG_HOOKNAME=post-cat HG_HOOKTYPE=post-cat HG_OPTS={'decode': None, 'exclude': [], 'include': [], 'output': '', 'rev': ''} HG_PATS=['b'] HG_RESULT=0
+ post-cat hook: HG_ARGS=cat b HG_HOOKNAME=post-cat HG_HOOKTYPE=post-cat HG_OPTS={'decode': None, 'exclude': [], 'include': [], 'output': '', 'rev': '', 'template': ''} HG_PATS=['b'] HG_RESULT=0
$ cd ../b
$ hg pull ../a
--- a/tests/test-subrepo.t Sat May 27 17:58:36 2017 +0900
+++ b/tests/test-subrepo.t Thu May 25 21:53:44 2017 +0900
@@ -1020,6 +1020,14 @@
$ hg cat sub/repo/foo
test
test
+ $ hg cat sub/repo/foo -Tjson
+ [
+ {
+ "abspath": "foo",
+ "data": "test\ntest\n",
+ "path": "sub/repo/foo" (glob)
+ }
+ ]
$ mkdir -p tmp/sub/repo
$ hg cat -r 0 --output tmp/%p_p sub/repo/foo
$ cat tmp/sub/repo/foo_p