[PATCH 1 of 2 V3] serve: add support for Mercurial subrepositories
Matt Harbison
mharbison72 at gmail.com
Sat Apr 15 17:52:09 EDT 2017
On Sat, 15 Apr 2017 15:04:32 -0400, Matt Harbison <mharbison72 at gmail.com>
wrote:
> On Thu, 30 Mar 2017 21:19:01 -0400, Matt Harbison
> <mharbison72 at gmail.com> wrote:
>
>> On Tue, 28 Mar 2017 10:11:15 -0400, Yuya Nishihara <yuya at tcha.org>
>> wrote:
>>
>>> On Sun, 26 Mar 2017 23:04:30 -0400, Matt Harbison wrote:
>>>> # HG changeset patch
>>>> # User Matt Harbison <matt_harbison at yahoo.com>
>>>> # Date 1488146743 18000
>>>> # Sun Feb 26 17:05:43 2017 -0500
>>>> # Node ID 0ff9bef3e0f67422cf29c200fa4a671d861d060b
>>>> # Parent c60091fa1426892552dd6c0dd4b9c49e3c3da045
>>>> serve: add support for Mercurial subrepositories
>>>
>>>> +def addwebdirpath(repo, serverpath, webconf):
>>>> + webconf[serverpath] = repo.root
>>>> + repo.ui.debug('adding %s = %s\n' % (serverpath, repo.root))
>>>> +
>>>> + for r in repo.revs('filelog("path:.hgsub")'):
>>>> + ctx = repo[r]
>>>> + for subpath in ctx.substate:
>>>> + ctx.sub(subpath).addwebdirpath(serverpath, webconf)
>>>
>>> [...]
>>>
>>>> --- a/mercurial/server.py
>>>> +++ b/mercurial/server.py
>>>> @@ -15,6 +15,7 @@
>>>>
>>>> from . import (
>>>> chgserver,
>>>> + cmdutil,
>>>> commandserver,
>>>> error,
>>>> hgweb,
>>>> @@ -130,11 +131,24 @@
>>>> baseui = ui
>>>> webconf = opts.get('web_conf') or opts.get('webdir_conf')
>>>> if webconf:
>>>> + if opts.get('subrepos'):
>>>> + raise error.Abort(_('--web-conf cannot be used with
>>>> --subrepos'))
>>>> +
>>>> # load server settings (e.g. web.port) to "copied" ui, which
>>>> allows
>>>> # hgwebdir to reload webconf cleanly
>>>> servui = ui.copy()
>>>> servui.readconfig(webconf, sections=['web'])
>>>> alluis.add(servui)
>>>> + elif opts.get('subrepos'):
>>>> + servui = ui.copy()
>>>> + alluis.add(servui)
>>>
>>> No need to make a copy of ui since nothing loaded into servui.
>>>
>>>> + @annotatesubrepoerror
>>>> + def addwebdirpath(self, serverpath, webconf):
>>>> + # The URL request contains the subrepo source path, not the
>>>> local
>>>> + # subrepo path. The distinction matters for 'foo = ../foo'
>>>> type
>>>> + # entries. It isn't possible to serve up 'foo = http://..'
>>>> type
>>>> + # entries, because the server path is relative to this local
>>>> server.
>>>> + src = self._state[0]
>>>> + if util.url(src).islocal():
>>>> + path = util.normpath(serverpath + src)
>>>> + cmdutil.addwebdirpath(self._repo, path + '/', webconf)
>>>
>>> What happens if src is '../../escape_from_web_root' ?
>>>
>>> I don't think it's correct to lay out subrepositories by peer URL
>>> since we're
>>> exporting a _local_ clone. If you do "hg clone sub1 sub2", you'll see
>>> sub1
>>> in local-path layout. "hg serve -S" just allows us to see sub1 over
>>> http.
>>
>> That was actually how I first coded it, but switched it because it
>> wasn't handling the test in test-subrepo-deep-nested-change.t
>> properly. I forget what exactly the problem was. I'll take another
>> look this weekend.
>
> I finally got back to this, now that I've got the serve tests working on
> Windows. The problem I had run into is that in
> test-subrepo-deep-nested-change.t, the repos exist in the filesystem as:
>
> main
> sub1
> sub2
>
> If you clone `hg clone main` right after the "main import" commit around
> line 74, it builds a tree like:
>
> cloning subrepo sub1 from $TESTTMP/sub1
> cloning subrepo sub1\sub2 from $TESTTMP/sub2
>
> The fact that you can locally clone the original 'main' strongly
> suggests that we should be able to serve the original main, and be able
> to clone from it too. The subsequent test I added there does that. It
> took using the peer layout to do this. (Though it really isn't a peer-
> it's what is in the local filesystem where the serve is happening.)
Ugh, nevermind. I see now that the extra copies of the subrepos allow the
local cloning to work:
main
main/sub1
main/sub1/sub2
sub1
sub2
The nested repos are used for commits, but not `hg clone`. And that's
what allows the filesystem clone to work. I thought you could only clone
foo=../foo type hierarchies once, but I was able to clone a clone in this
test. Until I renamed the top level sub{1,2} repos, and then it doesn't
even work once. So I guess it's not a big deal that you can't clone this
setup over http.
I wonder what else these extra copies are masking in the tests...
> It's easy enough to setup the dictionary such that the repos would be
> served up as:
>
> /
> /sub1
> /sub1/sub2
>
> But clone seems to want to follow the peer layout specified in .hgsub of
> the parent. (I can see "GET /../sub1?cmd=capabilities ..." in
> access.log, which is where clone is dying with a 404.)
>
> I know that escaping '/' is generally a security concern. But I'm not
> sure that it is here, since the only thing served above '/' is something
> explicitly in the repository (via .hgsub). So it can't be anything else
> that is potentially sensitive.
>
> I don't care too much about this case. I'd rather have the
> functionality for the recommended nested subrepo case, than not at all.
> But I don't want to sneak something in that is broken, with no obvious
> way to fix if somebody complains.
>
> Thoughts?
>
>>> Maybe it's okay to add all repositories found under repo.root to
>>> webconf.
>>> For strictness, we could check if a subrepo path exists in .hgsub of
>>> any
>>> revision.
>>
>> I'd like to avoid searching through the directory tree, if possible.
More information about the Mercurial-devel
mailing list