implement --timestamp, iso8601-like utc timestamp string or reference file/dir

note: this needs bug #282 to be fixed first, because it will create timestamps with microseconds==0.
This commit is contained in:
Thomas Waldmann 2015-04-18 21:36:10 +02:00
parent e815d6da8e
commit 0ffee1f1ee
3 changed files with 31 additions and 4 deletions

View File

@ -184,11 +184,13 @@ class Archive:
del self.manifest.archives[self.checkpoint_name]
self.cache.chunk_decref(self.id, self.stats)
def save(self, name=None):
def save(self, name=None, timestamp=None):
name = name or self.name
if name in self.manifest.archives:
raise self.AlreadyExists(name)
self.items_buffer.flush(flush=True)
if timestamp is None:
timestamp = datetime.utcnow()
metadata = StableDict({
'version': 1,
'name': name,
@ -196,7 +198,7 @@ class Archive:
'cmdline': sys.argv,
'hostname': socket.gethostname(),
'username': getuser(),
'time': datetime.utcnow().isoformat(),
'time': timestamp.isoformat(),
})
data = msgpack.packb(metadata, unicode_errors='surrogateescape')
self.id = self.key.id_hash(data)

View File

@ -15,7 +15,7 @@ from attic.repository import Repository
from attic.cache import Cache
from attic.key import key_creator
from attic.helpers import Error, location_validator, format_time, \
format_file_mode, ExcludePattern, exclude_path, adjust_patterns, to_localtime, \
format_file_mode, ExcludePattern, exclude_path, adjust_patterns, to_localtime, timestamp, \
get_cache_dir, get_keys_dir, format_timedelta, prune_within, prune_split, \
Manifest, remove_surrogates, update_excludes, format_archive, check_extension_modules, Statistics, \
is_cachedir, bigint_to_int
@ -127,7 +127,7 @@ Type "Yes I am sure" if you understand this and want to continue.\n""")
else:
restrict_dev = None
self._process(archive, cache, args.excludes, args.exclude_caches, skip_inodes, path, restrict_dev)
archive.save()
archive.save(timestamp=args.timestamp)
if args.stats:
t = datetime.now()
diff = t - t0
@ -551,6 +551,11 @@ Type "Yes I am sure" if you understand this and want to continue.\n""")
subparser.add_argument('--numeric-owner', dest='numeric_owner',
action='store_true', default=False,
help='only store numeric user and group identifiers')
subparser.add_argument('--timestamp', dest='timestamp',
type=timestamp, default=None,
metavar='yyyy-mm-ddThh:mm:ss',
help='manually specify the archive creation date/time (UTC). '
'alternatively, give a reference file/directory.')
subparser.add_argument('archive', metavar='ARCHIVE',
type=location_validator(archive=True),
help='archive to create')

View File

@ -257,6 +257,26 @@ class ExcludePattern(IncludePattern):
return '%s(%s)' % (type(self), self.pattern)
def timestamp(s):
"""Convert a --timestamp=s argument to a datetime object"""
try:
# is it pointing to a file / directory?
ts = os.stat(s).st_mtime
return datetime.utcfromtimestamp(ts)
except OSError:
# didn't work, try parsing as timestamp. UTC, no TZ, no microsecs support.
for format in ('%Y-%m-%dT%H:%M:%SZ', '%Y-%m-%dT%H:%M:%S+00:00',
'%Y-%m-%dT%H:%M:%S', '%Y-%m-%d %H:%M:%S',
'%Y-%m-%dT%H:%M', '%Y-%m-%d %H:%M',
'%Y-%m-%d', '%Y-%j',
):
try:
return datetime.strptime(s, format)
except ValueError:
continue
raise ValueError
def is_cachedir(path):
"""Determines whether the specified path is a cache directory (and
therefore should potentially be excluded from the backup) according to