~ubuntu-branches/ubuntu/maverick/ubuntu-dev-tools/maverick-proposed

« back to all changes in this revision

Viewing changes to requestsync

  • Committer: Bazaar Package Importer
  • Author(s): Luca Falavigna
  • Date: 2009-11-28 18:48:35 UTC
  • mfrom: (18.1.66 lucid)
  • Revision ID: james.westby@ubuntu.com-20091128184835-0ot21cscixychr6b
Tags: 0.83debian1
* Merge from Ubuntu Lucid, local Debian changes:
  - Adjust Maintainer and Uploaders.
  - Depend on python-lazr.restfulclient.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
#!/usr/bin/python
2
 
 
3
 
# (C) 2007 Canonical Ltd, Steve Kowalik
 
2
# -*- coding: utf-8 -*-
 
3
#
 
4
# (C) 2007 Canonical Ltd., Steve Kowalik
4
5
# Authors:
5
 
# Martin Pitt <martin.pitt@ubuntu.com>
6
 
# Steve Kowalik <stevenk@ubuntu.com>
7
 
# GPLv2, see /usr/share/common-licenses/GPL
8
 
 
9
 
import os, os.path, sys, urllib, subprocess, smtplib, getopt
10
 
 
11
 
changelog = 1
12
 
 
13
 
def cur_version_component(sourcepkg, release):
14
 
    madison = subprocess.Popen(['rmadison', '-u', 'ubuntu', '-a', 'source', \
15
 
                                '-s', release, sourcepkg], \
16
 
                               stdout=subprocess.PIPE)
17
 
    out = madison.communicate()[0]
18
 
    assert (madison.returncode == 0)
19
 
        
20
 
    for l in out.splitlines():
21
 
       (pkg, version, rel, builds) = l.split('|')
22
 
       component = 'main'
23
 
       if rel.find('/') != -1:
24
 
           component = rel.split('/')[1]
25
 
       return (version.strip(), component.strip())
26
 
           
27
 
    print "%s doesn't appear to exist in %s, specify -n for a package not in Ubuntu." % (sourcepkg, release)
28
 
    sys.exit(1)
29
 
 
30
 
def cur_deb_version(sourcepkg):
31
 
    ''' Return the current debian version of a package in unstable '''
32
 
    madison = subprocess.Popen(['rmadison', '-u', 'debian', '-a', 'source', \
33
 
                                '-s', 'unstable', sourcepkg], \
34
 
                               stdout=subprocess.PIPE)
35
 
    out = madison.communicate()[0]
36
 
    assert (madison.returncode == 0)
37
 
 
38
 
    try:
39
 
        assert out
40
 
    except AssertionError:
41
 
        print "%s doesn't appear to exist in Debian." % sourcepkg
42
 
        sys.exit(1)
43
 
   
44
 
    return out.split('|')[1].rstrip('[]''').lstrip()
45
 
 
46
 
    sys.exit(1)
47
 
 
48
 
def debian_changelog(sourcepkg, component, version):
49
 
    '''Return the Debian changelog from the latest up to the given version
50
 
    (exclusive).'''
51
 
 
52
 
    ch = ''
53
 
    subdir = sourcepkg[0]
54
 
    if sourcepkg.startswith('lib'):
55
 
        subdir = 'lib%s' % sourcepkg[3]
56
 
    for l in urllib.urlopen('http://packages.debian.org/changelogs/pool/%s/%s/%s/current/changelog.txt' % (component, subdir, sourcepkg)):
57
 
        if l.startswith(sourcepkg) and l.find(version + ')') > 0:
58
 
            break
59
 
        ch += l
60
 
 
61
 
    return ch
62
 
 
63
 
def debian_component(sourcepkg):
64
 
    '''Return the Debian component for the source package.'''
65
 
    madison = subprocess.Popen(['rmadison', '-a', 'source', '-s', 'unstable', \
66
 
                                sourcepkg], stdout=subprocess.PIPE)
67
 
    out = madison.communicate()[0]
68
 
    assert (madison.returncode == 0)
69
 
 
70
 
    try:
71
 
        assert out
72
 
    except AssertionError:
73
 
        print "%s doesn't appear to exist in Debian." % sourcepkg
74
 
        sys.exit(1)
75
 
    raw_comp = out.split('|')[2].split('/')
76
 
    component = 'main'
77
 
    if len(raw_comp) == 2:
78
 
        component = raw_comp[1]
79
 
    return component
80
 
 
81
 
def usage():
82
 
    print """Usage: requestsync [-n|-s|-k <keyid>] <source package> <target release> [basever]
83
 
 
84
 
In some cases, the base version (fork point from Debian) cannot be determined
85
 
automatically, and you'll get a complete Debian changelog. Specify the correct
86
 
base version of the package in Ubuntu."""
87
 
    sys.exit(1)
 
6
#  Martin Pitt <martin.pitt@ubuntu.com>
 
7
#  Steve Kowalik <stevenk@ubuntu.com>
 
8
#  Michael Bienia <geser@ubuntu.com>
 
9
#  Daniel Hahler <ubuntu@thequod.de>
 
10
#  Iain Lane <laney@ubuntu.com>
 
11
#  Jonathan Davies <jpds@ubuntu.com>
 
12
#  Markus Korn <thekorn@gmx.de> (python-launchpadlib support)
 
13
#
 
14
# ##################################################################
 
15
#
 
16
# This program is free software; you can redistribute it and/or
 
17
# modify it under the terms of the GNU General Public License
 
18
# as published by the Free Software Foundation; version 2.
 
19
 
20
# This program is distributed in the hope that it will be useful,
 
21
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
22
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
23
# GNU General Public License for more details.
 
24
#
 
25
# See file /usr/share/common-licenses/GPL-2 for more details.
 
26
#
 
27
# ##################################################################
 
28
 
 
29
import sys
 
30
from optparse import OptionParser
 
31
from debian_bundle.changelog import Version
 
32
 
 
33
# ubuntu-dev-tools modules
 
34
from ubuntutools.lp import udtexceptions
 
35
from ubuntutools.requestsync.common import *
 
36
# https_proxy fix
 
37
import ubuntutools.common
88
38
 
89
39
#
90
40
# entry point
91
41
#
92
42
 
93
 
newsource = False
94
 
sponsorship = False
95
 
keyid = None
96
 
try:
97
 
    opts, args = getopt.getopt(sys.argv[1:], 'nsk:')
98
 
except getopt.GetoptError:
99
 
    usage()
100
 
for o, a in opts:
101
 
    if o == "-n":
102
 
        newsource = True
103
 
    if o == "-s":
104
 
        sponsorship = True
105
 
    if o == "-k":
106
 
        keyid = a
107
 
 
108
 
if len(args) not in (2, 3):
109
 
    usage()
110
 
 
111
 
(srcpkg, release) = args[:2]
112
 
force_base_ver = None
113
 
if len(args) == 3:
114
 
    force_base_ver = args[2]
115
 
(cur_ver, component) = ('0', 'universe') # Let's assume universe
116
 
if not newsource:
117
 
    (cur_ver, component) = cur_version_component(srcpkg, release)
118
 
 
119
 
debiancomponent = debian_component(srcpkg)
120
 
 
121
 
# generate bug report
122
 
status = "confirmed"
123
 
subscribe = "ubuntu-archive"
124
 
deb_version = cur_deb_version(srcpkg)
125
 
if sponsorship:
126
 
    status = "new"
127
 
    if component in ['main', 'restricted']:
128
 
        subscribe = "ubuntu-main-sponsors"
129
 
    else:
130
 
        subscribe = "ubuntu-universe-sponsors"
131
 
 
132
 
affects = '/%s' % srcpkg
133
 
if newsource:
134
 
    affects = ''
135
 
 
136
 
report = ''' affects ubuntu%s
137
 
 status %s
138
 
 subscribe %s
139
 
 
140
 
Please sync %s %s (%s) from Debian unstable (%s).
141
 
''' % (affects, status, subscribe, srcpkg, deb_version, component, debiancomponent)
142
 
 
143
 
base_ver = cur_ver
144
 
uidx = base_ver.find('ubuntu')
145
 
if uidx > 0:
146
 
    base_ver = base_ver[:uidx]
147
 
 
148
 
    print 'Explanation of the Ubuntu delta and why it can be dropped:'
149
 
    explanation = '\nExplanation of the Ubuntu delta and why it can be dropped:\n'
150
 
    while (explanation[-2:] != '\n\n'):
151
 
        explanation += sys.stdin.readline()
152
 
    report += explanation
153
 
 
154
 
if changelog:
155
 
    uidx = base_ver.find('build')
156
 
    if uidx > 0:
157
 
        base_ver = base_ver[:uidx]
158
 
 
159
 
    if force_base_ver:
160
 
        base_ver = force_base_ver
161
 
 
162
 
    report += 'Changelog since current %s version %s:\n\n' % (release, cur_ver)
163
 
    report += debian_changelog(srcpkg, debiancomponent, base_ver) + '\n'
164
 
 
165
 
# sign it
166
 
sign_command = 'gpg'
167
 
for cmd in ('gpg2', 'gnome-gpg'):
168
 
    if os.access('/usr/bin/%s' % cmd, os.X_OK):
169
 
        sign_command = cmd
170
 
 
171
 
gpg_command = [sign_command, '--clearsign']
172
 
if keyid:
173
 
    gpg_command.extend(('-u', keyid))
174
 
 
175
 
gpg = subprocess.Popen(gpg_command, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
176
 
signed_report = gpg.communicate(report)[0]
177
 
assert gpg.returncode == 0
178
 
 
179
 
# generate email
180
 
myemailaddr = os.getenv('DEBEMAIL')
181
 
if not myemailaddr:
182
 
    print "The environment variable DEBEMAIL needs to be set to make use of this script."
183
 
    sys.exit(1)
184
 
to = 'new@bugs.launchpad.net'
185
 
 
186
 
mail = '''From: %s
187
 
To: %s
188
 
Subject: Please sync %s %s (%s) from Debian unstable (%s)
189
 
 
190
 
%s''' % (myemailaddr, to, srcpkg, deb_version, component, debiancomponent, signed_report)
191
 
 
192
 
print mail
193
 
 
194
 
print 'Press enter to file this bug, Control-C to abort'
195
 
 
196
 
sys.stdin.readline()
197
 
 
198
 
# get server address
199
 
mailserver = os.getenv('DEBSMTP')
200
 
if mailserver:
201
 
        print 'Using custom SMTP server:', mailserver
202
 
else :
203
 
        mailserver = 'fiordland.ubuntu.com'
204
 
 
205
 
# get server port
206
 
mailserver_port = os.getenv('DEBSMTP_PORT')
207
 
if mailserver_port:
208
 
    print 'Using custom SMTP port:', mailserver_port
209
 
else:
210
 
    mailserver_port = 25
211
 
 
212
 
# connect to the server
213
 
s = smtplib.SMTP(mailserver, mailserver_port)
214
 
 
215
 
# authenticate to the server
216
 
mailserver_user = os.getenv('DEBSMTP_USER')
217
 
mailserver_pass = os.getenv('DEBSMTP_PASS')
218
 
if mailserver_user and mailserver_pass:
219
 
        try:
220
 
                s.login(mailserver_user, mailserver_pass)
221
 
        except smtplib.SMTPAuthenticationError:
222
 
                print 'Error authenticating to the server: invalid username and password.'
223
 
                s.quit(); sys.exit(1)
224
 
        except:
225
 
                print 'Unknown SMTP error.'
226
 
                s.quit(); sys.exit(1)
227
 
                
228
 
 
229
 
s.sendmail(myemailaddr, to, mail)
230
 
s.quit()
 
43
if __name__ == '__main__':
 
44
        # Our usage options.
 
45
        usage = 'Usage: %prog [-d distro] [-k keyid] [-n] [--lp] [-s] [-e] ' \
 
46
                '<source package> [<target release> [base version]]'
 
47
        optParser = OptionParser(usage)
 
48
 
 
49
        optParser.add_option('-d', type = 'string',
 
50
                dest = 'dist', default = 'testing',
 
51
                help = 'Debian distribution to sync from.')
 
52
        optParser.add_option('-k', type = 'string',
 
53
                dest = 'keyid', default = None,
 
54
                help = 'GnuPG key ID to use for signing report (only used when emailing the sync request).')
 
55
        optParser.add_option('-n', action = 'store_true',
 
56
                dest = 'newpkg', default = False,
 
57
                help = 'Whether package to sync is a new package in Ubuntu.')
 
58
        optParser.add_option('--lp', action = 'store_true',
 
59
                dest = 'lpapi', default = False,
 
60
                help = 'Specify whether to use the LP API for filing the sync request (recommended).')
 
61
        optParser.add_option('-s', action = 'store_true',
 
62
                dest = 'sponsorship', default = False,
 
63
                help = 'Force sponsorship')
 
64
        optParser.add_option('-e', action = 'store_true',
 
65
                dest = 'ffe', default = False,
 
66
                help = 'Use this after FeatureFreeze for non-bug fix syncs, changes ' \
 
67
                        'default subscription to the appropriate release team.')
 
68
 
 
69
        (options, args) = optParser.parse_args()
 
70
 
 
71
        if not len(args):
 
72
                optParser.print_help()
 
73
                sys.exit(1)
 
74
 
 
75
        # import the needed requestsync module
 
76
        if options.lpapi:
 
77
                from ubuntutools.requestsync.lp import *
 
78
                from ubuntutools.lp.lpapicache import Distribution, PersonTeam
 
79
                # See if we have LP credentials and exit if we don't - cannot continue in this case
 
80
                try:
 
81
                        Launchpad.login()
 
82
                except IOError:
 
83
                        sys.exit(1)
 
84
        else:
 
85
                from ubuntutools.requestsync.mail import *
 
86
                if not getEmailAddress():
 
87
                        sys.exit(1)
 
88
 
 
89
        newsource = options.newpkg
 
90
        sponsorship = options.sponsorship
 
91
        distro = options.dist
 
92
        ffe = options.ffe
 
93
        lpapi = options.lpapi
 
94
        need_interaction = False
 
95
        force_base_version = None
 
96
        srcpkg = args[0]
 
97
 
 
98
        if len(args) == 1:
 
99
                if lpapi:
 
100
                        release = Distribution('ubuntu').getDevelopmentSeries().name
 
101
                        print >> sys.stderr, 'W: Target release missing - assuming %s' % release
 
102
                else:
 
103
                        print >> sys.stderr, 'E: Source package or target release missing. Exiting.'
 
104
                        sys.exit(1)
 
105
        elif len(args) == 2:
 
106
                release = args[1]
 
107
        elif len(args) == 3:
 
108
                release = args[1]
 
109
                force_base_version = Version(args[2])
 
110
        else:
 
111
                print >> sys.stderr, 'E: Too many arguments.'
 
112
                optParser.print_help()
 
113
                sys.exit(1)
 
114
 
 
115
        # Get the current Ubuntu source package
 
116
        try:
 
117
                ubuntu_srcpkg = getUbuntuSrcPkg(srcpkg, release)
 
118
                ubuntu_version = Version(ubuntu_srcpkg.getVersion())
 
119
                ubuntu_component = ubuntu_srcpkg.getComponent()
 
120
                newsource = False # override the -n flag
 
121
        except udtexceptions.PackageNotFoundException:
 
122
                ubuntu_srcpkg = None
 
123
                ubuntu_version = Version(0)
 
124
                ubuntu_component = 'universe' # let's assume universe
 
125
                if not newsource:
 
126
                        print "'%s' doesn't exist in 'Ubuntu %s'.\nDo you want to sync a new package?" % \
 
127
                                (srcpkg, release)
 
128
                        raw_input_exit_on_ctrlc('Press [Enter] to continue or [Ctrl-C] to abort. ')
 
129
                        newsource = True
 
130
 
 
131
        # Get the requested Debian source package
 
132
        try:
 
133
                debian_srcpkg = getDebianSrcPkg(srcpkg, distro)
 
134
                debian_version = Version(debian_srcpkg.getVersion())
 
135
                debian_component = debian_srcpkg.getComponent()
 
136
        except udtexceptions.PackageNotFoundException, e:
 
137
                print >> sys.stderr, "E: %s" % e
 
138
                sys.exit(1)
 
139
 
 
140
        # Debian and Ubuntu versions are the same - stop
 
141
        if ubuntu_version == debian_version:
 
142
                print  >> sys.stderr, \
 
143
                        'E: The versions in Debian and Ubuntu are the same already (%s). Aborting.' % ubuntu_version
 
144
                sys.exit(1)
 
145
 
 
146
        # -s flag not specified - check if we do need sponsorship
 
147
        if not sponsorship:
 
148
                sponsorship = needSponsorship(srcpkg, ubuntu_component)
 
149
 
 
150
        # Check for existing package reports
 
151
        if not newsource:
 
152
                checkExistingReports(srcpkg)
 
153
 
 
154
        # Generate bug report
 
155
        pkg_to_sync = '%s %s (%s) from Debian %s (%s)' % \
 
156
                (srcpkg, debian_version, ubuntu_component, distro, debian_component)
 
157
        title = "Sync %s" % pkg_to_sync
 
158
        if ffe:
 
159
                title = "FFe: " + title
 
160
        report = "Please sync %s\n\n" % pkg_to_sync
 
161
 
 
162
        if 'ubuntu' in str(ubuntu_version):
 
163
                need_interaction = True
 
164
 
 
165
                print 'Changes have been made to the package in Ubuntu.\n' \
 
166
                        'Please edit the report and give an explanation.\n' \
 
167
                        'Not saving the report file will abort the request.'
 
168
                report += 'Explanation of the Ubuntu delta and why it can be dropped:\n' \
 
169
                        '>>> ENTER_EXPLANATION_HERE <<<\n\n'
 
170
 
 
171
        if ffe:
 
172
                need_interaction = True
 
173
 
 
174
                print 'To approve FeatureFreeze exception, you need to state\n' \
 
175
                        'the reason why you feel it is necessary.\n' \
 
176
                        'Not saving the report file will abort the request.'
 
177
                report += 'Explanation of FeatureFreeze exception:\n' \
 
178
                        '>>> ENTER_EXPLANATION_HERE <<<\n\n'
 
179
 
 
180
        if need_interaction:
 
181
                raw_input_exit_on_ctrlc('Press [Enter] to continue. Press [Ctrl-C] to abort now. ')
 
182
 
 
183
        # Check if they have a per-package upload permission.
 
184
        if lpapi:
 
185
                ubuntu_archive = Distribution('ubuntu').getArchive()
 
186
                if PersonTeam.getMe().isPerPackageUploader(ubuntu_archive, srcpkg):
 
187
                        report += 'Note that I have per-package upload permissions for %s.\n\n' % srcpkg
 
188
 
 
189
        base_version = force_base_version or ubuntu_version
 
190
 
 
191
        if newsource:
 
192
                report += 'All changelog entries:\n\n'
 
193
        else:
 
194
                report += 'Changelog entries since current %s version %s:\n\n' % (release, ubuntu_version)
 
195
        changelog = getDebianChangelog(debian_srcpkg, base_version)
 
196
        if not changelog:
 
197
                print >> sys.stderr, "E: Did not retrieve any changelog entries. Was the package recently uploaded? (check http://packages.debian.org/changelogs/)"
 
198
                sys.exit(1)
 
199
        report += changelog
 
200
 
 
201
        (title, report) = edit_report(title, report, changes_required = need_interaction)
 
202
 
 
203
        # bug status and bug subscriber
 
204
        status = 'confirmed'
 
205
        subscribe = 'ubuntu-archive'
 
206
        if sponsorship:
 
207
                status = 'new'
 
208
                if ubuntu_component in ('main', 'restricted'):
 
209
                        subscribe = 'ubuntu-main-sponsors'
 
210
                else:
 
211
                        subscribe = 'ubuntu-universe-sponsors'
 
212
        if ffe:
 
213
                status = 'new'
 
214
                if ubuntu_component in ('main', 'restricted'):
 
215
                        subscribe = 'ubuntu-release'
 
216
                else:
 
217
                        subscribe = 'motu-release'
 
218
 
 
219
        srcpkg = not newsource and srcpkg or None
 
220
        if lpapi:
 
221
                # Map status to the values expected by LP API
 
222
                mapping = {'new': 'New', 'confirmed': 'Confirmed'}
 
223
                # Post sync request using LP API
 
224
                postBug(srcpkg, subscribe, mapping[status], title, report)
 
225
        else:
 
226
                # Mail sync request
 
227
                mailBug(srcpkg, subscribe, status, title, report, options.keyid)