50 |
51 |
51 self.__decode_config(cfg) |
52 self.__decode_config(cfg) |
52 |
53 |
53 self.config=config |
54 self.config=config |
54 self.lastrun=None |
55 self.lastrun=None |
|
56 self.lastrun_success=None |
55 self.borg_instance=None |
57 self.borg_instance=None |
|
58 self.current_operation=None |
56 self.thread=None |
59 self.thread=None |
57 self.lock=Lock() |
60 self.lock=Lock() |
58 |
61 |
59 def __block_when_running(self): |
62 def __block_when_running(self): |
60 self.lock.acquire() |
63 with self.lock: |
61 not_running=self.borg_instance is None and self.thread is None |
64 not_running=self.borg_instance is None and self.thread is None |
62 self.lock.release() |
|
63 assert(not_running) |
65 assert(not_running) |
64 |
66 |
65 def __listener(self): |
67 def __listener(self): |
|
68 success=True |
66 for status in iter(self.borg_instance.read, None): |
69 for status in iter(self.borg_instance.read, None): |
67 t=status['type'] |
70 t=status['type'] |
68 if t=='progress_percent': |
71 if t=='progress_percent': |
69 pass |
72 pass |
70 elif t=='archive_progress': |
73 elif t=='archive_progress': |
71 pass |
74 pass |
72 elif t=='progress_message': |
75 elif t=='progress_message': |
|
76 # handle errors |
73 pass |
77 pass |
74 elif t=='progress_percent': |
78 elif t=='progress_percent': |
75 pass |
79 pass |
76 elif t=='file_status': |
80 elif t=='file_status': |
77 pass |
81 pass |
78 elif t=='log_message': |
82 elif t=='log_message': |
79 pass |
83 pass |
80 elif t=='exception': |
84 elif t=='exception': |
|
85 success=False |
81 pass |
86 pass |
82 elif t=='unparsed_error': |
87 elif t=='unparsed_error': |
|
88 success=False |
83 pass |
89 pass |
84 # What to do? |
90 # What to do? |
85 print(status) |
91 print(status) |
86 |
92 |
87 logging.info('Borg subprocess finished; terminating listener thread') |
93 logging.info('Borg subprocess finished; terminating listener thread') |
88 |
94 |
89 self.lock.acquire() |
95 with self.lock: |
90 self.borg_instance=None |
96 if self.current_operation=='create': |
91 self.thread=None |
97 self.lastrun=self.time_started |
92 self.lock.release() |
98 self.lastrun_success=success |
|
99 self.borg_instance=None |
|
100 self.thread=None |
|
101 self.current_operation=None |
|
102 self.time_started=None |
93 |
103 |
94 def __launch(self, queue, operation, archive_or_repository, *args): |
104 def __launch(self, queue, operation, archive_or_repository, *args): |
95 |
105 |
96 inst=BorgInstance(operation, archive_or_repository, *args) |
106 inst=BorgInstance(operation, archive_or_repository, *args) |
97 inst.launch() |
107 inst.launch() |
120 self.__launch(queue, 'prune', self.repository, |
132 self.__launch(queue, 'prune', self.repository, |
121 [{'prefix': self.archive_prefix}] + self.prune_parameters) |
133 [{'prefix': self.archive_prefix}] + self.prune_parameters) |
122 |
134 |
123 # TODO: Decide exact (manual) abort mechanism. Perhaps two stages |
135 # TODO: Decide exact (manual) abort mechanism. Perhaps two stages |
124 def abort(self): |
136 def abort(self): |
125 self.lock.acquire() |
137 with self.lock: |
126 if self.borg_instance: |
138 if self.borg_instance: |
127 self.borg_instance.terminate() |
139 self.borg_instance.terminate() |
128 if self.thread: |
140 if self.thread: |
129 self.thread.terminate() |
141 self.thread.terminate() |
130 self.lock.release() |
|
131 |
142 |
132 def join(self): |
143 def join(self): |
133 if self.thread: |
144 if self.thread: |
134 self.thread.join() |
145 self.thread.join() |
135 |
146 |
|
147 def next_action(): |
|
148 # TODO pruning as well |
|
149 now=time.monotonic() |
|
150 if not self.lastrun: |
|
151 return 'create', now+self.retry_interval |
|
152 elif not self.lastrun_success: |
|
153 return 'create', self.lastrun+self.retry_interval |
|
154 else: |
|
155 if self.backup_interval==0: |
|
156 return 'none', 0 |
|
157 else: |
|
158 return 'create', self.lastrun+self.backup_interval |
136 |
159 |
137 |
160 |