[PATCH 2 of 3] cat: support cat with explicit paths in subrepos
Siddharth Agarwal
sid at less-broken.com
Tue Apr 15 17:14:55 UTC 2014
On 03/22/2014 10:08 AM, Matt Harbison wrote:
> # HG changeset patch
> # User Matt Harbison <matt_harbison at yahoo.com>
> # Date 1394847125 14400
> # Node ID 35686f3835c908e3e681a0abd0c805476ccdfddc
> # Parent 9c5c56f97c4df13462ad4e5684ead8b24466bcd1
> cat: support cat with explicit paths in subrepos
The first one and this one are queued for default, thanks.
>
> The cat command with an explicit path into a subrepo is now handled by invoking
> cat on the file, from that subrepo. The previous behavior was to complain that
> the file didn't exist in the revision (of the top most repo). Now when the file
> is actually missing, the revision of the subrepo is named instead (though it is
> probably desirable to continue naming the top level repo).
>
> The documented output formatters %d and %p reflect the path from the top level
> repo, since the purpose of this is to give the illusion of a unified repository.
> Support for the undocumented (for cat) formatters %H, %R, %h, %m and %r was
> added long ago (I tested back as far as 0.5), but unfortunately these will
> reflect the subrepo node instead of the parent context.
>
> The previous implementation was a bit loose with the return value, i.e. it would
> return 0 if _any_ file requested was cat'd successfully. This maintains that
> behavior.
>
> diff --git a/mercurial/cmdutil.py b/mercurial/cmdutil.py
> --- a/mercurial/cmdutil.py
> +++ b/mercurial/cmdutil.py
> @@ -1812,11 +1812,12 @@
> forgot.extend(forget)
> return bad, forgot
>
> -def cat(ui, repo, ctx, matcher, **opts):
> +def cat(ui, repo, ctx, matcher, prefix, **opts):
> err = 1
>
> def write(path):
> - fp = makefileobj(repo, opts.get('output'), ctx.node(), pathname=path)
> + fp = makefileobj(repo, opts.get('output'), ctx.node(),
> + pathname=os.path.join(prefix, path))
> data = ctx[path].data()
> if opts.get('decode'):
> data = repo.wwritedata(path, data)
> @@ -1833,9 +1834,35 @@
> write(file)
> return 0
>
> + # Don't warn about "missing" files that are really in subrepos
> + bad = matcher.bad
> +
> + def badfn(path, msg):
> + for subpath in ctx.substate:
> + if path.startswith(subpath):
> + return
> + bad(path, msg)
> +
> + matcher.bad = badfn
> +
> for abs in ctx.walk(matcher):
> write(abs)
> err = 0
> +
> + matcher.bad = bad
> +
> + for subpath in sorted(ctx.substate):
> + sub = ctx.sub(subpath)
> + try:
> + submatch = matchmod.narrowmatcher(subpath, matcher)
> +
> + if not sub.cat(ui, submatch, os.path.join(prefix, sub._path),
> + **opts):
> + err = 0
> + except error.RepoLookupError:
> + ui.status(_("skipping missing subrepository: %s\n")
> + % os.path.join(prefix, subpath))
> +
> return err
>
> def duplicatecopies(repo, rev, fromrev):
> diff --git a/mercurial/commands.py b/mercurial/commands.py
> --- a/mercurial/commands.py
> +++ b/mercurial/commands.py
> @@ -1171,7 +1171,7 @@
> ctx = scmutil.revsingle(repo, opts.get('rev'))
> m = scmutil.match(ctx, (file1,) + pats, opts)
>
> - return cmdutil.cat(ui, repo, ctx, m, **opts)
> + return cmdutil.cat(ui, repo, ctx, m, '', **opts)
>
> @command('^clone',
> [('U', 'noupdate', None,
> diff --git a/mercurial/help/subrepos.txt b/mercurial/help/subrepos.txt
> --- a/mercurial/help/subrepos.txt
> +++ b/mercurial/help/subrepos.txt
> @@ -84,6 +84,9 @@
> :archive: archive does not recurse in subrepositories unless
> -S/--subrepos is specified.
>
> +:cat: cat currently only handles exact file matches in subrepos.
> + Git and Subversion subrepositories are currently ignored.
> +
> :commit: commit creates a consistent snapshot of the state of the
> entire project and its subrepositories. If any subrepositories
> have been modified, Mercurial will abort. Mercurial can be made
> diff --git a/mercurial/subrepo.py b/mercurial/subrepo.py
> --- a/mercurial/subrepo.py
> +++ b/mercurial/subrepo.py
> @@ -439,6 +439,9 @@
> def add(self, ui, match, dryrun, listsubrepos, prefix, explicitonly):
> return []
>
> + def cat(self, ui, match, prefix, **opts):
> + return 1
> +
> def status(self, rev2, **opts):
> return [], [], [], [], [], [], []
>
> @@ -609,6 +612,12 @@
> os.path.join(prefix, self._path), explicitonly)
>
> @annotatesubrepoerror
> + def cat(self, ui, match, prefix, **opts):
> + rev = self._state[1]
> + ctx = self._repo[rev]
> + return cmdutil.cat(ui, self._repo, ctx, match, prefix, **opts)
> +
> + @annotatesubrepoerror
> def status(self, rev2, **opts):
> try:
> rev1 = self._state[1]
> diff --git a/tests/test-subrepo.t b/tests/test-subrepo.t
> --- a/tests/test-subrepo.t
> +++ b/tests/test-subrepo.t
> @@ -755,6 +755,19 @@
> $ echo test >> sub/repo/foo
> $ hg ci -mtest
> committing subrepository sub/repo (glob)
> + $ hg cat sub/repo/foo
> + test
> + test
> + $ mkdir -p tmp/sub/repo
> + $ hg cat -r 0 --output tmp/%p_p sub/repo/foo
> + $ cat tmp/sub/repo/foo_p
> + test
> + $ mv sub/repo sub_
> + $ hg cat sub/repo/baz
> + skipping missing subrepository: sub/repo
> + [1]
> + $ rm -rf sub/repo
> + $ mv sub_ sub/repo
> $ cd ..
>
> Create repo without default path, pull top repo, and see what happens on update
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel at selenic.com
> http://selenic.com/mailman/listinfo/mercurial-devel
More information about the Mercurial-devel
mailing list