|
@@ -58,7 +58,6 @@ try:
|
|
|
from ..helpers import ErrorIgnoringTextIOWrapper
|
|
|
from ..helpers import ProgressIndicatorPercent
|
|
|
from ..helpers import basic_json_data, json_print
|
|
|
- from ..helpers import prepare_subprocess_env
|
|
|
from ..helpers import umount
|
|
|
from ..helpers import flags_root, flags_dir, flags_special_follow, flags_special
|
|
|
from ..helpers import msgpack
|
|
@@ -107,10 +106,11 @@ def get_func(args):
|
|
|
from .benchmarks import BenchmarkMixIn
|
|
|
from .debug import DebugMixIn
|
|
|
from .keys import KeysMixIn
|
|
|
+from .locks import LocksMixIn
|
|
|
from .tar import TarMixIn
|
|
|
|
|
|
|
|
|
-class Archiver(DebugMixIn, TarMixIn, BenchmarkMixIn, KeysMixIn):
|
|
|
+class Archiver(DebugMixIn, TarMixIn, BenchmarkMixIn, KeysMixIn, LocksMixIn):
|
|
|
def __init__(self, lock_wait=None, prog=None):
|
|
|
self.exit_code = EXIT_SUCCESS
|
|
|
self.lock_wait = lock_wait
|
|
@@ -1376,36 +1376,6 @@ class Archiver(DebugMixIn, TarMixIn, BenchmarkMixIn, KeysMixIn):
|
|
|
cache.commit()
|
|
|
return self.exit_code
|
|
|
|
|
|
- @with_repository(manifest=False, exclusive=True)
|
|
|
- def do_with_lock(self, args, repository):
|
|
|
- """run a user specified command with the repository lock held"""
|
|
|
- # for a new server, this will immediately take an exclusive lock.
|
|
|
- # to support old servers, that do not have "exclusive" arg in open()
|
|
|
- # RPC API, we also do it the old way:
|
|
|
- # re-write manifest to start a repository transaction - this causes a
|
|
|
- # lock upgrade to exclusive for remote (and also for local) repositories.
|
|
|
- # by using manifest=False in the decorator, we avoid having to require
|
|
|
- # the encryption key (and can operate just with encrypted data).
|
|
|
- data = repository.get(Manifest.MANIFEST_ID)
|
|
|
- repository.put(Manifest.MANIFEST_ID, data)
|
|
|
- # usually, a 0 byte (open for writing) segment file would be visible in the filesystem here.
|
|
|
- # we write and close this file, to rather have a valid segment file on disk, before invoking the subprocess.
|
|
|
- # we can only do this for local repositories (with .io), though:
|
|
|
- if hasattr(repository, "io"):
|
|
|
- repository.io.close_segment()
|
|
|
- env = prepare_subprocess_env(system=True)
|
|
|
- try:
|
|
|
- # we exit with the return code we get from the subprocess
|
|
|
- return subprocess.call([args.command] + args.args, env=env)
|
|
|
- finally:
|
|
|
- # we need to commit the "no change" operation we did to the manifest
|
|
|
- # because it created a new segment file in the repository. if we would
|
|
|
- # roll back, the same file would be later used otherwise (for other content).
|
|
|
- # that would be bad if somebody uses rsync with ignore-existing (or
|
|
|
- # any other mechanism relying on existing segment data not changing).
|
|
|
- # see issue #1867.
|
|
|
- repository.commit(compact=False)
|
|
|
-
|
|
|
@with_repository(manifest=False, exclusive=True)
|
|
|
def do_compact(self, args, repository):
|
|
|
"""compact segment files in the repository"""
|
|
@@ -1547,13 +1517,6 @@ class Archiver(DebugMixIn, TarMixIn, BenchmarkMixIn, KeysMixIn):
|
|
|
if args.cache:
|
|
|
cache.close()
|
|
|
|
|
|
- @with_repository(lock=False, manifest=False)
|
|
|
- def do_break_lock(self, args, repository):
|
|
|
- """Break the repository lock (e.g. in case it was left by a dead borg."""
|
|
|
- repository.break_lock()
|
|
|
- Cache.break_lock(repository)
|
|
|
- return self.exit_code
|
|
|
-
|
|
|
helptext = collections.OrderedDict()
|
|
|
helptext["patterns"] = textwrap.dedent(
|
|
|
"""
|
|
@@ -2424,25 +2387,7 @@ class Archiver(DebugMixIn, TarMixIn, BenchmarkMixIn, KeysMixIn):
|
|
|
subparsers = parser.add_subparsers(title="required arguments", metavar="<command>")
|
|
|
|
|
|
self.build_parser_benchmarks(subparsers, common_parser, mid_common_parser)
|
|
|
-
|
|
|
- # borg break-lock
|
|
|
- break_lock_epilog = process_epilog(
|
|
|
- """
|
|
|
- This command breaks the repository and cache locks.
|
|
|
- Please use carefully and only while no borg process (on any machine) is
|
|
|
- trying to access the Cache or the Repository.
|
|
|
- """
|
|
|
- )
|
|
|
- subparser = subparsers.add_parser(
|
|
|
- "break-lock",
|
|
|
- parents=[common_parser],
|
|
|
- add_help=False,
|
|
|
- description=self.do_break_lock.__doc__,
|
|
|
- epilog=break_lock_epilog,
|
|
|
- formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
|
- help="break repository and cache locks",
|
|
|
- )
|
|
|
- subparser.set_defaults(func=self.do_break_lock)
|
|
|
+ self.build_parser_locks(subparsers, common_parser, mid_common_parser)
|
|
|
|
|
|
# borg check
|
|
|
check_epilog = process_epilog(
|
|
@@ -4107,37 +4052,6 @@ class Archiver(DebugMixIn, TarMixIn, BenchmarkMixIn, KeysMixIn):
|
|
|
"mountpoint", metavar="MOUNTPOINT", type=str, help="mountpoint of the filesystem to umount"
|
|
|
)
|
|
|
|
|
|
- # borg with-lock
|
|
|
- with_lock_epilog = process_epilog(
|
|
|
- """
|
|
|
- This command runs a user-specified command while the repository lock is held.
|
|
|
-
|
|
|
- It will first try to acquire the lock (make sure that no other operation is
|
|
|
- running in the repo), then execute the given command as a subprocess and wait
|
|
|
- for its termination, release the lock and return the user command's return
|
|
|
- code as borg's return code.
|
|
|
-
|
|
|
- .. note::
|
|
|
-
|
|
|
- If you copy a repository with the lock held, the lock will be present in
|
|
|
- the copy. Thus, before using borg on the copy from a different host,
|
|
|
- you need to use "borg break-lock" on the copied repository, because
|
|
|
- Borg is cautious and does not automatically remove stale locks made by a different host.
|
|
|
- """
|
|
|
- )
|
|
|
- subparser = subparsers.add_parser(
|
|
|
- "with-lock",
|
|
|
- parents=[common_parser],
|
|
|
- add_help=False,
|
|
|
- description=self.do_with_lock.__doc__,
|
|
|
- epilog=with_lock_epilog,
|
|
|
- formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
|
- help="run user command with lock held",
|
|
|
- )
|
|
|
- subparser.set_defaults(func=self.do_with_lock)
|
|
|
- subparser.add_argument("command", metavar="COMMAND", help="command to run")
|
|
|
- subparser.add_argument("args", metavar="ARGS", nargs=argparse.REMAINDER, help="command arguments")
|
|
|
-
|
|
|
self.build_parser_tar(subparsers, common_parser, mid_common_parser)
|
|
|
|
|
|
return parser
|