-
Notifications
You must be signed in to change notification settings - Fork 40
/
__init__.py
206 lines (169 loc) · 7.8 KB
/
__init__.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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
# -*- encoding: utf-8 -*-
#
# Copyright 2012 Martin Zimmermann <info@posativ.org>. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# The views and conclusions contained in the software and documentation are
# those of the authors and should not be interpreted as representing official
# policies, either expressed or implied, of Martin Zimmermann <info@posativ.org>.
import pkg_resources
dist = pkg_resources.get_distribution("acrylamid")
__author__ = 'Martin Zimmermann <info@posativ.org>'
__url__ = 'https://github.com/posativ/acrylamid/'
import sys
import os
import time
import argparse
import traceback
import signal
from os.path import dirname
from functools import partial
from acrylamid import log, commands, colors, tasks, core
from acrylamid.utils import Struct
from acrylamid.errors import AcrylamidException
signal.signal(signal.SIGINT, signal.SIG_DFL)
sys.path.append(dirname(__file__))
class AcrylFormatter(argparse.HelpFormatter):
"""Remove {a,b,c,d,e,...} subcommand listing from help."""
def _metavar_formatter(self, action, default_metavar):
if action.metavar is not None:
result = action.metavar
elif action.choices is not None:
result = ''
else:
result = default_metavar
def format(tuple_size):
if isinstance(result, tuple):
return result
else:
return (result, ) * tuple_size
return format
def Acryl():
"""The main function that dispatches the CLI. We use :class:`AcrylFormatter`
as custom help formatter that ommits the useless list of available subcommands
and their aliases.
All flags from acrylamid --help are also available in subcommands altough not
explicitely printed in their help."""
parser = argparse.ArgumentParser(
parents=[], formatter_class=AcrylFormatter
)
parser.add_argument("-v", "--verbose", action="store_const", dest="verbosity",
help="more verbose", const=log.SKIP, default=log.INFO)
parser.add_argument("-q", "--quiet", action="store_const", dest="verbosity",
help="less verbose", const=log.WARN)
parser.add_argument("-C", "--no-color", action="store_false", dest="colors",
help="disable color", default=True)
parser.add_argument("--conf", dest="conf", help="alternate conf.py",
default="conf.py", metavar="/path/to/conf")
parser.add_argument("--version", action="version",
version=colors.blue('Acrylamid ') + dist.version)
subparsers = parser.add_subparsers(dest="parser")
# a repeat yourself of default arguments but not visible on subcommand --help
default = argparse.ArgumentParser(add_help=False)
default.add_argument("-v", "--verbose", action="store_const", dest="verbosity",
help=argparse.SUPPRESS, const=log.SKIP, default=log.INFO)
default.add_argument("-q", "--quiet", action="store_const", dest="verbosity",
help=argparse.SUPPRESS, const=log.WARN)
default.add_argument("-C", "--no-color", action="store_false", dest="colors",
help=argparse.SUPPRESS, default=True)
# --- gen params --- #
generate = subparsers.add_parser('compile', help='compile blog', parents=[default])
generate.add_argument("-f", "--force", action="store_true", dest="force",
help="clear cache before compilation", default=False)
generate.add_argument("-n", "--dry-run", dest="dryrun", action='store_true',
help="show what would have been compiled", default=False)
generate.add_argument("--ignore", dest="ignore", action="store_true",
help="ignore critical errors", default=False)
generate.add_argument("--search", dest="search", action="store_true",
help="build search index", default=False)
# --- webserver params --- #
view = subparsers.add_parser('view', help="fire up built-in webserver", parents=[default])
view.add_argument("-p", "--port", dest="port", type=int, default=8000,
help="webserver port")
# --- aco params --- #
autocompile = subparsers.add_parser('autocompile', help="automatic compilation and serving",
parents=[default])
autocompile.add_argument("-f", "--force", action="store_true", dest="force",
help="clear cache before compilation", default=False)
autocompile.add_argument("-n", "--dry-run", dest="dryrun", action='store_true',
help="show what would have been compiled", default=False)
autocompile.add_argument("--ignore", dest="ignore", action="store_true",
help="ignore critical errors", default=False)
autocompile.add_argument("--search", dest="search", action="store_true",
help="build search index", default=False)
autocompile.add_argument("-p", "--port", dest="port", type=int, default=8000,
help="webserver port")
for alias in ('co', 'gen', 'generate'):
subparsers._name_parser_map[alias] = generate
for alias in ('serve', 'srv'):
subparsers._name_parser_map[alias] = view
subparsers._name_parser_map['aco'] = autocompile
# temporary log to catch issues during task initialization
log.init('temporary', level=log.WARN, colors=False)
# initialize other tasks
tasks.initialize(subparsers, default)
# parse args
options = parser.parse_args()
# initialize colored logger
log.init('acrylamid', level=options.verbosity, colors=options.colors)
env = core.Environment({'author': __author__, 'url': __url__,
'options': options, 'globals': Struct()})
try:
conf = core.load(options.conf)
except IOError:
log.critical('no conf.py found. Are you inside your blog?')
sys.exit(1)
except Exception as e:
log.critical("%s in `conf.py`" % e.__class__.__name__)
traceback.print_exc(file=sys.stdout)
sys.exit(1)
# -- run -- #
if options.parser in ('gen', 'generate', 'co', 'compile'):
log.setLevel(options.verbosity)
try:
commands.compile(conf, env)
except AcrylamidException as e:
log.exception(e.args[0])
sys.exit(1)
elif options.parser in ('srv', 'serve', 'view'):
from acrylamid.lib.httpd import Webserver
ws = partial(Webserver, options.port, conf['output_dir'])
ws = ws(log.info) if options.verbosity < 20 else ws(); ws.start()
log.info(' * Running on http://127.0.0.1:%i/' % options.port)
try:
while True:
time.sleep(1)
except (SystemExit, KeyboardInterrupt) as e:
ws.kill_received = True
sys.exit(0)
elif options.parser in ('aco', 'autocompile'):
from acrylamid.lib.httpd import Webserver
# XXX compile on request _or_ use inotify/fsevent
ws = Webserver(options.port, conf['output_dir']); ws.start()
log.info(' * Running on http://127.0.0.1:%i/' % options.port)
try:
commands.autocompile(ws, conf, env)
except (SystemExit, KeyboardInterrupt) as e:
ws.kill_received = True
log.error(e.args[0])
traceback.print_exc(file=sys.stdout)
sys.exit(0)
elif options.parser in tasks.collected:
try:
tasks.collected[options.parser](conf, env, options)
except AcrylamidException as e:
log.exception('uncaught exception')
sys.exit(1)
else:
log.critical('No such command!')
sys.exit(2)
sys.exit(0)