mirror of
https://github.com/borgbackup/borg.git
synced 2026-04-24 23:57:23 -04:00
Merge pull request #5488 from milkey-mouse/bp-5472
Use --timestamp in placeholders if given (1.1 backport)
This commit is contained in:
commit
d658fd7cd1
3 changed files with 24 additions and 7 deletions
|
|
@ -4457,6 +4457,8 @@ class Archiver:
|
|||
self.do_list, self.do_mount, self.do_umount}
|
||||
if func not in bypass_allowed:
|
||||
raise Error('Not allowed to bypass locking mechanism for chosen command')
|
||||
if getattr(args, 'timestamp', None):
|
||||
args.location = args.location.with_timestamp(args.timestamp)
|
||||
return args
|
||||
|
||||
def prerun_checks(self, logger, is_serve):
|
||||
|
|
|
|||
|
|
@ -606,7 +606,7 @@ def timestamp(s):
|
|||
try:
|
||||
# is it pointing to a file / directory?
|
||||
ts = safe_s(os.stat(s).st_mtime)
|
||||
return datetime.utcfromtimestamp(ts)
|
||||
return datetime.fromtimestamp(ts, tz=timezone.utc)
|
||||
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',
|
||||
|
|
@ -615,7 +615,7 @@ def timestamp(s):
|
|||
'%Y-%m-%d', '%Y-%j',
|
||||
):
|
||||
try:
|
||||
return datetime.strptime(s, format)
|
||||
return datetime.strptime(s, format).replace(tzinfo=timezone.utc)
|
||||
except ValueError:
|
||||
continue
|
||||
raise ValueError
|
||||
|
|
@ -718,7 +718,7 @@ def format_line(format, data):
|
|||
raise PlaceholderError(format, data, e.__class__.__name__, str(e))
|
||||
|
||||
|
||||
def replace_placeholders(text):
|
||||
def replace_placeholders(text, overrides={}):
|
||||
"""Replace placeholders in text with their values."""
|
||||
from .platform import fqdn, hostname
|
||||
current_time = datetime.now(timezone.utc)
|
||||
|
|
@ -735,6 +735,7 @@ def replace_placeholders(text):
|
|||
'borgmajor': '%d' % borg_version_tuple[:1],
|
||||
'borgminor': '%d.%d' % borg_version_tuple[:2],
|
||||
'borgpatch': '%d.%d.%d' % borg_version_tuple[:3],
|
||||
**overrides,
|
||||
}
|
||||
return format_line(text, data)
|
||||
|
||||
|
|
@ -1103,13 +1104,13 @@ class Location:
|
|||
| # or
|
||||
""" + optional_archive_re, re.VERBOSE) # archive name (optional, may be empty)
|
||||
|
||||
def __init__(self, text=''):
|
||||
if not self.parse(text):
|
||||
def __init__(self, text='', overrides={}):
|
||||
if not self.parse(text, overrides):
|
||||
raise ValueError('Invalid location format: "%s"' % self.orig)
|
||||
|
||||
def parse(self, text):
|
||||
def parse(self, text, overrides={}):
|
||||
self.orig = text
|
||||
text = replace_placeholders(text)
|
||||
text = replace_placeholders(text, overrides)
|
||||
valid = self._parse(text)
|
||||
if valid:
|
||||
return True
|
||||
|
|
@ -1202,6 +1203,12 @@ class Location:
|
|||
':{}'.format(self.port) if self.port else '',
|
||||
path)
|
||||
|
||||
def with_timestamp(self, timestamp):
|
||||
return Location(self.orig, overrides={
|
||||
'now': DatetimeWrapper(timestamp.astimezone(None)),
|
||||
'utcnow': DatetimeWrapper(timestamp),
|
||||
})
|
||||
|
||||
|
||||
def location_validator(archive=None, proto=None):
|
||||
def validator(text):
|
||||
|
|
|
|||
|
|
@ -189,6 +189,10 @@ class TestLocationWithoutEnv:
|
|||
assert repr(Location('ssh://host/path::2016-12-31@23:59:59')) == \
|
||||
"Location(proto='ssh', user=None, host='host', port=None, path='/path', archive='2016-12-31@23:59:59')"
|
||||
|
||||
def test_with_timestamp(self):
|
||||
assert repr(Location('path::archive-{utcnow}').with_timestamp(datetime(2002, 9, 19, tzinfo=timezone.utc))) == \
|
||||
"Location(proto='file', user=None, host=None, port=None, path='path', archive='archive-2002-09-19T00:00:00')"
|
||||
|
||||
def test_underspecified(self, monkeypatch):
|
||||
monkeypatch.delenv('BORG_REPO', raising=False)
|
||||
with pytest.raises(ValueError):
|
||||
|
|
@ -894,6 +898,10 @@ def test_replace_placeholders():
|
|||
assert int(replace_placeholders('{now:%Y}')) == now.year
|
||||
|
||||
|
||||
def test_override_placeholders():
|
||||
assert replace_placeholders('{uuid4}', overrides={'uuid4': "overridden"}) == "overridden"
|
||||
|
||||
|
||||
def working_swidth():
|
||||
return platform.swidth('선') == 2
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue