mirror of https://github.com/borgbackup/borg.git
borg with-lock REPO CMD ARGS
This commit is contained in:
parent
12fb137667
commit
962c2e9d54
|
@ -12,6 +12,7 @@ import os
|
|||
import shlex
|
||||
import signal
|
||||
import stat
|
||||
import subprocess
|
||||
import sys
|
||||
import textwrap
|
||||
import traceback
|
||||
|
@ -895,6 +896,21 @@ class Archiver:
|
|||
cache.commit()
|
||||
return self.exit_code
|
||||
|
||||
@with_repository(manifest=False)
|
||||
def do_with_lock(self, args, repository):
|
||||
"""run a user specified command with the repository lock held"""
|
||||
# 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)
|
||||
try:
|
||||
# we exit with the return code we get from the subprocess
|
||||
return subprocess.call([args.command] + args.args)
|
||||
finally:
|
||||
repository.rollback()
|
||||
|
||||
@with_repository()
|
||||
def do_debug_dump_archive_items(self, args, repository, manifest, key):
|
||||
"""dump (decrypted, decompressed) archive items metadata (not: data)"""
|
||||
|
@ -1831,6 +1847,32 @@ class Archiver:
|
|||
subparser.add_argument('paths', metavar='PATH', nargs='*', type=str,
|
||||
help='paths to recreate; patterns are supported')
|
||||
|
||||
with_lock_epilog = textwrap.dedent("""
|
||||
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, obviously. Thus, before using borg on the copy, you need to
|
||||
use "borg break-lock" on it.
|
||||
""")
|
||||
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('location', metavar='REPOSITORY',
|
||||
type=location_validator(archive=False),
|
||||
help='repository to lock')
|
||||
subparser.add_argument('command', metavar='COMMAND',
|
||||
help='command to run')
|
||||
subparser.add_argument('args', metavar='ARGS', nargs=argparse.REMAINDER,
|
||||
help='command arguments')
|
||||
|
||||
subparser = subparsers.add_parser('help', parents=[common_parser], add_help=False,
|
||||
description='Extra help')
|
||||
subparser.add_argument('--epilog-only', dest='epilog_only',
|
||||
|
|
|
@ -1399,6 +1399,12 @@ class ArchiverTestCase(ArchiverTestCaseBase):
|
|||
info_after = self.cmd('info', self.repository_location + '::test')
|
||||
assert info_before == info_after # includes archive ID
|
||||
|
||||
def test_with_lock(self):
|
||||
self.cmd('init', self.repository_location)
|
||||
lock_path = os.path.join(self.repository_path, 'lock.exclusive')
|
||||
cmd = 'python3', '-c', 'import os, sys; sys.exit(42 if os.path.exists("%s") else 23)' % lock_path
|
||||
self.cmd('with-lock', self.repository_location, *cmd, fork=True, exit_code=42)
|
||||
|
||||
|
||||
@unittest.skipUnless('binary' in BORG_EXES, 'no borg.exe available')
|
||||
class ArchiverTestCaseBinary(ArchiverTestCase):
|
||||
|
|
|
@ -647,6 +647,9 @@ Examples
|
|||
...
|
||||
|
||||
|
||||
.. include:: usage/with-lock.rst.inc
|
||||
|
||||
|
||||
.. include:: usage/break-lock.rst.inc
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
.. _borg_with-lock:
|
||||
|
||||
borg with-lock
|
||||
--------------
|
||||
::
|
||||
|
||||
borg with-lock <options> REPOSITORY COMMAND ARGS
|
||||
|
||||
positional arguments
|
||||
REPOSITORY
|
||||
repository to lock
|
||||
COMMAND
|
||||
command to run
|
||||
ARGS
|
||||
command arguments
|
||||
|
||||
`Common options`_
|
||||
|
|
||||
|
||||
Description
|
||||
~~~~~~~~~~~
|
||||
|
||||
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, obviously. Thus, before using borg on the copy, you need to
|
||||
use "borg break-lock" on it.
|
Loading…
Reference in New Issue