Skip to content

Commit

Permalink
In mount command switch from using --latest to using --all.
Browse files Browse the repository at this point in the history
Add --include-external option to check, list, mount, and prune commands.
Change default prefix to '{host_name}-{user_name}-{config_name}-'.
umount command now deletes directory used as mount point.
  • Loading branch information
Ken Kundert authored and Ken Kundert committed Sep 27, 2019
1 parent 436c05c commit 90d0052
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 22 deletions.
4 changes: 2 additions & 2 deletions doc/installing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,8 @@ reduce this risk.
If you do not specify either *archive* or *prefix*, then you get the following
defaults::

archive = '{config_name}-{{now}}'
prefix = '{config_name}-'
prefix = '{host_name}-{user_name}-{config_name}-'
archive = '{prefix}-{{now}}'

If you specify only *prefix*, then *archive* becomes::

Expand Down
5 changes: 4 additions & 1 deletion doc/releases.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ Releases
- Added support for multiple backup configurations in a single repository.
- Added *prefix*, *exclude_from*, and *verbose* settings.
- Provide default value for *archive* setting.
- Add --latest command line option to *mount* command.
- Add --all command line option to *mount* command.
- Add --include-external command line option to *check*, *list*, *mount*,
and *prune* commands.
- *umount* command now deletes directory used as mount point.
- Moved log files to ~/.local/share/emborg (run 'mv
~/.config/emborg/*.{log,lastbackup}* ~/.local/share/emborg' before using
this version).
Expand Down
65 changes: 50 additions & 15 deletions emborg/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
hostname = gethostname()
from inform import (
Color, Error,
codicil, conjoin, full_stop, is_str, narrate, os_error, output,
codicil, conjoin, display, full_stop, is_str, narrate, os_error, output,
render, warn,
)
from docopt import docopt
Expand Down Expand Up @@ -314,7 +314,9 @@ class CheckCommand(Command):
emborg check [options]
Options:
-v, --verify-data perform a full integrity verification (slow)
-e, --include-external check all archives in repository, not just
those associated with this configuration
-v, --verify-data perform a full integrity verification (slow)
""").strip()
REQUIRES_EXCLUSIVITY = True
COMPOSITE_CONFIGS = True
Expand All @@ -324,12 +326,14 @@ def run(cls, command, args, settings, options):
# read command line
cmdline = docopt(cls.USAGE, argv=[command] + args)
verify = ['--verify-data'] if cmdline['--verify-data'] else []
include_external_archives = cmdline['--include-external']

# run borg
borg = settings.run_borg(
cmd = 'check',
args = verify + [settings.destination()],
emborg_opts = options,
strip_prefix = include_external_archives,
)
out = borg.stdout
if out:
Expand Down Expand Up @@ -367,6 +371,12 @@ class DeleteCommand(Command):
Usage:
emborg delete <archive>
""").strip()
# borg allows you to delete all archives by simply not specifying an
# archive, but then it interactively asks the user to type YES if that
# deletes all archives from repository. Emborg currently does not have
# the ability support this and there appears to be no way of stopping
# borg from asking for confirmation, so just limit user to deleting one
# archive at a time.
REQUIRES_EXCLUSIVITY = True
COMPOSITE_CONFIGS = False

Expand All @@ -381,6 +391,7 @@ def run(cls, command, args, settings, options):
cmd = 'delete',
args = [settings.destination(archive)],
emborg_opts = options,
strip_prefix = True,
)
out = borg.stdout
if out:
Expand Down Expand Up @@ -625,7 +636,7 @@ class InfoCommand(Command):
emborg [options] info
Options:
-f, --fast only report local information
-f, --fast only report local information
""").strip()
REQUIRES_EXCLUSIVITY = True
COMPOSITE_CONFIGS = True
Expand All @@ -635,6 +646,8 @@ def run(cls, command, args, settings, options):
# read command line
cmdline = docopt(cls.USAGE, argv=[command] + args)
fast = cmdline['--fast']

# report local information
src_dirs = (str(d) for d in settings.src_dirs)
output(f' config: {settings.config_name}')
output(f' source: {", ".join(src_dirs)}')
Expand All @@ -651,11 +664,12 @@ def run(cls, command, args, settings, options):
if fast:
return

# now output the info from our borg repository
# now output the information from borg about the repository
borg = settings.run_borg(
cmd = 'info',
args = [settings.destination()],
emborg_opts = options,
strip_prefix = True,
)
out = borg.stdout
if out:
Expand Down Expand Up @@ -696,23 +710,29 @@ class ListCommand(Command):
DESCRIPTION = 'list the archives currently contained in the repository'
USAGE = dedent("""
Usage:
emborg list
emborg archives
emborg lr
emborg [options] list
emborg [options] archives
emborg [options] lr
Options:
-e, --include-external list all archives in repository, not just
those associated with this configuration
""").strip()
REQUIRES_EXCLUSIVITY = True
COMPOSITE_CONFIGS = False

@classmethod
def run(cls, command, args, settings, options):
# read command line
docopt(cls.USAGE, argv=[command] + args)
cmdline = docopt(cls.USAGE, argv=[command] + args)
include_external_archives = cmdline['--include-external']

# run borg
borg = settings.run_borg(
cmd = 'list',
args = ['--short', settings.destination()],
emborg_opts = options,
strip_prefix = include_external_archives,
)
out = borg.stdout
if out:
Expand Down Expand Up @@ -813,9 +833,12 @@ class MountCommand(Command):
emborg [options] mount <mount_point>
Options:
-a <archive>, --archive <archive> name of the archive to use
-d <date>, --date <date> date of the desired version of paths
-l, --latest mount latest available archive
-a <archive>, --archive <archive> name of the archive to mount
-A, --all mount all available archives
-d <date>, --date <date> date of the desired archive
-e, --include-external when mounting all archives, do
not limit archives to only those
associated with this configuration
You can mount a repository or archive using:
Expand Down Expand Up @@ -851,13 +874,14 @@ def run(cls, command, args, settings, options):
mount_point = cmdline['<mount_point>']
archive = cmdline['--archive']
date = cmdline['--date']
latest = cmdline['--latest']
mount_all = cmdline['--all']
include_external_archives = cmdline['--include-external']

# get the desired archive
if not archive:
if date:
archive = get_name_of_nearest_archive(settings, date)
elif latest:
elif not mount_all:
archive = get_name_of_latest_archive(settings)

# create mount point if it does not exist
Expand All @@ -871,6 +895,7 @@ def run(cls, command, args, settings, options):
cmd = 'mount',
args = [settings.destination(archive), mount_point],
emborg_opts = options,
strip_prefix = include_external_archives,
)
out = borg.stdout
if out:
Expand All @@ -883,15 +908,20 @@ class PruneCommand(Command):
DESCRIPTION = 'prune the repository of excess archives'
USAGE = dedent("""
Usage:
emborg prune
emborg [options] prune
Options:
-e, --include-external prune all archives in repository, not just
those associated with this configuration
""").strip()
REQUIRES_EXCLUSIVITY = True
COMPOSITE_CONFIGS = True

@classmethod
def run(cls, command, args, settings, options):
# read command line
docopt(cls.USAGE, argv=[command] + args)
cmdline = docopt(cls.USAGE, argv=[command] + args)
include_external_archives = cmdline['--include-external']

# checking the settings
intervals = 'within last minutely hourly daily weekly monthly yearly'
Expand All @@ -908,6 +938,7 @@ def run(cls, command, args, settings, options):
cmd = 'prune',
args = [settings.destination()],
emborg_opts = options,
strip_prefix = include_external_archives,
)
out = borg.stdout
if out:
Expand Down Expand Up @@ -980,6 +1011,10 @@ def run(cls, command, args, settings, options):
args = [mount_point],
emborg_opts = options,
)
try:
to_path(mount_point).rmdir()
except OSError as e:
warn(os_error(e))
except Error as e:
if 'busy' in str(e):
e.reraise(
Expand Down
10 changes: 6 additions & 4 deletions emborg/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ def read(self, name=None, path=None):
# default archive if not given
if 'archive' not in self.settings:
if not 'prefix' in self.settings:
self.settings['prefix'] = '{config_name}-'
self.settings['prefix'] = '{host_name}-{user_name}-{config_name}-'
self.settings['archive'] = self.settings['prefix'] + '{{now}}'

# check() {{{2
Expand Down Expand Up @@ -297,7 +297,7 @@ def values(self, name):
yield self.resolve(value)

# borg_options() {{{2
def borg_options(self, cmd, options):
def borg_options(self, cmd, options, strip_prefix=True):
# handle special cases first {{{3
args = []
if 'verbose' in options:
Expand Down Expand Up @@ -346,6 +346,8 @@ def borg_options(self, cmd, options):

# add the borg command line options appropriate to this command {{{3
for name, attrs in BORG_SETTINGS.items():
if strip_prefix and name == 'prefix':
continue
if cmd in attrs['cmds'] or 'all' in attrs['cmds']:
opt = convert_name_to_option(name)
val = self.value(name)
Expand Down Expand Up @@ -392,7 +394,7 @@ def publish_passcode(self):
raise Error('Cannot determine the encryption passphrase.')

# run_borg() {{{2
def run_borg(self, cmd, args='', borg_opts=None, emborg_opts=()):
def run_borg(self, cmd, args='', borg_opts=None, emborg_opts=(), strip_prefix=True):

# prepare the command
os.environ.update(self.publish_passcode())
Expand All @@ -401,7 +403,7 @@ def run_borg(self, cmd, args='', borg_opts=None, emborg_opts=()):
os.environ['BORG_RSH'] = self.ssh_command
executable = self.value('borg_executable', BORG)
if borg_opts is None:
borg_opts = self.borg_options(cmd, emborg_opts)
borg_opts = self.borg_options(cmd, emborg_opts, strip_prefix)
command = (
[executable]
+ cmd.split()
Expand Down

0 comments on commit 90d0052

Please sign in to comment.