diff --git a/docs/development.rst b/docs/development.rst index 50e4f0592..afefed0f8 100644 --- a/docs/development.rst +++ b/docs/development.rst @@ -21,9 +21,16 @@ Some guidance for contributors: - choose the branch you base your changesets on wisely: - - choose x.y-maint for stuff that should go into next x.y release - (it usually gets merged into master branch later also) - - choose master if that does not apply + - choose x.y-maint for stuff that should go into next x.y.z release + (it usually gets merged into master branch later also), like: + + - bug fixes (code or docs) + - missing *important* (and preferably small) features + - docs rearrangements (so stuff stays in-sync to avoid merge + troubles in future) + - choose master if that does not apply, like for: + + - developing new features - do clean changesets: diff --git a/docs/usage.rst b/docs/usage.rst index bfeb6ef0f..eab98cbec 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -575,6 +575,8 @@ Examples .. include:: usage/mount.rst.inc +.. include:: usage/umount.rst.inc + Examples ~~~~~~~~ borg mount @@ -584,7 +586,7 @@ borg mount $ borg mount /path/to/repo::root-2016-02-15 /tmp/mymountpoint $ ls /tmp/mymountpoint bin boot etc home lib lib64 lost+found media mnt opt root sbin srv tmp usr var - $ fusermount -u /tmp/mymountpoint + $ borg umount /tmp/mymountpoint :: diff --git a/docs/usage/umount.rst.inc b/docs/usage/umount.rst.inc new file mode 100644 index 000000000..febacda06 --- /dev/null +++ b/docs/usage/umount.rst.inc @@ -0,0 +1,40 @@ +.. IMPORTANT: this file is auto-generated from borg's built-in help, do not edit! + +.. _borg_umount: + +borg umount +----------- +:: + + usage: borg umount [-h] [--critical] [--error] [--warning] [--info] [--debug] + [--lock-wait N] [--show-rc] [--no-files-cache] [--umask M] + [--remote-path PATH] + MOUNTPOINT + + un-mount the FUSE filesystem + + positional arguments: + MOUNTPOINT mountpoint of the filesystem to umount + + optional arguments: + -h, --help show this help message and exit + --critical work on log level CRITICAL + --error work on log level ERROR + --warning work on log level WARNING (default) + --info, -v, --verbose + work on log level INFO + --debug work on log level DEBUG + --lock-wait N wait for the lock, but max. N seconds (default: 1). + --show-rc show/log the return code (rc) + --no-files-cache do not load/update the file metadata cache used to + detect unchanged files + --umask M set umask to M (local and remote, default: 0077) + --remote-path PATH set remote path to executable (default: "borg") + +Description +~~~~~~~~~~~ + +This command un-mounts a FUSE filesystem that was mounted with ``borg mount``. + +This is a convenience wrapper that just calls the platform-specific shell +command - usually this is either umount or fusermount -u. diff --git a/src/borg/archiver.py b/src/borg/archiver.py index 59f4e17bb..df9e9b03e 100644 --- a/src/borg/archiver.py +++ b/src/borg/archiver.py @@ -47,7 +47,7 @@ from .helpers import ProgressIndicatorPercent from .item import Item from .key import key_creator, RepoKey, PassphraseKey from .keymanager import KeyManager -from .platform import get_flags +from .platform import get_flags, umount from .remote import RepositoryServer, RemoteRepository, cache_if_remote from .repository import Repository from .selftest import selftest @@ -865,6 +865,10 @@ class Archiver: self.exit_code = EXIT_ERROR return self.exit_code + def do_umount(self, args): + """un-mount the FUSE filesystem""" + return umount(args.mountpoint) + @with_repository() def do_list(self, args, repository, manifest, key): """List archive or repository contents""" @@ -2154,6 +2158,21 @@ class Archiver: help='Extra mount options') self.add_archives_filters_args(subparser) + umount_epilog = textwrap.dedent(""" + This command un-mounts a FUSE filesystem that was mounted with ``borg mount``. + + This is a convenience wrapper that just calls the platform-specific shell + command - usually this is either umount or fusermount -u. + """) + subparser = subparsers.add_parser('umount', parents=[common_parser], add_help=False, + description=self.do_umount.__doc__, + epilog=umount_epilog, + formatter_class=argparse.RawDescriptionHelpFormatter, + help='umount repository') + subparser.set_defaults(func=self.do_umount) + subparser.add_argument('mountpoint', metavar='MOUNTPOINT', type=str, + help='mountpoint of the filesystem to umount') + info_epilog = textwrap.dedent(""" This command displays detailed information about the specified archive or repository. diff --git a/src/borg/helpers.py b/src/borg/helpers.py index 0898a4542..7400d8241 100644 --- a/src/borg/helpers.py +++ b/src/borg/helpers.py @@ -95,7 +95,7 @@ def check_extension_modules(): raise ExtensionModuleError if crypto.API_VERSION != 3: raise ExtensionModuleError - if platform.API_VERSION != platform.OS_API_VERSION != 4: + if platform.API_VERSION != platform.OS_API_VERSION != 5: raise ExtensionModuleError diff --git a/src/borg/platform/__init__.py b/src/borg/platform/__init__.py index 1be09fe79..cae738dea 100644 --- a/src/borg/platform/__init__.py +++ b/src/borg/platform/__init__.py @@ -9,7 +9,7 @@ Public APIs are documented in platform.base. from .base import acl_get, acl_set from .base import set_flags, get_flags from .base import SaveFile, SyncFile, sync_dir, fdatasync -from .base import swidth, API_VERSION +from .base import swidth, umount, API_VERSION from .posix import process_alive, get_process_id, local_pid_alive @@ -19,12 +19,12 @@ if sys.platform.startswith('linux'): # pragma: linux only from .linux import acl_get, acl_set from .linux import set_flags, get_flags from .linux import SyncFile - from .linux import swidth + from .linux import swidth, umount elif sys.platform.startswith('freebsd'): # pragma: freebsd only from .freebsd import API_VERSION as OS_API_VERSION from .freebsd import acl_get, acl_set - from .freebsd import swidth + from .freebsd import swidth, umount elif sys.platform == 'darwin': # pragma: darwin only from .darwin import API_VERSION as OS_API_VERSION from .darwin import acl_get, acl_set - from .darwin import swidth + from .darwin import swidth, umount diff --git a/src/borg/platform/base.py b/src/borg/platform/base.py index d024ce76b..cccd43ba3 100644 --- a/src/borg/platform/base.py +++ b/src/borg/platform/base.py @@ -13,7 +13,7 @@ platform API: that way platform APIs provided by the platform-specific support m are correctly composed into the base functionality. """ -API_VERSION = 4 +API_VERSION = 5 fdatasync = getattr(os, 'fdatasync', os.fsync) @@ -157,3 +157,8 @@ def swidth(s): For western scripts, this is just len(s), but for cjk glyphs, 2 cells are used. """ return len(s) + + +def umount(mountpoint): + """un-mount the FUSE filesystem mounted at """ + return 0 # dummy, see also posix module diff --git a/src/borg/platform/darwin.pyx b/src/borg/platform/darwin.pyx index 7f95f9e31..52b05a690 100644 --- a/src/borg/platform/darwin.pyx +++ b/src/borg/platform/darwin.pyx @@ -2,9 +2,9 @@ import os from ..helpers import user2uid, group2gid from ..helpers import safe_decode, safe_encode -from .posix import swidth +from .posix import swidth, umount -API_VERSION = 4 +API_VERSION = 5 cdef extern from "sys/acl.h": ctypedef struct _acl_t: diff --git a/src/borg/platform/freebsd.pyx b/src/borg/platform/freebsd.pyx index 1aed05d04..e63563db7 100644 --- a/src/borg/platform/freebsd.pyx +++ b/src/borg/platform/freebsd.pyx @@ -2,9 +2,9 @@ import os from ..helpers import posix_acl_use_stored_uid_gid from ..helpers import safe_encode, safe_decode -from .posix import swidth +from .posix import swidth, umount -API_VERSION = 4 +API_VERSION = 5 cdef extern from "errno.h": int errno diff --git a/src/borg/platform/linux.pyx b/src/borg/platform/linux.pyx index 7b043cf1b..f96b6f892 100644 --- a/src/borg/platform/linux.pyx +++ b/src/borg/platform/linux.pyx @@ -2,6 +2,7 @@ import os import re import resource import stat +import subprocess from ..helpers import posix_acl_use_stored_uid_gid from ..helpers import user2uid, group2gid @@ -12,7 +13,7 @@ from .posix import swidth from libc cimport errno from libc.stdint cimport int64_t -API_VERSION = 4 +API_VERSION = 5 cdef extern from "sys/types.h": int ACL_TYPE_ACCESS @@ -251,3 +252,7 @@ class SyncFile(BaseSyncFile): self.fd.flush() os.fdatasync(self.fileno) os.posix_fadvise(self.fileno, 0, 0, os.POSIX_FADV_DONTNEED) + + +def umount(mountpoint): + return subprocess.call(['fusermount', '-u', mountpoint]) diff --git a/src/borg/platform/posix.pyx b/src/borg/platform/posix.pyx index 30b7e126f..db71a17fe 100644 --- a/src/borg/platform/posix.pyx +++ b/src/borg/platform/posix.pyx @@ -1,7 +1,8 @@ - import errno import os import socket +import subprocess + cdef extern from "wchar.h": cdef int wcswidth(const Py_UNICODE *str, size_t n) @@ -69,3 +70,10 @@ def local_pid_alive(pid): return False # Any other error (eg. permissions) means that the process ID refers to a live process. return True + + +# most POSIX platforms (but not Linux) +def umount(mountpoint): + return subprocess.call(['umount', mountpoint]) + + diff --git a/src/borg/testsuite/__init__.py b/src/borg/testsuite/__init__.py index 0abe8efd2..fea632cb2 100644 --- a/src/borg/testsuite/__init__.py +++ b/src/borg/testsuite/__init__.py @@ -12,7 +12,7 @@ import uuid import unittest from ..xattr import get_all -from ..platform import get_flags +from ..platform import get_flags, umount from .. import platform # Note: this is used by borg.selftest, do not use or import py.test functionality here. @@ -200,11 +200,7 @@ class BaseTestCase(unittest.TestCase): self.cmd(*args, fork=True) self.wait_for_mount(mountpoint) yield - if sys.platform.startswith('linux'): - cmd = 'fusermount -u %s' % mountpoint - else: - cmd = 'umount %s' % mountpoint - os.system(cmd) + umount(mountpoint) os.rmdir(mountpoint) # Give the daemon some time to exit time.sleep(.2)