Merge lp:~mwhudson/launchpad/code-publisher-in-lp.code into lp:launchpad

Proposed by Michael Hudson-Doyle
Status: Merged
Approved by: Curtis Hovey
Approved revision: no longer in the source branch.
Merged at revision: 11196
Proposed branch: lp:~mwhudson/launchpad/code-publisher-in-lp.code
Merge into: lp:launchpad
Diff against target: 457 lines (+135/-43)
13 files modified
lib/canonical/configure.zcml (+2/-2)
lib/canonical/launchpad/doc/webapp-publication.txt (+1/-7)
lib/canonical/launchpad/layers.py (+0/-4)
lib/canonical/launchpad/webapp/meta.zcml (+7/-0)
lib/canonical/launchpad/webapp/metazcml.py (+20/-1)
lib/canonical/launchpad/webapp/servers.py (+0/-9)
lib/canonical/launchpad/zcml/marketing.zcml (+3/-3)
lib/lp/app/tests/test_help.py (+3/-1)
lib/lp/code/browser/configure.zcml (+14/-14)
lib/lp/code/configure.zcml (+5/-1)
lib/lp/code/publisher.py (+34/-0)
lib/lp/code/tests/test_publisher.py (+45/-0)
lib/lp/registry/browser/configure.zcml (+1/-1)
To merge this branch: bzr merge lp:~mwhudson/launchpad/code-publisher-in-lp.code
Reviewer Review Type Date Requested Status
Curtis Hovey (community) Approve
Review via email: mp+30124@code.launchpad.net

Commit message

Move the code-specific publication code into lp.code

Description of the change

Hi horsemen,

This branch moves the code-specific publication gubbins into lp.code. This was surprisingly easy!

The overriding of the zope:publisher ZCML to make priority optional is a bit odd, but it beats having to insert random values into the zcml imho. I also want to override this to make switching sites off possible based on config values later, so it's worth keeping the code to do that in here.

Cheers,
mwh

To post a comment you must log in.
Revision history for this message
Curtis Hovey (sinzui) wrote :

This looks good to land. I pondered the new metazcml directive. I think we need to dismantle webapp before we add some more to it.

review: Approve
Revision history for this message
Michael Hudson-Doyle (mwhudson) wrote :

Hi, can you look at this again? It failed tests so I made a few more changes.

I think we could eliminate some boilerplate by writing our own ZCML directive, how would something like

<lp:site
   name="code"
   web_service="true"
   request_class="lp.code.publisher.CodeLayer"/>

look to you?

Revision history for this message
Curtis Hovey (sinzui) wrote :

I like the suggestion. IT is not clear that site is a vhost. The directive could be vhost, but I think vhost="code" is most clear.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/canonical/configure.zcml'
2--- lib/canonical/configure.zcml 2010-07-15 15:57:40 +0000
3+++ lib/canonical/configure.zcml 2010-07-20 23:57:54 +0000
4@@ -99,14 +99,14 @@
5 <browser:defaultView
6 for="canonical.launchpad.interfaces.ILaunchpadRoot"
7 name="+code"
8- layer="canonical.launchpad.layers.CodeLayer"
9+ layer="lp.code.publisher.CodeLayer"
10 />
11 <browser:page
12 name=""
13 for="canonical.launchpad.interfaces.ILaunchpadRoot"
14 class="canonical.launchpad.browser.launchpad.LaunchpadImageFolder"
15 permission="zope.Public"
16- layer="canonical.launchpad.layers.CodeLayer"
17+ layer="lp.code.publisher.CodeLayer"
18 />
19
20 <!-- virtual host: translations -->
21
22=== modified file 'lib/canonical/launchpad/doc/webapp-publication.txt'
23--- lib/canonical/launchpad/doc/webapp-publication.txt 2010-03-02 03:22:01 +0000
24+++ lib/canonical/launchpad/doc/webapp-publication.txt 2010-07-20 23:57:54 +0000
25@@ -372,10 +372,6 @@
26 BugsBrowserRequest
27 BugsPublication
28
29- >>> print_request_and_publication('code.launchpad.dev')
30- CodeBrowserRequest
31- CodePublication
32-
33 >>> print_request_and_publication('feeds.launchpad.dev')
34 FeedsBrowserRequest
35 FeedsPublication
36@@ -417,7 +413,7 @@
37 WebServiceClientRequest
38 WebServicePublication
39 >>> for subdomain in [
40- ... 'answers', 'blueprints', 'bugs', 'code', 'translations']:
41+ ... 'answers', 'blueprints', 'bugs', 'translations']:
42 ... print_request_and_publication(
43 ... '%s.launchpad.dev' % subdomain, method='GET',
44 ... extra_environment={'PATH_INFO': '/api'})
45@@ -429,8 +425,6 @@
46 WebServicePublication
47 WebServiceClientRequest
48 WebServicePublication
49- WebServiceClientRequest
50- WebServicePublication
51
52 Requests for '/api' on other hosts like feeds are handled like
53 other requests on these hosts:
54
55=== modified file 'lib/canonical/launchpad/layers.py'
56--- lib/canonical/launchpad/layers.py 2009-12-25 22:36:11 +0000
57+++ lib/canonical/launchpad/layers.py 2010-07-20 23:57:54 +0000
58@@ -36,10 +36,6 @@
59 """The `BugsLayer` layer."""
60
61
62-class CodeLayer(LaunchpadLayer):
63- """The `CodeLayer` layer."""
64-
65-
66 class BlueprintLayer(LaunchpadLayer):
67 """The `BlueprintLayer` layer."""
68 BlueprintsLayer = BlueprintLayer
69
70=== modified file 'lib/canonical/launchpad/webapp/meta.zcml'
71--- lib/canonical/launchpad/webapp/meta.zcml 2009-07-13 18:15:02 +0000
72+++ lib/canonical/launchpad/webapp/meta.zcml 2010-07-20 23:57:54 +0000
73@@ -69,6 +69,13 @@
74 handler="canonical.launchpad.webapp.metazcml.authorizations"
75 />
76
77+ <directive
78+ namespace="http://namespaces.zope.org/zope"
79+ name="publisher"
80+ schema="canonical.launchpad.webapp.metazcml.ILaunchpadPublicationDirective"
81+ handler="canonical.launchpad.webapp.metazcml.launchpadPublisher"
82+ />
83+
84 <groupingDirective
85 namespace="http://namespaces.zope.org/zope"
86 name="facet"
87
88=== modified file 'lib/canonical/launchpad/webapp/metazcml.py'
89--- lib/canonical/launchpad/webapp/metazcml.py 2010-04-11 14:46:42 +0000
90+++ lib/canonical/launchpad/webapp/metazcml.py 2010-07-20 23:57:54 +0000
91@@ -10,6 +10,8 @@
92 import zope.configuration.config
93 from zope.app.file.image import Image
94 from zope.app.pagetemplate.engine import TrustedEngine
95+from zope.app.publication.metaconfigure import publisher
96+from zope.app.publication.metadirectives import IRequestPublicationDirective
97 from zope.component import getUtility
98 from zope.component.security import PublicPermission
99 from zope.component.zcml import adapter, handler, utility, view
100@@ -19,7 +21,7 @@
101 from zope.publisher.interfaces.browser import (
102 IBrowserPublisher, IBrowserRequest, IDefaultBrowserLayer)
103 from zope.publisher.interfaces.xmlrpc import IXMLRPCRequest
104-from zope.schema import TextLine
105+from zope.schema import Int, TextLine
106 from zope.security.checker import Checker, CheckerPublic
107 from zope.security.interfaces import IPermission
108 from zope.security.permission import Permission
109@@ -33,6 +35,7 @@
110 from z3c.ptcompat.zcml import page_directive as original_page
111 from z3c.ptcompat.zcml import pages_directive as original_pages
112
113+from canonical.config import config
114 from canonical.launchpad.layers import FeedsLayer
115 from canonical.launchpad.webapp.interfaces import (
116 IApplicationMenu, IAuthorization, ICanonicalUrlData, IContextMenu,
117@@ -651,3 +654,19 @@
118 description=''):
119 permission = LaunchpadPermission(id, title, access_level, description)
120 utility(_context, ILaunchpadPermission, permission, name=id)
121+
122+
123+class ILaunchpadPublicationDirective(IRequestPublicationDirective):
124+
125+ priorty = Int(required=False)
126+
127+_arbitrary_priority = 12
128+
129+
130+def launchpadPublisher(_context, name, factory, methods=['*'],
131+ mimetypes=['*'], priority=None):
132+ global _arbitrary_priority
133+ if priority is None:
134+ _arbitrary_priority += 1
135+ priority = _arbitrary_priority
136+ publisher(_context, name, factory, methods, mimetypes, priority)
137
138=== modified file 'lib/canonical/launchpad/webapp/servers.py'
139--- lib/canonical/launchpad/webapp/servers.py 2010-07-19 14:45:32 +0000
140+++ lib/canonical/launchpad/webapp/servers.py 2010-07-20 23:57:54 +0000
141@@ -1023,14 +1023,6 @@
142 class BlueprintPublication(LaunchpadBrowserPublication):
143 """The publication used for the Blueprint site."""
144
145-# ---- code
146-
147-class CodePublication(LaunchpadBrowserPublication):
148- """The publication used for the Code site."""
149-
150-class CodeBrowserRequest(LaunchpadBrowserRequest):
151- implements(canonical.launchpad.layers.CodeLayer)
152-
153 # ---- translations
154
155 class TranslationsPublication(LaunchpadBrowserPublication):
156@@ -1484,7 +1476,6 @@
157 VWSHRP('mainsite', LaunchpadBrowserRequest, MainLaunchpadPublication,
158 handle_default_host=True),
159 VWSHRP('blueprints', BlueprintBrowserRequest, BlueprintPublication),
160- VWSHRP('code', CodeBrowserRequest, CodePublication),
161 VWSHRP('translations', TranslationsBrowserRequest,
162 TranslationsPublication),
163 VWSHRP('bugs', BugsBrowserRequest, BugsPublication),
164
165=== modified file 'lib/canonical/launchpad/zcml/marketing.zcml'
166--- lib/canonical/launchpad/zcml/marketing.zcml 2009-07-13 18:15:02 +0000
167+++ lib/canonical/launchpad/zcml/marketing.zcml 2010-07-20 23:57:54 +0000
168@@ -95,14 +95,14 @@
169 <!-- Marketing material for Code. -->
170 <browser:renamed-page
171 for="canonical.launchpad.webapp.interfaces.ILaunchpadApplication"
172- layer="canonical.launchpad.layers.CodeLayer"
173+ layer="lp.code.publisher.CodeLayer"
174 name="+about"
175 new_name="+tour/branch-hosting-tracking"
176 rootsite="mainsite"
177 />
178 <browser:renamed-page
179 for="canonical.launchpad.webapp.interfaces.ILaunchpadApplication"
180- layer="canonical.launchpad.layers.CodeLayer"
181+ layer="lp.code.publisher.CodeLayer"
182 name="+faq"
183 new_name="+tour/branch-hosting-tracking"
184 rootsite="mainsite"
185@@ -110,7 +110,7 @@
186 <browser:renamed-page
187 name="+tour"
188 for="canonical.launchpad.webapp.interfaces.ILaunchpadApplication"
189- layer="canonical.launchpad.layers.CodeLayer"
190+ layer="lp.code.publisher.CodeLayer"
191 new_name="+tour/branch-hosting-tracking"
192 rootsite="mainsite"
193 />
194
195=== modified file 'lib/lp/app/tests/test_help.py'
196--- lib/lp/app/tests/test_help.py 2010-07-18 00:23:02 +0000
197+++ lib/lp/app/tests/test_help.py 2010-07-20 23:57:54 +0000
198@@ -11,13 +11,15 @@
199
200 from canonical.testing.layers import FunctionalLayer
201 from canonical.launchpad.layers import (
202- AnswersLayer, BlueprintsLayer, BugsLayer, CodeLayer, LaunchpadLayer,
203+ AnswersLayer, BlueprintsLayer, BugsLayer, LaunchpadLayer,
204 TranslationsLayer)
205 from canonical.launchpad.testing.systemdocs import create_view
206 from canonical.launchpad.webapp.interfaces import ILaunchpadApplication
207
208 from canonical.lazr.folder import ExportedFolder
209
210+from lp.code.publisher import CodeLayer
211+
212 # The root of the tree
213 ROOT = os.path.realpath(
214 os.path.join(
215
216=== modified file 'lib/lp/code/browser/configure.zcml'
217--- lib/lp/code/browser/configure.zcml 2010-07-14 10:09:35 +0000
218+++ lib/lp/code/browser/configure.zcml 2010-07-20 23:57:54 +0000
219@@ -18,11 +18,11 @@
220
221 <browser:defaultView
222 for="lp.registry.interfaces.product.IProductSet"
223- layer="canonical.launchpad.layers.CodeLayer"
224+ layer="lp.code.publisher.CodeLayer"
225 name="+project-cloud"/>
226 <browser:page
227 for="lp.registry.interfaces.product.IProductSet"
228- layer="canonical.launchpad.layers.CodeLayer"
229+ layer="lp.code.publisher.CodeLayer"
230 name="+project-cloud"
231 class="lp.code.browser.bazaar.BazaarProductView"
232 template="../templates/code-in-branches.pt"
233@@ -87,7 +87,7 @@
234 <browser:defaultView
235 for="lp.code.interfaces.codeimportmachine.ICodeImportMachine"
236 name="+index"
237- layer="canonical.launchpad.layers.CodeLayer"/>
238+ layer="lp.code.publisher.CodeLayer"/>
239 <browser:page
240 for="lp.code.interfaces.codeimportmachine.ICodeImportMachine"
241 class="lp.code.browser.codeimportmachine.CodeImportMachineView"
242@@ -109,7 +109,7 @@
243 <browser:defaultView
244 for="lp.code.interfaces.codeimportmachine.ICodeImportMachineSet"
245 name="+index"
246- layer="canonical.launchpad.layers.CodeLayer"/>
247+ layer="lp.code.publisher.CodeLayer"/>
248 <browser:page
249 for="lp.code.interfaces.codeimportmachine.ICodeImportMachineSet"
250 class="lp.code.browser.codeimportmachine.CodeImportMachineSetView"
251@@ -685,7 +685,7 @@
252 <browser:defaultView
253 for="lp.code.interfaces.codeimport.ICodeImportSet"
254 name="+index"
255- layer="canonical.launchpad.layers.CodeLayer"/>
256+ layer="lp.code.publisher.CodeLayer"/>
257 <browser:page
258 for="lp.code.interfaces.codeimport.ICodeImportSet"
259 class="lp.code.browser.codeimport.CodeImportSetView"
260@@ -717,7 +717,7 @@
261 <browser:defaultView
262 for="lp.registry.interfaces.projectgroup.IProjectGroup"
263 name="+branches"
264- layer="canonical.launchpad.layers.CodeLayer"/>
265+ layer="lp.code.publisher.CodeLayer"/>
266 <browser:page
267 for="lp.registry.interfaces.sourcepackage.ISourcePackage"
268 class="lp.code.browser.branchlisting.SourcePackageBranchesView"
269@@ -804,7 +804,7 @@
270 PersonBranchesMenu"/>
271 <browser:defaultView
272 for="lp.registry.interfaces.person.IPerson"
273- layer="canonical.launchpad.layers.CodeLayer"
274+ layer="lp.code.publisher.CodeLayer"
275 name="+branches"/>
276 <browser:page
277 for="lp.registry.interfaces.person.IPerson"
278@@ -914,22 +914,22 @@
279
280 <browser:defaultView
281 for="lp.registry.interfaces.sourcepackage.ISourcePackage"
282- layer="canonical.launchpad.layers.CodeLayer"
283+ layer="lp.code.publisher.CodeLayer"
284 name="+branches"/>
285
286 <browser:defaultView
287 for="lp.registry.interfaces.distributionsourcepackage.IDistributionSourcePackage"
288- layer="canonical.launchpad.layers.CodeLayer"
289+ layer="lp.code.publisher.CodeLayer"
290 name="+code-index"/>
291
292 <browser:defaultView
293 for="lp.registry.interfaces.distribution.IDistribution"
294- layer="canonical.launchpad.layers.CodeLayer"
295+ layer="lp.code.publisher.CodeLayer"
296 name="+branches"/>
297
298 <browser:defaultView
299 for="lp.registry.interfaces.distroseries.IDistroSeries"
300- layer="canonical.launchpad.layers.CodeLayer"
301+ layer="lp.code.publisher.CodeLayer"
302 name="+branches"/>
303
304 <browser:url
305@@ -956,7 +956,7 @@
306
307 <browser:defaultView
308 for="lp.registry.interfaces.personproduct.IPersonProduct"
309- layer="canonical.launchpad.layers.CodeLayer"
310+ layer="lp.code.publisher.CodeLayer"
311 name="+branches" />
312
313 <browser:page
314@@ -1099,7 +1099,7 @@
315 <browser:defaultView
316 for="lp.code.interfaces.sourcepackagerecipe.ISourcePackageRecipe"
317 name="+index"
318- layer="canonical.launchpad.layers.CodeLayer"/>
319+ layer="lp.code.publisher.CodeLayer"/>
320 <browser:page
321 for="lp.code.interfaces.sourcepackagerecipe.ISourcePackageRecipe"
322 class="lp.code.browser.sourcepackagerecipe.SourcePackageRecipeView"
323@@ -1117,7 +1117,7 @@
324 <browser:defaultView
325 for="lp.code.interfaces.sourcepackagerecipebuild.ISourcePackageRecipeBuild"
326 name="+index"
327- layer="canonical.launchpad.layers.CodeLayer"/>
328+ layer="lp.code.publisher.CodeLayer"/>
329 <browser:page
330 for="lp.code.interfaces.sourcepackagerecipebuild.ISourcePackageRecipeBuild"
331 class="lp.code.browser.sourcepackagerecipebuild.SourcePackageRecipeBuildView"
332
333=== modified file 'lib/lp/code/configure.zcml'
334--- lib/lp/code/configure.zcml 2010-06-16 18:18:32 +0000
335+++ lib/lp/code/configure.zcml 2010-07-20 23:57:54 +0000
336@@ -13,6 +13,10 @@
337 <include package=".browser"/>
338 <authorizations module="lp.code.security" />
339
340+ <publisher
341+ name="code"
342+ factory="lp.code.publisher.code_request_publication_factory"/>
343+
344 <!-- Branch Merge Queue -->
345
346 <class class="lp.code.model.branchmergequeue.SingleBranchMergeQueue">
347@@ -981,7 +985,7 @@
348 <adapter factory="lp.code.model.linkedbranch.DistributionPackageLinkedBranch" />
349
350 <lp:help-folder
351- folder="help" type="canonical.launchpad.layers.CodeLayer" />
352+ folder="help" type="lp.code.publisher.CodeLayer" />
353
354 <!-- Diffs -->
355 <class class="lp.code.model.diff.Diff">
356
357=== added file 'lib/lp/code/publisher.py'
358--- lib/lp/code/publisher.py 1970-01-01 00:00:00 +0000
359+++ lib/lp/code/publisher.py 2010-07-20 23:57:54 +0000
360@@ -0,0 +1,34 @@
361+# Copyright 2010 Canonical Ltd. This software is licensed under the
362+# GNU Affero General Public License version 3 (see the file LICENSE).
363+
364+"""Code's custom publication."""
365+
366+__metaclass__ = type
367+__all__ = [
368+ 'CodeBrowserRequest',
369+ 'CodeLayer',
370+ 'code_request_publication_factory',
371+ ]
372+
373+
374+from zope.interface import implements
375+from zope.publisher.interfaces.browser import (
376+ IBrowserRequest, IDefaultBrowserLayer)
377+
378+from canonical.launchpad.webapp.publication import LaunchpadBrowserPublication
379+from canonical.launchpad.webapp.servers import (
380+ LaunchpadBrowserRequest, VHostWebServiceRequestPublicationFactory)
381+
382+
383+class CodeLayer(IBrowserRequest, IDefaultBrowserLayer):
384+ """The Code layer."""
385+
386+
387+class CodeBrowserRequest(LaunchpadBrowserRequest):
388+ """Instances of CodeBrowserRequest provide `CodeLayer`."""
389+ implements(CodeLayer)
390+
391+
392+def code_request_publication_factory():
393+ return VHostWebServiceRequestPublicationFactory(
394+ 'code', CodeBrowserRequest, LaunchpadBrowserPublication)
395
396=== added file 'lib/lp/code/tests/test_publisher.py'
397--- lib/lp/code/tests/test_publisher.py 1970-01-01 00:00:00 +0000
398+++ lib/lp/code/tests/test_publisher.py 2010-07-20 23:57:54 +0000
399@@ -0,0 +1,45 @@
400+# Copyright 2010 Canonical Ltd. This software is licensed under the
401+# GNU Affero General Public License version 3 (see the file LICENSE).
402+
403+"""Tests for code's custom publications."""
404+
405+__metaclass__ = type
406+
407+import unittest
408+
409+from canonical.config import config
410+from canonical.launchpad.layers import WebServiceLayer
411+from canonical.testing.layers import FunctionalLayer
412+
413+from lp.testing import TestCase
414+from lp.testing.publication import get_request_and_publication
415+
416+from lp.code.publisher import CodeLayer
417+
418+
419+class TestRegistration(TestCase):
420+ """Code's publication customizations are installed correctly."""
421+
422+ layer = FunctionalLayer
423+
424+ def test_code_request_provides_code_layer(self):
425+ # The request constructed for requests to the code hostname provides
426+ # CodeLayer.
427+ request, publication = get_request_and_publication(
428+ host=config.vhost.code.hostname)
429+ self.assertProvides(request, CodeLayer)
430+
431+ def test_code_host_has_api(self):
432+ # Requests to /api on the code domain are treated as web service
433+ # requests.
434+ request, publication = get_request_and_publication(
435+ host=config.vhost.code.hostname,
436+ extra_environment={'PATH_INFO': '/api/1.0'})
437+ # XXX MichaelHudson, 2010-07-20, bug=607664: WebServiceLayer only
438+ # actually provides WebServiceLayer in the sense of verifyObject after
439+ # traversal has started.
440+ self.assertTrue(WebServiceLayer.providedBy(request))
441+
442+
443+def test_suite():
444+ return unittest.TestLoader().loadTestsFromName(__name__)
445
446=== modified file 'lib/lp/registry/browser/configure.zcml'
447--- lib/lp/registry/browser/configure.zcml 2010-05-27 04:10:17 +0000
448+++ lib/lp/registry/browser/configure.zcml 2010-07-20 23:57:54 +0000
449@@ -1357,7 +1357,7 @@
450 <browser:defaultView
451 for="lp.registry.interfaces.product.IProduct"
452 name="+code-index"
453- layer="canonical.launchpad.layers.CodeLayer"/>
454+ layer="lp.code.publisher.CodeLayer"/>
455 <browser:defaultView
456 for="lp.registry.interfaces.product.IProduct"
457 layer="canonical.launchpad.layers.AnswersLayer"