Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(269)

Side by Side Diff: runtime/bin/process_impl.dart

Issue 10392023: Change dart:io to use Future for one-shot operations. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Use defaults in more of File again. Created 8 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 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. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 class _ProcessStartStatus { 5 class _ProcessStartStatus {
6 int _errorCode; // Set to OS error code if process start failed. 6 int _errorCode; // Set to OS error code if process start failed.
7 String _errorMessage; // Set to OS error message if process start failed. 7 String _errorMessage; // Set to OS error message if process start failed.
8 } 8 }
9 9
10 10
11 // Abstract factory class capable of producing interactive and
12 // non-interactive processes.
13 class _Process { 11 class _Process {
14 12 static InteractiveProcess start(String path,
15 factory Process.start(String path, 13 List<String> arguments,
16 List<String> arguments, 14 [ProcessOptions options]) {
17 [ProcessOptions options]) {
18 return new _InteractiveProcess.start(path, arguments, options); 15 return new _InteractiveProcess.start(path, arguments, options);
19 } 16 }
20 17
21 factory Process.run(String path, 18 static Future<ProcessResult> run(String path,
22 List<String> arguments, 19 List<String> arguments,
23 ProcessOptions options, 20 [ProcessOptions options]) {
24 void callback(int exitCode, 21 return new _NonInteractiveProcess._start(path, arguments, options)._result;
25 String stdout,
26 String stderr)) {
27 return new _NonInteractiveProcess.start(path,
28 arguments,
29 options,
30 callback);
31 } 22 }
32 } 23 }
33 24
34 25
35 // _InteractiveProcess is the actual implementation of all processes 26 // _InteractiveProcess is the actual implementation of all processes
36 // started from Dart code. 27 // started from Dart code.
37 class _InteractiveProcess implements Process { 28 class _InteractiveProcess implements InteractiveProcess {
38 29
39 _InteractiveProcess.start(String path, 30 _InteractiveProcess.start(String path,
40 List<String> arguments, 31 List<String> arguments,
41 ProcessOptions options) { 32 ProcessOptions options) {
42 if (path is !String) { 33 if (path is !String) {
43 throw new IllegalArgumentException("Path is not a String: $path"); 34 throw new IllegalArgumentException("Path is not a String: $path");
44 } 35 }
45 _path = path; 36 _path = path;
46 37
47 if (arguments is !List) { 38 if (arguments is !List) {
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
90 _in = new _Socket._internalReadOnly(); // stdout coming from process. 81 _in = new _Socket._internalReadOnly(); // stdout coming from process.
91 _out = new _Socket._internalWriteOnly(); // stdin going to process. 82 _out = new _Socket._internalWriteOnly(); // stdin going to process.
92 _err = new _Socket._internalReadOnly(); // stderr coming from process. 83 _err = new _Socket._internalReadOnly(); // stderr coming from process.
93 _exitHandler = new _Socket._internalReadOnly(); 84 _exitHandler = new _Socket._internalReadOnly();
94 _closed = false; 85 _closed = false;
95 _killed = false; 86 _killed = false;
96 _started = false; 87 _started = false;
97 _onExit = null; 88 _onExit = null;
98 // TODO(ager): Make the actual process starting really async instead of 89 // TODO(ager): Make the actual process starting really async instead of
99 // simulating it with a timer. 90 // simulating it with a timer.
100 new Timer(0, (Timer ignore) => start()); 91 new Timer(0, (Timer ignore) => _start());
101 } 92 }
102 93
103 String _windowsArgumentEscape(String argument) { 94 String _windowsArgumentEscape(String argument) {
104 var result = argument; 95 var result = argument;
105 if (argument.contains('\t') || argument.contains(' ')) { 96 if (argument.contains('\t') || argument.contains(' ')) {
106 // Produce something that the C runtime on Windows will parse 97 // Produce something that the C runtime on Windows will parse
107 // back as this string. 98 // back as this string.
108 99
109 // Replace any number of '\' followed by '"' with 100 // Replace any number of '\' followed by '"' with
110 // twice as many '\' followed by '\"'. 101 // twice as many '\' followed by '\"'.
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
146 return result; 137 return result;
147 } 138 }
148 139
149 int _intFromBytes(List<int> bytes, int offset) { 140 int _intFromBytes(List<int> bytes, int offset) {
150 return (bytes[offset] + 141 return (bytes[offset] +
151 (bytes[offset + 1] << 8) + 142 (bytes[offset + 1] << 8) +
152 (bytes[offset + 2] << 16) + 143 (bytes[offset + 2] << 16) +
153 (bytes[offset + 3] << 24)); 144 (bytes[offset + 3] << 24));
154 } 145 }
155 146
156 void start() { 147 void _start() {
157 var status = new _ProcessStartStatus(); 148 var status = new _ProcessStartStatus();
158 bool success = _start(_path, 149 bool success = _startNative(_path,
159 _arguments, 150 _arguments,
160 _workingDirectory, 151 _workingDirectory,
161 _environment, 152 _environment,
162 _in, 153 _in,
163 _out, 154 _out,
164 _err, 155 _err,
165 _exitHandler, 156 _exitHandler,
166 status); 157 status);
167 if (!success) { 158 if (!success) {
168 close(); 159 close();
169 _reportError(new ProcessException(status._errorMessage, status._errorCode) ); 160 _reportError(new ProcessException(status._errorMessage, status._errorCode) );
ricow1 2012/05/10 11:48:01 Long line
Mads Ager (google) 2012/05/10 12:42:38 Done.
170 return; 161 return;
171 } 162 }
172 _started = true; 163 _started = true;
173 164
174 // Make sure to activate socket handlers now that the file 165 // Make sure to activate socket handlers now that the file
175 // descriptors have been set. 166 // descriptors have been set.
176 _in._activateHandlers(); 167 _in._activateHandlers();
177 _out._activateHandlers(); 168 _out._activateHandlers();
178 _err._activateHandlers(); 169 _err._activateHandlers();
179 170
(...skipping 20 matching lines...) Expand all
200 exitDataRead += _exitHandler.inputStream.readInto( 191 exitDataRead += _exitHandler.inputStream.readInto(
201 exitDataBuffer, exitDataRead, EXIT_DATA_SIZE - exitDataRead); 192 exitDataBuffer, exitDataRead, EXIT_DATA_SIZE - exitDataRead);
202 if (exitDataRead == EXIT_DATA_SIZE) handleExit(); 193 if (exitDataRead == EXIT_DATA_SIZE) handleExit();
203 }; 194 };
204 195
205 if (_onStart !== null) { 196 if (_onStart !== null) {
206 _onStart(); 197 _onStart();
207 } 198 }
208 } 199 }
209 200
210 bool _start(String path, 201 bool _startNative(String path,
211 List<String> arguments, 202 List<String> arguments,
212 String workingDirectory, 203 String workingDirectory,
213 List<String> environment, 204 List<String> environment,
214 Socket input, 205 Socket input,
215 Socket output, 206 Socket output,
216 Socket error, 207 Socket error,
217 Socket exitHandler, 208 Socket exitHandler,
218 _ProcessStartStatus status) native "Process_Start"; 209 _ProcessStartStatus status) native "Process_Start";
219 210
220 InputStream get stdout() { 211 InputStream get stdout() {
221 if (_closed) { 212 if (_closed) {
222 throw new ProcessException("Process closed"); 213 throw new ProcessException("Process closed");
223 } 214 }
224 return _in.inputStream; 215 return _in.inputStream;
225 } 216 }
226 217
227 InputStream get stderr() { 218 InputStream get stderr() {
228 if (_closed) { 219 if (_closed) {
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
311 Function _onError; 302 Function _onError;
312 Function _onStart; 303 Function _onStart;
313 } 304 }
314 305
315 306
316 // _NonInteractiveProcess is a wrapper around an interactive process 307 // _NonInteractiveProcess is a wrapper around an interactive process
317 // that restricts the interface to disallow access to the streams and 308 // that restricts the interface to disallow access to the streams and
318 // buffers output so it can be delivered to the callback when the 309 // buffers output so it can be delivered to the callback when the
319 // process exits. 310 // process exits.
320 class _NonInteractiveProcess implements Process { 311 class _NonInteractiveProcess implements Process {
321 _NonInteractiveProcess.start(String path, 312 _NonInteractiveProcess._start(String path,
322 List<String> arguments, 313 List<String> arguments,
323 ProcessOptions options, 314 ProcessOptions options) {
324 Function this._callback) { 315 _completer = new Completer<ProcessResult>();
325 // Extract output encoding options and verify arguments. 316 // Extract output encoding options and verify arguments.
326 var stdoutEncoding = Encoding.UTF_8; 317 var stdoutEncoding = Encoding.UTF_8;
327 var stderrEncoding = Encoding.UTF_8; 318 var stderrEncoding = Encoding.UTF_8;
328 if (options !== null) { 319 if (options !== null) {
329 if (options.stdoutEncoding !== null) { 320 if (options.stdoutEncoding !== null) {
330 stdoutEncoding = options.stdoutEncoding; 321 stdoutEncoding = options.stdoutEncoding;
331 if (stdoutEncoding is !Encoding) { 322 if (stdoutEncoding is !Encoding) {
332 throw new IllegalArgumentException( 323 throw new IllegalArgumentException(
333 'stdoutEncoding option is not an encoding: $stdoutEncoding'); 324 'stdoutEncoding option is not an encoding: $stdoutEncoding');
334 } 325 }
335 } 326 }
336 if (options.stderrEncoding !== null) { 327 if (options.stderrEncoding !== null) {
337 stderrEncoding = options.stderrEncoding; 328 stderrEncoding = options.stderrEncoding;
338 if (stderrEncoding is !Encoding) { 329 if (stderrEncoding is !Encoding) {
339 throw new IllegalArgumentException( 330 throw new IllegalArgumentException(
340 'stderrEncoding option is not an encoding: $stderrEncoding'); 331 'stderrEncoding option is not an encoding: $stderrEncoding');
341 } 332 }
342 } 333 }
343 } 334 }
344 335
345 // Start the underlying process. 336 // Start the underlying process.
346 _process = new _InteractiveProcess.start(path, arguments, options); 337 _process = new _InteractiveProcess.start(path, arguments, options);
347 338
339 // Setup process error handling.
340 _process.onError = (e) => _completer.completeException(e);
341
348 // Setup process exit handling. 342 // Setup process exit handling.
349 _process.onExit = (exitCode) { 343 _process.onExit = (exitCode) {
350 _exitCode = exitCode; 344 _exitCode = exitCode;
351 _checkDone(); 345 _checkDone();
352 }; 346 };
353 347
354 // Setup stdout handling. 348 // Setup stdout handling.
355 _stdoutBuffer = new StringBuffer(); 349 _stdoutBuffer = new StringBuffer();
356 var stdoutStream = new StringInputStream(_process.stdout, stdoutEncoding); 350 var stdoutStream = new StringInputStream(_process.stdout, stdoutEncoding);
357 stdoutStream.onData = () { 351 stdoutStream.onData = () {
(...skipping 13 matching lines...) Expand all
371 if (data != null) _stderrBuffer.add(data); 365 if (data != null) _stderrBuffer.add(data);
372 }; 366 };
373 stderrStream.onClosed = () { 367 stderrStream.onClosed = () {
374 _stderrClosed = true; 368 _stderrClosed = true;
375 _checkDone(); 369 _checkDone();
376 }; 370 };
377 } 371 }
378 372
379 void _checkDone() { 373 void _checkDone() {
380 if (_exitCode != null && _stderrClosed && _stdoutClosed) { 374 if (_exitCode != null && _stderrClosed && _stdoutClosed) {
381 _callback(_exitCode, _stdoutBuffer.toString(), _stderrBuffer.toString()); 375 _completer.complete(new _ProcessResult(_exitCode,
376 _stdoutBuffer.toString(),
377 _stderrBuffer.toString()));
382 } 378 }
383 } 379 }
384 380
385 InputStream get stdout() { 381 Future<ProcessResult> get _result() => _completer.future;
386 throw new UnsupportedOperationException(
387 'Cannot get stdout stream for process started with '
388 'the run constructor. The entire stdout '
389 'will be supplied in the callback on completion.');
390 }
391 382
392 InputStream get stderr() { 383 Completer<ProcessResult> _completer;
393 throw new UnsupportedOperationException( 384 InteractiveProcess _process;
394 'Cannot get stderr stream for process started with '
395 'the run constructor. The entire stderr '
396 'will be supplied in the callback on completion.');
397 }
398
399 OutputStream get stdin() {
400 throw new UnsupportedOperationException(
401 'Cannot communicate via stdin with process started with '
402 'the run constructor');
403 }
404
405 void set onStart(void callback()) => _process.onStart = callback;
406
407 void set onExit(void callback(int exitCode)) {
408 throw new UnsupportedOperationException(
409 'Cannot set exit handler on process started with '
410 'the run constructor. The exit code will '
411 'be supplied in the callback on completion.');
412 }
413
414 void set onError(void callback(e)) {
415 _process.onError = callback;
416 }
417
418 void kill() => _process.kill();
419
420 void close() => _process.close();
421
422 Process _process;
423 Function _callback;
424 StringBuffer _stdoutBuffer; 385 StringBuffer _stdoutBuffer;
425 StringBuffer _stderrBuffer; 386 StringBuffer _stderrBuffer;
426 int _exitCode; 387 int _exitCode;
427 bool _stdoutClosed = false; 388 bool _stdoutClosed = false;
428 bool _stderrClosed = false; 389 bool _stderrClosed = false;
429 } 390 }
391
392
393 class _ProcessResult implements ProcessResult {
394 _ProcessResult(int this._exitCode, String this._stdout, String this._stderr);
395
396 int get exitCode() => _exitCode;
397 String get stdout() => _stdout;
398 String get stderr() => _stderr;
399
400 int _exitCode;
401 String _stdout;
402 String _stderr;
403 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698