diff --git a/mercurial/cmdutil.py b/mercurial/cmdutil.py --- a/mercurial/cmdutil.py +++ b/mercurial/cmdutil.py @@ -2632,21 +2632,21 @@ def remove(ui, repo, m, prefix, after, f 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 @@ def cat(ui, repo, ctx, matcher, fntempla 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: diff --git a/mercurial/commands.py b/mercurial/commands.py --- a/mercurial/commands.py +++ b/mercurial/commands.py @@ -35,6 +35,7 @@ from . import ( error, exchange, extensions, + formatter, graphmod, hbisect, help, @@ -1338,7 +1339,7 @@ def bundle(ui, repo, fname, dest=None, * _('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 @@ def cat(ui, repo, file1, *pats, **opts): 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 ' diff --git a/mercurial/subrepo.py b/mercurial/subrepo.py --- a/mercurial/subrepo.py +++ b/mercurial/subrepo.py @@ -538,7 +538,7 @@ class abstractsubrepo(object): 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 @@ class hgsubrepo(abstractsubrepo): 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 @@ class gitsubrepo(abstractsubrepo): @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 @@ class gitsubrepo(abstractsubrepo): 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, diff --git a/tests/test-cat.t b/tests/test-cat.t --- a/tests/test-cat.t +++ b/tests/test-cat.t @@ -63,6 +63,46 @@ Test fileset 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 diff --git a/tests/test-completion.t b/tests/test-completion.t --- a/tests/test-completion.t +++ b/tests/test-completion.t @@ -241,7 +241,7 @@ Show all commands + options 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: diff --git a/tests/test-hook.t b/tests/test-hook.t --- a/tests/test-hook.t +++ b/tests/test-hook.t @@ -99,9 +99,9 @@ test generic hooks 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 diff --git a/tests/test-subrepo.t b/tests/test-subrepo.t --- a/tests/test-subrepo.t +++ b/tests/test-subrepo.t @@ -1020,6 +1020,14 @@ Prepare a repo with subrepo $ 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