Record installation date and time in DB (#7334)

* 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.
This commit is contained in:
Massimiliano Culpo
2018-03-22 19:07:27 +01:00
committed by Todd Gamblin
parent 6699ba8769
commit 5655895865
6 changed files with 255 additions and 44 deletions

View File

@@ -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
@@ -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):