From 9dd04a43bab20f2ee30e8b3d3a625704941d900e Mon Sep 17 00:00:00 2001 From: Stefano Rivera Date: Tue, 21 Dec 2010 12:26:00 +0200 Subject: [PATCH 01/17] requestsync: Convert the space-indented lines to tabs --- requestsync | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/requestsync b/requestsync index ed4af7f..9d89fab 100755 --- a/requestsync +++ b/requestsync @@ -146,7 +146,7 @@ if __name__ == '__main__': print >> sys.stderr, "E: %s" % e sys.exit(1) - # Stop if Ubuntu has already the version from Debian or a newer version + # Stop if Ubuntu has already the version from Debian or a newer version if (ubuntu_version >= debian_version) and options.lpapi: # try rmadison import ubuntutools.requestsync.mail @@ -162,10 +162,10 @@ if __name__ == '__main__': print >> sys.stderr, \ 'E: The versions in Debian and Ubuntu are the same already (%s). Aborting.' % ubuntu_version sys.exit(1) - if ubuntu_version > debian_version: - print >> sys.stderr, \ - 'E: The version in Ubuntu (%s) is newer than the version in Debian (%s). Aborting.' % (ubuntu_version, debian_version) - sys.exit(1) + if ubuntu_version > debian_version: + print >> sys.stderr, \ + 'E: The version in Ubuntu (%s) is newer than the version in Debian (%s). Aborting.' % (ubuntu_version, debian_version) + sys.exit(1) # -s flag not specified - check if we do need sponsorship if not sponsorship: From b1b1e5e3324ac4474544f1f87222609ed8afa45f Mon Sep 17 00:00:00 2001 From: Stefano Rivera Date: Tue, 21 Dec 2010 12:32:33 +0200 Subject: [PATCH 02/17] requestsync: Style: named parameters shouldn't have spaces around = --- requestsync | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/requestsync b/requestsync index 9d89fab..d554244 100755 --- a/requestsync +++ b/requestsync @@ -41,31 +41,31 @@ from ubuntutools.requestsync.common import (edit_report, getDebianChangelog, if __name__ == '__main__': # Our usage options. - usage = 'Usage: %prog [-d distro] [-k keyid] [-n] [--lp] [-s] [-e] ' \ + usage = 'Usage: %prog [options] ' \ ' [ [base version]]' optParser = OptionParser(usage) - optParser.add_option('-d', type = 'string', - dest = 'dist', default = 'unstable', - help = 'Debian distribution to sync from.') - optParser.add_option('-k', type = 'string', - dest = 'keyid', default = None, - help = 'GnuPG key ID to use for signing report (only used when emailing the sync request).') - optParser.add_option('-n', action = 'store_true', - dest = 'newpkg', default = False, - help = 'Whether package to sync is a new package in Ubuntu.') - optParser.add_option('--lp', action = 'store_true', - dest = 'lpapi', default = False, - help = 'Specify whether to use the LP API for filing the sync request (recommended).') - optParser.add_option('-s', action = 'store_true', - dest = 'sponsorship', default = False, - help = 'Force sponsorship') - optParser.add_option('-C', action = 'store_true', - dest = 'missing_changelog_ok', default = False, - help = 'Allow changelog to be manually filled in when missing') - optParser.add_option('-e', action = 'store_true', - dest = 'ffe', default = False, - help = 'Use this after FeatureFreeze for non-bug fix syncs, changes ' \ + optParser.add_option('-d', type='string', + dest='dist', default='unstable', + help='Debian distribution to sync from.') + optParser.add_option('-k', type='string', + dest='keyid', default=None, + help='GnuPG key ID to use for signing report (only used when emailing the sync request).') + optParser.add_option('-n', action='store_true', + dest='newpkg', default=False, + help='Whether package to sync is a new package in Ubuntu.') + optParser.add_option('--lp', action='store_true', + dest='lpapi', default=False, + help='Specify whether to use the LP API for filing the sync request (recommended).') + optParser.add_option('-s', action='store_true', + dest='sponsorship', default=False, + help='Force sponsorship') + optParser.add_option('-C', action='store_true', + dest='missing_changelog_ok', default=False, + help='Allow changelog to be manually filled in when missing') + optParser.add_option('-e', action='store_true', + dest='ffe', default=False, + help='Use this after FeatureFreeze for non-bug fix syncs, changes ' \ 'default subscription to the appropriate release team.') (options, args) = optParser.parse_args() From 8dd88f18f81db42172ae7679eeaefea328cce33d Mon Sep 17 00:00:00 2001 From: Stefano Rivera Date: Tue, 21 Dec 2010 12:59:45 +0200 Subject: [PATCH 03/17] Forgot EMAIL --- ubuntutools/config.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ubuntutools/config.py b/ubuntutools/config.py index 06a4c36..0c4d1bb 100644 --- a/ubuntutools/config.py +++ b/ubuntutools/config.py @@ -106,7 +106,7 @@ def ubu_email(name=None, email=None, export=True): """Find the developer's Ubuntu e-mail address, and export it in DEBFULLNAME, DEBEMAIL if necessary (and export isn't False). - e-mail Priority: arguments, UBUMAIL, DEBEMAIL, user@mailname + e-mail Priority: arguments, UBUMAIL, DEBEMAIL, EMAIL, user@mailname name Priority: arguments, UBUMAIL, DEBFULLNAME, DEBEMAIL, NAME, /etc/passwd Name and email are only exported if provided as arguments or found in @@ -129,6 +129,7 @@ def ubu_email(name=None, email=None, export=True): for var, target in (('UBUMAIL', 'email'), ('DEBFULLNAME', 'name'), ('DEBEMAIL', 'email'), + ('EMAIL', 'email'), ('NAME', 'name'), ): if name and email: From 7977a367fd5ef5e230443b92dd4065e9bd344089 Mon Sep 17 00:00:00 2001 From: Stefano Rivera Date: Tue, 21 Dec 2010 15:14:45 +0200 Subject: [PATCH 04/17] Rename --launchpad to --lpinstance --- backportpackage | 10 +++++----- doc/backportpackage.1 | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/backportpackage b/backportpackage index d9d12af..442a2a8 100755 --- a/backportpackage +++ b/backportpackage @@ -98,8 +98,8 @@ def parse(args): default=None, help='Specify a working directory (default: temporary dir)', metavar='WORKDIR') - p.add_option('-l', '--launchpad', - dest='launchpad', + p.add_option('--lpinstance', + dest='lpinstance', default=None, help='Launchpad instance to connect to (default: production)', metavar='INSTANCE') @@ -119,8 +119,8 @@ def parse(args): opts.update = config.get_value('UPDATE_BUILDER', boolean=True) if opts.workdir is None: opts.workdir = config.get_value('WORKDIR') - if opts.launchpad is None: - opts.launchpad = config.get_value('LPINSTANCE') + if opts.lpinstance is None: + opts.lpinstance = config.get_value('LPINSTANCE') if not opts.upload and not opts.workdir: p.error('Please specify either a working dir or an upload target!') @@ -276,7 +276,7 @@ def main(args): script_name = os.path.basename(sys.argv[0]) lp = launchpadlib.launchpad.Launchpad.login_anonymously(script_name, - opts.launchpad) + opts.lpinstance) if not opts.dest_releases: try: diff --git a/doc/backportpackage.1 b/doc/backportpackage.1 index f00e352..265d716 100644 --- a/doc/backportpackage.1 +++ b/doc/backportpackage.1 @@ -80,7 +80,7 @@ unpacked, built into, and otherwise manipulated in \fIWORKDIR\fR. Otherwise, a temporary directory is created, which is deleted before \fIbackportpackage\fR exits. .TP -.B \-l \fIINSTANCE\fR, \fB\-\-launchpad\fR=\fIINSTANCE\fR +.B \-\-lpinstance\fR=\fIINSTANCE\fR Use the specified instance of Launchpad (e.g. "staging"), instead of the default of "production". .TP @@ -109,7 +109,7 @@ The default value for \fB--update\fR. The default value for \fB--workdir\fR. .TP .BR BACKPORTPACKAGE_LPINSTANCE ", " UBUNTUTOOLS_LPINSTANCE -The default value for \fB--launchpad\fR. +The default value for \fB--lpinstance\fR. .SH EXAMPLES Test-build in your PPA a backport of znc from the current development release to your workstation's release, deleting the build products From 660209473b33e67158d67e2dd46a447a330042f2 Mon Sep 17 00:00:00 2001 From: Stefano Rivera Date: Tue, 21 Dec 2010 15:25:05 +0200 Subject: [PATCH 05/17] GPGKEY is not a supported environment variable --- doc/requestsync.1 | 5 ----- 1 file changed, 5 deletions(-) diff --git a/doc/requestsync.1 b/doc/requestsync.1 index 1908f05..0134fe2 100644 --- a/doc/requestsync.1 +++ b/doc/requestsync.1 @@ -52,8 +52,6 @@ attempt to look it up in Ubuntu since it will not exist. .TP .B \-k \fI\fR Specifies your GPG key. -Can also be set with the line `\fIexport GPGKEY=\fR' in your shell's -configuration (for example: \fI$HOME/.bashrc\fR). This is only used if the sync request is mailed to Launchpad. .TP .B \-\-lp @@ -87,9 +85,6 @@ Specify this option in this case. shell's configuration by adding \fIexport VARIABLE=\fR lines, where VARIABLE is one of the following: -.TP -.B GPGKEY -Specifies your GnuPG key ID. .TP .B DEBEMAIL Specifies which email should be used when sending to Launchpad. From 82eab1c349f5da105743d2b186e6539e26572762 Mon Sep 17 00:00:00 2001 From: Stefano Rivera Date: Tue, 21 Dec 2010 17:02:36 +0200 Subject: [PATCH 06/17] Config file support in requestsync --- doc/requestsync.1 | 35 +++++++++++++++++++++------ requestsync | 43 +++++++++++++++++++++++++++++---- ubuntutools/requestsync/lp.py | 2 +- ubuntutools/requestsync/mail.py | 36 ++++++++------------------- 4 files changed, 77 insertions(+), 39 deletions(-) diff --git a/doc/requestsync.1 b/doc/requestsync.1 index 0134fe2..ff9d7c7 100644 --- a/doc/requestsync.1 +++ b/doc/requestsync.1 @@ -67,6 +67,14 @@ This disables the upload permissions check described above. Use this flag after FeatureFreeze for non-bug fix syncs. \fBrequestsync\fR will subscribe ubuntu-release team instead of sponsorship team. .TP +.B \-\-lpinstance\fR=\fIINSTANCE\fR +Use the specified instance of Launchpad (e.g. "staging"), instead of +the default of "production". +.TP +.B \-\-no\-conf +Do not read any configuration files, or configuration from environment +variables. +.TP .B This is the source package that you would like to be synced from Debian. .TP @@ -80,27 +88,40 @@ In some cases, the base version (where the Ubuntu package started differing from the Debian package) cannot be automatically determined. Specify this option in this case. -.SH ENVIRONMENT VARIABLES +.SH ENVIRONMENT \fBrequestsync\fR uses the following variables which should be set in your shell's configuration by adding \fIexport VARIABLE=\fR lines, where VARIABLE is one of the following: - .TP -.B DEBEMAIL +.BR UBUMAIL ", " DEBEMAIL Specifies which email should be used when sending to Launchpad. +.P +All of the \fBCONFIGURATION VARIABLES\fR below are also supported as +environment variables. +Variables in the environment take precedence to those in configuration +files. + +.SH CONFIGURATION VARIABLES .TP -.B DEBSMTP +.B REQUESTSYNC_SMTP_SERVER Set which SMTP server to use when sending mail. If unspecified this defaults to fiordland.ubuntu.com. .TP -.B DEBSMTP_PORT +.B REQUESTSYNC_SMTP_PORT Sets which port of the SMTP server to use. Default is 25. .TP -.B DEBSMTP_USER \fRand\fB DEBSMTP_PASS +.BR REQUESTSYNC_SMTP_USER " and " REQUESTSYNC_SMTP_PASS Sets the username and password to use when authenticating to the SMTP server. +.TP +.BR REQUESTSYNC_USE_LPAPI +Setting this to \fIyes\fR is equivalent to running with \fB--lp\fR. +.TP +.BR REQUESTSYNC_LPINSTANCE ", " UBUNTUTOOLS_LPINSTANCE +The default value for \fB--lpinstance\fR. .SH SEE ALSO -.BR rmadison (1) +.BR rmadison (1), +.BR ubuntu\-dev\-tools (5) .SH AUTHOR .B requestsync diff --git a/requestsync b/requestsync index d554244..59ef919 100755 --- a/requestsync +++ b/requestsync @@ -26,11 +26,13 @@ # # ################################################################## -import sys from optparse import OptionParser +import os +import sys + from debian.changelog import Version -# ubuntu-dev-tools modules +from ubuntutools.config import UDTConfig, ubu_email from ubuntutools.lp import udtexceptions from ubuntutools.requestsync.common import (edit_report, getDebianChangelog, raw_input_exit_on_ctrlc) @@ -57,6 +59,9 @@ if __name__ == '__main__': optParser.add_option('--lp', action='store_true', dest='lpapi', default=False, help='Specify whether to use the LP API for filing the sync request (recommended).') + optParser.add_option('--lpinstance', type='string', metavar='INSTANCE', + dest='lpinstance', default=None, + help='Launchpad instance to connect to (default: production).') optParser.add_option('-s', action='store_true', dest='sponsorship', default=False, help='Force sponsorship') @@ -67,6 +72,9 @@ if __name__ == '__main__': dest='ffe', default=False, help='Use this after FeatureFreeze for non-bug fix syncs, changes ' \ 'default subscription to the appropriate release team.') + optParser.add_option('--no-conf', action='store_true', + dest='no_conf', default=False, + help="Don't read config files or environment variables") (options, args) = optParser.parse_args() @@ -74,8 +82,19 @@ if __name__ == '__main__': optParser.print_help() sys.exit(1) + config = UDTConfig(options.no_conf) + if not options.lpapi: + options.lpapi = config.get_value('USE_LPAPI', default=False, + boolean=True) + if options.lpinstance is None: + options.lpinstance = config.get_value('LPINSTANCE') + # import the needed requestsync module if options.lpapi: + # Needs to be set before lpapicache is imported: + import ubuntutools.lp + ubuntutools.lp.service = options.lpinstance + from ubuntutools.requestsync.lp import (checkExistingReports, getDebianSrcPkg, getUbuntuSrcPkg, @@ -90,10 +109,12 @@ if __name__ == '__main__': else: from ubuntutools.requestsync.mail import (checkExistingReports, getDebianSrcPkg, - getEmailAddress, getUbuntuSrcPkg, mailBug, needSponsorship) - if not getEmailAddress(): + if not any(x in os.environ for x in ('UBUMAIL', 'DEBEMAIL', 'EMAIL')): + print >> sys.stderr, ( + 'E: The environment variable UBUMAIL, DEBEMAIL or EMAIL needs ' + 'to be set to let this script mail the sync request.') sys.exit(1) newsource = options.newpkg @@ -242,5 +263,17 @@ if __name__ == '__main__': # Post sync request using LP API postBug(srcpkg, subscribe, mapping[status], title, report) else: + email_from = ubu_email(export=False)[1] + mailserver_host = config.get_value('SMTP_SERVER', + default='fiordland.ubuntu.com', + compat_keys=['UBUSMTP', 'DEBSMTP']) + mailserver_port = config.get_value('SMTP_PORT', default=25, + compat_keys=['UBUSMTP_PORT', 'DEBSMTP_PORT']) + mailserver_user = config.get_value('SMTP_USER', + compat_keys=['UBUSMTP_USER', 'DEBSMTP_USER']) + mailserver_pass = config.get_value('SMTP_PASS', + compat_keys=['UBUSMTP_PASS', 'DEBSMTP_PASS']) # Mail sync request - mailBug(srcpkg, subscribe, status, title, report, options.keyid) + mailBug(srcpkg, subscribe, status, title, report, options.lpinstance, + options.keyid, email_from, mailserver_host, mailserver_port, + mailserver_user, mailserver_pass) diff --git a/ubuntutools/requestsync/lp.py b/ubuntutools/requestsync/lp.py index 288ffa2..9aef9be 100644 --- a/ubuntutools/requestsync/lp.py +++ b/ubuntutools/requestsync/lp.py @@ -49,7 +49,7 @@ def needSponsorship(name, component, release): itself or the component ''' archive = Distribution('ubuntu').getArchive() - distroseries = Distribution('ubuntu').getSeries(release) + distroseries = Distribution('ubuntu').getSeries(release) need_sponsor = not PersonTeam.me.canUploadPackage(archive, distroseries, name, component) if need_sponsor: diff --git a/ubuntutools/requestsync/mail.py b/ubuntutools/requestsync/mail.py index ee0dec1..f6f4b00 100644 --- a/ubuntutools/requestsync/mail.py +++ b/ubuntutools/requestsync/mail.py @@ -31,7 +31,6 @@ from ubuntutools.lp.udtexceptions import PackageNotFoundException __all__ = [ 'getDebianSrcPkg', 'getUbuntuSrcPkg', - 'getEmailAddress', 'needSponsorship', 'checkExistingReports', 'mailBug', @@ -106,18 +105,6 @@ def getDebianSrcPkg(name, release): def getUbuntuSrcPkg(name, release): return getSrcPkg('ubuntu', name, release) -def getEmailAddress(): - ''' - Get the From email address from the UBUMAIL, DEBEMAIL or EMAIL - environment variable or give an error. - ''' - myemailaddr = os.getenv('UBUMAIL') or os.getenv('DEBEMAIL') or os.getenv('EMAIL') - if not myemailaddr: - print >> sys.stderr, 'E: The environment variable UBUMAIL, ' \ - 'DEBEMAIL or EMAIL needs to be set to let this script ' \ - 'mail the sync request.' - return myemailaddr - def needSponsorship(name, component, release): ''' Ask the user if he has upload permissions for the package or the @@ -143,16 +130,20 @@ def checkExistingReports(srcpkg): 'for duplicate sync requests before continuing.' % srcpkg raw_input_exit_on_ctrlc('Press [Enter] to continue or [Ctrl-C] to abort. ') -def mailBug(srcpkg, subscribe, status, bugtitle, bugtext, keyid = None): +def mailBug(srcpkg, subscribe, status, bugtitle, bugtext, lpinstance, keyid, + myemailaddr, mailserver_host, mailserver_port, mailserver_user, + mailserver_pass): ''' Submit the sync request per email. ''' - to = 'new@bugs.launchpad.net' - - # getEmailAddress() can't fail here as the main code in requestsync - # already checks its return value - myemailaddr = getEmailAddress() + if lpinstance == 'production': + to = 'new@bugs.launchpad.net' + elif lpinstance == 'staging': + to = 'new@bugs.staging.launchpad.net' + else: + print >> sys.stderr, 'Error: Unknown launchpad instance:', lpinstance + sys.exit(1) # generate mailbody if srcpkg: @@ -195,10 +186,6 @@ Content-Type: text/plain; charset=UTF-8 print 'The final report is:\n%s' % mail raw_input_exit_on_ctrlc('Press [Enter] to continue or [Ctrl-C] to abort. ') - # get server address and port - mailserver_host = os.getenv('UBUSMTP') or os.getenv('DEBSMTP') or 'fiordland.ubuntu.com' - mailserver_port = os.getenv('UBUSMTP_PORT') or os.getenv('DEBSMTP_PORT') or 25 - # connect to the server try: print 'Connecting to %s:%s ...' % (mailserver_host, mailserver_port) @@ -208,9 +195,6 @@ Content-Type: text/plain; charset=UTF-8 (mailserver_host, mailserver_port, s[1], s[0]) return - # authenticate to the server - mailserver_user = os.getenv('UBUSMTP_USER') or os.getenv('DEBSMTP_USER') - mailserver_pass = os.getenv('UBUSMTP_PASS') or os.getenv('DEBSMTP_PASS') if mailserver_user and mailserver_pass: try: s.login(mailserver_user, mailserver_pass) From a435c3234b76c0f1e9ea5b8c6a2fa59eacb9ce29 Mon Sep 17 00:00:00 2001 From: Stefano Rivera Date: Tue, 21 Dec 2010 21:52:12 +0200 Subject: [PATCH 07/17] Use the improved staging support in lpapicache --- requestsync | 6 +----- ubuntutools/lp/lpapicache.py | 5 +++-- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/requestsync b/requestsync index 59ef919..5f4cd87 100755 --- a/requestsync +++ b/requestsync @@ -91,10 +91,6 @@ if __name__ == '__main__': # import the needed requestsync module if options.lpapi: - # Needs to be set before lpapicache is imported: - import ubuntutools.lp - ubuntutools.lp.service = options.lpinstance - from ubuntutools.requestsync.lp import (checkExistingReports, getDebianSrcPkg, getUbuntuSrcPkg, @@ -103,7 +99,7 @@ if __name__ == '__main__': # See if we have LP credentials and exit if we don't - cannot continue in this case try: - Launchpad.login() + Launchpad.login(service=options.lpinstance) except IOError: sys.exit(1) else: diff --git a/ubuntutools/lp/lpapicache.py b/ubuntutools/lp/lpapicache.py index 9de3474..9163045 100644 --- a/ubuntutools/lp/lpapicache.py +++ b/ubuntutools/lp/lpapicache.py @@ -52,11 +52,12 @@ __all__ = [ class Launchpad(object): '''Singleton for LP API access.''' - def login(self): + def login(self, service=service): '''Enforce a non-anonymous login.''' if '_Launchpad__lp' not in self.__dict__: try: - self.__lp = libsupport.get_launchpad('ubuntu-dev-tools') + self.__lp = libsupport.get_launchpad('ubuntu-dev-tools', + server=service) except IOError, error: print >> sys.stderr, 'E: %s' % error raise From 692627c7717ac2c4d86095a7396fe80c1658d59a Mon Sep 17 00:00:00 2001 From: Stefano Rivera Date: Tue, 21 Dec 2010 21:54:57 +0200 Subject: [PATCH 08/17] Restore -l --- backportpackage | 2 +- doc/backportpackage.1 | 2 +- doc/requestsync.1 | 2 +- requestsync | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/backportpackage b/backportpackage index 442a2a8..a2d7879 100755 --- a/backportpackage +++ b/backportpackage @@ -98,7 +98,7 @@ def parse(args): default=None, help='Specify a working directory (default: temporary dir)', metavar='WORKDIR') - p.add_option('--lpinstance', + p.add_option('-l', '--lpinstance', dest='lpinstance', default=None, help='Launchpad instance to connect to (default: production)', diff --git a/doc/backportpackage.1 b/doc/backportpackage.1 index 265d716..27aa012 100644 --- a/doc/backportpackage.1 +++ b/doc/backportpackage.1 @@ -80,7 +80,7 @@ unpacked, built into, and otherwise manipulated in \fIWORKDIR\fR. Otherwise, a temporary directory is created, which is deleted before \fIbackportpackage\fR exits. .TP -.B \-\-lpinstance\fR=\fIINSTANCE\fR +.B \-l \fIINSTANCE\fR, \fB\-\-lpinstance\fR=\fIINSTANCE\fR Use the specified instance of Launchpad (e.g. "staging"), instead of the default of "production". .TP diff --git a/doc/requestsync.1 b/doc/requestsync.1 index ff9d7c7..c2863e2 100644 --- a/doc/requestsync.1 +++ b/doc/requestsync.1 @@ -67,7 +67,7 @@ This disables the upload permissions check described above. Use this flag after FeatureFreeze for non-bug fix syncs. \fBrequestsync\fR will subscribe ubuntu-release team instead of sponsorship team. .TP -.B \-\-lpinstance\fR=\fIINSTANCE\fR +.B \-l \fIINSTANCE\fR, \fB\-\-lpinstance\fR=\fIINSTANCE\fR Use the specified instance of Launchpad (e.g. "staging"), instead of the default of "production". .TP diff --git a/requestsync b/requestsync index 5f4cd87..3e377a3 100755 --- a/requestsync +++ b/requestsync @@ -59,7 +59,7 @@ if __name__ == '__main__': optParser.add_option('--lp', action='store_true', dest='lpapi', default=False, help='Specify whether to use the LP API for filing the sync request (recommended).') - optParser.add_option('--lpinstance', type='string', metavar='INSTANCE', + optParser.add_option('-l', '--lpinstance', type='string', metavar='INSTANCE', dest='lpinstance', default=None, help='Launchpad instance to connect to (default: production).') optParser.add_option('-s', action='store_true', From 3f776be478fe82c0f4af3facbfb6df20ee8962fb Mon Sep 17 00:00:00 2001 From: Stefano Rivera Date: Tue, 21 Dec 2010 22:12:05 +0200 Subject: [PATCH 09/17] Config file support for ack-sync --- ack-sync | 39 +++++++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/ack-sync b/ack-sync index 19a2bfd..66c29cd 100755 --- a/ack-sync +++ b/ack-sync @@ -28,6 +28,7 @@ import logging import glob import fnmatch +from ubuntutools.config import UDTConfig from ubuntutools.lp.libsupport import get_launchpad COMMAND_LINE_SYNTAX_ERROR = 1 @@ -147,8 +148,9 @@ def unsubscribe_sponsors(launchpad, bug): def main(bug_numbers, all_package, all_version, all_section, update, - all_uploader_email, key, upload, verbose=False, silent=False): - launchpad = get_launchpad("ubuntu-dev-tools") + all_uploader_email, key, upload, lpinstance, verbose=False, + silent=False): + launchpad = get_launchpad("ubuntu-dev-tools", server=lpinstance) # TODO: use release-info (once available) series = launchpad.distributions["ubuntu"].current_series dist = series.name @@ -300,8 +302,11 @@ def usage(): -e, specify uploader email address -h, --help displays this help -k, --key key used to sign the package (in case of sponsoring) + --lpinstance= Launchpad instance to connect to + (default: production) -l, --lvm lvm root dev directory, used for sbuild and piuparts default is /dev/vg + --no-conf Don't read config files or environment variables -p, --package= set the package -P, --with-piuparts use piuparts to check the instalability --section=
Debian section (one of main, contrib, non-free) @@ -318,7 +323,7 @@ if __name__ == '__main__': try: long_opts = ["help", "key=", "lvm=", "package=", "section=", "silent", "update", "upload", "verbose", "version=", "with-sbuild", - "pbuilder=", "with-piuparts"] + "pbuilder=", "with-piuparts", "lpinstance=", "no-conf"] opts, args = getopt.gnu_getopt(sys.argv[1:], "e:hk:p:PsSC:uUvV:", long_opts) except getopt.GetoptError, e: # will print something like "option -a not recognized" @@ -335,9 +340,11 @@ if __name__ == '__main__': verbose = False version = None piuparts = False - pbuilder = 'pbuilder' + pbuilder = None lvm = "/dev/vg" key = None + lpinstance = None + no_conf = False for o, a in opts: if o in ("-h", "--help"): @@ -347,8 +354,12 @@ if __name__ == '__main__': uploader_email = a elif o in ("-k", "--key"): key = a + elif o in ("--lpinstance"): + lpinstance = a elif o in ("-l", "--lvm"): lvm = a + elif o in ("--no-conf"): + no_conf = True elif o in ("-p", "--package"): package = a elif o in ("-P", "--with-piuparts"): @@ -360,7 +371,7 @@ if __name__ == '__main__': elif o in ("-S", "--with-sbuild"): sbuild = True elif o in ("-C", "--pbuilder"): - pbuilder=a + pbuilder=a elif o in ("-u", "--update"): update = True elif o in ("-U", "--upload"): @@ -387,5 +398,21 @@ if __name__ == '__main__': sys.exit(COMMAND_LINE_SYNTAX_ERROR) bug_numbers.append(number) + config = UDTConfig(no_conf) + if lpinstance is None: + lpinstance = config.get_value('LPINSTANCE') + if pbuilder is None and not sbuild: + builder = config.get_value('BUILDER') + if builder == 'pbuilder': + pbuilder = 'pbuilder' + elif builder == 'sbuild': + sbuild = True + else: + print >> sys.stderr, "E: Unsupported build-system: %s" % builder + sys.exit(COMMAND_LINE_SYNTAX_ERROR) + if not update: + update = config.get_value('UPDATE_BUILDER', boolean=True) + #TODO: Support WORKDIR + main(bug_numbers, package, version, section, update, uploader_email, key, - upload, verbose, silent) + upload, lpinstance, verbose, silent) From eedb60b2962e1de1b76b7c8c3e50c0f5e9b2be91 Mon Sep 17 00:00:00 2001 From: Stefano Rivera Date: Tue, 21 Dec 2010 22:33:53 +0200 Subject: [PATCH 10/17] Port grab-attachments to optparse --- grab-attachments | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/grab-attachments b/grab-attachments index 4ddec36..e4c2218 100755 --- a/grab-attachments +++ b/grab-attachments @@ -18,30 +18,28 @@ # # ################################################################## +from optparse import OptionParser import os import sys + from ubuntutools.lp.libsupport import get_launchpad USAGE = "grab-attachments " def main(): - if len(sys.argv) == 1: - print >> sys.stderr, USAGE - sys.exit(1) - - if sys.argv[1] in ["--help", "-h"]: - print USAGE - sys.exit(0) + p = OptionParser('Usage: %prog [options] ') + opts, args = p.parse_args() + if len(args) < 1: + p.error('No bug numbers provided') try: launchpad = get_launchpad("ubuntu-dev-tools") - for arg in sys.argv[1:]: + for arg in args: try: number = int(arg) except: - print >> sys.stderr, "'%s' is not a valid bug number." % arg - sys.exit(1) + p.error("'%s' is not a valid bug number." % arg) b = launchpad.bugs[number] From 86facf23c2b1b2a17ada08797b1c3bfc16762415 Mon Sep 17 00:00:00 2001 From: Stefano Rivera Date: Tue, 21 Dec 2010 22:42:29 +0200 Subject: [PATCH 11/17] Config file support for grab-attachments (almost doubling its size) :P --- doc/grab-attachments.1 | 35 +++++++++++++++++++++++++++++------ grab-attachments | 15 +++++++++++++-- 2 files changed, 42 insertions(+), 8 deletions(-) diff --git a/doc/grab-attachments.1 b/doc/grab-attachments.1 index d66339e..97a71bc 100644 --- a/doc/grab-attachments.1 +++ b/doc/grab-attachments.1 @@ -2,7 +2,7 @@ .SH NAME grab\-attachments \- downloads attachments from a Launchpad bug .SH SYNOPSIS -.B grab\-attachments\fR <\fIbug-number\fR> +.B grab\-attachments\fR [\fIoptions\fR] \fIbug-number\fR... .br .B grab\-attachments \-h .SH DESCRIPTION @@ -12,13 +12,36 @@ Launchpad bug report into the current directory. .SH OPTIONS Listed below are the command line options for grab\-attachments: .TP -.B \-h -Display a help message and exit. -.TP -.B +.I bug-number Specifies the Launchpad bug number that the script should download attachments from. - +.TP +.BR \-h ", " \-\-help +Display a help message and exit. +.TP +.B \-l \fIINSTANCE\fR, \fB\-\-lpinstance\fR=\fIINSTANCE\fR +Use the specified instance of Launchpad (e.g. "staging"), instead of +the default of "production". +.TP +.B \-\-no\-conf +Do not read any configuration files, or configuration from environment +variables. +.SH ENVIRONMENT +All of the \fBCONFIGURATION VARIABLES\fR below are also supported as +environment variables. +Variables in the environment take precedence to those in configuration +files. +.SH CONFIGURATION VARIABLES +The following variables can be set in the environment or in +.BR ubuntu\-dev\-tools (5) +configuration files. +In each case, the script\-specific variable takes precedence over the +package\-wide variable. +.TP +.BR GRAB_ATTACHMENTS_LPINSTANCE ", " UBUNTUTOOLS_LPINSTANCE +The default value for \fB--lpinstance\fR. +.SH SEE ALSO +.BR ubuntu\-dev\-tools (5) .SH AUTHOR \fBgrab\-attachments\fR was written by Daniel Holbach and this manual page was written by Jonathan Patrick Davies. diff --git a/grab-attachments b/grab-attachments index e4c2218..00f46fd 100755 --- a/grab-attachments +++ b/grab-attachments @@ -1,7 +1,8 @@ #!/usr/bin/python # # Copyright (C) 2007, Canonical Ltd. -# Written by Daniel Holbach +# Written by Daniel Holbach, +# Stefano Rivera # # ################################################################## # @@ -22,18 +23,28 @@ from optparse import OptionParser import os import sys +from ubuntutools.config import UDTConfig from ubuntutools.lp.libsupport import get_launchpad USAGE = "grab-attachments " def main(): p = OptionParser('Usage: %prog [options] ') + p.add_option('-l', '--lpinstance', metavar='INSTANCE', + dest='lpinstance', default=None, + help='Launchpad instance to connect to (default: production)') + p.add_option('--no-conf', + dest='no_conf', default=False, action='store_true', + help="Don't read config files or environment variables") opts, args = p.parse_args() if len(args) < 1: p.error('No bug numbers provided') + config = UDTConfig(opts.no_conf) + if opts.lpinstance is None: + opts.lpinstance = config.get_value('LPINSTANCE') try: - launchpad = get_launchpad("ubuntu-dev-tools") + launchpad = get_launchpad("ubuntu-dev-tools", server=opts.lpinstance) for arg in args: try: From c43e9775e099e6857ea5af2e8fc83f3392427a1a Mon Sep 17 00:00:00 2001 From: Stefano Rivera Date: Wed, 22 Dec 2010 00:07:48 +0200 Subject: [PATCH 12/17] - Support this in many u-d-t scripts, and update manpages. - Deprecate old configuration environment variables. --- debian/changelog | 4 +++- ubuntutools/config.py | 15 +++++++++------ ubuntutools/test/test_config.py | 12 ++++++++++++ 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/debian/changelog b/debian/changelog index 08f8689..67082e0 100644 --- a/debian/changelog +++ b/debian/changelog @@ -11,6 +11,8 @@ ubuntu-dev-tools (0.109) UNRELEASED; urgency=low * Support reading configuration variables from devscripts configuration files. (LP: #681693) - Added ubuntu-dev-tools.5 + - Support this in many u-d-t scripts, and update manpages. + - Deprecate old configuration environment variables. * Support the combined "Name " format in UBUMAIL, DEBFULLNAME, and DEBEMAIL. (LP: #665202) * Add the beginnings of a test suite. (LP: #690386) @@ -22,7 +24,7 @@ ubuntu-dev-tools (0.109) UNRELEASED; urgency=low * ubuntutools/lp/lpapicache.py: Allow easier selection of 'staging' as LP instance to use (lp: #693060). - -- Michael Bienia Tue, 21 Dec 2010 19:14:57 +0100 + -- Stefano Rivera Wed, 22 Dec 2010 00:06:29 +0200 ubuntu-dev-tools (0.108) experimental; urgency=low diff --git a/ubuntutools/config.py b/ubuntutools/config.py index 0c4d1bb..d0e2409 100644 --- a/ubuntutools/config.py +++ b/ubuntutools/config.py @@ -21,8 +21,7 @@ import pwd import re import shlex import socket -import StringIO -import sys +from sys import argv, stderr class UDTConfig(object): """Ubuntu Dev Tools configuration file (devscripts config file) and @@ -43,7 +42,7 @@ class UDTConfig(object): def __init__(self, no_conf=False, prefix=None): self.no_conf = no_conf if prefix is None: - prefix = os.path.basename(sys.argv[0]).upper().replace('-', '_') + prefix = os.path.basename(argv[0]).upper().replace('-', '_') self.prefix = prefix if not no_conf: self.config = self.parse_devscripts_config() @@ -60,10 +59,10 @@ class UDTConfig(object): continue for line in f: parsed = shlex.split(line, comments=True) - if len(parsed) > 1 and not isinstance(f, StringIO.StringIO): - print >> sys.stderr, ( + if len(parsed) > 1: + print >> stderr, ( "W: Cannot parse variable assignment in %s: %s" - % (f.name, line)) + % (getattr(f, 'name', ''), line)) if len(parsed) >= 1 and '=' in parsed[0]: key, value = parsed[0].split('=', 1) config[key] = value @@ -98,6 +97,10 @@ class UDTConfig(object): value = value == 'yes' else: continue + if k in compat_keys: + print >> stderr, ( + 'W: Deprecated configuration variable: %s. ' + 'Replaced by %s.') % (k, key) return value return default diff --git a/ubuntutools/test/test_config.py b/ubuntutools/test/test_config.py index 2d32cf2..992edd4 100644 --- a/ubuntutools/test/test_config.py +++ b/ubuntutools/test/test_config.py @@ -17,6 +17,7 @@ import os import os.path from StringIO import StringIO +from sys import stderr import ubuntutools.config from ubuntutools.config import UDTConfig, ubu_email @@ -42,10 +43,13 @@ def fake_open(filename, mode='r'): class ConfigTestCase(unittest.TestCase): def setUp(self): ubuntutools.config.open = fake_open + ubuntutools.config.stderr = StringIO() self.cleanEnvironment() def tearDown(self): del ubuntutools.config.open + self.assertEqual(ubuntutools.config.stderr.getvalue(), '') + ubuntutools.config.stderr = stderr self.cleanEnvironment() def cleanEnvironment(self): @@ -82,6 +86,10 @@ REPEAT=yes 'INHERIT': 'user', 'REPEAT': 'yes', }) + errs = ubuntutools.config.stderr.getvalue().strip() + ubuntutools.config.stderr = StringIO() + self.assertEqual(len(errs.splitlines()), 1) + self.assertRegexpMatches(errs, r'Cannot parse.*\bCOMMAND_EXECUTION=a') def get_value(self, *args, **kwargs): config = UDTConfig(prefix='TEST') @@ -117,6 +125,10 @@ REPEAT=yes config_files['user'] = 'COMPATFOOBAR=bar' self.assertEqual(self.get_value('QUX', compat_keys=['COMPATFOOBAR']), 'bar') + errs = ubuntutools.config.stderr.getvalue().strip() + ubuntutools.config.stderr = StringIO() + self.assertEqual(len(errs.splitlines()), 1) + self.assertRegexpMatches(errs, r'Deprecated.*\bCOMPATFOOBAR\b.*\bQUX\b') def test_boolean(self): config_files['user'] = "TEST_BOOLEAN=yes" From b46114c20fee19a835f065df1ab10898a2e18670 Mon Sep 17 00:00:00 2001 From: Stefano Rivera Date: Wed, 22 Dec 2010 00:11:10 +0200 Subject: [PATCH 13/17] Move up mailserver config parsing, so we return deprecation errors fast --- requestsync | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/requestsync b/requestsync index 3e377a3..dc1cba0 100755 --- a/requestsync +++ b/requestsync @@ -88,6 +88,15 @@ if __name__ == '__main__': boolean=True) if options.lpinstance is None: options.lpinstance = config.get_value('LPINSTANCE') + mailserver_host = config.get_value('SMTP_SERVER', + default='fiordland.ubuntu.com', + compat_keys=['UBUSMTP', 'DEBSMTP']) + mailserver_port = config.get_value('SMTP_PORT', default=25, + compat_keys=['UBUSMTP_PORT', 'DEBSMTP_PORT']) + mailserver_user = config.get_value('SMTP_USER', + compat_keys=['UBUSMTP_USER', 'DEBSMTP_USER']) + mailserver_pass = config.get_value('SMTP_PASS', + compat_keys=['UBUSMTP_PASS', 'DEBSMTP_PASS']) # import the needed requestsync module if options.lpapi: @@ -260,15 +269,6 @@ if __name__ == '__main__': postBug(srcpkg, subscribe, mapping[status], title, report) else: email_from = ubu_email(export=False)[1] - mailserver_host = config.get_value('SMTP_SERVER', - default='fiordland.ubuntu.com', - compat_keys=['UBUSMTP', 'DEBSMTP']) - mailserver_port = config.get_value('SMTP_PORT', default=25, - compat_keys=['UBUSMTP_PORT', 'DEBSMTP_PORT']) - mailserver_user = config.get_value('SMTP_USER', - compat_keys=['UBUSMTP_USER', 'DEBSMTP_USER']) - mailserver_pass = config.get_value('SMTP_PASS', - compat_keys=['UBUSMTP_PASS', 'DEBSMTP_PASS']) # Mail sync request mailBug(srcpkg, subscribe, status, title, report, options.lpinstance, options.keyid, email_from, mailserver_host, mailserver_port, From 0184a10c212a1e19cf214a4aaf43abeef36cf90d Mon Sep 17 00:00:00 2001 From: Stefano Rivera Date: Wed, 22 Dec 2010 00:14:28 +0200 Subject: [PATCH 14/17] Prefix replacement in warning --- ubuntutools/config.py | 5 ++++- ubuntutools/test/test_config.py | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/ubuntutools/config.py b/ubuntutools/config.py index d0e2409..1235e59 100644 --- a/ubuntutools/config.py +++ b/ubuntutools/config.py @@ -98,9 +98,12 @@ class UDTConfig(object): else: continue if k in compat_keys: + r_prefix = self.prefix + if key in self.defaults: + r_prefix = 'UBUNTUTOOLS' print >> stderr, ( 'W: Deprecated configuration variable: %s. ' - 'Replaced by %s.') % (k, key) + 'Replaced by %s_%s.') % (k, r_prefix, key) return value return default diff --git a/ubuntutools/test/test_config.py b/ubuntutools/test/test_config.py index 992edd4..8606830 100644 --- a/ubuntutools/test/test_config.py +++ b/ubuntutools/test/test_config.py @@ -128,7 +128,8 @@ REPEAT=yes errs = ubuntutools.config.stderr.getvalue().strip() ubuntutools.config.stderr = StringIO() self.assertEqual(len(errs.splitlines()), 1) - self.assertRegexpMatches(errs, r'Deprecated.*\bCOMPATFOOBAR\b.*\bQUX\b') + self.assertRegexpMatches(errs, + r'Deprecated.*\bCOMPATFOOBAR\b.*\bTEST_QUX\b') def test_boolean(self): config_files['user'] = "TEST_BOOLEAN=yes" From 2c2aaf90b3aec5bdff1e575a7e1f9fc40e533453 Mon Sep 17 00:00:00 2001 From: Stefano Rivera Date: Wed, 22 Dec 2010 02:09:04 +0200 Subject: [PATCH 15/17] Migrate to logging --- ubuntutools/config.py | 31 ++++++++++++++++++--------- ubuntutools/test/__init__.py | 25 ++++++++++++++++++---- ubuntutools/test/test_config.py | 37 ++++++++++++++++++++------------- 3 files changed, 64 insertions(+), 29 deletions(-) diff --git a/ubuntutools/config.py b/ubuntutools/config.py index 1235e59..41fc93e 100644 --- a/ubuntutools/config.py +++ b/ubuntutools/config.py @@ -15,13 +15,14 @@ # OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. +import logging import os import os.path import pwd import re import shlex import socket -from sys import argv, stderr +import sys class UDTConfig(object): """Ubuntu Dev Tools configuration file (devscripts config file) and @@ -40,9 +41,12 @@ class UDTConfig(object): config = {} def __init__(self, no_conf=False, prefix=None): + setup_logging() + self.logger = logging.getLogger('config') + self.no_conf = no_conf if prefix is None: - prefix = os.path.basename(argv[0]).upper().replace('-', '_') + prefix = os.path.basename(sys.argv[0]).upper().replace('-', '_') self.prefix = prefix if not no_conf: self.config = self.parse_devscripts_config() @@ -60,9 +64,9 @@ class UDTConfig(object): for line in f: parsed = shlex.split(line, comments=True) if len(parsed) > 1: - print >> stderr, ( - "W: Cannot parse variable assignment in %s: %s" - % (getattr(f, 'name', ''), line)) + self.logger.warn( + 'Cannot parse variable assignment in %s: %s', + getattr(f, 'name', ''), line) if len(parsed) >= 1 and '=' in parsed[0]: key, value = parsed[0].split('=', 1) config[key] = value @@ -98,12 +102,13 @@ class UDTConfig(object): else: continue if k in compat_keys: - r_prefix = self.prefix + replacements = self.prefix + '_' + key if key in self.defaults: - r_prefix = 'UBUNTUTOOLS' - print >> stderr, ( - 'W: Deprecated configuration variable: %s. ' - 'Replaced by %s_%s.') % (k, r_prefix, key) + replacements += 'or UBUNTUTOOLS_' + key + self.logger.warn( + 'Using deprecated configuration variable %s. ' + 'You should use %s.', + k, replacements) return value return default @@ -167,3 +172,9 @@ def ubu_email(name=None, email=None, export=True): os.environ['DEBFULLNAME'] = name os.environ['DEBEMAIL'] = email return name, email + +def setup_logging(): + """Basic logging configuration + This has no effect if logger is already configured.""" + logging.basicConfig(level=logging.INFO, + format='%(levelname)s (%(name)s) %(message)s') diff --git a/ubuntutools/test/__init__.py b/ubuntutools/test/__init__.py index f47644d..767b7a5 100644 --- a/ubuntutools/test/__init__.py +++ b/ubuntutools/test/__init__.py @@ -14,17 +14,34 @@ # OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. -from sys import version_info as _version_info +import logging +import os +import sys -if _version_info < (2, 7): +if sys.version_info < (2, 7): import unittest2 as unittest else: import unittest def discover(): - import os - import sys # import __main__ triggers code re-execution __main__ = sys.modules['__main__'] setupDir = os.path.abspath(os.path.dirname(__main__.__file__)) return unittest.defaultTestLoader.discover(setupDir) + + +class LoggingCatcher(logging.Handler): + def __init__(self): + logging.Handler.__init__(self) + self.m = {'critical': [], + 'error': [], + 'warning': [], + 'info': [], + 'debug': [], + 'notset': []} + + def emit(self, record): + self.m[record.levelname.lower()].append(record.getMessage()) + + def __getitem__(self, key): + return self.m[key] diff --git a/ubuntutools/test/test_config.py b/ubuntutools/test/test_config.py index 8606830..6895041 100644 --- a/ubuntutools/test/test_config.py +++ b/ubuntutools/test/test_config.py @@ -14,14 +14,16 @@ # OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. +import logging import os import os.path from StringIO import StringIO -from sys import stderr import ubuntutools.config -from ubuntutools.config import UDTConfig, ubu_email -from ubuntutools.test import unittest +from ubuntutools.config import UDTConfig, ubu_email, setup_logging +from ubuntutools.test import unittest, LoggingCatcher + +setup_logging() config_files = { 'system': '', @@ -43,13 +45,21 @@ def fake_open(filename, mode='r'): class ConfigTestCase(unittest.TestCase): def setUp(self): ubuntutools.config.open = fake_open - ubuntutools.config.stderr = StringIO() + + self.logs = LoggingCatcher() + self.logging_handler = logging.root.handlers[0] + logging.root.removeHandler(self.logging_handler) + logging.root.addHandler(self.logs) + self.cleanEnvironment() def tearDown(self): del ubuntutools.config.open - self.assertEqual(ubuntutools.config.stderr.getvalue(), '') - ubuntutools.config.stderr = stderr + + logging.root.removeHandler(self.logs) + logging.root.addHandler(self.logging_handler) + self.assertTrue(all(len(x) == 0 for x in self.logs.m.itervalues())) + self.cleanEnvironment() def cleanEnvironment(self): @@ -86,10 +96,9 @@ REPEAT=yes 'INHERIT': 'user', 'REPEAT': 'yes', }) - errs = ubuntutools.config.stderr.getvalue().strip() - ubuntutools.config.stderr = StringIO() - self.assertEqual(len(errs.splitlines()), 1) - self.assertRegexpMatches(errs, r'Cannot parse.*\bCOMMAND_EXECUTION=a') + self.assertEqual(len(self.logs['warning']), 1) + self.assertRegexpMatches(self.logs['warning'].pop(), + r'Cannot parse.*\bCOMMAND_EXECUTION=a') def get_value(self, *args, **kwargs): config = UDTConfig(prefix='TEST') @@ -125,11 +134,9 @@ REPEAT=yes config_files['user'] = 'COMPATFOOBAR=bar' self.assertEqual(self.get_value('QUX', compat_keys=['COMPATFOOBAR']), 'bar') - errs = ubuntutools.config.stderr.getvalue().strip() - ubuntutools.config.stderr = StringIO() - self.assertEqual(len(errs.splitlines()), 1) - self.assertRegexpMatches(errs, - r'Deprecated.*\bCOMPATFOOBAR\b.*\bTEST_QUX\b') + self.assertEqual(len(self.logs['warning']), 1) + self.assertRegexpMatches(self.logs['warning'].pop(), + r'deprecated.*\bCOMPATFOOBAR\b.*\bTEST_QUX\b') def test_boolean(self): config_files['user'] = "TEST_BOOLEAN=yes" From b94d134650034a20ab17e56690a6384c95cfbfd6 Mon Sep 17 00:00:00 2001 From: Stefano Rivera Date: Wed, 22 Dec 2010 21:04:53 +0200 Subject: [PATCH 16/17] Add warning() and substitution support to logger --- ubuntutools/logger.py | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/ubuntutools/logger.py b/ubuntutools/logger.py index db6a016..0c1613a 100644 --- a/ubuntutools/logger.py +++ b/ubuntutools/logger.py @@ -33,22 +33,27 @@ class Logger(object): print "%s: I: %s" % (cls.script_name, " ".join(cmd)) @classmethod - def debug(cls, message): + def debug(cls, message, *args): if cls.verbose: - print "%s: D: %s" % (cls.script_name, message) + print "%s: D: %s" % (cls.script_name, message % args) @classmethod - def error(cls, message): - print >> sys.stderr, "%s: Error: %s" % (cls.script_name, message) + def error(cls, message, *args): + print >> sys.stderr, "%s: Error: %s" % (cls.script_name, message % args) @classmethod - def info(cls, message): + def warn(cls, message, *args): + print >> sys.stderr, "%s: Warning: %s" % (cls.script_name, + message % args) + + @classmethod + def info(cls, message, *args): if cls.verbose: - print "%s: I: %s" % (cls.script_name, message) + print "%s: I: %s" % (cls.script_name, message % args) @classmethod - def normal(cls, message): - print "%s: %s" % (cls.script_name, message) + def normal(cls, message, *args): + print "%s: %s" % (cls.script_name, message % args) @classmethod def set_verbosity(cls, verbose): From 8cee5455688d63079b35847cca64ce1b09016cf4 Mon Sep 17 00:00:00 2001 From: Stefano Rivera Date: Wed, 22 Dec 2010 21:24:35 +0200 Subject: [PATCH 17/17] Migrate to ubuntutools.logger --- ubuntutools/config.py | 19 +++++------------ ubuntutools/logger.py | 15 +++++++------ ubuntutools/test/__init__.py | 18 ---------------- ubuntutools/test/test_config.py | 37 +++++++++++++++++---------------- 4 files changed, 33 insertions(+), 56 deletions(-) diff --git a/ubuntutools/config.py b/ubuntutools/config.py index 41fc93e..df28724 100644 --- a/ubuntutools/config.py +++ b/ubuntutools/config.py @@ -15,7 +15,6 @@ # OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. -import logging import os import os.path import pwd @@ -24,6 +23,8 @@ import shlex import socket import sys +from ubuntutools.logger import Logger + class UDTConfig(object): """Ubuntu Dev Tools configuration file (devscripts config file) and environment variable parsing. @@ -41,9 +42,6 @@ class UDTConfig(object): config = {} def __init__(self, no_conf=False, prefix=None): - setup_logging() - self.logger = logging.getLogger('config') - self.no_conf = no_conf if prefix is None: prefix = os.path.basename(sys.argv[0]).upper().replace('-', '_') @@ -64,9 +62,8 @@ class UDTConfig(object): for line in f: parsed = shlex.split(line, comments=True) if len(parsed) > 1: - self.logger.warn( - 'Cannot parse variable assignment in %s: %s', - getattr(f, 'name', ''), line) + Logger.warn('Cannot parse variable assignment in %s: %s', + getattr(f, 'name', ''), line) if len(parsed) >= 1 and '=' in parsed[0]: key, value = parsed[0].split('=', 1) config[key] = value @@ -105,7 +102,7 @@ class UDTConfig(object): replacements = self.prefix + '_' + key if key in self.defaults: replacements += 'or UBUNTUTOOLS_' + key - self.logger.warn( + Logger.warn( 'Using deprecated configuration variable %s. ' 'You should use %s.', k, replacements) @@ -172,9 +169,3 @@ def ubu_email(name=None, email=None, export=True): os.environ['DEBFULLNAME'] = name os.environ['DEBEMAIL'] = email return name, email - -def setup_logging(): - """Basic logging configuration - This has no effect if logger is already configured.""" - logging.basicConfig(level=logging.INFO, - format='%(levelname)s (%(name)s) %(message)s') diff --git a/ubuntutools/logger.py b/ubuntutools/logger.py index 0c1613a..1b0ecf7 100644 --- a/ubuntutools/logger.py +++ b/ubuntutools/logger.py @@ -24,36 +24,39 @@ class Logger(object): script_name = os.path.basename(sys.argv[0]) verbose = False + stdout = sys.stdout + stderr = sys.stderr + @classmethod def command(cls, cmd): if cls.verbose: for i in xrange(len(cmd)): if cmd[i].find(" ") >= 0: cmd[i] = '"' + cmd[i] + '"' - print "%s: I: %s" % (cls.script_name, " ".join(cmd)) + print >> cls.stdout, "%s: I: %s" % (cls.script_name, " ".join(cmd)) @classmethod def debug(cls, message, *args): if cls.verbose: - print "%s: D: %s" % (cls.script_name, message % args) + print >> cls.stderr, "%s: D: %s" % (cls.script_name, message % args) @classmethod def error(cls, message, *args): - print >> sys.stderr, "%s: Error: %s" % (cls.script_name, message % args) + print >> cls.stderr, "%s: Error: %s" % (cls.script_name, message % args) @classmethod def warn(cls, message, *args): - print >> sys.stderr, "%s: Warning: %s" % (cls.script_name, + print >> cls.stderr, "%s: Warning: %s" % (cls.script_name, message % args) @classmethod def info(cls, message, *args): if cls.verbose: - print "%s: I: %s" % (cls.script_name, message % args) + print >> cls.stdout, "%s: I: %s" % (cls.script_name, message % args) @classmethod def normal(cls, message, *args): - print "%s: %s" % (cls.script_name, message % args) + print >> cls.stdout, "%s: %s" % (cls.script_name, message % args) @classmethod def set_verbosity(cls, verbose): diff --git a/ubuntutools/test/__init__.py b/ubuntutools/test/__init__.py index 767b7a5..0a68b2f 100644 --- a/ubuntutools/test/__init__.py +++ b/ubuntutools/test/__init__.py @@ -14,7 +14,6 @@ # OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. -import logging import os import sys @@ -28,20 +27,3 @@ def discover(): __main__ = sys.modules['__main__'] setupDir = os.path.abspath(os.path.dirname(__main__.__file__)) return unittest.defaultTestLoader.discover(setupDir) - - -class LoggingCatcher(logging.Handler): - def __init__(self): - logging.Handler.__init__(self) - self.m = {'critical': [], - 'error': [], - 'warning': [], - 'info': [], - 'debug': [], - 'notset': []} - - def emit(self, record): - self.m[record.levelname.lower()].append(record.getMessage()) - - def __getitem__(self, key): - return self.m[key] diff --git a/ubuntutools/test/test_config.py b/ubuntutools/test/test_config.py index 6895041..70adde8 100644 --- a/ubuntutools/test/test_config.py +++ b/ubuntutools/test/test_config.py @@ -14,16 +14,15 @@ # OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. -import logging import os import os.path +import sys from StringIO import StringIO import ubuntutools.config -from ubuntutools.config import UDTConfig, ubu_email, setup_logging -from ubuntutools.test import unittest, LoggingCatcher - -setup_logging() +from ubuntutools.config import UDTConfig, ubu_email +from ubuntutools.logger import Logger +from ubuntutools.test import unittest config_files = { 'system': '', @@ -45,20 +44,18 @@ def fake_open(filename, mode='r'): class ConfigTestCase(unittest.TestCase): def setUp(self): ubuntutools.config.open = fake_open - - self.logs = LoggingCatcher() - self.logging_handler = logging.root.handlers[0] - logging.root.removeHandler(self.logging_handler) - logging.root.addHandler(self.logs) + Logger.stdout = StringIO() + Logger.stderr = StringIO() self.cleanEnvironment() def tearDown(self): del ubuntutools.config.open - logging.root.removeHandler(self.logs) - logging.root.addHandler(self.logging_handler) - self.assertTrue(all(len(x) == 0 for x in self.logs.m.itervalues())) + self.assertEqual(Logger.stdout.getvalue(), '') + self.assertEqual(Logger.stderr.getvalue(), '') + Logger.stdout = sys.stdout + Logger.stderr = sys.stderr self.cleanEnvironment() @@ -96,9 +93,11 @@ REPEAT=yes 'INHERIT': 'user', 'REPEAT': 'yes', }) - self.assertEqual(len(self.logs['warning']), 1) - self.assertRegexpMatches(self.logs['warning'].pop(), - r'Cannot parse.*\bCOMMAND_EXECUTION=a') + errs = Logger.stderr.getvalue().strip() + Logger.stderr = StringIO() + self.assertEqual(len(errs.splitlines()), 1) + self.assertRegexpMatches(errs, + r'Warning: Cannot parse.*\bCOMMAND_EXECUTION=a') def get_value(self, *args, **kwargs): config = UDTConfig(prefix='TEST') @@ -134,8 +133,10 @@ REPEAT=yes config_files['user'] = 'COMPATFOOBAR=bar' self.assertEqual(self.get_value('QUX', compat_keys=['COMPATFOOBAR']), 'bar') - self.assertEqual(len(self.logs['warning']), 1) - self.assertRegexpMatches(self.logs['warning'].pop(), + errs = Logger.stderr.getvalue().strip() + Logger.stderr = StringIO() + self.assertEqual(len(errs.splitlines()), 1) + self.assertRegexpMatches(errs, r'deprecated.*\bCOMPATFOOBAR\b.*\bTEST_QUX\b') def test_boolean(self):