Skip to content

Commit

Permalink
Miscellaneous enhancements and fixes.
Browse files Browse the repository at this point in the history
Added --sort argument to manifest command
Added --latest argument to delete command
Assure that path settings are properly expanded (they will not be expanded by Run)
Add --quiet option
  • Loading branch information
Ken Kundert authored and Ken Kundert committed Sep 29, 2019
1 parent b86c677 commit a8af8e7
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 23 deletions.
3 changes: 3 additions & 0 deletions doc/releases.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ Releases
- Add --all command line option to *mount* command.
- Add --include-external command line option to *check*, *list*, *mount*,
and *prune* commands.
- Add --sort command line option to *manifest* command.
- Add --latest command line option to *delete* command.
- Added --quiet option
- *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
Expand Down
21 changes: 17 additions & 4 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, display, full_stop, is_str, narrate, os_error, output,
codicil, conjoin, full_stop, is_str, narrate, os_error, output,
render, warn,
)
from docopt import docopt
Expand Down Expand Up @@ -369,7 +369,10 @@ class DeleteCommand(Command):
DESCRIPTION = 'delete an archive currently contained in the repository'
USAGE = dedent("""
Usage:
emborg delete <archive>
emborg [options] delete [<archive>]
Options:
-l, --latest delete the most recently created 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
Expand All @@ -385,6 +388,10 @@ def run(cls, command, args, settings, options):
# read command line
cmdline = docopt(cls.USAGE, argv=[command] + args)
archive = cmdline['<archive>']
if not archive:
archive = get_name_of_latest_archive(settings)
if not archive:
raise Error('archive missing.')

# run borg
borg = settings.run_borg(
Expand Down Expand Up @@ -577,7 +584,7 @@ def run(cls, command, args, settings, options):
if paths != new_paths:
for path in paths:
if path.startswith('/'):
warn('removing initial /.', culprit=path)
narrate('removing initial /.', culprit=path)
paths = new_paths

# assure that paths correspond to src_dirs
Expand Down Expand Up @@ -776,6 +783,7 @@ class ManifestCommand(Command):
-a <archive>, --archive <archive> name of the archive to use
-d <date>, --date <date> date of the desired archive
-n, --name output only the filename
-s, --sort sort by filename if -n specified
Once a backup has been performed, you can list the files available in
your archive using:
Expand Down Expand Up @@ -804,6 +812,7 @@ def run(cls, command, args, settings, options):
archive = cmdline['--archive']
date = cmdline['--date']
filenames_only = cmdline['--name']
sort = cmdline['--sort'] and filenames_only

# get the desired archive
if date and not archive:
Expand All @@ -821,7 +830,11 @@ def run(cls, command, args, settings, options):
)
out = borg.stdout
if out:
output(out.rstrip())
out = out.rstrip()
if sort:
output('\n'.join(sorted(out.splitlines())))
else:
output(out)


# MountCommand command {{{1
Expand Down
3 changes: 3 additions & 0 deletions emborg/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
-h, --help Output basic usage information.
-m, --mute Suppress all output.
-n, --narrate Send emborg and Borg narration to stdout.
-q, --quiet Suppress optional output.
-t, --trial-run Run Borg in dry run mode.
-v, --verbose Make Borg more verbose.
--no-log Do not create log file.
Expand Down Expand Up @@ -64,6 +65,8 @@ def main():
args = cmdline['<args>']
if cmdline['--mute']:
inform.mute = True
if cmdline['--quiet']:
inform.quiet = True
options = cull([
'verbose' if cmdline['--verbose'] else '',
'narrate' if cmdline['--narrate'] else '',
Expand Down
47 changes: 28 additions & 19 deletions emborg/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,9 +137,9 @@ def __init__(self, name=None, command=None, options=()):
self.composite_config_allowed = False
self.settings = {}
self.options = options
self.config_dir = to_path(CONFIG_DIR)
self.read(name)
self.check()
self.config_dir = to_path(CONFIG_DIR)

# read() {{{2
def read(self, name=None, path=None):
Expand All @@ -156,14 +156,16 @@ def read(self, name=None, path=None):
"""

if path:
narrate('reading:', str(path))
settings = PythonFile(path).run()
parent = path.parent
includes = Collection(settings.get(INCLUDE_SETTING))
else:
# this is the generic settings file
parent = to_path(CONFIG_DIR)
parent = self.config_dir
if not parent.exists():
# config dir does not exist, create and populate it
narrate('creating config directory:', str(parent))
parent.mkdir(mode=0o700, parents=True, exist_ok=True)
for name, contents in [
(SETTINGS_FILE, INITIAL_SETTINGS_FILE_CONTENTS),
Expand All @@ -185,6 +187,7 @@ def read(self, name=None, path=None):

path = PythonFile(parent, SETTINGS_FILE)
settings_filename = path.path
narrate('reading:', str(path))
settings = path.run()

config = get_config(name, settings, self.composite_config_allowed)
Expand Down Expand Up @@ -239,6 +242,7 @@ def resolve(self, value):
return str(value)
return value

# expand names contained in braces
try:
resolved = value.format(
host_name=hostname, user_name=username, prog_name=PROGRAM_NAME,
Expand All @@ -252,6 +256,12 @@ def resolve(self, value):
# restore escaped double braces with single braces
return resolved.replace(r'\b', '{').replace(r'\e', '}')

# resolve_path {{{2
def resolve_path(self, value, parent_dir=None):
if parent_dir:
return to_path(parent_dir, self.resolve(value))
return to_path(self.resolve(value))

# handle errors {{{2
def fail(self, *msg, comment=''):
msg = full_stop(' '.join(str(m) for m in msg))
Expand Down Expand Up @@ -388,13 +398,15 @@ def publish_passcode(self):
if passcode:
return dict(BORG_PASSPHRASE = passcode)

if self.encryption is None:
self.encryption = 'none'
if self.encryption == 'none':
narrate('passphrase is not available, encryption disabled.')
return {}
raise Error('Cannot determine the encryption passphrase.')

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

# prepare the command
os.environ.update(self.publish_passcode())
Expand Down Expand Up @@ -439,7 +451,7 @@ def run_borg_raw(self, args):
os.environ.update(self.publish_passcode())
os.environ['BORG_DISPLAY_PASSPHRASE'] = 'no'
executable = self.value('borg_executable', BORG)
repository = self.value('repository')
repository = str(self.repository)
command = (
[executable] + [
(repository if a == '@repo' else a) for a in args
Expand All @@ -454,7 +466,7 @@ def run_borg_raw(self, args):

# destination() {{{2
def destination(self, archive=None):
repository = self.value('repository')
repository = str(self.repository)
if archive is True:
archive = self.value('archive')
if not archive:
Expand All @@ -476,37 +488,34 @@ def __iter__(self):
# enter {{{2
def __enter__(self):
# resolve src directories
self.src_dirs = [to_path(self.resolve(d)) for d in self.src_dirs]
self.src_dirs = [self.resolve_path(d) for d in self.src_dirs]

# resolve repository and archive
self.repository = self.resolve(self.repository)
self.repository = self.resolve_path(self.repository)
self.archive = self.resolve(self.archive)

# resolve other files and directories
data_dir = self.resolve(DATA_DIR)
self.data_dir = to_path(data_dir, data_dir)
data_dir = self.resolve_path(DATA_DIR)
self.data_dir = data_dir

if not self.data_dir.exists():
# config dir does not exist, create and populate it
if not data_dir.exists():
# data dir does not exist, create it
self.data_dir.mkdir(mode=0o700, parents=True, exist_ok=True)

logfile = self.resolve(LOG_FILE)
self.logfile = to_path(data_dir, logfile)
self.logfile = self.resolve_path(LOG_FILE, data_dir)

if 'no-log' not in self.options:
prev_logfile = self.resolve(PREV_LOG_FILE)
self.prev_logfile = to_path(data_dir, prev_logfile)
self.prev_logfile = self.resolve_path(PREV_LOG_FILE, data_dir)
rm(self.prev_logfile)
if self.logfile.exists():
mv(self.logfile, self.prev_logfile)

date_file = self.resolve(DATE_FILE)
self.date_file = to_path(data_dir, date_file)
self.date_file = self.resolve_path(DATE_FILE, data_dir)

# perform locking
lockfile = self.lockfile = to_path(data_dir, self.resolve(LOCK_FILE))
lockfile = self.lockfile = self.resolve_path(LOCK_FILE, data_dir)
if self.requires_exclusivity:
# check for existance of lockfile
# check for existence of lockfile
if lockfile.exists():
raise Error(f'currently running (see {lockfile} for details).')

Expand Down

0 comments on commit a8af8e7

Please sign in to comment.