[PATCH 2 of 3] cat: support cat with explicit paths in subrepos

Siddharth Agarwal sid at less-broken.com
Tue Apr 15 12:14:55 CDT 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