Merge lp:~stevenk/launchpad/destroy-librarianformatter into lp:launchpad

Proposed by Steve Kowalik
Status: Merged
Approved by: Steve Kowalik
Approved revision: no longer in the source branch.
Merged at revision: 16300
Proposed branch: lp:~stevenk/launchpad/destroy-librarianformatter
Merge into: lp:launchpad
Diff against target: 775 lines (+83/-430)
13 files modified
cronscripts/expire-bugtasks.py (+4/-13)
lib/lp/hardwaredb/doc/hwdb-submission.txt (+3/-0)
lib/lp/services/scripts/base.py (+4/-4)
lib/lp/services/scripts/doc/launchpad-scripts.txt (+4/-0)
lib/lp/services/scripts/logger.py (+10/-75)
lib/lp/services/scripts/tests/librarianformatter.txt (+0/-142)
lib/lp/services/scripts/tests/librarianformatter_noca.txt (+0/-66)
lib/lp/services/scripts/tests/raiseexception.py (+0/-35)
lib/lp/services/scripts/tests/test_librarianformatter.py (+0/-45)
lib/lp/services/scripts/tests/test_librarianformatter_noca.py (+0/-22)
lib/lp/soyuz/doc/gina-multiple-arch.txt (+3/-1)
lib/lp/soyuz/doc/gina.txt (+54/-27)
lib/lp/translations/doc/distroseries-translations-copy.txt (+1/-0)
To merge this branch: bzr merge lp:~stevenk/launchpad/destroy-librarianformatter
Reviewer Review Type Date Requested Status
Stuart Bishop (community) Approve
Review via email: mp+135311@code.launchpad.net

Commit message

Kill LibrarianFormatter, we now log the entire traceback and the OOPS id.

Description of the change

Kill LibrarianFormatter and its two doctests entirely.

The new plan is that OopsHandler will log the OOPS created (at level INFO) after it has done so.

With a script raising an uncaught Exception:

2012-11-21 03:36:40 ERROR Unhandled exception
2012-11-21 03:36:40 INFO OOPS-432e7c3e29181f82f8352b061429d202

And with a script logging something at ERROR:

2012-11-21 03:38:22 ERROR Causing OOPS
2012-11-21 03:38:22 INFO OOPS-ba8ec0f55e9b71f94ce43b65eee2d6c5

I have removed the catch-all exception from cronscripts/expire-bugtasks.py since now OopsHandler will now deal with it. I have also checked the other scripts in cronscripts/*, and none of them use a catch-all exception.

To post a comment you must log in.
Revision history for this message
Stuart Bishop (stub) wrote :

Looks good.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'cronscripts/expire-bugtasks.py'
2--- cronscripts/expire-bugtasks.py 2012-01-01 03:14:54 +0000
3+++ cronscripts/expire-bugtasks.py 2012-11-22 00:17:20 +0000
4@@ -1,10 +1,8 @@
5 #!/usr/bin/python -S
6 #
7-# Copyright 2009 Canonical Ltd. This software is licensed under the
8+# Copyright 2009-2012 Canonical Ltd. This software is licensed under the
9 # GNU Affero General Public License version 3 (see the file LICENSE).
10
11-# pylint: disable-msg=C0103,W0403
12-
13 """Expire all old, Incomplete bugs tasks that are unassigned in Malone.
14
15 Only bug task for project that use Malone may be expired. The expiration
16@@ -47,16 +45,9 @@
17 # Avoid circular import.
18 from lp.registry.interfaces.distribution import IDistributionSet
19 target = getUtility(IDistributionSet).getByName('ubuntu')
20- try:
21- janitor = BugJanitor(
22- log=self.logger, target=target, limit=self.options.limit)
23- janitor.expireBugTasks(self.txn)
24- except Exception:
25- # We use a catchall here because we don't know (and don't care)
26- # about the particular error--we'll just log it to as an Oops.
27- self.logger.error(
28- 'An error occured trying to expire bugtasks.', exc_info=1)
29- raise
30+ janitor = BugJanitor(
31+ log=self.logger, target=target, limit=self.options.limit)
32+ janitor.expireBugTasks(self.txn)
33
34
35 if __name__ == '__main__':
36
37=== modified file 'lib/lp/hardwaredb/doc/hwdb-submission.txt'
38--- lib/lp/hardwaredb/doc/hwdb-submission.txt 2011-12-30 01:48:17 +0000
39+++ lib/lp/hardwaredb/doc/hwdb-submission.txt 2012-11-22 00:17:20 +0000
40@@ -273,6 +273,7 @@
41 INFO Creating lockfile: /var/lock/launchpad-hwdbsubmissions.lock
42 ERROR Parsing submission test_submission_id_1: syntax error:
43 line 1, column 0
44+ INFO OOPS-...
45 INFO Processed 0 valid and 1 invalid HWDB submissions
46 <BLANKLINE>
47 >>> print out
48@@ -308,7 +309,9 @@
49 >>> print err
50 INFO Creating lockfile: /var/lock/launchpad-hwdbsubmissions.lock
51 ERROR Parsing submission unique-id-1: syntax error: line 1, column 0
52+ INFO OOPS-...
53 INFO Processed 1 valid and 1 invalid HWDB submissions
54+ <BLANKLINE>
55 >>> print out
56 <BLANKLINE>
57
58
59=== modified file 'lib/lp/services/scripts/base.py'
60--- lib/lp/services/scripts/base.py 2012-06-29 08:40:05 +0000
61+++ lib/lp/services/scripts/base.py 2012-11-22 00:17:20 +0000
62@@ -1,4 +1,4 @@
63-# Copyright 2009-2011 Canonical Ltd. This software is licensed under the
64+# Copyright 2009-2012 Canonical Ltd. This software is licensed under the
65 # GNU Affero General Public License version 3 (see the file LICENSE).
66
67 __metaclass__ = type
68@@ -384,8 +384,7 @@
69 """
70 self.lock_or_die(blocking=blocking)
71 try:
72- self.run(
73- use_web_security=use_web_security, isolation=isolation)
74+ self.run(use_web_security=use_web_security, isolation=isolation)
75 finally:
76 self.unlock(skip_delete=skip_delete)
77
78@@ -413,7 +412,8 @@
79 # self.name is used instead of the name argument, since it may have
80 # have been overridden by command-line parameters or by
81 # overriding the name property.
82- logging.getLogger().addHandler(OopsHandler(self.name))
83+ oops_hdlr = OopsHandler(self.name, logger=self.logger)
84+ logging.getLogger().addHandler(oops_hdlr)
85
86 def get_last_activity(self):
87 """Return the last activity, if any."""
88
89=== modified file 'lib/lp/services/scripts/doc/launchpad-scripts.txt'
90--- lib/lp/services/scripts/doc/launchpad-scripts.txt 2011-12-29 05:29:36 +0000
91+++ lib/lp/services/scripts/doc/launchpad-scripts.txt 2012-11-22 00:17:20 +0000
92@@ -28,12 +28,16 @@
93 >>> print p.communicate()[0]
94 INFO Creating lockfile: ...
95 WARNING This is a warning
96+ INFO None
97 INFO New OOPS detected
98 CRITICAL This is critical
99+ INFO None
100 INFO New OOPS detected
101 ERROR Unhandled exception
102 ...
103 NotImplementedError: Whoops
104+ INFO None
105+ <BLANKLINE>
106 >>> p.returncode
107 1
108
109
110=== modified file 'lib/lp/services/scripts/logger.py'
111--- lib/lp/services/scripts/logger.py 2012-10-12 11:49:10 +0000
112+++ lib/lp/services/scripts/logger.py 2012-11-22 00:17:20 +0000
113@@ -1,8 +1,6 @@
114-# Copyright 2009-2011 Canonical Ltd. This software is licensed under the
115+# Copyright 2009-2012 Canonical Ltd. This software is licensed under the
116 # GNU Affero General Public License version 3 (see the file LICENSE).
117
118-# pylint: disable-msg=W0702
119-
120 """Logging setup for scripts.
121
122 Don't import from this module. Import it from lp.services.scripts.
123@@ -10,7 +8,7 @@
124
125 __metaclass__ = type
126
127-# Don't import stuff from this module. Import it from canonical.scripts
128+# Don't import stuff from this module. Import it from lp.services.scripts
129 __all__ = [
130 'DEBUG2',
131 'DEBUG3',
132@@ -30,9 +28,6 @@
133
134
135 from contextlib import contextmanager
136-from cStringIO import StringIO
137-from datetime import timedelta
138-import hashlib
139 import logging
140 from logging.handlers import WatchedFileHandler
141 from optparse import OptionParser
142@@ -42,19 +37,10 @@
143 import time
144 from traceback import format_exception_only
145
146-from zope.component import getUtility
147 from zope.exceptions.log import Formatter
148
149 from lp.services.config import config
150-from lp.services.librarian.interfaces.client import (
151- ILibrarianClient,
152- UploadFailed,
153- )
154 from lp.services.log import loglevels
155-from lp.services.utils import (
156- compress_hash,
157- utc_now,
158- )
159 from lp.services.webapp.errorlog import (
160 globalErrorUtility,
161 ScriptRequest,
162@@ -75,12 +61,13 @@
163 class OopsHandler(logging.Handler):
164 """Handler to log to the OOPS system."""
165
166- def __init__(self, script_name, level=logging.WARN):
167+ def __init__(self, script_name, level=logging.WARN, logger=None):
168 logging.Handler.__init__(self, level)
169 # Context for OOPS reports.
170 self.request = ScriptRequest(
171 [('script_name', script_name), ('path', sys.argv[0])])
172 self.setFormatter(LaunchpadFormatter())
173+ self.logger = logger
174
175 def emit(self, record):
176 """Emit a record as an OOPS."""
177@@ -91,6 +78,8 @@
178 msg = record.getMessage()
179 with globalErrorUtility.oopsMessage(msg):
180 globalErrorUtility.raising(info, self.request)
181+ if self.logger:
182+ self.logger.info(self.request.oopsid)
183 except Exception:
184 self.handleError(record)
185
186@@ -110,59 +99,6 @@
187 self.converter = time.gmtime
188
189
190-class LibrarianFormatter(LaunchpadFormatter):
191- """A logging.Formatter that stores tracebacks in the Librarian and emits
192- a URL rather than emitting the traceback directly.
193-
194- The traceback will be emitted as a fallback if the Librarian cannot be
195- contacted.
196-
197- XXX bug=641103 StuartBishop -- This class should die. Remove it and
198- replace with LaunchpadFormatter, fixing the test fallout.
199- """
200-
201- def formatException(self, ei):
202- """Format the exception and store it in the Librian.
203-
204- Returns the URL, or the formatted exception if the Librarian is
205- not available.
206- """
207- traceback = LaunchpadFormatter.formatException(self, ei)
208- # Uncomment this line to stop exception storage in the librarian.
209- # Useful for debugging tests.
210- # return traceback
211- try:
212- librarian = getUtility(ILibrarianClient)
213- except LookupError:
214- return traceback
215-
216- exception_string = ''
217- try:
218- exception_string = str(ei[1]).encode('ascii')
219- except:
220- pass
221- if not exception_string:
222- exception_string = ei[0].__name__
223-
224- expiry = utc_now() + timedelta(days=90)
225- try:
226- filename = compress_hash(hashlib.sha1(traceback)) + '.txt'
227- url = librarian.remoteAddFile(
228- filename, len(traceback), StringIO(traceback),
229- 'text/plain;charset=%s' % sys.getdefaultencoding(),
230- expires=expiry)
231- return ' -> %s (%s)' % (url, exception_string)
232- except UploadFailed:
233- return traceback
234- except Exception:
235- # Exceptions raised by the Formatter get swallowed, but we want
236- # to know about them. Since we are already spitting out exception
237- # information, we can stuff our own problems in there too.
238- return '%s\n\nException raised in formatter:\n%s\n' % (
239- traceback,
240- LaunchpadFormatter.formatException(self, sys.exc_info()))
241-
242-
243 class LogLevelNudger:
244 """Callable to adjust the global log level.
245
246@@ -393,9 +329,8 @@
247 root_logger.removeHandler(hdlr)
248
249
250-def _logger(
251- level, out_stream, name=None,
252- log_file=None, log_file_level=logging.DEBUG, milliseconds=False):
253+def _logger(level, out_stream, name=None, log_file=None,
254+ log_file_level=logging.DEBUG, milliseconds=False):
255 """Create the actual logger instance, logging at the given level
256
257 if name is None, it will get args[0] without the extension (e.g. gina).
258@@ -425,10 +360,10 @@
259 hdlr.setLevel(level)
260 if milliseconds:
261 # Python default datefmt includes milliseconds.
262- formatter = LibrarianFormatter(datefmt=None)
263+ formatter = LaunchpadFormatter(datefmt=None)
264 else:
265 # Launchpad default datefmt does not include milliseconds.
266- formatter = LibrarianFormatter()
267+ formatter = LaunchpadFormatter()
268 hdlr.setFormatter(formatter)
269 root_logger.addHandler(hdlr)
270
271
272=== removed file 'lib/lp/services/scripts/tests/librarianformatter.txt'
273--- lib/lp/services/scripts/tests/librarianformatter.txt 2011-12-28 17:03:06 +0000
274+++ lib/lp/services/scripts/tests/librarianformatter.txt 1970-01-01 00:00:00 +0000
275@@ -1,142 +0,0 @@
276-
277-The LibrarianFormatter works just like a normal logger.Formatter if there
278-is no Librarian available or active
279-
280->>> from lp.services.scripts.logger import LibrarianFormatter
281-
282-This is a helper to quickly construct a Logger instance with a particular
283-formatter. Each call generates a unique Logger.
284-
285->>> _count = 0
286->>> def make_logger(formatter_class):
287-... global _count
288-... _count += 1
289-... logger = logging.getLogger('log%d' % _count)
290-... output = StringIO()
291-... handler = logging.StreamHandler(output)
292-... # Note - no timestamp so we can make valid comparisons!
293-... formatter = formatter_class(fmt='%(levelname)s %(message)s')
294-... handler.setFormatter(formatter)
295-... logger.addHandler(handler)
296-... logger.setLevel(logging.DEBUG)
297-... logger.propagate = False
298-... return logger, output
299-
300-Create an exception we can reuse
301-
302->>> try:
303-... raise RuntimeError('An Exception')
304-... except RuntimeError:
305-... exception = sys.exc_info()
306-
307-Because no Librarian is running, output from the two loggers should be
308-identical. Note the overhead involved in attempting to contact the
309-Librarian is not significant.
310-
311->>> from lp.testing.layers import LibrarianLayer
312->>> LibrarianLayer.hide()
313-
314->>> from lp.services.utils import utc_now
315-
316->>> normal_log, normal_out= make_logger(logging.Formatter)
317->>> librarian_log, librarian_out = make_logger(LibrarianFormatter)
318->>> import time
319->>> start_time = time.time()
320->>> for log in (normal_log, librarian_log):
321-... log.error('Blah!', exc_info=exception)
322->>> end_time = time.time()
323->>> (end_time - start_time) < 5.0
324-True
325-
326->>> print normal_out.getvalue()
327-ERROR Blah!
328-Traceback (most recent call last):
329-...
330-RuntimeError: An Exception
331-<BLANKLINE>
332-
333->>> print librarian_out.getvalue()
334-ERROR Blah!
335-Traceback (most recent call last):
336-...
337-RuntimeError: An Exception
338-<BLANKLINE>
339-
340->>> normal_out.getvalue() == librarian_out.getvalue()
341-True
342-
343-Now if we fire up the Librarian, the LibrarianFormatter should start
344-storing tracebacks there instead, reducing the verbosity of spam from
345-cronjobs
346-
347->>> LibrarianLayer.reveal()
348->>> librarian_log, librarian_out = make_logger(LibrarianFormatter)
349->>> librarian_log.error('Oops', exc_info=exception)
350->>> print librarian_out.getvalue()
351-ERROR Oops
352- -> http://.../....txt (An Exception)
353->>> url = librarian_out.getvalue().splitlines()[-1].split()[1:2][0]
354->>> print url
355-http://.../....txt
356->>> print urlopen(url).read()
357-Traceback (most recent call last):
358- ...
359-RuntimeError: An Exception
360-
361-As the librarian commits to the test database in a subprocess, we need
362-to force the DatabaseLayer to fully tear down and restore the database
363-after this test.
364-
365->>> from lp.testing.layers import DatabaseLayer
366->>> DatabaseLayer.force_dirty_database()
367-
368-We keep exceptions from expiring for about 3 months.
369-
370->>> match = re.search('/(\d+)/', url)
371->>> alias_id = match.group(1)
372->>> from lp.services.librarian.model import LibraryFileAlias
373->>> transaction.abort() # To see db changes made by the librarian
374->>> alias = LibraryFileAlias.get(alias_id)
375->>> alias.expires > utc_now() + timedelta(days=89)
376-True
377-
378-Note that we also need to remain informative with dud exceptions, such as
379-those with a non-ASCII string representation or no string representation
380-at all
381-
382->>> librarian_log, librarian_out = make_logger(LibrarianFormatter)
383->>> class Dud(Exception):
384-... pass
385->>> try:
386-... raise Dud()
387-... except Dud:
388-... librarian_log.exception('Dud1')
389->>> try:
390-... raise Dud(u'\N{BIOHAZARD SIGN}'.encode('utf8'))
391-... except Dud:
392-... librarian_log.exception('Dud2')
393->>> print librarian_out.getvalue()
394-ERROR Dud1
395- -> http://.../....txt (Dud)
396-ERROR Dud2
397- -> http://.../....txt (Dud)
398-<BLANKLINE>
399-
400-The end result of this is to not have scripts display exceptions to
401-stderr, instead reporting URLs and greatly reducing the verbosity.
402-
403->>> script = os.path.join(this_directory, 'raiseexception.py')
404->>> import subprocess
405->>> p = subprocess.Popen([sys.executable, script], stdin=subprocess.PIPE,
406-... stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
407->>> (out, err) = p.communicate()
408->>> p.returncode
409-0
410->>> print out
411-Script Output
412-ERROR Oops
413- -> http://.../....txt (Aargh)
414-ERROR Root oops
415- -> http://.../....txt (Aargh)
416-
417-
418
419=== removed file 'lib/lp/services/scripts/tests/librarianformatter_noca.txt'
420--- lib/lp/services/scripts/tests/librarianformatter_noca.txt 2011-12-21 19:44:48 +0000
421+++ lib/lp/services/scripts/tests/librarianformatter_noca.txt 1970-01-01 00:00:00 +0000
422@@ -1,66 +0,0 @@
423->>> import logging
424->>> import sys
425->>> from cStringIO import StringIO
426-
427-The LibrarianFormatter works just like a normal logger.Formatter if there
428-is no Librarian available or active
429-
430->>> from lp.services.scripts.logger import LibrarianFormatter
431-
432-This is a helper to quickly construct a Logger instance with a particular
433-formatter. Each call generates a unique Logger.
434-
435->>> _count = 0
436->>> def make_logger(formatter_class):
437-... global _count
438-... _count += 1
439-... logger = logging.getLogger('log%d' % _count)
440-... output = StringIO()
441-... handler = logging.StreamHandler(output)
442-... # Note - no timestamp so we can make valid comparisons!
443-... formatter = formatter_class(fmt='%(levelname)s %(message)s')
444-... handler.setFormatter(formatter)
445-... logger.addHandler(handler)
446-... logger.setLevel(logging.DEBUG)
447-... return logger, output
448-
449-Now setup two identical Logger instances except for their formatter
450-
451->>> normal_log, normal_out = make_logger(logging.Formatter)
452->>> librarian_log, librarian_out = make_logger(LibrarianFormatter)
453-
454-Output from the standard formatter should match the output from
455-LibrianFormatter at this stage, as we have no component architecture
456-loaded and no Librarian running.
457-
458-First, create an exception we can reuse
459-
460->>> try:
461-... raise RuntimeError('An Exception')
462-... except RuntimeError:
463-... exception = sys.exc_info()
464-... for log in (normal_log, librarian_log):
465-... log.info('Some crap')
466-... log.error('Oops!', exc_info=exception)
467-... log.error('Error %d occurred', 42)
468->>> normal_out.getvalue() == librarian_out.getvalue()
469-True
470->>> print normal_out.getvalue()
471-INFO Some crap
472-ERROR Oops!
473-Traceback (most recent call last):
474- File "<doctest librarianformatter_noca.txt[...]>", line 2, in <module>
475- raise RuntimeError('An Exception')
476-RuntimeError: An Exception
477-ERROR Error 42 occurred
478-<BLANKLINE>
479->>> print librarian_out.getvalue()
480-INFO Some crap
481-ERROR Oops!
482-Traceback (most recent call last):
483- File "<doctest librarianformatter_noca.txt[...]>", line 2, in <module>
484- raise RuntimeError('An Exception')
485-RuntimeError: An Exception
486-ERROR Error 42 occurred
487-<BLANKLINE>
488-
489
490=== removed file 'lib/lp/services/scripts/tests/raiseexception.py'
491--- lib/lp/services/scripts/tests/raiseexception.py 2011-12-21 20:23:01 +0000
492+++ lib/lp/services/scripts/tests/raiseexception.py 1970-01-01 00:00:00 +0000
493@@ -1,35 +0,0 @@
494-# Copyright 2009 Canonical Ltd. This software is licensed under the
495-# GNU Affero General Public License version 3 (see the file LICENSE).
496-
497-"""This script is called from librarianformatter.txt to
498-demonstrate a script using the LibrarianFormatter
499-"""
500-
501-__metaclass__ = type
502-
503-import logging
504-from optparse import OptionParser
505-import sys
506-
507-from lp.services.scripts import (
508- execute_zcml_for_scripts,
509- logger,
510- logger_options,
511- )
512-
513-
514-if __name__ == '__main__':
515- parser = OptionParser()
516- logger_options(parser)
517- (options, args) = parser.parse_args()
518- log = logger(options)
519- # Test the root logger too, because some code is using it
520- root_log = logging.getLogger()
521- execute_zcml_for_scripts()
522- print >> sys.stderr, 'Script Output'
523- try:
524- raise RuntimeError('Aargh')
525- except RuntimeError:
526- log.exception('Oops')
527- root_log.exception('Root oops')
528-
529
530=== removed file 'lib/lp/services/scripts/tests/test_librarianformatter.py'
531--- lib/lp/services/scripts/tests/test_librarianformatter.py 2011-12-28 17:03:06 +0000
532+++ lib/lp/services/scripts/tests/test_librarianformatter.py 1970-01-01 00:00:00 +0000
533@@ -1,45 +0,0 @@
534-# Copyright 2009 Canonical Ltd. This software is licensed under the
535-# GNU Affero General Public License version 3 (see the file LICENSE).
536-
537-"""Module docstring goes here."""
538-
539-__metaclass__ = type
540-
541-from datetime import (
542- datetime,
543- timedelta,
544- )
545-import logging
546-import os.path
547-import re
548-from StringIO import StringIO
549-import sys
550-import time
551-from urllib2 import urlopen
552-
553-from pytz import utc
554-import transaction
555-
556-from lp.testing import (
557- ANONYMOUS,
558- login,
559- logout,
560- )
561-from lp.testing.layers import LaunchpadFunctionalLayer
562-from lp.testing.systemdocs import LayeredDocFileSuite
563-
564-
565-this_directory = os.path.dirname(__file__)
566-
567-def setUp(test):
568- # Suck this modules environment into the test environment
569- test.globs.update(globals())
570- login(ANONYMOUS)
571-
572-def tearDown(test):
573- logout()
574-
575-def test_suite():
576- return LayeredDocFileSuite(
577- 'librarianformatter.txt', setUp=setUp, tearDown=tearDown,
578- layer=LaunchpadFunctionalLayer)
579
580=== removed file 'lib/lp/services/scripts/tests/test_librarianformatter_noca.py'
581--- lib/lp/services/scripts/tests/test_librarianformatter_noca.py 2011-12-28 17:03:06 +0000
582+++ lib/lp/services/scripts/tests/test_librarianformatter_noca.py 1970-01-01 00:00:00 +0000
583@@ -1,22 +0,0 @@
584-# Copyright 2009 Canonical Ltd. This software is licensed under the
585-# GNU Affero General Public License version 3 (see the file LICENSE).
586-
587-"""Python harness for librarianformatter_noca.txt."""
588-
589-__metaclass__ = type
590-
591-from lp.testing import reset_logging
592-from lp.testing.systemdocs import LayeredDocFileSuite
593-
594-
595-def setUp(test):
596- # Suck this modules environment into the test environment
597- reset_logging()
598-
599-def tearDown(test):
600- reset_logging()
601-
602-def test_suite():
603- return LayeredDocFileSuite(
604- 'librarianformatter_noca.txt',
605- setUp=setUp, tearDown=tearDown, stdout_logging=False)
606
607=== modified file 'lib/lp/soyuz/doc/gina-multiple-arch.txt'
608--- lib/lp/soyuz/doc/gina-multiple-arch.txt 2012-07-06 19:53:17 +0000
609+++ lib/lp/soyuz/doc/gina-multiple-arch.txt 2012-11-22 00:17:20 +0000
610@@ -93,7 +93,9 @@
611 >>> print proc.stderr.read()
612 WARNING ...
613 ERROR Database setup required for run on powerpc
614- -> http://... (Unable to find a processor...dapper/powerpc)
615+ Traceback (most recent call last):
616+ ...
617+ DataSetupError: Unable to find a processor from the processor family...
618 <BLANKLINE>
619 >>> proc.wait()
620 1
621
622=== modified file 'lib/lp/soyuz/doc/gina.txt'
623--- lib/lp/soyuz/doc/gina.txt 2012-07-06 19:53:17 +0000
624+++ lib/lp/soyuz/doc/gina.txt 2012-11-22 00:17:20 +0000
625@@ -140,41 +140,54 @@
626
627 >>> print proc.stderr.read()
628 ERROR Error processing package files for clearlooks
629- -> http://...Error 2 unpacking source)
630+ ...
631+ ExecutionError: Error 2 unpacking source
632 WARNING Invalid format in db1-compat, assumed '1.0'
633 WARNING Source package ed lacks section, assumed 'misc'
634 ERROR Unable to create SourcePackageData for mkvmlinuz
635- -> http://...version: None)
636+ ...
637+ InvalidVersionError: mkvmlinuz has an invalid version: None
638 WARNING Invalid urgency in python-pam, None, assumed 'low'
639 ERROR Error processing package files for util-linux
640- -> http://...dsc not in archive)
641+ ...
642+ PoolFileNotFound: File util-linux_2.12p-2ubuntu2.2.dsc not in archive
643 ERROR Error processing package files for bsdutils
644- -> http://...deb not found)
645+ ...
646+ PoolFileNotFound: .../bsdutils_2.12p-2ubuntu2_i386.deb not found
647 WARNING Binary package ed lacks valid priority, assumed 'extra'
648 ERROR Unable to create BinaryPackageData for mount
649- -> http://...invalid version...)
650+ ...
651+ InvalidVersionError: mount has an invalid version: -ewePP2.12p-2ubuntu2
652 WARNING Binary package python-pam lacks a section, assumed 'misc'
653 ERROR Error processing package files for python2.4-pam
654- -> http://...deb not found)
655+ ...
656+ PoolFileNotFound: .../python2.4-pam_0.4.2-10.1ubuntu3_i386.deb not found
657 ERROR Error processing package files for python2.4-sqlite
658- -> http://...deb not found)
659+ ...
660+ PoolFileNotFound: .../python2.4-sqlite_1.0.1-1ubuntu1_i386.deb not found
661 WARNING No source package rioutil (1.4.4-1.0.1) listed for rioutil (1.4.4-1.0.1), scrubbing archive...
662 WARNING Nope, couldn't find it. Could it be a bin-only-NMU? Checking...
663 ERROR Error processing package files for util-linux
664- -> http://...deb not found)
665+ ...
666+ PoolFileNotFound: .../util-linux_2.12p-2ubuntu2_i386.deb not found
667 ERROR Unable to create BinaryPackageData for util-linux-locales
668- -> http://...installed_size'])
669+ ...
670+ MissingRequiredArguments: ['installed_size']
671 ERROR Invalid Sources stanza in /tmp/tmp...
672- -> http://...bogus\n')
673+ ...
674+ KeyError: 'Bogus, bogus, bogus\n'
675 WARNING No changelog file found for mkvmlinuz in mkvmlinuz-14ubuntu1
676 WARNING No copyright file found for mkvmlinuz in mkvmlinuz-14ubuntu1
677 WARNING Invalid urgency in mkvmlinuz, None, assumed 'low'
678 ERROR Error processing package files for python-sqlite
679- -> http://...dsc not in archive)
680+ ...
681+ PoolFileNotFound: File python-sqlite_1.0.1-2ubuntu1.dsc not in archive
682 ERROR Error processing package files for util-linux
683- -> http://...dsc not in archive)
684+ ...
685+ PoolFileNotFound: File util-linux_2.12p-6ubuntu5.dsc not in archive
686 ERROR Error processing package files for python-sqlite
687- -> http://...deb not found)
688+ ...
689+ PoolFileNotFound: .../python-sqlite_1.0.1-2ubuntu1_all.deb not found
690 WARNING No source package ubuntu-meta (0.80) listed for ubuntu-base (0.80), scrubbing archive...
691 <BLANKLINE>
692
693@@ -515,34 +528,47 @@
694 >>> proc = subprocess.Popen(gina_proc, stderr=subprocess.PIPE)
695 >>> print proc.stderr.read()
696 ERROR Error processing package files for clearlooks
697- -> http://...Error 2 unpacking source)
698+ ...
699+ ExecutionError: Error 2 unpacking source
700 WARNING Source package ed lacks section, assumed 'misc'
701 ERROR Unable to create SourcePackageData for mkvmlinuz
702- -> http://...version: None)
703+ ...
704+ InvalidVersionError: mkvmlinuz has an invalid version: None
705 ERROR Error processing package files for util-linux
706- -> http://...dsc not in archive)
707+ ...
708+ PoolFileNotFound: File util-linux_2.12p-2ubuntu2.2.dsc not in archive
709 ERROR Error processing package files for bsdutils
710- -> http://...deb not found)
711+ ...
712+ PoolFileNotFound: .../bsdutils_2.12p-2ubuntu2_i386.deb not found
713 WARNING Binary package ed lacks valid priority, assumed 'extra'
714 ERROR Unable to create BinaryPackageData for mount
715- -> http://...invalid version...)
716+ ...
717+ InvalidVersionError: mount has an invalid version: -ewePP2.12p-2ubuntu2
718 WARNING Binary package python-pam lacks a section, assumed 'misc'
719 ERROR Error processing package files for python2.4-pam
720- -> http://...deb not found)
721+ ...
722+ PoolFileNotFound: .../python2.4-pam_0.4.2-10.1ubuntu3_i386.deb not found
723 ERROR Error processing package files for python2.4-sqlite
724- -> http://...deb not found)
725+ ...
726+ PoolFileNotFound: .../python2.4-sqlite_1.0.1-1ubuntu1_i386.deb not found
727 ERROR Error processing package files for util-linux
728- -> http://...deb not found)
729+ ...
730+ PoolFileNotFound: .../util-linux_2.12p-2ubuntu2_i386.deb not found
731 ERROR Unable to create BinaryPackageData for util-linux-locales
732- -> http://...installed_size'])
733+ ...
734+ MissingRequiredArguments: ['installed_size']
735 ERROR Invalid Sources stanza in /tmp/tmp...
736- -> http://...bogus\n')
737+ ...
738+ KeyError: 'Bogus, bogus, bogus\n'
739 ERROR Error processing package files for python-sqlite
740- -> http://...dsc not in archive)
741+ ...
742+ PoolFileNotFound: File python-sqlite_1.0.1-2ubuntu1.dsc not in archive
743 ERROR Error processing package files for util-linux
744- -> http://...dsc not in archive)
745+ ...
746+ PoolFileNotFound: File util-linux_2.12p-6ubuntu5.dsc not in archive
747 ERROR Error processing package files for python-sqlite
748- -> http://...deb not found)
749+ ...
750+ PoolFileNotFound: .../python-sqlite_1.0.1-2ubuntu1_all.deb not found
751 <BLANKLINE>
752 >>> proc.wait()
753 0
754@@ -787,7 +813,8 @@
755 >>> proc = subprocess.Popen(gina_proc, stderr=subprocess.PIPE)
756 >>> print proc.stderr.read()
757 ERROR Failed to analyze archive for bogoland
758- -> http://...)
759+ ...
760+ MangledArchiveError: No archive directory for bogoland/main
761 <BLANKLINE>
762 >>> proc.wait()
763 1
764
765=== modified file 'lib/lp/translations/doc/distroseries-translations-copy.txt'
766--- lib/lp/translations/doc/distroseries-translations-copy.txt 2012-05-05 06:08:43 +0000
767+++ lib/lp/translations/doc/distroseries-translations-copy.txt 2012-11-22 00:17:20 +0000
768@@ -201,6 +201,7 @@
769 defer_translation_imports flags for distribution foobuntu, series
770 darty; or use the --force option to make it happen
771 automatically.
772+ INFO OOPS-...
773 <BLANKLINE>
774
775 >>> transaction.abort()