# HG changeset patch # User Tuomo Valkonen # Date 1517139481 0 # Node ID b075b3db3044fe373a888ae4084d92eea1c7975b # Parent 83b43987e61ec23cf5716bf9655ce25830762e1a Cleaned up module organisation to simplify borgend.py and not have to import it in other modules. diff -r 83b43987e61e -r b075b3db3044 backup.py --- a/backup.py Sun Jan 28 11:04:52 2018 +0000 +++ b/backup.py Sun Jan 28 11:38:01 2018 +0000 @@ -5,7 +5,7 @@ import config import logging import time -import borgend +import loggers import repository import dreamtime from enum import IntEnum @@ -13,7 +13,7 @@ from threading import Thread, Lock, Condition from scheduler import TerminableThread -logger=borgend.logger.getChild(__name__) +logger=loggers.get(__name__) JOIN_TIMEOUT=60 diff -r 83b43987e61e -r b075b3db3044 borgend.py --- a/borgend.py Sun Jan 28 11:04:52 2018 +0000 +++ b/borgend.py Sun Jan 28 11:38:01 2018 +0000 @@ -1,174 +1,108 @@ #!/usr/local/bin/python3 +# Common modules import os import sys -import logging -import logging.handlers import argparse import platform - -# -# Branding -# -appname="borgend" -appname_stylised="Borgend" - -# -# Logging configuration -# - -loglevel=logging.INFO -logfmt="%(asctime)s:%(levelname)s:%(name)s:%(message)s" -fifolog_capacity=1000 -fifolog_fmt="%(asctime)s:%(levelname)s:%(message)s" - -# -# Setup logger, needed by the config module to be loaded next -# - -logger=logging.getLogger(appname) -logger.handlers.clear() -logger.setLevel(loglevel) -stderrlog=logging.StreamHandler() -stderrlog.setLevel(logging.WARNING) -logger.addHandler(stderrlog) -logger.propagate=True - -# -# Import our own modules. This needs to be done here -# for the things above to be available to them -# - -import config -from scheduler import Scheduler -from fifolog import FIFOHandler -from repository import Repository +import branding +# Own modules needed at this stage +import locations # # Argument processing # -def do_args(): - parser=argparse.ArgumentParser( - description=appname_stylised + ': BorgBackup scheduler and tray icon.', - epilog='Configuration file location:\n\n %s\n ' % config.cfgfile, - formatter_class=argparse.RawDescriptionHelpFormatter) +parser=argparse.ArgumentParser( + description=branding.appname_stylised + ": BorgBackup scheduler, queue, and tray icon.", + epilog='Configuration file location:\n\n %s\n ' % locations.cfgfile, + formatter_class=argparse.RawDescriptionHelpFormatter) - parser.add_argument( - '--no-tray', - dest='notray', - action='store_true', - help='Do not show the tray icon') +parser.add_argument( + '--no-tray', + dest='notray', + action='store_true', + help='Do not show the tray icon') - parser.add_argument( - '--debug', - dest='debug', - action='store_true', - help='Set logging level to debug') +parser.add_argument( + '--debug', + dest='debug', + action='store_true', + help='Set logging level to debug') - return parser.parse_args() +args=parser.parse_args() # -# Main routine +# Done parsing args, import our own modules, and launch everything # -# First, setup our own logging handlers -fifolog=FIFOHandler(fifolog_capacity) -logger.addHandler(fifolog) -fifolog.setFormatter(logging.Formatter(fifolog_fmt)) +import branding +import config +import dreamtime +import loggers +import logging +from scheduler import Scheduler +from repository import Repository +from backup import Backup -if __name__=="__main__": - # Parse args. Let argparse handle errors/exit if there are any - args= do_args() - tray = None - repos=[] - backups=[] +logger=loggers.mainlogger - try: - args=do_args() - - if args.debug: - logger.setLevel(logging.DEBUG) - - if not os.path.isdir(config.logs_dir): - os.makedirs(config.logs_dir) +if args.debug: + logger.setLevel(logging.DEBUG) - handler=logging.handlers.TimedRotatingFileHandler( - os.path.join(config.logs_dir, appname+'.log'), - when='D', interval=1) - handler.setFormatter(logging.Formatter(logfmt)) - logger.addHandler(handler) +tray = None +repos=[] +backups=[] - from threading import Thread - from backup import Backup - from queue import Queue - import signal, os - import dreamtime +try: + dreamtime.start_monitoring() - dreamtime.start_monitoring() + scheduler = Scheduler() + scheduler.start() - scheduler = Scheduler() - scheduler.start() - - repoconfigs=config.settings['repositories'] + repoconfigs=config.settings['repositories'] - for i in range(len(repoconfigs)): - logger.info('Setting up repository %d' % i) - r=Repository(i, repoconfigs[i]) - repos.append(r) + for i in range(len(repoconfigs)): + logger.info('Setting up repository %d' % i) + r=Repository(i, repoconfigs[i]) + repos.append(r) - backupconfigs=config.settings['backups'] + backupconfigs=config.settings['backups'] - for i in range(len(backupconfigs)): - logger.info('Setting up backup set %d' % i) - b=Backup(i, backupconfigs[i], scheduler) - backups.append(b) - - for r in repos: - r.start() - - for b in backups: - b.start() + for i in range(len(backupconfigs)): + logger.info('Setting up backup set %d' % i) + b=Backup(i, backupconfigs[i], scheduler) + backups.append(b) - if args.notray or platform.system()!='Darwin': - # Wait for scheduler to finish - scheduler.join() - else: - # Start UI, and let it handle exit control - from ui import BorgendTray - tray=BorgendTray(backups); - tray.run() + for r in repos: + r.start() - except Exception as err: - # TODO: Should write errors here to stderr; - # perhaps add an extra stderr logger for error level messages - logger.exception("Exception fell through to outer level: exiting") + for b in backups: + b.start() - finally: - for b in backups: - b.terminate() - - for r in repos: - r.terminate() - - if tray: - tray.quit() - else: - logging.shutdown() + if args.notray or platform.system()!='Darwin': + # Wait for scheduler to finish + scheduler.join() + else: + # Start UI, and let it handle exit control + from ui import BorgendTray + tray=BorgendTray(backups); + tray.run() - # - # This shit is fucked, disables ^C etc., and threading doesn't seem to help - # +except Exception as err: + # TODO: Should write errors here to stderr; + # perhaps add an extra stderr logger for error level messages + logger.exception("Exception fell through: exiting") - # ui_thread=Thread(target=tray.run) - # ui_thread.daemon=True - # ui_thread.start() +finally: + for b in backups: + b.terminate() - # def quit_signal_handler(signum, frame): - # print('Signal handler called with signal %s' % str(signum)) - # ui_thread.terminate() - # os.exit() + for r in repos: + r.terminate() - # signal.signal(signal.SIGTERM, quit_signal_handler) - # signal.signal(signal.SIGINT, quit_signal_handler) + if tray: + tray.quit() + else: + logging.shutdown() diff -r 83b43987e61e -r b075b3db3044 branding.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/branding.py Sun Jan 28 11:38:01 2018 +0000 @@ -0,0 +1,6 @@ +# +# Branding +# + +appname="borgend" +appname_stylised="Borgend" diff -r 83b43987e61e -r b075b3db3044 config.py --- a/config.py Sun Jan 28 11:04:52 2018 +0000 +++ b/config.py Sun Jan 28 11:38:01 2018 +0000 @@ -10,9 +10,11 @@ import logging import platform from functools import reduce -import borgend +import loggers +import branding +import locations -logger=borgend.logger.getChild(__name__) +logger=loggers.get(__name__) # # Defaults @@ -39,20 +41,6 @@ } # -# Locations -# - -if platform.system()!='Darwin': - import xdg - cfgfile=os.path.join(xdg.XDG_CONFIG_HOME, borgend.appname, "config.yaml") - logs_dir=os.path.join(xdg.XDG_DATA_HOME, borgend.appname, "logs") -else: - import rumps - __base=rumps.application_support(borgend.appname) - cfgfile=os.path.join(__base, "config.yaml") - logs_dir=os.path.join(__base, "logs") - -# # Type checking etc. # @@ -156,12 +144,12 @@ return out -if not (os.path.exists(cfgfile) and os.path.isfile(cfgfile)): - raise SystemExit("Configuration file required: %s" % cfgfile) +if not (os.path.exists(locations.cfgfile) and os.path.isfile(locations.cfgfile)): + raise SystemExit("Configuration file required: %s" % locations.cfgfile) -logger.info("Reading configuration %s missing" % cfgfile) +logger.info("Reading configuration %s missing" % locations.cfgfile) -with io.open(cfgfile, 'r') as file: +with io.open(locations.cfgfile, 'r') as file: settings=expand_env(yaml.load(file), os.environ); # diff -r 83b43987e61e -r b075b3db3044 dreamtime.py --- a/dreamtime.py Sun Jan 28 11:04:52 2018 +0000 +++ b/dreamtime.py Sun Jan 28 11:38:01 2018 +0000 @@ -9,9 +9,9 @@ import threading import weakref import datetime -import borgend +import loggers -logger=borgend.logger.getChild(__name__) +logger=loggers.get(__name__) _dreamtime_monitor=None diff -r 83b43987e61e -r b075b3db3044 instance.py --- a/instance.py Sun Jan 28 11:04:52 2018 +0000 +++ b/instance.py Sun Jan 28 11:38:01 2018 +0000 @@ -5,11 +5,11 @@ import json import logging import os -import borgend +import loggers from config import settings from subprocess import Popen, PIPE -logger=borgend.logger.getChild(__name__) +logger=loggers.get(__name__) necessary_opts=['--log-json', '--progress'] diff -r 83b43987e61e -r b075b3db3044 locations.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/locations.py Sun Jan 28 11:38:01 2018 +0000 @@ -0,0 +1,17 @@ +# +# Locations +# + +import os +import platform +import branding + +if platform.system()!='Darwin': + import xdg + cfgfile=os.path.join(xdg.XDG_CONFIG_HOME, branding.appname, "config.yaml") + logs_dir=os.path.join(xdg.XDG_DATA_HOME, branding.appname, "logs") +else: + import rumps + __base=rumps.application_support(branding.appname) + cfgfile=os.path.join(__base, "config.yaml") + logs_dir=os.path.join(__base, "logs") diff -r 83b43987e61e -r b075b3db3044 loggers.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loggers.py Sun Jan 28 11:38:01 2018 +0000 @@ -0,0 +1,61 @@ +# +# Loggers +# + +import os +import logging +import logging.handlers +import atexit + +from fifolog import FIFOHandler +import branding +import locations + +# +# Logging configuration +# + +loglevel=logging.INFO +logfmt="%(asctime)s:%(levelname)s:%(name)s:%(message)s" +fifo_capacity=1000 +fifo_fmt="%(asctime)s:%(levelname)s:%(message)s" + +# +# Setting up the main logger with fifo, stderr, and rotating files output +# + +mainlogger=logging.getLogger(branding.appname) +mainlogger.setLevel(loglevel) +mainlogger.propagate=True + +mainlogger.handlers.clear() + +# Internal FIFO history +fifo=FIFOHandler(fifo_capacity) +fifo.setFormatter(logging.Formatter(fifo_fmt)) +mainlogger.addHandler(fifo) + +# stderr +stderrlog=logging.StreamHandler() +stderrlog.setLevel(logging.WARNING) +mainlogger.addHandler(stderrlog) + +# Rotating files +if not os.path.isdir(locations.logs_dir): + os.makedirs(locations.logs_dir) + +fileslog=logging.handlers.TimedRotatingFileHandler( + os.path.join(locations.logs_dir, branding.appname+'.log'), + when='D', interval=1) +fileslog.setFormatter(logging.Formatter(logfmt)) +mainlogger.addHandler(fileslog) + +atexit.register(logging.shutdown) + +# +# Routine for obtaining sub-loggers +# + +def get(name): + return mainlogger.getChild(name) + diff -r 83b43987e61e -r b075b3db3044 repository.py --- a/repository.py Sun Jan 28 11:04:52 2018 +0000 +++ b/repository.py Sun Jan 28 11:38:01 2018 +0000 @@ -4,11 +4,11 @@ import weakref import keyring -import borgend +import loggers import config from scheduler import QueueThread, QueuedEvent -logger=borgend.logger.getChild(__name__) +logger=loggers.get(__name__) class FIFOEvent(QueuedEvent): def __init__(self, cond, name=None): diff -r 83b43987e61e -r b075b3db3044 scheduler.py --- a/scheduler.py Sun Jan 28 11:04:52 2018 +0000 +++ b/scheduler.py Sun Jan 28 11:38:01 2018 +0000 @@ -5,11 +5,11 @@ # import time -import borgend +import loggers import dreamtime from threading import Condition, Lock, Thread -logger=borgend.logger.getChild(__name__) +logger=loggers.get(__name__) class QueuedEvent: def __init__(self, cond, name=None): diff -r 83b43987e61e -r b075b3db3044 ui.py --- a/ui.py Sun Jan 28 11:04:52 2018 +0000 +++ b/ui.py Sun Jan 28 11:38:01 2018 +0000 @@ -5,15 +5,16 @@ import rumps import time import datetime -import logging -import borgend +import objc +from threading import Lock, Timer + +import loggers import backup import dreamtime -from threading import Lock, Timer +import branding from config import settings -import objc -logger=borgend.logger.getChild(__name__) +logger=loggers.get(__name__) traynames_ok={ backup.State.INACTIVE: 'B.', @@ -256,11 +257,10 @@ logger.debug("Opening notification for error %s '%s'", msgid, errorlog['message']) - notification_workaround(borgend.appname_stylised, + notification_workaround(branding.appname_stylised, msgid, errorlog['message']) def quit(self): - logging.shutdown() rumps.quit_application() def __menu_select_backup(self, sender, b): @@ -270,7 +270,7 @@ b.create() except Exception as err: logger.exception("Failure to initialise backup") - notification_workaround(borgend.appname_stylised, + notification_workaround(branding.appname_stylised, err.__class__.__name__, str(err)) #