Issues (158)

doorpi/main.py (1 issue)

1
#!/usr/bin/python
2
# -*- coding: utf-8 -*-
3
4
import argparse
5
import sys
6
import logging
7
import logging.handlers
8
import os
9
import metadata
10
import doorpi
11
from resource import getrlimit, RLIMIT_NOFILE
12
13
TRACE_LEVEL = 5
14
LOG_FORMAT = '%(asctime)s [%(levelname)s]  \t[%(name)s] %(message)s'
15
16
logger = logging.getLogger(__name__)
17
18
log_level = logging.INFO
19
20
21
def add_trace_level():
22
    logging.addLevelName(TRACE_LEVEL, "TRACE")
23
    def trace(self, message, *args, **kws):
24
        # Yes, logger takes its '*args' as 'args'.
25
        self._log(TRACE_LEVEL, message, args, **kws)
26
    logging.Logger.trace = trace
27
28
29
def init_logger(arguments):
30
    add_trace_level()
31
32
    global log_level
33
    if '--debug' in arguments: log_level = logging.DEBUG
34
    if '--trace' in arguments: log_level = TRACE_LEVEL
35
36
    logging.basicConfig(
37
        level = log_level,
38
        format = LOG_FORMAT
39
    #    datefmt = '%m/%d/%Y %I:%M:%S %p'
40
    )
41
42
    return logging.getLogger(__name__)
43
44
45
def parse_arguments(argv):
46
    arg_parser = argparse.ArgumentParser(
47
        prog=argv[0],
48
        formatter_class=argparse.RawDescriptionHelpFormatter,
49
        description=metadata.description,
50
        epilog = metadata.epilog
51
    )
52
53
    arg_parser.add_argument(
54
        '-V', '--version',
55
        action='version',
56
        version='{0} {1}'.format(metadata.project, metadata.version)
57
    )
58
    arg_parser.add_argument('--debug', action="store_true")
59
    arg_parser.add_argument('--trace', action="store_true")
60
    arg_parser.add_argument('--test', action="store_true")
61
    arg_parser.add_argument(
62
        '-c', '--configfile',
63
        help='configfile for DoorPi - https://github.com/motom001/DoorPi/wiki for more help',
64
        dest='configfile'
65
    )
66
    try:
67
        if len(sys.argv) > 1 and sys.argv[1] in ['start', 'stop', 'restart', 'status']:
68
            return arg_parser.parse_args(args=sys.argv[2:])
69
        else:
70
            return arg_parser.parse_args(args=sys.argv[1:])
71
    except IOError:
72
        print("EXCEPTION: configfile does not exist or is not readable")
73
        print("please refer to the DoorPi wiki for more information ")
74
        print("<https://github.com/motom001/DoorPi/wiki>")
75
        raise SystemExit(1)
76
77
78
def files_preserve_by_path(*paths):
79
    wanted = []
80
    for path in paths:
81
        fd = os.open(path, os.O_RDONLY)
82
        try:
83
            wanted.append(os.fstat(fd)[1:3])
84
        finally:
85
            os.close(fd)
86
87
    def fd_wanted(fd):
88
        try:
89
            return os.fstat(fd)[1:3] in wanted
90
        except OSError:
91
            return False
92
93
    fd_max = getrlimit(RLIMIT_NOFILE)[1]
94
    return [fd for fd in xrange(fd_max) if fd_wanted(fd)]
95
96
97
def main_as_daemon(argv):
98
    if argv[1] is 'reload':
99
        print('not implemeted yet - use restart instead')
100
        return 1
101
    if argv[1] in ['stop']:
102
        parsed_arguments = None
103
    else:
104
        parsed_arguments = parse_arguments(argv)
105
106
    if not os.path.exists(metadata.log_folder):
107
        os.makedirs(metadata.log_folder)
108
109
    log_file = os.path.join(metadata.log_folder, "doorpi.log")
110
    logrotating = logging.handlers.RotatingFileHandler(
111
          log_file,
112
          maxBytes=5000000,
113
          backupCount=10
114
    )
115
    global log_level
0 ignored issues
show
The variable log_level was imported from global scope, but was never written to.
Loading history...
116
    logrotating.setLevel(log_level)
117
    logrotating.setFormatter(logging.Formatter(LOG_FORMAT))
118
119
    logging.getLogger('').addHandler(logrotating)
120
121
    print(metadata.epilog)
122
123
    from daemon import runner
124
    from daemon.runner import DaemonRunnerInvalidActionError
125
    from daemon.runner import DaemonRunnerStartFailureError
126
    from daemon.runner import DaemonRunnerStopFailureError
127
128
    daemon_runner = runner.DaemonRunner(doorpi.DoorPi(parsed_arguments))
129
    #This ensures that the logger file handle does not get closed during daemonization
130
    daemon_runner.daemon_context.files_preserve = files_preserve_by_path(log_file)
131
    try:
132
        daemon_runner.do_action()
133
    except DaemonRunnerStopFailureError as ex:
134
        print("can't stop DoorPi daemon - maybe it's not running? (Message: %s)" % ex)
135
        return 1
136
    except DaemonRunnerStartFailureError as ex:
137
        print("can't start DoorPi daemon - maybe it's running already? (Message: %s)" % ex)
138
        return 1
139
    except Exception as ex:
140
        print("Exception NameError: %s" % ex)
141
    finally:
142
        doorpi.DoorPi().destroy()
143
    return 0
144
145
146
def main_as_application(argv):
147
148
    parsed_arguments = parse_arguments(argv)
149
    logger.info(metadata.epilog)
150
    logger.debug('loaded with arguments: %s', str(argv))
151
152
    try:                        doorpi.DoorPi(parsed_arguments).run()
153
    except KeyboardInterrupt:   logger.info("KeyboardInterrupt -> DoorPi will shutdown")
154
    except Exception as ex:     logger.exception("Exception NameError: %s", ex)
155
    finally:                    doorpi.DoorPi().destroy()
156
157
    return 0
158
159
160
def entry_point():
161
    init_logger(sys.argv)
162
163
    """Zero-argument entry point for use with setuptools/distribute."""
164
    if len(sys.argv) > 1 and sys.argv[1] in ['status']:
165
        raise SystemExit(get_status_from_doorpi(sys.argv))
166
    elif len(sys.argv) > 1 and sys.argv[1] in ['start', 'stop', 'restart', 'reload']:
167
        raise SystemExit(main_as_daemon(sys.argv))
168
    else:
169
        raise SystemExit(main_as_application(sys.argv))
170
171
if __name__ == '__main__':
172
    entry_point()
173