--- a/instance.py Sun Jan 28 11:38:01 2018 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,134 +0,0 @@ -# -# Borgend borg launcher / processor -# - -import json -import logging -import os -import loggers -from config import settings -from subprocess import Popen, PIPE - -logger=loggers.get(__name__) - -necessary_opts=['--log-json', '--progress'] - -necessary_opts_for={ - 'create': ['--json'], - 'info': ['--json'], - 'list': ['--json'], -} - -# Conversion of config into command line -def arglistify(args): - flatten=lambda l: [item for sublist in l for item in sublist] - if args is None: - return [] - else: - return flatten([['--' + key, str(d[key])] for d in args for key in d]) - -class BorgInstance: - def __init__(self, operation, archive_or_repository, - common_params, op_params, paths): - self.operation=operation; - self.archive_or_repository=archive_or_repository; - self.common_params=common_params - self.op_params=op_params - self.paths=paths - - def construct_cmdline(self): - cmd=([settings['borg']['executable']]+necessary_opts+ - arglistify(self.common_params)+ - [self.operation]) - - if self.operation in necessary_opts_for: - cmd=cmd+necessary_opts_for[self.operation] - - return (cmd+arglistify(self.op_params) - +[self.archive_or_repository]+self.paths) - - def launch(self, passphrase=None): - cmd=self.construct_cmdline() - - logger.info('Launching ' + str(cmd)) - - # Set passphrase if not, or set to empty if not known, so borg - # won't hang waiting for it, which seems to happen even if we - # close stdin. - env=os.environ.copy() - env['BORG_PASSPHRASE']=passphrase or '' - - # Workaround: if launched is a standalone app created with py2app, - # borg will fail unless Python environment is reset. - # TODO: Of course, this will fail if the system needs the variables - # PYTHONPATH or PYTHONHOME set to certain values. - if '_PY2APP_LAUNCHED_' in env: - val=env['_PY2APP_LAUNCHED_'] - if val=='1': - del env['PYTHONPATH'] - del env['PYTHONHOME'] - - self.proc=Popen(cmd, env=env, stdout=PIPE, stderr=PIPE, stdin=PIPE) - - # We don't do passphrase input etc. - self.proc.stdin.close() - - def read_result(self): - stream=self.proc.stdout - line=stream.read(-1) - if line==b'': - logger.debug('Borg stdout pipe EOF?') - return None - - try: - return json.loads(line) - except Exception as err: - logger.warning('JSON parse failed on: "%s"' % line) - return None - - def read_log(self): - stream=self.proc.stderr - try: - line=stream.readline() - except err: - logger.debug('Pipe read failed: %s' % str(err)) - - return {'type': 'log_message', - 'levelname': 'CRITICAL', - 'name': 'borgend.instance.BorgInstance', - 'msgid': 'Borgend.Exception', - 'message': err} - - if line==b'': - - logger.debug('Borg stderr pipe EOF?') - - return None - - try: - res=json.loads(line) - if 'type' not in res: - res['type']='UNKNOWN' - return res - except: - logger.debug('JSON parse failed on: "%s"' % str(line)) - - errmsg=line - for line in iter(stream.readline, b''): - errmsg=errmsg+line - - return {'type': 'log_message', - 'levelname': 'ERROR', - 'name': 'borgend.instance.BorgInstance', - 'msgid': 'Borgend.JSONFail', - 'message': str(errmsg)} - - def terminate(self): - self.proc.terminate() - - def wait(self): - return self.proc.wait() is not None - - def has_terminated(self): - return self.proc.poll() is not None -