Tushar Gupta has proposed merging ~tushar5526/launchpad:add-support-for-parallel-publishing into launchpad:master.
Requested reviews: Launchpad code reviewers (launchpad-reviewers) For more details, see: https://code.launchpad.net/~tushar5526/launchpad/+git/launchpad/+merge/480435 -- Your team Launchpad code reviewers is requested to review the proposed merge of ~tushar5526/launchpad:add-support-for-parallel-publishing into launchpad:master.
diff --git a/lib/lp/archivepublisher/scripts/base.py b/lib/lp/archivepublisher/scripts/base.py index f590791..757c909 100644 --- a/lib/lp/archivepublisher/scripts/base.py +++ b/lib/lp/archivepublisher/scripts/base.py @@ -14,6 +14,7 @@ from zope.component import getUtility from lp.registry.interfaces.distribution import IDistributionSet from lp.services.scripts.base import LaunchpadCronScript +from lp.soyuz.interfaces.archive import IArchiveSet class PublisherScript(LaunchpadCronScript): @@ -36,6 +37,34 @@ class PublisherScript(LaunchpadCronScript): help="Publish all Ubuntu-derived distributions.", ) + def addParallelPublisherOptions(self): + self.parser.add_option( + "--archive", + action="append", + dest="archives", + metavar="REFERENCE", + default=[], + help="Only run over the archives identified by this reference. " + "You can specify multiple archives by repeating the option", + ) + + self.parser.add_option( + "--exclude", + action="append", + dest="excluded_archives", + metavar="REFERENCE", + default=[], + help="Skip the archives identified by this reference in the " + "publisher run. You can specify multiple archives by repeating " + "the option", + ) + + self.parser.add_option( + "--lockfilename", + dest="lockfilename", + help="lockfilename to be used by the publisher run", + ) + def findSelectedDistro(self): """Find the `Distribution` named by the --distribution option. @@ -62,3 +91,35 @@ class PublisherScript(LaunchpadCronScript): return self.findDerivedDistros() else: return [self.findSelectedDistro()] + + def findArchives(self, archive_references, distribution=None): + """ + Retrieve a list of archives based on the provided references and + optional distribution. + + Args: + archive_references (list): A list of archive references to + retrieve. + distribution (IDistributionSet, optional): The distribution + to filter archives by. Defaults to None. + + Returns: + list: A list of archives that match the provided references and + distribution. + """ + if not archive_references: + return [] + + archives = [] + for reference in archive_references: + archive = getUtility(IArchiveSet).getByReference(reference) + if not archive: + self.logger.warning( + "Cannot find the excluded archive with reference: '%s', " + % reference + ) + continue + if distribution and archive.distribution != distribution: + continue + archives.append(archive) + return archives diff --git a/lib/lp/archivepublisher/scripts/processaccepted.py b/lib/lp/archivepublisher/scripts/processaccepted.py index da27fb9..dc46718 100644 --- a/lib/lp/archivepublisher/scripts/processaccepted.py +++ b/lib/lp/archivepublisher/scripts/processaccepted.py @@ -40,11 +40,12 @@ class ProcessAccepted(PublisherScript): @property def lockfilename(self): """See `LaunchpadScript`.""" - return GLOBAL_PUBLISHER_LOCK + return self.options.lockfilename or GLOBAL_PUBLISHER_LOCK def add_my_options(self): """Command line options for this script.""" self.addDistroOptions() + self.addParallelPublisherOptions() self.parser.add_option( "--ppa", @@ -62,6 +63,18 @@ class ProcessAccepted(PublisherScript): help="Run only over COPY archives.", ) + def countExclusiveOptions(self): + """Return the number of exclusive "mode" options that were set. + + In valid use, at most one of them should be set. + """ + exclusive_options = [ + self.options.ppa, + self.options.copy_archives, + self.options.archives, + ] + return len(list(filter(None, exclusive_options))) + def validateArguments(self): """Validate command-line arguments.""" if self.options.ppa and self.options.copy_archives: @@ -72,11 +85,25 @@ class ProcessAccepted(PublisherScript): raise OptionValueError( "Can't combine --derived with a distribution name." ) + if self.countExclusiveOptions() > 1: + raise OptionValueError( + "Can only specify one of ppa, copy-archive, archive" + ) def getTargetArchives(self, distribution): """Find archives to target based on given options.""" + excluded_archives = self.findArchives( + self.options.excluded_archives, distribution + ) + + if self.options.archives: + return self.findArchives(self.options.archives, distribution) if self.options.ppa: - return distribution.getPendingAcceptancePPAs() + return [ + archive + for archive in distribution.getPendingAcceptancePPAs() + if archive not in excluded_archives + ] elif self.options.copy_archives: return getUtility(IArchiveSet).getArchivesForDistribution( distribution, purposes=[ArchivePurpose.COPY] diff --git a/lib/lp/archivepublisher/scripts/publishdistro.py b/lib/lp/archivepublisher/scripts/publishdistro.py index 38ee406..22cc478 100644 --- a/lib/lp/archivepublisher/scripts/publishdistro.py +++ b/lib/lp/archivepublisher/scripts/publishdistro.py @@ -71,10 +71,13 @@ def has_oval_data_changed(incoming_dir, published_dir): class PublishDistro(PublisherScript): """Distro publisher.""" - lockfilename = GLOBAL_PUBLISHER_LOCK + @property + def lockfilename(self): + return self.options.lockfilename or GLOBAL_PUBLISHER_LOCK def add_my_options(self): self.addDistroOptions() + self.addParallelPublisherOptions() self.parser.add_option( "-C", @@ -227,13 +230,6 @@ class PublishDistro(PublisherScript): help="Only run over the copy archives.", ) - self.parser.add_option( - "--archive", - dest="archive", - metavar="REFERENCE", - help="Only run over the archive identified by this reference.", - ) - def isCareful(self, option): """Is the given "carefulness" option enabled? @@ -275,7 +271,7 @@ class PublishDistro(PublisherScript): self.options.ppa, self.options.private_ppa, self.options.copy_archive, - self.options.archive, + self.options.archives, ] return len(list(filter(None, exclusive_options))) @@ -375,20 +371,32 @@ class PublishDistro(PublisherScript): def getTargetArchives(self, distribution): """Find the archive(s) selected by the script's options.""" - if self.options.archive: - archive = getUtility(IArchiveSet).getByReference( - self.options.archive - ) - if archive.distribution == distribution: - return [archive] - else: - return [] + if self.options.archives: + return self.findArchives(self.options.archives, distribution) elif self.options.partner: return [distribution.getArchiveByComponent("partner")] elif self.options.ppa: - return filter(is_ppa_public, self.getPPAs(distribution)) + return [ + archive + for archive in filter( + is_ppa_public, self.getPPAs(distribution) + ) + if archive + not in self.findArchives( + self.options.excluded_archives, distribution + ) + ] elif self.options.private_ppa: - return filter(is_ppa_private, self.getPPAs(distribution)) + return [ + archive + for archive in filter( + is_ppa_private, self.getPPAs(distribution) + ) + if archive + not in self.findArchives( + self.options.excluded_archives, distribution + ) + ] elif self.options.copy_archive: return self.getCopyArchives(distribution) else: @@ -597,12 +605,14 @@ class PublishDistro(PublisherScript): # store and cause performance problems. Store.of(archive).reset() - def rsyncOVALData(self): + def _buildRsyncCommand(self, src, dest, extra_options=None): + if extra_options is None: + extra_options = [] + # Ensure that the rsync paths have a trailing slash. - rsync_src = os.path.join( - config.archivepublisher.oval_data_rsync_endpoint, "" - ) - rsync_dest = os.path.join(config.archivepublisher.oval_data_root, "") + rsync_src = os.path.join(src, "") + rsync_dest = os.path.join(dest, "") + rsync_command = [ "/usr/bin/rsync", "-a", @@ -612,28 +622,69 @@ class PublishDistro(PublisherScript): ), "--delete", "--delete-after", - rsync_src, - rsync_dest, ] - try: - self.logger.info( - "Attempting to rsync the OVAL data from '%s' to '%s'", - rsync_src, - rsync_dest, - ) - check_call(rsync_command) - except CalledProcessError: - self.logger.exception( - "Failed to rsync OVAL data from '%s' to '%s'", - rsync_src, - rsync_dest, + rsync_command.extend(extra_options) + rsync_command.extend([rsync_src, rsync_dest]) + return rsync_command + + def _generateOVALDataRsyncCommands(self): + if self.options.archives: + return [ + self._buildRsyncCommand( + # -R: copies the OVALData and preserves the src path in + # dest directory + # --ignore-missing-args: If the source directory is not + # present, don't throw an error + # man rsync can provide detailed explanation of these + # options + extra_options=["-R", "--ignore-missing-args"], + src=os.path.join( + config.archivepublisher.oval_data_rsync_endpoint, + reference, + ), + dest=os.path.join(config.archivepublisher.oval_data_root), + ) + for reference in self.options.archives + ] + + exclude_options = [] + # If there are any archives specified to be excluded, exclude rsync + # for them in the rsync command + for excluded_archive in self.findArchives( + self.options.excluded_archives + ): + exclude_options.append("--exclude") + exclude_options.append(excluded_archive.reference) + return [ + self._buildRsyncCommand( + extra_options=exclude_options, + src=config.archivepublisher.oval_data_rsync_endpoint, + dest=config.archivepublisher.oval_data_root, ) - raise + ] + + def rsyncOVALData(self): + for rsync_command in self._generateOVALDataRsyncCommands(): + try: + self.logger.info( + "Attempting to rsync the OVAL data: %s", + rsync_command, + ) + check_call(rsync_command) + except CalledProcessError: + self.logger.exception( + "Failed to rsync OVAL data: %s", + rsync_command, + ) + raise def checkForUpdatedOVALData(self, distribution): """Compare the published OVAL files with the incoming one.""" start_dir = Path(config.archivepublisher.oval_data_root) archive_set = getUtility(IArchiveSet) + excluded_archives = self.findArchives( + self.options.excluded_archives, distribution + ) for owner_path in start_dir.iterdir(): if not owner_path.name.startswith("~"): continue @@ -644,6 +695,11 @@ class PublishDistro(PublisherScript): archive = archive_set.getPPAByDistributionAndOwnerName( distribution, owner_path.name[1:], archive_path.name ) + if ( + self.options.archives + and archive.reference not in self.options.archives + ): + continue if archive is None: self.logger.info( "Skipping OVAL data for '~%s/%s/%s' " @@ -653,6 +709,15 @@ class PublishDistro(PublisherScript): archive_path.name, ) continue + if archive in excluded_archives: + self.logger.info( + "Skipping OVAL data for '~%s/%s/%s' " + "(archive excluded from the publisher run).", + owner_path.name[1:], + distribution.name, + archive_path.name, + ) + continue for suite_path in archive_path.iterdir(): try: series, pocket = distribution.getDistroSeriesAndPocket( diff --git a/lib/lp/archivepublisher/tests/test_processaccepted.py b/lib/lp/archivepublisher/tests/test_processaccepted.py index 34c459e..8c95f7a 100644 --- a/lib/lp/archivepublisher/tests/test_processaccepted.py +++ b/lib/lp/archivepublisher/tests/test_processaccepted.py @@ -8,6 +8,7 @@ from optparse import OptionValueError import transaction from testtools.matchers import EndsWith, LessThan, MatchesListwise +from lp.archivepublisher.publishing import GLOBAL_PUBLISHER_LOCK from lp.archivepublisher.scripts.processaccepted import ProcessAccepted from lp.registry.interfaces.series import SeriesStatus from lp.services.config import config @@ -269,3 +270,104 @@ class TestProcessAccepted(TestCaseWithFactory): ] ), ) + + def test_countExclusiveOptions_is_zero_if_none_set(self): + # If none of the exclusive options is set, countExclusiveOptions + # counts zero. + self.assertEqual(0, self.getScript().countExclusiveOptions()) + + def test_countExclusiveOptions_counts_ppa(self): + # countExclusiveOptions includes the "ppa" option. + self.assertEqual( + 1, self.getScript(test_args=["--ppa"]).countExclusiveOptions() + ) + + def test_countExclusiveOptions_counts_copy_archives(self): + # countExclusiveOptions includes the "copy-archive" option. + self.assertEqual( + 1, + self.getScript( + test_args=["--copy-archives"] + ).countExclusiveOptions(), + ) + + def test_countExclusiveOptions_counts_archive(self): + # countExclusiveOptions includes the "copy-archive" option. + self.assertEqual( + 1, self.getScript(test_args=["--archive"]).countExclusiveOptions() + ) + + def test_lockfilename_option_overrides_default_lock(self): + script = self.getScript(test_args=["--lockfilename", "foo.lock"]) + assert script.lockfilepath == "/var/lock/foo.lock" + + def test_default_lock(self): + script = self.getScript() + assert script.lockfilepath == "/var/lock/%s" % GLOBAL_PUBLISHER_LOCK + + def test_getTargetArchives_ignores_excluded_archives_for_ppa(self): + # If the selected exclusive option is "ppa," getTargetArchives + # leaves out excluded PPAs. + distroseries = self.factory.makeDistroSeries(distribution=self.distro) + + ppa = self.factory.makeArchive(self.distro, purpose=ArchivePurpose.PPA) + excluded_ppa_1 = self.factory.makeArchive( + self.distro, purpose=ArchivePurpose.PPA + ) + excluded_ppa_2 = self.factory.makeArchive( + self.distro, purpose=ArchivePurpose.PPA, private=True + ) + + for archive in [ppa, excluded_ppa_1, excluded_ppa_2]: + self.createWaitingAcceptancePackage( + archive=archive, distroseries=distroseries + ) + script = self.getScript( + test_args=[ + "--ppa", + "--exclude", + excluded_ppa_1.reference, + "--exclude", + excluded_ppa_2.reference, + ], + ) + self.assertContentEqual([ppa], script.getTargetArchives(self.distro)) + + def test_getTargetArchives_gets_specific_archives(self): + # If the selected exclusive option is "archive," + # getTargetArchives looks for the specified archives. + + distroseries = self.factory.makeDistroSeries(distribution=self.distro) + + ppa1 = self.factory.makeArchive( + self.distro, purpose=ArchivePurpose.PPA + ) + ppa2 = self.factory.makeArchive( + self.distro, purpose=ArchivePurpose.PPA, private=True + ) + ppa3 = self.factory.makeArchive( + self.distro, purpose=ArchivePurpose.PPA + ) + ppa4 = self.factory.makeArchive( + self.distro, purpose=ArchivePurpose.PPA, private=True + ) + + # create another random archive in the same distro + self.factory.makeArchive(self.distro, purpose=ArchivePurpose.PPA) + + for archive in [ppa1, ppa2, ppa3, ppa4]: + self.createWaitingAcceptancePackage( + archive=archive, distroseries=distroseries + ) + + script = self.getScript( + test_args=[ + "--archive", + ppa1.reference, + "--archive", + ppa2.reference, + ], + ) + self.assertContentEqual( + [ppa1, ppa2], script.getTargetArchives(self.distro) + ) diff --git a/lib/lp/archivepublisher/tests/test_publishdistro.py b/lib/lp/archivepublisher/tests/test_publishdistro.py index ad591fa..a7fa759 100644 --- a/lib/lp/archivepublisher/tests/test_publishdistro.py +++ b/lib/lp/archivepublisher/tests/test_publishdistro.py @@ -24,7 +24,7 @@ from lp.archivepublisher.interfaces.archivegpgsigningkey import ( IArchiveGPGSigningKey, ) from lp.archivepublisher.interfaces.publisherconfig import IPublisherConfigSet -from lp.archivepublisher.publishing import Publisher +from lp.archivepublisher.publishing import GLOBAL_PUBLISHER_LOCK, Publisher from lp.archivepublisher.scripts.publishdistro import PublishDistro from lp.archivepublisher.tests.artifactory_fixture import ( FakeArtifactoryFixture, @@ -34,7 +34,7 @@ from lp.registry.interfaces.person import IPersonSet from lp.registry.interfaces.pocket import PackagePublishingPocket from lp.services.config import config from lp.services.database.interfaces import IStore -from lp.services.log.logger import BufferLogger, DevNullLogger +from lp.services.log.logger import BufferLogger from lp.services.osutils import write_file from lp.services.scripts.base import LaunchpadScriptFailure from lp.soyuz.enums import ( @@ -330,11 +330,94 @@ class TestPublishDistro(TestNativePublishingBase): ] mock_subprocess_check_call.assert_called_once_with(call_args) expected_log_line = ( - "ERROR Failed to rsync OVAL data from " - "'oval.internal::oval/' to '%s/'" % self.oval_data_root + "ERROR Failed to rsync OVAL data: " + "['/usr/bin/rsync', '-a', '-q', '--timeout=90', '--delete', " + "'--delete-after', 'oval.internal::oval/', '%s/']" + % self.oval_data_root ) self.assertTrue(expected_log_line in self.logger.getLogBuffer()) + def testPublishDistroOVALDataRsyncForExcludedArchives(self): + """ + Test publisher skips excluded archives specified via --exclude + during OVALData rsync. + """ + self.setUpOVALDataRsync() + ppa1 = self.factory.makeArchive(private=True) + ppa2 = self.factory.makeArchive() + self.factory.makeArchive() + + mock_subprocess_check_call = self.useFixture( + MockPatch("lp.archivepublisher.scripts.publishdistro.check_call") + ).mock + + call_args = [ + "/usr/bin/rsync", + "-a", + "-q", + "--timeout=90", + "--delete", + "--delete-after", + "--exclude", + ppa1.reference, + "--exclude", + ppa2.reference, + "oval.internal::oval/", + self.oval_data_root + "/", + ] + self.runPublishDistro( + extra_args=[ + "--exclude", + ppa1.reference, + "--exclude", + ppa2.reference, + ] + ) + mock_subprocess_check_call.assert_called_once_with(call_args) + + def testPublishDistroOVALDataRsyncForSpecificArchives(self): + """ + Test publisher only runs for archives specified via --archive + during OVALData rsync. + """ + self.setUpOVALDataRsync() + ppa1 = self.factory.makeArchive(private=True) + ppa2 = self.factory.makeArchive() + self.factory.makeArchive() + + mock_subprocess_check_call = self.useFixture( + MockPatch("lp.archivepublisher.scripts.publishdistro.check_call") + ).mock + + call_args = [ + call( + [ + "/usr/bin/rsync", + "-a", + "-q", + "--timeout=90", + "--delete", + "--delete-after", + "-R", + "--ignore-missing-args", + os.path.join("oval.internal::oval/", ppa.reference, ""), + self.oval_data_root + "/", + ] + ) + for ppa in [ppa1, ppa2] + ] + + self.runPublishDistro( + extra_args=[ + "--archive", + ppa1.reference, + "--archive", + ppa2.reference, + ] + ) + + assert mock_subprocess_check_call.call_args_list == call_args + def test_checkForUpdatedOVALData_new(self): self.setUpOVALDataRsync() self.useFixture( @@ -487,6 +570,105 @@ class TestPublishDistro(TestNativePublishingBase): ) self.assertIsNone(archive.dirty_suites) + def test_checkForUpdatedOVALData_skips_excluded_ppas(self): + """ + Skip excluded PPAs in checkForUpdatedOVALData + """ + self.setUpOVALDataRsync() + self.useFixture( + MockPatch("lp.archivepublisher.scripts.publishdistro.check_call") + ) + ppa1 = self.factory.makeArchive(purpose=ArchivePurpose.PPA) + ppa2 = self.factory.makeArchive(purpose=ArchivePurpose.PPA) + ppa3 = self.factory.makeArchive(purpose=ArchivePurpose.PPA) + # Disable normal publication so that dirty_suites isn't cleared. + ppa1.publish = False + ppa2.publish = False + ppa3.publish = False + + for archive in [ppa1, ppa2, ppa3]: + incoming_dir = ( + Path(self.oval_data_root) + / archive.reference + / "breezy-autotest" + / "main" + ) + write_file(str(incoming_dir), b"test") + + self.runPublishDistro( + extra_args=[ + "--ppa", + "--exclude", + ppa2.reference, + "--exclude", + ppa3.reference, + ], + distribution="ubuntu", + ) + + self.assertEqual(["breezy-autotest"], ppa1.dirty_suites) + self.assertIsNone(ppa2.dirty_suites) + self.assertIsNone(ppa3.dirty_suites) + self.assertIn( + "INFO Skipping OVAL data for '%s' " + "(archive excluded from the publisher run)." % (ppa2.reference), + self.logger.getLogBuffer(), + ) + self.assertIn( + "INFO Skipping OVAL data for '%s' " + "(archive excluded from the publisher run)." % (ppa3.reference), + self.logger.getLogBuffer(), + ) + + def test_checkForUpdatedOVALData_runs_for_specific_archive(self): + """ + checkForUpdatedOVALData should only run for specific archives + if "archive" option is specified. + """ + + self.setUpOVALDataRsync() + self.useFixture( + MockPatch("lp.archivepublisher.scripts.publishdistro.check_call") + ) + + ppa1 = self.factory.makeArchive(purpose=ArchivePurpose.PPA) + ppa2 = self.factory.makeArchive(purpose=ArchivePurpose.PPA) + ppa3 = self.factory.makeArchive(purpose=ArchivePurpose.PPA) + # Disable normal publication so that dirty_suites isn't cleared. + ppa1.publish = False + ppa2.publish = False + ppa3.publish = False + + for archive in [ppa1, ppa2, ppa3]: + incoming_dir = ( + Path(self.oval_data_root) + / archive.reference + / "breezy-autotest" + / "main" + ) + write_file(str(incoming_dir), b"test") + + self.runPublishDistro( + extra_args=[ + "--archive", + ppa1.reference, + "--archive", + ppa2.reference, + ], + distribution="ubuntu", + ) + + self.assertEqual(["breezy-autotest"], ppa1.dirty_suites) + self.assertEqual(["breezy-autotest"], ppa2.dirty_suites) + self.assertIsNone(ppa3.dirty_suites) + + # Further logs should not have any reference to other PPAs + # as we skip them when --archive option is set. + self.assertNotIn( + ppa3.reference, + self.logger.getLogBuffer(), + ) + @defer.inlineCallbacks def testForPPA(self): """Try to run publish-distro in PPA mode. @@ -951,7 +1133,8 @@ class TestPublishDistroMethods(TestCaseWithFactory): full_args = args + distro_args script = PublishDistro(test_args=full_args) script.distribution = distribution - script.logger = DevNullLogger() + self.logger = BufferLogger() + script.logger = self.logger return script def test_isCareful_is_false_if_option_not_set(self): @@ -1016,6 +1199,12 @@ class TestPublishDistroMethods(TestCaseWithFactory): 1, self.makeScript(args=["--copy-archive"]).countExclusiveOptions() ) + def test_countExclusiveOptions_counts_archive(self): + # countExclusiveOptions includes the "copy-archive" option. + self.assertEqual( + 1, self.makeScript(args=["--archive"]).countExclusiveOptions() + ) + def test_countExclusiveOptions_detects_conflict(self): # If more than one of the exclusive options has been set, that # raises the result from countExclusiveOptions above 1. @@ -1112,6 +1301,55 @@ class TestPublishDistroMethods(TestCaseWithFactory): [], self.makeScript(all_derived=True).findDistros() ) + def test_findArchives_without_distro_filter(self): + ppa1 = self.factory.makeArchive(purpose=ArchivePurpose.PPA) + ppa2 = self.factory.makeArchive(purpose=ArchivePurpose.PPA) + non_existing_ppa_reference = "~foo/ubuntu/bar-ppa" + + archvie_references = [ + ppa1.reference, + ppa2.reference, + non_existing_ppa_reference, + ] + self.assertContentEqual( + [ppa1, ppa2], + self.makeScript(all_derived=True).findArchives(archvie_references), + ) + + self.assertIn( + "WARNING Cannot find the excluded archive with reference: '%s'" + % (non_existing_ppa_reference), + self.logger.getLogBuffer(), + ) + + def test_findArchives_with_distro_filter(self): + distro1 = self.makeDistro() + distro2 = self.makeDistro() + ppa1 = self.factory.makeArchive(distro1, purpose=ArchivePurpose.PPA) + ppa2 = self.factory.makeArchive(distro1, purpose=ArchivePurpose.PPA) + ppa3 = self.factory.makeArchive(distro2, purpose=ArchivePurpose.PPA) + non_existing_ppa_reference = "~foo/ubuntu/bar-ppa" + + archvie_references = [ + ppa1.reference, + ppa2.reference, + ppa3.reference, + non_existing_ppa_reference, + ] + self.assertContentEqual( + [ppa1, ppa2], + self.makeScript().findArchives(archvie_references, distro1), + ) + self.assertContentEqual( + [ppa3], self.makeScript().findArchives(archvie_references, distro2) + ) + + self.assertIn( + "WARNING Cannot find the excluded archive with reference: '%s'" + % (non_existing_ppa_reference), + self.logger.getLogBuffer(), + ) + def test_findSuite_finds_release_pocket(self): # Despite its lack of a suffix, a release suite shows up # normally in findSuite results. @@ -1316,6 +1554,56 @@ class TestPublishDistroMethods(TestCaseWithFactory): script = self.makeScript(distro, ["--ppa"]) self.assertContentEqual([], script.getTargetArchives(distro)) + def test_getTargetArchives_ignores_excluded_archives_for_ppa(self): + # If the selected exclusive option is "ppa," getTargetArchives + # leaves out excluded PPAs. + distro = self.makeDistro() + ppa = self.factory.makeArchive(distro, purpose=ArchivePurpose.PPA) + excluded_ppa_1 = self.factory.makeArchive( + distro, purpose=ArchivePurpose.PPA + ) + excluded_ppa_2 = self.factory.makeArchive( + distro, purpose=ArchivePurpose.PPA + ) + script = self.makeScript( + distro, + [ + "--ppa", + "--careful", + "--exclude", + excluded_ppa_1.reference, + "--exclude", + excluded_ppa_2.reference, + ], + ) + self.assertContentEqual([ppa], script.getTargetArchives(distro)) + + def test_getTargetArchives_ignores_excluded_archives_for_private_ppa(self): + # If the selected exclusive option is "private-ppa," getTargetArchives + # leaves out excluded PPAs. + distro = self.makeDistro() + ppa = self.factory.makeArchive( + distro, purpose=ArchivePurpose.PPA, private=True + ) + excluded_ppa_1 = self.factory.makeArchive( + distro, purpose=ArchivePurpose.PPA, private=True + ) + excluded_ppa_2 = self.factory.makeArchive( + distro, purpose=ArchivePurpose.PPA, private=True + ) + script = self.makeScript( + distro, + [ + "--private-ppa", + "--careful", + "--exclude", + excluded_ppa_1.reference, + "--exclude", + excluded_ppa_2.reference, + ], + ) + self.assertContentEqual([ppa], script.getTargetArchives(distro)) + def test_getTargetArchives_gets_copy_archives(self): # If the selected exclusive option is "copy-archive," # getTargetArchives looks for a copy archive. @@ -1324,6 +1612,25 @@ class TestPublishDistroMethods(TestCaseWithFactory): script = self.makeScript(distro, ["--copy-archive"]) self.assertContentEqual([copy], script.getTargetArchives(distro)) + def test_getTargetArchives_gets_specific_archives(self): + # If the selected exclusive option is "archive," + # getTargetArchives looks for the specified archives. + distro = self.makeDistro() + + ppa_1 = self.factory.makeArchive(distro, purpose=ArchivePurpose.PPA) + ppa_2 = self.factory.makeArchive(distro, purpose=ArchivePurpose.PPA) + + # create another random archive in the same distro + self.factory.makeArchive(distro, purpose=ArchivePurpose.PPA) + + script = self.makeScript( + distro, + ["--archive", ppa_1.reference, "--archive", ppa_2.reference], + ) + self.assertContentEqual( + [ppa_1, ppa_2], script.getTargetArchives(distro) + ) + def test_getPublisher_returns_publisher(self): # getPublisher produces a Publisher instance. distro = self.makeDistro() @@ -1806,3 +2113,11 @@ class TestPublishDistroMethods(TestCaseWithFactory): self.assertTrue(by_hash_dir.is_dir()) # and still contains the two test files self.assertEqual(2, len(list(by_hash_dir.iterdir()))) + + def test_lockfilename_option_overrides_default_lock(self): + script = self.makeScript(args=["--lockfilename", "foo.lock"]) + assert script.lockfilepath == "/var/lock/foo.lock" + + def test_default_lock(self): + script = self.makeScript() + assert script.lockfilepath == "/var/lock/%s" % GLOBAL_PUBLISHER_LOCK
_______________________________________________ Mailing list: https://launchpad.net/~launchpad-reviewers Post to : launchpad-reviewers@lists.launchpad.net Unsubscribe : https://launchpad.net/~launchpad-reviewers More help : https://help.launchpad.net/ListHelp