def print_control_message(html_message): message = normalize_space(''.join(html_message.xpath('.//text()'))) match = re.match( r'^(.*) ' r'Request was from (.+) to ([\w-]+@bugs[.]debian[.]org). ' r'(?:[(]([A-Z][a-z]{2}, [0-9]{2} [A-Z][a-z]{2} [0-9]{4} [0-9]{2}:[0-9]{2}:[0-9]{2} GMT)[)] )?' r'Full text and rfc822 format available[.]$', message) if match is not None: message, req_from, req_to, date = match.groups() print_header('Request-From', '{mail}', mail=req_from) print_header('Request-To', '{mail}', mail=req_to) if date is not None: date = email.utils.parsedate_to_datetime(date) print_header('Date', '{date}', date=date) colorterm.print() colorterm.print('{msg}', msg=message)
def print_control_message(html_message): message = normalize_space( ''.join(html_message.xpath('.//text()')) ) match = re.match( r'^(.*) ' r'Request was from (.+) to ([\w-]+@bugs[.]debian[.]org). ' r'(?:[(]([A-Z][a-z]{2}, [0-9]{2} [A-Z][a-z]{2} [0-9]{4} [0-9]{2}:[0-9]{2}:[0-9]{2} GMT)[)] )?' r'Full text and rfc822 format available[.]$', message ) if match is not None: message, req_from, req_to, date = match.groups() print_header('Request-From', '{mail}', mail=req_from) print_header('Request-To', '{mail}', mail=req_to) if date is not None: date = email.utils.parsedate_to_datetime(date) print_header('Date', '{date}', date=date) colorterm.print() colorterm.print('{msg}', msg=message)
def print_message(message, attachments=()): headers = message.header for hname in ['From', 'To', 'Cc', 'Subject']: value = headers[hname] if value is None: continue value = decode_header(value) value = normalize_space(value) print_header(hname, '{v}', v=value) date = headers['Date'] if date is not None: date = email.utils.parsedate_to_datetime(date) print_header('Date', '{date}', date=date) if attachments: print_header('Attachments') for name, url, tp in attachments: template = '<{t.cyan}{url}{t.off}> ({tp})' if name is not None: template = '{name} ' + template colorterm.print(' ' + template, name=name, url=url, tp=tp ) colorterm.print() body = message.body or '' for line in body.splitlines(): colorterm.print('{l}', l=line)
def print_message(message, attachments=()): headers = message.header for hname in ['From', 'To', 'Cc', 'Subject']: value = headers[hname] if value is None: continue value = decode_header(value) value = normalize_space(value) print_header(hname, '{v}', v=value) date = headers['Date'] if date is not None: date = email.utils.parsedate_to_datetime(date) print_header('Date', '{date}', date=date) if attachments: print_header('Attachments') for name, url, tp in attachments: template = '<{t.cyan}{url}{t.off}> ({tp})' if name is not None: template = '{name} ' + template colorterm.print(' ' + template, name=name, url=url, tp=tp) colorterm.print() body = message.body or '' for line in body.splitlines(): colorterm.print('{l}', l=line)
def run(options): debsoap_client = debsoap.Client(session=options.session) queries = [] for selection in options.selections: bugno = None try: bugno = deblogic.parse_bugspec(selection) except ValueError: pass if bugno is not None: queries += [bugno] elif ':' in selection: selector, value = selection.split(':', 1) selector = selectors[selector] if callable(selector): queries += selector(value) else: queries += [{selector: value}] elif deblogic.is_package_name(selection): queries += [dict(package=selection)] else: path = selection try: os.stat(path) except OSError: options.error('{0!r} is not a valid package name'.format(selection)) if os.path.isdir(path): queries += select_for_unpacked(path) elif path.endswith('.deb'): queries += select_for_deb(path) elif path.endswith('.dsc'): queries += select_for_dsc(path) else: options.error('{0!r} is not a valid package name'.format(selection)) bugs = debsoap_client.get_bugs(*queries) bugs = sorted(bugs, key=(lambda bug: -bug.id)) for bug in bugs: package = bug.package subject = bug.subject or '' default_severity = 'normal' if package == 'wnpp': for wnpp_tag in deblogic.wnpp_tags: if subject.startswith(wnpp_tag + ': '): if wnpp_tag[-1] == 'P': default_severity = 'wishlist' package = None break elif package == 'sponsorship-requests': if subject.startswith('RFS:'): package = None template = '' source = None subject_color = '{t.green}' if bug.done else '{t.bold}' if package is not None: if package.startswith('src:'): source = package[4:] new_subject = strip_package_prefix(subject, source) if subject != new_subject: subject = new_subject template += '[src:' + subject_color + '{src}{t.off}] ' else: template += '[src:{src}] ' else: new_subject = strip_package_prefix(subject, package) if subject != new_subject: subject = new_subject template += '[' + subject_color + '{pkg}{t.off}] ' else: template += '[{pkg}] ' if subject: template += subject_color + '{subject}{t.off}' else: template += '{t.red}(no subject){t.off}' colorterm.print(template, pkg=package, src=source, subject=subject, ) indent = ' ' template = indent + '{t.cyan}https://bugs.debian.org/{n}{t.off}' if bug.forwarded: template += ' -> {t.cyan}{forwarded}{t.off}' colorterm.print(template, n=bug.id, forwarded=bug.forwarded) template = indent + '{user}; {date}-00:00' user = bug.submitter if package == 'wnpp' and bug.owner is not None: user = bug.owner colorterm.print(template, user=user, date=bug.date, ) template = '' if bug.severity != default_severity: severity_color = ( '{t.bold}{t.red}' if bug.severity in deblogic.rc_severities else '' ) template = severity_color + '{severity}{t.off}' if bug.tags: if template: template += ' ' template += '{tags}' if template: template = indent + template colorterm.print(template, tags=' '.join('+' + t for t in bug.tags), severity=bug.severity, ) template = '' if bug.found_versions: template = 'found in {found}' if bug.fixed_versions: if template: template += '; ' template += 'fixed in {fixed}' if template: template = indent + template colorterm.print(template, found=', '.join(bug.found_versions), fixed=', '.join(bug.fixed_versions), ) print()
def run_one(bugno, *, options): print_header('Location', '{t.cyan}{t.bold}https://bugs.debian.org/{N}{t.off}', N=bugno) session = options.session url = 'https://bugs.debian.org/cgi-bin/bugreport.cgi?bug={0}'.format(bugno) data = session.get(url) html = lxml.html.fromstring(data) html.make_links_absolute(base_url=url) debsoap_client = debsoap.Client(session=session) status = debsoap_client.get_status(bugno) print_header('Subject', '{t.bold}{subject}{t.off}', subject=status.subject) if ',' not in status.package and status.package.startswith('src:'): print_header('Source', '{t.bold}{pkg}{t.off}', pkg=status.package[4:]) else: packages = status.package.split(',') template = ', '.join('{t.bold}{pkgs[N]}{t.off}'.replace('N', str(i)) for i, _ in enumerate(packages)) print_header('Package', template, pkgs=packages) if status.source is not None: print_header('Source', '{pkg}', pkg=status.source) # TODO: use SOAP to extract Maintainer # https://bugs.debian.org/553661 print_header('Maintainer', '{maint}', maint=', '.join(extract_maintainers(html))) if status.affects: print_header('Affects') for apkg in status.affects: colorterm.print(' {pkg}', pkg=apkg) if status.owner: print_header('Owner', '{user}', user=status.owner) if status.package == 'wnpp' and status.owner == status.submitter: pass else: print_header('Submitter', '{user}', user=status.submitter) print_header('Date', '{date}-00:00', date=status.date) severity_color = ('{t.bold}{t.red}' if status.severity in deblogic.rc_severities else '') print_header( 'Severity', severity_color + '{severity}{t.off}', severity=status.severity, ) version_graph = extract_bug_version_graph(html, options=options) if status.tags: print_header('Tags', '{tags}', tags=' '.join(status.tags)) if status.merged_with: print_header('Merged-with') for mbug in status.merged_with: colorterm.print(' {t.cyan}https://bugs.debian.org/{N}{t.off}', N=mbug) if status.found_versions: print_header('Found') for version in status.found_versions: colorterm.print(' {ver}', ver=version) if status.fixed_versions: print_header('Fixed') for version in status.fixed_versions: colorterm.print(' {ver}', ver=version) if version_graph: print_header('Version-Graph') print_version_graph(version_graph, ilevel=2) if status.blocked_by: print_header('Blocked-by') for bbug in status.blocked_by: colorterm.print(' {t.cyan}https://bugs.debian.org/{N}{t.off}', N=bbug) if status.blocks: print_header('Blocks') for bbug in status.blocks: colorterm.print(' {t.cyan}https://bugs.debian.org/{N}{t.off}', N=bbug) if status.done: print_header('Done', '{user}', user=status.done) if status.archived: print_header('Archived', 'yes') if status.forwarded: print_header('Forwarded', '{url}', url=status.forwarded) colorterm.print_hr() bug_log = debsoap_client.get_log(bugno) html_messages = html.xpath('//*[@class="msgreceived"]') attachments = extract_attachments(html) for html_message in html_messages: anchors = html_message.xpath('./a/@name') if not anchors: continue msgno = int(anchors[0]) print_header('Location', '{t.cyan}https://bugs.debian.org/{N}#{id}{t.off}', N=bugno, id=msgno) try: message = bug_log[msgno] except KeyError: print_control_message(html_message) else: print_message(message, attachments=attachments[msgno]) colorterm.print_hr() colorterm.print() if options.merged: options.merged = False try: for mbug in status.merged_with: run_one(mbug, options=options) finally: options.merged = True
def print_header(_h, _s=None, **kwargs): template = '{t.yellow}' + _h + ':{t.off}' if _s is not None: template += ' ' + _s colorterm.print(template, **kwargs)
def run(options): utils.reset_SIGPIPE() debsoap_client = debsoap.Client(session=options.session) queries = [] for selection in options.selections: bugno = None try: bugno = deblogic.parse_bugspec(selection) except ValueError: pass if bugno is not None: queries += [bugno] elif utils.looks_like_path(selection): path = selection try: os.stat(path) except OSError: options.error('{0!r} is not a package'.format(path)) if os.path.isdir(path + '/debian'): queries += select_for_unpacked(path) elif path.endswith('.dsc'): queries += select_for_dsc(path) elif path.endswith('.deb'): queries += select_for_deb(path) else: options.error('{0!r} is not a package'.format(path)) elif ':' in selection: selector, value = selection.split(':', 1) try: selector = selectors[selector] except KeyError: options.error('{0!r} is not a valid selector'.format(selector)) if callable(selector): queries += selector(value) else: queries += [{selector: value}] elif deblogic.is_package_name(selection): queries += [dict(package=selection)] else: options.error( '{0!r} is not a valid package name'.format(selection)) bugs = debsoap_client.get_bugs(*queries) bugs = sorted(bugs, key=(lambda bug: -bug.id)) for bug in bugs: package = bug.package subject = bug.subject or '' default_severity = 'normal' if package == 'wnpp': for wnpp_tag in deblogic.wnpp_tags: if subject.startswith(wnpp_tag + ': '): if wnpp_tag[-1] == 'P': default_severity = 'wishlist' package = None break elif package == 'sponsorship-requests': if subject.startswith('RFS:'): package = None template = '' source = None subject_color = '{t.green}' if bug.done else '{t.bold}' if package is not None: if package.startswith('src:'): source = package[4:] new_subject = strip_package_prefix(subject, source) if subject != new_subject: subject = new_subject template += '[src:' + subject_color + '{src}{t.off}] ' else: template += '[src:{src}] ' else: new_subject = strip_package_prefix(subject, package) if subject != new_subject: subject = new_subject template += '[' + subject_color + '{pkg}{t.off}] ' else: template += '[{pkg}] ' if subject: template += subject_color + '{subject}{t.off}' else: template += '{t.red}(no subject){t.off}' colorterm.print( template, pkg=package, src=source, subject=subject, ) indent = ' ' template = indent + '{t.cyan}https://bugs.debian.org/{n}{t.off}' if bug.forwarded: template += ' -> {t.cyan}{forwarded}{t.off}' colorterm.print(template, n=bug.id, forwarded=bug.forwarded) template = indent + '{user}; {date}-00:00' user = bug.submitter if package == 'wnpp' and bug.owner is not None: user = bug.owner colorterm.print( template, user=user, date=bug.date, ) template = '' if bug.severity != default_severity: severity_color = ('{t.bold}{t.red}' if bug.severity in deblogic.rc_severities else '') template = severity_color + '{severity}{t.off}' if bug.tags: if template: template += ' ' template += '{tags}' if template: template = indent + template colorterm.print( template, tags=' '.join('+' + t for t in bug.tags), severity=bug.severity, ) template = '' if bug.found_versions: template = 'found in {found}' if bug.fixed_versions: if template: template += '; ' template += 'fixed in {fixed}' if template: template = indent + template colorterm.print( template, found=', '.join(bug.found_versions), fixed=', '.join(bug.fixed_versions), ) print()
def run_one(bugno, *, options): print_header('Location', '{t.cyan}{t.bold}https://bugs.debian.org/{N}{t.off}', N=bugno) session = options.session url = 'https://bugs.debian.org/cgi-bin/bugreport.cgi?bug={0}'.format(bugno) response = session.get(url) response.raise_for_status() html = lxml.html.fromstring(response.text) html.make_links_absolute(base_url=url) debsoap_client = debsoap.Client(session=session) status = debsoap_client.get_status(bugno) print_header('Subject', '{t.bold}{subject}{t.off}', subject=status.subject) if ',' not in status.package and status.package.startswith('src:'): print_header('Source', '{t.bold}{pkg}{t.off}', pkg=status.package[4:]) else: packages = status.package.split(',') template = ', '.join( '{t.bold}{pkgs[N]}{t.off}'.replace('N', str(i)) for i, _ in enumerate(packages) ) print_header('Package', template, pkgs=packages) if status.source is not None: print_header('Source', '{pkg}', pkg=status.source) # TODO: use SOAP to extract Maintainer # https://bugs.debian.org/553661 print_header('Maintainer', '{maint}', maint=', '.join(extract_maintainers(html)) ) if status.affects: print_header('Affects') for apkg in status.affects: colorterm.print(' {pkg}', pkg=apkg) if status.owner: print_header('Owner', '{user}', user=status.owner) if status.package == 'wnpp' and status.owner == status.submitter: pass else: print_header('Submitter', '{user}', user=status.submitter) print_header('Date', '{date}-00:00', date=status.date) severity_color = ( '{t.bold}{t.red}' if status.severity in deblogic.rc_severities else '' ) print_header('Severity', severity_color + '{severity}{t.off}', severity=status.severity, ) version_graph = extract_bug_version_graph(html, options=options) if status.tags: print_header('Tags', '{tags}', tags=' '.join(status.tags)) if status.merged_with: print_header('Merged-with') for mbug in status.merged_with: colorterm.print(' {t.cyan}https://bugs.debian.org/{N}{t.off}', N=mbug) if status.found_versions: print_header('Found') for version in status.found_versions: colorterm.print(' {ver}', ver=version) if status.fixed_versions: print_header('Fixed') for version in status.fixed_versions: colorterm.print(' {ver}', ver=version) if version_graph: print_header('Version-Graph') print_version_graph(version_graph, ilevel=2) if status.blocked_by: print_header('Blocked-by') for bbug in status.blocked_by: colorterm.print(' {t.cyan}https://bugs.debian.org/{N}{t.off}', N=bbug) if status.blocks: print_header('Blocks') for bbug in status.blocks: colorterm.print(' {t.cyan}https://bugs.debian.org/{N}{t.off}', N=bbug) if status.done: print_header('Done', '{user}', user=status.done) if status.archived: print_header('Archived', 'yes') if status.forwarded: print_header('Forwarded', '{url}', url=status.forwarded) colorterm.print_hr() bug_log = debsoap_client.get_log(bugno) html_messages = html.xpath('//*[@class="msgreceived"]') attachments = extract_attachments(html) for html_message in html_messages: anchors = html_message.xpath('./a/@name') if not anchors: continue msgno = int(anchors[0]) print_header('Location', '{t.cyan}https://bugs.debian.org/{N}#{id}{t.off}', N=bugno, id=msgno) try: message = bug_log[msgno] except KeyError: print_control_message(html_message) else: print_message(message, attachments=attachments[msgno]) colorterm.print_hr() colorterm.print() if options.merged: options.merged = False try: for mbug in status.merged_with: run_one(mbug, options=options) finally: options.merged = True