← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~rharding/launchpad/gallery-accordian_fix into lp:launchpad

 

Richard Harding has proposed merging lp:~rharding/launchpad/gallery-accordian_fix into lp:launchpad with lp:~rharding/launchpad/combo_yui_tests5 as a prerequisite.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~rharding/launchpad/gallery-accordian_fix/+merge/93406

= Summary =
Ignore the poor branch name. This started out as fixing gallery-accordion for the combo loader so that it can be served via the build/js directory. In the end, the goal was to wipe out contrib and find better homes for all of the code there.

== Proposed Fix ==
We've moved the accordion and mustache code into lib/lp/app. We then moved the google analytics to the icing directory and pull it in with the rest of the GA setup code in the base-layout instead. Finally, we moved the webfonts to the place it was originally symlinked from.

== Implementation Details ==
These changes required us to update tests to pull from the build location vs the contrib directory, but in the end, since things are pulled in via YUI.use(), it doesn't require any changes to the real JS blocks.


== Tests ==
lib/lp/app/javascript/tests/test_listing_navigator.html
lib/lp/bugs/javascript/tests/test_buglisting.html
lib/lp/registry/javascript/tests/test_structural_subscription.html

== Demo and Q/A ==
- The mustache templates when using the bug listings should still work fine
- The Google Analytics code should still load on each page load if you have the combo loader FF or not.
- You should still get the custom fonts css on every page load
- The structural subscriptions view should still be able to load the accordion code if you have the combo loader FF or not enabled.
-- 
https://code.launchpad.net/~rharding/launchpad/gallery-accordian_fix/+merge/93406
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~rharding/launchpad/gallery-accordian_fix into lp:launchpad.
=== modified file 'buildout-templates/bin/combine-css.in'
--- buildout-templates/bin/combine-css.in	2011-12-23 18:06:50 +0000
+++ buildout-templates/bin/combine-css.in	2012-02-16 14:03:30 +0000
@@ -11,10 +11,6 @@
 from lp.scripts.utilities.js.jsbuild import ComboFile
 from lp.scripts.utilities.js.combo import combine_files
 
-# This constant helps us meet maximum line-length goals.
-GALLERY_ACCORDION = 'yui3-gallery/gallery-accordion/assets/'
-
-
 root = os.path.abspath('.')
 root = os.path.normpath(${buildout:directory|path-repr})
 icing = os.path.join(root, 'lib/canonical/launchpad/icing')
@@ -42,8 +38,8 @@
     'build/activator/assets/skins/sam/activator.css',
     'build/choiceedit/assets/choiceedit-core.css',
     'build/ordering/assets/ordering-core.css',
-    GALLERY_ACCORDION + 'gallery-accordion-core.css',
-    GALLERY_ACCORDION + 'skins/sam/gallery-accordion-skin.css',
+    'build/gallery-accordion/assets/gallery-accordion-core.css',
+    'build/gallery-accordion/assets/skins/sam/gallery-accordion-skin.css',
     'build/sprite.css',
     # Include our main stylesheets at the end so they
     # take precedence over the others.

=== modified file 'buildout-templates/bin/combo-rootdir.in'
--- buildout-templates/bin/combo-rootdir.in	2012-02-15 03:54:32 +0000
+++ buildout-templates/bin/combo-rootdir.in	2012-02-16 14:03:30 +0000
@@ -33,8 +33,6 @@
 find $BUILD_DIR/lp -name 'tests' -type d | xargs rm -rf
 
 # We have to move some modules around.
-cp lib/lp/contrib/javascript/lp.mustache.js $BUILD_DIR/lp
-rm $BUILD_DIR/lp/contrib/mustache.js
 rm $BUILD_DIR/lp/app/worlddata
 cp lib/lp/services/worlddata/javascript/languages.js $BUILD_DIR/lp
 cp lib/lp/app/longpoll/javascript/longpoll.js $BUILD_DIR/lp

=== renamed directory 'lib/lp/contrib/javascript/google-analytics' => 'lib/canonical/launchpad/icing/google-analytics'
=== renamed file 'lib/lp/contrib/css/ubuntu-webfonts.css' => 'lib/canonical/launchpad/icing/ubuntu-webfonts.css'
=== removed symlink 'lib/canonical/launchpad/icing/ubuntu-webfonts.css'
=== target was u'../../../lp/contrib/css/ubuntu-webfonts.css'
=== renamed directory 'lib/lp/contrib/javascript/yui3-gallery/gallery-accordion' => 'lib/lp/app/javascript/gallery-accordion'
=== modified file 'lib/lp/app/javascript/indicator/tests/test_indicator.js'
--- lib/lp/app/javascript/indicator/tests/test_indicator.js	2012-02-16 14:03:28 +0000
+++ lib/lp/app/javascript/indicator/tests/test_indicator.js	2012-02-06 13:29:18 +0000
@@ -1,6 +1,5 @@
 /* Copyright (c) 2011, Canonical Ltd. All rights reserved. */
 
-<<<<<<< TREE
 YUI.add('lp.indicator.test', function (Y) {
     var tests = Y.namespace('lp.indicator.test');
     tests.suite = new Y.Test.Suite('Indicator Tests');
@@ -213,228 +212,8 @@
             this.indicator.render();
             this.indicator.error();
             Assert.isTrue(called);
-=======
-YUI.add('lp.indicator.test', function (Y) {
-
-var tests = Y.namespace('lp.indicator.test');
-tests.suite = new Y.Test.Suite('Indicator Tests');
-var Assert = Y.Assert;
-
-// add the suite to the NS for the testrunner.js to find
-tests.suite.add(new Y.Test.Case({
-
-    name: 'indicator_tests',
-
-    setUp: function () {
-        this.div = Y.Node.create('<div/>');
-        // Generate an id so we can keep these around as we work.
-        this.div.generateID();
-        // We want to store this for the testing of the target, after that we
-        // can just use this.div.
-        this.div_id = this.div.get('id');
-        Y.one('body').appendChild(this.div);
-    },
-
-    tearDown: function () {
-        // Delete the reference to this.div so we can recreate new ones for
-        // each test without worry.
-        this.div.remove();
-        delete this.div;
-        if (Y.Lang.isValue(this.indicator)) {
-            this.indicator.destroy();
->>>>>>> MERGE-SOURCE
         }
-<<<<<<< TREE
     }));
 
-=======
-    },
-
-    test_target_attribute: function () {
-        // Constrain attribute should be set from passing in target.
-        var test_node = Y.one('#' + this.div_id);
-        this.indicator = new Y.lp.app.indicator.OverlayIndicator({
-            target: test_node
-        });
-        this.indicator.render();
-        Assert.areEqual(test_node, this.indicator.get('target'));
-    },
-
-    test_indicator_appended_to_parent: function() {
-        // Indicator node is appended to target's parent, rather
-        // than target or body.
-        var child_div = Y.Node.create('<div/>');
-        // We need to create some nesting to really ensure
-        // the test is good.
-        this.div.appendChild(child_div);
-        this.indicator = new Y.lp.app.indicator.OverlayIndicator({
-            target: child_div
-        });
-        this.indicator.render();
-        // this.div is actually the parentNode now.
-        Assert.areEqual(
-            this.div,
-            this.indicator.get('boundingBox').get('parentNode'));
-    },
-
-    test_indicator_has_loading_icon: function () {
-        // The indicator should have a loading image added
-        // to the contentBox.
-        this.indicator = new Y.lp.app.indicator.OverlayIndicator({
-            target: this.div
-        });
-        this.indicator.render();
-        var content = this.indicator.get('boundingBox');
-        var test = content.getContent();
-        var img = content.one('img');
-        Assert.areEqual('file:///@@/spinner-big', img.get('src'));
-    },
-
-    test_indiciator_starts_invisible: function () {
-        // Indicator widgets should start hidden.
-        this.indicator = new Y.lp.app.indicator.OverlayIndicator({
-            target: this.div
-        });
-        this.indicator.render();
-        Assert.isFalse(this.indicator.get('visible'));
-        Assert.isTrue(this.indicator.get('boundingBox').hasClass(
-            'yui3-overlay-indicator-hidden'));
-    },
-
-    test_set_busy_shows_overlay: function() {
-        // setBusy should show the overlay.
-        this.indicator = new Y.lp.app.indicator.OverlayIndicator({
-            target: this.div
-        });
-        this.indicator.render();
-        this.indicator.setBusy();
-        Assert.isTrue(this.indicator.get('visible'));
-        Assert.isFalse(this.indicator.get('boundingBox').hasClass(
-            'yui3-overlay-indicator-hidden'));
-    },
-
-    test_size_matches_on_set_busy: function() {
-        // Indicator should always resize when target changes size.
-        this.indicator = new Y.lp.app.indicator.OverlayIndicator({
-            target: this.div
-        });
-        this.indicator.render();
-        // Mess with the size of target div.
-        var expected_width = 800;
-        var expected_height = 600;
-        this.div.set('offsetWidth', expected_width);
-        this.div.set('offsetHeight', expected_height);
-        Assert.areNotEqual(
-            expected_width,
-            this.indicator.get('boundingBox').get('offsetWidth'));
-        Assert.areNotEqual(
-            expected_height,
-            this.indicator.get('boundingBox').get('offsetHeight'));
-        this.indicator.setBusy();
-        Assert.areEqual(
-            expected_width,
-            this.indicator.get('boundingBox').get('offsetWidth'));
-        Assert.areEqual(
-            expected_height,
-            this.indicator.get('boundingBox').get('offsetHeight'));
-    },
-
-    test_position_matches_on_set_busy: function() {
-        // Indicator should always reposition itself before setBusy.
-        this.indicator = new Y.lp.app.indicator.OverlayIndicator({
-            target: this.div
-        });
-        this.indicator.render();
-        // Change the position of target div.
-        var expected_xy = [100, 300];
-        this.div.setXY(expected_xy);
-        var actual_xy = this.indicator.get('boundingBox').getXY();
-        Assert.areNotEqual(expected_xy[0], actual_xy[0]);
-        Assert.areNotEqual(expected_xy[1], actual_xy[1]);
-        this.indicator.setBusy();
-        var final_xy = this.indicator.get('boundingBox').getXY();
-        Assert.areEqual(expected_xy[0], final_xy[0]);
-        Assert.areEqual(expected_xy[1], final_xy[1]);
-
-    },
-
-    test_success_hides_overlay: function() {
-        // Calling success should hide the overlay.
-        this.indicator = new Y.lp.app.indicator.OverlayIndicator({
-            target: this.div
-        });
-        this.indicator.render();
-        this.indicator.setBusy();
-        this.indicator.success();
-        Assert.isFalse(this.indicator.get('visible'));
-        Assert.isTrue(this.indicator.get('boundingBox').hasClass(
-            'yui3-overlay-indicator-hidden'));
-    },
-
-    test_success_callback: function() {
-        // We should be able to pass in a callback as success_action.
-        var called = false;
-        var callback = function() {
-            called = true;
-        };
-        this.indicator = new Y.lp.app.indicator.OverlayIndicator({
-            target: this.div,
-            success_action: callback
-        });
-        this.indicator.render();
-        this.indicator.success();
-        Assert.isTrue(called);
-    },
-
-    test_focus_target_scrolls_success: function () {
-        // Provided function scroll_to_target should scroll to target.
-        var viewport = Y.DOM.viewportRegion();
-        this.div.set('offsetWidth', viewport.right + 1000);
-        this.div.set('offsetHeight', viewport.bottom + 1000);
-        this.indicator = new Y.lp.app.indicator.OverlayIndicator({
-            target: this.div,
-            success_action: Y.lp.app.indicator.actions.scroll_to_target
-        });
-        this.indicator.render();
-        window.scrollTo(1000, 1000);
-        Assert.areEqual(1000, Y.DOM.docScrollX());
-        Assert.areEqual(1000, Y.DOM.docScrollY());
-        this.indicator.setBusy();
-        this.indicator.success();
-        var expected_xy = this.indicator.get('target').getXY();
-        Assert.areEqual(expected_xy[0], Y.DOM.docScrollX());
-        Assert.areEqual(expected_xy[1], Y.DOM.docScrollY());
-    },
-
-    test_error_hides_overlay: function () {
-        // Calling error should hide the overlay.
-        this.indicator = new Y.lp.app.indicator.OverlayIndicator({
-            target: this.div
-        });
-        this.indicator.render();
-        this.indicator.setBusy();
-        this.indicator.error();
-        Assert.isFalse(this.indicator.get('visible'));
-        Assert.isTrue(this.indicator.get('boundingBox').hasClass(
-            'yui3-overlay-indicator-hidden'));
-    },
-
-    test_error_callback: function() {
-        // We should be able to pass in a callback as error_action.
-        var called = false;
-        var callback = function() {
-            called = true;
-        };
-        this.indicator = new Y.lp.app.indicator.OverlayIndicator({
-            target: this.div,
-            error_action: callback
-        });
-        this.indicator.render();
-        this.indicator.error();
-        Assert.isTrue(called);
-    }
-}));
-
->>>>>>> MERGE-SOURCE
 
 }, '0.1', {'requires': ['test', 'lp.app.indicator']});

=== renamed file 'lib/lp/contrib/javascript/lp.mustache.js' => 'lib/lp/app/javascript/mustache.js'
=== modified file 'lib/lp/app/javascript/tests/test_beta_notification.html'
--- lib/lp/app/javascript/tests/test_beta_notification.html	2012-02-10 13:51:00 +0000
+++ lib/lp/app/javascript/tests/test_beta_notification.html	2012-02-16 14:03:30 +0000
@@ -27,7 +27,7 @@
 
       <!-- Dependencies -->
       <script type="text/javascript"
-          src="../../../../../build/js/lp/lp.mustache.js"></script>
+          src="../../../../../build/js/lp/app/mustache.js"></script>
 
       <!-- The module under test. -->
       <script type="text/javascript" src="../beta-notification.js"></script>

=== modified file 'lib/lp/app/javascript/tests/test_listing_navigator.html'
--- lib/lp/app/javascript/tests/test_listing_navigator.html	2012-02-10 13:51:00 +0000
+++ lib/lp/app/javascript/tests/test_listing_navigator.html	2012-02-16 14:03:30 +0000
@@ -43,7 +43,7 @@
       <script type="text/javascript"
           src="../../../../../build/js/lp/app/lp.js"></script>
       <script type="text/javascript"
-          src="../../../../../build/js/lp/lp.mustache.js"></script>
+          src="../../../../../build/js/lp/app/mustache.js"></script>
       <script type="text/javascript"
           src="../../../../../build/js/lp/app/overlay/overlay.js"></script>
       <script type="text/javascript"

=== modified file 'lib/lp/app/templates/base-layout.pt'
--- lib/lp/app/templates/base-layout.pt	2012-02-13 18:51:42 +0000
+++ lib/lp/app/templates/base-layout.pt	2012-02-16 14:03:30 +0000
@@ -80,6 +80,9 @@
           _gaq.push(['_setAllowHash', false]);
           _gaq.push(['_trackPageview']);
         </script>
+        <script type="text/javascript"
+            tal:condition="python: is_lpnet"
+            tal:attributes="src string:${icingroot}/google-analytics/ga.js"></script>
     <div class="yui-d0">
       <div id="locationbar" class="login-logout">
         <tal:login replace="structure context/@@login_status" />

=== modified file 'lib/lp/bugs/javascript/tests/test_buglisting.html'
--- lib/lp/bugs/javascript/tests/test_buglisting.html	2012-02-16 14:03:28 +0000
+++ lib/lp/bugs/javascript/tests/test_buglisting.html	2012-02-16 14:03:30 +0000
@@ -27,7 +27,7 @@
 
       <!-- Dependencies -->
       <script type="text/javascript"
-          src="../../../../../build/js/lp/lp.mustache.js"></script>
+          src="../../../../../build/js/lp/app/mustache.js"></script>
       <script type="text/javascript"
           src="../../../../../build/js/lp/app/client.js"></script>
       <script type="text/javascript"

=== modified file 'lib/lp/bugs/javascript/tests/test_bugtask_delete.html'
--- lib/lp/bugs/javascript/tests/test_bugtask_delete.html	2012-02-16 14:03:28 +0000
+++ lib/lp/bugs/javascript/tests/test_bugtask_delete.html	2012-02-16 14:03:30 +0000
@@ -30,11 +30,10 @@
       <script type="text/javascript" src="../../../../../build/js/lp/app/client.js"></script>
       <script type="text/javascript" src="../../../../../build/js/lp/app/errors.js"></script>
       <script type="text/javascript" src="../../../../../build/js/lp/app/lp.js"></script>
-  
+
       <!-- Other dependencies -->
       <script type="text/javascript" src="../../../../../build/js/lp/app/testing/mockio.js"></script>
-      <script type="text/javascript"
-        src="../../../contrib/javascript/mustache.j../../build/js/lp/s"><
+      <script type="text/javascript" src="../../../../../build/js/lp/app/mustache.js"><
       <script type="text/javascript" src="../../../../../build/js/lp/app/activator/activator.js"></script>
       <script type="text/javascript" src="../../../../../build/js/lp/app/anim/anim.js"></script>
       <script type="text/javascript" src="../../../../../build/js/lp/app/confirmationoverlay/confirmationoverlay.js"></script>

=== modified file 'lib/lp/bugs/javascript/tests/test_bugtask_delete.js'
--- lib/lp/bugs/javascript/tests/test_bugtask_delete.js	2012-01-31 02:45:45 +0000
+++ lib/lp/bugs/javascript/tests/test_bugtask_delete.js	2012-02-16 14:03:30 +0000
@@ -1,6 +1,6 @@
 YUI().use('lp.testing.runner', 'lp.testing.mockio', 'base', 'test', 'console',
           'node', 'node-event-simulate', 'lp.bugs.bugtask_index',
-          'lp.app.picker',
+          'lp.app.picker', 'lp.mustache',
     function(Y) {
 
 var suite = new Y.Test.Suite("Bugtask deletion Tests");

=== modified file 'lib/lp/code/doc/revision.txt'
--- lib/lp/code/doc/revision.txt	2012-02-16 14:03:28 +0000
+++ lib/lp/code/doc/revision.txt	2012-02-15 17:29:54 +0000
@@ -130,19 +130,33 @@
 In particular, IBranch.getScannerData efficiently retrieves the BranchRevision
 data needed by the branch-scanner script.
 
-    >>> history = branch.getScannerData()
-
-The return value is a sequence of tuples with revision numbers and
-revision_ids.
-
-    >>> for revno, revision_id in history:
-    ...     print "%d, %s" % (revno, revision_id)
-    6, foo@localhost-20051031170357-1301ad6d387feb23
-    5, foo@localhost-20051031170239-5fce7d6bd3f01efc
-    4, foo@localhost-20051031170008-098959758bf79803
-    3, foo@localhost-20051031165758-48acedf2b6a2e898
-    2, test@xxxxxxxxxxxxx-20051031165338-5f2f3d6b10bb3bf0
-    1, test@xxxxxxxxxxxxx-20051031165248-6f1bb97973c2b4f4
+    >>> ancestry, history = branch.getScannerData()
+
+The first return value is a set of revision_id strings for the full ancestry
+of the branch.
+
+    >>> for revision_id in sorted(ancestry):
+    ...     print revision_id
+    foo@localhost-20051031165758-48acedf2b6a2e898
+    foo@localhost-20051031170008-098959758bf79803
+    foo@localhost-20051031170239-5fce7d6bd3f01efc
+    foo@localhost-20051031170357-1301ad6d387feb23
+    test@xxxxxxxxxxxxx-20051031165248-6f1bb97973c2b4f4
+    test@xxxxxxxxxxxxx-20051031165338-5f2f3d6b10bb3bf0
+    test@xxxxxxxxxxxxx-20051031165532-3113df343e494daa
+    test@xxxxxxxxxxxxx-20051031165901-43b9644ec2eacc4e
+
+The second return value is a sequence of revision_id strings for the revision
+history of the branch.
+
+    >>> for revision_id in history:
+    ...     print revision_id
+    test@xxxxxxxxxxxxx-20051031165248-6f1bb97973c2b4f4
+    test@xxxxxxxxxxxxx-20051031165338-5f2f3d6b10bb3bf0
+    foo@localhost-20051031165758-48acedf2b6a2e898
+    foo@localhost-20051031170008-098959758bf79803
+    foo@localhost-20051031170239-5fce7d6bd3f01efc
+    foo@localhost-20051031170357-1301ad6d387feb23
 
 
 === Deleting BranchRevisions ===

=== modified file 'lib/lp/code/interfaces/branch.py'
--- lib/lp/code/interfaces/branch.py	2012-02-16 14:03:28 +0000
+++ lib/lp/code/interfaces/branch.py	2012-02-15 17:29:54 +0000
@@ -889,14 +889,19 @@
         """
 
     def getScannerData():
-        """Retrieve the full history of a branch for the branch scanner.
+        """Retrieve the full ancestry of a branch for the branch scanner.
 
         The branch scanner script is the only place where we need to retrieve
-        all the BranchRevision rows for a branch. Since the history of some
+        all the BranchRevision rows for a branch. Since the ancestry of some
         branches is into the tens of thousands we don't want to materialise
         BranchRevision instances for each of these.
 
-        :return: Iterator over bzr revision-ids in history, newest first.
+        :return: tuple of three items.
+            1. Ancestry set of bzr revision-ids.
+            2. History list of bzr revision-ids. Similar to the result of
+               bzrlib.Branch.revision_history().
+            3. Dictionnary mapping bzr bzr revision-ids to the database ids of
+               the corresponding BranchRevision rows for this branch.
         """
 
     def getInternalBzrUrl():

=== modified file 'lib/lp/code/javascript/tests/test_branchmergeproposal.nominate.html'
--- lib/lp/code/javascript/tests/test_branchmergeproposal.nominate.html	2012-02-16 14:03:28 +0000
+++ lib/lp/code/javascript/tests/test_branchmergeproposal.nominate.html	2012-02-16 14:03:30 +0000
@@ -26,7 +26,7 @@
       <link rel="stylesheet" href="../../../app/javascript/testing/test.css" />
 
       <!-- Dependencies -->
-      <script type="text/javascript" src="../../../../../build/js/lp/lp.mustache.js"></script>
+      <script type="text/javascript" src="../../../../../build/js/lp/app/mustache.js"></script>
       <script type="text/javascript" src="../../../../../build/js/lp/app/client.js"></script>
       <script type="text/javascript" src="../../../../../build/js/lp/app/lp.js"></script>
       <script type="text/javascript" src="../../../../../build/js/lp/app/activator/activator.js"></script>
@@ -72,4 +72,3 @@
 
     </body>
 </html>
-

=== modified file 'lib/lp/code/model/branch.py'
--- lib/lp/code/model/branch.py	2012-02-16 14:03:28 +0000
+++ lib/lp/code/model/branch.py	2012-02-15 17:29:54 +0000
@@ -975,12 +975,19 @@
 
     def getScannerData(self):
         """See `IBranch`."""
+        columns = (BranchRevision.sequence, Revision.revision_id)
         rows = Store.of(self).using(Revision, BranchRevision).find(
-            (BranchRevision.sequence, Revision.revision_id),
+            columns,
             Revision.id == BranchRevision.revision_id,
-            BranchRevision.branch_id == self.id,
-            BranchRevision.sequence != None)
-        return rows.order_by(Desc(BranchRevision.sequence))
+            BranchRevision.branch_id == self.id)
+        rows = rows.order_by(BranchRevision.sequence)
+        ancestry = set()
+        history = []
+        for sequence, revision_id in rows:
+            ancestry.add(revision_id)
+            if sequence is not None:
+                history.append(revision_id)
+        return ancestry, history
 
     def getPullURL(self):
         """See `IBranch`."""

=== modified file 'lib/lp/code/model/branchjob.py'
--- lib/lp/code/model/branchjob.py	2012-02-16 14:03:28 +0000
+++ lib/lp/code/model/branchjob.py	2012-02-15 22:01:27 +0000
@@ -485,20 +485,16 @@
 
     def iterAddedMainline(self):
         """Iterate through revisions added to the mainline."""
-        graph = self.bzr_branch.repository.get_graph()
-        branch_last_revinfo = self.bzr_branch.last_revision_info()
-        # Find the revision number matching self.last_revision_id.
-        last_revno = graph.find_distance_to_null(
-            self.last_revision_id,
-            [(branch_last_revinfo[1], branch_last_revinfo[0])])
-        added_revisions = graph.find_unique_ancestors(
-            self.last_revision_id, [self.last_scanned_id, NULL_REVISION])
+        repository = self.bzr_branch.repository
+        added_revisions = repository.get_graph().find_unique_ancestors(
+            self.last_revision_id, [self.last_scanned_id])
         # Avoid hitting the database since bzrlib makes it easy to check.
-        history = graph.iter_lefthand_ancestry(
-            self.last_revision_id, [NULL_REVISION, self.last_scanned_id, None])
-        for distance, revid in enumerate(history):
+        # There are possibly more efficient ways to get the mainline
+        # revisions, but this is simple and it works.
+        history = self.bzr_branch.revision_history()
+        for num, revid in enumerate(history):
             if revid in added_revisions:
-                yield revid, last_revno - distance
+                yield repository.get_revision(revid), num + 1
 
     def generateDiffs(self):
         """Determine whether to generate diffs."""
@@ -519,11 +515,8 @@
 
         self.bzr_branch.lock_read()
         try:
-            for revision_id, revno in reversed(
-                    list(self.iterAddedMainline())):
+            for revision, revno in self.iterAddedMainline():
                 assert revno is not None
-                revision = self.bzr_branch.repository.get_revision(
-                    revision_id)
                 mailer = self.getMailerForRevision(
                     revision, revno, self.generateDiffs())
                 mailer.sendAll()

=== modified file 'lib/lp/code/model/tests/test_branchjob.py'
--- lib/lp/code/model/tests/test_branchjob.py	2012-02-16 14:03:28 +0000
+++ lib/lp/code/model/tests/test_branchjob.py	2012-02-15 22:01:27 +0000
@@ -378,13 +378,16 @@
         job = RevisionsAddedJob.create(branch, 'rev1', 'rev2', '')
         self.assertEqual([job], list(RevisionsAddedJob.iterReady()))
 
-    def updateDBRevisions(self, branch, bzr_branch, revision_ids):
+    def updateDBRevisions(self, branch, bzr_branch, revision_ids=None):
         """Update the database for the revisions.
 
         :param branch: The database branch associated with the revisions.
         :param bzr_branch: The Bazaar branch associated with the revisions.
-        :param revision_ids: The ids of the revisions to update.
+        :param revision_ids: The ids of the revisions to update.  If not
+            supplied, the branch revision history is used.
         """
+        if revision_ids is None:
+            revision_ids = bzr_branch.revision_history()
         for bzr_revision in bzr_branch.repository.get_revisions(revision_ids):
             existing = branch.getBranchRevision(
                 revision_id=bzr_revision.revision_id)
@@ -430,7 +433,7 @@
         job = RevisionsAddedJob.create(branch, 'rev1', 'rev2', '')
         job.bzr_branch.lock_read()
         self.addCleanup(job.bzr_branch.unlock)
-        [(revision_id, revno)] = list(job.iterAddedMainline())
+        [(revision, revno)] = list(job.iterAddedMainline())
         self.assertEqual(2, revno)
 
     def test_iterAddedNonMainline(self):
@@ -444,24 +447,24 @@
         with override_environ(BZR_EMAIL='me@xxxxxxxxxxx'):
             tree.commit('rev3a', rev_id='rev3a')
         self.updateDBRevisions(branch, tree.branch, ['rev3', 'rev3a'])
-        job = RevisionsAddedJob.create(branch, 'rev1', 'rev2', '')
+        job = RevisionsAddedJob.create(branch, 'rev1', 'rev3', '')
         job.bzr_branch.lock_read()
         self.addCleanup(job.bzr_branch.unlock)
-        out = [x for x, y in job.iterAddedMainline()]
+        out = [x.revision_id for x, y in job.iterAddedMainline()]
         self.assertEqual(['rev2'], out)
 
     def test_iterAddedMainline_order(self):
-        """iterAddedMainline iterates in reverse commit order."""
+        """iterAddedMainline iterates in commit order."""
         self.useBzrBranches(direct_database=True)
         branch, tree = self.create3CommitsBranch()
         job = RevisionsAddedJob.create(branch, 'rev1', 'rev3', '')
         job.bzr_branch.lock_read()
         self.addCleanup(job.bzr_branch.unlock)
         # Since we've gone from rev1 to rev3, we've added rev2 and rev3.
-        [(rev3, revno3), (rev2, revno2)] = list(job.iterAddedMainline())
-        self.assertEqual('rev2', rev2)
+        [(rev2, revno2), (rev3, revno3)] = list(job.iterAddedMainline())
+        self.assertEqual('rev2', rev2.revision_id)
         self.assertEqual(2, revno2)
-        self.assertEqual('rev3', rev3)
+        self.assertEqual('rev3', rev3.revision_id)
         self.assertEqual(3, revno3)
 
     def makeBranchWithCommit(self):
@@ -773,8 +776,7 @@
                 committer="Joe Bloggs <joe@xxxxxxxxxxx>",
                 timestamp=1000100000.0, timezone=0)
         switch_dbuser('branchscanner')
-        self.updateDBRevisions(
-            db_branch, tree.branch, [first_revision, second_revision])
+        self.updateDBRevisions(db_branch, tree.branch)
         expected = (
             u"-" * 60 + '\n'
             "revno: 1" '\n'
@@ -817,8 +819,7 @@
                 committer=u"Non ASCII: \xed", timestamp=1000000000.0,
                 timezone=0)
         switch_dbuser('branchscanner')
-        self.updateDBRevisions(
-            db_branch, tree.branch, [rev_id])
+        self.updateDBRevisions(db_branch, tree.branch)
         job = RevisionsAddedJob.create(db_branch, '', '', '')
         message = job.getRevisionMessage(rev_id, 1)
         # The revision message must be a unicode object.

=== modified file 'lib/lp/codehosting/codeimport/tests/test_worker.py'
--- lib/lp/codehosting/codeimport/tests/test_worker.py	2012-02-16 14:03:28 +0000
+++ lib/lp/codehosting/codeimport/tests/test_worker.py	2012-02-15 17:29:54 +0000
@@ -185,7 +185,7 @@
         store = self.makeBranchStore()
         bzr_branch = store.pull(
             self.arbitrary_branch_id, self.temp_dir, default_format)
-        self.assertEqual((0, 'null:'), bzr_branch.last_revision_info())
+        self.assertEqual([], bzr_branch.revision_history())
 
     def test_getNewBranch_without_tree(self):
         # If pull() with needs_tree=False creates a new branch, it doesn't
@@ -657,7 +657,7 @@
         # import.
         worker = self.makeImportWorker()
         bzr_branch = worker.getBazaarBranch()
-        self.assertEqual((0, 'null:'), bzr_branch.last_revision_info())
+        self.assertEqual([], bzr_branch.revision_history())
 
     def test_bazaarBranchLocation(self):
         # getBazaarBranch makes the working tree under the current working
@@ -844,7 +844,7 @@
         worker.run()
         branch = self.getStoredBazaarBranch(worker)
         self.assertEqual(
-            self.foreign_commit_count, branch.revno())
+            self.foreign_commit_count, len(branch.revision_history()))
 
     def test_sync(self):
         # Do an import.
@@ -854,7 +854,7 @@
         worker.run()
         branch = self.getStoredBazaarBranch(worker)
         self.assertEqual(
-            self.foreign_commit_count, branch.revno())
+            self.foreign_commit_count, len(branch.revision_history()))
 
         # Change the remote branch.
         self.makeForeignCommit(worker.source_details)
@@ -865,7 +865,7 @@
         # Check that the new revisions are in the Bazaar branch.
         branch = self.getStoredBazaarBranch(worker)
         self.assertEqual(
-            self.foreign_commit_count, branch.revno())
+            self.foreign_commit_count, len(branch.revision_history()))
 
     def test_import_script(self):
         # Like test_import, but using the code-import-worker.py script
@@ -902,7 +902,7 @@
         branch = Branch.open(branch_url)
 
         self.assertEqual(
-            self.foreign_commit_count, branch.revno())
+            self.foreign_commit_count, len(branch.revision_history()))
 
     def test_script_exit_codes(self):
         # After a successful import that imports revisions, the worker exits
@@ -1381,7 +1381,8 @@
         self.assertEqual(
             CodeImportWorkerExitCode.SUCCESS, worker.run())
         branch = self.getStoredBazaarBranch(worker)
-        self.assertEqual(1, branch.revno())
+        self.assertEqual(
+            1, len(branch.revision_history()))
         self.assertEqual(
             "Some Random Hacker <jane@xxxxxxxxxxx>",
             branch.repository.get_revision(branch.last_revision()).committer)

=== modified file 'lib/lp/codehosting/codeimport/tests/test_workermonitor.py'
--- lib/lp/codehosting/codeimport/tests/test_workermonitor.py	2012-02-16 14:03:28 +0000
+++ lib/lp/codehosting/codeimport/tests/test_workermonitor.py	2012-02-15 17:29:54 +0000
@@ -803,7 +803,8 @@
         url = get_default_bazaar_branch_store()._getMirrorURL(
             code_import.branch.id)
         branch = Branch.open(url)
-        self.assertEqual(self.foreign_commit_count, branch.revno())
+        self.assertEqual(
+            self.foreign_commit_count, len(branch.revision_history()))
 
     def assertImported(self, ignored, code_import_id):
         """Assert that the `CodeImport` of the given id was imported."""

=== modified file 'lib/lp/codehosting/scanner/bzrsync.py'
--- lib/lp/codehosting/scanner/bzrsync.py	2012-02-16 14:03:28 +0000
+++ lib/lp/codehosting/scanner/bzrsync.py	2012-02-15 17:29:54 +0000
@@ -16,7 +16,6 @@
 
 import logging
 
-from bzrlib.errors import NoSuchRevision
 from bzrlib.graph import DictParentsProvider
 from bzrlib.revision import NULL_REVISION
 import pytz
@@ -85,16 +84,16 @@
         # Get the history and ancestry from the branch first, to fail early
         # if something is wrong with the branch.
         self.logger.info("Retrieving history from bzrlib.")
-        last_revision_info = bzr_branch.last_revision_info()
+        bzr_history = bzr_branch.revision_history()
         # The BranchRevision, Revision and RevisionParent tables are only
         # written to by the branch-scanner, so they are not subject to
         # write-lock contention. Update them all in a single transaction to
         # improve the performance and allow garbage collection in the future.
-        db_history = self.retrieveDatabaseAncestry()
+        db_ancestry, db_history = self.retrieveDatabaseAncestry()
 
         (new_ancestry, branchrevisions_to_delete,
             revids_to_insert) = self.planDatabaseChanges(
-            bzr_branch, last_revision_info, db_history)
+            bzr_branch, bzr_history, db_ancestry, db_history)
         new_db_revs = (
             new_ancestry - getUtility(IRevisionSet).onlyPresent(new_ancestry))
         self.logger.info("Adding %s new revisions.", len(new_db_revs))
@@ -116,7 +115,7 @@
 
         # Notify any listeners that the tip of the branch has changed, but
         # before we've actually updated the database branch.
-        initial_scan = (self.db_branch.last_scanned_id is None)
+        initial_scan = (len(db_history) == 0)
         notify(events.TipChanged(self.db_branch, bzr_branch, initial_scan))
 
         # The Branch table is modified by other systems, including the web UI,
@@ -126,7 +125,7 @@
         # not been updated. Since this has no ill-effect, and can only err on
         # the pessimistic side (tell the user the data has not yet been
         # updated although it has), the race is acceptable.
-        self.updateBranchStatus(last_revision_info)
+        self.updateBranchStatus(bzr_history)
         notify(
             events.ScanCompleted(
                 self.db_branch, bzr_branch, self.logger, new_ancestry))
@@ -135,7 +134,8 @@
     def retrieveDatabaseAncestry(self):
         """Efficiently retrieve ancestry from the database."""
         self.logger.info("Retrieving ancestry from database.")
-        return self.db_branch.getScannerData()
+        db_ancestry, db_history = self.db_branch.getScannerData()
+        return db_ancestry, db_history
 
     def _getRevisionGraph(self, bzr_branch, db_last):
         if bzr_branch.repository.has_revision(db_last):
@@ -155,32 +155,42 @@
 
         return bzr_branch.repository.get_graph(PPSource)
 
-    def getAncestryDelta(self, bzr_branch, bzr_last_revinfo, graph, db_last):
-        added_ancestry, removed_ancestry = graph.find_difference(
-            bzr_last_revinfo[1], db_last)
-        added_ancestry.discard(NULL_REVISION)
+    def getAncestryDelta(self, bzr_branch):
+        bzr_last = bzr_branch.last_revision()
+        db_last = self.db_branch.last_scanned_id
+        if db_last is None:
+            added_ancestry = set(bzr_branch.repository.get_ancestry(bzr_last))
+            added_ancestry.discard(None)
+            removed_ancestry = set()
+        else:
+            graph = self._getRevisionGraph(bzr_branch, db_last)
+            added_ancestry, removed_ancestry = (
+                graph.find_difference(bzr_last, db_last))
+            added_ancestry.discard(NULL_REVISION)
         return added_ancestry, removed_ancestry
 
-    def getHistoryDelta(self, bzr_branch, bzr_last_revinfo, graph, db_history):
+    def getHistoryDelta(self, bzr_history, db_history):
         self.logger.info("Calculating history delta.")
-        removed_history = []
-        common_revid = NULL_REVISION
-        for (revno, revid) in db_history:
-            try:
-                if bzr_branch.get_rev_id(revno) == revid:
-                    common_revid = revid
-                    common_len = revno
+        common_len = min(len(bzr_history), len(db_history))
+        while common_len > 0:
+            # The outer conditional improves efficiency. Without it, the
+            # algorithm is O(history-size * change-size), which can be
+            # excessive if a long branch is replaced by another long branch
+            # with a distant (or no) common mainline parent. The inner
+            # conditional is needed for correctness with branches where the
+            # history does not follow the line of leftmost parents.
+            if db_history[common_len - 1] == bzr_history[common_len - 1]:
+                if db_history[:common_len] == bzr_history[:common_len]:
                     break
-            except NoSuchRevision:
-                pass
-            removed_history.append(revid)
+            common_len -= 1
         # Revision added or removed from the branch's history. These lists may
         # include revisions whose history position has merely changed.
-        added_history = list(graph.iter_lefthand_ancestry(bzr_last_revinfo[1],
-            (common_revid, )))
+        removed_history = db_history[common_len:]
+        added_history = bzr_history[common_len:]
         return added_history, removed_history
 
-    def planDatabaseChanges(self, bzr_branch, bzr_last_revinfo, db_history):
+    def planDatabaseChanges(self, bzr_branch, bzr_history, db_ancestry,
+                            db_history):
         """Plan database changes to synchronize with bzrlib data.
 
         Use the data retrieved by `retrieveDatabaseAncestry` and
@@ -188,18 +198,9 @@
         """
         self.logger.info("Planning changes.")
         # Find the length of the common history.
-        db_last = self.db_branch.last_scanned_id
-        if db_last is None:
-            db_last = NULL_REVISION
-        graph = self._getRevisionGraph(bzr_branch, db_last)
-        bzr_branch.lock_read()
-        try:
-            added_history, removed_history = self.getHistoryDelta(
-                bzr_branch, bzr_last_revinfo, graph, db_history)
-            added_ancestry, removed_ancestry = self.getAncestryDelta(
-                bzr_branch, bzr_last_revinfo, graph, db_last)
-        finally:
-            bzr_branch.unlock()
+        added_history, removed_history = self.getHistoryDelta(
+            bzr_history, db_history)
+        added_ancestry, removed_ancestry = self.getAncestryDelta(bzr_branch)
 
         notify(
             events.RevisionsRemoved(
@@ -214,9 +215,10 @@
 
         # We must insert BranchRevision rows for all revisions which were
         # added to the ancestry or whose sequence value has changed.
+        last_revno = len(bzr_history)
         revids_to_insert = dict(
             self.revisionsToInsert(
-                added_history, bzr_last_revinfo[0], added_ancestry))
+                added_history, last_revno, added_ancestry))
         # We must remove any stray BranchRevisions that happen to already be
         # present.
         existing_branchrevisions = Store.of(self.db_branch).find(
@@ -234,8 +236,8 @@
         :param revisions: the set of Bazaar revision IDs to return bzrlib
             Revision objects for.
         """
-        revisions = list(bzr_branch.repository.has_revisions(revisions))
-        return bzr_branch.repository.get_revisions(revisions)
+        revisions = bzr_branch.repository.get_parent_map(revisions)
+        return bzr_branch.repository.get_revisions(revisions.keys())
 
     def syncOneRevision(self, bzr_branch, bzr_revision, revids_to_insert):
         """Import the revision with the given revision_id.
@@ -261,13 +263,13 @@
         """Calculate the revisions to insert and their revnos.
 
         :param added_history: A list of revision ids added to the revision
-            history in child-to-parent order.
+            history in parent-to-child order.
         :param last_revno: The revno of the last revision.
         :param added_ancestry: A set of revisions that have been added to the
             ancestry of the branch.  May overlap with added_history.
         """
         start_revno = last_revno - len(added_history) + 1
-        for (revno, revision_id) in enumerate(reversed(added_history), start_revno):
+        for (revno, revision_id) in enumerate(added_history, start_revno):
             yield revision_id, revno
         for revision_id in added_ancestry.difference(added_history):
             yield revision_id, None
@@ -294,10 +296,12 @@
         for revid_seq_pair_chunk in iter_list_chunks(revid_seq_pairs, 1000):
             self.db_branch.createBranchRevisionFromIDs(revid_seq_pair_chunk)
 
-    def updateBranchStatus(self, (revision_count, last_revision)):
+    def updateBranchStatus(self, bzr_history):
         """Update the branch-scanner status in the database Branch table."""
         # Record that the branch has been updated.
+        revision_count = len(bzr_history)
         if revision_count > 0:
+            last_revision = bzr_history[-1]
             revision = getUtility(IRevisionSet).getByRevisionId(last_revision)
         else:
             revision = None

=== modified file 'lib/lp/codehosting/scanner/tests/test_bzrsync.py'
--- lib/lp/codehosting/scanner/tests/test_bzrsync.py	2012-02-16 14:03:28 +0000
+++ lib/lp/codehosting/scanner/tests/test_bzrsync.py	2012-02-15 17:29:54 +0000
@@ -17,7 +17,6 @@
 from bzrlib.tests import TestCaseWithTransport
 from bzrlib.uncommit import uncommit
 import pytz
-from storm.expr import Desc
 from storm.locals import Store
 from twisted.python.util import mergeFunctionMetadata
 from zope.component import getUtility
@@ -429,10 +428,9 @@
             else:
                 bzr_branch.set_last_revision_info(revno, bzr_rev)
                 delta_branch = bzr_branch
-            return sync.getAncestryDelta(
-                delta_branch, delta_branch.last_revision_info(), graph, db_rev)
+            return sync.getAncestryDelta(delta_branch)
 
-        added_ancestry, removed_ancestry = get_delta('merge', NULL_REVISION)
+        added_ancestry, removed_ancestry = get_delta('merge', None)
         # All revisions are new for an unscanned branch
         self.assertEqual(
             set(['base', 'trunk', 'branch', 'merge']), added_ancestry)
@@ -473,11 +471,8 @@
         # yield each revision along with a sequence number, starting at 1.
         self.commitRevision(rev_id='rev-1')
         bzrsync = self.makeBzrSync(self.db_branch)
-        bzr_history = ['rev-1']
-        graph = bzrsync._getRevisionGraph(self.bzr_branch, 'rev-1')
-        added_ancestry = bzrsync.getAncestryDelta(
-            self.bzr_branch, self.bzr_branch.last_revision_info(),
-            graph, 'rev-1')[0]
+        bzr_history = self.bzr_branch.revision_history()
+        added_ancestry = bzrsync.getAncestryDelta(self.bzr_branch)[0]
         result = bzrsync.revisionsToInsert(
             bzr_history, self.bzr_branch.revno(), added_ancestry)
         self.assertEqual({'rev-1': 1}, dict(result))
@@ -488,12 +483,8 @@
         (db_branch, bzr_tree), ignored = self.makeBranchWithMerge(
             'base', 'trunk', 'branch', 'merge')
         bzrsync = self.makeBzrSync(db_branch)
-        bzr_history = ['merge', 'trunk', 'base']
-        graph = bzrsync._getRevisionGraph(bzr_tree.branch, 'merge')
-        self.addCleanup(bzr_tree.branch.lock_read().unlock)
-        added_ancestry = bzrsync.getAncestryDelta(
-            bzr_tree.branch, bzr_tree.branch.last_revision_info(),
-            graph, NULL_REVISION)[0]
+        bzr_history = bzr_tree.branch.revision_history()
+        added_ancestry = bzrsync.getAncestryDelta(bzr_tree.branch)[0]
         expected = {'base': 1, 'trunk': 2, 'merge': 3, 'branch': None}
         self.assertEqual(
             expected, dict(bzrsync.revisionsToInsert(bzr_history,
@@ -537,7 +528,7 @@
         self.assertEqual(self.getBranchRevisions(db_trunk), expected)
 
     def test_retrieveDatabaseAncestry(self):
-        # retrieveDatabaseAncestry should set db_history to
+        # retrieveDatabaseAncestry should set db_ancestry and db_history to
         # Launchpad's current understanding of the branch state.
         # db_branch_revision_map should map Bazaar revision_ids to
         # BranchRevision.ids.
@@ -550,16 +541,19 @@
             '~name12/+junk/junk.contrib')
         branch_revisions = IStore(BranchRevision).find(
             BranchRevision, BranchRevision.branch == branch)
-        sampledata = list(branch_revisions.order_by(Desc(BranchRevision.sequence)))
-        expected_history = [
-            (branch_revision.sequence, branch_revision.revision.revision_id)
+        sampledata = list(branch_revisions.order_by(BranchRevision.sequence))
+        expected_ancestry = set(branch_revision.revision.revision_id
+            for branch_revision in sampledata)
+        expected_history = [branch_revision.revision.revision_id
             for branch_revision in sampledata
             if branch_revision.sequence is not None]
 
         self.create_branch_and_tree(db_branch=branch)
 
         bzrsync = self.makeBzrSync(branch)
-        db_history = bzrsync.retrieveDatabaseAncestry()
+        db_ancestry, db_history = (
+            bzrsync.retrieveDatabaseAncestry())
+        self.assertEqual(expected_ancestry, set(db_ancestry))
         self.assertEqual(expected_history, list(db_history))
 
 
@@ -582,9 +576,9 @@
         syncer.syncBranchAndClose(self.bzr_tree.branch)
         self.assertEqual(rev2_id, self.db_branch.last_scanned_id)
         self.db_branch.last_scanned_id = rev1_id
-        db_history = self.db_branch.getScannerData()
+        db_ancestry, db_history = self.db_branch.getScannerData()
         branchrevisions_to_delete = syncer.planDatabaseChanges(
-            self.bzr_branch, (2, rev2_id), db_history)[1]
+            self.bzr_branch, [rev1_id, rev2_id], db_ancestry, db_history)[1]
         self.assertIn(merge_id, branchrevisions_to_delete)
 
 

=== modified file 'lib/lp/codehosting/tests/test_branchdistro.py'
--- lib/lp/codehosting/tests/test_branchdistro.py	2012-02-16 14:03:28 +0000
+++ lib/lp/codehosting/tests/test_branchdistro.py	2012-02-15 17:29:54 +0000
@@ -267,9 +267,12 @@
         self.assertEqual(tip_revision_id, new_branch.last_mirrored_id)
         self.assertEqual(tip_revision_id, new_branch.last_scanned_id)
         # Make sure that the branch revisions have been copied.
-        old_history = removeSecurityProxy(db_branch).getScannerData()
-        new_history = removeSecurityProxy(new_branch).getScannerData()
-        self.assertEqual(list(old_history), list(new_history))
+        old_ancestry, old_history = removeSecurityProxy(
+            db_branch).getScannerData()
+        new_ancestry, new_history = removeSecurityProxy(
+            new_branch).getScannerData()
+        self.assertEqual(old_ancestry, new_ancestry)
+        self.assertEqual(old_history, new_history)
         self.assertFalse(new_branch.pending_writes)
         self.assertIs(None, new_branch.stacked_on)
         self.assertEqual(new_branch, db_branch.stacked_on)

=== removed directory 'lib/lp/contrib'
=== removed directory 'lib/lp/contrib/css'
=== removed directory 'lib/lp/contrib/javascript'
=== removed symlink 'lib/lp/contrib/javascript/mustache.js'
=== target was u'../../../../sourcecode/mustache.js/mustache.js'
=== removed directory 'lib/lp/contrib/javascript/yui3-gallery'
=== modified file 'lib/lp/registry/browser/product.py'
--- lib/lp/registry/browser/product.py	2012-02-16 14:03:28 +0000
+++ lib/lp/registry/browser/product.py	2012-02-15 16:35:48 +0000
@@ -1534,7 +1534,6 @@
     usage_fieldname = 'answers_usage'
 
 
-<<<<<<< TREE
 class ProductPrivateBugsMixin():
     """A mixin for setting the product private_bugs field."""
     def setUpFields(self):
@@ -1566,39 +1565,6 @@
         return parent.updateContextFromData(data, context, notify_modified)
 
 
-=======
-class ProductPrivateBugsMixin():
-    """A mixin for setting the product private_bugs field."""
-    def setUpFields(self):
-        # private_bugs is readonly since we are using a mutator but we need
-        # to edit it on the form.
-        super(ProductPrivateBugsMixin, self).setUpFields()
-        self.form_fields = self.form_fields.omit('private_bugs')
-        private_bugs = copy_field(IProduct['private_bugs'], readonly=False)
-        self.form_fields += form.Fields(private_bugs)
-
-    def validate(self, data):
-        super(ProductPrivateBugsMixin, self).validate(data)
-        private_bugs = data.get('private_bugs')
-        if private_bugs is None:
-            return
-        try:
-            self.context.checkPrivateBugsTransitionAllowed(
-                private_bugs, self.user)
-        except Exception as e:
-            self.setFieldError('private_bugs', e.message)
-
-    def updateContextFromData(self, data, context=None, notify_modified=True):
-        # private_bugs uses a mutator to check permissions, so it needs to
-        # be handled separately.
-        if data.has_key('private_bugs'):
-            self.context.setPrivateBugs(data['private_bugs'], self.user)
-            del data['private_bugs']
-        parent = super(ProductPrivateBugsMixin, self)
-        return parent.updateContextFromData(data, context, notify_modified)
-
-
->>>>>>> MERGE-SOURCE
 class ProductEditView(ProductLicenseMixin, LaunchpadEditFormView):
     """View class that lets you edit a Product object."""
 

=== modified file 'lib/lp/registry/browser/team.py'
--- lib/lp/registry/browser/team.py	2012-02-16 14:03:28 +0000
+++ lib/lp/registry/browser/team.py	2012-02-16 03:12:17 +0000
@@ -272,15 +272,9 @@
                     'Private teams must have a Restricted subscription '
                     'policy.')
 
-<<<<<<< TREE
     def setUpVisibilityField(self, render_context=False):
         """Set the visibility field to read-write, or remove it."""
-=======
-    def setUpVisibilityField(self):
-        """Set the visibility field to read-write, or remove it."""
->>>>>>> MERGE-SOURCE
         self.form_fields = self.form_fields.omit('visibility')
-<<<<<<< TREE
         if self.user and self.user.checkAllowVisibility():
             visibility = copy_field(ITeam['visibility'], readonly=False)
             self.form_fields += Fields(
@@ -290,11 +284,6 @@
             field = field_names.pop()
             field_names.insert(2, field)
             self.form_fields = self.form_fields.select(*field_names)
-=======
-        if self.user and self.user.checkAllowVisibility():
-            visibility = copy_field(ITeam['visibility'], readonly=False)
-            self.form_fields += Fields(visibility)
->>>>>>> MERGE-SOURCE
 
 
 class TeamEditView(TeamFormMixin, PersonRenameFormMixin,
@@ -327,11 +316,7 @@
         self.field_names.remove('contactemail')
         self.field_names.remove('teamowner')
         super(TeamEditView, self).setUpFields()
-<<<<<<< TREE
         self.setUpVisibilityField(render_context=True)
-=======
-        self.setUpVisibilityField()
->>>>>>> MERGE-SOURCE
 
     def setUpWidgets(self):
         super(TeamEditView, self).setUpWidgets()

=== modified file 'lib/lp/registry/javascript/tests/test_structural_subscription.html'
--- lib/lp/registry/javascript/tests/test_structural_subscription.html	2012-02-16 14:03:28 +0000
+++ lib/lp/registry/javascript/tests/test_structural_subscription.html	2012-02-16 14:03:30 +0000
@@ -43,7 +43,7 @@
       <script type="text/javascript"
           src="../../../../../build/js/lp/app/inlinehelp/inlinehelp.js"></script>
       <script type="text/javascript"
-          src="../../../contrib/javascript/yui3-gallery/gallery-accordion/gallery-accordion.js"></script>
+          src="../../../../../build/js/lp/app//gallery-accordion/gallery-accordion.js"></script>
 
       <!-- The module under test. -->
       <script type="text/javascript" src="../structural-subscription.js"></script>

=== modified file 'lib/lp/registry/javascript/tests/test_team_mailinglists.html'
--- lib/lp/registry/javascript/tests/test_team_mailinglists.html	2012-02-16 14:03:28 +0000
+++ lib/lp/registry/javascript/tests/test_team_mailinglists.html	2012-02-16 14:03:30 +0000
@@ -1,4 +1,5 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+
   "http://www.w3.org/TR/html4/strict.dtd";>
 <!--
 Copyright 2012 Canonical Ltd.  This software is licensed under the
@@ -27,7 +28,7 @@
 
       <!-- Dependencies -->
       <script type="text/javascript"
-          src="../../../../../build/js/lp/lp.mustache.js"></script>
+          src="../../../../../build/js/lp/app/mustache.js"></script>
 
       <!-- The module under test. -->
       <script type="text/javascript" src="../team_mailinglists.js"></script>

=== modified file 'lib/lp/registry/model/person.py'
--- lib/lp/registry/model/person.py	2012-02-16 14:03:28 +0000
+++ lib/lp/registry/model/person.py	2012-02-16 08:27:37 +0000
@@ -291,7 +291,6 @@
 from lp.services.verification.interfaces.authtoken import LoginTokenType
 from lp.services.verification.interfaces.logintoken import ILoginTokenSet
 from lp.services.verification.model.logintoken import LoginToken
-from lp.services.webapp.authorization import check_permission
 from lp.services.webapp.dbpolicy import MasterDatabasePolicy
 from lp.services.webapp.interfaces import ILaunchBag
 from lp.services.worlddata.model.language import Language
@@ -3064,7 +3063,6 @@
         """See `IPerson.`"""
         return self.subscriptionpolicy in CLOSED_TEAM_POLICY
 
-<<<<<<< TREE
     def checkAllowVisibility(self):
         role = IPersonRoles(self)
         if role.in_commercial_admin or role.in_admin:
@@ -3083,27 +3081,6 @@
             raise ImmutableVisibilityError()
         self.visibility = visibility
 
-=======
-    def checkAllowVisibility(self):
-        feature_flag = getFeatureFlag(
-            'disclosure.show_visibility_for_team_add.enabled')
-        if feature_flag:
-            if self.hasCurrentCommercialSubscription():
-                return True
-        else:
-            if check_permission('launchpad.Commercial', self):
-                return True
-        return False
-
-    def transitionVisibility(self, visibility, user):
-        if self.visibility == visibility:
-            return
-        validate_person_visibility(self, 'visibility', visibility)
-        if not user.checkAllowVisibility():
-            raise ImmutableVisibilityError()
-        self.visibility = visibility
-
->>>>>>> MERGE-SOURCE
 
 class PersonSet:
     """The set of persons."""

=== modified file 'lib/lp/registry/stories/product/xx-product-with-private-defaults.txt'
--- lib/lp/registry/stories/product/xx-product-with-private-defaults.txt	2012-02-16 14:03:28 +0000
+++ lib/lp/registry/stories/product/xx-product-with-private-defaults.txt	2012-02-15 13:24:01 +0000
@@ -18,13 +18,9 @@
     >>> admin_browser.open("http://launchpad.dev/redfish/+admin";)
     >>> admin_browser.getControl(name="field.private_bugs").value = True
     >>> admin_browser.getControl("Change").click()
-<<<<<<< TREE
     >>> admin_browser.open("http://launchpad.dev/redfish/+admin";)
     >>> admin_browser.getControl(name="field.private_bugs").value
     True
-=======
-
->>>>>>> MERGE-SOURCE
 
 Filing a new bug
 ----------------

=== modified file 'lib/lp/registry/tests/test_person.py'
--- lib/lp/registry/tests/test_person.py	2012-02-16 14:03:28 +0000
+++ lib/lp/registry/tests/test_person.py	2012-02-16 08:27:37 +0000
@@ -550,7 +550,6 @@
         person = self.factory.makePerson()
         self.assertFalse(person.hasCurrentCommercialSubscription())
 
-<<<<<<< TREE
     def test_commercial_admin_with_ff_checkAllowVisibility(self):
         admin = getUtility(IPersonSet).getByEmail(ADMIN_EMAIL)
         feature_flag = {
@@ -564,14 +563,6 @@
             ImmutableVisibilityError, person.transitionVisibility,
             PersonVisibility.PRIVATE, person)
 
-=======
-    def test_can_not_set_visibility(self):
-        person = self.factory.makePerson()
-        self.assertRaises(
-            ImmutableVisibilityError, person.transitionVisibility,
-            PersonVisibility.PRIVATE, person)
-
->>>>>>> MERGE-SOURCE
 
 class TestPersonStates(TestCaseWithFactory):
 


Follow ups