[Bug 3747] New: archive --subrepos tries to create unnecessary subrepo clones

mercurial-bugs at selenic.com mercurial-bugs at selenic.com
Sat Dec 29 14:19:34 CST 2012


http://bz.selenic.com/show_bug.cgi?id=3747

          Priority: normal
            Bug ID: 3747
                CC: mercurial-devel at selenic.com
          Assignee: bugzilla at selenic.com
           Summary: archive --subrepos tries to create unnecessary subrepo
                    clones
          Severity: bug
    Classification: Unclassified
                OS: All
          Reporter: trev at adblockplus.org
          Hardware: All
            Status: UNCONFIRMED
           Version: 2.4.1
         Component: Mercurial
           Product: Mercurial

I have a Mercurial server that is also a build server. To create a build it
does "hg archive --subrepos" first to create a temporary directory with all the
necessary data. This has been failing with a "Permissions denied" error because
Mercurial attempts to create subdirectories inside the main repository - clones
of the subrepositories as it turns out, despite the fact that all these
subrepositories are local.

To reproduce run the following commands on a non-root account:

> cd ~
> hg init foo
> hg init bar
> echo 'bar = ../bar' > foo/.hgsub
> hg commit -A -R foo -m 'Add subrepo'
> hg up -R foo 000000
> rm -rf foo/bar/
> sudo chown -R root:root foo bar
> hg archive -S -R foo -r tip test

Note that I made root the owner of the repositories for simplicity - the
repository should simply be read-only, normally this shouldn't be an issue for
"hg archive". Also, "hg up" and "rm" are necessary to clean up the working copy
(typical state for a server). The result is the message "abort: Permission
denied: ~/foo/bar" even though accessing that directory shouldn't be necessary.

I figured out that the issue here is the loop at the end of archival.py. It
works with subrepositories of the main repository by creating (indirectly)
hgsubrepo instances. hgsubrepo only knows the main repository and the relative
path of the subrepo inside the main repository so it tries to access the
repository under ~/foo/bar instead of ~/bar - and creates the subrepo under
that location if it cannot find it there.

My hacky solution was to pass a root parameter all the way from
archival.archive() through context.changectx.sub() and subrepo.subrepo() to
subrepo.hgsubrepo.__init__() (same parameter is passed to svnsubrepo and
gitsubrepo then but ignored). And the loop in archival.py changes into:

>        import hg
>        for subpath, (src, rev, kind) in ctx.substate.iteritems():
>            root = src if hg.islocal(src) else None
>            sub = ctx.sub(subpath, root=root)
>            submatch = matchmod.narrowmatcher(subpath, matchfn)
>            sub.archive(repo.ui, archiver, prefix, submatch)

A similar change has to be done to the loop in subrepo.hgsubrepo.archive():

>        import hg
>        for subpath, (src, rev, kind) in ctx.substate.iteritems():
>            root = src if hg.islocal(src) else None
>            s = subrepo(ctx, subpath, root=root)
>            submatch = matchmod.narrowmatcher(subpath, match)
>            s.archive(ui, archiver, os.path.join(prefix, self._path), submatch)

This isn't ideal but it works. I hope that you can implement some solution to
make sure that "hg archive" is free of side-effects whenever possible.

-- 
You are receiving this mail because:
You are on the CC list for the bug.


More information about the Mercurial-devel mailing list