mirror of
				https://git.launchpad.net/ubuntu-dev-tools
				synced 2025-11-04 07:54:03 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			370 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			370 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
#!/usr/bin/python
 | 
						|
# -*- coding: utf-8 -*-
 | 
						|
#
 | 
						|
# (C) 2007 Canonical Ltd., Steve Kowalik
 | 
						|
# Authors:
 | 
						|
#  Martin Pitt <martin.pitt@ubuntu.com>
 | 
						|
#  Steve Kowalik <stevenk@ubuntu.com>
 | 
						|
#  Michael Bienia <geser@ubuntu.com>
 | 
						|
#  Daniel Hahler <ubuntu@thequod.de>
 | 
						|
#  Iain Lane <laney@ubuntu.com>
 | 
						|
#  Jonathan Davies <jpds@ubuntu.com>
 | 
						|
#  Markus Korn <thekorn@gmx.de> (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.
 | 
						|
#
 | 
						|
# ##################################################################
 | 
						|
 | 
						|
import optparse
 | 
						|
import os
 | 
						|
import sys
 | 
						|
 | 
						|
from debian.changelog import Version
 | 
						|
from distro_info import UbuntuDistroInfo, DistroDataOutdated
 | 
						|
 | 
						|
from ubuntutools.config import UDTConfig, ubu_email
 | 
						|
from ubuntutools.lp import udtexceptions
 | 
						|
from ubuntutools.misc import require_utf8
 | 
						|
from ubuntutools.question import confirmation_prompt, EditBugReport
 | 
						|
 | 
						|
#
 | 
						|
# entry point
 | 
						|
#
 | 
						|
 | 
						|
def main():
 | 
						|
    ubu_info = UbuntuDistroInfo()
 | 
						|
    DEFAULT_SOURCE = 'unstable'
 | 
						|
    try:
 | 
						|
        if ubu_info.is_lts(ubu_info.devel()):
 | 
						|
            DEFAULT_SOURCE = 'testing'
 | 
						|
    except DistroDataOutdated, e:
 | 
						|
        print >> sys.stderr, str(e)
 | 
						|
 | 
						|
    # Our usage options.
 | 
						|
    usage = ('Usage: %prog [options] '
 | 
						|
             '<source package> [<target release> [base version]]')
 | 
						|
    parser = optparse.OptionParser(usage)
 | 
						|
 | 
						|
    parser.add_option('-d', type='string',
 | 
						|
                      dest='dist', default=DEFAULT_SOURCE,
 | 
						|
                      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('--email', action='store_true', default=False,
 | 
						|
                      help='Use a PGP-signed email for filing the sync '
 | 
						|
                           'request, rather than the LP API.')
 | 
						|
    parser.add_option('--lp', dest='deprecated_lp_flag',
 | 
						|
                      action='store_true', default=False,
 | 
						|
                      help=optparse.SUPPRESS_HELP)
 | 
						|
    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 options.deprecated_lp_flag:
 | 
						|
        print "The --lp flag is now default, ignored."
 | 
						|
    if options.email:
 | 
						|
        options.lpapi = False
 | 
						|
    else:
 | 
						|
        options.lpapi = config.get_value('USE_LPAPI', default=True,
 | 
						|
                                         boolean=True)
 | 
						|
    if options.lpinstance is None:
 | 
						|
        options.lpinstance = config.get_value('LPINSTANCE')
 | 
						|
 | 
						|
    if options.keyid is None:
 | 
						|
        options.keyid = config.get_value('KEYID')
 | 
						|
 | 
						|
    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:
 | 
						|
            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 (check_existing_reports,
 | 
						|
                                                get_debian_srcpkg,
 | 
						|
                                                get_ubuntu_srcpkg,
 | 
						|
                                                get_ubuntu_delta_changelog,
 | 
						|
                                                need_sponsorship, post_bug)
 | 
						|
        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:
 | 
						|
            # devel for changelogUrl()
 | 
						|
            Launchpad.login(service=options.lpinstance, api_version='devel')
 | 
						|
        except IOError:
 | 
						|
            sys.exit(1)
 | 
						|
    else:
 | 
						|
        from ubuntutools.requestsync.mail import (check_existing_reports,
 | 
						|
                                                  get_debian_srcpkg,
 | 
						|
                                                  get_ubuntu_srcpkg,
 | 
						|
                                                  get_ubuntu_delta_changelog,
 | 
						|
                                                  mail_bug, need_sponsorship)
 | 
						|
        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 = ubu_info.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 = get_ubuntu_srcpkg(srcpkg, release, 'Proposed')
 | 
						|
        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 = None  # Set after getting the Debian info
 | 
						|
        if not newsource:
 | 
						|
            print ("'%s' doesn't exist in 'Ubuntu %s'.\n"
 | 
						|
                   "Do you want to sync a new package?"
 | 
						|
                   % (srcpkg, release))
 | 
						|
            confirmation_prompt()
 | 
						|
            newsource = True
 | 
						|
    except udtexceptions.SeriesNotFoundException, error:
 | 
						|
        print >> sys.stderr, "E: %s" % error
 | 
						|
        sys.exit(1)
 | 
						|
 | 
						|
    # Get the requested Debian source package
 | 
						|
    try:
 | 
						|
        debian_srcpkg = get_debian_srcpkg(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)
 | 
						|
    except udtexceptions.SeriesNotFoundException, error:
 | 
						|
        print >> sys.stderr, "E: %s" % error
 | 
						|
        sys.exit(1)
 | 
						|
 | 
						|
    if ubuntu_component is None:
 | 
						|
        if debian_component == 'main':
 | 
						|
            ubuntu_component = 'universe'
 | 
						|
        else:
 | 
						|
            ubuntu_component = 'multiverse'
 | 
						|
 | 
						|
    # 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.get_debian_srcpkg(
 | 
						|
                    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 = need_sponsorship(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:
 | 
						|
        check_existing_reports(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 += (u'Explanation of the Ubuntu delta and why it can be '
 | 
						|
                   u'dropped:\n%s\n>>> ENTER_EXPLANATION_HERE <<<\n\n'
 | 
						|
                   % get_ubuntu_delta_changelog(ubuntu_srcpkg))
 | 
						|
 | 
						|
    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:
 | 
						|
        confirmation_prompt()
 | 
						|
 | 
						|
    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 = debian_srcpkg.getChangelog(since_version=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
 | 
						|
 | 
						|
    editor = EditBugReport(title, report)
 | 
						|
    editor.edit(optional=not need_interaction)
 | 
						|
    title, report = editor.get_report()
 | 
						|
 | 
						|
    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
 | 
						|
        post_bug(srcpkg, subscribe, mapping[status], title, report)
 | 
						|
    else:
 | 
						|
        email_from = ubu_email(export=False)[1]
 | 
						|
        # Mail sync request
 | 
						|
        mail_bug(srcpkg, subscribe, status, title, report, bug_mail_domain,
 | 
						|
                 options.keyid, email_from, mailserver_host, mailserver_port,
 | 
						|
                 mailserver_user, mailserver_pass)
 | 
						|
 | 
						|
if __name__ == '__main__':
 | 
						|
    try:
 | 
						|
        main()
 | 
						|
    except KeyboardInterrupt:
 | 
						|
        print "\nUser abort."
 | 
						|
        sys.exit(2)
 |