13
from ConfigParser import ConfigParser
14
from StringIO import StringIO
15
from fnmatch import fnmatch
16
from getpass import getpass
17
from locale import getpreferredencoding
18
from optparse import OptionParser
19
from urlparse import (urlparse, urljoin)
20
from zipfile import ZipFile
24
import gnomekeyring as gkeyring
26
from arsenal.bugzilla_adapter import *
28
from lazr.restfulclient.errors import HTTPError
30
from lpltk import LaunchpadService
31
from lpltk.LaunchpadService import LaunchpadServiceError
32
from lpltk.attachments import *
33
from lpltk.bug import Bug
37
def __init__(self, **kwargs):
38
for attr in self.attrs:
39
setattr(self, attr, kwargs.get(attr, None))
42
return "<%s>" % u" ".join(["%s: %s" % (attr, getattr(self, attr))
43
for attr in self.attrs])
46
return u"\n".join(["%s: %s" % (attr, getattr(self, attr))
47
for attr in self.attrs])
49
class LaunchpadInfo(Info):
56
class BugzillaInfo(Info):
64
class FlagsAndModifiers(type):
65
def __init__(cls, name, bases, dct):
66
super(FlagsAndModifiers, cls).__init__(name, bases, dict)
68
for index, flagname in enumerate(cls.flagnames):
69
setattr(cls, flagname, 1 << index)
71
for modifier in cls.modifiers:
72
setattr(cls, modifier, None)
74
def parse_flags(self, flags):
75
for flagname in self.flagnames:
76
flag = getattr(self, flagname)
78
setattr(self, flagname, 0)
80
def parse_modifiers(self, modifiers):
81
for modifier, value in modifiers.iteritems():
82
setattr(self, modifier, value)
84
setattr(cls, 'parse_flags', parse_flags)
85
setattr(cls, 'parse_modifiers', parse_modifiers)
87
class LaunchpadBugzillaApp(object):
88
__metaclass__ = FlagsAndModifiers
94
def __init__(self, appname, lpurl, bzurl, flags, modifiers):
95
self.appname = appname
98
self.parse_flags(flags)
99
self.parse_modifiers(modifiers)
101
self.launchpad = LaunchpadInfo(url=lpurl)
104
self.bugzilla = BugzillaInfo(url=bzurl,
106
password=self.bzpassword)
113
self.print_debug(self.launchpad, self.bugzilla)
115
def print_debug(self, *args):
121
def parse_bugids(self):
122
pattern = re.compile(r'^.*[^\d](\d+)$')
123
result = pattern.search(self.launchpad.url)
125
self.launchpad.bugid = result.groups()[0]
128
result = pattern.search(self.bugzilla.url)
130
self.bugzilla.bugid = result.groups()[0]
132
def parse_urls(self):
133
self.launchpad.parsedurl = urlparse(self.launchpad.url)
134
pattern = re.compile(r'^.*?\.(.*)\.(.*)$')
135
matches = pattern.search(self.launchpad.parsedurl.netloc).groups()
136
self.launchpad.api = (self.launchpad.parsedurl.scheme + '://api.' +
137
matches[0] + '.' + matches[1])
138
self.launchpad.api = urljoin(self.launchpad.api, 'beta/')
141
self.bugzilla.parsedurl = urlparse(self.bugzilla.url)
143
pattern = re.compile(r'^(.*)show_bug\.cgi\?id=(\d+)$')
144
self.bugzilla.attachurl = pattern.sub(
145
r'\1attachment.cgi?bugid=\2&action=enter', self.bugzilla.url)
147
def sub_url_query(self, url):
148
pattern = re.compile(r'^(.*\/)([^\/]*?)$')
149
return pattern.sub(r'\1' + url, self.bugzilla.url)
151
def get_user_from_config(self):
152
path = os.path.expanduser('~/.config/arsenal')
154
if not os.path.isdir(path):
156
fd = open(os.path.join(path, 'bugzilla.ini'), 'a+')
158
config = ConfigParser()
161
section = self.bugzilla.parsedurl.netloc
162
if not config.has_section(section):
163
config.add_section(section)
165
if not config.has_option(section, 'user'):
166
config.set(section, 'user',
167
raw_input('\tEnter Bugzilla username: '))
172
return config.get(section, 'user')
174
def get_password_from_keyring(self):
176
glib.set_application_name(keyring)
178
if not keyring in gkeyring.list_keyring_names_sync():
179
print "\tCreating new keyring for Arsenal"
180
gkeyring.create_sync(keyring, getpass("\tKeyring Password: "))
182
info = gkeyring.get_info_sync(keyring)
183
if info.get_is_locked():
184
print "\tUnlocking keyring for Arsenal"
185
gkeyring.unlock_sync(keyring, getpass("\tKeyring Password: "))
188
for id in gkeyring.list_item_ids_sync(keyring):
189
item = gkeyring.item_get_info_sync(keyring, id)
190
if self.bugzilla.username == item.get_display_name():
191
attrs = gkeyring.item_get_attributes_sync(keyring, id)
192
if attrs['netloc'] == self.bugzilla.parsedurl.netloc:
193
secret = item.get_secret()
196
attrs = {'netloc' : self.bugzilla.parsedurl.netloc}
197
id = gkeyring.item_create_sync(keyring,
198
gkeyring.ITEM_GENERIC_SECRET,
199
self.bugzilla.username,
201
getpass("\tEnter Bugzilla password: "),
203
item = gkeyring.item_get_info_sync(keyring, id)
204
secret = item.get_secret()
208
def login_launchpad(self):
209
print "Logging into Launchpad"
211
self.launchpad.service = LaunchpadService(config={
212
'launchpad_client_name': self.appname,
213
'launchpad_services_root': self.launchpad.api,
215
print ("\t[Success: Logged in as %s]" %
216
self.launchpad.service.launchpad.me.display_name)
218
def login_bugzilla(self, bzadapter):
219
if not self.bugzilla.username:
220
self.bugzilla.username = self.get_user_from_config()
222
if not self.bugzilla.password:
223
self.bugzilla.password = self.get_password_from_keyring()
225
if self.bugzilla.username and self.bugzilla.password:
226
return bzadapter.login(self.bugzilla.attachurl,
227
self.bugzilla.username,
228
self.bugzilla.password)
230
raise BugzillaLoginError("Invalid username/password")
233
self.tmpdir = tempfile.mkdtemp()
236
self.login_launchpad()
237
except LaunchpadServiceError as e:
238
print "\t[Error: %s]" % e.msg
242
self.bzadapter = BugzillaAdapter(self.tmpdir)
243
if self.bzadapter.is_login_required(self.bugzilla.attachurl):
245
print "Logging into Bugzilla"
246
username = self.login_bugzilla(self.bzadapter)
248
print "\t[Success: Logged in as %s]" % username
249
except BugzillaLoginError as e:
250
print "\t[Error: %s]" % e
255
shutil.rmtree(self.tmpdir)