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

Side by Side Diff: utils/pub/io.dart

Issue 11638010: Convert /** comments to /// in pub. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Respond to review. Created 8 years 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
« no previous file with comments | « utils/pub/http.dart ('k') | utils/pub/lock_file.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 /** 5 /// Helper functionality to make working with IO easier.
6 * Helper functionality to make working with IO easier.
7 */
8 library io; 6 library io;
9 7
10 import 'dart:io'; 8 import 'dart:io';
11 import 'dart:isolate'; 9 import 'dart:isolate';
12 import 'dart:json'; 10 import 'dart:json';
13 import 'dart:uri'; 11 import 'dart:uri';
14 12
15 import '../../pkg/path/lib/path.dart' as path; 13 import '../../pkg/path/lib/path.dart' as path;
16 import 'log.dart' as log; 14 import 'log.dart' as log;
17 import 'utils.dart'; 15 import 'utils.dart';
18 16
19 bool _isGitInstalledCache; 17 bool _isGitInstalledCache;
20 18
21 /// The cached Git command. 19 /// The cached Git command.
22 String _gitCommandCache; 20 String _gitCommandCache;
23 21
24 final NEWLINE_PATTERN = new RegExp("\r\n?|\n\r?"); 22 final NEWLINE_PATTERN = new RegExp("\r\n?|\n\r?");
25 23
26 /** 24 /// Joins a number of path string parts into a single path. Handles
27 * Joins a number of path string parts into a single path. Handles 25 /// platform-specific path separators. Parts can be [String], [Directory], or
28 * platform-specific path separators. Parts can be [String], [Directory], or 26 /// [File] objects.
29 * [File] objects.
30 */
31 String join(part1, [part2, part3, part4, part5, part6, part7, part8]) { 27 String join(part1, [part2, part3, part4, part5, part6, part7, part8]) {
32 var parts = [part1, part2, part3, part4, part5, part6, part7, part8] 28 var parts = [part1, part2, part3, part4, part5, part6, part7, part8]
33 .map((part) => part == null ? null : _getPath(part)); 29 .map((part) => part == null ? null : _getPath(part));
34 30
35 return path.join(parts[0], parts[1], parts[2], parts[3], parts[4], parts[5], 31 return path.join(parts[0], parts[1], parts[2], parts[3], parts[4], parts[5],
36 parts[6], parts[7]); 32 parts[6], parts[7]);
37 } 33 }
38 34
39 /// Gets the basename, the file name without any leading directory path, for 35 /// Gets the basename, the file name without any leading directory path, for
40 /// [file], which can either be a [String], [File], or [Directory]. 36 /// [file], which can either be a [String], [File], or [Directory].
41 String basename(file) => path.basename(_getPath(file)); 37 String basename(file) => path.basename(_getPath(file));
42 38
43 /// Gets the the leading directory path for [file], which can either be a 39 /// Gets the the leading directory path for [file], which can either be a
44 /// [String], [File], or [Directory]. 40 /// [String], [File], or [Directory].
45 String dirname(file) => path.dirname(_getPath(file)); 41 String dirname(file) => path.dirname(_getPath(file));
46 42
47 /// Splits [entry] into its individual components. 43 /// Splits [entry] into its individual components.
48 List<String> splitPath(entry) => path.split(_getPath(entry)); 44 List<String> splitPath(entry) => path.split(_getPath(entry));
49 45
50 /// Returns whether or not [entry] is nested somewhere within [dir]. This just 46 /// Returns whether or not [entry] is nested somewhere within [dir]. This just
51 /// performs a path comparison; it doesn't look at the actual filesystem. 47 /// performs a path comparison; it doesn't look at the actual filesystem.
52 bool isBeneath(entry, dir) { 48 bool isBeneath(entry, dir) {
53 var relative = relativeTo(entry, dir); 49 var relative = relativeTo(entry, dir);
54 return !path.isAbsolute(relative) && splitPath(relative)[0] != '..'; 50 return !path.isAbsolute(relative) && splitPath(relative)[0] != '..';
55 } 51 }
56 52
57 /// Returns the path to [target] from [base]. 53 /// Returns the path to [target] from [base].
58 String relativeTo(target, base) => path.relative(target, from: base); 54 String relativeTo(target, base) => path.relative(target, from: base);
59 55
60 /** 56 /// Asynchronously determines if [path], which can be a [String] file path, a
61 * Asynchronously determines if [path], which can be a [String] file path, a 57 /// [File], or a [Directory] exists on the file system. Returns a [Future] that
62 * [File], or a [Directory] exists on the file system. Returns a [Future] that 58 /// completes with the result.
63 * completes with the result.
64 */
65 Future<bool> exists(path) { 59 Future<bool> exists(path) {
66 path = _getPath(path); 60 path = _getPath(path);
67 return Futures.wait([fileExists(path), dirExists(path)]).transform((results) { 61 return Futures.wait([fileExists(path), dirExists(path)]).transform((results) {
68 return results[0] || results[1]; 62 return results[0] || results[1];
69 }); 63 });
70 } 64 }
71 65
72 /** 66 /// Asynchronously determines if [file], which can be a [String] file path or a
73 * Asynchronously determines if [file], which can be a [String] file path or a 67 /// [File], exists on the file system. Returns a [Future] that completes with
74 * [File], exists on the file system. Returns a [Future] that completes with 68 /// the result.
75 * the result.
76 */
77 Future<bool> fileExists(file) { 69 Future<bool> fileExists(file) {
78 var path = _getPath(file); 70 var path = _getPath(file);
79 return log.ioAsync("Seeing if file $path exists.", 71 return log.ioAsync("Seeing if file $path exists.",
80 new File(path).exists(), 72 new File(path).exists(),
81 (exists) => "File $path ${exists ? 'exists' : 'does not exist'}."); 73 (exists) => "File $path ${exists ? 'exists' : 'does not exist'}.");
82 } 74 }
83 75
84 /** 76 /// Reads the contents of the text file [file], which can either be a [String]
85 * Reads the contents of the text file [file], which can either be a [String] or 77 /// or a [File].
86 * a [File].
87 */
88 Future<String> readTextFile(file) { 78 Future<String> readTextFile(file) {
89 var path = _getPath(file); 79 var path = _getPath(file);
90 return log.ioAsync("Reading text file $path.", 80 return log.ioAsync("Reading text file $path.",
91 new File(path).readAsString(Encoding.UTF_8), 81 new File(path).readAsString(Encoding.UTF_8),
92 (contents) { 82 (contents) {
93 // Sanity check: don't spew a huge file. 83 // Sanity check: don't spew a huge file.
94 if (contents.length < 1024 * 1024) { 84 if (contents.length < 1024 * 1024) {
95 return "Read $path. Contents:\n$contents"; 85 return "Read $path. Contents:\n$contents";
96 } else { 86 } else {
97 return "Read ${contents.length} characters from $path."; 87 return "Read ${contents.length} characters from $path.";
98 } 88 }
99 }); 89 });
100 } 90 }
101 91
102 /** 92 /// Creates [file] (which can either be a [String] or a [File]), and writes
103 * Creates [file] (which can either be a [String] or a [File]), and writes 93 /// [contents] to it. Completes when the file is written and closed.
104 * [contents] to it. Completes when the file is written and closed. 94 ///
105 * 95 /// If [dontLogContents] is true, the contents of the file will never be logged.
106 * If [dontLogContents] is true, the contents of the file will never be logged.
107 */
108 Future<File> writeTextFile(file, String contents, {dontLogContents: false}) { 96 Future<File> writeTextFile(file, String contents, {dontLogContents: false}) {
109 var path = _getPath(file); 97 var path = _getPath(file);
110 file = new File(path); 98 file = new File(path);
111 99
112 // Sanity check: don't spew a huge file. 100 // Sanity check: don't spew a huge file.
113 log.io("Writing ${contents.length} characters to text file $path."); 101 log.io("Writing ${contents.length} characters to text file $path.");
114 if (!dontLogContents && contents.length < 1024 * 1024) { 102 if (!dontLogContents && contents.length < 1024 * 1024) {
115 log.fine("Contents:\n$contents"); 103 log.fine("Contents:\n$contents");
116 } 104 }
117 105
118 return file.open(FileMode.WRITE).chain((opened) { 106 return file.open(FileMode.WRITE).chain((opened) {
119 return opened.writeString(contents).chain((ignore) { 107 return opened.writeString(contents).chain((ignore) {
120 return opened.close().transform((_) { 108 return opened.close().transform((_) {
121 log.fine("Wrote text file $path."); 109 log.fine("Wrote text file $path.");
122 return file; 110 return file;
123 }); 111 });
124 }); 112 });
125 }); 113 });
126 } 114 }
127 115
128 /** 116 /// Asynchronously deletes [file], which can be a [String] or a [File]. Returns
129 * Asynchronously deletes [file], which can be a [String] or a [File]. Returns a 117 /// a [Future] that completes when the deletion is done.
130 * [Future] that completes when the deletion is done.
131 */
132 Future<File> deleteFile(file) { 118 Future<File> deleteFile(file) {
133 var path = _getPath(file); 119 var path = _getPath(file);
134 return log.ioAsync("delete file $path", 120 return log.ioAsync("delete file $path",
135 new File(path).delete()); 121 new File(path).delete());
136 } 122 }
137 123
138 /// Writes [stream] to a new file at [path], which may be a [String] or a 124 /// Writes [stream] to a new file at [path], which may be a [String] or a
139 /// [File]. Will replace any file already at that path. Completes when the file 125 /// [File]. Will replace any file already at that path. Completes when the file
140 /// is done being written. 126 /// is done being written.
141 Future<File> createFileFromStream(InputStream stream, path) { 127 Future<File> createFileFromStream(InputStream stream, path) {
(...skipping 26 matching lines...) Expand all
168 log.fine("Got error after stream was closed: $error"); 154 log.fine("Got error after stream was closed: $error");
169 } 155 }
170 } 156 }
171 157
172 stream.onError = completeError; 158 stream.onError = completeError;
173 outputStream.onError = completeError; 159 outputStream.onError = completeError;
174 160
175 return completer.future; 161 return completer.future;
176 } 162 }
177 163
178 /** 164 /// Creates a directory [dir]. Returns a [Future] that completes when the
179 * Creates a directory [dir]. Returns a [Future] that completes when the 165 /// directory is created.
180 * directory is created.
181 */
182 Future<Directory> createDir(dir) { 166 Future<Directory> createDir(dir) {
183 dir = _getDirectory(dir); 167 dir = _getDirectory(dir);
184 return log.ioAsync("create directory ${dir.path}", 168 return log.ioAsync("create directory ${dir.path}",
185 dir.create()); 169 dir.create());
186 } 170 }
187 171
188 /** 172 /// Ensures that [path] and all its parent directories exist. If they don't
189 * Ensures that [path] and all its parent directories exist. If they don't 173 /// exist, creates them. Returns a [Future] that completes once all the
190 * exist, creates them. Returns a [Future] that completes once all the 174 /// directories are created.
191 * directories are created.
192 */
193 Future<Directory> ensureDir(path) { 175 Future<Directory> ensureDir(path) {
194 path = _getPath(path); 176 path = _getPath(path);
195 log.fine("Ensuring directory $path exists."); 177 log.fine("Ensuring directory $path exists.");
196 if (path == '.') return new Future.immediate(new Directory('.')); 178 if (path == '.') return new Future.immediate(new Directory('.'));
197 179
198 return dirExists(path).chain((exists) { 180 return dirExists(path).chain((exists) {
199 if (exists) { 181 if (exists) {
200 log.fine("Directory $path already exists."); 182 log.fine("Directory $path already exists.");
201 return new Future.immediate(new Directory(path)); 183 return new Future.immediate(new Directory(path));
202 } 184 }
(...skipping 12 matching lines...) Expand all
215 197
216 completer.complete(_getDirectory(path)); 198 completer.complete(_getDirectory(path));
217 return true; 199 return true;
218 }); 200 });
219 future.then(completer.complete); 201 future.then(completer.complete);
220 return completer.future; 202 return completer.future;
221 }); 203 });
222 }); 204 });
223 } 205 }
224 206
225 /** 207 /// Creates a temp directory whose name will be based on [dir] with a unique
226 * Creates a temp directory whose name will be based on [dir] with a unique 208 /// suffix appended to it. If [dir] is not provided, a temp directory will be
227 * suffix appended to it. If [dir] is not provided, a temp directory will be 209 /// created in a platform-dependent temporary location. Returns a [Future] that
228 * created in a platform-dependent temporary location. Returns a [Future] that 210 /// completes when the directory is created.
229 * completes when the directory is created.
230 */
231 Future<Directory> createTempDir([dir = '']) { 211 Future<Directory> createTempDir([dir = '']) {
232 dir = _getDirectory(dir); 212 dir = _getDirectory(dir);
233 return log.ioAsync("create temp directory ${dir.path}", 213 return log.ioAsync("create temp directory ${dir.path}",
234 dir.createTemp()); 214 dir.createTemp());
235 } 215 }
236 216
237 /** 217 /// Asynchronously recursively deletes [dir], which can be a [String] or a
238 * Asynchronously recursively deletes [dir], which can be a [String] or a 218 /// [Directory]. Returns a [Future] that completes when the deletion is done.
239 * [Directory]. Returns a [Future] that completes when the deletion is done.
240 */
241 Future<Directory> deleteDir(dir) { 219 Future<Directory> deleteDir(dir) {
242 dir = _getDirectory(dir); 220 dir = _getDirectory(dir);
243 221
244 return _attemptRetryable(() => log.ioAsync("delete directory ${dir.path}", 222 return _attemptRetryable(() => log.ioAsync("delete directory ${dir.path}",
245 dir.delete(recursive: true))); 223 dir.delete(recursive: true)));
246 } 224 }
247 225
248 /// Asynchronously lists the contents of [dir], which can be a [String] 226 /// Asynchronously lists the contents of [dir], which can be a [String]
249 /// directory path or a [Directory]. If [recursive] is `true`, lists 227 /// directory path or a [Directory]. If [recursive] is `true`, lists
250 /// subdirectory contents (defaults to `false`). If [includeHiddenFiles] is 228 /// subdirectory contents (defaults to `false`). If [includeHiddenFiles] is
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
308 return Futures.wait(children).transform((childContents) { 286 return Futures.wait(children).transform((childContents) {
309 contents.addAll(flatten(childContents)); 287 contents.addAll(flatten(childContents));
310 return contents; 288 return contents;
311 }); 289 });
312 }); 290 });
313 } 291 }
314 292
315 return doList(_getDirectory(dir), new Set<String>()); 293 return doList(_getDirectory(dir), new Set<String>());
316 } 294 }
317 295
318 /** 296 /// Asynchronously determines if [dir], which can be a [String] directory path
319 * Asynchronously determines if [dir], which can be a [String] directory path 297 /// or a [Directory], exists on the file system. Returns a [Future] that
320 * or a [Directory], exists on the file system. Returns a [Future] that 298 /// completes with the result.
321 * completes with the result.
322 */
323 Future<bool> dirExists(dir) { 299 Future<bool> dirExists(dir) {
324 dir = _getDirectory(dir); 300 dir = _getDirectory(dir);
325 return log.ioAsync("Seeing if directory ${dir.path} exists.", 301 return log.ioAsync("Seeing if directory ${dir.path} exists.",
326 dir.exists(), 302 dir.exists(),
327 (exists) => "Directory ${dir.path} " 303 (exists) => "Directory ${dir.path} "
328 "${exists ? 'exists' : 'does not exist'}."); 304 "${exists ? 'exists' : 'does not exist'}.");
329 } 305 }
330 306
331 /** 307 /// "Cleans" [dir]. If that directory already exists, it will be deleted. Then a
332 * "Cleans" [dir]. If that directory already exists, it will be deleted. Then a 308 /// new empty directory will be created. Returns a [Future] that completes when
333 * new empty directory will be created. Returns a [Future] that completes when 309 /// the new clean directory is created.
334 * the new clean directory is created.
335 */
336 Future<Directory> cleanDir(dir) { 310 Future<Directory> cleanDir(dir) {
337 return dirExists(dir).chain((exists) { 311 return dirExists(dir).chain((exists) {
338 if (exists) { 312 if (exists) {
339 // Delete it first. 313 // Delete it first.
340 return deleteDir(dir).chain((_) => createDir(dir)); 314 return deleteDir(dir).chain((_) => createDir(dir));
341 } else { 315 } else {
342 // Just create it. 316 // Just create it.
343 return createDir(dir); 317 return createDir(dir);
344 } 318 }
345 }); 319 });
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
380 354
381 // Wait a bit and try again. 355 // Wait a bit and try again.
382 log.fine("Operation failed, retrying (attempt $attempts)."); 356 log.fine("Operation failed, retrying (attempt $attempts).");
383 return sleep(500).chain(makeAttempt); 357 return sleep(500).chain(makeAttempt);
384 }); 358 });
385 } 359 }
386 360
387 return makeAttempt(null); 361 return makeAttempt(null);
388 } 362 }
389 363
390 /** 364 /// Creates a new symlink that creates an alias from [from] to [to], both of
391 * Creates a new symlink that creates an alias from [from] to [to], both of 365 /// which can be a [String], [File], or [Directory]. Returns a [Future] which
392 * which can be a [String], [File], or [Directory]. Returns a [Future] which 366 /// completes to the symlink file (i.e. [to]).
393 * completes to the symlink file (i.e. [to]).
394 */
395 Future<File> createSymlink(from, to) { 367 Future<File> createSymlink(from, to) {
396 from = _getPath(from); 368 from = _getPath(from);
397 to = _getPath(to); 369 to = _getPath(to);
398 370
399 log.fine("Create symlink $from -> $to."); 371 log.fine("Create symlink $from -> $to.");
400 372
401 var command = 'ln'; 373 var command = 'ln';
402 var args = ['-s', from, to]; 374 var args = ['-s', from, to];
403 375
404 if (Platform.operatingSystem == 'windows') { 376 if (Platform.operatingSystem == 'windows') {
405 // Call mklink on Windows to create an NTFS junction point. Only works on 377 // Call mklink on Windows to create an NTFS junction point. Only works on
406 // Vista or later. (Junction points are available earlier, but the "mklink" 378 // Vista or later. (Junction points are available earlier, but the "mklink"
407 // command is not.) I'm using a junction point (/j) here instead of a soft 379 // command is not.) I'm using a junction point (/j) here instead of a soft
408 // link (/d) because the latter requires some privilege shenanigans that 380 // link (/d) because the latter requires some privilege shenanigans that
409 // I'm not sure how to specify from the command line. 381 // I'm not sure how to specify from the command line.
410 command = 'mklink'; 382 command = 'mklink';
411 args = ['/j', to, from]; 383 args = ['/j', to, from];
412 } 384 }
413 385
414 return runProcess(command, args).transform((result) { 386 return runProcess(command, args).transform((result) {
415 // TODO(rnystrom): Check exit code and output? 387 // TODO(rnystrom): Check exit code and output?
416 return new File(to); 388 return new File(to);
417 }); 389 });
418 } 390 }
419 391
420 /** 392 /// Creates a new symlink that creates an alias from the `lib` directory of
421 * Creates a new symlink that creates an alias from the `lib` directory of 393 /// package [from] to [to], both of which can be a [String], [File], or
422 * package [from] to [to], both of which can be a [String], [File], or 394 /// [Directory]. Returns a [Future] which completes to the symlink file (i.e.
423 * [Directory]. Returns a [Future] which completes to the symlink file (i.e. 395 /// [to]). If [from] does not have a `lib` directory, this shows a warning if
424 * [to]). If [from] does not have a `lib` directory, this shows a warning if 396 /// appropriate and then does nothing.
425 * appropriate and then does nothing.
426 */
427 Future<File> createPackageSymlink(String name, from, to, 397 Future<File> createPackageSymlink(String name, from, to,
428 {bool isSelfLink: false}) { 398 {bool isSelfLink: false}) {
429 // See if the package has a "lib" directory. 399 // See if the package has a "lib" directory.
430 from = join(from, 'lib'); 400 from = join(from, 'lib');
431 return dirExists(from).chain((exists) { 401 return dirExists(from).chain((exists) {
432 log.fine("Creating ${isSelfLink ? "self" : ""}link for package '$name'."); 402 log.fine("Creating ${isSelfLink ? "self" : ""}link for package '$name'.");
433 if (exists) return createSymlink(from, to); 403 if (exists) return createSymlink(from, to);
434 404
435 // It's OK for the self link (i.e. the root package) to not have a lib 405 // It's OK for the self link (i.e. the root package) to not have a lib
436 // directory since it may just be a leaf application that only has 406 // directory since it may just be a leaf application that only has
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
517 }; 487 };
518 488
519 stream.onError = (e) { 489 stream.onError = (e) {
520 removeCallbacks(); 490 removeCallbacks();
521 completer.completeException(e, stackTrace); 491 completer.completeException(e, stackTrace);
522 }; 492 };
523 493
524 return completer.future; 494 return completer.future;
525 } 495 }
526 496
527 /** 497 /// Takes all input from [source] and writes it to [sink].
528 * Takes all input from [source] and writes it to [sink]. 498 ///
529 * 499 /// Returns a future that completes when [source] is closed.
530 * Returns a future that completes when [source] is closed.
531 */
532 Future pipeInputToInput(InputStream source, ListInputStream sink) { 500 Future pipeInputToInput(InputStream source, ListInputStream sink) {
533 var completer = new Completer(); 501 var completer = new Completer();
534 source.onClosed = () { 502 source.onClosed = () {
535 sink.markEndOfStream(); 503 sink.markEndOfStream();
536 completer.complete(null); 504 completer.complete(null);
537 }; 505 };
538 source.onData = () { 506 source.onData = () {
539 // Even if the sink is closed and we aren't going to do anything with more 507 // Even if the sink is closed and we aren't going to do anything with more
540 // data, we still need to drain it from source to work around issue 7218. 508 // data, we still need to drain it from source to work around issue 7218.
541 var data = source.read(); 509 var data = source.read();
542 try { 510 try {
543 if (!sink.closed) sink.write(data); 511 if (!sink.closed) sink.write(data);
544 } on StreamException catch (e, stackTrace) { 512 } on StreamException catch (e, stackTrace) {
545 // Ignore an exception to work around issue 4222. 513 // Ignore an exception to work around issue 4222.
546 log.io("Writing to an unclosed ListInputStream caused exception $e\n" 514 log.io("Writing to an unclosed ListInputStream caused exception $e\n"
547 "$stackTrace"); 515 "$stackTrace");
548 } 516 }
549 }; 517 };
550 // TODO(nweiz): propagate this error to the sink. See issue 3657. 518 // TODO(nweiz): propagate this error to the sink. See issue 3657.
551 source.onError = (e) { throw e; }; 519 source.onError = (e) { throw e; };
552 return completer.future; 520 return completer.future;
553 } 521 }
554 522
555 /** 523 /// Buffers all input from an InputStream and returns it as a future.
556 * Buffers all input from an InputStream and returns it as a future.
557 */
558 Future<List<int>> consumeInputStream(InputStream stream) { 524 Future<List<int>> consumeInputStream(InputStream stream) {
559 if (stream.closed) return new Future.immediate(<int>[]); 525 if (stream.closed) return new Future.immediate(<int>[]);
560 526
561 // TODO(nweiz): remove this when issue 4061 is fixed. 527 // TODO(nweiz): remove this when issue 4061 is fixed.
562 var stackTrace; 528 var stackTrace;
563 try { 529 try {
564 throw ""; 530 throw "";
565 } catch (_, localStackTrace) { 531 } catch (_, localStackTrace) {
566 stackTrace = localStackTrace; 532 stackTrace = localStackTrace;
567 } 533 }
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after
687 if (environment != null) { 653 if (environment != null) {
688 options.environment = new Map.from(Platform.environment); 654 options.environment = new Map.from(Platform.environment);
689 environment.forEach((key, value) => options.environment[key] = value); 655 environment.forEach((key, value) => options.environment[key] = value);
690 } 656 }
691 657
692 log.process(executable, args); 658 log.process(executable, args);
693 659
694 return fn(executable, args, options); 660 return fn(executable, args, options);
695 } 661 }
696 662
697 /** 663 /// Wraps [input] to provide a timeout. If [input] completes before
698 * Wraps [input] to provide a timeout. If [input] completes before 664 /// [milliseconds] have passed, then the return value completes in the same way.
699 * [milliseconds] have passed, then the return value completes in the same way. 665 /// However, if [milliseconds] pass before [input] has completed, it completes
700 * However, if [milliseconds] pass before [input] has completed, it completes 666 /// with a [TimeoutException] with [description] (which should be a fragment
701 * with a [TimeoutException] with [description] (which should be a fragment 667 /// describing the action that timed out).
702 * describing the action that timed out). 668 ///
703 * 669 /// Note that timing out will not cancel the asynchronous operation behind
704 * Note that timing out will not cancel the asynchronous operation behind 670 /// [input].
705 * [input].
706 */
707 Future timeout(Future input, int milliseconds, String description) { 671 Future timeout(Future input, int milliseconds, String description) {
708 var completer = new Completer(); 672 var completer = new Completer();
709 var timer = new Timer(milliseconds, (_) { 673 var timer = new Timer(milliseconds, (_) {
710 if (completer.future.isComplete) return; 674 if (completer.future.isComplete) return;
711 completer.completeException(new TimeoutException( 675 completer.completeException(new TimeoutException(
712 'Timed out while $description.')); 676 'Timed out while $description.'));
713 }); 677 });
714 input.handleException((e) { 678 input.handleException((e) {
715 if (completer.future.isComplete) return false; 679 if (completer.future.isComplete) return false;
716 timer.cancel(); 680 timer.cancel();
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
796 760
797 future.handleException((err) { 761 future.handleException((err) {
798 // If the process failed, they probably don't have it. 762 // If the process failed, they probably don't have it.
799 completer.complete(false); 763 completer.complete(false);
800 return true; 764 return true;
801 }); 765 });
802 766
803 return completer.future; 767 return completer.future;
804 } 768 }
805 769
806 /** 770 /// Extracts a `.tar.gz` file from [stream] to [destination], which can be a
807 * Extracts a `.tar.gz` file from [stream] to [destination], which can be a 771 /// directory or a path. Returns whether or not the extraction was successful.
808 * directory or a path. Returns whether or not the extraction was successful.
809 */
810 Future<bool> extractTarGz(InputStream stream, destination) { 772 Future<bool> extractTarGz(InputStream stream, destination) {
811 destination = _getPath(destination); 773 destination = _getPath(destination);
812 774
813 log.fine("Extracting .tar.gz stream to $destination."); 775 log.fine("Extracting .tar.gz stream to $destination.");
814 776
815 if (Platform.operatingSystem == "windows") { 777 if (Platform.operatingSystem == "windows") {
816 return _extractTarGzWindows(stream, destination); 778 return _extractTarGzWindows(stream, destination);
817 } 779 }
818 780
819 var completer = new Completer<int>(); 781 var completer = new Completer<int>();
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after
965 // stderr. We don't want to show that since it's meaningless. 927 // stderr. We don't want to show that since it's meaningless.
966 // TODO(rnystrom): Should log this and display it if an actual error 928 // TODO(rnystrom): Should log this and display it if an actual error
967 // occurs. 929 // occurs.
968 consumeInputStream(process.stderr); 930 consumeInputStream(process.stderr);
969 return pipeInputToInput(process.stdout, stream); 931 return pipeInputToInput(process.stdout, stream);
970 }); 932 });
971 }); 933 });
972 return stream; 934 return stream;
973 } 935 }
974 936
975 /** 937 /// Exception thrown when an operation times out.
976 * Exception thrown when an operation times out.
977 */
978 class TimeoutException implements Exception { 938 class TimeoutException implements Exception {
979 final String message; 939 final String message;
980 940
981 const TimeoutException(this.message); 941 const TimeoutException(this.message);
982 942
983 String toString() => message; 943 String toString() => message;
984 } 944 }
985 945
986 /** 946 /// Contains the results of invoking a [Process] and waiting for it to complete.
987 * Contains the results of invoking a [Process] and waiting for it to complete.
988 */
989 class PubProcessResult { 947 class PubProcessResult {
990 final List<String> stdout; 948 final List<String> stdout;
991 final List<String> stderr; 949 final List<String> stderr;
992 final int exitCode; 950 final int exitCode;
993 951
994 const PubProcessResult(this.stdout, this.stderr, this.exitCode); 952 const PubProcessResult(this.stdout, this.stderr, this.exitCode);
995 953
996 bool get success => exitCode == 0; 954 bool get success => exitCode == 0;
997 } 955 }
998 956
999 /** 957 /// Gets the path string for [entry], which can either already be a path string,
1000 * Gets the path string for [entry], which can either already be a path string, 958 /// or be a [File] or [Directory]. Allows working generically with "file-like"
1001 * or be a [File] or [Directory]. Allows working generically with "file-like" 959 /// objects.
1002 * objects.
1003 */
1004 String _getPath(entry) { 960 String _getPath(entry) {
1005 if (entry is String) return entry; 961 if (entry is String) return entry;
1006 if (entry is File) return entry.name; 962 if (entry is File) return entry.name;
1007 if (entry is Directory) return entry.path; 963 if (entry is Directory) return entry.path;
1008 throw 'Entry $entry is not a supported type.'; 964 throw 'Entry $entry is not a supported type.';
1009 } 965 }
1010 966
1011 /** 967 /// Gets a [Directory] for [entry], which can either already be one, or be a
1012 * Gets a [Directory] for [entry], which can either already be one, or be a 968 /// [String].
1013 * [String].
1014 */
1015 Directory _getDirectory(entry) { 969 Directory _getDirectory(entry) {
1016 if (entry is Directory) return entry; 970 if (entry is Directory) return entry;
1017 return new Directory(entry); 971 return new Directory(entry);
1018 } 972 }
1019 973
1020 /** 974 /// Gets a [Uri] for [uri], which can either already be one, or be a [String].
1021 * Gets a [Uri] for [uri], which can either already be one, or be a [String].
1022 */
1023 Uri _getUri(uri) { 975 Uri _getUri(uri) {
1024 if (uri is Uri) return uri; 976 if (uri is Uri) return uri;
1025 return new Uri.fromString(uri); 977 return new Uri.fromString(uri);
1026 } 978 }
OLDNEW
« no previous file with comments | « utils/pub/http.dart ('k') | utils/pub/lock_file.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698