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
+
+
+
+
+
+files for changeset 9087c84a0f5d: /
+
+
+
+
+
+![mercurial](/static/hglogo.png)
+
+
+
+
+
+% ERRORS ENCOUNTERED