[PATCH] hgweb: support directory and subrepository navigation when descend mode is disabled

Matt Mackall mpm at selenic.com
Sun Jan 29 19:25:38 UTC 2012


On Sun, 2012-01-29 at 20:03 +0100, Paul Boddie wrote:
> # HG changeset patch
> # User Paul Boddie <paul at boddie.org.uk>
> # Date 1327863292 -3600
> # Branch stable
> # Node ID 967d0f22ee70762029beb539e15daf97b36ace86
> # Parent  f8955a7f82e6a06a682cd95631fd1c5e55f46103
> hgweb: support directory and subrepository navigation when descend mode is disabled

a) it's not clear that this won't be a security surprise to existing
users

b) we're in the middle of the 2.1 code freeze, please resend after Feb 1
for discussion

> diff -r f8955a7f82e6 -r 967d0f22ee70 mercurial/hgweb/hgwebdir_mod.py
> --- a/mercurial/hgweb/hgwebdir_mod.py	Fri Jan 27 03:00:32 2012 +0100
> +++ b/mercurial/hgweb/hgwebdir_mod.py	Sun Jan 29 19:54:52 2012 +0100
> @@ -245,12 +245,61 @@
>          def rawentries(subdir="", **map):
>  
>              descend = self.ui.configbool('web', 'descend', True)
> +            seenrepos = set()
> +            seendirs = set()
>              for name, path in self.repos:
>  
>                  if not name.startswith(subdir):
>                      continue
>                  name = name[len(subdir):]
> +                directory = False
> +
>                  if not descend and '/' in name:
> +                    nameparts = name.split('/')
> +                    rootname = nameparts[0]
> +
> +                    if rootname in seendirs:
> +                        continue
> +                    elif rootname in seenrepos:
> +                        pass
> +                    else:
> +                        directory = True
> +                        name = rootname
> +
> +                        # redefine the path to refer to the directory
> +                        discarded = '/'.join(nameparts[1:])
> +
> +                        # remove name parts plus accompanying slash
> +                        path = path[:-len(discarded) - 1]
> +
> +                parts = [name]
> +                if 'PATH_INFO' in req.env:
> +                    parts.insert(0, req.env['PATH_INFO'].rstrip('/'))
> +                if req.env['SCRIPT_NAME']:
> +                    parts.insert(0, req.env['SCRIPT_NAME'])
> +                url = re.sub(r'/+', '/', '/'.join(parts) + '/')
> +
> +                # show either a directory entry or a repository
> +                if directory:
> +                    # get the directory's time information
> +                    try:
> +                        d = (get_mtime(path), util.makedate()[1])
> +                    except OSError:
> +                        continue
> +
> +                    row = dict(contact="",
> +                               contact_sort="",
> +                               name=name,
> +                               name_sort=name,
> +                               url=url,
> +                               description="",
> +                               description_sort="",
> +                               lastchange=d,
> +                               lastchange_sort=d[1]-d[0],
> +                               archives=[])
> +
> +                    seendirs.add(name)
> +                    yield row
>                      continue
>  
>                  u = self.ui.copy()
> @@ -267,13 +316,6 @@
>  
>                  if not self.read_allowed(u, req):
>                      continue
> -
> -                parts = [name]
> -                if 'PATH_INFO' in req.env:
> -                    parts.insert(0, req.env['PATH_INFO'].rstrip('/'))
> -                if req.env['SCRIPT_NAME']:
> -                    parts.insert(0, req.env['SCRIPT_NAME'])
> -                url = re.sub(r'/+', '/', '/'.join(parts) + '/')
>  
>                  # update time with local timezone
>                  try:
> @@ -302,6 +344,8 @@
>                             lastchange=d,
>                             lastchange_sort=d[1]-d[0],
>                             archives=archivelist(u, "tip", url))
> +
> +                seenrepos.add(name)
>                  yield row
>  
>          sortdefault = None, False
> diff -r f8955a7f82e6 -r 967d0f22ee70 tests/test-hgwebdir.t
> --- a/tests/test-hgwebdir.t	Fri Jan 27 03:00:32 2012 +0100
> +++ b/tests/test-hgwebdir.t	Sun Jan 29 19:54:52 2012 +0100
> @@ -30,6 +30,28 @@
>    $ echo c > c/c
>    $ hg --cwd c ci -Amc -d'3 0'
>    adding c
> +
> +create a subdirectory containing repositories and subrepositories
> +
> +  $ mkdir notrepo
> +  $ cd notrepo
> +  $ hg init e
> +  $ echo e > e/e
> +  $ hg --cwd e ci -Ame -d'4 0'
> +  adding e
> +  $ hg init e/e2
> +  $ echo e2 > e/e2/e2
> +  $ hg --cwd e/e2 ci -Ame2 -d '4 0'
> +  adding e2
> +  $ hg init f
> +  $ echo f > f/f
> +  $ hg --cwd f ci -Amf -d'4 0'
> +  adding f
> +  $ hg init f/f2
> +  $ echo f2 > f/f2/f2
> +  $ hg --cwd f/f2 ci -Amf2 -d '4 0'
> +  adding f2
> +  $ cd ..
>  
>  create repository without .hg/store
>  
> @@ -119,20 +141,32 @@
>    /coll/a/.hg/patches/
>    /coll/b/
>    /coll/c/
> +  /coll/notrepo/e/
> +  /coll/notrepo/f/
>    /rcoll/a/
>    /rcoll/a/.hg/patches/
>    /rcoll/b/
>    /rcoll/b/d/
>    /rcoll/c/
> +  /rcoll/notrepo/e/
> +  /rcoll/notrepo/e/e2/
> +  /rcoll/notrepo/f/
> +  /rcoll/notrepo/f/f2/
>    /star/webdir/a/
>    /star/webdir/a/.hg/patches/
>    /star/webdir/b/
>    /star/webdir/c/
> +  /star/webdir/notrepo/e/
> +  /star/webdir/notrepo/f/
>    /starstar/webdir/a/
>    /starstar/webdir/a/.hg/patches/
>    /starstar/webdir/b/
>    /starstar/webdir/b/d/
>    /starstar/webdir/c/
> +  /starstar/webdir/notrepo/e/
> +  /starstar/webdir/notrepo/e/e2/
> +  /starstar/webdir/notrepo/f/
> +  /starstar/webdir/notrepo/f/f2/
>    /astar/
>    /astar/.hg/patches/
>    
> @@ -217,6 +251,22 @@
>    </tr>
>    
>    <tr class="parity0">
> +  <td><a href="/coll/notrepo/e/?style=paper">coll/notrepo/e</a></td>
> +  <td>unknown</td>
> +  <td>Foo Bar <foo.bar@example.com></td>
> +  <td class="age">*</td> (glob)
> +  <td class="indexlinks"></td>
> +  </tr>
> +  
> +  <tr class="parity1">
> +  <td><a href="/coll/notrepo/f/?style=paper">coll/notrepo/f</a></td>
> +  <td>unknown</td>
> +  <td>Foo Bar <foo.bar@example.com></td>
> +  <td class="age">*</td> (glob)
> +  <td class="indexlinks"></td>
> +  </tr>
> +  
> +  <tr class="parity0">
>    <td><a href="/rcoll/a/?style=paper">rcoll/a</a></td>
>    <td>unknown</td>
>    <td>Foo Bar <foo.bar@example.com></td>
> @@ -257,6 +307,38 @@
>    </tr>
>    
>    <tr class="parity1">
> +  <td><a href="/rcoll/notrepo/e/?style=paper">rcoll/notrepo/e</a></td>
> +  <td>unknown</td>
> +  <td>Foo Bar <foo.bar@example.com></td>
> +  <td class="age">*</td> (glob)
> +  <td class="indexlinks"></td>
> +  </tr>
> +  
> +  <tr class="parity0">
> +  <td><a href="/rcoll/notrepo/e/e2/?style=paper">rcoll/notrepo/e/e2</a></td>
> +  <td>unknown</td>
> +  <td>Foo Bar <foo.bar@example.com></td>
> +  <td class="age">*</td> (glob)
> +  <td class="indexlinks"></td>
> +  </tr>
> +  
> +  <tr class="parity1">
> +  <td><a href="/rcoll/notrepo/f/?style=paper">rcoll/notrepo/f</a></td>
> +  <td>unknown</td>
> +  <td>Foo Bar <foo.bar@example.com></td>
> +  <td class="age">*</td> (glob)
> +  <td class="indexlinks"></td>
> +  </tr>
> +  
> +  <tr class="parity0">
> +  <td><a href="/rcoll/notrepo/f/f2/?style=paper">rcoll/notrepo/f/f2</a></td>
> +  <td>unknown</td>
> +  <td>Foo Bar <foo.bar@example.com></td>
> +  <td class="age">*</td> (glob)
> +  <td class="indexlinks"></td>
> +  </tr>
> +  
> +  <tr class="parity1">
>    <td><a href="/star/webdir/a/?style=paper">star/webdir/a</a></td>
>    <td>unknown</td>
>    <td>Foo Bar <foo.bar@example.com></td>
> @@ -282,6 +364,22 @@
>    
>    <tr class="parity0">
>    <td><a href="/star/webdir/c/?style=paper">star/webdir/c</a></td>
> +  <td>unknown</td>
> +  <td>Foo Bar <foo.bar@example.com></td>
> +  <td class="age">*</td> (glob)
> +  <td class="indexlinks"></td>
> +  </tr>
> +  
> +  <tr class="parity1">
> +  <td><a href="/star/webdir/notrepo/e/?style=paper">star/webdir/notrepo/e</a></td>
> +  <td>unknown</td>
> +  <td>Foo Bar <foo.bar@example.com></td>
> +  <td class="age">*</td> (glob)
> +  <td class="indexlinks"></td>
> +  </tr>
> +  
> +  <tr class="parity0">
> +  <td><a href="/star/webdir/notrepo/f/?style=paper">star/webdir/notrepo/f</a></td>
>    <td>unknown</td>
>    <td>Foo Bar <foo.bar@example.com></td>
>    <td class="age">*</td> (glob)
> @@ -322,6 +420,38 @@
>    
>    <tr class="parity1">
>    <td><a href="/starstar/webdir/c/?style=paper">starstar/webdir/c</a></td>
> +  <td>unknown</td>
> +  <td>Foo Bar <foo.bar@example.com></td>
> +  <td class="age">*</td> (glob)
> +  <td class="indexlinks"></td>
> +  </tr>
> +  
> +  <tr class="parity0">
> +  <td><a href="/starstar/webdir/notrepo/e/?style=paper">starstar/webdir/notrepo/e</a></td>
> +  <td>unknown</td>
> +  <td>Foo Bar <foo.bar@example.com></td>
> +  <td class="age">*</td> (glob)
> +  <td class="indexlinks"></td>
> +  </tr>
> +  
> +  <tr class="parity1">
> +  <td><a href="/starstar/webdir/notrepo/e/e2/?style=paper">starstar/webdir/notrepo/e/e2</a></td>
> +  <td>unknown</td>
> +  <td>Foo Bar <foo.bar@example.com></td>
> +  <td class="age">*</td> (glob)
> +  <td class="indexlinks"></td>
> +  </tr>
> +  
> +  <tr class="parity0">
> +  <td><a href="/starstar/webdir/notrepo/f/?style=paper">starstar/webdir/notrepo/f</a></td>
> +  <td>unknown</td>
> +  <td>Foo Bar <foo.bar@example.com></td>
> +  <td class="age">*</td> (glob)
> +  <td class="indexlinks"></td>
> +  </tr>
> +  
> +  <tr class="parity1">
> +  <td><a href="/starstar/webdir/notrepo/f/f2/?style=paper">starstar/webdir/notrepo/f/f2</a></td>
>    <td>unknown</td>
>    <td>Foo Bar <foo.bar@example.com></td>
>    <td class="age">*</td> (glob)
> @@ -489,6 +619,8 @@
>    /coll/a/.hg/patches/
>    /coll/b/
>    /coll/c/
> +  /coll/notrepo/e/
> +  /coll/notrepo/f/
>    
>    $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/coll/a/file/tip/a?style=raw'
>    200 Script output follows
> @@ -506,11 +638,63 @@
>    /rcoll/b/
>    /rcoll/b/d/
>    /rcoll/c/
> +  /rcoll/notrepo/e/
> +  /rcoll/notrepo/e/e2/
> +  /rcoll/notrepo/f/
> +  /rcoll/notrepo/f/f2/
>    
>    $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/rcoll/b/d/file/tip/d?style=raw'
>    200 Script output follows
>    
>    d
> +
> +Test descend = False
> +
> +  $ "$TESTDIR/killdaemons.py"
> +  $ cat >> paths.conf <<EOF
> +  > [web]
> +  > descend=false
> +  > EOF
> +  $ hg serve -p $HGPORT1 -d --pid-file=hg.pid --webdir-conf paths.conf \
> +  >     -A access-paths.log -E error-paths-3.log
> +  $ cat hg.pid >> $DAEMON_PIDS
> +  $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/rcoll/?style=raw'
> +  200 Script output follows
> +  
> +  
> +  /rcoll/a/
> +  /rcoll/a/.hg/patches/
> +  /rcoll/b/
> +  /rcoll/b/d/
> +  /rcoll/c/
> +  /rcoll/notrepo/
> +  
> +
> +Test intermediate directories
> +
> +  $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/rcoll/notrepo/?style=raw'
> +  200 Script output follows
> +  
> +  
> +  /rcoll/notrepo/e/
> +  /rcoll/notrepo/e/e2/
> +  /rcoll/notrepo/f/
> +  /rcoll/notrepo/f/f2/
> +  
> +
> +Test repositories inside intermediate directories
> +
> +  $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/rcoll/notrepo/e/file/tip/e?style=raw'
> +  200 Script output follows
> +  
> +  e
> +
> +Test subrepositories inside intermediate directories
> +
> +  $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/rcoll/notrepo/f/f2/file/tip/f2?style=raw'
> +  200 Script output follows
> +  
> +  f2
>  
>  Test [paths] '*' in a repo root
>  
> @@ -536,6 +720,7 @@
>    200 Script output follows
>    
>    
> +  /t/
>    /c/
>    
>    $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/t/?style=raw'
> @@ -617,6 +802,8 @@
>    /a/.hg/patches/
>    /b/
>    /c/
> +  /notrepo/e/
> +  /notrepo/f/
>    
>    $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/a/file/tip/a?style=raw'
>    200 Script output follows
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel at selenic.com
> http://selenic.com/mailman/listinfo/mercurial-devel


-- 
Mathematics is the supreme nostalgia of our time.





More information about the Mercurial-devel mailing list