# HG changeset patch # User Ry4an Brase # Date 1225704028 -3600 # Node ID c21d236ca897105057dbf8d5609057eaa6f28088 # Parent 68374f1c8c87177dec40de56f3b046a84693e9be hgweb: descend empty directories in web view When a manifest has a series of directories with nothing in them but a single directory, displaying the entire chain of empty directories allows for navigation down to the first non-empty directory with a single click. Because Java links package hierarchy to directory hierarchy, and because Java conventions include at least three empty directories at the top of this hierarchy, descending down empty directories is very common in Java web tools. diff -r 68374f1c8c87 -r c21d236ca897 mercurial/hgweb/webcommands.py --- a/mercurial/hgweb/webcommands.py Sun Nov 02 22:44:42 2008 +0100 +++ b/mercurial/hgweb/webcommands.py Mon Nov 03 10:20:28 2008 +0100 @@ -264,6 +264,7 @@ node = ctx.node() files = {} + dirs = {} parity = paritygen(web.stripecount) if path and path[-1] != "/": @@ -275,20 +276,25 @@ 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 @@ "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 -r 68374f1c8c87 -r c21d236ca897 templates/coal/map --- a/templates/coal/map Sun Nov 02 22:44:42 2008 +0100 +++ b/templates/coal/map Mon Nov 03 10:20:28 2008 +0100 @@ -23,7 +23,7 @@ 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 -r 68374f1c8c87 -r c21d236ca897 templates/gitweb/map --- a/templates/gitweb/map Sun Nov 02 22:44:42 2008 +0100 +++ b/templates/gitweb/map Mon Nov 03 10:20:28 2008 +0100 @@ -19,7 +19,7 @@ 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 -r 68374f1c8c87 -r c21d236ca897 templates/map --- a/templates/map Sun Nov 02 22:44:42 2008 +0100 +++ b/templates/map Mon Nov 03 10:20:28 2008 +0100 @@ -19,7 +19,7 @@ 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 -r 68374f1c8c87 -r c21d236ca897 templates/paper/map --- a/templates/paper/map Sun Nov 02 22:44:42 2008 +0100 +++ b/templates/paper/map Mon Nov 03 10:20:28 2008 +0100 @@ -23,7 +23,7 @@ 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 -r 68374f1c8c87 -r c21d236ca897 tests/test-hgweb-descend-empties --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-hgweb-descend-empties Mon Nov 03 10:20:28 2008 +0100 @@ -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 -r 68374f1c8c87 -r c21d236ca897 tests/test-hgweb-descend-empties.out --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-hgweb-descend-empties.out Mon Nov 03 10:20:28 2008 +0100 @@ -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