[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