| 1 # |
1 # |
| 2 # Borgend Backup instance |
2 # Borgend Backup instance |
| 3 # |
3 # |
| 4 |
4 |
| 5 import config |
5 import config |
| |
6 import logging |
| 6 from instance import BorgInstance |
7 from instance import BorgInstance |
| 7 from queue import Queue |
8 from queue import Queue |
| 8 from threading import Thread |
9 from threading import Thread, Lock |
| 9 |
10 |
| 10 class Backup: |
11 class Backup: |
| 11 |
12 |
| 12 def __decode_config(self, cfg): |
13 def __decode_config(self, cfg): |
| 13 loc0='backup target %d' % self.identifier |
14 loc0='backup target %d' % self.identifier |
| 51 |
52 |
| 52 self.config=config |
53 self.config=config |
| 53 self.lastrun=None |
54 self.lastrun=None |
| 54 self.borg_instance=None |
55 self.borg_instance=None |
| 55 self.thread=None |
56 self.thread=None |
| |
57 self.lock=Lock() |
| 56 |
58 |
| 57 def __block_when_running(self): |
59 def __block_when_running(self): |
| 58 assert(self.borg_instance is None and self.thread is None) |
60 self.lock.acquire() |
| |
61 not_running=self.borg_instance is None and self.thread is None |
| |
62 self.lock.release() |
| |
63 assert(not_running) |
| 59 |
64 |
| 60 def __listener(self): |
65 def __listener(self): |
| 61 for status in iter(self.borg_instance.read, None): |
66 for status in iter(self.borg_instance.read, None): |
| |
67 t=status['type'] |
| |
68 if t=='progress_percent': |
| |
69 pass |
| |
70 elif t=='archive_progress': |
| |
71 pass |
| |
72 elif t=='progress_message': |
| |
73 pass |
| |
74 elif t=='progress_percent': |
| |
75 pass |
| |
76 elif t=='file_status': |
| |
77 pass |
| |
78 elif t=='log_message': |
| |
79 pass |
| |
80 elif t=='exception': |
| |
81 pass |
| |
82 elif t=='unparsed_error': |
| |
83 pass |
| 62 # What to do? |
84 # What to do? |
| 63 print(status) |
85 print(status) |
| 64 # What to do on error |
86 |
| 65 # queue.put({'identifier': instance.identifier, |
87 logging.info('Borg subprocess finished; terminating listener thread') |
| 66 # 'operation': instance.operation, |
88 |
| 67 # 'status': status}) |
89 self.lock.acquire() |
| |
90 self.borg_instance=None |
| |
91 self.thread=None |
| |
92 self.lock.release() |
| 68 |
93 |
| 69 def __launch(self, queue, operation, archive_or_repository, *args): |
94 def __launch(self, queue, operation, archive_or_repository, *args): |
| 70 |
95 |
| 71 inst=BorgInstance(operation, archive_or_repository, *args) |
96 inst=BorgInstance(operation, archive_or_repository, *args) |
| 72 inst.launch() |
97 inst.launch() |
| 93 def prune(self, queue): |
118 def prune(self, queue): |
| 94 self.__block_when_running() |
119 self.__block_when_running() |
| 95 self.__launch(queue, 'prune', self.repository, |
120 self.__launch(queue, 'prune', self.repository, |
| 96 [{'prefix': self.archive_prefix}] + self.prune_parameters) |
121 [{'prefix': self.archive_prefix}] + self.prune_parameters) |
| 97 |
122 |
| |
123 # TODO: Decide exact (manual) abort mechanism. Perhaps two stages |
| |
124 def abort(self): |
| |
125 self.lock.acquire() |
| |
126 if self.borg_instance: |
| |
127 self.borg_instance.terminate() |
| |
128 if self.thread: |
| |
129 self.thread.terminate() |
| |
130 self.lock.release() |
| |
131 |
| 98 def join(self): |
132 def join(self): |
| 99 if self.thread: |
133 if self.thread: |
| 100 self.thread.join() |
134 self.thread.join() |
| 101 |
135 |
| 102 |
136 |