Submitter | Matt Harbison |
---|---|
Date | March 22, 2014, 5:08 p.m. |
Message ID | <35686f3835c908e3e681.1395508097@Envy> |
Download | mbox | patch |
Permalink | /patch/4038/ |
State | Accepted |
Commit | a2cc3c08c3ac39f7d2481760fe96522419dced6d |
Headers | show |
Comments
On Sat, 22 Mar 2014 13:08:17 -0400, Matt Harbison wrote: > # HG changeset patch # User Matt Harbison <matt_harbison@yahoo.com> > # Date 1394847125 14400 # Node ID > 35686f3835c908e3e681a0abd0c805476ccdfddc # Parent > 9c5c56f97c4df13462ad4e5684ead8b24466bcd1 cat: support cat with explicit > paths in subrepos > > 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 > @@ -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): Side note: this catches RepoLookupError because if it catches LookupError like other places that recurse into subrepos, the test below where the subrepo isn't present crashes. I even rollbacked back the subrepo thinking that a LookupError would be generated when the revision that parent wants isn't present- but it still caught a RepoLookupError. So the other places catching LookupError (like cmdutil.add(), cmdutil.forget(), etc) are just wrong? For the case of a parent looking for a subrepo revision that isn't present, it would probably be useful to indicate that a revision in the subrepo is missing (and what it is), not the whole repo itself. > 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
On 03/22/2014 10:08 AM, Matt Harbison wrote: > # HG changeset patch > # User Matt Harbison <matt_harbison@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@selenic.com > http://selenic.com/mailman/listinfo/mercurial-devel
Patch
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