Skip to content

Commit

Permalink
Record installation date and time in DB (#7334)
Browse files Browse the repository at this point in the history
* Added installation date and time to the database

Information on the date and time of installation of a spec is recorded
into the database. The information is retained on reindexing.

* Expose the possibility to query for installation date

The DB can now be queried for specs that have been installed in a given
time window. This query possibility is exposed to command line via two
new options of the `find` command.

* Extended docstring for Database._add

* Use timestamps since the epoch instead of formatted date in the DB

* Allow 'pretty date' formats from command line

* Substituted kwargs with explicit arguments

* Simplified regex for pretty date strings. Added unit tests.
  • Loading branch information
alalazo authored and tgamblin committed Mar 22, 2018
1 parent 6699ba8 commit 5655895
Show file tree
Hide file tree
Showing 6 changed files with 262 additions and 51 deletions.
61 changes: 60 additions & 1 deletion lib/spack/llnl/util/lang.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
import functools
import collections
import inspect
from datetime import datetime
from datetime import datetime, timedelta
from six import string_types

# Ignore emacs backups when listing modules
Expand Down Expand Up @@ -442,6 +442,65 @@ def pretty_date(time, now=None):
return str(diff) + " years ago"


def pretty_string_to_date(date_str, now=None):
"""Parses a string representing a date and returns a datetime object.
Args:
date_str (str): string representing a date. This string might be
in different format (like ``YYYY``, ``YYYY-MM``, ``YYYY-MM-DD``)
or be a *pretty date* (like ``yesterday`` or ``two months ago``)
Returns:
(datetime): datetime object corresponding to ``date_str``
"""

pattern = {}

now = now or datetime.now()

# datetime formats
pattern[re.compile('^\d{4}$')] = lambda x: datetime.strptime(x, '%Y')
pattern[re.compile('^\d{4}-\d{2}$')] = lambda x: datetime.strptime(
x, '%Y-%m'
)
pattern[re.compile('^\d{4}-\d{2}-\d{2}$')] = lambda x: datetime.strptime(
x, '%Y-%m-%d'
)

pretty_regex = re.compile(
r'(a|\d+)\s*(year|month|week|day|hour|minute|second)s?\s*ago')

def _n_xxx_ago(x):
how_many, time_period = pretty_regex.search(x).groups()

how_many = 1 if how_many == 'a' else int(how_many)

# timedelta natively supports time periods up to 'weeks'.
# To apply month or year we convert to 30 and 365 days
if time_period == 'month':
how_many *= 30
time_period = 'day'
elif time_period == 'year':
how_many *= 365
time_period = 'day'

kwargs = {(time_period + 's'): how_many}
return now - timedelta(**kwargs)

pattern[pretty_regex] = _n_xxx_ago

# yesterday
callback = lambda x: now - timedelta(days=1)
pattern[re.compile('^yesterday$')] = callback

for regexp, parser in pattern.items():
if bool(regexp.match(date_str)):
return parser(date_str)

msg = 'date "{0}" does not match any valid format'.format(date_str)
raise ValueError(msg)


class RequiredAttributeError(ValueError):

def __init__(self, message):
Expand Down
17 changes: 17 additions & 0 deletions lib/spack/spack/cmd/find.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@
import sys

import llnl.util.tty as tty
import llnl.util.lang
import spack
import spack.database
import spack.cmd.common.arguments as arguments
from spack.cmd import display_specs

Expand Down Expand Up @@ -96,6 +98,14 @@ def setup_parser(subparser):
action='store_true',
help='show fully qualified package names')

subparser.add_argument(
'--start-date',
help='earliest date of installation [YYYY-MM-DD]'
)
subparser.add_argument(
'--end-date', help='latest date of installation [YYYY-MM-DD]'
)

arguments.add_common_arguments(subparser, ['constraint'])


Expand All @@ -114,6 +124,13 @@ def query_arguments(args):
if args.implicit:
explicit = False
q_args = {'installed': installed, 'known': known, "explicit": explicit}

# Time window of installation
for attribute in ('start_date', 'end_date'):
date = getattr(args, attribute)
if date:
q_args[attribute] = llnl.util.lang.pretty_string_to_date(date)

return q_args


Expand Down
Loading

0 comments on commit 5655895

Please sign in to comment.