#!/usr/bin/python # -*- coding: utf-8 -*- # # (C) 2007 Canonical Ltd., Steve Kowalik # Authors: # Martin Pitt # Steve Kowalik # Michael Bienia # Daniel Hahler # Iain Lane # Jonathan Davies # Markus Korn (python-launchpadlib support) # # ################################################################## # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; version 2. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # See file /usr/share/common-licenses/GPL-2 for more details. # # ################################################################## from optparse import OptionParser import os import sys from debian.changelog import Version from distro_info import UbuntuDistroInfo from ubuntutools.config import UDTConfig, ubu_email from ubuntutools.lp import udtexceptions from ubuntutools.misc import require_utf8 from ubuntutools.requestsync.common import (edit_report, getDebianChangelog, raw_input_exit_on_ctrlc) # # entry point # def main(): # Our usage options. usage = ('Usage: %prog [options] ' ' [ [base version]]') parser = OptionParser(usage) parser.add_option('-d', type='string', dest='dist', default='unstable', help='Debian distribution to sync from.') parser.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).') parser.add_option('-n', action='store_true', dest='newpkg', default=False, help='Whether package to sync is a new package in ' 'Ubuntu.') parser.add_option('--lp', action='store_true', dest='lpapi', default=False, help='Specify whether to use the LP API for filing ' 'the sync request (recommended).') parser.add_option('-l', '--lpinstance', metavar='INSTANCE', dest='lpinstance', default=None, help='Launchpad instance to connect to ' '(default: production).') parser.add_option('-s', action='store_true', dest='sponsorship', default=False, help='Force sponsorship') parser.add_option('-C', action='store_true', dest='missing_changelog_ok', default=False, help='Allow changelog to be manually filled in ' 'when missing') parser.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.') parser.add_option('--no-conf', action='store_true', dest='no_conf', default=False, help="Don't read config files or environment variables") (options, args) = parser.parse_args() if not len(args): parser.print_help() sys.exit(1) require_utf8() 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') if not options.lpapi: if options.lpinstance == 'production': bug_mail_domain = 'bugs.launchpad.net' elif options.lpinstance == 'staging': bug_mail_domain = 'bugs.staging.launchpad.net' else: print >> sys.stderr, ('Error: Unknown launchpad instance: %s' % options.lpinstance) sys.exit(1) mailserver_host = config.get_value('SMTP_SERVER', default=None, compat_keys=['UBUSMTP', 'DEBSMTP']) if not options.lpapi and not mailserver_host: try: import DNS DNS.DiscoverNameServers() mxlist = DNS.mxlookup(bug_mail_domain) firstmx = mxlist[0] mailserver_host = firstmx[1] except ImportError, x: print >> sys.stderr, ('Please install python-dns to support ' 'Launchpad mail server lookup.') sys.exit(1) 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: from ubuntutools.requestsync.lp import (checkExistingReports, getDebianSrcPkg, getUbuntuSrcPkg, needSponsorship, postBug) from ubuntutools.lp.lpapicache import Distribution, Launchpad # See if we have LP credentials and exit if we don't - # cannot continue in this case try: Launchpad.login(service=options.lpinstance) except IOError: sys.exit(1) else: from ubuntutools.requestsync.mail import (checkExistingReports, getDebianSrcPkg, getUbuntuSrcPkg, mailBug, needSponsorship) 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 sponsorship = options.sponsorship distro = options.dist ffe = options.ffe lpapi = options.lpapi need_interaction = False force_base_version = None srcpkg = args[0] if len(args) == 1: if lpapi: release = Distribution('ubuntu').getDevelopmentSeries().name else: release = UbuntuDistroInfo().devel() print >> sys.stderr, 'W: Target release missing - assuming %s' % release elif len(args) == 2: release = args[1] elif len(args) == 3: release = args[1] force_base_version = Version(args[2]) else: print >> sys.stderr, 'E: Too many arguments.' parser.print_help() sys.exit(1) # Get the current Ubuntu source package try: ubuntu_srcpkg = getUbuntuSrcPkg(srcpkg, release) ubuntu_version = Version(ubuntu_srcpkg.getVersion()) ubuntu_component = ubuntu_srcpkg.getComponent() newsource = False # override the -n flag except udtexceptions.PackageNotFoundException: ubuntu_srcpkg = None ubuntu_version = Version('~') ubuntu_component = 'universe' # let's assume universe if not newsource: print ("'%s' doesn't exist in 'Ubuntu %s'.\n" "Do you want to sync a new package?" % (srcpkg, release)) raw_input_exit_on_ctrlc('Press [Enter] to continue ' 'or [Ctrl-C] to abort. ') newsource = True # Get the requested Debian source package try: debian_srcpkg = getDebianSrcPkg(srcpkg, distro) debian_version = Version(debian_srcpkg.getVersion()) debian_component = debian_srcpkg.getComponent() except udtexceptions.PackageNotFoundException, error: print >> sys.stderr, "E: %s" % error sys.exit(1) # 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 try: debian_srcpkg = ubuntutools.requestsync.mail.getDebianSrcPkg( srcpkg, distro) debian_version = Version(debian_srcpkg.getVersion()) debian_component = debian_srcpkg.getComponent() except udtexceptions.PackageNotFoundException, error: print >> sys.stderr, "E: %s" % error sys.exit(1) if ubuntu_version == debian_version: 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) # -s flag not specified - check if we do need sponsorship if not sponsorship: sponsorship = needSponsorship(srcpkg, ubuntu_component, release) if not sponsorship and not ffe: print >> sys.stderr, ('Consider using syncpackage(1) for syncs that ' 'do not require feature freeze exceptions.') # Check for existing package reports if not newsource: checkExistingReports(srcpkg) # Generate bug report pkg_to_sync = ('%s %s (%s) from Debian %s (%s)' % (srcpkg, debian_version, ubuntu_component, distro, debian_component)) title = "Sync %s" % pkg_to_sync if ffe: title = "FFe: " + title report = "Please sync %s\n\n" % pkg_to_sync if 'ubuntu' in str(ubuntu_version): need_interaction = True print ('Changes have been made to the package in Ubuntu.\n' 'Please edit the report and give an explanation.\n' 'Not saving the report file will abort the request.') report += ('Explanation of the Ubuntu delta and why it can be ' 'dropped:\n>>> ENTER_EXPLANATION_HERE <<<\n\n') if ffe: need_interaction = True print ('To approve FeatureFreeze exception, you need to state\n' 'the reason why you feel it is necessary.\n' 'Not saving the report file will abort the request.') report += ('Explanation of FeatureFreeze exception:\n' '>>> ENTER_EXPLANATION_HERE <<<\n\n') if need_interaction: raw_input_exit_on_ctrlc('Press [Enter] to continue.' 'Press [Ctrl-C] to abort now. ') base_version = force_base_version or ubuntu_version if newsource: report += 'All changelog entries:\n\n' else: report += ('Changelog entries since current %s version %s:\n\n' % (release, ubuntu_version)) changelog = getDebianChangelog(debian_srcpkg, base_version) if not changelog: if not options.missing_changelog_ok: print >> sys.stderr, ("E: Did not retrieve any changelog entries. " "Do you need to specify '-C'? " "Was the package recently uploaded? (check " "http://packages.debian.org/changelogs/)") sys.exit(1) else: need_interaction = True changelog = "XXX FIXME: add changelog here XXX" report += changelog (title, report) = edit_report(title, report, changes_required=need_interaction) if 'XXX FIXME' in report: print >> sys.stderr, ("E: changelog boilerplate found in report, " "please manually add changelog when using '-C'") sys.exit(1) # bug status and bug subscriber status = 'confirmed' subscribe = 'ubuntu-archive' if sponsorship: status = 'new' subscribe = 'ubuntu-sponsors' if ffe: status = 'new' subscribe = 'ubuntu-release' srcpkg = not newsource and srcpkg or None if lpapi: # Map status to the values expected by LP API mapping = {'new': 'New', 'confirmed': 'Confirmed'} # Post sync request using LP API postBug(srcpkg, subscribe, mapping[status], title, report) else: email_from = ubu_email(export=False)[1] # Mail sync request mailBug(srcpkg, subscribe, status, title, report, bug_mail_domain, options.keyid, email_from, mailserver_host, mailserver_port, mailserver_user, mailserver_pass) if __name__ == '__main__': main()