borgend.py

changeset 79
b075b3db3044
parent 78
83b43987e61e
child 80
a409242121d5
equal deleted inserted replaced
78:83b43987e61e 79:b075b3db3044
1 #!/usr/local/bin/python3 1 #!/usr/local/bin/python3
2 2
3 # Common modules
3 import os 4 import os
4 import sys 5 import sys
5 import logging
6 import logging.handlers
7 import argparse 6 import argparse
8 import platform 7 import platform
9 8 import branding
10 # 9 # Own modules needed at this stage
11 # Branding 10 import locations
12 #
13 appname="borgend"
14 appname_stylised="Borgend"
15
16 #
17 # Logging configuration
18 #
19
20 loglevel=logging.INFO
21 logfmt="%(asctime)s:%(levelname)s:%(name)s:%(message)s"
22 fifolog_capacity=1000
23 fifolog_fmt="%(asctime)s:%(levelname)s:%(message)s"
24
25 #
26 # Setup logger, needed by the config module to be loaded next
27 #
28
29 logger=logging.getLogger(appname)
30 logger.handlers.clear()
31 logger.setLevel(loglevel)
32 stderrlog=logging.StreamHandler()
33 stderrlog.setLevel(logging.WARNING)
34 logger.addHandler(stderrlog)
35 logger.propagate=True
36
37 #
38 # Import our own modules. This needs to be done here
39 # for the things above to be available to them
40 #
41
42 import config
43 from scheduler import Scheduler
44 from fifolog import FIFOHandler
45 from repository import Repository
46 11
47 # 12 #
48 # Argument processing 13 # Argument processing
49 # 14 #
50 15
51 def do_args(): 16 parser=argparse.ArgumentParser(
52 parser=argparse.ArgumentParser( 17 description=branding.appname_stylised + ": BorgBackup scheduler, queue, and tray icon.",
53 description=appname_stylised + ': BorgBackup scheduler and tray icon.', 18 epilog='Configuration file location:\n\n %s\n ' % locations.cfgfile,
54 epilog='Configuration file location:\n\n %s\n ' % config.cfgfile, 19 formatter_class=argparse.RawDescriptionHelpFormatter)
55 formatter_class=argparse.RawDescriptionHelpFormatter)
56 20
57 parser.add_argument( 21 parser.add_argument(
58 '--no-tray', 22 '--no-tray',
59 dest='notray', 23 dest='notray',
60 action='store_true', 24 action='store_true',
61 help='Do not show the tray icon') 25 help='Do not show the tray icon')
62 26
63 parser.add_argument( 27 parser.add_argument(
64 '--debug', 28 '--debug',
65 dest='debug', 29 dest='debug',
66 action='store_true', 30 action='store_true',
67 help='Set logging level to debug') 31 help='Set logging level to debug')
68 32
69 return parser.parse_args() 33 args=parser.parse_args()
70 34
71 # 35 #
72 # Main routine 36 # Done parsing args, import our own modules, and launch everything
73 # 37 #
74 38
75 # First, setup our own logging handlers 39 import branding
76 fifolog=FIFOHandler(fifolog_capacity) 40 import config
77 logger.addHandler(fifolog) 41 import dreamtime
78 fifolog.setFormatter(logging.Formatter(fifolog_fmt)) 42 import loggers
43 import logging
44 from scheduler import Scheduler
45 from repository import Repository
46 from backup import Backup
79 47
80 if __name__=="__main__": 48 logger=loggers.mainlogger
81 # Parse args. Let argparse handle errors/exit if there are any
82 args= do_args()
83 tray = None
84 repos=[]
85 backups=[]
86 49
87 try: 50 if args.debug:
88 args=do_args() 51 logger.setLevel(logging.DEBUG)
89 52
90 if args.debug: 53 tray = None
91 logger.setLevel(logging.DEBUG) 54 repos=[]
55 backups=[]
92 56
93 if not os.path.isdir(config.logs_dir): 57 try:
94 os.makedirs(config.logs_dir) 58 dreamtime.start_monitoring()
95 59
96 handler=logging.handlers.TimedRotatingFileHandler( 60 scheduler = Scheduler()
97 os.path.join(config.logs_dir, appname+'.log'), 61 scheduler.start()
98 when='D', interval=1)
99 handler.setFormatter(logging.Formatter(logfmt))
100 logger.addHandler(handler)
101 62
102 from threading import Thread 63 repoconfigs=config.settings['repositories']
103 from backup import Backup
104 from queue import Queue
105 import signal, os
106 import dreamtime
107 64
108 dreamtime.start_monitoring() 65 for i in range(len(repoconfigs)):
66 logger.info('Setting up repository %d' % i)
67 r=Repository(i, repoconfigs[i])
68 repos.append(r)
109 69
110 scheduler = Scheduler() 70 backupconfigs=config.settings['backups']
111 scheduler.start()
112 71
113 repoconfigs=config.settings['repositories'] 72 for i in range(len(backupconfigs)):
73 logger.info('Setting up backup set %d' % i)
74 b=Backup(i, backupconfigs[i], scheduler)
75 backups.append(b)
114 76
115 for i in range(len(repoconfigs)): 77 for r in repos:
116 logger.info('Setting up repository %d' % i) 78 r.start()
117 r=Repository(i, repoconfigs[i])
118 repos.append(r)
119 79
120 backupconfigs=config.settings['backups'] 80 for b in backups:
81 b.start()
121 82
122 for i in range(len(backupconfigs)): 83 if args.notray or platform.system()!='Darwin':
123 logger.info('Setting up backup set %d' % i) 84 # Wait for scheduler to finish
124 b=Backup(i, backupconfigs[i], scheduler) 85 scheduler.join()
125 backups.append(b) 86 else:
87 # Start UI, and let it handle exit control
88 from ui import BorgendTray
89 tray=BorgendTray(backups);
90 tray.run()
126 91
127 for r in repos: 92 except Exception as err:
128 r.start() 93 # TODO: Should write errors here to stderr;
94 # perhaps add an extra stderr logger for error level messages
95 logger.exception("Exception fell through: exiting")
129 96
130 for b in backups: 97 finally:
131 b.start() 98 for b in backups:
99 b.terminate()
132 100
133 if args.notray or platform.system()!='Darwin': 101 for r in repos:
134 # Wait for scheduler to finish 102 r.terminate()
135 scheduler.join()
136 else:
137 # Start UI, and let it handle exit control
138 from ui import BorgendTray
139 tray=BorgendTray(backups);
140 tray.run()
141 103
142 except Exception as err: 104 if tray:
143 # TODO: Should write errors here to stderr; 105 tray.quit()
144 # perhaps add an extra stderr logger for error level messages 106 else:
145 logger.exception("Exception fell through to outer level: exiting") 107 logging.shutdown()
146 108
147 finally:
148 for b in backups:
149 b.terminate()
150
151 for r in repos:
152 r.terminate()
153
154 if tray:
155 tray.quit()
156 else:
157 logging.shutdown()
158
159 #
160 # This shit is fucked, disables ^C etc., and threading doesn't seem to help
161 #
162
163 # ui_thread=Thread(target=tray.run)
164 # ui_thread.daemon=True
165 # ui_thread.start()
166
167 # def quit_signal_handler(signum, frame):
168 # print('Signal handler called with signal %s' % str(signum))
169 # ui_thread.terminate()
170 # os.exit()
171
172 # signal.signal(signal.SIGTERM, quit_signal_handler)
173 # signal.signal(signal.SIGINT, quit_signal_handler)
174

mercurial