OLD | NEW |
| (Empty) |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 library pub.command.serve; | |
6 | |
7 import 'dart:async'; | |
8 import 'dart:math' as math; | |
9 | |
10 import 'package:barback/barback.dart'; | |
11 | |
12 import '../barback/asset_environment.dart'; | |
13 import '../barback/pub_package_provider.dart'; | |
14 import '../log.dart' as log; | |
15 import '../utils.dart'; | |
16 import 'barback.dart'; | |
17 | |
18 final _arrow = getSpecial('\u2192', '=>'); | |
19 | |
20 /// Handles the `serve` pub command. | |
21 class ServeCommand extends BarbackCommand { | |
22 String get name => "serve"; | |
23 String get description => | |
24 'Run a local web development server.\n\n' | |
25 'By default, this serves "web/" and "test/", but an explicit list of \
n' | |
26 'directories to serve can be provided as well.'; | |
27 String get invocation => "pub serve [directories...]"; | |
28 String get docUrl => "http://dartlang.org/tools/pub/cmd/pub-serve.html"; | |
29 | |
30 PubPackageProvider _provider; | |
31 | |
32 String get hostname => argResults['hostname']; | |
33 | |
34 /// The base port for the servers. | |
35 /// | |
36 /// This will print a usage error and exit if the specified port is invalid. | |
37 int get port => parseInt(argResults['port'], 'port'); | |
38 | |
39 /// The port for the admin UI. | |
40 /// | |
41 /// This will print a usage error and exit if the specified port is invalid. | |
42 int get adminPort { | |
43 var adminPort = argResults['admin-port']; | |
44 return adminPort == null ? null : parseInt(adminPort, 'admin port'); | |
45 } | |
46 | |
47 /// `true` if Dart entrypoints should be compiled to JavaScript. | |
48 bool get useDart2JS => argResults['dart2js']; | |
49 | |
50 /// `true` if the admin server URL should be displayed on startup. | |
51 bool get logAdminUrl => argResults['log-admin-url']; | |
52 | |
53 BarbackMode get defaultMode => BarbackMode.DEBUG; | |
54 | |
55 List<String> get defaultSourceDirectories => ["web", "test"]; | |
56 | |
57 /// This completer is used to keep pub running (by not completing) and to | |
58 /// pipe fatal errors to pub's top-level error-handling machinery. | |
59 final _completer = new Completer(); | |
60 | |
61 ServeCommand() { | |
62 argParser.addOption( | |
63 'hostname', | |
64 defaultsTo: 'localhost', | |
65 help: 'The hostname to listen on.'); | |
66 argParser.addOption( | |
67 'port', | |
68 defaultsTo: '8080', | |
69 help: 'The base port to listen on.'); | |
70 | |
71 // TODO(rnystrom): A hidden option to print the URL that the admin server | |
72 // is bound to on startup. Since this is currently only used for the Web | |
73 // Socket interface, we don't want to show it to users, but the tests and | |
74 // Editor need this logged to know what port to bind to. | |
75 // Remove this (and always log) when #16954 is fixed. | |
76 argParser.addFlag('log-admin-url', defaultsTo: false, hide: true); | |
77 | |
78 // TODO(nweiz): Make this public when issue 16954 is fixed. | |
79 argParser.addOption('admin-port', hide: true); | |
80 | |
81 argParser.addFlag( | |
82 'dart2js', | |
83 defaultsTo: true, | |
84 help: 'Compile Dart to JavaScript.'); | |
85 argParser.addFlag( | |
86 'force-poll', | |
87 defaultsTo: false, | |
88 help: 'Force the use of a polling filesystem watcher.'); | |
89 } | |
90 | |
91 Future onRunTransformerCommand() { | |
92 final completer0 = new Completer(); | |
93 scheduleMicrotask(() { | |
94 try { | |
95 var port = parseInt(argResults['port'], 'port'); | |
96 join0(x0) { | |
97 var adminPort = x0; | |
98 join1(x1) { | |
99 var watcherType = x1; | |
100 new Future.value( | |
101 AssetEnvironment.create( | |
102 entrypoint, | |
103 mode, | |
104 watcherType: watcherType, | |
105 hostname: hostname, | |
106 basePort: port, | |
107 useDart2JS: useDart2JS)).then((x2) { | |
108 try { | |
109 var environment = x2; | |
110 var directoryLength = sourceDirectories.map(((dir) { | |
111 return dir.length; | |
112 })).reduce(math.max); | |
113 new Future.value( | |
114 environment.startAdminServer(adminPort)).then((x3) { | |
115 try { | |
116 var server = x3; | |
117 server.results.listen(((_) { | |
118 assert(false); | |
119 }), onError: _fatalError); | |
120 join2() { | |
121 environment.pauseUpdates(); | |
122 var it0 = sourceDirectories.iterator; | |
123 break0() { | |
124 environment.barback.errors.listen(((error) { | |
125 log.error(log.red("Build error:\n$error")); | |
126 })); | |
127 environment.barback.results.listen(((result) { | |
128 if (result.succeeded) { | |
129 log.message( | |
130 "Build completed ${log.green('successfully')}"); | |
131 } else { | |
132 log.message( | |
133 "Build completed with " "${log.red(result.errors
.length)} errors."); | |
134 } | |
135 }), onError: _fatalError); | |
136 environment.resumeUpdates(); | |
137 new Future.value(_completer.future).then((x4) { | |
138 try { | |
139 x4; | |
140 completer0.complete(); | |
141 } catch (e0, s0) { | |
142 completer0.completeError(e0, s0); | |
143 } | |
144 }, onError: completer0.completeError); | |
145 } | |
146 var trampoline0; | |
147 continue0() { | |
148 trampoline0 = null; | |
149 if (it0.moveNext()) { | |
150 var directory = it0.current; | |
151 new Future.value( | |
152 _startServer(environment, directory, directoryLeng
th)).then((x5) { | |
153 trampoline0 = () { | |
154 trampoline0 = null; | |
155 try { | |
156 x5; | |
157 trampoline0 = continue0; | |
158 do trampoline0(); while (trampoline0 != null); | |
159 } catch (e1, s1) { | |
160 completer0.completeError(e1, s1); | |
161 } | |
162 }; | |
163 do trampoline0(); while (trampoline0 != null); | |
164 }, onError: completer0.completeError); | |
165 } else { | |
166 break0(); | |
167 } | |
168 } | |
169 trampoline0 = continue0; | |
170 do trampoline0(); while (trampoline0 != null); | |
171 } | |
172 if (logAdminUrl) { | |
173 log.message( | |
174 "Running admin server on " "${log.bold('http://${hostn
ame}:${server.port}')}"); | |
175 join2(); | |
176 } else { | |
177 join2(); | |
178 } | |
179 } catch (e2, s2) { | |
180 completer0.completeError(e2, s2); | |
181 } | |
182 }, onError: completer0.completeError); | |
183 } catch (e3, s3) { | |
184 completer0.completeError(e3, s3); | |
185 } | |
186 }, onError: completer0.completeError); | |
187 } | |
188 if (argResults['force-poll']) { | |
189 join1(WatcherType.POLLING); | |
190 } else { | |
191 join1(WatcherType.AUTO); | |
192 } | |
193 } | |
194 if (argResults['admin-port'] == null) { | |
195 join0(null); | |
196 } else { | |
197 join0(parseInt(argResults['admin-port'], 'admin port')); | |
198 } | |
199 } catch (e, s) { | |
200 completer0.completeError(e, s); | |
201 } | |
202 }); | |
203 return completer0.future; | |
204 } | |
205 | |
206 Future _startServer(AssetEnvironment environment, String rootDirectory, | |
207 int directoryLength) { | |
208 final completer0 = new Completer(); | |
209 scheduleMicrotask(() { | |
210 try { | |
211 new Future.value(environment.serveDirectory(rootDirectory)).then((x0) { | |
212 try { | |
213 var server = x0; | |
214 join0() { | |
215 var prefix = | |
216 log.gray(padRight("[${server.rootDirectory}]", directoryLength
+ 2)); | |
217 server.results.listen(((result) { | |
218 var buffer = new StringBuffer(); | |
219 buffer.write("$prefix "); | |
220 if (result.isSuccess) { | |
221 buffer.write( | |
222 "${log.green('GET')} ${result.url.path} $_arrow ${result.i
d}"); | |
223 } else { | |
224 buffer.write("${log.red('GET')} ${result.url.path} $_arrow"); | |
225 var error = result.error.toString(); | |
226 if (error.contains("\n")) { | |
227 buffer.write("\n${prefixLines(error)}"); | |
228 } else { | |
229 buffer.write(" $error"); | |
230 } | |
231 } | |
232 log.message(buffer); | |
233 }), onError: _fatalError); | |
234 log.message( | |
235 "Serving ${entrypoint.root.name} " | |
236 "${padRight(server.rootDirectory, directoryLength)} " | |
237 "on ${log.bold('http://${hostname}:${server.port}')}"); | |
238 completer0.complete(); | |
239 } | |
240 if (mode == BarbackMode.RELEASE) { | |
241 server.allowAsset = ((url) { | |
242 return !url.path.endsWith(".dart"); | |
243 }); | |
244 join0(); | |
245 } else { | |
246 join0(); | |
247 } | |
248 } catch (e0, s0) { | |
249 completer0.completeError(e0, s0); | |
250 } | |
251 }, onError: completer0.completeError); | |
252 } catch (e, s) { | |
253 completer0.completeError(e, s); | |
254 } | |
255 }); | |
256 return completer0.future; | |
257 } | |
258 | |
259 /// Reports [error] and exits the server. | |
260 void _fatalError(error, [stackTrace]) { | |
261 if (_completer.isCompleted) return; | |
262 _completer.completeError(error, stackTrace); | |
263 } | |
264 } | |
OLD | NEW |