[PATCH] hgweb: expose list of per-repo labels to templates

Gregory Szorc gregory.szorc at gmail.com
Thu Jun 30 22:09:57 EDT 2016


# HG changeset patch
# User Gregory Szorc <gregory.szorc at gmail.com>
# Date 1467338393 25200
#      Thu Jun 30 18:59:53 2016 -0700
# Node ID 4b7c13a0b961b3ab838dc6c8a5b127f85df07b36
# Parent  7dce56174916e09be39c690278942b4f7567b3f6
hgweb: expose list of per-repo labels to templates

hgweb currently offers limited functionality for "classifying"
repositories. This patch aims to change that.

The web.labels config option list is introduced. It's values
are exposed to the "index" and "summary" templates. Custom
templates can use template features like ifcontains() to e.g.
look for the presence of a specific label and engage specific
behavior. For example, a site operator may wish to assign a
"defunct" label to a repository so the repository is prominently
marked as dead in repository indexes.

diff --git a/mercurial/help/config.txt b/mercurial/help/config.txt
--- a/mercurial/help/config.txt
+++ b/mercurial/help/config.txt
@@ -2020,16 +2020,24 @@ The full set of options is:
 
 ``hidden``
     Whether to hide the repository in the hgwebdir index.
     (default: False)
 
 ``ipv6``
     Whether to use IPv6. (default: False)
 
+``labels``
+    List of string *labels* associated with the repository.
+
+    Labels are exposed as a template keyword and can be used to customize
+    output. e.g. the ``index`` template can group or filter repositories
+    by labels and the ``summary`` template can display additional content
+    if a specific label is present.
+
 ``logoimg``
     File name of the logo image that some templates display on each page.
     The file name is relative to ``staticurl``. That is, the full path to
     the logo image is "staticurl/logoimg".
     If unset, ``hglogo.png`` will be used.
 
 ``logourl``
     Base URL to use for logos. If unset, ``https://mercurial-scm.org/``
diff --git a/mercurial/hgweb/hgwebdir_mod.py b/mercurial/hgweb/hgwebdir_mod.py
--- a/mercurial/hgweb/hgwebdir_mod.py
+++ b/mercurial/hgweb/hgwebdir_mod.py
@@ -361,17 +361,19 @@ class hgwebdir(object):
                            'name': name + '/',
                            'name_sort': name,
                            'url': url,
                            'description': "",
                            'description_sort': "",
                            'lastchange': d,
                            'lastchange_sort': d[1]-d[0],
                            'archives': [],
-                           'isdirectory': True}
+                           'isdirectory': True,
+                           'labels': [],
+                           }
 
                     seendirs.add(name)
                     yield row
                     continue
 
                 u = self.ui.copy()
                 try:
                     u.readconfig(os.path.join(path, '.hg', 'hgrc'))
@@ -411,16 +413,17 @@ class hgwebdir(object):
                        'name_sort': name,
                        'url': url,
                        'description': description or "unknown",
                        'description_sort': description.upper() or "unknown",
                        'lastchange': d,
                        'lastchange_sort': d[1]-d[0],
                        'archives': archivelist(u, "tip", url),
                        'isdirectory': None,
+                       'labels': u.configlist('web', 'labels', untrusted=True),
                        }
 
                 yield row
 
         sortdefault = None, False
         def entries(sortcolumn="", descending=False, subdir="", **map):
             rows = rawentries(subdir=subdir, **map)
 
diff --git a/mercurial/hgweb/webcommands.py b/mercurial/hgweb/webcommands.py
--- a/mercurial/hgweb/webcommands.py
+++ b/mercurial/hgweb/webcommands.py
@@ -720,17 +720,18 @@ def summary(web, req, tmpl):
                 owner=get_contact(web.config) or "unknown",
                 lastchange=tip.date(),
                 tags=tagentries,
                 bookmarks=bookmarks,
                 branches=webutil.branchentries(web.repo, web.stripecount, 10),
                 shortlog=changelist,
                 node=tip.hex(),
                 symrev='tip',
-                archives=web.archivelist("tip"))
+                archives=web.archivelist("tip"),
+                labels=web.configlist('web', 'labels'))
 
 @webcommand('filediff')
 def filediff(web, req, tmpl):
     """
     /diff/{revision}/{path}
     -----------------------
 
     Show how a file changed in a particular commit.
diff --git a/mercurial/templates/json/map b/mercurial/templates/json/map
--- a/mercurial/templates/json/map
+++ b/mercurial/templates/json/map
@@ -104,17 +104,18 @@ branchentry = '\{
 shortlogentry = '{changelistentry}'
 summary = '\{
   "node": {node|json},
   "lastchange": {lastchange|json},
   "bookmarks": [{join(bookmarks%bookmarkentry, ", ")}],
   "branches": [{join(branches%branchentry, ", ")}],
   "shortlog": [{join(shortlog%shortlogentry, ", ")}],
   "tags": [{join(tags%tagentry, ", ")}],
-  "archives": [{join(archives%archiveentry, ", ")}]
+  "archives": [{join(archives%archiveentry, ", ")}],
+  "labels": {labels|json}
   }'
 archiveentry = '\{
   "node": {node|json},
   "extension": {extension|json},
   "type": {type|json}
   }'
 filediff = '\{
   "path": {file|json},
@@ -214,10 +215,11 @@ filenodelink = ''
 filenolink = ''
 index = '\{
   "entries": [{join(entries%indexentry, ", ")}]
   }'
 indexentry = '\{
   "name": {name|utf8|json},
   "description": {description|utf8|json},
   "contact": {contact|utf8|json},
-  "lastchange": {lastchange|json}
+  "lastchange": {lastchange|json},
+  "labels": {labels|json}
   }'
diff --git a/tests/test-hgweb-json.t b/tests/test-hgweb-json.t
--- a/tests/test-hgweb-json.t
+++ b/tests/test-hgweb-json.t
@@ -834,16 +834,17 @@ summary/ shows a summary of repository s
         "date": [
           0.0,
           0
         ],
         "node": "ed66c30e87eb65337c05a4229efaa5f1d5285a90",
         "status": "inactive"
       }
     ],
+    "labels": [],
     "lastchange": [
       0.0,
       0
     ],
     "node": "cc725e08502a79dd1eda913760fbe06ed7a9abc7",
     "shortlog": [
       {
         "bookmarks": [],
diff --git a/tests/test-hgwebdir.t b/tests/test-hgwebdir.t
--- a/tests/test-hgwebdir.t
+++ b/tests/test-hgwebdir.t
@@ -57,16 +57,17 @@ create a subdirectory containing reposit
   $ hg --cwd f/f2 ci -Amf2 -d '4 0'
   adding f2
   $ echo 'f2 = f2' > f/.hgsub
   $ hg -R f ci -Am 'add subrepo' -d'4 0'
   adding .hgsub
   $ cat >> f/.hg/hgrc << EOF
   > [web]
   > name = fancy name for repo f
+  > labels = foo, bar
   > EOF
   $ cd ..
 
 create repository without .hg/store
 
   $ hg init nostore
   $ rm -R nostore/.hg/store
   $ root=`pwd`
@@ -103,22 +104,24 @@ should succeed
   $ get-with-headers.py localhost:$HGPORT '?style=json'
   200 Script output follows
   
   {
   "entries": [{
   "name": "a",
   "description": "unknown",
   "contact": "Foo Bar \u003cfoo.bar at example.com\u003e",
-  "lastchange": [*, *] (glob)
+  "lastchange": [*, *], (glob)
+  "labels": []
   }, {
   "name": "b",
   "description": "unknown",
   "contact": "Foo Bar \u003cfoo.bar at example.com\u003e",
-  "lastchange": [*, *] (glob)
+  "lastchange": [*, *], (glob)
+  "labels": []
   }]
   } (no-eol)
 
   $ get-with-headers.py localhost:$HGPORT 'a/file/tip/a?style=raw'
   200 Script output follows
   
   a
   $ get-with-headers.py localhost:$HGPORT 'b/file/tip/b?style=raw'
@@ -196,16 +199,228 @@ should succeed, slashy names
   /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/
   
+
+  $ get-with-headers.py localhost:$HGPORT1 '?style=json'
+  200 Script output follows
+  
+  {
+  "entries": [{
+  "name": "t/a",
+  "description": "unknown",
+  "contact": "Foo Bar \u003cfoo.bar at example.com\u003e",
+  "lastchange": [*, *], (glob)
+  "labels": []
+  }, {
+  "name": "b",
+  "description": "unknown",
+  "contact": "Foo Bar \u003cfoo.bar at example.com\u003e",
+  "lastchange": [*, *], (glob)
+  "labels": []
+  }, {
+  "name": "coll/a",
+  "description": "unknown",
+  "contact": "Foo Bar \u003cfoo.bar at example.com\u003e",
+  "lastchange": [*, *], (glob)
+  "labels": []
+  }, {
+  "name": "coll/a/.hg/patches",
+  "description": "unknown",
+  "contact": "Foo Bar \u003cfoo.bar at example.com\u003e",
+  "lastchange": [*, *], (glob)
+  "labels": []
+  }, {
+  "name": "coll/b",
+  "description": "unknown",
+  "contact": "Foo Bar \u003cfoo.bar at example.com\u003e",
+  "lastchange": [*, *], (glob)
+  "labels": []
+  }, {
+  "name": "coll/c",
+  "description": "unknown",
+  "contact": "Foo Bar \u003cfoo.bar at example.com\u003e",
+  "lastchange": [*, *], (glob)
+  "labels": []
+  }, {
+  "name": "coll/notrepo/e",
+  "description": "unknown",
+  "contact": "Foo Bar \u003cfoo.bar at example.com\u003e",
+  "lastchange": [*, *], (glob)
+  "labels": []
+  }, {
+  "name": "fancy name for repo f",
+  "description": "unknown",
+  "contact": "Foo Bar \u003cfoo.bar at example.com\u003e",
+  "lastchange": [*, *], (glob)
+  "labels": ["foo", "bar"]
+  }, {
+  "name": "rcoll/a",
+  "description": "unknown",
+  "contact": "Foo Bar \u003cfoo.bar at example.com\u003e",
+  "lastchange": [*, *], (glob)
+  "labels": []
+  }, {
+  "name": "rcoll/a/.hg/patches",
+  "description": "unknown",
+  "contact": "Foo Bar \u003cfoo.bar at example.com\u003e",
+  "lastchange": [*, *], (glob)
+  "labels": []
+  }, {
+  "name": "rcoll/b",
+  "description": "unknown",
+  "contact": "Foo Bar \u003cfoo.bar at example.com\u003e",
+  "lastchange": [*, *], (glob)
+  "labels": []
+  }, {
+  "name": "rcoll/b/d",
+  "description": "unknown",
+  "contact": "Foo Bar \u003cfoo.bar at example.com\u003e",
+  "lastchange": [*, *], (glob)
+  "labels": []
+  }, {
+  "name": "rcoll/c",
+  "description": "unknown",
+  "contact": "Foo Bar \u003cfoo.bar at example.com\u003e",
+  "lastchange": [*, *], (glob)
+  "labels": []
+  }, {
+  "name": "rcoll/notrepo/e",
+  "description": "unknown",
+  "contact": "Foo Bar \u003cfoo.bar at example.com\u003e",
+  "lastchange": [*, *], (glob)
+  "labels": []
+  }, {
+  "name": "rcoll/notrepo/e/e2",
+  "description": "unknown",
+  "contact": "Foo Bar \u003cfoo.bar at example.com\u003e",
+  "lastchange": [*, *], (glob)
+  "labels": []
+  }, {
+  "name": "fancy name for repo f",
+  "description": "unknown",
+  "contact": "Foo Bar \u003cfoo.bar at example.com\u003e",
+  "lastchange": [*, *], (glob)
+  "labels": ["foo", "bar"]
+  }, {
+  "name": "rcoll/notrepo/f/f2",
+  "description": "unknown",
+  "contact": "Foo Bar \u003cfoo.bar at example.com\u003e",
+  "lastchange": [*, *], (glob)
+  "labels": []
+  }, {
+  "name": "star/webdir/a",
+  "description": "unknown",
+  "contact": "Foo Bar \u003cfoo.bar at example.com\u003e",
+  "lastchange": [*, *], (glob)
+  "labels": []
+  }, {
+  "name": "star/webdir/a/.hg/patches",
+  "description": "unknown",
+  "contact": "Foo Bar \u003cfoo.bar at example.com\u003e",
+  "lastchange": [*, *], (glob)
+  "labels": []
+  }, {
+  "name": "star/webdir/b",
+  "description": "unknown",
+  "contact": "Foo Bar \u003cfoo.bar at example.com\u003e",
+  "lastchange": [*, *], (glob)
+  "labels": []
+  }, {
+  "name": "star/webdir/c",
+  "description": "unknown",
+  "contact": "Foo Bar \u003cfoo.bar at example.com\u003e",
+  "lastchange": [*, *], (glob)
+  "labels": []
+  }, {
+  "name": "star/webdir/notrepo/e",
+  "description": "unknown",
+  "contact": "Foo Bar \u003cfoo.bar at example.com\u003e",
+  "lastchange": [*, *], (glob)
+  "labels": []
+  }, {
+  "name": "fancy name for repo f",
+  "description": "unknown",
+  "contact": "Foo Bar \u003cfoo.bar at example.com\u003e",
+  "lastchange": [*, *], (glob)
+  "labels": ["foo", "bar"]
+  }, {
+  "name": "starstar/webdir/a",
+  "description": "unknown",
+  "contact": "Foo Bar \u003cfoo.bar at example.com\u003e",
+  "lastchange": [*, *], (glob)
+  "labels": []
+  }, {
+  "name": "starstar/webdir/a/.hg/patches",
+  "description": "unknown",
+  "contact": "Foo Bar \u003cfoo.bar at example.com\u003e",
+  "lastchange": [*, *], (glob)
+  "labels": []
+  }, {
+  "name": "starstar/webdir/b",
+  "description": "unknown",
+  "contact": "Foo Bar \u003cfoo.bar at example.com\u003e",
+  "lastchange": [*, *], (glob)
+  "labels": []
+  }, {
+  "name": "starstar/webdir/b/d",
+  "description": "unknown",
+  "contact": "Foo Bar \u003cfoo.bar at example.com\u003e",
+  "lastchange": [*, *], (glob)
+  "labels": []
+  }, {
+  "name": "starstar/webdir/c",
+  "description": "unknown",
+  "contact": "Foo Bar \u003cfoo.bar at example.com\u003e",
+  "lastchange": [*, *], (glob)
+  "labels": []
+  }, {
+  "name": "starstar/webdir/notrepo/e",
+  "description": "unknown",
+  "contact": "Foo Bar \u003cfoo.bar at example.com\u003e",
+  "lastchange": [*, *], (glob)
+  "labels": []
+  }, {
+  "name": "starstar/webdir/notrepo/e/e2",
+  "description": "unknown",
+  "contact": "Foo Bar \u003cfoo.bar at example.com\u003e",
+  "lastchange": [*, *], (glob)
+  "labels": []
+  }, {
+  "name": "fancy name for repo f",
+  "description": "unknown",
+  "contact": "Foo Bar \u003cfoo.bar at example.com\u003e",
+  "lastchange": [*, *], (glob)
+  "labels": ["foo", "bar"]
+  }, {
+  "name": "starstar/webdir/notrepo/f/f2",
+  "description": "unknown",
+  "contact": "Foo Bar \u003cfoo.bar at example.com\u003e",
+  "lastchange": [*, *], (glob)
+  "labels": []
+  }, {
+  "name": "astar",
+  "description": "unknown",
+  "contact": "Foo Bar \u003cfoo.bar at example.com\u003e",
+  "lastchange": [*, *], (glob)
+  "labels": []
+  }, {
+  "name": "astar/.hg/patches",
+  "description": "unknown",
+  "contact": "Foo Bar \u003cfoo.bar at example.com\u003e",
+  "lastchange": [*, *], (glob)
+  "labels": []
+  }]
+  } (no-eol)
+
   $ get-with-headers.py localhost:$HGPORT1 '?style=paper'
   200 Script output follows
   
   <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
   <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
   <head>
   <link rel="icon" href="/static/hgicon.png" type="image/png" />
   <meta name="robots" content="index, nofollow" />


More information about the Mercurial-devel mailing list