← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~jelmer/launchpad/update-bzr-hg into lp:launchpad

 

Jelmer Vernooij has proposed merging lp:~jelmer/launchpad/update-bzr-hg into lp:launchpad.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers): code
Related bugs:
  #599397 code imports break when tdb is installed
  https://bugs.launchpad.net/bugs/599397


This updates bzr-hg to a newer upstream revision, one that makes it use directories for caches rather than individual files. I've made matching changes to lp.codehosting to cope with the fact that the bzr-hg cache is now stored differently.

These changes make it possible to run the lp codehosting tests with success when python-tdb is installed. It should also make it easier to install python-tdb on the production machines later (there are some advantages to using python-tdb; it's quicker and allows multiple concurrent writers).
-- 
https://code.launchpad.net/~jelmer/launchpad/update-bzr-hg/+merge/32652
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~jelmer/launchpad/update-bzr-hg into lp:launchpad.
=== modified file 'database/schema/security.cfg'
--- database/schema/security.cfg	2010-08-10 05:49:16 +0000
+++ database/schema/security.cfg	2010-08-14 01:47:47 +0000
@@ -1053,7 +1053,10 @@
 
 [uploader]
 type=user
-groups=script
+groups=script,uploading
+
+[uploading]
+type=group
 # Everything is keyed off an archive
 public.archive                          = SELECT, INSERT, UPDATE
 public.archivearch                      = SELECT, INSERT, UPDATE

=== modified file 'lib/lp/app/templates/base-layout-macros.pt'
--- lib/lp/app/templates/base-layout-macros.pt	2010-08-03 11:18:34 +0000
+++ lib/lp/app/templates/base-layout-macros.pt	2010-08-14 01:47:47 +0000
@@ -231,6 +231,16 @@
             tal:attributes="src string:${lp_js}/translations/languages.js"></script>
     <script type="text/javascript"
             tal:attributes="src string:${lp_js}/translations/pofile.js"></script>
+
+    <script type="text/javascript"
+            tal:attributes="src string:${lp_js}/soyuz/archivesubscribers_index.js"></script>
+    <script type="text/javascript"
+            tal:attributes="src string:${lp_js}/soyuz/base.js"></script>
+    <script type="text/javascript"
+            tal:attributes="src string:${lp_js}/soyuz/lp_dynamic_dom_updater.js"></script>
+    <script type="text/javascript"
+            tal:attributes="src string:${lp_js}/soyuz/update_archive_build_statuses.js"></script>
+
     <script type="text/javascript"
             tal:attributes="src string:${lp_js}/bugs/filebug_dupefinder.js">
     </script>

=== modified file 'lib/lp/buildmaster/model/builder.py'
--- lib/lp/buildmaster/model/builder.py	2010-08-06 10:48:49 +0000
+++ lib/lp/buildmaster/model/builder.py	2010-08-14 01:47:47 +0000
@@ -12,6 +12,7 @@
     'updateBuilderStatus',
     ]
 
+import errno
 import httplib
 import gzip
 import logging
@@ -200,24 +201,38 @@
     if logger:
         logger.debug('Checking %s' % builder.name)
 
-    try:
-        builder.checkSlaveAlive()
-        builder.rescueIfLost(logger)
-    # Catch only known exceptions.
-    # XXX cprov 2007-06-15 bug=120571: ValueError & TypeError catching is
-    # disturbing in this context. We should spend sometime sanitizing the
-    # exceptions raised in the Builder API since we already started the
-    # main refactoring of this area.
-    except (ValueError, TypeError, xmlrpclib.Fault,
-            BuildDaemonError), reason:
-        builder.failBuilder(str(reason))
-        if logger:
-            logger.warn(
-                "%s (%s) marked as failed due to: %s",
-                builder.name, builder.url, builder.failnotes, exc_info=True)
-    except socket.error, reason:
-        error_message = str(reason)
-        builder.handleTimeout(logger, error_message)
+    MAX_EINTR_RETRIES = 42 # pulling a number out of my a$$ here
+    eintr_retry_count = 0
+
+    while True:
+        try:
+            builder.checkSlaveAlive()
+            builder.rescueIfLost(logger)
+        # Catch only known exceptions.
+        # XXX cprov 2007-06-15 bug=120571: ValueError & TypeError catching is
+        # disturbing in this context. We should spend sometime sanitizing the
+        # exceptions raised in the Builder API since we already started the
+        # main refactoring of this area.
+        except (ValueError, TypeError, xmlrpclib.Fault,
+                BuildDaemonError), reason:
+            builder.failBuilder(str(reason))
+            if logger:
+                logger.warn(
+                    "%s (%s) marked as failed due to: %s",
+                    builder.name, builder.url, builder.failnotes, exc_info=True)
+        except socket.error, reason:
+            # In Python 2.6 we can use IOError instead.  It also has
+            # reason.errno but we might be using 2.5 here so use the
+            # index hack.
+            if reason[0] == errno.EINTR:
+                eintr_retry_count += 1
+                if eintr_retry_count != MAX_EINTR_RETRIES:
+                    continue
+            error_message = str(reason)
+            builder.handleTimeout(logger, error_message)
+            return
+        else:
+            return
 
 
 class Builder(SQLBase):

=== modified file 'lib/lp/buildmaster/tests/test_builder.py'
--- lib/lp/buildmaster/tests/test_builder.py	2010-08-02 16:00:50 +0000
+++ lib/lp/buildmaster/tests/test_builder.py	2010-08-14 01:47:47 +0000
@@ -3,6 +3,9 @@
 
 """Test Builder features."""
 
+import errno
+import socket
+
 from zope.component import getUtility
 from zope.security.proxy import removeSecurityProxy
 
@@ -23,6 +26,7 @@
     BinaryPackageBuildBehavior)
 from lp.soyuz.tests.test_publishing import SoyuzTestPublisher
 from lp.testing import TestCaseWithFactory
+from lp.testing.fakemethod import FakeMethod
 
 
 class TestBuilder(TestCaseWithFactory):
@@ -43,6 +47,43 @@
         bq = builder.getBuildQueue()
         self.assertIs(None, bq)
 
+    def test_updateBuilderStatus_catches_repeated_EINTR(self):
+        # A single EINTR return from a socket operation should cause the
+        # operation to be retried, not fail/reset the builder.
+        builder = removeSecurityProxy(self.factory.makeBuilder())
+        builder.handleTimeout = FakeMethod()
+        builder.rescueIfLost = FakeMethod()
+
+        def _fake_checkSlaveAlive():
+            # Raise an EINTR error for all invocations.
+            raise socket.error(errno.EINTR, "fake eintr")
+
+        builder.checkSlaveAlive = _fake_checkSlaveAlive
+        builder.updateStatus()
+
+        # builder.updateStatus should eventually have called
+        # handleTimeout()
+        self.assertEqual(1, builder.handleTimeout.call_count)
+
+    def test_updateBuilderStatus_catches_single_EINTR(self):
+        builder = removeSecurityProxy(self.factory.makeBuilder())
+        builder.handleTimeout = FakeMethod()
+        builder.rescueIfLost = FakeMethod()
+        self.eintr_returned = False
+
+        def _fake_checkSlaveAlive():
+            # raise an EINTR error for the first invocation only.
+            if not self.eintr_returned:
+                self.eintr_returned = True
+                raise socket.error(errno.EINTR, "fake eintr")
+
+        builder.checkSlaveAlive = _fake_checkSlaveAlive
+        builder.updateStatus()
+
+        # builder.updateStatus should never call handleTimeout() for a
+        # single EINTR.
+        self.assertEqual(0, builder.handleTimeout.call_count)
+
 
 class TestFindBuildCandidateBase(TestCaseWithFactory):
     """Setup the test publisher and some builders."""

=== modified file 'lib/lp/codehosting/codeimport/worker.py'
--- lib/lp/codehosting/codeimport/worker.py	2010-04-28 23:33:48 +0000
+++ lib/lp/codehosting/codeimport/worker.py	2010-08-14 01:47:47 +0000
@@ -650,8 +650,6 @@
     The only behaviour we add is preserving the id-sha map between runs.
     """
 
-    db_file = 'hg-v2.db'
-
     @property
     def format_classes(self):
         """See `PullingImportWorker.opening_format`."""
@@ -667,8 +665,17 @@
         it in the Bazaar tree, that is at '.bzr/repository/hg-v2.db'.
         """
         branch = PullingImportWorker.getBazaarBranch(self)
+        # Fetch the legacy cache from the store, if present.
         self.import_data_store.fetch(
-            self.db_file, branch.repository._transport)
+            'hg-v2.db', branch.repository._transport)
+        # The cache dir from newer bzr-hgs is stored as a tarball.
+        local_name = 'hg-cache.tar.gz'
+        if self.import_data_store.fetch(local_name):
+            repo_transport = branch.repository._transport
+            repo_transport.mkdir('hg')
+            hg_db_dir = os.path.join(
+                local_path_from_url(repo_transport.base), 'hg')
+            extract_tarball(local_name, hg_db_dir)
         return branch
 
     def pushBazaarBranch(self, bazaar_branch):
@@ -680,8 +687,11 @@
         """
         non_trivial = PullingImportWorker.pushBazaarBranch(
             self, bazaar_branch)
-        self.import_data_store.put(
-            self.db_file, bazaar_branch.repository._transport)
+        repo_base = bazaar_branch.repository._transport.base
+        hg_db_dir = os.path.join(local_path_from_url(repo_base), 'hg')
+        local_name = 'hg-cache.tar.gz'
+        create_tarball(hg_db_dir, local_name)
+        self.import_data_store.put(local_name)
         return non_trivial
 
 

=== renamed directory 'lib/canonical/launchpad/javascript/soyuz' => 'lib/lp/soyuz/javascript'
=== modified file 'lib/lp/soyuz/javascript/archivesubscribers_index.js'
--- lib/canonical/launchpad/javascript/soyuz/archivesubscribers_index.js	2009-11-24 09:30:01 +0000
+++ lib/lp/soyuz/javascript/archivesubscribers_index.js	2010-08-14 01:47:47 +0000
@@ -3,19 +3,20 @@
  *
  * Enhancements for adding ppa subscribers.
  *
- * @module ArchiveSubscribersIndex
+ * @module soyuz
+ * @submodule archivesubscribers_index
  * @requires  event, node, oop
  */
-YUI.add('soyuz.archivesubscribers_index', function(Y) {
+YUI.add('lp.soyuz.archivesubscribers_index', function(Y) {
 
-var soyuz = Y.namespace('soyuz');
+var namespace = Y.namespace('lp.soyuz.archivesubscribers_index');
 
 /*
  * Setup the style and click handler for the add subscriber link.
  *
  * @method setup_archivesubscribers_index
  */
-Y.soyuz.setup_archivesubscribers_index = function() {
+namespace.setup_archivesubscribers_index = function() {
     // If there are no errors then we hide the add-subscriber row and
     // potentially the whole table if there are no subscribers.
     if (Y.Lang.isNull(Y.one('p.error.message'))) {

=== modified file 'lib/lp/soyuz/javascript/base.js'
--- lib/canonical/launchpad/javascript/soyuz/base.js	2009-11-23 19:29:02 +0000
+++ lib/lp/soyuz/javascript/base.js	2010-08-14 01:47:47 +0000
@@ -4,24 +4,21 @@
  * Auxiliary functions used in Soyuz pages
  *
  * @module soyuz
- * @submodule soyuz-base
+ * @submodule base
  * @namespace soyuz
  * @requires yahoo, node
  */
 
-YUI.add('soyuz-base', function(Y) {
+YUI.add('lp.soyuz.base', function(Y) {
 
-/*
- * Define the 'Y.soyuz' namespace
- */
-var soyuz = Y.namespace('soyuz');
+var namespace = Y.namespace('lp.soyuz.base');
 
 
 /*
  * Return a node containing a standard failure message to be used
  * in XHR-based page updates.
  */
-soyuz.makeFailureNode = function (text, handler) {
+namespace.makeFailureNode = function (text, handler) {
     var failure_message = Y.Node.create('<p>');
     failure_message.addClass('update-failure-message');
 
@@ -44,7 +41,7 @@
  * Return a node containing a standard in-progress message to be used
  * in XHR-based page updates.
  */
-soyuz.makeInProgressNode = function (text) {
+namespace.makeInProgressNode = function (text) {
     var in_progress_message = Y.Node.create('<p>');
     var message = Y.Node.create('<span>');
 

=== modified file 'lib/lp/soyuz/javascript/lp_dynamic_dom_updater.js'
--- lib/canonical/launchpad/javascript/soyuz/lp_dynamic_dom_updater.js	2009-11-24 16:11:43 +0000
+++ lib/lp/soyuz/javascript/lp_dynamic_dom_updater.js	2010-08-14 01:47:47 +0000
@@ -5,16 +5,16 @@
  * can be plugged in to a DOM subtree, so that the subtree can update itself
  * regularly using the Launchpad API.
  *
- * @module DynamicDomUpdater
+ * @module soyuz
+ * @submodule dynamic_dom_updater
  * @requires yahoo, node, plugin, LP
  */
-YUI.add('soyuz.dynamic_dom_updater', function(Y) {
+YUI.add('lp.soyuz.dynamic_dom_updater', function(Y) {
 
-/* Ensure that the Y.lp namespace exists. */
-var lp = Y.namespace('lp');
+var namespace = Y.namespace('lp.soyuz.dynamic_dom_updater');
 
     /**
-     * The DomUpdater class provides the ability to plugin functionality 
+     * The DomUpdater class provides the ability to plugin functionality
      * to a DOM subtree so that it can update itself when given data in an
      * expected format.
      *
@@ -74,12 +74,12 @@
     });
 
     /*
-     * Ensure that the DomUpdater is available within the Y.lp namespace.
+     * Ensure that the DomUpdater is available within the namespace.
      */
-    Y.lp.DomUpdater = DomUpdater;
+    namespace.DomUpdater = DomUpdater;
 
     /**
-     * The DynamicDomUpdater class provides the ability to plug functionality 
+     * The DynamicDomUpdater class provides the ability to plug functionality
      * into a DOM subtree so that it can update itself using an LP api method.
      *
      * For example:
@@ -94,7 +94,7 @@
      * Once configured, the 'table' dom subtree will now update itself
      * by calling the user defined domUpdateFunction (with a default interval
      * of 6000ms) with the result of the LPs api call.
-     * 
+     *
      * @class DynamicDomUpdater
      * @extends DomUpdater
      * @constructor
@@ -326,7 +326,7 @@
             }
 
             if (actual_interval_updated) {
-                Y.log("Actual poll interval updated to " + 
+                Y.log("Actual poll interval updated to " +
                     this._actual_interval + "ms.");
             }
 
@@ -350,9 +350,8 @@
     });
 
     /*
-     * Ensure that the DynamicDomUpdater is available within the Y.lp
-     * namespace.
+     * Ensure that the DynamicDomUpdater is available within the namespace.
      */
-    Y.lp.DynamicDomUpdater = DynamicDomUpdater;
+    namespace.DynamicDomUpdater = DynamicDomUpdater;
 
 }, "0.1", {"requires":["node", "plugin"]});

=== modified file 'lib/lp/soyuz/javascript/tests/archivesubscribers_index.js'
--- lib/canonical/launchpad/javascript/soyuz/tests/archivesubscribers_index.js	2010-07-26 13:42:32 +0000
+++ lib/lp/soyuz/javascript/tests/archivesubscribers_index.js	2010-08-14 01:47:47 +0000
@@ -2,11 +2,11 @@
    GNU Affero General Public License version 3 (see the file LICENSE). */
 
 YUI({
-    base: '../../../icing/yui/',
+    base: '../../../../canonical/launchpad/icing/yui/',
     filter: 'raw',
     combine: false
     }).use(
-        'test', 'console', 'soyuz.archivesubscribers_index', function(Y) {
+        'test', 'console', 'lp.soyuz.archivesubscribers_index', function(Y) {
 
 var Assert = Y.Assert;  // For easy access to isTrue(), etc.
 
@@ -68,7 +68,7 @@
 
     test_add_row_hidden_after_setup: function() {
         // The add subscriber row is hidden during setup.
-        Y.soyuz.setup_archivesubscribers_index();
+        Y.lp.soyuz.archivesubscribers_index.setup_archivesubscribers_index();
         Assert.areEqual(
             'none', this.add_subscriber_row.getStyle('display'),
             'The add subscriber row should be hidden during setup.');
@@ -76,7 +76,7 @@
 
     test_subscribers_section_displayed_after_setup: function() {
         // The subscribers div normally remains displayed after setup.
-        Y.soyuz.setup_archivesubscribers_index();
+        Y.lp.soyuz.archivesubscribers_index.setup_archivesubscribers_index();
         Assert.areEqual(
             'block', this.subscribers_div.getStyle('display'),
             'The subscribers div should remain displayed after setup.');
@@ -87,7 +87,7 @@
 
         // Add a paragraph with the no-subscribers id.
         this.error_div.set('innerHTML', '<p id="no-subscribers">blah</p>');
-        Y.soyuz.setup_archivesubscribers_index();
+        Y.lp.soyuz.archivesubscribers_index.setup_archivesubscribers_index();
         Assert.areEqual(
             'none', this.subscribers_div.getStyle('display'),
             'The subscribers div should be hidden when there are ' +
@@ -100,7 +100,7 @@
 
         // Add an error paragraph.
         this.error_div.set('innerHTML', '<p class="error message">Blah</p>');
-        Y.soyuz.setup_archivesubscribers_index();
+        Y.lp.soyuz.archivesubscribers_index.setup_archivesubscribers_index();
         Assert.areEqual(
             'table-row', this.add_subscriber_row.getStyle('display'),
             'The add subscriber row should not be hidden if there are ' +
@@ -110,7 +110,7 @@
     test_add_access_link_added_after_setup: function() {
         // The 'Add access' link is created during setup.
 
-        Y.soyuz.setup_archivesubscribers_index();
+        Y.lp.soyuz.archivesubscribers_index.setup_archivesubscribers_index();
         Assert.areEqual(
             '<a class="js-action sprite add" href="#">Add access</a>',
             this.add_subscriber_placeholder.get('innerHTML'),
@@ -119,7 +119,7 @@
 
     test_click_add_access_displays_add_row: function() {
         // The add subscriber row is displayed after clicking 'Add access'.
-        Y.soyuz.setup_archivesubscribers_index();
+        Y.lp.soyuz.archivesubscribers_index.setup_archivesubscribers_index();
         var link_node = this.add_subscriber_placeholder.one('a');
         Assert.areEqual(
             'Add access', link_node.get('innerHTML'));
@@ -133,6 +133,11 @@
     }
 }));
 
+Y.Test.Runner.on('complete', function(data) {
+    status_node = Y.Node.create(
+        '<p id="complete">Test status: complete</p>');
+    Y.get('body').appendChild(status_node);
+});
 Y.Test.Runner.add(suite);
 
 var yconsole = new Y.Console({

=== modified file 'lib/lp/soyuz/javascript/tests/lp_dynamic_dom_updater.js'
--- lib/canonical/launchpad/javascript/soyuz/tests/lp_dynamic_dom_updater.js	2010-07-26 13:42:32 +0000
+++ lib/lp/soyuz/javascript/tests/lp_dynamic_dom_updater.js	2010-08-14 01:47:47 +0000
@@ -2,10 +2,10 @@
    GNU Affero General Public License version 3 (see the file LICENSE). */
 
 YUI({
-    base: '../../../icing/yui/',
+    base: '../../../../canonical/launchpad/icing/yui/',
     filter: 'raw',
     combine: false
-    }).use('test', 'console', 'soyuz.dynamic_dom_updater', function(Y) {
+    }).use('test', 'console', 'lp.soyuz.dynamic_dom_updater', function(Y) {
 
 var Assert = Y.Assert;  // For easy access to isTrue(), etc.
 
@@ -31,14 +31,15 @@
             this.eg_div.updater,
             "Sanity check: initially there is no updater attribute.");
 
-        this.eg_div.plug(Y.lp.DomUpdater, this.config);
+        this.eg_div.plug(
+            Y.lp.soyuz.dynamic_dom_updater.DomUpdater, this.config);
 
         Assert.isNotUndefined(
             this.eg_div.updater,
             "After plugging, the object has an 'updater' attribute.");
 
         Assert.isInstanceOf(
-            Y.lp.DomUpdater,
+            Y.lp.soyuz.dynamic_dom_updater.DomUpdater,
             this.eg_div.updater,
             "DomUpdater was not plugged correctly.");
     },
@@ -52,7 +53,8 @@
             "Sanity check that the innerHTML of our example div has not" +
                 "been modified.");
 
-        this.eg_div.plug(Y.lp.DomUpdater, this.config);
+        this.eg_div.plug(
+            Y.lp.soyuz.dynamic_dom_updater.DomUpdater, this.config);
         this.eg_div.updater.update({msg: "Boo. I've changed."});
         Assert.areEqual(
             "Boo. I've changed.",
@@ -97,14 +99,15 @@
             this.eg_div.updater,
             "Sanity check: initially there is no updater attribute.");
 
-        this.eg_div.plug(Y.lp.DynamicDomUpdater, this.config);
+        this.eg_div.plug(
+            Y.lp.soyuz.dynamic_dom_updater.DynamicDomUpdater, this.config);
 
         Assert.isNotUndefined(
             this.eg_div.updater,
             "After plugging, the object has an 'updater' attribute.");
 
         Assert.isInstanceOf(
-            Y.lp.DynamicDomUpdater,
+            Y.lp.soyuz.dynamic_dom_updater.DynamicDomUpdater,
             this.eg_div.updater,
             "DynamicDomUpdater was not plugged correctly.");
     },
@@ -113,7 +116,8 @@
         // Requests to the LP API should only be re-issued if a successful
         // response was received previously.
 
-        this.eg_div.plug(Y.lp.DynamicDomUpdater, this.config);
+        this.eg_div.plug(
+            Y.lp.soyuz.dynamic_dom_updater.DynamicDomUpdater, this.config);
 
         // Verify that our expectation of only one named_get was met:
         this.wait(function() {
@@ -132,7 +136,8 @@
             callCount: 2
         });
 
-        this.eg_div.plug(Y.lp.DynamicDomUpdater, this.config);
+        this.eg_div.plug(
+            Y.lp.soyuz.dynamic_dom_updater.DynamicDomUpdater, this.config);
 
         // Wait 5ms just to ensure that the DynamicDomUpdater finishes
         // its initialization.
@@ -151,7 +156,8 @@
         // The actual polling interval is doubled if the elapsed time
         // for the previous request was greater than the
         // long_processing_time attribute.
-        this.eg_div.plug(Y.lp.DynamicDomUpdater, this.config);
+        this.eg_div.plug(
+            Y.lp.soyuz.dynamic_dom_updater.DynamicDomUpdater, this.config);
 
         // Wait 5ms just to ensure that the DynamicDomUpdater finishes
         // its initialization.
@@ -175,7 +181,8 @@
         // The actual polling interval remains unchanged if the elapsed time
         // for the previous request was within the short/long processing
         // times.
-        this.eg_div.plug(Y.lp.DynamicDomUpdater, this.config);
+        this.eg_div.plug(
+            Y.lp.soyuz.dynamic_dom_updater.DynamicDomUpdater, this.config);
 
         // Wait 5ms just to ensure that the DynamicDomUpdater finishes
         // its initialization.
@@ -200,7 +207,8 @@
         // The actual polling interval is halved if the elapsed time
         // for the previous request was less than the short_processing_time
 
-        this.eg_div.plug(Y.lp.DynamicDomUpdater, this.config);
+        this.eg_div.plug(
+            Y.lp.soyuz.dynamic_dom_updater.DynamicDomUpdater, this.config);
 
         // Wait 5ms just to ensure that the DynamicDomUpdater finishes
         // its initialization.
@@ -220,7 +228,8 @@
             Assert.areEqual(
                 8,
                 this.eg_div.updater._actual_interval,
-                "Poll interval is halved if request is faster than expected.");
+                "Poll interval is halved if request is faster than " +
+                "expected.");
 
         }, 5);
     },
@@ -229,7 +238,8 @@
         // Even if the processing time is quick, the actual interval
         // is never smaller than the interval set in the configuration.
 
-        this.eg_div.plug(Y.lp.DynamicDomUpdater, this.config);
+        this.eg_div.plug(
+            Y.lp.soyuz.dynamic_dom_updater.DynamicDomUpdater, this.config);
 
         // Wait 5ms just to ensure that the DynamicDomUpdater finishes
         // its initialization.
@@ -259,6 +269,11 @@
 
 }));
 
+    Y.Test.Runner.on('complete', function(data) {
+        status_node = Y.Node.create(
+            '<p id="complete">Test status: complete</p>');
+        Y.get('body').appendChild(status_node);
+    });
     Y.Test.Runner.add(suite);
 
     var yconsole = new Y.Console({

=== renamed file 'lib/canonical/launchpad/javascript/soyuz/tests/archivesubscribers_index.html' => 'lib/lp/soyuz/javascript/tests/test_archivesubscribers_index.html'
--- lib/canonical/launchpad/javascript/soyuz/tests/archivesubscribers_index.html	2010-07-26 13:42:32 +0000
+++ lib/lp/soyuz/javascript/tests/test_archivesubscribers_index.html	2010-08-14 01:47:47 +0000
@@ -4,11 +4,11 @@
   <title>Launchpad ArchiveSubscriberIndex</title>
 
   <!-- YUI 3.0 Setup -->
-  <script type="text/javascript" src="../../../icing/yui/yui/yui.js"></script>
-  <link rel="stylesheet" href="../../../icing/yui/cssreset/reset.css"/>
-  <link rel="stylesheet" href="../../../icing/yui/cssfonts/fonts.css"/>
-  <link rel="stylesheet" href="../../../icing/yui/cssbase/base.css"/>
-  <link rel="stylesheet" href="../../test.css" />
+  <script type="text/javascript" src="../../../../canonical/launchpad/icing/yui/yui/yui.js"></script>
+  <link rel="stylesheet" href="../../../../canonical/launchpad/icing/yui/cssreset/reset.css"/>
+  <link rel="stylesheet" href="../../../../canonical/launchpad/icing/yui/cssfonts/fonts.css"/>
+  <link rel="stylesheet" href="../../../../canonical/launchpad/icing/yui/cssbase/base.css"/>
+  <link rel="stylesheet" href="../../../../canonical/launchpad/test.css" />
 
   <!-- The module under test -->
   <script type="text/javascript" src="../archivesubscribers_index.js"></script>

=== renamed file 'lib/canonical/launchpad/javascript/soyuz/tests/lp_dynamic_dom_updater.html' => 'lib/lp/soyuz/javascript/tests/test_lp_dynamic_dom_updater.html'
--- lib/canonical/launchpad/javascript/soyuz/tests/lp_dynamic_dom_updater.html	2010-07-26 13:42:32 +0000
+++ lib/lp/soyuz/javascript/tests/test_lp_dynamic_dom_updater.html	2010-08-14 01:47:47 +0000
@@ -4,11 +4,11 @@
   <title>Launchpad DynamicDomUpdater</title>
 
   <!-- YUI 3.0 Setup -->
-  <script type="text/javascript" src="../../../icing/yui/yui/yui.js"></script>
-  <link rel="stylesheet" href="../../../icing/yui/cssreset/reset.css"/>
-  <link rel="stylesheet" href="../../../icing/yui/cssfonts/fonts.css"/>
-  <link rel="stylesheet" href="../../../icing/yui/cssbase/base.css"/>
-  <link rel="stylesheet" href="../../test.css" />
+  <script type="text/javascript" src="../../../../canonical/launchpad/icing/yui/yui/yui.js"></script>
+  <link rel="stylesheet" href="../../../../canonical/launchpad/icing/yui/cssreset/reset.css"/>
+  <link rel="stylesheet" href="../../../../canonical/launchpad/icing/yui/cssfonts/fonts.css"/>
+  <link rel="stylesheet" href="../../../../canonical/launchpad/icing/yui/cssbase/base.css"/>
+  <link rel="stylesheet" href="../../../../canonical/launchpad/javascript/test.css" />
 
   <!-- The module under test -->
   <script type="text/javascript" src="../lp_dynamic_dom_updater.js"></script>

=== modified file 'lib/lp/soyuz/javascript/update_archive_build_statuses.js'
--- lib/canonical/launchpad/javascript/soyuz/update_archive_build_statuses.js	2009-11-24 09:30:01 +0000
+++ lib/lp/soyuz/javascript/update_archive_build_statuses.js	2010-08-14 01:47:47 +0000
@@ -11,7 +11,7 @@
  * The second is the Archive/PPA source package table, the configuration of
  * which is set in source_package_table_dynamic_update_config.
  */
-YUI.add('soyuz.update_archive_build_statuses', function(Y){
+YUI.add('lp.soyuz.update_archive_build_statuses', function(Y){
 
     /**
      * Create one Launchpad client to be used by both dynamic tables.
@@ -86,7 +86,7 @@
         var portlet = Y.one('div#build-status-summary');
         build_summary_portlet_dynamic_update_config.uri =
             LP.client.cache.context.self_link;
-        portlet.plug(Y.lp.DynamicDomUpdater,
+        portlet.plug(Y.lp.soyuz.dynamic_dom_updater.DynamicDomUpdater,
                    build_summary_portlet_dynamic_update_config);
     });
 
@@ -110,8 +110,8 @@
         domUpdateFunction: function(table_node, data_object){
             // For each source id in the data object:
             Y.each(data_object, function(build_summary, source_id){
-                // Grab the related td element (and fail silently if it doesn't
-                // exist).
+                // Grab the related td element (and fail silently if it
+                // doesn't exist).
                 var td_elem = Y.one("#pubstatus" + source_id);
                 if (td_elem === null) {
                     return;
@@ -221,12 +221,13 @@
          * @config parameterEvaluatorFunction
          */
         parameterEvaluatorFunction: function(table_node){
-            // Grab all the td's with the class 'build_status' and an additional
-            // class of either 'NEEDSBUILD' or 'BUILDING':
+            // Grab all the td's with the class 'build_status' and an
+            // additional class of either 'NEEDSBUILD' or 'BUILDING':
             var td_list = table_node.all('td.build_status');
             var tds_needsbuild = td_list.filter(".NEEDSBUILD");
             var tds_building = td_list.filter(".BUILDING");
-            var tds_fullybuilt_pending = td_list.filter(".FULLYBUILT_PENDING");
+            var tds_fullybuilt_pending = td_list.filter(
+                ".FULLYBUILT_PENDING");
 
             if (tds_needsbuild.size() === 0 &&
                 tds_building.size() === 0 &&
@@ -275,8 +276,9 @@
         if (table !== null) {
            source_package_table_dynamic_update_config.uri =
                 LP.client.cache.context.self_link;
-            table.plug(Y.lp.DynamicDomUpdater,
+            table.plug(Y.lp.soyuz.dynamic_dom_updater.DynamicDomUpdater,
                        source_package_table_dynamic_update_config);
         }
     });
-}, "0.1", {"requires":["node", "lazr.anim", "anim", "soyuz.dynamic_dom_updater"]});
+}, "0.1", {"requires":[
+    "node", "lazr.anim", "anim", "lp.soyuz.dynamic_dom_updater"]});

=== modified file 'lib/lp/soyuz/stories/ppa/xx-private-ppa-subscriptions.txt'
--- lib/lp/soyuz/stories/ppa/xx-private-ppa-subscriptions.txt	2010-07-14 14:58:30 +0000
+++ lib/lp/soyuz/stories/ppa/xx-private-ppa-subscriptions.txt	2010-08-14 01:47:47 +0000
@@ -56,7 +56,6 @@
     ...
     http://launchpad.dev/+icing/.../build/app/calendar.js
     http://launchpad.dev/+icing/.../yui_2.7.0b/build/calendar/assets/skins/sam/calendar.css
-    ...
 
 Initially there are no subscriptions for a newly privatized PPA (although,
 this may need to change, to add the owner/team). A heading is displayed

=== modified file 'lib/lp/soyuz/templates/archive-packages.pt'
--- lib/lp/soyuz/templates/archive-packages.pt	2010-03-24 16:54:56 +0000
+++ lib/lp/soyuz/templates/archive-packages.pt	2010-08-14 01:47:47 +0000
@@ -8,23 +8,10 @@
   >
 <body>
     <metal:block fill-slot="head_epilogue">
-      <tal:devmode condition="devmode">
-        <tal:archive_js define="lp_js string:${icingroot}/build">
-          <script type="text/javascript"
-                  tal:attributes="src string:${lp_js}/soyuz/base.js">
-          </script>
-          <script type="text/javascript"
-                  tal:attributes="src string:${lp_js}/soyuz/lp_dynamic_dom_updater.js">
-          </script>
-          <script type="text/javascript"
-                  tal:attributes="src string:${lp_js}/soyuz/update_archive_build_statuses.js">
-          </script>
-        </tal:archive_js>
-      </tal:devmode>
       <script type="text/javascript" id="repository-size-update"
               tal:condition="view/archive_url">
-LPS.use('io-base', 'lazr.anim', 'node', 'soyuz-base',
-          'soyuz.update_archive_build_statuses', function(Y) {
+LPS.use('io-base', 'lazr.anim', 'node', 'lp.soyuz.base',
+          'lp.soyuz.update_archive_build_statuses', function(Y) {
 
 
 /*
@@ -45,7 +32,7 @@
         dispatchUpdate();
     };
 
-    var failure_message = Y.soyuz.makeFailureNode(
+    var failure_message = Y.lp.soyuz.base.makeFailureNode(
         'Failed to fetch repository size ...', retry_handler);
 
     args.container.set('innerHTML', '');
@@ -62,7 +49,7 @@
  * Communicate an update is in progress and fire the XHR.
  */
 function dispatchUpdate () {
-    in_progress_message = Y.soyuz.makeInProgressNode(
+    in_progress_message = Y.lp.soyuz.base.makeInProgressNode(
         'Fetching repository size ...')
 
     var container = Y.one('#package-counters');

=== modified file 'lib/lp/soyuz/templates/archive-subscribers.pt'
--- lib/lp/soyuz/templates/archive-subscribers.pt	2009-12-03 18:33:22 +0000
+++ lib/lp/soyuz/templates/archive-subscribers.pt	2010-08-14 01:47:47 +0000
@@ -10,11 +10,6 @@
   <metal:block fill-slot="head_epilogue">
     <metal:yui-dependencies
       use-macro="context/@@launchpad_widget_macros/yui2calendar-dependencies" />
-
-    <tal:devmode condition="devmode">
-        <script type="text/javascript"
-                tal:attributes="src string:${lp_js}/soyuz/archivesubscribers_index.js"></script>
-    </tal:devmode>
   </metal:block>
 
   <div metal:fill-slot="main">
@@ -98,8 +93,8 @@
         </form>
       </div><!-- class="portlet" -->
       <script type="text/javascript" id="setup-archivesubscribers-index">
-          LPS.use('soyuz.archivesubscribers_index', function(Y) {
-              Y.soyuz.setup_archivesubscribers_index();
+          LPS.use('lp.soyuz.archivesubscribers_index', function(Y) {
+              Y.lp.soyuz.archivesubscribers_index.setup_archivesubscribers_index();
           });
       </script>
     </div>

=== added file 'lib/lp/soyuz/windmill/tests/test_yuitests.py'
--- lib/lp/soyuz/windmill/tests/test_yuitests.py	1970-01-01 00:00:00 +0000
+++ lib/lp/soyuz/windmill/tests/test_yuitests.py	2010-08-14 01:47:47 +0000
@@ -0,0 +1,21 @@
+# Copyright 2010 Canonical Ltd.  This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+"""Run YUI.test tests."""
+
+__metaclass__ = type
+__all__ = []
+
+from lp.testing import build_yui_unittest_suite, YUIUnitTestCase
+from lp.soyuz.windmill.testing import SoyuzWindmillLayer
+
+
+class SoyuzYUIUnitTestCase(YUIUnitTestCase):
+
+    layer = SoyuzWindmillLayer
+    suite_name = 'SoyuzYUIUnitTests'
+
+
+def test_suite():
+    app_testing_path = 'lp/soyuz/javascript/tests'
+    return build_yui_unittest_suite(app_testing_path, SoyuzYUIUnitTestCase)

=== modified file 'utilities/lp-deps.py'
--- utilities/lp-deps.py	2010-07-16 16:14:39 +0000
+++ utilities/lp-deps.py	2010-08-14 01:47:47 +0000
@@ -25,6 +25,7 @@
     (os.path.join('lib', 'lp', 'code', 'javascript'), 'code'),
     (os.path.join('lib', 'lp', 'registry', 'javascript'), 'registry'),
     (os.path.join('lib', 'lp', 'translations', 'javascript'), 'translations'),
+    (os.path.join('lib', 'lp', 'soyuz', 'javascript'), 'soyuz'),
     ]
 ICING_ROOT = os.path.join(TOP, 'lib', 'canonical', 'launchpad', 'icing')
 ICING_BUILD = os.path.join(ICING_ROOT, 'build')

=== modified file 'utilities/sourcedeps.conf'
--- utilities/sourcedeps.conf	2010-08-04 11:34:32 +0000
+++ utilities/sourcedeps.conf	2010-08-14 01:47:47 +0000
@@ -1,6 +1,6 @@
 bzr-builder lp:~launchpad-pqm/bzr-builder/trunk;revno=65
 bzr-git lp:~launchpad-pqm/bzr-git/devel;revno=257
-bzr-hg lp:~launchpad-pqm/bzr-hg/devel;revno=281
+bzr-hg lp:~launchpad-pqm/bzr-hg/devel;revno=282
 bzr-loom lp:~launchpad-pqm/bzr-loom/trunk;revno=47
 bzr-svn lp:~launchpad-pqm/bzr-svn/devel;revno=2709
 cscvs lp:~launchpad-pqm/launchpad-cscvs/devel;revno=432