-
Notifications
You must be signed in to change notification settings - Fork 0
/
cli.py
157 lines (125 loc) · 5.33 KB
/
cli.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
#!/usr/bin/env python
"""Command-line interface."""
import sys
import argparse
from . import CLI, VERSION, DESCRIPTION
from . import common
from .data import Data
from .services import get_path
from .manager import get_manager
import yorm
log = common.logger(__name__)
def main(args=None):
"""Process command-line arguments and run the program."""
# Shared options
debug = argparse.ArgumentParser(add_help=False)
debug.add_argument('-V', '--version', action='version', version=VERSION)
group = debug.add_mutually_exclusive_group()
group.add_argument('-v', '--verbose', action='count', default=0,
help="enable verbose logging")
group.add_argument('-q', '--quiet', action='store_const', const=-1,
dest='verbose', help="only display errors and prompts")
shared = {'formatter_class': common.HelpFormatter,
'parents': [debug]}
# Build main parser
parser = argparse.ArgumentParser(prog=CLI, description=DESCRIPTION,
**shared)
parser.add_argument('-f', '--file', help="custom settings file path")
# Parse arguments
args = parser.parse_args(args=args)
# Configure logging
common.configure_logging(args.verbose)
# Run the program
try:
log.debug("running main command...")
success = run(path=args.file)
except KeyboardInterrupt:
msg = "command cancelled"
if common.verbosity == common.MAX_VERBOSITY:
log.exception(msg)
else:
log.debug(msg)
success = False
if success:
log.debug("command succeeded")
else:
log.debug("command failed")
sys.exit(1)
def run(path=None):
"""Run the program."""
manager = get_manager()
path = path or get_path()
# TODO: convert to `yorm.load()` when available
data = Data()
yorm.store(data, path)
config = data.config
status = data.status
log.info("identifying current computer...")
computer = config.computers.get_current()
log.info("current computer: %s", computer)
# TODO: remove this fix when YORM stops overwriting attributes: https://github.com/jacebrowning/yorm/issues/47
data.config = config
launch_next(config, status, computer, manager)
update_status(config, status, computer, manager)
# TODO: remove this fix when YORM stores on nested attributes: https://github.com/jacebrowning/yorm/issues/42
data.yorm_mapper.store(data) # pylint: disable=E1101
return True
# TODO: consider moving this logic to `data`
def launch_next(config, status, computer, manager):
"""Launch applications that have been queued."""
log.info("launching queued applications...")
for app_status in status.applications:
if app_status.next:
application = config.applications.get(app_status.application)
log.info("%s queued for: %s", application, app_status.next)
if app_status.next == computer:
latest = status.get_latest(application)
if latest in (computer, None):
if not manager.is_running(application):
manager.start(application)
app_status.next = None
else:
log.info("%s still running on: %s", application, latest)
elif manager.is_running(application):
manager.stop(application)
# TODO: consider moving this logic to `data`
def update_status(config, status, computer, manager):
"""Update and store each application's status."""
log.info("recording application status...")
for application in config.applications:
if manager.is_running(application):
latest = status.get_latest(application)
if computer != latest:
if status.is_running(application, computer):
# case 1: application just launched remotely
log.info("%s launched on: %s", application, latest)
manager.stop(application)
status.stop(application, computer)
show_running(application, latest)
show_stopped(application, computer)
else:
# case 2: application just launched locally
status.start(application, computer)
show_running(application, computer)
else:
# case 3: application already running locally
pass
else:
if status.is_running(application, computer):
# case 4: application just closed locally
status.stop(application, computer)
show_stopped(application, computer)
else:
# case 5: application already closed locally
pass
def show_running(application, computer):
"""Display the new state of a running application."""
print("{} is now running on {}".format(application, computer))
def show_started(application, computer):
"""Display the new state of a started application."""
print("{} is now started on {}".format(application, computer))
def show_stopped(application, computer):
"""Display the new state of a stopped application."""
print("{} is now stopped on {}".format(application, computer))
if __name__ == '__main__': # pragma: no cover (manual test)
main()