diff --git a/CouchPotato.py b/CouchPotato.py index 83fac59b..479a290a 100755 --- a/CouchPotato.py +++ b/CouchPotato.py @@ -5,6 +5,8 @@ from os.path import dirname import os import sys +import subprocess + # Root path base_path = dirname(os.path.abspath(__file__)) @@ -15,10 +17,39 @@ sys.path.insert(0, os.path.join(base_path, 'libs')) from couchpotato.core.logger import CPLog log = CPLog(__name__) +# Get options via arg +from couchpotato.cli import getOptions +options = getOptions(base_path, sys.argv[1:]) + +def start(): + try: + args = [sys.executable] + sys.argv + new_environ = os.environ.copy() + new_environ['cp_main'] = 'true' + + if os.name == 'nt': + for key, value in new_environ.iteritems(): + if isinstance(value, unicode): + new_environ[key] = value.encode('iso-8859-1') + + subprocess.call(args, env = new_environ) + return os.path.isfile(os.path.join(options.data_dir, 'restart')) + except Exception, e: + log.critical(e) + return 0 from couchpotato import cli if __name__ == '__main__': - try: - cli.cmd_couchpotato(base_path, sys.argv[1:]) - except Exception, e: - log.critical(e) + + if os.environ.get('cp_main', 'false') == 'true': + try: + cli.cmd_couchpotato(options, base_path, sys.argv[1:]) + except Exception, e: + log.critical(e) + else: + while 1: + restart = start() + if not restart: + break + + sys.exit() diff --git a/couchpotato/cli.py b/couchpotato/cli.py index 2e0552c8..9111667c 100644 --- a/couchpotato/cli.py +++ b/couchpotato/cli.py @@ -9,9 +9,7 @@ import logging import os.path import sys - -def cmd_couchpotato(base_path, args): - '''Commandline entry point.''' +def getOptions(base_path, args): # Options parser = ArgumentParser(prog = 'CouchPotato.py') @@ -28,10 +26,16 @@ def cmd_couchpotato(base_path, args): options = parser.parse_args(args) + options.data_dir = os.path.expanduser(options.data_dir) + + return options + + +def cmd_couchpotato(options, base_path, args): + '''Commandline entry point.''' # Create data dir if needed if not os.path.isdir(options.data_dir): - options.data_dir = os.path.expanduser(options.data_dir) os.makedirs(options.data_dir) # Create logging dir @@ -91,35 +95,36 @@ def cmd_couchpotato(base_path, args): log.debug('Started with options %s' % options) - # Load configs & plugins - loader = Env.get('loader') - loader.preload(root = base_path) - loader.run() + # Load configs & plugins (only run once when debugging) + if os.environ.get('WERKZEUG_RUN_MAIN') or not debug: + loader = Env.get('loader') + loader.preload(root = base_path) + loader.run() - # Load migrations - from migrate.versioning.api import version_control, db_version, version, upgrade - db = Env.get('db_path') - repo = os.path.join(base_path, 'couchpotato', 'core', 'migration') - logging.getLogger('migrate').setLevel(logging.WARNING) # Disable logging for migration + # Load migrations + from migrate.versioning.api import version_control, db_version, version, upgrade + db = Env.get('db_path') + repo = os.path.join(base_path, 'couchpotato', 'core', 'migration') + logging.getLogger('migrate').setLevel(logging.WARNING) # Disable logging for migration - latest_db_version = version(repo) + latest_db_version = version(repo) - try: - current_db_version = db_version(db, repo) - except: - version_control(db, repo, version = latest_db_version) - current_db_version = db_version(db, repo) + try: + current_db_version = db_version(db, repo) + except: + version_control(db, repo, version = latest_db_version) + current_db_version = db_version(db, repo) - if current_db_version < latest_db_version and not debug: - log.info('Doing database upgrade. From %d to %d' % (current_db_version, latest_db_version)) - upgrade(db, repo) + if current_db_version < latest_db_version and not debug: + log.info('Doing database upgrade. From %d to %d' % (current_db_version, latest_db_version)) + upgrade(db, repo) - # Configure Database - from couchpotato.core.settings.model import setup - setup() + # Configure Database + from couchpotato.core.settings.model import setup + setup() - fireEventAsync('app.load') + fireEventAsync('app.load') # Create app from couchpotato import app diff --git a/couchpotato/core/_base/_core/__init__.py b/couchpotato/core/_base/_core/__init__.py index 87cd5afc..3e2f0710 100644 --- a/couchpotato/core/_base/_core/__init__.py +++ b/couchpotato/core/_base/_core/__init__.py @@ -1,7 +1,8 @@ +from .main import Core from uuid import uuid4 def start(): - pass + return Core() config = [{ 'name': 'core', diff --git a/couchpotato/core/_base/_core/main.py b/couchpotato/core/_base/_core/main.py new file mode 100644 index 00000000..24746853 --- /dev/null +++ b/couchpotato/core/_base/_core/main.py @@ -0,0 +1,54 @@ +from couchpotato.api import addApiView +from couchpotato.core.event import fireEvent +from couchpotato.core.logger import CPLog +from couchpotato.core.plugins.base import Plugin +from couchpotato.environment import Env +from flask import request +import os + + +log = CPLog(__name__) + +class Core(Plugin): + + def __init__(self): + addApiView('app.shutdown', self.shutdown) + addApiView('app.restart', self.restart) + + self.removeRestartFile() + + def shutdown(self): + self.initShutdown() + return 'shutdown' + + def restart(self): + self.initShutdown(restart = True) + return 'restarting' + + def initShutdown(self, restart = False): + + fireEvent('app.shutdown') + + if restart: + self.writeRestartFile() + + func = request.environ.get('werkzeug.server.shutdown') + if func is None: + raise RuntimeError('Not running with the Werkzeug Server') + func() + + def removeRestartFile(self): + try: + os.remove(self.restartFilePath()) + except: + pass + + def writeRestartFile(self): + try: + with open(self.restartFilePath(), 'w') as f: + f.write('This is the most suckiest way to register if CP is restarted. Ever...') + except Exception, e: + log.error('Could not write shutdown file: %s' % e) + + def restartFilePath(self): + return os.path.join(Env.get('data_dir'), 'restart') diff --git a/couchpotato/core/_base/scheduler/main.py b/couchpotato/core/_base/scheduler/main.py index 31aa123a..c425a510 100644 --- a/couchpotato/core/_base/scheduler/main.py +++ b/couchpotato/core/_base/scheduler/main.py @@ -20,6 +20,7 @@ class Scheduler(Plugin): addEvent('schedule.restart', self.start) addEvent('app.load', self.start) + addEvent('app.shutdown', self.stop) self.sched = Sched(misfire_grace_time = 60) diff --git a/couchpotato/core/loader.py b/couchpotato/core/loader.py index 11ce931c..8105a956 100644 --- a/couchpotato/core/loader.py +++ b/couchpotato/core/loader.py @@ -81,6 +81,7 @@ class Loader: def loadPlugins(self, module, name): try: klass = module.start() + klass.registerPlugin() if klass and getattr(klass, 'auto_register_static'): klass.registerStatic(module.__file__) diff --git a/couchpotato/core/plugins/base.py b/couchpotato/core/plugins/base.py index 6ba27446..6c2321e6 100644 --- a/couchpotato/core/plugins/base.py +++ b/couchpotato/core/plugins/base.py @@ -1,5 +1,5 @@ from couchpotato import addView -from couchpotato.core.event import fireEvent +from couchpotato.core.event import fireEvent, addEvent from couchpotato.core.helpers.variable import getExt from couchpotato.core.logger import CPLog from couchpotato.environment import Env @@ -16,6 +16,11 @@ class Plugin(object): enabled_option = 'enabled' auto_register_static = True + needs_shutdown = False + + def registerPlugin(self): + addEvent('app.shutdown', self.doShutdown) + def conf(self, attr, default = None): return Env.setting(attr, self.getName().lower(), default = default) @@ -60,6 +65,16 @@ class Plugin(object): except Exception, e: log.error('Unable to create folder "%s": %s' % (path, e)) + + def doShutdown(self): + self.shuttingDown(True) + + def shuttingDown(self, value = None): + if value is None: + return self.needs_shutdown + + self.needs_shutdown = value + def isDisabled(self): return not self.isEnabled()