diff --git a/mercurial/hgweb/webcommands.py b/mercurial/hgweb/webcommands.py --- a/mercurial/hgweb/webcommands.py +++ b/mercurial/hgweb/webcommands.py @@ -264,6 +264,7 @@ def manifest(web, req, tmpl): node = ctx.node() files = {} + dirs = {} parity = paritygen(web.stripecount) if path and path[-1] != "/": @@ -275,20 +276,25 @@ def manifest(web, req, tmpl): if f[:l] != path: continue remain = f[l:] - idx = remain.find('/') - if idx != -1: - remain = remain[:idx+1] - n = None - files[remain] = (f, n) + elements = remain.split('/') + if len(elements) == 1: + files[remain] = f + else: + h = dirs # need to retain ref to dirs (root) + for elem in elements[0:-1]: + if elem not in h: + h[elem] = {} + h = h[elem] + if len(h) > 1: + break + h[None] = None # denotes files present - if not files: + if not files and not dirs: raise ErrorResponse(HTTP_NOT_FOUND, 'path not found: ' + path) def filelist(**map): for f in util.sort(files): - full, fnode = files[f] - if not fnode: - continue + full = files[f] fctx = ctx.filectx(full) yield {"file": full, @@ -299,14 +305,21 @@ def manifest(web, req, tmpl): "permissions": mf.flags(full)} def dirlist(**map): - for f in util.sort(files): - full, fnode = files[f] - if fnode: - continue + for d in util.sort(dirs): + emptydirs = [] + h = dirs[d] + while isinstance(h, dict) and len(h) == 1: + k,v = h.items()[0] + if v: + emptydirs.append(k) + h = v + + path = "%s%s" % (abspath, d) yield {"parity": parity.next(), - "path": "%s%s" % (abspath, f), - "basename": f[:-1]} + "path": path, + "emptydirs": "/".join(emptydirs), + "basename": d} return tmpl("manifest", rev=ctx.rev(), diff --git a/templates/coal/map b/templates/coal/map --- a/templates/coal/map +++ b/templates/coal/map @@ -23,7 +23,7 @@ searchentry = shortlogentry.tmpl changeset = changeset.tmpl manifest = manifest.tmpl -direntry = ' {basename|escape}/drwxr-xr-x' +direntry = ' {basename|escape}/ {emptydirs|escape}drwxr-xr-x' fileentry = ' {basename|escape}{size}{permissions|permissions}' filerevision = filerevision.tmpl diff --git a/templates/gitweb/map b/templates/gitweb/map --- a/templates/gitweb/map +++ b/templates/gitweb/map @@ -19,7 +19,7 @@ changelogentry = changelogentry.tmpl searchentry = changelogentry.tmpl changeset = changeset.tmpl manifest = manifest.tmpl -direntry = 'drwxr-xr-x#basename|escape#files' +direntry = 'drwxr-xr-x#basename|escape# #emptydirs|escape#files' fileentry = '#permissions|permissions##date|isodate##size##basename|escape#file | revisions | annotate' filerevision = filerevision.tmpl fileannotate = fileannotate.tmpl diff --git a/templates/map b/templates/map --- a/templates/map +++ b/templates/map @@ -19,7 +19,7 @@ changelogentry = changelogentry.tmpl searchentry = changelogentry.tmpl changeset = changeset.tmpl manifest = manifest.tmpl -direntry = 'drwxr-xr-x   #basename|escape#/' +direntry = 'drwxr-xr-x   #basename|escape#/ #emptydirs|urlescape#' fileentry = '#permissions|permissions# #date|isodate# #size# #basename|escape#' filerevision = filerevision.tmpl fileannotate = fileannotate.tmpl diff --git a/templates/paper/map b/templates/paper/map --- a/templates/paper/map +++ b/templates/paper/map @@ -23,7 +23,7 @@ searchentry = ../coal/shortlogentry.tmpl changeset = ../coal/changeset.tmpl manifest = ../coal/manifest.tmpl -direntry = ' {basename|escape}/drwxr-xr-x' +direntry = ' {basename|escape}/ {emptydirs|escape}drwxr-xr-x' fileentry = ' {basename|escape}{size}{permissions|permissions}' filerevision = ../coal/filerevision.tmpl diff --git a/tests/test-hgweb-descend-empties b/tests/test-hgweb-descend-empties new file mode 100755 --- /dev/null +++ b/tests/test-hgweb-descend-empties @@ -0,0 +1,28 @@ +#!/bin/sh +# Test chains of near empty directories, terminating 3 different ways: +# - a1: file at level 4 (deepest) +# - b1: two dirs at level 3 +# - e1: file at level 2 + +echo % Set up the repo +hg init test +cd test +mkdir -p a1/a2/a3/a4 +mkdir -p b1/b2/b3/b4 +mkdir -p b1/b2/c3/c4 +mkdir -p d1/d2/d3/d4 +echo foo > a1/a2/a3/a4/foo +echo foo > b1/b2/b3/b4/foo +echo foo > b1/b2/c3/c4/foo +echo foo > d1/d2/d3/d4/foo +echo foo > d1/d2/foo +hg ci -Ama + +hg serve -n test -p $HGPORT -d --pid-file=hg.pid -E errors.log +cat hg.pid >> $DAEMON_PIDS + +echo % manifest with descending +"$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '/file' + +echo % ERRORS ENCOUNTERED +cat errors.log diff --git a/tests/test-hgweb-descend-empties.out b/tests/test-hgweb-descend-empties.out new file mode 100644 --- /dev/null +++ b/tests/test-hgweb-descend-empties.out @@ -0,0 +1,51 @@ +% Set up the repo +adding a1/a2/a3/a4/foo +adding b1/b2/b3/b4/foo +adding b1/b2/c3/c4/foo +adding d1/d2/d3/d4/foo +adding d1/d2/foo +% manifest with descending +200 Script output follows + + + + + + + + +test: files for changeset 9087c84a0f5d + + + +
+changelog +shortlog +graph +tags +changeset + +
+ +

files for changeset 9087c84a0f5d: /

+ + + + +
drwxr-xr-x  +   +   + [up] +
drwxr-xr-x   a1/ a2/a3/a4
drwxr-xr-x   b1/ b2
drwxr-xr-x   d1/ d2 + +
+ + + + + + +% ERRORS ENCOUNTERED