← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~jml/launchpad/what-is-in-the-web-ui into lp:launchpad

 

Jonathan Lange has proposed merging lp:~jml/launchpad/what-is-in-the-web-ui into lp:launchpad.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~jml/launchpad/what-is-in-the-web-ui/+merge/52594

I'd like to figure exactly what is in the web UI. We need to clean it up a fair bit, but there's so much there it's hard to tell where to start or what needs to be done.

One approach is to get a list of what "pages" we have, pages like the one you are looking at now. These pages can then be tied, perhaps, to features in the feature checklist or things in the strategy & scope document.

This script is my first attempt at an automated way of gathering that data.

Problem is, I don't really know anything about Zope, and I'm not really sure how pageids work, and well, I don't really know what I'm doing.

Pages like:
  https://code.launchpad.net/ubuntu/+source/openssh
are interesting,

Pages like:
  https://code.launchpad.net/ubuntu/+source/openssh/+count-summary
are not.

I guess I probably want to know what facets (remind me what they are again?) / subdomains a page is valid for.

Anyway, I'd appreciate any help in making this script useful / better / more correct. The XXX comments are a good starting place.

Thanks!
jml
-- 
https://code.launchpad.net/~jml/launchpad/what-is-in-the-web-ui/+merge/52594
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~jml/launchpad/what-is-in-the-web-ui into lp:launchpad.
=== added file 'utilities/list-pages'
--- utilities/list-pages	1970-01-01 00:00:00 +0000
+++ utilities/list-pages	2011-03-10 10:01:57 +0000
@@ -0,0 +1,140 @@
+#!/usr/bin/python -S
+#
+# Copyright 2011 Canonical Ltd.  This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+"""list-pages -- list the pages that are in Launchpad
+
+Prints out a CSV of all of the pages that exist in Launchpad. A "page" is a
+whole, actual, web page. Something you might actually want to see filling a
+browser window. Page fragments, portlets etc. are excluded.
+
+The output contains the page ID, content interface, layer and template.  Here
+'layer' is a clue as to the subdomain.
+"""
+
+# The implementation approach here is fairly simple:
+# - load the ZCML
+# - go through all of the adapters, find the ones that look like they might
+#   be for pages.
+# - bang the adapter nut against the hardest rock we can find until it cracks
+# - print the nourishing nutty goodness to stdout
+
+import _pythonpath
+
+from inspect import getmro
+import os
+from pprint import pformat, pprint
+
+from zope.app.pagetemplate.simpleviewclass import simple
+from zope.app.testing.functional import FunctionalTestSetup
+from zope.component import getGlobalSiteManager
+
+from zope.publisher.interfaces.browser import IDefaultBrowserLayer
+
+from canonical.launchpad import pagetitles
+from canonical.launchpad.scripts import execute_zcml_for_scripts
+from canonical.launchpad.webapp.interfaces import ICanonicalUrlData
+
+
+ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
+
+
+def load_zcml(zopeless=False):
+    """Load ZCML the way we do in our tests."""
+    if zopeless:
+        execute_zcml_for_scripts()
+    else:
+        FunctionalTestSetup(
+            os.path.join(ROOT, 'zcml', 'ftesting.zcml')).setUp()
+
+
+def is_page_adapter(adapter):
+    """Is 'adapter' a page adapter?
+
+    We figure this out by checking to see whether it is adapting from
+    IDefaultBrowserLayer or one of its subclasses.
+    """
+    for interface in adapter.required:
+        if issubclass(interface, IDefaultBrowserLayer):
+            return True
+    return False
+
+
+def get_view(adapter):
+    """Get the view factory associated with 'adapter'."""
+    return adapter.factory
+
+
+def get_template_filename(view):
+    """Return the template filename associated with 'view'."""
+    try:
+        filename = view.index.filename
+    except AttributeError:
+        return None
+    filename = os.path.abspath(filename)[len(ROOT)+1:]
+    return filename
+
+
+def has_page_title(adapter):
+    """Does 'adapter' have a page title?
+
+    We use this to tell if 'adapter' is indeed an adapter for rendering an
+    entire page. The theory goes that if there's a page title associated with
+    something, then it's a page.
+    """
+    view = get_view(adapter)
+    marker = object()
+    if getattr(view, 'page_title', marker) is not marker:
+        return True
+    template = get_template_filename(view)
+    if template is None:
+        return False
+    name = os.path.splitext(os.path.basename(template))[0].replace('-', '_')
+    return getattr(pagetitles, name, marker) is not marker
+
+
+def iter_page_adapters():
+    """Iterate over adapters for browser:page directives."""
+    gsm = getGlobalSiteManager()
+    return (a for a in gsm.registeredAdapters()
+            if is_page_adapter(a) and has_page_title(a))
+
+
+def format_page_adapter(a):
+    """Format the adapter 'a' for end-user display.
+
+    :return: A string of the form, "pageid,content,layer,template".
+    """
+    factory = a.factory
+    try:
+        bases = getmro(factory)
+    except AttributeError:
+        return a.name
+    # Zope, bless it, does all sorts of type shenanigans to obscure the name
+    # of the factory as it appears in our code. (See
+    # z.browserpage.metaconfigure.page and
+    # z.app.pagetemplate.simpleviewclass). Ideally, we'd just construct the
+    # view, but that's hard, since in general they won't construct without an
+    # object that implements the interface they need.
+    bases = [b for b in bases
+             if b is not simple
+             and 'SimpleViewClass' not in b.__name__]
+    template = get_template_filename(get_view(a))
+    return '%s:%s,%s,%s,%s' % (
+        bases[0].__name__,
+        a.name,
+        a.required[0].__name__,
+        a.required[1].__name__,
+        template)
+
+
+def main():
+    load_zcml()
+    gsm = getGlobalSiteManager()
+    for adapter in iter_page_adapters():
+        print format_page_adapter(adapter)
+
+
+if __name__ == '__main__':
+    main()


References