def _check_dsc(self, verify_signature=False): "Check that the dsc matches what we are expecting" assert self._dsc is not None self.source = self.dsc['Source'] self.version = debian.debian_support.Version(self.dsc['Version']) valid = False message = None gpg_info = None try: gpg_info = self.dsc.get_gpg_info() valid = gpg_info.valid() except IOError: message = ('Signature on %s could not be verified, install ' 'debian-keyring' % self.dsc_name) if message is None: if valid: message = 'Valid signature' else: message = ('Signature on %s could not be verified' % self.dsc_name) if gpg_info is not None: if 'GOODSIG' in gpg_info: message = ('Good signature by %s (0x%s)' % (gpg_info['GOODSIG'][1], gpg_info['GOODSIG'][0])) elif 'VALIDSIG' in gpg_info: message = 'Valid signature by 0x%s' % gpg_info['VALIDSIG'][0] if verify_signature: if valid: Logger.normal(message) else: Logger.error(message) raise DownloadError(message) else: Logger.info(message)
def ask_for_patch_or_branch(bug, attached_patches, linked_branches): patch = None branch = None if len(attached_patches) == 0: msg = "https://launchpad.net/bugs/%i has %i branches linked:" % \ (bug.id, len(linked_branches)) elif len(linked_branches) == 0: msg = "https://launchpad.net/bugs/%i has %i patches attached:" % \ (bug.id, len(attached_patches)) else: branches = "%i branch" % len(linked_branches) if len(linked_branches) > 1: branches += "es" patches = "%i patch" % len(attached_patches) if len(attached_patches) > 1: patches += "es" msg = "https://launchpad.net/bugs/%i has %s linked and %s attached:" % \ (bug.id, branches, patches) Logger.normal(msg) i = 0 for linked_branch in linked_branches: i += 1 print("%i) %s" % (i, linked_branch.display_name)) for attached_patch in attached_patches: i += 1 print("%i) %s" % (i, attached_patch.title)) selected = input_number("Which branch or patch do you want to download", 1, i, i) if selected <= len(linked_branches): branch = linked_branches[selected - 1].bzr_identity else: patch = Patch(attached_patches[selected - len(linked_branches) - 1]) return (patch, branch)
def get_open_ubuntu_bug_task(launchpad, bug, branch=None): """Returns an open Ubuntu bug task for a given Launchpad bug. The bug task needs to be open (not complete) and target Ubuntu. The user will be ask to select one if multiple open Ubuntu bug task exits for the bug. """ bug_tasks = [BugTask(x, launchpad) for x in bug.bug_tasks] ubuntu_tasks = [x for x in bug_tasks if x.is_ubuntu_task()] bug_id = bug.id if branch: branch = branch.split('/') # Non-production LP? if len(branch) > 5: branch = branch[3:] if len(ubuntu_tasks) == 0: Logger.error("No Ubuntu bug task found on bug #%i." % (bug_id)) sys.exit(1) elif len(ubuntu_tasks) == 1: task = ubuntu_tasks[0] if len(ubuntu_tasks) > 1 and branch and branch[1] == 'ubuntu': tasks = [ t for t in ubuntu_tasks if t.get_series() == branch[2] and t.package == branch[3] ] if len(tasks) > 1: # A bug targeted to the development series? tasks = [t for t in tasks if t.series is not None] assert len(tasks) == 1 task = tasks[0] elif len(ubuntu_tasks) > 1: task_list = [t.get_short_info() for t in ubuntu_tasks] Logger.info("%i Ubuntu tasks exist for bug #%i.\n%s", len(ubuntu_tasks), bug_id, "\n".join(task_list)) open_ubuntu_tasks = [x for x in ubuntu_tasks if not x.is_complete()] if len(open_ubuntu_tasks) == 1: task = open_ubuntu_tasks[0] else: Logger.normal( "https://launchpad.net/bugs/%i has %i Ubuntu tasks:" % (bug_id, len(ubuntu_tasks))) for i in range(len(ubuntu_tasks)): print("%i) %s" % (i + 1, ubuntu_tasks[i].get_package_and_series())) selected = input_number( "To which Ubuntu task does the patch belong", 1, len(ubuntu_tasks)) task = ubuntu_tasks[selected - 1] Logger.info("Selected Ubuntu task: %s" % (task.get_short_info())) return task
def ack_sync(self, upload, task, launchpad): """Acknowledge a sync request and subscribe ubuntu-archive.""" if upload == "ubuntu": self._print_logs() question = Question(["yes", "edit", "no"]) answer = question.ask("Do you want to acknowledge the sync request", "no") if answer == "edit": return False elif answer == "no": user_abort() bug = task.bug task.status = "Confirmed" if task.importance == "Undecided": task.importance = "Wishlist" task.lp_save() Logger.info("Set bug #%i status to Confirmed.", bug.id) msg = "Sync request ACK'd." if self._build_log: msg = ("%s %s builds on %s. " + msg) % \ (self._package, self._version, self._builder.get_architecture()) bug.newMessage(content=msg, subject="sponsor-patch") Logger.info("Acknowledged sync request bug #%i.", bug.id) bug.subscribe(person=launchpad.people['ubuntu-archive']) Logger.info("Subscribed ubuntu-archive to bug #%i.", bug.id) bug.subscribe(person=launchpad.me) Logger.info("Subscribed me to bug #%i.", bug.id) sponsorsteam = launchpad.people['ubuntu-sponsors'] for sub in bug.subscriptions: if sub.person == sponsorsteam and sub.canBeUnsubscribedByUser(): bug.unsubscribe(person=launchpad.people['ubuntu-sponsors']) Logger.info("Unsubscribed ubuntu-sponsors from bug #%i.", bug.id) elif sub.person == sponsorsteam: Logger.info("Couldn't unsubscribe ubuntu-sponsors from " "bug #%i.", bug.id) Logger.normal("Successfully acknowledged sync request bug #%i.", bug.id) else: Logger.error("Sync requests can only be acknowledged when the " "upload target is Ubuntu.") sys.exit(1) return True
def _download_file(self, url, filename): "Download url to filename in workdir." pathname = os.path.join(self.workdir, filename) if self.dsc.verify_file(pathname): Logger.debug('Using existing %s', filename) return True size = [ entry['size'] for entry in self.dsc['Files'] if entry['name'] == filename ] assert len(size) == 1 size = int(size[0]) parsed = urlparse(url) if not self.quiet: Logger.normal('Downloading %s from %s (%0.3f MiB)', filename, parsed.hostname, size / 1024.0 / 1024) if parsed.scheme == 'file': in_ = open(parsed.path, 'rb') else: try: in_ = self.url_opener.open(url) except URLError: return False downloaded = 0 bar_width = 60 try: with open(pathname, 'wb') as out: while True: block = in_.read(10240) if block == b'': break downloaded += len(block) out.write(block) if not self.quiet: percent = downloaded * 100 // size bar = '=' * int(round(downloaded * bar_width / size)) bar = (bar + '>' + ' ' * bar_width)[:bar_width] Logger.stdout.write('[%s] %#3i%%\r' % (bar, percent)) Logger.stdout.flush() in_.close() finally: if not self.quiet: Logger.stdout.write(' ' * (bar_width + 7) + '\r') Logger.stdout.flush() if not self.dsc.verify_file(pathname): Logger.error('Checksum for %s does not match.', filename) return False return True
def pull(self): "Pull into workdir" self._write_dsc() for entry in self.dsc['Files']: name = entry['name'] for url in self._source_urls(name): try: if self._download_file(url, name): break except HTTPError as e: Logger.normal('HTTP Error %i: %s', e.code, str(e)) except URLError as e: Logger.normal('URL Error: %s', e.reason) else: raise DownloadError('File %s could not be found' % name)
def lp_spph(self): "Return the LP Source Package Publishing History entry" if not self._spph: try: return super(DebianSourcePackage, self).lp_spph except IndexError: pass Logger.normal('Using rmadison for component determination') comp = 'main' for record in rmadison(self.distribution, self.source): if record.get('source') != self.source: continue comp = record['component'] if record['version'] == self.version.full_version: self._spph = FakeSPPH(record['source'], record['version'], comp, 'debian') return self._spph Logger.normal('Guessing component from most recent upload') self._spph = FakeSPPH(self.source, self.version.full_version, comp, 'debian') return self._spph
def mail_bug(srcpkg, subscribe, status, bugtitle, bugtext, bug_mail_domain, keyid, myemailaddr, mailserver_host, mailserver_port, mailserver_user, mailserver_pass): ''' Submit the sync request per email. ''' to = 'new@' + bug_mail_domain # generate mailbody if srcpkg: mailbody = ' affects ubuntu/%s\n' % srcpkg else: mailbody = ' affects ubuntu\n' mailbody += '''\ status %s importance wishlist subscribe %s done %s''' % (status, subscribe, bugtext) # prepare sign command gpg_command = None for cmd in ('gnome-gpg', 'gpg2', 'gpg'): if os.access('/usr/bin/%s' % cmd, os.X_OK): gpg_command = [cmd] break if not gpg_command: Logger.error("Cannot locate gpg, please install the 'gnupg' package!") sys.exit(1) gpg_command.append('--clearsign') if keyid: gpg_command.extend(('-u', keyid)) # sign the mail body gpg = subprocess.Popen(gpg_command, stdin=subprocess.PIPE, stdout=subprocess.PIPE) signed_report = gpg.communicate( mailbody.encode('utf-8'))[0].decode('utf-8') if gpg.returncode != 0: Logger.error("%s failed.", gpg_command[0]) sys.exit(1) # generate email mail = u'''\ From: %s To: %s Subject: %s Content-Type: text/plain; charset=UTF-8 %s''' % (myemailaddr, to, bugtitle, signed_report) print('The final report is:\n%s' % mail) confirmation_prompt() # save mail in temporary file backup = tempfile.NamedTemporaryFile( mode='w', delete=False, prefix='requestsync-' + re.sub(r'[^a-zA-Z0-9_-]', '', bugtitle.replace(' ', '_'))) with backup: backup.write(mail) Logger.normal( 'The e-mail has been saved in %s and will be deleted ' 'after succesful transmission', backup.name) # connect to the server while True: try: Logger.normal('Connecting to %s:%s ...', mailserver_host, mailserver_port) s = smtplib.SMTP(mailserver_host, mailserver_port) break except smtplib.SMTPConnectError as s: try: # py2 path # pylint: disable=unsubscriptable-object Logger.error('Could not connect to %s:%s: %s (%i)', mailserver_host, mailserver_port, s[1], s[0]) except TypeError: # pylint: disable=no-member Logger.error('Could not connect to %s:%s: %s (%i)', mailserver_host, mailserver_port, s.strerror, s.errno) if s.smtp_code == 421: confirmation_prompt( message='This is a temporary error, press [Enter] ' 'to retry. Press [Ctrl-C] to abort now.') except socket.error as s: try: # py2 path # pylint: disable=unsubscriptable-object Logger.error('Could not connect to %s:%s: %s (%i)', mailserver_host, mailserver_port, s[1], s[0]) except TypeError: # pylint: disable=no-member Logger.error('Could not connect to %s:%s: %s (%i)', mailserver_host, mailserver_port, s.strerror, s.errno) return if mailserver_user and mailserver_pass: try: s.login(mailserver_user, mailserver_pass) except smtplib.SMTPAuthenticationError: Logger.error('Error authenticating to the server: ' 'invalid username and password.') s.quit() return except smtplib.SMTPException: Logger.error('Unknown SMTP error.') s.quit() return while True: try: s.sendmail(myemailaddr, to, mail.encode('utf-8')) s.quit() os.remove(backup.name) Logger.normal('Sync request mailed.') break except smtplib.SMTPRecipientsRefused as smtperror: smtp_code, smtp_message = smtperror.recipients[to] Logger.error('Error while sending: %i, %s', smtp_code, smtp_message) if smtp_code == 450: confirmation_prompt( message='This is a temporary error, press [Enter] ' 'to retry. Press [Ctrl-C] to abort now.') else: return except smtplib.SMTPResponseException as e: Logger.error('Error while sending: %i, %s', e.smtp_code, e.smtp_error) return except smtplib.SMTPServerDisconnected: Logger.error('Server disconnected while sending the mail.') return