mirror of https://github.com/borgbackup/borg.git
Merge branch '1.0-maint' into master
# Conflicts: # src/borg/archive.py # src/borg/archiver.py # src/borg/helpers.py
This commit is contained in:
commit
a9db2a2e55
|
@ -75,6 +75,7 @@ Main features
|
|||
* FreeBSD
|
||||
* OpenBSD and NetBSD (no xattrs/ACLs support or binaries yet)
|
||||
* Cygwin (not supported, no binaries yet)
|
||||
* Linux Subsystem of Windows 10 (not supported)
|
||||
|
||||
**Free and Open Source Software**
|
||||
* security and functionality can be audited independently
|
||||
|
|
|
@ -3,7 +3,7 @@ import os
|
|||
import pytest
|
||||
|
||||
# needed to get pretty assertion failures in unit tests:
|
||||
pytest.register_assert_rewrite('borg')
|
||||
pytest.register_assert_rewrite('borg.testsuite')
|
||||
|
||||
from borg.logger import setup_logging
|
||||
|
||||
|
|
|
@ -82,6 +82,9 @@ Bug fixes:
|
|||
- skip corrupted chunks during manifest rebuild
|
||||
- fix TypeError in integrity error handler, #1903, #1894
|
||||
- fix location parser for archives with @ char (regression introduced in 1.0.8), #1930
|
||||
- fix wrong duration/timestamps if system clock jumped during a create
|
||||
- fix progress display not updating if system clock jumps backwards
|
||||
- fix checkpoint interval being incorrect if system clock jumps
|
||||
|
||||
Other changes:
|
||||
|
||||
|
|
|
@ -290,12 +290,21 @@ and commands to make fuse work for using the mount command.
|
|||
sysctl vfs.usermount=1
|
||||
|
||||
|
||||
Windows 10's Linux Subsystem
|
||||
++++++++++++++++++++++++++++
|
||||
|
||||
.. note::
|
||||
Running under Windows 10's Linux Subsystem is experimental and has not been tested much yet.
|
||||
|
||||
Just follow the Ubuntu Linux installation steps. You can omit the FUSE stuff, it won't work anyway.
|
||||
|
||||
|
||||
Cygwin
|
||||
++++++
|
||||
|
||||
.. note::
|
||||
Running under Cygwin is experimental and has only been tested with Cygwin
|
||||
(x86-64) v2.5.2.
|
||||
(x86-64) v2.5.2. Remote repositories are known broken, local repositories should work.
|
||||
|
||||
Use the Cygwin installer to install the dependencies::
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ import stat
|
|||
import sys
|
||||
import time
|
||||
from contextlib import contextmanager
|
||||
from datetime import datetime, timezone
|
||||
from datetime import datetime, timezone, timedelta
|
||||
from functools import partial
|
||||
from getpass import getuser
|
||||
from io import BytesIO
|
||||
|
@ -81,7 +81,7 @@ class Statistics:
|
|||
return format_file_size(self.csize)
|
||||
|
||||
def show_progress(self, item=None, final=False, stream=None, dt=None):
|
||||
now = time.time()
|
||||
now = time.monotonic()
|
||||
if dt is None or now - self.last_progress > dt:
|
||||
self.last_progress = now
|
||||
columns, lines = get_terminal_size()
|
||||
|
@ -255,7 +255,7 @@ class Archive:
|
|||
|
||||
def __init__(self, repository, key, manifest, name, cache=None, create=False,
|
||||
checkpoint_interval=300, numeric_owner=False, noatime=False, noctime=False, progress=False,
|
||||
chunker_params=CHUNKER_PARAMS, start=None, end=None, compression=None, compression_files=None,
|
||||
chunker_params=CHUNKER_PARAMS, start=None, start_monotonic=None, end=None, compression=None, compression_files=None,
|
||||
consider_part_files=False):
|
||||
self.cwd = os.getcwd()
|
||||
self.key = key
|
||||
|
@ -270,10 +270,13 @@ class Archive:
|
|||
self.numeric_owner = numeric_owner
|
||||
self.noatime = noatime
|
||||
self.noctime = noctime
|
||||
assert (start is None) == (start_monotonic is None), 'Logic error: if start is given, start_monotonic must be given as well and vice versa.'
|
||||
if start is None:
|
||||
start = datetime.utcnow()
|
||||
start_monotonic = time.monotonic()
|
||||
self.chunker_params = chunker_params
|
||||
self.start = start
|
||||
self.start_monotonic = start_monotonic
|
||||
if end is None:
|
||||
end = datetime.utcnow()
|
||||
self.end = end
|
||||
|
@ -288,7 +291,7 @@ class Archive:
|
|||
key.compression_decider2 = CompressionDecider2(compression or CompressionSpec('none'))
|
||||
if name in manifest.archives:
|
||||
raise self.AlreadyExists(name)
|
||||
self.last_checkpoint = time.time()
|
||||
self.last_checkpoint = time.monotonic()
|
||||
i = 0
|
||||
while True:
|
||||
self.checkpoint_name = '%s.checkpoint%s' % (name, i and ('.%d' % i) or '')
|
||||
|
@ -381,14 +384,17 @@ Number of files: {0.stats.nfiles}'''.format(
|
|||
if name in self.manifest.archives:
|
||||
raise self.AlreadyExists(name)
|
||||
self.items_buffer.flush(flush=True)
|
||||
duration = timedelta(seconds=time.monotonic() - self.start_monotonic)
|
||||
if timestamp is None:
|
||||
self.end = datetime.utcnow()
|
||||
self.start = self.end - duration
|
||||
start = self.start
|
||||
end = self.end
|
||||
else:
|
||||
self.end = timestamp
|
||||
start = timestamp
|
||||
end = timestamp # we only have 1 value
|
||||
self.start = timestamp - duration
|
||||
end = timestamp
|
||||
start = self.start
|
||||
metadata = {
|
||||
'version': 1,
|
||||
'name': name,
|
||||
|
|
|
@ -12,11 +12,11 @@ import stat
|
|||
import subprocess
|
||||
import sys
|
||||
import textwrap
|
||||
import time
|
||||
import traceback
|
||||
from binascii import unhexlify
|
||||
from datetime import datetime
|
||||
from itertools import zip_longest
|
||||
from operator import attrgetter
|
||||
|
||||
from .logger import create_logger, setup_logging
|
||||
logger = create_logger()
|
||||
|
@ -327,7 +327,6 @@ class Archiver:
|
|||
if args.progress:
|
||||
archive.stats.show_progress(final=True)
|
||||
if args.stats:
|
||||
archive.end = datetime.utcnow()
|
||||
log_multi(DASHES,
|
||||
str(archive),
|
||||
DASHES,
|
||||
|
@ -341,6 +340,7 @@ class Archiver:
|
|||
self.ignore_inode = args.ignore_inode
|
||||
dry_run = args.dry_run
|
||||
t0 = datetime.utcnow()
|
||||
t0_monotonic = time.monotonic()
|
||||
if not dry_run:
|
||||
with Cache(repository, key, manifest, do_files=args.cache_files, progress=args.progress,
|
||||
lock_wait=self.lock_wait) as cache:
|
||||
|
@ -348,7 +348,7 @@ class Archiver:
|
|||
create=True, checkpoint_interval=args.checkpoint_interval,
|
||||
numeric_owner=args.numeric_owner, noatime=args.noatime, noctime=args.noctime,
|
||||
progress=args.progress,
|
||||
chunker_params=args.chunker_params, start=t0,
|
||||
chunker_params=args.chunker_params, start=t0, start_monotonic=t0_monotonic,
|
||||
compression=args.compression, compression_files=args.compression_files)
|
||||
create_inner(archive, cache)
|
||||
else:
|
||||
|
|
|
@ -328,7 +328,8 @@ class ArchiverTestCaseBase(BaseTestCase):
|
|||
except PermissionError:
|
||||
have_root = False
|
||||
except OSError as e:
|
||||
if e.errno != errno.EINVAL:
|
||||
# Note: ENOSYS "Function not implemented" happens as non-root on Win 10 Linux Subsystem.
|
||||
if e.errno not in (errno.EINVAL, errno.ENOSYS):
|
||||
raise
|
||||
have_root = False
|
||||
return have_root
|
||||
|
|
Loading…
Reference in New Issue