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 LaunchpadApplication(object):
88
__metaclass__ = FlagsAndModifiers
94
def __init__(self, appname, lpurl, flags, modifiers):
95
self.launchpad = LaunchpadInfo(url=lpurl)
97
self.appname = appname
100
self.parse_flags(flags)
101
self.parse_modifiers(modifiers)
106
self.print_debug(self.launchpad)
108
def print_debug(self, *args):
114
def parse_bugids(self):
115
pattern = re.compile(r'^.*[^\d](\d+)$')
116
result = pattern.search(self.launchpad.url)
118
self.launchpad.bugid = result.groups()[0]
120
def parse_urls(self):
121
self.launchpad.parsedurl = urlparse(self.launchpad.url)
122
pattern = re.compile(r'^.*?\.(.*)\.(.*)$')
123
matches = pattern.search(self.launchpad.parsedurl.netloc).groups()
124
self.launchpad.api = (self.launchpad.parsedurl.scheme + '://api.' +
125
matches[0] + '.' + matches[1])
126
self.launchpad.api = urljoin(self.launchpad.api, 'beta/')
128
def sub_url_query(self, url):
129
pattern = re.compile(r'^(.*\/)([^\/]*?)$')
130
return pattern.sub(r'\1' + url, self.bugzilla.url)
132
def login_launchpad(self):
133
print "Logging into Launchpad"
135
self.launchpad.service = LaunchpadService(config={
136
'launchpad_client_name': self.appname,
137
'launchpad_services_root': self.launchpad.api,
139
print ("\t[Success: Logged in as %s]" %
140
self.launchpad.service.launchpad.me.display_name)
142
def prepare_to_launch(self):
143
self.tmpdir = tempfile.mkdtemp()
146
self.login_launchpad()
147
except LaunchpadServiceError as e:
148
print "\t[Error: %s]" % e.msg
151
def finish_launched(self):
152
shutil.rmtree(self.tmpdir)
155
self.prepare_to_launch()
157
self.finish_launched()
159
class LaunchpadBugzillaApplication(LaunchpadApplication):
160
def __init__(self, appname, lpurl, bzurl, flags, modifiers):
161
self.bugzilla = BugzillaInfo(url=bzurl,
163
password=self.bzpassword)
165
LaunchpadApplication.__init__(self,
171
self.print_debug(self.bugzilla)
173
def parse_bugids(self):
174
LaunchpadApplication.parse_bugids(self)
176
pattern = re.compile(r'^.*[^\d](\d+)$')
177
result = pattern.search(self.bugzilla.url)
179
self.bugzilla.bugid = result.groups()[0]
181
def parse_urls(self):
182
LaunchpadApplication.parse_urls(self)
184
self.bugzilla.parsedurl = urlparse(self.bugzilla.url)
186
pattern = re.compile(r'^(.*)show_bug\.cgi\?id=(\d+)$')
187
self.bugzilla.attachurl = pattern.sub(
188
r'\1attachment.cgi?bugid=\2&action=enter', self.bugzilla.url)
190
def get_user_from_config(self):
191
path = os.path.expanduser('~/.config/arsenal')
193
if not os.path.isdir(path):
195
fd = open(os.path.join(path, 'bugzilla.ini'), 'a+')
197
config = ConfigParser()
200
section = self.bugzilla.parsedurl.netloc
201
if not config.has_section(section):
202
config.add_section(section)
204
if not config.has_option(section, 'user'):
205
config.set(section, 'user',
206
raw_input('\tEnter Bugzilla username: '))
211
return config.get(section, 'user')
213
def get_password_from_keyring(self):
215
glib.set_application_name(keyring)
217
if not keyring in gkeyring.list_keyring_names_sync():
218
print "\tCreating new keyring for Arsenal"
219
gkeyring.create_sync(keyring, getpass("\tKeyring Password: "))
221
info = gkeyring.get_info_sync(keyring)
222
if info.get_is_locked():
223
print "\tUnlocking keyring for Arsenal"
224
gkeyring.unlock_sync(keyring, getpass("\tKeyring Password: "))
227
for id in gkeyring.list_item_ids_sync(keyring):
228
item = gkeyring.item_get_info_sync(keyring, id)
229
if self.bugzilla.username == item.get_display_name():
230
attrs = gkeyring.item_get_attributes_sync(keyring, id)
231
if attrs['netloc'] == self.bugzilla.parsedurl.netloc:
232
secret = item.get_secret()
235
attrs = {'netloc' : self.bugzilla.parsedurl.netloc}
236
id = gkeyring.item_create_sync(keyring,
237
gkeyring.ITEM_GENERIC_SECRET,
238
self.bugzilla.username,
240
getpass("\tEnter Bugzilla password: "),
242
item = gkeyring.item_get_info_sync(keyring, id)
243
secret = item.get_secret()
247
def login_bugzilla(self, bzadapter):
248
if not self.bugzilla.username:
249
self.bugzilla.username = self.get_user_from_config()
251
if not self.bugzilla.password:
252
self.bugzilla.password = self.get_password_from_keyring()
254
if self.bugzilla.username and self.bugzilla.password:
255
return bzadapter.login(self.bugzilla.attachurl,
256
self.bugzilla.username,
257
self.bugzilla.password)
259
raise BugzillaLoginError("Invalid username/password")
261
def prepare_to_launch(self):
262
LaunchpadApplication.prepare_to_launch(self)
264
self.bzadapter = BugzillaAdapter(self.tmpdir)
265
if self.bzadapter.is_login_required(self.bugzilla.attachurl):
267
print "Logging into Bugzilla"
268
username = self.login_bugzilla(self.bzadapter)
270
print "\t[Success: Logged in as %s]" % username
271
except BugzillaLoginError as e:
272
print "\t[Error: %s]" % e