This repository has been archived by the owner on May 19, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathdevserver
executable file
·180 lines (149 loc) · 6.72 KB
/
devserver
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
#!/usr/bin/env python3
# Development Server for nCoda
#
# This script can concurrently run the following services:
# - lessc (compiles LESS to CSS)
# - watchify (compiles ES6 and JSX to ES5 JavaScript)
# - Electron (the user agent shell for nCoda)
# - HTTPServer (Python's built-in HTTP server)
#
# The script checks whether Electron is installed, and will prefer to open it instead of starting
# an HTTPServer. If Electron is not installed, the HTTPServer will be started.
# Script to concurrently run "watchify" and the SimpleHTTPServer module.
from http import server
import pathlib
import subprocess
import time
_HTTP_PORT = 8000
# list of the JS files that must be compiled with Watchify; it's input filename, then output filename
_COMPILE_WITH_WATCHIFY = [
('js/ncoda-init.js', 'js/ncoda-compiled.js'),
]
# list of the CSS files that must be compiled from LESS; it's the shell path we should ask Watchman
# to watch, then the input and output filenames for lessc.
_COMPILE_WITH_LESSC = [
('css/ncoda/*.less', 'css/ncoda/main.less', 'css/ncoda/main.css'),
]
_PATH_TO_WATCHIFY = 'node_modules/.bin/watchify'
_PATH_TO_LESSC = 'node_modules/.bin/lessc'
_PATH_TO_ELECTRON = 'node_modules/.bin/electron'
# see whether "watchman" is installed
try:
_PATH_TO_WATCHMAN = subprocess.check_output(['which', 'watchman-make'])
_PATH_TO_WATCHMAN = str(_PATH_TO_WATCHMAN, encoding='utf-8').strip()
except subprocess.CalledProcessError:
_PATH_TO_WATCHMAN = None
def run_http_server():
print('Starting the HTTPServer on http://localhost:{}'.format(_HTTP_PORT))
server_address = ('', _HTTP_PORT)
httpd = server.HTTPServer(server_address, server.SimpleHTTPRequestHandler)
httpd.serve_forever()
def wait_for_existence(files):
'''
Given a list with filenames, don't return until all those files exist.
'''
print('Waiting for the JavaScript assets to compile.\n' +
'... (Electron or the HTTP server will start automatically)...'
)
files = [pathlib.Path(x) for x in files]
compiled = [False for _ in range(len(files))]
while not all(compiled):
time.sleep(0.25)
for i, path in enumerate(files):
if not compiled[i]:
if path.exists():
compiled[i] = True
def the_script():
# see if we can find/use watchify
watchify = pathlib.Path(_PATH_TO_WATCHIFY)
if not watchify.exists():
print('Could not find Watchify. Is it installed?')
raise SystemExit(1)
del watchify # because this will be a long-running script
# see if we can find/use lessc
lessc = pathlib.Path(_PATH_TO_LESSC)
if not lessc.exists():
print('Could not find lessc. Is it installed?')
raise SystemExit(1)
del lessc # because this will be a long-running script
# see if electron is installed
we_have_electron = True
electron = pathlib.Path(_PATH_TO_ELECTRON)
if not electron.exists():
we_have_electron = False
print('\n!! NOTICE: "electron" not found, so you will have to run nCoda in your browser !!\n')
del electron # because this will be a long-running script
# remove existing Watchify-compiled files (when they exist again, we'll know they're current)
for each_file in _COMPILE_WITH_WATCHIFY:
compiled = pathlib.Path(each_file[1])
if compiled.exists():
compiled.unlink()
# hold the Popen instances
subprocesses = []
try:
# set up some Watchify instances
for each_file in _COMPILE_WITH_WATCHIFY:
print('Starting Watchify for {}'.format(each_file[0]))
try:
kummand = [_PATH_TO_WATCHIFY, each_file[0], '-o', each_file[1], '--debug', '--ignore-missing']
subprocesses.append(subprocess.Popen(kummand))
except subprocess.CalledProcessError as cperr:
print('Encountered the following error while starting Watchify:\n{}'.format(cperr))
raise SystemExit(1)
# Compile LESS files to CSS
# first compile the files initially
for each_file in _COMPILE_WITH_LESSC:
try:
kummand = [_PATH_TO_LESSC, '--clean-css', '--source-map', each_file[1], each_file[2]]
subprocess.check_output(kummand)
except subprocess.CalledProcessError as cperr:
print('Encountered the following error while starting lessc:\n{}'.format(cperr))
raise SystemExit(1)
# now, if we can, start Watchman too
if _PATH_TO_WATCHMAN:
# the command will look something like this (note the single quotes! And how they're
# missing in what we submit below!):
# watchman-make --make path_to_lessc -p 'path_to_watch' -t '--clean-css compile_this compiled_path'
#
print('Starting Watchman for automatic LESS compilation.')
kummand = ['watchman-make', '--make', '{}'.format(_PATH_TO_LESSC)]
for each_file in _COMPILE_WITH_LESSC:
kummand.append('-p')
kummand.append('{}'.format(each_file[0]))
kummand.append('-t')
kummand.append("--clean-css --source-map {0} {1}".format(each_file[1], each_file[2]))
try:
subprocesses.append(subprocess.Popen(kummand))
except subprocess.CalledProcessError as cperr:
print('Encountered the following error while starting Watchman:\n{}'.format(cperr))
raise SystemExit(1)
# wait for the compiled JavaScript files to appear
wait_for_existence([x[1] for x in _COMPILE_WITH_WATCHIFY])
# see whether any of the subprocesses have crashed
for proc in subprocesses:
proc.poll()
if proc.returncode is not None:
print('\nERROR: One of the processes had a problem; devserver quitting!')
raise SystemExit(1)
# we'll catch KeyboardInterrupt so we can try killing babel on the way out
try:
if we_have_electron:
print('Starting Electron')
subprocess.call([_PATH_TO_ELECTRON, '.'])
else:
# no Electron---use HTTPServer
run_http_server()
except KeyboardInterrupt:
print('')
finally:
for each_instance in subprocesses:
try:
each_instance.terminate()
print('Terminated subprocess with PID {}'.format(each_instance.pid))
each_instance.wait(timeout=30)
except ProcessLookupError:
print('Subprocess with PID {} had already terminated.'.format(each_instance.pid))
if '__main__' == __name__:
the_script()
else:
print('This script is only intended to be run from a commandline.')