#!/usr/bin/python3 import argparse from datetime import datetime import os import re import subprocess import sys def format_date(timestamp): date_to_format = datetime.utcfromtimestamp(timestamp) delta = datetime.utcnow() - date_to_format output = date_to_format.strftime('%Y-%m-%d %H:%M') if delta.days > 1: output += ' ({} days ago)'.format(delta.days) elif delta.days == 1: output += ' (yesterday)' return output parser = argparse.ArgumentParser(description="Review DSA/DLA needed queues") parser.add_argument('--lts', action='store_true', help='Review dla-needed.txt instead of dsa-needed.txt') parser.add_argument('-v', '--verbose', action='store_true', help='Review dla-needed.txt instead of dsa-needed.txt') parser.add_argument('--sort-by', default='last-update', help='Sort by last-update (default) or by claimed-date') parser.add_argument('--skip-unclaimed', action='store_true', help='Skip unclaimed packages in the review') args = parser.parse_args() if args.lts: dsa_dla_needed = 'data/dla-needed.txt' else: dsa_dla_needed = 'data/dsa-needed.txt' if args.sort_by not in ('last-update', 'claimed-date'): sys.stderr.write('ERROR: usage: --sort-by={last-update,claimed-date}\n') sys.exit(1) if not os.path.exists(dsa_dla_needed): sys.stderr.write("ERROR: {} not found\n".format(dsa_dla_needed)) sys.exit(1) if not os.path.exists(".git"): sys.stderr.write("ERROR: works only in a git checkout\n") sys.exit(1) process = subprocess.Popen(["git", "blame", "--line-porcelain", "--", dsa_dla_needed], stdout=subprocess.PIPE) context = {} in_preamble = True all_entries = [] entry = None for line in process.stdout: line = line.decode('utf-8') res = re.search(r'^([0-9a-f]{40}) \d+', line) if res: context['commit'] = res.group(1) if line.startswith('author '): context['author'] = line.strip().split()[1] elif line.startswith('author-time '): context['author-time'] = int(line.strip().split()[1]) elif line.startswith('summary '): context['summary'] = line.strip().split(maxsplit=1)[1] elif line.startswith("\t"): line = line[1:] if line.startswith("--"): in_preamble = False entry = None elif in_preamble: continue elif line[0] == ' ' or line[0] == "\t": entry['note'] += line if context['author-time'] > entry['last-update']: entry['last-update'] = context['author-time'] entry['last-update-author'] = context['author'] entry['last-update-summary'] = context['summary'] entry['last-update-commit'] = context['commit'] else: res = re.match(r'^(\S+)(?:\s+\((.*)\)\s*)?$', line) entry = { 'pkg': res.group(1), 'claimed-by': res.group(2), 'claimed-date': context['author-time'], 'last-update': context['author-time'], 'last-update-author': context['author'], 'last-update-summary': context['summary'], 'last-update-commit': context['commit'], 'author': context['author'], 'note': '', } all_entries.append(entry) retcode = process.wait() if retcode != 0: sys.stderr.write("WARNING: git blame returned error code {}\n".format(retcode)) all_entries.sort(key=lambda x: x[args.sort_by]) for entry in all_entries: if args.skip_unclaimed and not entry['claimed-by']: continue print("Package: {}".format(entry['pkg'])) if entry['claimed-by']: print("Claimed-By: {}".format(entry['claimed-by'])) print("Claimed-Date: {}".format(format_date(entry['claimed-date']))) else: print("Unclaimed-Since: {}".format(format_date(entry['claimed-date']))) if entry['last-update'] > entry['claimed-date']: print("Last-Update: {}".format(format_date(entry['last-update']))) if not args.verbose: print("") continue print("Last-Update-Author: {}".format(entry['last-update-author'])) print("Last-Update-Summary: {}".format(entry['last-update-summary'])) print("Last-Update-Commit: {}".format(entry['last-update-commit'])) if entry['note']: print("Notes:\n{}".format(entry['note'])) else: print("")