launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #03942
[Merge] lp:~rvb/launchpad/init-series-bug-789091-previous-series into lp:launchpad
Raphaël Victor Badin has proposed merging lp:~rvb/launchpad/init-series-bug-789091-previous-series into lp:launchpad with lp:~rvb/launchpad/init-series-bug-789091-devel as a prerequisite.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
Related bugs:
Bug #789091 in Launchpad itself: "initialise_distroseries doesn't work with multiple parents"
https://bugs.launchpad.net/launchpad/+bug/789091
For more details, see:
https://code.launchpad.net/~rvb/launchpad/init-series-bug-789091-previous-series/+merge/64414
This branch is the backend side work to support initializing a series in a distribution with already initialized series. The given parent list will be used to create DSP but the series will be *derived* from the previous_series.
= Tests =
./bin/test -cvv test_initialise_distroseries test_derive_from_previous_parents
./bin/test -cvv test_initialise_distroseries test_derive_from_previous_parents_empty_parents
./bin/test -cvv test_initialise_distroseries test_derive_empty_parents_distribution_not_initialized
= Q/A =
This will be QAed using initialize-from-parent.py and using the UI that will come in a subsequent branch.
--
https://code.launchpad.net/~rvb/launchpad/init-series-bug-789091-previous-series/+merge/64414
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~rvb/launchpad/init-series-bug-789091-previous-series into lp:launchpad.
=== modified file 'lib/lp/soyuz/scripts/initialise_distroseries.py'
--- lib/lp/soyuz/scripts/initialise_distroseries.py 2011-06-13 15:22:31 +0000
+++ lib/lp/soyuz/scripts/initialise_distroseries.py 2011-06-13 15:22:32 +0000
@@ -47,10 +47,24 @@
includes all configuration for distroseries as well as distroarchseries,
publishing and all publishing records for sources and binaries.
+ We support 2 use cases here:
+ #1 If the child distribution has zero initialized series:
+ - the parent list can't be empty (otherwise we trigger an error);
+ - the series will be derived from the parents;
+ - the parents will be set to the parents passed as argument;
+ - first_derivation = True.
+ #2 If the child distribution has more than zero initialized series:
+ - the series will be derived from the previous_series'
+ parents;
+ - the parents will be set to the parents passed as argument or
+ the parents of the previous_series if the passed argument is empty;
+ - first_derivation = False.
+
Preconditions:
The distroseries must exist, and be completly unused, with no source
or binary packages existing, as well as no distroarchseries set up.
- Section and component selections must be empty. It must not have any parent series.
+ Section and component selections must be empty. It must not have any
+ parent series.
Outcome:
The distroarchseries set up in the parent series will be copied.
@@ -70,7 +84,7 @@
"""
def __init__(
- self, distroseries, parents, arches=(), packagesets=(),
+ self, distroseries, parents=(), arches=(), packagesets=(),
rebuild=False, overlays=(), overlay_pockets=(),
overlay_components=()):
# Avoid circular imports
@@ -93,18 +107,48 @@
self.overlay_components = overlay_components
self._store = IMasterStore(DistroSeries)
+ self.first_derivation = (
+ not self.distroseries.distribution.has_published_sources)
+ if self.first_derivation:
+ # Use-case #1.
+ self.derivation_parents = self.parents
+ self.derivation_parent_ids = self.parent_ids
+ else:
+ # Use-case #2.
+ self.derivation_parents = [self.distroseries.previous_series]
+ self.derivation_parent_ids = [
+ p.id for p in self.derivation_parents]
+ if self.parent_ids == []:
+ self.parents = (
+ self.distroseries.previous_series.getParentSeries())
+
def check(self):
if self.distroseries.is_derived_series:
raise InitialisationError(
("DistroSeries {child.name} has already been initialized"
".").format(
child=self.distroseries))
- for parent in self.parents:
+ self._checkParents()
+ for parent in self.derivation_parents:
if self.distroseries.distribution.id == parent.distribution.id:
self._checkBuilds(parent)
self._checkQueue(parent)
self._checkSeries()
+ def _checkParents(self):
+ """
+ If self.first_derivation, the parents list cannot be empty.
+ """
+ if self.first_derivation:
+ # Use-case #1.
+ if len(self.parent_ids) == 0:
+ raise InitialisationError(
+ ("Distroseries {child.name} cannot be initialized: "
+ "No other series in the distribution is initialized "
+ "and no parent was passed to the initilization method"
+ ".").format(
+ child=self.distroseries))
+
def _checkBuilds(self, parent):
"""Assert there are no pending builds for the given parent series.
@@ -188,11 +232,12 @@
def _copy_configuration(self):
self.distroseries.backports_not_automatic = any(
- [parent.backports_not_automatic for parent in self.parents])
+ [parent.backports_not_automatic
+ for parent in self.derivation_parents])
def _copy_architectures(self):
filtering = ' AND distroseries IN %s ' % (
- sqlvalues(self.parent_ids))
+ sqlvalues([p.id for p in self.derivation_parents]))
if self.arches:
filtering += ' AND architecturetag IN %s ' % (
sqlvalues(self.arches))
@@ -208,7 +253,7 @@
self._store.flush()
# Take nominatedarchindep from the first parent.
self.distroseries.nominatedarchindep = self.distroseries[
- self.parents[0].nominatedarchindep.architecturetag]
+ self.derivation_parents[0].nominatedarchindep.architecturetag]
def _copy_packages(self):
# Perform the copies
@@ -217,7 +262,7 @@
# Prepare the lists of distroarchseries for which binary packages
# shall be copied.
distroarchseries_lists = {}
- for parent in self.parents:
+ for parent in self.derivation_parents:
distroarchseries_lists[parent] = []
for arch in self.distroseries.architectures:
if self.arches and (arch.architecturetag not in self.arches):
@@ -251,7 +296,7 @@
pkgset = self._store.get(Packageset, int(pkgsetid))
spns += list(pkgset.getSourcesIncluded())
- for parent in self.parents:
+ for parent in self.derivation_parents:
distroarchseries_list = distroarchseries_lists[parent]
for archive in parent.distribution.all_distro_archives:
if archive.purpose not in (
@@ -289,14 +334,14 @@
SELECT DISTINCT %s AS distroseries, cs.component AS component
FROM ComponentSelection AS cs WHERE cs.distroseries IN %s
''' % sqlvalues(self.distroseries.id,
- self.parent_ids))
+ self.derivation_parent_ids))
# Copy the section selections
self._store.execute('''
INSERT INTO SectionSelection (distroseries, section)
SELECT DISTINCT %s as distroseries, ss.section AS section
FROM SectionSelection AS ss WHERE ss.distroseries IN %s
''' % sqlvalues(self.distroseries.id,
- self.parent_ids))
+ self.derivation_parent_ids))
# Copy the source format selections
self._store.execute('''
INSERT INTO SourcePackageFormatSelection (distroseries, format)
@@ -304,7 +349,7 @@
FROM SourcePackageFormatSelection AS spfs
WHERE spfs.distroseries IN %s
''' % sqlvalues(self.distroseries.id,
- self.parent_ids))
+ self.derivation_parent_ids))
def _copy_packaging_links(self):
"""Copy the packaging links from the parent series to this one."""
@@ -348,7 +393,8 @@
)
)
""" % sqlvalues(
- self.parent_ids, self.distroseries.id, self.parent_ids))
+ self.derivation_parent_ids, self.distroseries.id,
+ self.derivation_parent_ids))
def _copy_packagesets(self):
"""Copy packagesets from the parent distroseries."""
@@ -356,11 +402,11 @@
from lp.registry.model.distroseries import DistroSeries
packagesets = self._store.find(
- Packageset, DistroSeries.id.is_in(self.parent_ids))
+ Packageset, DistroSeries.id.is_in(self.derivation_parent_ids))
parent_to_child = {}
# Create the packagesets, and any archivepermissions
parent_distro_ids = [
- parent.distribution.id for parent in self.parents]
+ parent.distribution.id for parent in self.derivation_parents]
for parent_ps in packagesets:
# Cross-distro initialisations get packagesets owned by the
# distro owner, otherwise the old owner is preserved.
=== modified file 'lib/lp/soyuz/scripts/tests/test_initialise_distroseries.py'
--- lib/lp/soyuz/scripts/tests/test_initialise_distroseries.py 2011-06-13 15:22:31 +0000
+++ lib/lp/soyuz/scripts/tests/test_initialise_distroseries.py 2011-06-13 15:22:32 +0000
@@ -112,7 +112,7 @@
pocket=PackagePublishingPocket.RELEASE)
source.createMissingBuilds()
child = self.factory.makeDistroSeries(
- distribution=self.parent.parent)
+ distribution=self.parent.parent, previous_series=self.parent)
ids = InitialiseDistroSeries(child, [self.parent.id])
self.assertRaisesWithContent(
InitialisationError, "Parent series has pending builds.",
@@ -180,11 +180,13 @@
# Other configuration bits are copied too.
self.assertTrue(child.backports_not_automatic)
- def _fullInitialise(self, parents, child=None, arches=(), packagesets=(),
- rebuild=False, distribution=None, overlays=(),
+ def _fullInitialise(self, parents, child=None, previous_series=None,
+ arches=(), packagesets=(), rebuild=False,
+ distribution=None, overlays=(),
overlay_pockets=(), overlay_components=()):
if child is None:
- child = self.factory.makeDistroSeries(distribution=distribution)
+ child = self.factory.makeDistroSeries(
+ distribution=distribution, previous_series=previous_series)
ids = InitialiseDistroSeries(
child, [parent.id for parent in parents], arches, packagesets,
rebuild, overlays, overlay_pockets, overlay_components)
@@ -269,7 +271,7 @@
def test_packageset_owner_preserved_within_distro(self):
# When initialising a new series within a distro, the copied
# packagesets have ownership preserved.
- self.parent, self.parent_das = self.setupParent()
+ self.parent, self.parent_das = self.setupParent(packages={})
ps_owner = self.factory.makePerson()
getUtility(IPackagesetSet).new(
u'ps', u'packageset', ps_owner, distroseries=self.parent)
@@ -389,12 +391,12 @@
test1.addSources('udev')
getUtility(IArchivePermissionSet).newPackagesetUploader(
self.parent.main_archive, uploader, test1)
- # The child must have a parent series because initialise-from-parent
- # expects it; this script supports the old-style derivation of
- # distribution series where the parent series is specified at the time
- # of adding the series. New-style derivation leaves the specification
- # of the parent series until later.
child = self.factory.makeDistroSeries(previous_series=self.parent)
+ # Create an initialized series in the distribution.
+ other_series = self.factory.makeDistroSeries(
+ distribution=child.parent)
+ self.factory.makeSourcePackagePublishingHistory(
+ distroseries=other_series)
transaction.commit()
ifp = os.path.join(
config.root, 'scripts', 'ftpmaster-tools',
@@ -599,3 +601,89 @@
self.assertEquals(
u'0.3-1',
published_sources[0].sourcepackagerelease.version)
+
+ def setUpSeriesWithPreviousSeries(self, parent, previous_parents=(),
+ publish_in_distribution=True):
+ # Helper method to create a series within an initialized
+ # distribution (i.e. that has an initialized series) with a
+ # 'previous_series' with parents.
+
+ # Create a previous_series derived from 2 parents.
+ previous_series = self._fullInitialise(previous_parents)
+
+ child = self.factory.makeDistroSeries(previous_series=previous_series)
+
+ # Add a publishing in another series from this distro.
+ other_series = self.factory.makeDistroSeries(
+ distribution=child.distribution)
+ if publish_in_distribution:
+ self.factory.makeSourcePackagePublishingHistory(
+ distroseries=other_series)
+
+ return child
+
+ def test_derive_from_previous_parents(self):
+ # If the series to be initialized is in a distribution with
+ # initialized series, the series is *derived* from
+ # the previous_series' parents.
+ previous_parent1, unused = self.setupParent(packages={u'p1': u'1.2'})
+ previous_parent2, unused = self.setupParent(packages={u'p2': u'1.5'})
+ parent, unused = self.setupParent()
+ child = self.setUpSeriesWithPreviousSeries(
+ parent=parent,
+ previous_parents=[previous_parent1, previous_parent2])
+ self._fullInitialise([parent], child=child)
+
+ # The parent for the derived series is the distroseries given as
+ # argument to InitializeSeries.
+ self.assertContentEqual(
+ [parent],
+ child.getParentSeries())
+
+ # The new series has been derived from previous_series.
+ published_sources = child.main_archive.getPublishedSources(
+ distroseries=child)
+ self.assertEquals(2, published_sources.count())
+ pub_sources = sorted(
+ [(s.sourcepackagerelease.sourcepackagename.name,
+ s.sourcepackagerelease.version)
+ for s in published_sources])
+ self.assertEquals(
+ [(u'p1', u'1.2'), (u'p2', u'1.5')],
+ pub_sources)
+
+ def test_derive_from_previous_parents_empty_parents(self):
+ # If an empty list is passed to InitialiseDistroSeries, the
+ # parents of the previous series are used as parents.
+ previous_parent1, unused = self.setupParent(packages={u'p1': u'1.2'})
+ previous_parent2, unused = self.setupParent(packages={u'p2': u'1.5'})
+ parent, unused = self.setupParent()
+ child = self.setUpSeriesWithPreviousSeries(
+ parent=parent,
+ previous_parents=[previous_parent1, previous_parent2])
+ # Initialize from an empty list of parents.
+ self._fullInitialise([], child=child)
+
+ self.assertContentEqual(
+ [previous_parent1, previous_parent2],
+ child.getParentSeries())
+
+ def test_derive_empty_parents_distribution_not_initialized(self):
+ # Initializing a series with an empty parent list if the series'
+ # distribution has no initialized series triggers an error.
+ parent, unused = self.setupParent()
+ previous_parent1, unused = self.setupParent(packages={u'p1': u'1.2'})
+ child = self.setUpSeriesWithPreviousSeries(
+ parent=parent,
+ previous_parents=[previous_parent1],
+ publish_in_distribution=False)
+
+ # Initialize from an empty list of parents.
+ ids = InitialiseDistroSeries(child, [])
+ self.assertRaisesWithContent(
+ InitialisationError,
+ ("Distroseries {child.name} cannot be initialized: "
+ "No other series in the distribution is initialized "
+ "and no parent was passed to the initilization method"
+ ".").format(child=child),
+ ids.check)
=== modified file 'scripts/ftpmaster-tools/initialise-from-parent.py'
--- scripts/ftpmaster-tools/initialise-from-parent.py 2011-05-30 17:56:56 +0000
+++ scripts/ftpmaster-tools/initialise-from-parent.py 2011-06-13 15:22:32 +0000
@@ -81,13 +81,7 @@
arches = ()
if options.arches is not None:
arches = tuple(options.arches.split(','))
- # InitialiseDistroSeries does not like it if the parent series is
- # specified on the child, so we must unset it and pass it in. This is
- # a temporary hack until confidence in InitialiseDistroSeriesJob is
- # good, at which point this script will be obsolete.
- parent, distroseries.previous_series = (
- distroseries.previous_series, None)
- ids = InitialiseDistroSeries(distroseries, [parent.id], arches)
+ ids = InitialiseDistroSeries(distroseries, arches=arches)
ids.check()
log.debug('initialising from parent(s), copying publishing records.')
ids.initialise()