Add 'spack blame' command: shows contributors to packages

`spack blame` prints out the contributors to a package.

By modification time:

```
$ spack blame --time llvm
LAST_COMMIT    LINES  %      AUTHOR               EMAIL
3 days ago     2      0.6    Andrey Prokopenko    <andrey.prok@gmail.com>
3 weeks ago    125    34.7   Massimiliano Culpo   <massimiliano.culpo@epfl.ch>
3 weeks ago    3      0.8    Peter Scheibel       <scheibel1@llnl.gov>
2 months ago   21     5.8    Adam J. Stewart      <ajstewart426@gmail.com>
2 months ago   1      0.3    Gregory Becker       <becker33@llnl.gov>
3 months ago   116    32.2   Todd Gamblin         <tgamblin@llnl.gov>
5 months ago   2      0.6    Jimmy Tang           <jcftang@gmail.com>
5 months ago   6      1.7    Jean-Paul Pelteret   <jppelteret@gmail.com>
7 months ago   65     18.1   Tom Scogland         <tscogland@llnl.gov>
11 months ago  13     3.6    Kelly (KT) Thompson  <kgt@lanl.gov>
a year ago     1      0.3    Scott Pakin          <pakin@lanl.gov>
a year ago     3      0.8    Erik Schnetter       <schnetter@gmail.com>
3 years ago    2      0.6    David Beckingsale    <davidbeckingsale@gmail.com>

3 days ago     360    100.0
```

Or by percent contribution:

```
$ spack blame --percent llvm
LAST_COMMIT    LINES  %      AUTHOR               EMAIL
3 weeks ago    125    34.7   Massimiliano Culpo   <massimiliano.culpo@epfl.ch>
3 months ago   116    32.2   Todd Gamblin         <tgamblin@llnl.gov>
7 months ago   65     18.1   Tom Scogland         <tscogland@llnl.gov>
2 months ago   21     5.8    Adam J. Stewart      <ajstewart426@gmail.com>
11 months ago  13     3.6    Kelly (KT) Thompson  <kgt@lanl.gov>
5 months ago   6      1.7    Jean-Paul Pelteret   <jppelteret@gmail.com>
3 weeks ago    3      0.8    Peter Scheibel       <scheibel1@llnl.gov>
a year ago     3      0.8    Erik Schnetter       <schnetter@gmail.com>
3 years ago    2      0.6    David Beckingsale    <davidbeckingsale@gmail.com>
3 days ago     2      0.6    Andrey Prokopenko    <andrey.prok@gmail.com>
5 months ago   2      0.6    Jimmy Tang           <jcftang@gmail.com>
2 months ago   1      0.3    Gregory Becker       <becker33@llnl.gov>
a year ago     1      0.3    Scott Pakin          <pakin@lanl.gov>

3 days ago     360    100.0
```
This commit is contained in:
Todd Gamblin
2017-09-28 10:47:08 -07:00
parent 46d5901770
commit 41a2652ef2
6 changed files with 280 additions and 25 deletions

View File

@@ -27,6 +27,7 @@
import functools
import collections
import inspect
from datetime import datetime
from six import string_types
# Ignore emacs backups when listing modules
@@ -385,6 +386,75 @@ def dedupe(sequence):
seen.add(x)
def pretty_date(time, now=None):
"""Convert a datetime or timestamp to a pretty, relative date.
Args:
time (datetime or int): date to print prettily
now (datetime): dateimte for 'now', i.e. the date the pretty date
is relative to (default is datetime.now())
Returns:
(str): pretty string like 'an hour ago', 'Yesterday',
'3 months ago', 'just now', etc.
Adapted from https://stackoverflow.com/questions/1551382.
"""
if now is None:
now = datetime.now()
if type(time) is int:
diff = now - datetime.fromtimestamp(time)
elif isinstance(time, datetime):
diff = now - time
else:
raise ValueError("pretty_date requires a timestamp or datetime")
second_diff = diff.seconds
day_diff = diff.days
if day_diff < 0:
return ''
if day_diff == 0:
if second_diff < 10:
return "just now"
if second_diff < 60:
return str(second_diff) + " seconds ago"
if second_diff < 120:
return "a minute ago"
if second_diff < 3600:
return str(second_diff / 60) + " minutes ago"
if second_diff < 7200:
return "an hour ago"
if second_diff < 86400:
return str(second_diff / 3600) + " hours ago"
if day_diff == 1:
return "yesterday"
if day_diff < 7:
return str(day_diff) + " days ago"
if day_diff < 28:
weeks = day_diff / 7
if weeks == 1:
return "a week ago"
else:
return str(day_diff / 7) + " weeks ago"
if day_diff < 365:
months = day_diff / 30
if months == 1:
return "a month ago"
elif months == 12:
months -= 1
return str(months) + " months ago"
diff = day_diff / 365
if diff == 1:
return "a year ago"
else:
return str(diff) + " years ago"
class RequiredAttributeError(ValueError):
def __init__(self, message):