lliendo/Radar

View on GitHub
radar/launcher/__init__.py

Summary

Maintainability
A
0 mins
Test Coverage
# -*- coding: utf-8 -*-

"""
This file is part of Radar.

Radar is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Radar is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Lesser GNU General Public License for more details.

You should have received a copy of the Lesser GNU General Public License
along with Radar. If not, see <http://www.gnu.org/licenses/>.

Copyright 2015 Lucas Liendo.
"""


from errno import EINTR
from abc import ABCMeta
from argparse import ArgumentParser
from ..logger import RadarLogger
from ..platform_setup import Platform


class CLIError(Exception):
    pass


class RadarLauncherError(Exception):
    pass


class CLI(object):
    def __init__(self, default_main_config_path, program_name='', version=''):
        self._program_name = program_name
        self._version = version
        self._options = self._build_parser(default_main_config_path).parse_args()

    def __getattr__(self, option):
        try:
            return getattr(self._options, option)
        except AttributeError:
            raise CLIError('Error - Option: \'{:}\' does not exist.'.format(option))

    def _build_parser(self, default_main_config_path):
        parser = ArgumentParser(prog=self._program_name)
        parser.add_argument('-c', '--config', dest='main_config', action='store', default=default_main_config_path, required=False)
        parser.add_argument('-v', '--version', action='version', version=self._version)

        return parser


class RadarLauncher(object):

    __metaclass__ = ABCMeta

    PROGRAM_NAME = ''
    PROGRAM_VERSION = ''
    THREAD_POLLING_TIME = 0.2
    AVAILABLE_PLATFORMS = {}

    def __init__(self):
        cli = CLI(self._get_default_main_config_path(), program_name=self.PROGRAM_NAME, version=self.PROGRAM_VERSION)
        self._platform_setup = self._setup_platform(cli.main_config)

    def _get_default_main_config_path(self):
        return self.AVAILABLE_PLATFORMS[Platform.get_platform_type()].MAIN_CONFIG_PATH

    def _setup_platform(self, path):
        platform = Platform.get_platform_type()

        try:
            PlatformSetup = self.AVAILABLE_PLATFORMS[platform]
            platform_setup = PlatformSetup(path).configure(self).build()
        except KeyError:
            raise RadarLauncherError('Error - Platform : \'{:}\' is not available.'.format(platform))

        return platform_setup

    def _start_threads(self, threads):
        [t.start() for t in threads]

    def _join_threads(self):
        while any([t.is_alive() for t in self._threads]):
            [t.join(self.THREAD_POLLING_TIME) for t in self._threads if t.is_alive()]

    def stop(self, *args):
        [t.stop_event.set() for t in self._threads]

    # Let's try to re-join the threads one more time for graceful termination.
    def _resume_interrupted_call(self, error):
        if error.errno != EINTR:
            raise error

        self._join_threads()

    def run(self):
        try:
            RadarLogger.log('Starting {:}.'.format(self.PROGRAM_NAME))
            self._start_and_join_threads()
        except IOError as e:
            self._resume_interrupted_call(e)
        except Exception as e:
            RadarLogger.log('Error - {:} raised an error. Details : {:}.'.format(self.__class__.__name__, e))
        finally:
            RadarLogger.log('Shutting down {:}.'.format(self.PROGRAM_NAME))
            self._platform_setup.tear_down()