Merge lp:~cjwatson/launchpad/remove-archive-cruft-check into lp:launchpad

Proposed by Colin Watson
Status: Merged
Approved by: Francis J. Lacoste
Approved revision: no longer in the source branch.
Merged at revision: 14075
Proposed branch: lp:~cjwatson/launchpad/remove-archive-cruft-check
Merge into: lp:launchpad
Diff against target: 675 lines (+0/-637)
4 files modified
lib/lp/soyuz/doc/soyuz-upload.txt (+0/-30)
lib/lp/soyuz/scripts/ftpmaster.py (+0/-404)
lib/lp/soyuz/scripts/tests/test_archivecruftchecker.py (+0/-147)
scripts/ftpmaster-tools/archive-cruft-check.py (+0/-56)
To merge this branch: bzr merge lp:~cjwatson/launchpad/remove-archive-cruft-check
Reviewer Review Type Date Requested Status
j.c.sackett (community) Approve
Review via email: mp+77524@code.launchpad.net

Commit message

[r=jcsackett][no-qa] Removes archive cruft check machinery.

Description of the change

Remove archive-cruft-check. The Ubuntu archive admins now use an API script based on this instead.

I believe this is qa-untestable. Robert and William expressed general approbation on IRC.

To post a comment you must log in.
Revision history for this message
j.c.sackett (jcsackett) wrote :

So, this code looks fine to land, assuming that I'm understanding correctly that only the Ubuntu archive admins ever used this functionality.

I've confirmed that nothing else seems to use any of this code, so I have no worries about it breaking.

Colin, if you can confirm my assumption is correct, I will be happy to mark this as approved.

Likewise, if someone else in the reviewer team is looking at this and can confirm my assumption, feel free to just vote approve on this.

review: Needs Information
Revision history for this message
j.c.sackett (jcsackett) wrote :

... and assumption confirmed.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/lp/soyuz/doc/soyuz-upload.txt'
--- lib/lp/soyuz/doc/soyuz-upload.txt 2011-09-29 09:37:58 +0000
+++ lib/lp/soyuz/doc/soyuz-upload.txt 2011-09-29 13:11:28 +0000
@@ -615,36 +615,6 @@
615 END615 END
616616
617617
618Testing archive-cruft-check-ng behaviour:
619^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
620
621Defining path to the script:
622
623 >>> script = os.path.join(config.root, "scripts", "ftpmaster-tools",
624 ... "archive-cruft-check.py")
625 >>> process = subprocess.Popen([sys.executable, script, "-vn",
626 ... "-d", "ubuntutest",
627 ... "-s", "breezy-autotest",
628 ... "/var/tmp/archive"],
629 ... stdout=subprocess.PIPE,
630 ... stderr=subprocess.PIPE,)
631 >>> stdout, stderr = process.communicate()
632 >>> process.returncode
633 0
634 >>> print stderr
635 INFO Creating lockfile: ...
636 DEBUG Considering Sources:
637 DEBUG Processing /var/tmp/archive/ubuntutest/dists/breezy-autotest/restricted/source/Sources.gz
638 DEBUG Processing /var/tmp/archive/ubuntutest/dists/breezy-autotest/main/source/Sources.gz
639 DEBUG Processing /var/tmp/archive/ubuntutest/dists/breezy-autotest/multiverse/source/Sources.gz
640 DEBUG Processing /var/tmp/archive/ubuntutest/dists/breezy-autotest/universe/source/Sources.gz
641 DEBUG Building not build from source list (NBS):
642 DEBUG Building all superseded by any list (ASBA):
643 DEBUG No NBS found
644 DEBUG Removing lock file: ...
645 <BLANKLINE>
646
647
648Nice! That's enough for now.. let's kill the process and clean618Nice! That's enough for now.. let's kill the process and clean
649everything up.619everything up.
650620
651621
=== modified file 'lib/lp/soyuz/scripts/ftpmaster.py'
--- lib/lp/soyuz/scripts/ftpmaster.py 2011-09-05 03:12:47 +0000
+++ lib/lp/soyuz/scripts/ftpmaster.py 2011-09-29 13:11:28 +0000
@@ -6,8 +6,6 @@
6__metaclass__ = type6__metaclass__ = type
77
8__all__ = [8__all__ = [
9 'ArchiveCruftChecker',
10 'ArchiveCruftCheckerError',
11 'ChrootManager',9 'ChrootManager',
12 'ChrootManagerError',10 'ChrootManagerError',
13 'LpQueryDistro',11 'LpQueryDistro',
@@ -69,408 +67,6 @@
69 )67 )
7068
7169
72class ArchiveCruftCheckerError(Exception):
73 """ArchiveCruftChecker specific exception.
74
75 Mostly used to describe errors in the initialization of this object.
76 """
77
78
79class TagFileNotFound(Exception):
80 """Raised when an archive tag file could not be found."""
81
82
83class ArchiveCruftChecker:
84 """Perform overall checks to identify and remove obsolete records.
85
86 Use initialize() method to validate passed parameters and build the
87 infrastructure variables. It will raise ArchiveCruftCheckerError if
88 something goes wrong.
89 """
90
91 # XXX cprov 2006-05-15: the default archive path should come
92 # from the config.
93 def __init__(self, logger, distribution_name='ubuntu', suite=None,
94 archive_path='/srv/launchpad.net/ubuntu-archive'):
95 """Store passed arguments.
96
97 Also Initialize empty variables for storing preliminar results.
98 """
99 self.distribution_name = distribution_name
100 self.suite = suite
101 self.archive_path = archive_path
102 self.logger = logger
103 # initialize a group of variables to store temporary results
104 # available versions of published sources
105 self.source_versions = {}
106 # available binaries produced by published sources
107 self.source_binaries = {}
108 # 'Not Build From Source' binaries
109 self.nbs = {}
110 # 'All superseded by Any' binaries
111 self.asba = {}
112 # published binary package names
113 self.bin_pkgs = {}
114 # Architecture specific binary packages
115 self.arch_any = {}
116 # proposed NBS (before clean up)
117 self.dubious_nbs = {}
118 # NBS after clean up
119 self.real_nbs = {}
120 # definitive NBS organized for clean up
121 self.nbs_to_remove = []
122
123 @property
124 def architectures(self):
125 return dict([(a.architecturetag, a)
126 for a in self.distroseries.architectures])
127
128 @property
129 def components(self):
130 return dict([(c.name, c) for c in self.distroseries.components])
131
132 @property
133 def components_and_di(self):
134 components_and_di = []
135 for component in self.components:
136 components_and_di.append(component)
137 components_and_di.append('%s/debian-installer' % (component))
138 return components_and_di
139
140 @property
141 def dist_archive(self):
142 return os.path.join(
143 self.archive_path, self.distro.name, 'dists',
144 self.distroseries.name + pocketsuffix[self.pocket])
145
146 def gunzipTagFileContent(self, filename):
147 """Gunzip the contents of passed filename.
148
149 Check filename presence, if not present in the filesystem,
150 raises ArchiveCruftCheckerError. Use an tempfile.mkstemp()
151 to store the uncompressed content. Invoke system available
152 gunzip`, raises ArchiveCruftCheckError if it fails.
153
154 This method doesn't close the file descriptor used and does not
155 remove the temporary file from the filesystem, those actions
156 are required in the callsite. (apt_pkg.ParseTagFile is lazy)
157
158 Return a tuple containing:
159 * temp file descriptor
160 * temp filename
161 * the contents parsed by apt_pkg.ParseTagFile()
162 """
163 if not os.path.exists(filename):
164 raise TagFileNotFound("File does not exist: %s" % filename)
165
166 temp_fd, temp_filename = tempfile.mkstemp()
167 (result, output) = commands.getstatusoutput(
168 "gunzip -c %s > %s" % (filename, temp_filename))
169 if result != 0:
170 raise ArchiveCruftCheckerError(
171 "Gunzip invocation failed!\n%s" % output)
172
173 temp_file = os.fdopen(temp_fd)
174 # XXX cprov 2006-05-15: maybe we need some sort of data integrity
175 # check at this point, and maybe keep the uncrompressed file
176 # for debug purposes, let's see how it behaves in real conditions.
177 parsed_contents = apt_pkg.ParseTagFile(temp_file)
178
179 return temp_file, temp_filename, parsed_contents
180
181 def processSources(self):
182 """Process archive sources index.
183
184 Build source_binaries, source_versions and bin_pkgs lists.
185 """
186 self.logger.debug("Considering Sources:")
187 for component in self.components:
188 filename = os.path.join(
189 self.dist_archive, "%s/source/Sources.gz" % component)
190
191 self.logger.debug("Processing %s" % filename)
192 try:
193 temp_fd, temp_filename, parsed_sources = (
194 self.gunzipTagFileContent(filename))
195 except TagFileNotFound, warning:
196 self.logger.warn(warning)
197 return
198 try:
199 while parsed_sources.Step():
200 source = parsed_sources.Section.Find("Package")
201 source_version = parsed_sources.Section.Find("Version")
202 binaries = parsed_sources.Section.Find("Binary")
203 for binary in [
204 item.strip() for item in binaries.split(',')]:
205 self.bin_pkgs.setdefault(binary, [])
206 self.bin_pkgs[binary].append(source)
207
208 self.source_binaries[source] = binaries
209 self.source_versions[source] = source_version
210 finally:
211 # close fd and remove temporary file used to store
212 # uncompressed tag file content from the filesystem.
213 temp_fd.close()
214 os.unlink(temp_filename)
215
216 def buildNBS(self):
217 """Build the group of 'not build from source' binaries"""
218 # Checks based on the Packages files
219 self.logger.debug("Building not build from source list (NBS):")
220 for component in self.components_and_di:
221 for architecture in self.architectures:
222 self.buildArchNBS(component, architecture)
223
224 def buildArchNBS(self, component, architecture):
225 """Build NBS per architecture.
226
227 Store results in self.nbs, also build architecture specific
228 binaries group (stored in self.arch_any)
229 """
230 filename = os.path.join(
231 self.dist_archive,
232 "%s/binary-%s/Packages.gz" % (component, architecture))
233
234 self.logger.debug("Processing %s" % filename)
235 try:
236 temp_fd, temp_filename, parsed_packages = (
237 self.gunzipTagFileContent(filename))
238 except TagFileNotFound, warning:
239 self.logger.warn(warning)
240 return
241
242 try:
243 while parsed_packages.Step():
244 package = parsed_packages.Section.Find('Package')
245 source = parsed_packages.Section.Find('Source', "")
246 version = parsed_packages.Section.Find('Version')
247 architecture = parsed_packages.Section.Find('Architecture')
248
249 if source == "":
250 source = package
251
252 if source.find("(") != -1:
253 m = re_extract_src_version.match(source)
254 source = m.group(1)
255 version = m.group(2)
256
257 if package not in self.bin_pkgs:
258 self.nbs.setdefault(source, {})
259 self.nbs[source].setdefault(package, {})
260 self.nbs[source][package][version] = ""
261
262 if architecture != "all":
263 self.arch_any.setdefault(package, "0")
264 if apt_pkg.VersionCompare(
265 version, self.arch_any[package]) < 1:
266 self.arch_any[package] = version
267 finally:
268 # close fd and remove temporary file used to store uncompressed
269 # tag file content from the filesystem.
270 temp_fd.close()
271 os.unlink(temp_filename)
272
273 def buildASBA(self):
274 """Build the group of 'all superseded by any' binaries."""
275 self.logger.debug("Building all superseded by any list (ASBA):")
276 for component in self.components_and_di:
277 for architecture in self.architectures:
278 self.buildArchASBA(component, architecture)
279
280 def buildArchASBA(self, component, architecture):
281 """Build ASBA per architecture.
282
283 Store the result in self.asba, require self.arch_any to be built
284 previously.
285 """
286 filename = os.path.join(
287 self.dist_archive,
288 "%s/binary-%s/Packages.gz" % (component, architecture))
289
290 try:
291 temp_fd, temp_filename, parsed_packages = (
292 self.gunzipTagFileContent(filename))
293 except TagFileNotFound, warning:
294 self.logger.warn(warning)
295 return
296
297 try:
298 while parsed_packages.Step():
299 package = parsed_packages.Section.Find('Package')
300 source = parsed_packages.Section.Find('Source', "")
301 version = parsed_packages.Section.Find('Version')
302 architecture = parsed_packages.Section.Find('Architecture')
303
304 if source == "":
305 source = package
306
307 if source.find("(") != -1:
308 m = re_extract_src_version.match(source)
309 source = m.group(1)
310 version = m.group(2)
311
312 if architecture == "all":
313 if (package in self.arch_any and
314 apt_pkg.VersionCompare(
315 version, self.arch_any[package]) > -1):
316 self.asba.setdefault(source, {})
317 self.asba[source].setdefault(package, {})
318 self.asba[source][package].setdefault(version, {})
319 self.asba[source][package][version][architecture] = ""
320 finally:
321 # close fd and remove temporary file used to store uncompressed
322 # tag file content from the filesystem.
323 temp_fd.close()
324 os.unlink(temp_filename)
325
326 def addNBS(self, nbs_d, source, version, package):
327 """Add a new entry in given organized nbs_d list
328
329 Ensure the package is still published in the suite before add.
330 """
331 result = self.distroseries.getBinaryPackagePublishing(name=package)
332
333 if len(list(result)) == 0:
334 return
335
336 nbs_d.setdefault(source, {})
337 nbs_d[source].setdefault(version, {})
338 nbs_d[source][version][package] = ""
339
340 def refineNBS(self):
341 """ Distinguish dubious from real NBS.
342
343 They are 'dubious' if the version numbers match and 'real'
344 if the versions don't match.
345 It stores results in self.dubious_nbs and self.real_nbs.
346 """
347 for source in self.nbs.keys():
348 for package in self.nbs[source].keys():
349 versions = self.nbs[source][package].keys()
350 versions.sort(apt_pkg.VersionCompare)
351 latest_version = versions.pop()
352
353 source_version = self.source_versions.get(source, "0")
354
355 if apt_pkg.VersionCompare(latest_version,
356 source_version) == 0:
357 self.addNBS(self.dubious_nbs, source, latest_version,
358 package)
359 else:
360 self.addNBS(self.real_nbs, source, latest_version,
361 package)
362
363 def outputNBS(self):
364 """Properly display built NBS entries.
365
366 Also organize the 'real' NBSs for removal in self.nbs_to_remove
367 attribute.
368 """
369 output = "Not Built from Source\n"
370 output += "---------------------\n\n"
371
372 nbs_keys = self.real_nbs.keys()
373 nbs_keys.sort()
374
375 for source in nbs_keys:
376 proposed_bin = self.source_binaries.get(
377 source, "(source does not exist)")
378 porposed_version = self.source_versions.get(source, "??")
379 output += (" * %s_%s builds: %s\n"
380 % (source, porposed_version, proposed_bin))
381 output += "\tbut no longer builds:\n"
382 versions = self.real_nbs[source].keys()
383 versions.sort(apt_pkg.VersionCompare)
384
385 for version in versions:
386 packages = self.real_nbs[source][version].keys()
387 packages.sort()
388
389 for pkg in packages:
390 self.nbs_to_remove.append(pkg)
391
392 output += " o %s: %s\n" % (
393 version, ", ".join(packages))
394
395 output += "\n"
396
397 if self.nbs_to_remove:
398 self.logger.info(output)
399 else:
400 self.logger.debug("No NBS found")
401
402 def initialize(self):
403 """Initialize and build required lists of obsolete entries in archive.
404
405 Check integrity of passed parameters and store organised data.
406 The result list is the self.nbs_to_remove which should contain
407 obsolete packages not currently able to be built from again.
408 Another preliminary lists can be inspected in order to have better
409 idea of what was computed.
410 If anything goes wrong mid-process, it raises ArchiveCruftCheckError,
411 otherwise a list of packages to be removes is printed.
412 """
413 if self.distribution_name is None:
414 self.distro = getUtility(ILaunchpadCelebrities).ubuntu
415 else:
416 try:
417 self.distro = getUtility(IDistributionSet)[
418 self.distribution_name]
419 except NotFoundError:
420 raise ArchiveCruftCheckerError(
421 "Invalid distribution: '%s'" % self.distribution_name)
422
423 if not self.suite:
424 self.distroseries = self.distro.currentseries
425 self.pocket = PackagePublishingPocket.RELEASE
426 else:
427 try:
428 self.distroseries, self.pocket = (
429 self.distro.getDistroSeriesAndPocket(self.suite))
430 except NotFoundError:
431 raise ArchiveCruftCheckerError(
432 "Invalid suite: '%s'" % self.suite)
433
434 if not os.path.exists(self.dist_archive):
435 raise ArchiveCruftCheckerError(
436 "Invalid archive path: '%s'" % self.dist_archive)
437
438 apt_pkg.init()
439 self.processSources()
440 self.buildNBS()
441 self.buildASBA()
442 self.refineNBS()
443 self.outputNBS()
444
445 def doRemovals(self):
446 """Perform the removal of the obsolete packages found.
447
448 It iterates over the previously build list (self.nbs_to_remove)
449 and mark them as 'superseded' in the archive DB model. They will
450 get removed later by the archive sanity check run each cycle
451 of the cron.daily.
452 """
453 for package in self.nbs_to_remove:
454
455 for distroarchseries in self.distroseries.architectures:
456 binarypackagename = getUtility(IBinaryPackageNameSet)[package]
457 dasbp = distroarchseries.getBinaryPackage(binarypackagename)
458 dasbpr = dasbp.currentrelease
459 try:
460 bpph = dasbpr.current_publishing_record
461 bpph.supersede()
462 # We're blindly removing for all arches, if it's not there
463 # for some, that's fine ...
464 except NotFoundError:
465 pass
466 else:
467 version = bpph.binarypackagerelease.version
468 self.logger.info("Removed %s_%s from %s/%s ... "
469 % (package, version,
470 self.distroseries.name,
471 distroarchseries.architecturetag))
472
473
474class PubBinaryContent:70class PubBinaryContent:
475 """Binary publication container.71 """Binary publication container.
47672
47773
=== removed file 'lib/lp/soyuz/scripts/tests/test_archivecruftchecker.py'
--- lib/lp/soyuz/scripts/tests/test_archivecruftchecker.py 2011-07-20 14:46:38 +0000
+++ lib/lp/soyuz/scripts/tests/test_archivecruftchecker.py 1970-01-01 00:00:00 +0000
@@ -1,147 +0,0 @@
1# Copyright 2009-2010 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).
3
4"""ArchiveCruftChecker tests.
5
6Check how scripts/ftpmaster-tools/archive-cruft-check.py works on a
7just-published 'ubuntutest' archive.
8"""
9
10__metaclass__ = type
11
12import shutil
13import transaction
14import unittest
15
16from zope.component import getUtility
17
18from canonical.config import config
19from canonical.testing.layers import LaunchpadZopelessLayer
20from lp.registry.interfaces.distribution import IDistributionSet
21from lp.registry.interfaces.pocket import PackagePublishingPocket
22from lp.services.log.logger import BufferLogger
23from lp.soyuz.scripts.ftpmaster import (
24 ArchiveCruftChecker,
25 ArchiveCruftCheckerError,
26 )
27from lp.soyuz.scripts.publishdistro import PublishDistro
28
29
30# XXX cprov 2006-05-15: {create, remove}TestArchive functions should be
31# moved to the publisher test domain as soon as we have it.
32def createTestArchive():
33 """Creates a fresh test archive based on sampledata."""
34 script = PublishDistro(test_args=["-C", "-q", "-d", "ubuntutest"])
35 script.txn = transaction
36 script.main()
37
38
39def removeTestArchive():
40 # XXX JeroenVermeulen 2011-07-20 bug=813538: Use a temporary
41 # directory so we don't have to commit this horror.
42 """Remove the entire test archive directory from the filesystem."""
43 shutil.rmtree("/var/tmp/archive/")
44
45
46class TestArchiveCruftChecker(unittest.TestCase):
47 layer = LaunchpadZopelessLayer
48
49 def setUp(self):
50 """Setup the test environment."""
51 self.layer.switchDbUser(config.archivepublisher.dbuser)
52 self.log = BufferLogger()
53 self.ubuntutest = getUtility(IDistributionSet)['ubuntutest']
54 self.breezy_autotest = self.ubuntutest['breezy-autotest']
55 self.archive_path = "/var/tmp/archive"
56 createTestArchive()
57
58 def tearDown(self):
59 """Clean up test environment and remove the test archive."""
60 removeTestArchive()
61
62 def testInitializeSuccess(self):
63 """Test ArchiveCruftChecker initialization process.
64
65 Check if the correct attributes are built after initialization.
66 """
67 checker = ArchiveCruftChecker(
68 self.log, distribution_name='ubuntutest', suite='breezy-autotest',
69 archive_path=self.archive_path)
70 checker.initialize()
71
72 self.assertEqual(self.ubuntutest, checker.distro)
73 self.assertEqual(self.breezy_autotest, checker.distroseries)
74 self.assertEqual(PackagePublishingPocket.RELEASE, checker.pocket)
75 self.assertEqual(0, len(checker.nbs_to_remove))
76 self.assertEqual(0, len(checker.real_nbs))
77 self.assertEqual(0, len(checker.dubious_nbs))
78 self.assertEqual(0, len(checker.bin_pkgs))
79 self.assertEqual(0, len(checker.arch_any))
80 self.assertEqual(0, len(checker.source_versions))
81 self.assertEqual(0, len(checker.source_binaries))
82
83 # The 'dist_archive' is an absolute path to the 'dists' section
84 # based on the given 'archive_path'.
85 self.assertEqual(
86 checker.dist_archive,
87 '/var/tmp/archive/ubuntutest/dists/breezy-autotest')
88
89 # The 'components' dictionary contains all components selected
90 # for the given distroseries organized as:
91 # {$component_name: IComponent, ...}
92 for component_name, component in checker.components.iteritems():
93 self.assertEqual(component_name, component.name)
94 checker_components = sorted(
95 [component_name for component_name in checker.components.keys()])
96 self.assertEqual(
97 checker_components,
98 ['main', 'multiverse', 'restricted', 'universe'])
99
100 # The 'components_and_di' lists the relative 'dists' paths
101 # for all components subsections of the archive which contain
102 # indexes.
103 expected = [
104 'main',
105 'main/debian-installer',
106 'multiverse',
107 'multiverse/debian-installer',
108 'restricted',
109 'restricted/debian-installer',
110 'universe',
111 'universe/debian-installer',
112 ]
113 self.assertEqual(sorted(checker.components_and_di), expected)
114
115 def testSuiteDistArchive(self):
116 """Check if 'dist_archive' path considers pocket correctly."""
117 checker = ArchiveCruftChecker(
118 self.log, distribution_name='ubuntutest',
119 suite='breezy-autotest-security',
120 archive_path=self.archive_path)
121 checker.initialize()
122
123 self.assertEqual(
124 checker.dist_archive,
125 '/var/tmp/archive/ubuntutest/dists/breezy-autotest-security')
126
127 def testInitializeFailure(self):
128 """ArchiveCruftCheck initialization failures.
129
130 * An unknown suite;
131 * An unknown distribution;
132 * The absence of the distribution in the given archive path.
133 """
134 checker = ArchiveCruftChecker(
135 self.log, distribution_name='ubuntu', suite='miserable',
136 archive_path=self.archive_path)
137 self.assertRaises(ArchiveCruftCheckerError, checker.initialize)
138
139 checker = ArchiveCruftChecker(
140 self.log, distribution_name='foobuntu', suite='breezy-autotest',
141 archive_path=self.archive_path)
142 self.assertRaises(ArchiveCruftCheckerError, checker.initialize)
143
144 checker = ArchiveCruftChecker(
145 self.log, distribution_name='ubuntu', suite='breezy-autotest',
146 archive_path=self.archive_path)
147 self.assertRaises(ArchiveCruftCheckerError, checker.initialize)
1480
=== removed file 'scripts/ftpmaster-tools/archive-cruft-check.py'
--- scripts/ftpmaster-tools/archive-cruft-check.py 2011-09-18 05:45:56 +0000
+++ scripts/ftpmaster-tools/archive-cruft-check.py 1970-01-01 00:00:00 +0000
@@ -1,56 +0,0 @@
1#!/usr/bin/python -S
2#
3# Copyright 2009 Canonical Ltd. This software is licensed under the
4# GNU Affero General Public License version 3 (see the file LICENSE).
5
6# pylint: disable-msg=W0403
7
8"""Archive Cruft checker.
9
10A kind of archive garbage collector, supersede NBS binaries (not build
11from source).
12"""
13
14import _pythonpath
15
16from canonical.config import config
17from lp.services.scripts.base import LaunchpadScript, LaunchpadScriptFailure
18from lp.soyuz.scripts.ftpmaster import (
19 ArchiveCruftChecker, ArchiveCruftCheckerError)
20
21
22class ArchiveCruftCheckerScript(LaunchpadScript):
23
24 usage = "Usage: archive-cruft-check.py [options] <ARCHIVE_PATH>"
25
26 def add_my_options(self):
27 self.parser.add_option(
28 "-d", "--distro", dest="distro", help="remove from DISTRO")
29 self.parser.add_option(
30 "-n", "--no-action", dest="action", default=True,
31 action="store_false", help="don't do anything")
32 self.parser.add_option(
33 "-s", "--suite", dest="suite", help="only act on SUITE")
34
35 def main(self):
36 if len(self.args) != 1:
37 self.parser.error('ARCHIVEPATH is require')
38 archive_path = self.args[0]
39
40 checker = ArchiveCruftChecker(
41 self.logger, distribution_name=self.options.distro,
42 suite=self.options.suite, archive_path=archive_path)
43
44 try:
45 checker.initialize()
46 except ArchiveCruftCheckerError, info:
47 raise LaunchpadScriptFailure(info)
48
49 # XXX cprov 2007-06-26 bug=121784: Disabling by distro-team request.
50 # if checker.nbs_to_remove and options.action:
51 # checker.doRemovals()
52 # ztm.commit()
53
54if __name__ == '__main__':
55 ArchiveCruftCheckerScript(
56 'archive-cruft-check', config.archivepublisher.dbuser).lock_and_run()