[Qa-jenkins-scm] [jenkins.debian.net] 01/03: reproducible debian: improve package page navigation

Holger Levsen holger at layer-acht.org
Fri Jun 17 21:32:24 UTC 2016


This is an automated email from the git hooks/post-receive script.

holger pushed a commit to branch master
in repository jenkins.debian.net.

commit 0c3fcd537bd06556cda1d290ee926e8365969a04
Author: Valerie R Young <spectranaut at riseup.net>
Date:   Thu Jun 16 09:45:56 2016 -0400

    reproducible debian: improve package page navigation
    
    Changes made:
    - suite and arch specific details moved from the top of side bar to
      the suite and arch section
    - "notes" and "test history" (suite and arch agnostic) move to the top
      of side bar
    - hover text added to most links, starting with either "Go to:" (if
      the link takes you away from package page) or "Show:" (if the link
      opens a file in the iframe)
    - enabled notifications flag still on top left, by "Test Details" header
    
    reproducible debian: address mattia's code review comments
    
    Signed-off-by: Holger Levsen <holger at layer-acht.org>
---
 bin/reproducible_common.py                       |   1 +
 bin/reproducible_html_packages.py                | 289 ++++++++++++-----------
 bin/templates/package_page.mustache              |  44 ++++
 bin/templates/package_suitearch_details.mustache |  36 +++
 bin/templates/package_suitearch_section.mustache |  30 +++
 bin/templates/status_icon_link.mustache          |  14 ++
 update_jdn.sh                                    |   1 +
 7 files changed, 272 insertions(+), 143 deletions(-)

diff --git a/bin/reproducible_common.py b/bin/reproducible_common.py
index 3c3f31b..d0224b1 100755
--- a/bin/reproducible_common.py
+++ b/bin/reproducible_common.py
@@ -44,6 +44,7 @@ defaultarch = 'amd64'
 BIN_PATH = '/srv/jenkins/bin'
 BASE = '/var/lib/jenkins/userContent/reproducible'
 DEBIAN_BASE = '/var/lib/jenkins/userContent/reproducible/debian'
+TEMPLATE_PATH = BIN_PATH + '/templates'
 
 REPRODUCIBLE_JSON = BASE + '/reproducible.json'
 REPRODUCIBLE_TRACKER_JSON = BASE + '/reproducible-tracker.json'
diff --git a/bin/reproducible_html_packages.py b/bin/reproducible_html_packages.py
index 840bc17..f9d2619 100755
--- a/bin/reproducible_html_packages.py
+++ b/bin/reproducible_html_packages.py
@@ -10,48 +10,18 @@
 # Build rb-pkg pages (the pages that describe the package status)
 
 from reproducible_common import *
+import pystache
 
-html_package_page = Template((tab*2).join(("""
-<header class="head">
-    <h2 class="package-name">$package</h2>
-    <ul class="menu">
-        <li><ul class="children">
-          <li>$version <a href="debian/index_notify.html" target="_parent">
-            <span class="notification" title="Notifications for this package are enabled. Every reproducibility related status change will be emailed to the maintainers">$notify_maintainer</span></a></li>
-          <li>$suite/$arch </li>
-          <li>$status </li>
-          <li><span class="build-time">$build_time</span></li>
-          $links
-        </ul></li>
-        <li>
-            <a href="https://tracker.debian.org/$package">PTS</a>
-            <a href="https://bugs.debian.org/src:$package">BTS</a>
-        </li>
-        <li>
-            <a href="https://sources.debian.net/src/$package/$version/">sources</a>
-            <a href="https://sources.debian.net/src/$package/$version/debian">debian/</a>
-            <ul class="children">
-                <li><a href="https://sources.debian.net/src/$package/$version/debian/changelog">changelog</a></li>
-                <li><a href="https://sources.debian.net/src/$package/$version/debian/control">control</a></li>
-                <li><a href="https://sources.debian.net/src/$package/$version/debian/rules">rules</a></li>
-            </ul>
-        </li>
-        <li>
-          <a href="$history" target="main">Test history</a>
-        </li>
-${suites_links}
-     <li><a href="%s">Debian dashboard</a></li></ul>
-    </ul>
-${project_links}
-</header>
-
-<iframe id="main" name="main" tabindex="1" src="${default_view}">
-    <p>
-        Your browser does not support iframes.
-        Use a different one or follow the links above.
-    </p>
-</iframe>""" % DEBIAN_URL ).splitlines(True)))
-
+# Templates used for creating package pages
+renderer = pystache.Renderer();
+package_page_template = renderer.load_template(
+    TEMPLATE_PATH + '/package_page')
+suitearch_section_template = renderer.load_template(
+    TEMPLATE_PATH + '/package_suitearch_section')
+suitearch_details_template = renderer.load_template(
+    TEMPLATE_PATH + '/package_suitearch_details')
+status_icon_link_template = renderer.load_template(
+    TEMPLATE_PATH + '/status_icon_link')
 
 def sizeof_fmt(num):
     for unit in ['B','KB','MB','GB']:
@@ -65,37 +35,33 @@ def sizeof_fmt(num):
 
 
 def gen_status_link_icon(status, spokenstatus, icon, suite, arch):
-    html = """
-        <a href="/{suite}/{arch}/index_{status}.html" target="_parent" title="{spokenstatus}">
-            <img src="/static/{icon}" alt="{spokenstatus}"></a>
-
-        <a href="/{suite}/{arch}/index_{status}.html" target="_parent" title="{spokenstatus}">
-            {spokenstatus}</a>
-    """
-
-    # There are no indices for untested packages
-    if status == 'untested':
-        html = '<img src="/static/{icon}" alt="{spokenstatus}"> {spokenstatus}'
-
-    return html.format(status=status, spokenstatus=spokenstatus, icon=icon, suite=suite, arch=arch)
+    context = {
+        'status': status,
+        'spokenstatus': spokenstatus,
+        'icon': icon,
+        'suite': suite,
+        'arch': arch,
+        'untested': True if status == 'untested' else False,
+    }
+    return renderer.render(status_icon_link_template, context)
 
-
-def link_buildlogs(package, eversion, suite, arch):
-    html = ''
+def get_buildlog_links_context(package, eversion, suite, arch):
     log = suite + '/' + arch + '/' + package + '_' + eversion + '.build2.log.gz'
     diff = suite + '/' + arch + '/' + package + '_' + eversion + '.diff.gz'
+
+    context = {}
     if os.access(LOGS_PATH+'/'+log, os.R_OK):
-        uri = LOGS_URI + '/' + log
-        size = sizeof_fmt(os.stat(LOGS_PATH+'/'+log).st_size)
-        html += '<a href="' + uri + '" target="main">build2 (' + size + ')</a>\n'
+        context['build2_uri'] = LOGS_URI + '/' + log
+        context['build2_size'] = sizeof_fmt(os.stat(LOGS_PATH+'/'+log).st_size)
+
     if os.access(DIFFS_PATH+'/'+diff, os.R_OK):
-        uri = DIFFS_URI + '/' + diff
-        html += '<a href="' + uri + '" target="main">diff</a>\n'
-    return html
+        context['diff_uri'] = DIFFS_URI + '/' + diff
+
+    return context
 
 
-def link_diffs(package, eversion, suite, arch, status):
-    html = ''
+def get_dbd_link_context(package, eversion, suite, arch, status):
+
     dbd = DBD_PATH + '/' + suite + '/' + arch + '/' + package + '_' + \
           eversion + '.diffoscope.html'
     dbdtxt = DBDTXT_PATH + '/' + suite + '/' + arch + '/' + package + '_' + \
@@ -104,98 +70,132 @@ def link_diffs(package, eversion, suite, arch, status):
               eversion + '.diffoscope.html'
     dbdtxt_url = DBDTXT_URI + '/' + suite + '/' + arch + '/' +  package + '_' + \
                 eversion + '.diffoscope.txt'
+
+    context = {}
     if os.access(dbd, os.R_OK):
-        html += '<li><a href="' + dbd_url + '" target="main">differences</a>\n'
+        context['dbd_url'] = dbd_url
         if os.access(dbdtxt, os.R_OK):
-            html += '<a href="' + dbdtxt_url + '" target="main">(txt)</a>\n'
-        html += '</li>\n'
+            context['dbdtxt_url'] = dbdtxt_url
     else:
         if status == 'unreproducible' and not args.ignore_missing_files:
             log.critical(DEBIAN_URL + '/' + suite + '/' + arch + '/' + package +
                          ' is unreproducible, but without diffoscope output.')
-    return html, dbd_url
+    return context, dbd_url
 
 
-def gen_extra_links(package, version, suite, arch, status):
+def gen_suitearch_details(package, version, suite, arch, status, spokenstatus,
+                          build_date):
     eversion = strip_epoch(version)
-    notes = NOTES_PATH + '/' + package + '_note.html'
-    buildinfo = BUILDINFO_PATH + '/' + suite + '/' + arch + '/' + package + \
+    buildinfo_file = BUILDINFO_PATH + '/' + suite + '/' + arch + '/' + package + \
                 '_' + eversion + '_' + arch + '.buildinfo'
 
-    links = ''
+    context = {}
     default_view = ''
-    if os.access(notes, os.R_OK):
-        url = NOTES_URI + '/' + package + '_note.html'
-        links += '<li><a href="' + url + '" target="main">notes</a></li>\n'
-        default_view = url
-    dbd = link_diffs(package, eversion, suite, arch, status)
-    links += dbd[0] if dbd[0] else ''
-    if dbd[0] and not default_view:
-            default_view = dbd[1]
+
+    # Make notes the default default view
+    notes_file = NOTES_PATH + '/' + package + '_note.html'
+    notes_uri = NOTES_URI + '/' + package + '_note.html'
+    if os.access(notes_file, os.R_OK):
+        default_view = notes_uri
+
+    # Get summary context
+    context['status_html'] = gen_status_link_icon(status, spokenstatus, None,
+                                                  suite, arch)
+    context['build_date'] =  build_date
+
+    default_view = ''
+    # Get diffoscope differences context
+    dbd = get_dbd_link_context(package, eversion, suite, arch, status)
+    if dbd[0]:
+        context['dbd'] = dbd[0]
+        default_view = default_view if default_view else dbd[1]
+
+    # Get buildinfo context
     if pkg_has_buildinfo(package, version, suite, arch):
         url = BUILDINFO_URI + '/' + suite + '/' + arch + '/' + package + \
               '_' + eversion + '_' + arch + '.buildinfo'
-        links += '<li><a href="' + url + '" target="main">buildinfo</a></li>\n'
-        if not default_view:
-            default_view = url
+        context['buildinfo_uri'] = url
+        default_view = default_view if default_view else url
     elif not args.ignore_missing_files and status not in \
         ('untested', 'blacklisted', 'FTBFS', 'not for us', 'depwait', '404'):
-            log.critical('buildinfo not detected at ' + buildinfo)
+            log.critical('buildinfo not detected at ' + buildinfo_file)
+
+    # Get rbuild, build2 and build diffs context
     rbuild = pkg_has_rbuild(package, version, suite, arch)
     if rbuild:  # being a tuple (rbuild path, size), empty if non existant
         url = RBUILD_URI + '/' + suite + '/' + arch + '/' + package + '_' + \
               eversion + '.rbuild.log'  # apache ignores the trailing .gz
-        links +='<li><a href="' + url + '" target="main">rbuild (' + \
-                sizeof_fmt(rbuild[1]) + ')</a>\n'
-        if not default_view:
-            default_view = url
-        links += link_buildlogs(package, eversion, suite, arch) + '</li>\n'
-    elif status not in ('untested', 'blacklisted') and not args.ignore_missing_files:
+        context['rbuild_uri'] = url
+        context['rbuild_size'] = sizeof_fmt(rbuild[1])
+        default_view = default_view if default_view else url
+        context['buildlogs'] = get_buildlog_links_context(package, eversion,
+                                                          suite, arch)
+    elif status not in ('untested', 'blacklisted') and \
+         not args.ignore_missing_files:
         log.critical(DEBIAN_URL  + '/' + suite + '/' + arch + '/' + package +
                      ' didn\'t produce a buildlog, even though it has been built.')
-    default_view = '/untested.html' if not default_view else default_view
-    return (links, default_view)
 
+    context['has_buildloginfo'] = 'buildinfo_uri' in context or \
+                                  'buildlogs' in context or \
+                                  'rbuild_uri' in context
 
-def gen_suites_links(package, current_suite, current_arch):
-    html = '<ul>\n'
+    default_view = '/untested.html' if not default_view else default_view
+    suitearch_details_html = renderer.render(suitearch_details_template, context)
+    return (suitearch_details_html, default_view)
+
+def gen_suitearch_section(package, current_suite, current_arch):
+    default_view = ''
+    context = {}
+    context['architectures'] = []
     for a in ARCHS:
-        html += tab + '<li>{}\n'.format(a)
-        html += tab + '<ul class="children">\n'
+
+        suites = []
         for s in SUITES:
+
             status = package.get_status(s, a)
             if not status:  # The package is not available in that suite/arch
                 continue
             version = package.get_tested_version(s, a)
+
             build_date = package.get_build_date(s, a)
             status, icon, spokenstatus = get_status_icon(status)
-            if build_date and status != 'blacklisted':
-                build_date = ' on ' + build_date
-            else:
+
+            if not (build_date and status != 'blacklisted'):
                 build_date = ''
+
             li_classes = ['suite']
             if s == current_suite and a == current_arch:
                 li_classes.append('active')
-            html += '<li class="' + ' '.join(li_classes) + '">\n' + tab
-            if ( s == current_suite and a == current_arch ) or status == 'untested':
-                prefix = ''
-                suffix = '\n'
-            else:
-                prefix = '<a href="/debian/{}/{}/index_{}.html">'.format(s, a, status)
-                suffix = '</a>\n'
-            icon_html = prefix + '<img src="/static/{icon}" alt="{spokenstatus}" title="{spokenstatus}"/>' + suffix
-            html += icon_html.format(icon=icon, status=status, spokenstatus=spokenstatus)
-            if ( s == current_suite and a == current_arch ):
-                html += (tab*2 + ' {}').format(version)
-            else:
-                html += (tab*2 + ' <a href="{}/{}/{}/{}.html" target="_parent"' + \
-                     ' title="{}: {}{}">{}</a>').format(RB_PKG_URI,
-                     s, a, package.name, spokenstatus, version, build_date, version)
-            html += ' in <a href="/debian/{}/{}/" target="_parent">{}</a>\n'.format(s, a, s)
-            html += '</li>\n'
-        html += tab + '</ul></li>'
-    html += '</ul>\n'
-    return tab*5 + (tab*7).join(html.splitlines(True))
+            package_uri = ('{}/{}/{}/{}.html').format(RB_PKG_URI, s, a, package.name)
+
+            suitearch_details_html = ''
+            if (s == current_suite and a == current_arch):
+                suitearch_details_html, default_view = gen_suitearch_details(
+                    package.name, version, s, a, status, spokenstatus, build_date)
+
+            suites.append({
+                'status': status,
+                'version': version,
+                'build_date': build_date,
+                'icon': icon,
+                'spokenstatus': spokenstatus,
+                'li_classes': ' '.join(li_classes),
+                'arch': a,
+                'suite': s,
+                'untested': status == 'untested',
+                'current_suitearch': s == current_suite and a == current_arch,
+                'package_uri': package_uri,
+                'suitearch_details_html': suitearch_details_html,
+            })
+
+        if len(suites):
+            context['architectures'].append({
+                'arch': a,
+                'suites': suites,
+            })
+
+    html = renderer.render(suitearch_section_template, context)
+    return html, default_view
 
 def shorten_if_debiannet(hostname):
     if hostname[-11:] == '.debian.net':
@@ -247,42 +247,45 @@ def gen_packages_html(packages, no_clean=False):
         assert isinstance(package, Package)
         gen_history_page(package)
         pkg = package.name
+
+        notes_uri = ''
+        notes_file = NOTES_PATH + '/' + pkg + '_note.html'
+        if os.access(notes_file, os.R_OK):
+            notes_uri = NOTES_URI + '/' + pkg + '_note.html'
+
         for suite in SUITES:
             for arch in ARCHS:
+
                 status = package.get_status(suite, arch)
                 version = package.get_tested_version(suite, arch)
                 build_date = package.get_build_date(suite, arch)
-                if build_date and status != 'blacklisted':
-                    build_date = 'at ' + build_date
-                else:
-                    build_date = ''
                 if status == False:  # the package is not in the checked suite
                     continue
                 log.debug('Generating the page of %s/%s/%s @ %s built at %s',
                           pkg, suite, arch, version, build_date)
 
-                links, default_view = gen_extra_links(
-                    pkg, version, suite, arch, status)
-                suites_links = gen_suites_links(package, suite, arch)
-                status, icon, spokenstatus = get_status_icon(status)
-                status = gen_status_link_icon(status, spokenstatus, icon, suite, arch)
+                suitearch_section_html, default_view = gen_suitearch_section(
+                    package, suite, arch)
+
                 history = '{}/{}.html'.format(HISTORY_URI, pkg)
                 project_links = html_project_links.substitute()
 
-                html = html_package_page.substitute(
-                    package=pkg,
-                    suite=suite,
-                    arch=arch,
-                    status=status,
-                    version=version,
-                    build_time=build_date,
-                    history=history,
-                    links=links,
-                    notify_maintainer=package.notify_maint,
-                    suites_links=suites_links,
-                    project_links=project_links,
-                    default_view=default_view)
-                destfile = RB_PKG_PATH + '/' + suite + '/' + arch + '/' + pkg + '.html'
+                html = renderer.render(package_page_template, {
+                    'package': pkg,
+                    'suite': suite,
+                    'arch': arch,
+                    'version': version,
+                    'history': history,
+                    'notes_uri': notes_uri,
+                    'notify_maintainer': package.notify_maint,
+                    'suitearch_section_html': suitearch_section_html,
+                    'project_links_html': project_links,
+                    'default_view': default_view,
+                    'dashboard_url': DEBIAN_URL,
+                })
+
+                destfile = RB_PKG_PATH + '/' + suite + '/' + arch + '/' + \
+                           pkg + '.html'
                 desturl = REPRODUCIBLE_URL + RB_PKG_URI + '/' + suite + \
                           '/' + arch + '/' + pkg + '.html'
                 title = pkg + ' - reproducible build results'
diff --git a/bin/templates/package_page.mustache b/bin/templates/package_page.mustache
new file mode 100644
index 0000000..059bffb
--- /dev/null
+++ b/bin/templates/package_page.mustache
@@ -0,0 +1,44 @@
+<header class="head">
+  <h2 class="package-name">{{package}}</h2>
+  <ul class="menu">
+    <h3>Test Details
+      <a href="debian/index_notify.html" target="_parent">
+        <span class="notification" title="Notifications for this package are enabled. Every reproducibility related status change will be emailed to the maintainers">{{notify_maintainer}}</span>
+      </a>
+    </h3>
+    {{#notes_uri}}
+    <li><a href="{{notes_uri}}" title="Additional commentary on this packages unreproduciblity"target="main">notes</a></li>
+    {{/notes_uri}}
+    <li>
+      <a href="{{history}}" target="main">test history</a>
+    </li>
+    <h3>Suite and Architecture</h3>
+    {{{suitearch_section_html}}}
+    <h3>General Package Details</h3>
+    <li>
+      <a href="https://tracker.debian.org/{{package}}" title="Go to: Debian Package Tracking Site">PTS</a>
+      <a href="https://bugs.debian.org/src:{{package}}" title="Go to: Debian Bug Tracking Site">BTS</a>
+    </li>
+    <li>
+      <a href="hxttps://sources.debian.net/src/{{package}}/{{version}}/" title="Go to: the package source!">sources</a>
+      <ul class="children">
+        <li>
+          <div><a href="https://sources.debian.net/src/{{package}}/{{version}}/debian">debian/</a></div>
+          <div><a href="https://sources.debian.net/src/{{package}}/{{version}}/debian/changelog">debian/changelog</a></div>
+          <div><a href="https://sources.debian.net/src/{{package}}/{{version}}/debian/control">debian/control</a></div>
+          <div><a href="https://sources.debian.net/src/{{package}}/{{version}}/debian/rules">debian/rules</a></div>
+        </li>
+      </ul>
+    </li>
+  </ul>
+  <ul class="children">
+    <li><a href="{{dashboard_url}}">Debian dashboard</a></li>
+  </ul>
+{{{project_links_html}}}
+</header>
+<iframe id="main" name="main" tabindex="1" src="{{default_view}}">
+  <p>
+    Your browser does not support iframes.
+    Use a different one or follow the links above.
+  </p>
+</iframe>
diff --git a/bin/templates/package_suitearch_details.mustache b/bin/templates/package_suitearch_details.mustache
new file mode 100644
index 0000000..685d663
--- /dev/null
+++ b/bin/templates/package_suitearch_details.mustache
@@ -0,0 +1,36 @@
+<ul class="children">
+  <li>
+    {{{status_html}}}
+    {{#build_date}}
+    <div><span class="build-time">at {{build_date}}</span></div>
+    {{/build_date}}
+  </li>
+  {{#dbd}}
+  <li>
+    <div>
+      <a href="{{dbd_url}}" title="Show: formatted diffoscope results" target="main">differences</a>
+      {{#dbdtxt_url}}
+      <a href="{{dbdtxt_url}}" target="main">(txt)</a>
+      {{/dbdtxt_url}}
+    </div>
+  </li>
+  {{/dbd}}
+  {{#has_buildloginfo}}
+  <li>
+    {{#buildinfo_uri}}
+    <div>
+      <a href="{{buildinfo_uri}}" title="Show: build info" target="main">buildinfo</a>
+    </div>
+    {{/buildinfo_uri}}
+    <div>
+      {{#rbuild_uri}}
+      <a href="{{rbuild_uri}}" title="Show: log of first build (+some other stuff)" target="main">rbuild ({{rbuild_size}})</a>
+      {{/rbuild_uri}}
+      {{#buildlogs}}
+      <a href="{{build2_uri}}" title="Show: log of second build" target="main">build2 ({{build2_size}})</a>
+      <a href="{{diff_uri}}" title="Show: diff between the first and second builds" target="main">diff</a>
+      {{/buildlogs}}
+    </div>
+  </li>
+  {{/has_buildloginfo}}
+</ul>
diff --git a/bin/templates/package_suitearch_section.mustache b/bin/templates/package_suitearch_section.mustache
new file mode 100644
index 0000000..ed29ba8
--- /dev/null
+++ b/bin/templates/package_suitearch_section.mustache
@@ -0,0 +1,30 @@
+<ul>
+  {{#architectures}}
+  <li>
+    {{arch}}
+    <ul class="children">
+      {{#suites}}
+      <li class="{{li_classes}}">
+        {{^untested}}
+        <a href="/debian/{{arch}}/{{suite}}/index_{{status}}.html">
+          <img src="/static/{{icon}}" alt="{{spokenstatus}}" title="{{spokenstatus}}"/>
+        </a>
+        {{/untested}}
+        {{#untested}}
+        <img src="/static/{{icon}}" alt="{{spokenstatus}}" title="{{spokenstatus}}"/>
+        {{/untested}}
+        {{^current_suitearch}}
+        <a href="{{package_uri}}" target="_parent" title="{{spokenstatus}}: {{version}} on {{build_date}}">
+          {{version}}
+        </a> in <a href="/debian/{{suite}}/{{arch}}/" title="Go to: summary of all tests for {{arch}}/{{suite}}" target="_parent">{{suite}}</a>
+        {{/current_suitearch}}
+        {{#current_suitearch}}
+        {{version}} in <a href="/debian/{{suite}}/{{arch}}/" title="Go to: summary of all tests for {{arch}}/{{suite}}" target="_parent">{{suite}}</a>
+        {{/current_suitearch}}
+        {{{suitearch_details_html}}}
+      </li>
+      {{/suites}}
+    </ul>
+  </li>
+  {{/architectures}}
+</ul>
diff --git a/bin/templates/status_icon_link.mustache b/bin/templates/status_icon_link.mustache
new file mode 100644
index 0000000..2b866f7
--- /dev/null
+++ b/bin/templates/status_icon_link.mustache
@@ -0,0 +1,14 @@
+{{^untested}}
+{{#icon}}
+<a href="/debian/{{suite}}/{{arch}}/index_{{status}}.html" title="Go to: summary of all {{spokenstatus}} packages" target="_parent">
+  <img src="/static/{{icon}}" alt="{{spokenstatus}}">
+</a>
+{{/icon}}
+<a href="/debian/{{suite}}/{{arch}}/index_{{status}}.html" title="Go to: summary of all {{spokenstatus}} packages" target="_parent">
+  {{spokenstatus}}
+</a>
+{{/untested}}
+
+{{#untested}}
+{{#icon}}<img src="/static/{{icon}}" alt="{{spokenstatus}}">{{/icon}} {{spokenstatus}}
+{{/untested}}
diff --git a/update_jdn.sh b/update_jdn.sh
index 2c52ff7..3fa5559 100755
--- a/update_jdn.sh
+++ b/update_jdn.sh
@@ -328,6 +328,7 @@ if [ -f /etc/debian_version ] ; then
 				python3-debian 
 				python3-xdg
 				python3-yaml 
+				python3-pystache
 				python-arpy 
 				python-hachoir-metadata 
 				python-imaging 

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/qa/jenkins.debian.net.git



More information about the Qa-jenkins-scm mailing list