launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #01570
[Merge] lp:~abentley/launchpad/partial-ancestry-scanner into lp:launchpad/devel
Aaron Bentley has proposed merging lp:~abentley/launchpad/partial-ancestry-scanner into lp:launchpad/devel.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
Related bugs:
#638637 Stop loading the entire ancestry of a branch during the scan
https://bugs.launchpad.net/bugs/638637
= Summary =
Fix bug #638637: Stop loading the entire ancestry of a branch during the scan
== Proposed fix ==
Use the set of revisions added to the ancestry, in most cases.
== Pre-implementation notes ==
Pre- and mid- implementation with thumper.
== Implementation details ==
I took the opportunity to refactor how things work a lot. Removing
whole-ancestry traversal made retrieveBranchDetails trivial, so I replaced it
with Branch.revision_history.
I also replaced BzrSync.getRevisions with BzrSync.revisionsToInsert, which
can use a partial ancestry and last-revno to generate the required info.
I also factored code out, e.g. getHistoryDelta.
Along the way, I added a write_locked Context Manager and added parent_ids to
makeBranchRevision so I could test getAncestryDelta.
_getRevisionGraph is designed to handle the case where not only has the tip
changed, but the old tip isn't present in the new repository. This requires
generating a Graph using the Revisions associated with the branch. However,
it's an extremely rare case, so I didn't optimize it.
== Tests ==
bin/test -vv scanner
== Demo and Q/A ==
None.
= Launchpad lint =
Checking for conflicts and issues in changed files.
Linting changed files:
lib/lp/codehosting/scanner/tests/test_bzrsync.py
lib/lp/codehosting/scanner/tests/test_mergedetection.py
lib/lp/codehosting/scanner/events.py
lib/lp/codehosting/bzrutils.py
lib/lp/testing/factory.py
lib/lp/codehosting/scanner/bzrsync.py
lib/lp/codehosting/scanner/mergedetection.py
./lib/lp/codehosting/scanner/tests/test_mergedetection.py
374: E231 missing whitespace after ','
121: Line exceeds 78 characters.
--
https://code.launchpad.net/~abentley/launchpad/partial-ancestry-scanner/+merge/38582
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~abentley/launchpad/partial-ancestry-scanner into lp:launchpad/devel.
=== modified file 'lib/lp/codehosting/bzrutils.py'
--- lib/lp/codehosting/bzrutils.py 2010-09-21 14:39:59 +0000
+++ lib/lp/codehosting/bzrutils.py 2010-10-15 18:41:34 +0000
@@ -162,6 +162,7 @@
def make_oops_logging_exception_hook(error_utility, request):
"""Make a hook for logging OOPSes."""
+
def log_oops():
error_utility.raising(sys.exc_info(), request)
return log_oops
@@ -340,6 +341,7 @@
def makeURLChecker(allowed_scheme):
"""Make a callable that rejects URLs not on the given scheme."""
+
def checkURL(url):
"""Check that `url` is safe to open."""
if URI(url).scheme != allowed_scheme:
@@ -374,3 +376,13 @@
yield
finally:
branch.unlock()
+
+
+@contextmanager
+def write_locked(branch):
+ """Provide a context in which the branch is write-locked."""
+ branch.lock_write()
+ try:
+ yield
+ finally:
+ branch.unlock()
=== modified file 'lib/lp/codehosting/scanner/bzrsync.py'
--- lib/lp/codehosting/scanner/bzrsync.py 2010-09-09 02:26:42 +0000
+++ lib/lp/codehosting/scanner/bzrsync.py 2010-10-15 18:41:34 +0000
@@ -16,8 +16,11 @@
import logging
+from bzrlib.graph import DictParentsProvider
+from bzrlib.revision import NULL_REVISION
import pytz
import transaction
+from storm.locals import Store
from zope.component import getUtility
from zope.event import notify
@@ -25,6 +28,8 @@
from lp.code.interfaces.branchjob import IRosettaUploadJobSource
from lp.code.interfaces.revision import IRevisionSet
+from lp.code.model.branchrevision import (BranchRevision)
+from lp.code.model.revision import Revision
from lp.codehosting import iter_list_chunks
from lp.codehosting.scanner import events
from lp.translations.interfaces.translationtemplatesbuildjob import (
@@ -65,7 +70,8 @@
* Revision: there must be one Revision row for each revision in the
branch ancestry. If the row for a revision that has just been added
- to the branch is already present, it must be checked for consistency.
+ to the branch is already present, it must be checked for
+ consistency.
* BranchRevision: there must be one BrancheRevision row for each
revision in the branch ancestry. If history revisions became merged
@@ -78,20 +84,21 @@
self.logger.info(" from %s", bzr_branch.base)
# Get the history and ancestry from the branch first, to fail early
# if something is wrong with the branch.
- bzr_ancestry, bzr_history = self.retrieveBranchDetails(bzr_branch)
+ self.logger.info("Retrieving history from bzrlib.")
+ 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_ancestry, db_history = self.retrieveDatabaseAncestry()
- (added_ancestry, branchrevisions_to_delete,
+ (new_ancestry, branchrevisions_to_delete,
revids_to_insert) = self.planDatabaseChanges(
- bzr_branch, bzr_ancestry, bzr_history, db_ancestry, db_history)
- added_ancestry.difference_update(
- getUtility(IRevisionSet).onlyPresent(added_ancestry))
- self.logger.info("Adding %s new revisions.", len(added_ancestry))
- for revids in iter_list_chunks(list(added_ancestry), 1000):
+ 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))
+ for revids in iter_list_chunks(list(new_db_revs), 1000):
revisions = self.getBazaarRevisions(bzr_branch, revids)
for revision in revisions:
# This would probably go much faster if we found some way to
@@ -122,7 +129,7 @@
self.updateBranchStatus(bzr_history)
notify(
events.ScanCompleted(
- self.db_branch, bzr_branch, bzr_ancestry, self.logger))
+ self.db_branch, bzr_branch, self.logger, new_ancestry))
transaction.commit()
def retrieveDatabaseAncestry(self):
@@ -131,28 +138,40 @@
db_ancestry, db_history = self.db_branch.getScannerData()
return db_ancestry, db_history
- def retrieveBranchDetails(self, bzr_branch):
- """Retrieve ancestry from the the bzr branch on disk."""
- self.logger.info("Retrieving ancestry from bzrlib.")
- last_revision = bzr_branch.last_revision()
- # Make bzr_ancestry a set for consistency with db_ancestry.
- bzr_ancestry_ordered = (
- bzr_branch.repository.get_ancestry(last_revision))
- first_ancestor = bzr_ancestry_ordered.pop(0)
- assert first_ancestor is None, 'history horizons are not supported'
- bzr_ancestry = set(bzr_ancestry_ordered)
- bzr_history = bzr_branch.revision_history()
- return bzr_ancestry, bzr_history
-
- def planDatabaseChanges(self, bzr_branch, bzr_ancestry, bzr_history,
- db_ancestry, db_history):
- """Plan database changes to synchronize with bzrlib data.
-
- Use the data retrieved by `retrieveDatabaseAncestry` and
- `retrieveBranchDetails` to plan the changes to apply to the database.
- """
- self.logger.info("Planning changes.")
- # Find the length of the common history.
+ def _getRevisionGraph(self, bzr_branch, db_last):
+ if bzr_branch.repository.has_revision(db_last):
+ return bzr_branch.repository.get_graph()
+ revisions = Store.of(self.db_branch).find(Revision,
+ BranchRevision.branch_id == self.db_branch.id,
+ Revision.id == BranchRevision.revision_id)
+ parent_map = dict(
+ (r.revision_id, r.parent_ids) for r in revisions)
+ parents_provider = DictParentsProvider(parent_map)
+
+ class PPSource:
+
+ @staticmethod
+ def _make_parents_provider():
+ return parents_provider
+
+ return bzr_branch.repository.get_graph(PPSource)
+
+ 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_history, db_history):
+ self.logger.info("Calculating history delta.")
common_len = min(len(bzr_history), len(db_history))
while common_len > 0:
# The outer conditional improves efficiency. Without it, the
@@ -165,39 +184,44 @@
if db_history[:common_len] == bzr_history[:common_len]:
break
common_len -= 1
-
- # Revisions added to the branch's ancestry.
- added_ancestry = bzr_ancestry.difference(db_ancestry)
-
# Revision added or removed from the branch's history. These lists may
# include revisions whose history position has merely changed.
removed_history = db_history[common_len:]
added_history = bzr_history[common_len:]
+ return added_history, removed_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
+ `retrieveBranchDetails` to plan the changes to apply to the database.
+ """
+ self.logger.info("Planning changes.")
+ # Find the length of the common history.
+ added_history, removed_history = self.getHistoryDelta(
+ bzr_history, db_history)
+ added_ancestry, removed_ancestry = self.getAncestryDelta(bzr_branch)
notify(
events.RevisionsRemoved(
self.db_branch, bzr_branch, removed_history))
- # Merged (non-history) revisions in the database and the bzr branch.
- old_merged = db_ancestry.difference(db_history)
- new_merged = bzr_ancestry.difference(bzr_history)
-
- # Revisions added or removed from the set of merged revisions.
- removed_merged = old_merged.difference(new_merged)
- added_merged = new_merged.difference(old_merged)
-
# We must delete BranchRevision rows for all revisions which where
# removed from the ancestry or whose sequence value has changed.
- branchrevisions_to_delete = list(
- removed_merged.union(removed_history))
+ branchrevisions_to_delete = set(removed_history)
+ branchrevisions_to_delete.update(removed_ancestry)
+ branchrevisions_to_delete.update(
+ set(added_history).difference(added_ancestry))
# 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.getRevisions(
- bzr_history, added_merged.union(added_history)))
+ self.revisionsToInsert(
+ added_history, last_revno, added_ancestry))
- return (added_ancestry, branchrevisions_to_delete,
+ return (added_ancestry, list(branchrevisions_to_delete),
revids_to_insert)
def getBazaarRevisions(self, bzr_branch, revisions):
@@ -228,17 +252,20 @@
self.db_branch, bzr_branch, db_revision, bzr_revision,
revids_to_insert[revision_id]))
- def getRevisions(self, bzr_history, revision_subset):
- """Iterate over '(revid, revno)' pairs in a branch's ancestry.
+ @staticmethod
+ def revisionsToInsert(added_history, last_revno, added_ancestry):
+ """Calculate the revisions to insert and their revnos.
- Generate a sequence of (revision-id, sequence) pairs to be inserted
- into the branchrevision table.
+ :param added_history: A list of revision ids added to the revision
+ 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.
"""
- for (index, revision_id) in enumerate(bzr_history):
- if revision_id in revision_subset:
- # sequence numbers start from 1
- yield revision_id, index + 1
- for revision_id in revision_subset.difference(set(bzr_history)):
+ start_revno = last_revno - len(added_history) + 1
+ 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
def deleteBranchRevisions(self, revision_ids_to_delete):
=== modified file 'lib/lp/codehosting/scanner/events.py'
--- lib/lp/codehosting/scanner/events.py 2010-08-20 20:31:18 +0000
+++ lib/lp/codehosting/scanner/events.py 2010-10-15 18:41:34 +0000
@@ -111,6 +111,7 @@
ScannerEvent.__init__(self, db_branch, bzr_branch)
self.removed_history = removed_history
+
class IScanCompleted(IObjectEvent):
"""The scan has been completed and the database is up-to-date."""
@@ -120,7 +121,7 @@
implements(IScanCompleted)
- def __init__(self, db_branch, bzr_branch, bzr_ancestry, logger):
+ def __init__(self, db_branch, bzr_branch, logger, new_ancestry):
"""Construct a `ScanCompleted` event.
:param db_branch: The database branch.
@@ -131,7 +132,7 @@
information, such as merges that we find.
"""
ScannerEvent.__init__(self, db_branch, bzr_branch)
- self.bzr_ancestry = bzr_ancestry
+ self.new_ancestry = new_ancestry
# This is kind of ick. In a strict Zope sense, the logger should
# probably be a registered utility.
self.logger = logger
=== modified file 'lib/lp/codehosting/scanner/mergedetection.py'
--- lib/lp/codehosting/scanner/mergedetection.py 2010-08-20 20:31:18 +0000
+++ lib/lp/codehosting/scanner/mergedetection.py 2010-10-15 18:41:34 +0000
@@ -78,7 +78,7 @@
determine which other branches this branch has been merged into.
"""
db_branch = scan_completed.db_branch
- bzr_ancestry = scan_completed.bzr_ancestry
+ new_ancestry = scan_completed.new_ancestry
logger = scan_completed.logger
# XXX: JonathanLange 2009-05-05 spec=package-branches: Yet another thing
@@ -112,7 +112,7 @@
# If the tip revisions are the same, then it is the same
# branch, not one merged into the other.
pass
- elif last_scanned in bzr_ancestry:
+ elif last_scanned in new_ancestry:
merge_detected(logger, branch, db_branch)
@@ -140,7 +140,7 @@
def auto_merge_proposals(scan_completed):
"""Detect merged proposals."""
db_branch = scan_completed.db_branch
- bzr_ancestry = scan_completed.bzr_ancestry
+ new_ancestry = scan_completed.new_ancestry
logger = scan_completed.logger
# Check landing candidates in non-terminal states to see if their tip
@@ -159,7 +159,7 @@
scan_completed.bzr_branch.iter_merge_sorted_revisions())
for proposal in db_branch.landing_candidates:
tip_rev_id = proposal.source_branch.last_scanned_id
- if tip_rev_id in bzr_ancestry:
+ if tip_rev_id in new_ancestry:
merged_revno = find_merged_revno(merge_sorted, tip_rev_id)
# Remember so we can find the merged revision number.
merge_detected(
=== modified file 'lib/lp/codehosting/scanner/tests/test_bzrsync.py'
--- lib/lp/codehosting/scanner/tests/test_bzrsync.py 2010-10-04 19:50:45 +0000
+++ lib/lp/codehosting/scanner/tests/test_bzrsync.py 2010-10-15 18:41:34 +0000
@@ -38,9 +38,10 @@
RevisionAuthor,
RevisionParent,
)
+from lp.codehosting.bzrutils import write_locked
from lp.codehosting.scanner.bzrsync import BzrSync
from lp.services.osutils import override_environ
-from lp.testing import TestCaseWithFactory
+from lp.testing import TestCaseWithFactory, temp_dir
from lp.translations.interfaces.translations import (
TranslationsBranchImportMode,
)
@@ -391,37 +392,99 @@
self.assertEqual(rev_1.revision_date, dt)
self.assertEqual(rev_2.revision_date, dt)
- def test_get_revisions_empty(self):
+ def getAncestryDelta_test(self, clean_repository=False):
+ """"Test various ancestry delta calculations.
+
+ :param clean_repository: If True, perform calculations with a branch
+ whose repository contains only revisions in the ancestry of the
+ tip.
+ """
+ (db_branch, bzr_tree), ignored = self.makeBranchWithMerge(
+ 'base', 'trunk', 'branch', 'merge')
+ bzr_branch = bzr_tree.branch
+ self.factory.makeBranchRevision(db_branch, 'base', 0)
+ self.factory.makeBranchRevision(
+ db_branch, 'trunk', 1, parent_ids=['base'])
+ self.factory.makeBranchRevision(
+ db_branch, 'branch', None, parent_ids=['base'])
+ self.factory.makeBranchRevision(
+ db_branch, 'merge', 2, parent_ids=['trunk', 'branch'])
+ sync = self.makeBzrSync(db_branch)
+ self.useContext(write_locked(bzr_branch))
+
+ def get_delta(bzr_rev, db_rev):
+ db_branch.last_scanned_id = db_rev
+ graph = bzr_branch.repository.get_graph()
+ revno = graph.find_distance_to_null(bzr_rev, [])
+ if clean_repository:
+ tempdir = self.useContext(temp_dir())
+ delta_branch = self.createBranchAtURL(tempdir)
+ self.useContext(write_locked(delta_branch))
+ delta_branch.pull(bzr_branch, stop_revision=bzr_rev)
+ else:
+ bzr_branch.set_last_revision_info(revno, bzr_rev)
+ delta_branch = bzr_branch
+ return sync.getAncestryDelta(delta_branch)
+
+ 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)
+ self.assertEqual(set(), removed_ancestry)
+ added_ancestry, removed_ancestry = get_delta('merge', 'base')
+ self.assertEqual(
+ set(['trunk', 'branch', 'merge']), added_ancestry)
+ self.assertEqual(set(), removed_ancestry)
+ added_ancestry, removed_ancestry = get_delta(NULL_REVISION, 'merge')
+ self.assertEqual(
+ set(), added_ancestry)
+ self.assertEqual(
+ set(['base', 'trunk', 'branch', 'merge']), removed_ancestry)
+ added_ancestry, removed_ancestry = get_delta('base', 'merge')
+ self.assertEqual(
+ set(), added_ancestry)
+ self.assertEqual(
+ set(['trunk', 'branch', 'merge']), removed_ancestry)
+ added_ancestry, removed_ancestry = get_delta('trunk', 'branch')
+ self.assertEqual(set(['trunk']), added_ancestry)
+ self.assertEqual(set(['branch']), removed_ancestry)
+
+ def test_getAncestryDelta(self):
+ """"Test ancestry delta calculations with a dirty repository."""
+ return self.getAncestryDelta_test()
+
+ def test_getAncestryDelta_clean_repository(self):
+ """"Test ancestry delta calculations with a clean repository."""
+ return self.getAncestryDelta_test(clean_repository=True)
+
+ def test_revisionsToInsert_empty(self):
# An empty branch should have no revisions.
- bzrsync = self.makeBzrSync(self.db_branch)
- bzr_ancestry, bzr_history = (
- bzrsync.retrieveBranchDetails(self.bzr_branch))
self.assertEqual(
- [], list(bzrsync.getRevisions(bzr_history, bzr_ancestry)))
+ [], list(BzrSync.revisionsToInsert([], 0, set())))
- def test_get_revisions_linear(self):
- # If the branch has a linear ancestry, getRevisions() should yield
- # each revision along with a sequence number, starting at 1.
+ def test_revisionsToInsert_linear(self):
+ # If the branch has a linear ancestry, revisionsToInsert() should
+ # yield each revision along with a sequence number, starting at 1.
self.commitRevision(rev_id='rev-1')
bzrsync = self.makeBzrSync(self.db_branch)
- bzr_ancestry, bzr_history = (
- bzrsync.retrieveBranchDetails(self.bzr_branch))
- self.assertEqual(
- [('rev-1', 1)],
- list(bzrsync.getRevisions(bzr_history, bzr_ancestry)))
+ 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))
- def test_get_revisions_branched(self):
+ def test_revisionsToInsert_branched(self):
# Confirm that these revisions are generated by getRevisions with None
# as the sequence 'number'.
(db_branch, bzr_tree), ignored = self.makeBranchWithMerge(
'base', 'trunk', 'branch', 'merge')
bzrsync = self.makeBzrSync(db_branch)
- bzr_ancestry, bzr_history = (
- bzrsync.retrieveBranchDetails(bzr_tree.branch))
- expected = set(
- [('base', 1), ('trunk', 2), ('merge', 3), ('branch', None)])
+ 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, set(bzrsync.getRevisions(bzr_history, bzr_ancestry)))
+ expected, dict(bzrsync.revisionsToInsert(bzr_history,
+ bzr_tree.branch.revno(), added_ancestry)))
def test_sync_with_merged_branches(self):
# Confirm that when we syncHistory, all of the revisions are included
@@ -460,19 +523,6 @@
expected = set([(1, 'base'), (2, 'branch')])
self.assertEqual(self.getBranchRevisions(db_trunk), expected)
- def test_retrieveBranchDetails(self):
- # retrieveBranchDetails should set last_revision, bzr_ancestry and
- # bzr_history on the BzrSync instance to match the information in the
- # Bazaar branch.
- (db_trunk, trunk_tree), ignored = self.makeBranchWithMerge(
- 'base', 'trunk', 'branch', 'merge')
- bzrsync = self.makeBzrSync(db_trunk)
- bzr_ancestry, bzr_history = (
- bzrsync.retrieveBranchDetails(trunk_tree.branch))
- expected_ancestry = set(['base', 'trunk', 'branch', 'merge'])
- self.assertEqual(expected_ancestry, bzr_ancestry)
- self.assertEqual(['base', 'trunk', 'merge'], bzr_history)
-
def test_retrieveDatabaseAncestry(self):
# retrieveDatabaseAncestry should set db_ancestry and db_history to
# Launchpad's current understanding of the branch state.
=== modified file 'lib/lp/codehosting/scanner/tests/test_mergedetection.py'
--- lib/lp/codehosting/scanner/tests/test_mergedetection.py 2010-10-04 19:50:45 +0000
+++ lib/lp/codehosting/scanner/tests/test_mergedetection.py 2010-10-15 18:41:34 +0000
@@ -197,11 +197,11 @@
mergedetection.merge_detected = self._original_merge_detected
TestCaseWithFactory.tearDown(self)
- def autoMergeBranches(self, db_branch, bzr_ancestry):
+ def autoMergeBranches(self, db_branch, new_ancestry):
mergedetection.auto_merge_branches(
events.ScanCompleted(
db_branch=db_branch, bzr_branch=None,
- bzr_ancestry=bzr_ancestry, logger=None))
+ logger=None, new_ancestry=new_ancestry))
def mergeDetected(self, logger, source, target):
# Record the merged branches
@@ -360,7 +360,7 @@
target = self.factory.makeBranchTargetBranch(source.target)
target.product.development_focus.branch = target
logger = logging.getLogger('test')
- notify(events.ScanCompleted(target, None, ['23foo'], logger))
+ notify(events.ScanCompleted(target, None, logger, ['23foo']))
self.assertEqual(
BranchLifecycleStatus.MERGED, source.lifecycle_status)
=== modified file 'lib/lp/testing/factory.py'
--- lib/lp/testing/factory.py 2010-10-14 12:57:25 +0000
+++ lib/lp/testing/factory.py 2010-10-15 18:41:34 +0000
@@ -1310,8 +1310,10 @@
'', parent.revision_id, None, None, None)
branch.updateScannedDetails(parent, sequence)
- def makeBranchRevision(self, branch, revision_id, sequence=None):
- revision = self.makeRevision(rev_id=revision_id)
+ def makeBranchRevision(self, branch, revision_id, sequence=None,
+ parent_ids=None):
+ revision = self.makeRevision(
+ rev_id=revision_id, parent_ids=parent_ids)
return branch.createBranchRevision(sequence, revision)
def makeBug(self, product=None, owner=None, bug_watch_url=None,
@@ -1844,22 +1846,6 @@
expires=expires, restricted=restricted)
return library_file_alias
- def makePackageDiff(self, from_spr=None, to_spr=None):
- """Make a completed package diff."""
- if from_spr is None:
- from_spr = self.makeSourcePackageRelease()
- if to_spr is None:
- to_spr = self.makeSourcePackageRelease()
-
- diff = from_spr.requestDiffTo(
- from_spr.creator, to_spr)
-
- naked_diff = removeSecurityProxy(diff)
- naked_diff.status = PackageDiffStatus.COMPLETED
- naked_diff.diff_content = self.makeLibraryFileAlias()
- naked_diff.date_fulfilled = UTC_NOW
- return diff
-
def makeDistribution(self, name=None, displayname=None, owner=None,
members=None, title=None, aliases=None):
"""Make a new distribution."""