def dump_json(rows, last_mod, total_lines, emails): """ Dump the blame as a json object to the terminal. """ result = {} authors = [] for author, nlines in rows: authors.append({ "last_commit": pretty_date(last_mod[author]), "lines": nlines, "percentage": round(nlines / float(total_lines) * 100, 1), "author": author, "email": emails[author] }) result['authors'] = authors result["totals"] = { "last_commit": pretty_date(max(last_mod.values())), "lines": total_lines, "percentage": "100.0" } sjson.dump(result, sys.stdout)
def print_table(rows, last_mod, total_lines, emails): """ Given a set of rows with authors and lines, print a table. """ table = [['LAST_COMMIT', 'LINES', '%', 'AUTHOR', 'EMAIL']] for author, nlines in rows: table += [[ pretty_date(last_mod[author]), nlines, round(nlines / float(total_lines) * 100, 1), author, emails[author] ]] table += [[''] * 5] table += [[pretty_date(max(last_mod.values())), total_lines, '100.0'] + [''] * 3] colify_table(table)
def blame(parser, args): # make sure this is a git repo if not spack_is_git_repo(): tty.die("This spack is not a git clone. Can't use 'spack blame'") git = which('git', required=True) # Get name of file to blame blame_file = None if os.path.isfile(args.package_name): path = os.path.realpath(args.package_name) if path.startswith(spack.paths.prefix): blame_file = path if not blame_file: pkg = spack.repo.get(args.package_name) blame_file = pkg.module.__file__.rstrip('c') # .pyc -> .py # get git blame for the package with working_dir(spack.paths.prefix): if args.view == 'git': git('blame', blame_file) return else: output = git('blame', '--line-porcelain', blame_file, output=str) lines = output.split('\n') # Histogram authors counts = {} emails = {} last_mod = {} total_lines = 0 for line in lines: match = re.match(r'^author (.*)', line) if match: author = match.group(1) match = re.match(r'^author-mail (.*)', line) if match: email = match.group(1) match = re.match(r'^author-time (.*)', line) if match: mod = int(match.group(1)) last_mod[author] = max(last_mod.setdefault(author, 0), mod) # ignore comments if re.match(r'^\t[^#]', line): counts[author] = counts.setdefault(author, 0) + 1 emails.setdefault(author, email) total_lines += 1 if args.view == 'time': rows = sorted( counts.items(), key=lambda t: last_mod[t[0]], reverse=True) else: # args.view == 'percent' rows = sorted(counts.items(), key=lambda t: t[1], reverse=True) # Print a nice table with authors and emails table = [['LAST_COMMIT', 'LINES', '%', 'AUTHOR', 'EMAIL']] for author, nlines in rows: table += [[ pretty_date(last_mod[author]), nlines, round(nlines / float(total_lines) * 100, 1), author, emails[author]]] table += [[''] * 5] table += [[pretty_date(max(last_mod.values())), total_lines, '100.0'] + [''] * 3] colify_table(table)
def test_pretty_date(): """Make sure pretty_date prints the right dates.""" now = datetime.now() just_now = now - timedelta(seconds=5) assert pretty_date(just_now, now) == "just now" seconds = now - timedelta(seconds=30) assert pretty_date(seconds, now) == "30 seconds ago" a_minute = now - timedelta(seconds=60) assert pretty_date(a_minute, now) == "a minute ago" minutes = now - timedelta(seconds=1800) assert pretty_date(minutes, now) == "30 minutes ago" an_hour = now - timedelta(hours=1) assert pretty_date(an_hour, now) == "an hour ago" hours = now - timedelta(hours=2) assert pretty_date(hours, now) == "2 hours ago" yesterday = now - timedelta(days=1) assert pretty_date(yesterday, now) == "yesterday" days = now - timedelta(days=3) assert pretty_date(days, now) == "3 days ago" a_week = now - timedelta(weeks=1) assert pretty_date(a_week, now) == "a week ago" weeks = now - timedelta(weeks=2) assert pretty_date(weeks, now) == "2 weeks ago" a_month = now - timedelta(days=30) assert pretty_date(a_month, now) == "a month ago" months = now - timedelta(days=60) assert pretty_date(months, now) == "2 months ago" a_year = now - timedelta(days=365) assert pretty_date(a_year, now) == "a year ago" years = now - timedelta(days=365 * 2) assert pretty_date(years, now) == "2 years ago"
def blame(parser, args): # make sure this is a git repo if not spack_is_git_repo(): tty.die("This spack is not a git clone. Can't use 'spack blame'") git = which('git', required=True) # Get name of file to blame blame_file = None if os.path.isfile(args.package_or_file): path = os.path.realpath(args.package_or_file) if path.startswith(spack.paths.prefix): blame_file = path if not blame_file: pkg = spack.repo.get(args.package_or_file) blame_file = pkg.module.__file__.rstrip('c') # .pyc -> .py # get git blame for the package with working_dir(spack.paths.prefix): if args.view == 'git': git('blame', blame_file) return else: output = git('blame', '--line-porcelain', blame_file, output=str) lines = output.split('\n') # Histogram authors counts = {} emails = {} last_mod = {} total_lines = 0 for line in lines: match = re.match(r'^author (.*)', line) if match: author = match.group(1) match = re.match(r'^author-mail (.*)', line) if match: email = match.group(1) match = re.match(r'^author-time (.*)', line) if match: mod = int(match.group(1)) last_mod[author] = max(last_mod.setdefault(author, 0), mod) # ignore comments if re.match(r'^\t[^#]', line): counts[author] = counts.setdefault(author, 0) + 1 emails.setdefault(author, email) total_lines += 1 if args.view == 'time': rows = sorted(counts.items(), key=lambda t: last_mod[t[0]], reverse=True) else: # args.view == 'percent' rows = sorted(counts.items(), key=lambda t: t[1], reverse=True) # Print a nice table with authors and emails table = [['LAST_COMMIT', 'LINES', '%', 'AUTHOR', 'EMAIL']] for author, nlines in rows: table += [[ pretty_date(last_mod[author]), nlines, round(nlines / float(total_lines) * 100, 1), author, emails[author] ]] table += [[''] * 5] table += [[pretty_date(max(last_mod.values())), total_lines, '100.0'] + [''] * 3] colify_table(table)