| 6 import logging |
6 import logging |
| 7 from subprocess import Popen, PIPE |
7 from subprocess import Popen, PIPE |
| 8 from config import settings, arglistify |
8 from config import settings, arglistify |
| 9 |
9 |
| 10 necessary_opts=['--log-json', '--progress'] |
10 necessary_opts=['--log-json', '--progress'] |
| |
11 |
| |
12 necessary_opts_for={ |
| |
13 'create': ['--json'], |
| |
14 'info': ['--json'], |
| |
15 'list': ['--json'], |
| |
16 } |
| 11 |
17 |
| 12 class BorgInstance: |
18 class BorgInstance: |
| 13 def __init__(self, operation, archive_or_repository, args, argsl): |
19 def __init__(self, operation, archive_or_repository, args, argsl): |
| 14 self.operation=operation; |
20 self.operation=operation; |
| 15 self.args=args; |
21 self.args=args; |
| 22 [self.operation]) |
28 [self.operation]) |
| 23 tmp1=self.operation+'_parameters' |
29 tmp1=self.operation+'_parameters' |
| 24 if tmp1 in settings['borg']: |
30 if tmp1 in settings['borg']: |
| 25 cmd=cmd+arglistify(settings['borg'][tmp1]) |
31 cmd=cmd+arglistify(settings['borg'][tmp1]) |
| 26 |
32 |
| |
33 if self.operation in necessary_opts_for: |
| |
34 cmd=cmd+necessary_opts_for[self.operation] |
| |
35 |
| 27 return cmd+arglistify(self.args)+[self.archive_or_repository]+self.argsl |
36 return cmd+arglistify(self.args)+[self.archive_or_repository]+self.argsl |
| 28 |
37 |
| 29 def launch(self): |
38 def launch(self): |
| 30 # Borg prints json to stderr, so pipe it |
|
| 31 cmd=self.construct_cmdline() |
39 cmd=self.construct_cmdline() |
| 32 |
40 |
| 33 logging.info('Launching ' + str(cmd)) |
41 logging.info('Launching ' + str(cmd)) |
| 34 |
42 |
| 35 self.proc=Popen(cmd, stderr=PIPE) |
43 self.proc=Popen(cmd, stdout=PIPE, stderr=PIPE) |
| 36 |
44 |
| 37 def read(self): |
45 def read_result(self): |
| |
46 stream=self.proc.stdout |
| |
47 line=stream.read(-1) |
| |
48 if line==b'': |
| |
49 logging.debug('Borg stdout pipe EOF?') |
| |
50 return None |
| |
51 |
| 38 try: |
52 try: |
| 39 line=self.proc.stderr.readline() |
53 return json.loads(line) |
| |
54 except: |
| |
55 logging.warning('JSON parse failed on: "%s"' % line) |
| |
56 return None |
| |
57 |
| |
58 def read_log(self): |
| |
59 stream=self.proc.stderr |
| |
60 try: |
| |
61 line=stream.readline() |
| 40 except err: |
62 except err: |
| 41 logging.info('Pipe read failed: %s' % str(err)) |
63 logging.debug('Pipe read failed: %s' % str(err)) |
| 42 |
64 |
| 43 return {'type': 'exception', 'exception': err} |
65 return {'type': 'exception', 'exception': err} |
| 44 |
66 |
| 45 if line==b'': |
67 if line==b'': |
| 46 |
68 |
| 47 logging.info('Pipe EOF?') |
69 logging.debug('Borg stderr pipe EOF?') |
| 48 |
70 |
| 49 return None |
71 return None |
| 50 |
72 |
| 51 try: |
73 try: |
| 52 res=json.loads(line) |
74 res=json.loads(line) |
| 53 if 'type' not in res: |
75 if 'type' not in res: |
| 54 res['type']='UNKNOWN' |
76 res['type']='UNKNOWN' |
| 55 return res |
77 return res |
| 56 except: |
78 except: |
| 57 logging.warning('JSON parse failed on: "%s"' % line) |
79 logging.debug('JSON parse failed on: "%s"' % line) |
| 58 |
80 |
| 59 errmsg=line |
81 errmsg=line |
| 60 for line in iter(self.proc.stderr.readline, b''): |
82 for line in iter(stream.readline, b''): |
| 61 errmsg=errmsg+line |
83 errmsg=errmsg+line |
| 62 |
84 |
| 63 return {'type': 'unparsed_error', 'message': str(errmsg)} |
85 return {'type': 'unparsed_error', 'message': str(errmsg)} |
| 64 |
86 |
| 65 def terminate(self): |
87 def terminate(self): |