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

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

Issue 11472016: Revert "Add logging system to pub and sprinkle some logging in." (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: 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/hosted_source.dart ('k') | utils/pub/log.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 /**
6 * Helper functionality to make working with IO easier. 6 * Helper functionality to make working with IO easier.
7 */ 7 */
8 library io; 8 library io;
9 9
10 import 'dart:io'; 10 import 'dart:io';
11 import 'dart:isolate'; 11 import 'dart:isolate';
12 import 'dart:uri'; 12 import 'dart:uri';
13 13
14 // TODO(nweiz): Make this import better. 14 // TODO(nweiz): Make this import better.
15 import '../../pkg/http/lib/http.dart' as http; 15 import '../../pkg/http/lib/http.dart' as http;
16 import 'utils.dart';
16 import 'curl_client.dart'; 17 import 'curl_client.dart';
17 import 'log.dart' as log;
18 import 'utils.dart';
19 18
20 bool _isGitInstalledCache; 19 bool _isGitInstalledCache;
21 20
22 /// The cached Git command. 21 /// The cached Git command.
23 String _gitCommandCache; 22 String _gitCommandCache;
24 23
25 /** Gets the current working directory. */ 24 /** Gets the current working directory. */
26 String get currentWorkingDir => new File('.').fullPathSync(); 25 String get currentWorkingDir => new File('.').fullPathSync();
27 26
28 final NEWLINE_PATTERN = new RegExp("\r\n?|\n\r?"); 27 final NEWLINE_PATTERN = new RegExp("\r\n?|\n\r?");
29 28
30 /** 29 /**
30 * Prints the given string to `stderr` on its own line.
31 */
32 void printError(value) {
33 stderr.writeString(value.toString());
34 stderr.writeString('\n');
35 }
36
37
38 /**
31 * Joins a number of path string parts into a single path. Handles 39 * Joins a number of path string parts into a single path. Handles
32 * platform-specific path separators. Parts can be [String], [Directory], or 40 * platform-specific path separators. Parts can be [String], [Directory], or
33 * [File] objects. 41 * [File] objects.
34 */ 42 */
35 String join(part1, [part2, part3, part4]) { 43 String join(part1, [part2, part3, part4]) {
36 final parts = _sanitizePath(part1).split('/'); 44 final parts = _sanitizePath(part1).split('/');
37 45
38 for (final part in [part2, part3, part4]) { 46 for (final part in [part2, part3, part4]) {
39 if (part == null) continue; 47 if (part == null) continue;
40 48
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
107 return results[0] || results[1]; 115 return results[0] || results[1];
108 }); 116 });
109 } 117 }
110 118
111 /** 119 /**
112 * Asynchronously determines if [file], which can be a [String] file path or a 120 * Asynchronously determines if [file], which can be a [String] file path or a
113 * [File], exists on the file system. Returns a [Future] that completes with 121 * [File], exists on the file system. Returns a [Future] that completes with
114 * the result. 122 * the result.
115 */ 123 */
116 Future<bool> fileExists(file) { 124 Future<bool> fileExists(file) {
117 var path = _getPath(file); 125 return new File(_getPath(file)).exists();
118 return log.ioAsync("Seeing if file $path exists.",
119 new File(path).exists(),
120 (exists) => "File $path ${exists ? 'exists' : 'does not exist'}.");
121 } 126 }
122 127
123 /** 128 /**
124 * Reads the contents of the text file [file], which can either be a [String] or 129 * Reads the contents of the text file [file], which can either be a [String] or
125 * a [File]. 130 * a [File].
126 */ 131 */
127 Future<String> readTextFile(file) { 132 Future<String> readTextFile(file) {
128 var path = _getPath(file); 133 return new File(_getPath(file)).readAsString(Encoding.UTF_8);
129 return log.ioAsync("Reading text file $path.",
130 new File(path).readAsString(Encoding.UTF_8),
131 (contents) {
132 // Sanity check: don't spew a huge file.
133 if (contents.length < 1024 * 1024) {
134 return "Read $path. Contents:\n$contents";
135 } else {
136 return "Read ${contents.length} characters from $path.";
137 }
138 });
139 } 134 }
140 135
141 /** 136 /**
142 * Creates [file] (which can either be a [String] or a [File]), and writes 137 * Creates [file] (which can either be a [String] or a [File]), and writes
143 * [contents] to it. Completes when the file is written and closed. 138 * [contents] to it. Completes when the file is written and closed.
144 */ 139 */
145 Future<File> writeTextFile(file, String contents) { 140 Future<File> writeTextFile(file, String contents) {
146 var path = _getPath(file); 141 file = new File(_getPath(file));
147 file = new File(path);
148
149 // Sanity check: don't spew a huge file.
150 log.io("Writing ${contents.length} characters to text file $path.");
151 if (contents.length < 1024 * 1024) {
152 log.fine("Contents:\n$contents");
153 }
154
155 return file.open(FileMode.WRITE).chain((opened) { 142 return file.open(FileMode.WRITE).chain((opened) {
156 return opened.writeString(contents).chain((ignore) { 143 return opened.writeString(contents).chain((ignore) {
157 return opened.close().transform((_) { 144 return opened.close().transform((ignore) => file);
158 log.fine("Wrote text file $path.");
159 return file;
160 });
161 }); 145 });
162 }); 146 });
163 } 147 }
164 148
165 /** 149 /**
166 * Asynchronously deletes [file], which can be a [String] or a [File]. Returns a 150 * Asynchronously deletes [file], which can be a [String] or a [File]. Returns a
167 * [Future] that completes when the deletion is done. 151 * [Future] that completes when the deletion is done.
168 */ 152 */
169 Future<File> deleteFile(file) { 153 Future<File> deleteFile(file) {
170 var path = _getPath(file); 154 return new File(_getPath(file)).delete();
171 return log.ioAsync("delete file $path",
172 new File(path).delete());
173 } 155 }
174 156
175 /// Writes [stream] to a new file at [path], which may be a [String] or a 157 /// Writes [stream] to a new file at [path], which may be a [String] or a
176 /// [File]. Will replace any file already at that path. Completes when the file 158 /// [File]. Will replace any file already at that path. Completes when the file
177 /// is done being written. 159 /// is done being written.
178 Future<File> createFileFromStream(InputStream stream, path) { 160 Future<File> createFileFromStream(InputStream stream, path) {
179 path = _getPath(path); 161 path = _getPath(path);
180 162
181 log.io("Creating $path from stream.");
182
183 var completer = new Completer<File>(); 163 var completer = new Completer<File>();
184 var file = new File(path); 164 var file = new File(path);
185 var outputStream = file.openOutputStream(); 165 var outputStream = file.openOutputStream();
186 stream.pipe(outputStream); 166 stream.pipe(outputStream);
187 167
188 outputStream.onClosed = () { 168 outputStream.onClosed = () {
189 log.fine("Created $path from stream.");
190 completer.complete(file); 169 completer.complete(file);
191 }; 170 };
192 171
193 // TODO(nweiz): remove this when issue 4061 is fixed. 172 // TODO(nweiz): remove this when issue 4061 is fixed.
194 var stackTrace; 173 var stackTrace;
195 try { 174 try {
196 throw ""; 175 throw "";
197 } catch (_, localStackTrace) { 176 } catch (_, localStackTrace) {
198 stackTrace = localStackTrace; 177 stackTrace = localStackTrace;
199 } 178 }
200 179
201 completeError(error) { 180 completeError(error) {
202 if (!completer.isComplete) { 181 if (!completer.isComplete) completer.completeException(error, stackTrace);
203 completer.completeException(error, stackTrace);
204 } else {
205 log.fine("Got error after stream was closed: $error");
206 }
207 } 182 }
208 183
209 stream.onError = completeError; 184 stream.onError = completeError;
210 outputStream.onError = completeError; 185 outputStream.onError = completeError;
211 186
212 return completer.future; 187 return completer.future;
213 } 188 }
214 189
215 /** 190 /**
216 * Creates a directory [dir]. Returns a [Future] that completes when the 191 * Creates a directory [dir]. Returns a [Future] that completes when the
217 * directory is created. 192 * directory is created.
218 */ 193 */
219 Future<Directory> createDir(dir) { 194 Future<Directory> createDir(dir) {
220 dir = _getDirectory(dir); 195 dir = _getDirectory(dir);
221 return log.ioAsync("create directory ${dir.path}", 196 return dir.create();
222 dir.create());
223 } 197 }
224 198
225 /** 199 /**
226 * Ensures that [path] and all its parent directories exist. If they don't 200 * Ensures that [path] and all its parent directories exist. If they don't
227 * exist, creates them. Returns a [Future] that completes once all the 201 * exist, creates them. Returns a [Future] that completes once all the
228 * directories are created. 202 * directories are created.
229 */ 203 */
230 Future<Directory> ensureDir(path) { 204 Future<Directory> ensureDir(path) {
231 path = _getPath(path); 205 path = _getPath(path);
232 log.fine("Ensuring directory $path exists.");
233 if (path == '.') return new Future.immediate(new Directory('.')); 206 if (path == '.') return new Future.immediate(new Directory('.'));
234 207
235 return dirExists(path).chain((exists) { 208 return dirExists(path).chain((exists) {
236 if (exists) { 209 if (exists) return new Future.immediate(new Directory(path));
237 log.fine("Directory $path already exists.");
238 return new Future.immediate(new Directory(path));
239 }
240
241 return ensureDir(dirname(path)).chain((_) { 210 return ensureDir(dirname(path)).chain((_) {
242 var completer = new Completer<Directory>(); 211 var completer = new Completer<Directory>();
243 var future = createDir(path); 212 var future = createDir(path);
244 future.handleException((error) { 213 future.handleException((error) {
245 if (error is! DirectoryIOException) return false; 214 if (error is! DirectoryIOException) return false;
246 // Error 17 means the directory already exists (or 183 on Windows). 215 // Error 17 means the directory already exists (or 183 on Windows).
247 if (error.osError.errorCode != 17 && 216 if (error.osError.errorCode != 17 &&
248 error.osError.errorCode != 183) { 217 error.osError.errorCode != 183) return false;
249 log.fine("Got 'already exists' error when creating directory.");
250 return false;
251 }
252 218
253 completer.complete(_getDirectory(path)); 219 completer.complete(_getDirectory(path));
254 return true; 220 return true;
255 }); 221 });
256 future.then(completer.complete); 222 future.then(completer.complete);
257 return completer.future; 223 return completer.future;
258 }); 224 });
259 }); 225 });
260 } 226 }
261 227
262 /** 228 /**
263 * Creates a temp directory whose name will be based on [dir] with a unique 229 * Creates a temp directory whose name will be based on [dir] with a unique
264 * suffix appended to it. If [dir] is not provided, a temp directory will be 230 * suffix appended to it. If [dir] is not provided, a temp directory will be
265 * created in a platform-dependent temporary location. Returns a [Future] that 231 * created in a platform-dependent temporary location. Returns a [Future] that
266 * completes when the directory is created. 232 * completes when the directory is created.
267 */ 233 */
268 Future<Directory> createTempDir([dir = '']) { 234 Future<Directory> createTempDir([dir = '']) {
269 dir = _getDirectory(dir); 235 dir = _getDirectory(dir);
270 return log.ioAsync("create temp directory ${dir.path}", 236 return dir.createTemp();
271 dir.createTemp());
272 } 237 }
273 238
274 /** 239 /**
275 * Asynchronously recursively deletes [dir], which can be a [String] or a 240 * Asynchronously recursively deletes [dir], which can be a [String] or a
276 * [Directory]. Returns a [Future] that completes when the deletion is done. 241 * [Directory]. Returns a [Future] that completes when the deletion is done.
277 */ 242 */
278 Future<Directory> deleteDir(dir) { 243 Future<Directory> deleteDir(dir) {
279 dir = _getDirectory(dir); 244 dir = _getDirectory(dir);
280 return log.ioAsync("delete directory ${dir.path}", 245 return dir.delete(recursive: true);
281 dir.delete(recursive: true));
282 } 246 }
283 247
284 /** 248 /**
285 * Asynchronously lists the contents of [dir], which can be a [String] directory 249 * Asynchronously lists the contents of [dir], which can be a [String] directory
286 * path or a [Directory]. If [recursive] is `true`, lists subdirectory contents 250 * path or a [Directory]. If [recursive] is `true`, lists subdirectory contents
287 * (defaults to `false`). If [includeHiddenFiles] is `true`, includes files and 251 * (defaults to `false`). If [includeHiddenFiles] is `true`, includes files and
288 * directories beginning with `.` (defaults to `false`). 252 * directories beginning with `.` (defaults to `false`).
289 */ 253 */
290 Future<List<String>> listDir(dir, 254 Future<List<String>> listDir(dir,
291 {bool recursive: false, bool includeHiddenFiles: false}) { 255 {bool recursive: false, bool includeHiddenFiles: false}) {
292 final completer = new Completer<List<String>>(); 256 final completer = new Completer<List<String>>();
293 final contents = <String>[]; 257 final contents = <String>[];
294 258
295 dir = _getDirectory(dir); 259 dir = _getDirectory(dir);
296 log.io("Listing directory ${dir.path}.");
297 var lister = dir.list(recursive: recursive); 260 var lister = dir.list(recursive: recursive);
298 261
299 lister.onDone = (done) { 262 lister.onDone = (done) {
300 // TODO(rnystrom): May need to sort here if it turns out onDir and onFile 263 // TODO(rnystrom): May need to sort here if it turns out onDir and onFile
301 // aren't guaranteed to be called in a certain order. So far, they seem to. 264 // aren't guaranteed to be called in a certain order. So far, they seem to.
302 if (done) { 265 if (done) completer.complete(contents);
303 log.fine("Listed directory ${dir.path}:\n"
304 "${Strings.join(contents, '\n')}");
305 completer.complete(contents);
306 }
307 }; 266 };
308 267
309 // TODO(nweiz): remove this when issue 4061 is fixed. 268 // TODO(nweiz): remove this when issue 4061 is fixed.
310 var stackTrace; 269 var stackTrace;
311 try { 270 try {
312 throw ""; 271 throw "";
313 } catch (_, localStackTrace) { 272 } catch (_, localStackTrace) {
314 stackTrace = localStackTrace; 273 stackTrace = localStackTrace;
315 } 274 }
316 275
(...skipping 10 matching lines...) Expand all
327 return completer.future; 286 return completer.future;
328 } 287 }
329 288
330 /** 289 /**
331 * Asynchronously determines if [dir], which can be a [String] directory path 290 * Asynchronously determines if [dir], which can be a [String] directory path
332 * or a [Directory], exists on the file system. Returns a [Future] that 291 * or a [Directory], exists on the file system. Returns a [Future] that
333 * completes with the result. 292 * completes with the result.
334 */ 293 */
335 Future<bool> dirExists(dir) { 294 Future<bool> dirExists(dir) {
336 dir = _getDirectory(dir); 295 dir = _getDirectory(dir);
337 return log.ioAsync("Seeing if directory ${dir.path} exists.", 296 return dir.exists();
338 dir.exists(),
339 (exists) => "Directory ${dir.path} "
340 "${exists ? 'exists' : 'does not exist'}.");
341 } 297 }
342 298
343 /** 299 /**
344 * "Cleans" [dir]. If that directory already exists, it will be deleted. Then a 300 * "Cleans" [dir]. If that directory already exists, it will be deleted. Then a
345 * new empty directory will be created. Returns a [Future] that completes when 301 * new empty directory will be created. Returns a [Future] that completes when
346 * the new clean directory is created. 302 * the new clean directory is created.
347 */ 303 */
348 Future<Directory> cleanDir(dir) { 304 Future<Directory> cleanDir(dir) {
349 return dirExists(dir).chain((exists) { 305 return dirExists(dir).chain((exists) {
350 if (exists) { 306 if (exists) {
351 // Delete it first. 307 // Delete it first.
352 return deleteDir(dir).chain((_) => createDir(dir)); 308 return deleteDir(dir).chain((_) => createDir(dir));
353 } else { 309 } else {
354 // Just create it. 310 // Just create it.
355 return createDir(dir); 311 return createDir(dir);
356 } 312 }
357 }); 313 });
358 } 314 }
359 315
360 /// Renames (i.e. moves) the directory [from] to [to]. Returns a [Future] with 316 /// Renames (i.e. moves) the directory [from] to [to]. Returns a [Future] with
361 /// the destination directory. 317 /// the destination directory.
362 Future<Directory> renameDir(from, String to) { 318 Future<Directory> renameDir(from, String to) {
363 from = _getDirectory(from); 319 from = _getDirectory(from);
364 log.io("Renaming directory ${from.path} to $to.");
365 320
366 if (Platform.operatingSystem != 'windows') { 321 if (Platform.operatingSystem != 'windows') return from.rename(to);
367 return from.rename(to).transform((dir) {
368 log.fine("Renamed directory ${from.path} to $to.");
369 return dir;
370 });
371 }
372 322
373 // On Windows, we sometimes get failures where the directory is still in use 323 // On Windows, we sometimes get failures where the directory is still in use
374 // when we try to move it. To be a bit more resilient, we wait and retry a 324 // when we try to move it. To be a bit more resilient, we wait and retry a
375 // few times. 325 // few times.
376 var attempts = 0; 326 var attempts = 0;
377 attemptRename(_) { 327 attemptRename(_) {
378 attempts++; 328 attempts++;
379 return from.rename(to).transform((dir) { 329 return from.rename(to).transformException((e) {
380 log.fine("Renamed directory ${from.path} to $to.");
381 return dir;
382 }).transformException((e) {
383 if (attempts >= 10) { 330 if (attempts >= 10) {
384 throw 'Could not move directory "${from.path}" to "$to". Gave up ' 331 throw 'Could not move directory "${from.path}" to "$to". Gave up '
385 'after $attempts attempts.'; 332 'after $attempts attempts.';
386 } 333 }
387 334
388 // Wait a bit and try again. 335 // Wait a bit and try again.
389 log.fine("Rename ${from.path} failed, retrying (attempt $attempts).");
390 return sleep(500).chain(attemptRename); 336 return sleep(500).chain(attemptRename);
391 }); 337 });
392 338
393 return from; 339 return from;
394 } 340 }
395 341
396 return attemptRename(null); 342 return attemptRename(null);
397 } 343 }
398 344
399 /** 345 /**
400 * Creates a new symlink that creates an alias from [from] to [to], both of 346 * Creates a new symlink that creates an alias from [from] to [to], both of
401 * which can be a [String], [File], or [Directory]. Returns a [Future] which 347 * which can be a [String], [File], or [Directory]. Returns a [Future] which
402 * completes to the symlink file (i.e. [to]). 348 * completes to the symlink file (i.e. [to]).
403 */ 349 */
404 Future<File> createSymlink(from, to) { 350 Future<File> createSymlink(from, to) {
405 from = _getPath(from); 351 from = _getPath(from);
406 to = _getPath(to); 352 to = _getPath(to);
407 353
408 log.fine("Create symlink $from -> $to.");
409
410 var command = 'ln'; 354 var command = 'ln';
411 var args = ['-s', from, to]; 355 var args = ['-s', from, to];
412 356
413 if (Platform.operatingSystem == 'windows') { 357 if (Platform.operatingSystem == 'windows') {
414 // Call mklink on Windows to create an NTFS junction point. Only works on 358 // Call mklink on Windows to create an NTFS junction point. Only works on
415 // Vista or later. (Junction points are available earlier, but the "mklink" 359 // Vista or later. (Junction points are available earlier, but the "mklink"
416 // command is not.) I'm using a junction point (/j) here instead of a soft 360 // command is not.) I'm using a junction point (/j) here instead of a soft
417 // link (/d) because the latter requires some privilege shenanigans that 361 // link (/d) because the latter requires some privilege shenanigans that
418 // I'm not sure how to specify from the command line. 362 // I'm not sure how to specify from the command line.
419 command = 'mklink'; 363 command = 'mklink';
(...skipping 11 matching lines...) Expand all
431 * package [from] to [to], both of which can be a [String], [File], or 375 * package [from] to [to], both of which can be a [String], [File], or
432 * [Directory]. Returns a [Future] which completes to the symlink file (i.e. 376 * [Directory]. Returns a [Future] which completes to the symlink file (i.e.
433 * [to]). If [from] does not have a `lib` directory, this shows a warning if 377 * [to]). If [from] does not have a `lib` directory, this shows a warning if
434 * appropriate and then does nothing. 378 * appropriate and then does nothing.
435 */ 379 */
436 Future<File> createPackageSymlink(String name, from, to, 380 Future<File> createPackageSymlink(String name, from, to,
437 {bool isSelfLink: false}) { 381 {bool isSelfLink: false}) {
438 // See if the package has a "lib" directory. 382 // See if the package has a "lib" directory.
439 from = join(from, 'lib'); 383 from = join(from, 'lib');
440 return dirExists(from).chain((exists) { 384 return dirExists(from).chain((exists) {
441 log.fine("Creating ${isSelfLink ? "self" : ""}link for package '$name'.");
442 if (exists) return createSymlink(from, to); 385 if (exists) return createSymlink(from, to);
443 386
444 // It's OK for the self link (i.e. the root package) to not have a lib 387 // It's OK for the self link (i.e. the root package) to not have a lib
445 // directory since it may just be a leaf application that only has 388 // directory since it may just be a leaf application that only has
446 // code in bin or web. 389 // code in bin or web.
447 if (!isSelfLink) { 390 if (!isSelfLink) {
448 log.warning('Warning: Package "$name" does not have a "lib" directory so ' 391 printError(
449 'you will not be able to import any libraries from it.'); 392 'Warning: Package "$name" does not have a "lib" directory so you '
393 'will not be able to import any libraries from it.');
450 } 394 }
451 395
452 return new Future.immediate(to); 396 return new Future.immediate(to);
453 }); 397 });
454 } 398 }
455 399
456 /// Given [entry] which may be a [String], [File], or [Directory] relative to 400 /// Given [entry] which may be a [String], [File], or [Directory] relative to
457 /// the current working directory, returns its full canonicalized path. 401 /// the current working directory, returns its full canonicalized path.
458 String getFullPath(entry) { 402 String getFullPath(entry) {
459 var path = _getPath(entry); 403 var path = _getPath(entry);
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
555 499
556 /// An HTTP client that transforms 40* errors and socket exceptions into more 500 /// An HTTP client that transforms 40* errors and socket exceptions into more
557 /// user-friendly error messages. 501 /// user-friendly error messages.
558 class PubHttpClient extends http.BaseClient { 502 class PubHttpClient extends http.BaseClient {
559 final http.Client _inner; 503 final http.Client _inner;
560 504
561 PubHttpClient([http.Client inner]) 505 PubHttpClient([http.Client inner])
562 : _inner = inner == null ? new http.Client() : inner; 506 : _inner = inner == null ? new http.Client() : inner;
563 507
564 Future<http.StreamedResponse> send(http.BaseRequest request) { 508 Future<http.StreamedResponse> send(http.BaseRequest request) {
565 log.io("Sending HTTP request $request.");
566
567 // TODO(nweiz): remove this when issue 4061 is fixed. 509 // TODO(nweiz): remove this when issue 4061 is fixed.
568 var stackTrace; 510 var stackTrace;
569 try { 511 try {
570 throw null; 512 throw null;
571 } catch (_, localStackTrace) { 513 } catch (_, localStackTrace) {
572 stackTrace = localStackTrace; 514 stackTrace = localStackTrace;
573 } 515 }
574 516
575 // TODO(nweiz): Ideally the timeout would extend to reading from the 517 // TODO(nweiz): Ideally the timeout would extend to reading from the
576 // response input stream, but until issue 3657 is fixed that's not feasible. 518 // response input stream, but until issue 3657 is fixed that's not feasible.
577 return timeout(_inner.send(request).chain((streamedResponse) { 519 return timeout(_inner.send(request).chain((streamedResponse) {
578 log.fine("Got response ${streamedResponse.statusCode} "
579 "${streamedResponse.reasonPhrase}.");
580
581 var status = streamedResponse.statusCode; 520 var status = streamedResponse.statusCode;
582 // 401 responses should be handled by the OAuth2 client. It's very 521 // 401 responses should be handled by the OAuth2 client. It's very
583 // unlikely that they'll be returned by non-OAuth2 requests. 522 // unlikely that they'll be returned by non-OAuth2 requests.
584 if (status < 400 || status == 401) { 523 if (status < 400 || status == 401) {
585 return new Future.immediate(streamedResponse); 524 return new Future.immediate(streamedResponse);
586 } 525 }
587 526
588 return http.Response.fromStream(streamedResponse).transform((response) { 527 return http.Response.fromStream(streamedResponse).transform((response) {
589 throw new PubHttpException(response); 528 throw new PubHttpException(response);
590 }); 529 });
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
676 Future<PubProcessResult> runProcess(String executable, List<String> args, 615 Future<PubProcessResult> runProcess(String executable, List<String> args,
677 {workingDir, Map<String, String> environment}) { 616 {workingDir, Map<String, String> environment}) {
678 return _doProcess(Process.run, executable, args, workingDir, environment) 617 return _doProcess(Process.run, executable, args, workingDir, environment)
679 .transform((result) { 618 .transform((result) {
680 // TODO(rnystrom): Remove this and change to returning one string. 619 // TODO(rnystrom): Remove this and change to returning one string.
681 List<String> toLines(String output) { 620 List<String> toLines(String output) {
682 var lines = output.split(NEWLINE_PATTERN); 621 var lines = output.split(NEWLINE_PATTERN);
683 if (!lines.isEmpty && lines.last == "") lines.removeLast(); 622 if (!lines.isEmpty && lines.last == "") lines.removeLast();
684 return lines; 623 return lines;
685 } 624 }
686 625 return new PubProcessResult(toLines(result.stdout),
687 var pubResult = new PubProcessResult(toLines(result.stdout),
688 toLines(result.stderr), 626 toLines(result.stderr),
689 result.exitCode); 627 result.exitCode);
690
691 log.processResult(executable, pubResult);
692 return pubResult;
693 }); 628 });
694 } 629 }
695 630
696 /// Spawns the process located at [executable], passing in [args]. Returns a 631 /// Spawns the process located at [executable], passing in [args]. Returns a
697 /// [Future] that will complete with the [Process] once it's been started. 632 /// [Future] that will complete with the [Process] once it's been started.
698 /// 633 ///
699 /// The spawned process will inherit its parent's environment variables. If 634 /// The spawned process will inherit its parent's environment variables. If
700 /// [environment] is provided, that will be used to augment (not replace) the 635 /// [environment] is provided, that will be used to augment (not replace) the
701 /// the inherited variables. 636 /// the inherited variables.
702 Future<Process> startProcess(String executable, List<String> args, 637 Future<Process> startProcess(String executable, List<String> args,
(...skipping 18 matching lines...) Expand all
721 final options = new ProcessOptions(); 656 final options = new ProcessOptions();
722 if (workingDir != null) { 657 if (workingDir != null) {
723 options.workingDirectory = _getDirectory(workingDir).path; 658 options.workingDirectory = _getDirectory(workingDir).path;
724 } 659 }
725 660
726 if (environment != null) { 661 if (environment != null) {
727 options.environment = new Map.from(Platform.environment); 662 options.environment = new Map.from(Platform.environment);
728 environment.forEach((key, value) => options.environment[key] = value); 663 environment.forEach((key, value) => options.environment[key] = value);
729 } 664 }
730 665
731 log.process(executable, args);
732
733 return fn(executable, args, options); 666 return fn(executable, args, options);
734 } 667 }
735 668
736 /// Closes [response] while ignoring the body of [request]. Returns a Future 669 /// Closes [response] while ignoring the body of [request]. Returns a Future
737 /// that completes once the response is closed. 670 /// that completes once the response is closed.
738 /// 671 ///
739 /// Due to issue 6984, it's necessary to drain the request body before closing 672 /// Due to issue 6984, it's necessary to drain the request body before closing
740 /// the response. 673 /// the response.
741 Future closeHttpResponse(HttpRequest request, HttpResponse response) { 674 Future closeHttpResponse(HttpRequest request, HttpResponse response) {
742 // TODO(nweiz): remove this when issue 4061 is fixed. 675 // TODO(nweiz): remove this when issue 4061 is fixed.
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
791 724
792 /// Creates a temporary directory and passes its path to [fn]. Once the [Future] 725 /// Creates a temporary directory and passes its path to [fn]. Once the [Future]
793 /// returned by [fn] completes, the temporary directory and all its contents 726 /// returned by [fn] completes, the temporary directory and all its contents
794 /// will be deleted. 727 /// will be deleted.
795 Future withTempDir(Future fn(String path)) { 728 Future withTempDir(Future fn(String path)) {
796 var tempDir; 729 var tempDir;
797 var future = createTempDir().chain((dir) { 730 var future = createTempDir().chain((dir) {
798 tempDir = dir; 731 tempDir = dir;
799 return fn(tempDir.path); 732 return fn(tempDir.path);
800 }); 733 });
801 future.onComplete((_) { 734 future.onComplete((_) => tempDir.delete(recursive: true));
802 log.fine('Cleaning up temp directory ${tempDir.path}.');
803 deleteDir(tempDir);
804 });
805 return future; 735 return future;
806 } 736 }
807 737
808 /// Tests whether or not the git command-line app is available for use. 738 /// Tests whether or not the git command-line app is available for use.
809 Future<bool> get isGitInstalled { 739 Future<bool> get isGitInstalled {
810 if (_isGitInstalledCache != null) { 740 if (_isGitInstalledCache != null) {
811 // TODO(rnystrom): The sleep is to pump the message queue. Can use 741 // TODO(rnystrom): The sleep is to pump the message queue. Can use
812 // Future.immediate() when #3356 is fixed. 742 // Future.immediate() when #3356 is fixed.
813 return sleep(0).transform((_) => _isGitInstalledCache); 743 return sleep(0).transform((_) => _isGitInstalledCache);
814 } 744 }
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
867 return completer.future; 797 return completer.future;
868 } 798 }
869 799
870 /** 800 /**
871 * Extracts a `.tar.gz` file from [stream] to [destination], which can be a 801 * Extracts a `.tar.gz` file from [stream] to [destination], which can be a
872 * directory or a path. Returns whether or not the extraction was successful. 802 * directory or a path. Returns whether or not the extraction was successful.
873 */ 803 */
874 Future<bool> extractTarGz(InputStream stream, destination) { 804 Future<bool> extractTarGz(InputStream stream, destination) {
875 destination = _getPath(destination); 805 destination = _getPath(destination);
876 806
877 log.fine("Extracting .tar.gz stream to $destination.");
878
879 if (Platform.operatingSystem == "windows") { 807 if (Platform.operatingSystem == "windows") {
880 return _extractTarGzWindows(stream, destination); 808 return _extractTarGzWindows(stream, destination);
881 } 809 }
882 810
883 var completer = new Completer<int>(); 811 var completer = new Completer<int>();
884 var processFuture = Process.start("tar", 812 var processFuture = Process.start("tar",
885 ["--extract", "--gunzip", "--directory", destination]); 813 ["--extract", "--gunzip", "--directory", destination]);
886 processFuture.then((process) { 814 processFuture.then((process) {
887 process.onExit = completer.complete; 815 process.onExit = completer.complete;
888 stream.pipe(process.stdin); 816 stream.pipe(process.stdin);
889 process.stdout.pipe(stdout, close: false); 817 process.stdout.pipe(stdout, close: false);
890 process.stderr.pipe(stderr, close: false); 818 process.stderr.pipe(stderr, close: false);
891 }); 819 });
892 processFuture.handleException((error) { 820 processFuture.handleException((error) {
893 completer.completeException(error, processFuture.stackTrace); 821 completer.completeException(error, processFuture.stackTrace);
894 return true; 822 return true;
895 }); 823 });
896 824
897 return completer.future.transform((exitCode) { 825 return completer.future.transform((exitCode) => exitCode == 0);
898 log.fine("Extracted .tar.gz stream to $destination. Exit code $exitCode.");
899 // TODO(rnystrom): Does anything check this result value? If not, it should
900 // throw on a bad exit code.
901 return exitCode == 0;
902 });
903 } 826 }
904 827
905 Future<bool> _extractTarGzWindows(InputStream stream, String destination) { 828 Future<bool> _extractTarGzWindows(InputStream stream, String destination) {
906 // TODO(rnystrom): In the repo's history, there is an older implementation of 829 // TODO(rnystrom): In the repo's history, there is an older implementation of
907 // this that does everything in memory by piping streams directly together 830 // this that does everything in memory by piping streams directly together
908 // instead of writing out temp files. The code is simpler, but unfortunately, 831 // instead of writing out temp files. The code is simpler, but unfortunately,
909 // 7zip seems to periodically fail when we invoke it from Dart and tell it to 832 // 7zip seems to periodically fail when we invoke it from Dart and tell it to
910 // read from stdin instead of a file. Consider resurrecting that version if 833 // read from stdin instead of a file. Consider resurrecting that version if
911 // we can figure out why it fails. 834 // we can figure out why it fails.
912 835
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
949 872
950 // Untar the archive into the destination directory. 873 // Untar the archive into the destination directory.
951 return runProcess(command, ['x', tarFile], workingDir: destination); 874 return runProcess(command, ['x', tarFile], workingDir: destination);
952 }).chain((result) { 875 }).chain((result) {
953 if (result.exitCode != 0) { 876 if (result.exitCode != 0) {
954 throw 'Could not un-tar (exit code ${result.exitCode}). Error:\n' 877 throw 'Could not un-tar (exit code ${result.exitCode}). Error:\n'
955 '${Strings.join(result.stdout, "\n")}\n' 878 '${Strings.join(result.stdout, "\n")}\n'
956 '${Strings.join(result.stderr, "\n")}'; 879 '${Strings.join(result.stderr, "\n")}';
957 } 880 }
958 881
959 log.fine('Clean up 7zip temp directory ${tempDir.path}.'); 882 // Clean up the temp directory.
960 // TODO(rnystrom): Should also delete this if anything fails. 883 // TODO(rnystrom): Should also delete this if anything fails.
961 return deleteDir(tempDir); 884 return deleteDir(tempDir);
962 }).transform((_) => true); 885 }).transform((_) => true);
963 } 886 }
964 887
965 /// Create a .tar.gz archive from a list of entries. Each entry can be a 888 /// Create a .tar.gz archive from a list of entries. Each entry can be a
966 /// [String], [Directory], or [File] object. The root of the archive is 889 /// [String], [Directory], or [File] object. The root of the archive is
967 /// considered to be [baseDir], which defaults to the current working directory. 890 /// considered to be [baseDir], which defaults to the current working directory.
968 /// Returns an [InputStream] that will emit the contents of the archive. 891 /// Returns an [InputStream] that will emit the contents of the archive.
969 InputStream createTarGz(List contents, {baseDir}) { 892 InputStream createTarGz(List contents, {baseDir}) {
970 log.fine('Creating .tag.gz stream containing:');
971 contents.forEach(log.fine);
972
973 // TODO(nweiz): Propagate errors to the returned stream (including non-zero 893 // TODO(nweiz): Propagate errors to the returned stream (including non-zero
974 // exit codes). See issue 3657. 894 // exit codes). See issue 3657.
975 var stream = new ListInputStream(); 895 var stream = new ListInputStream();
976 896
977 if (baseDir == null) baseDir = currentWorkingDir; 897 if (baseDir == null) baseDir = currentWorkingDir;
978 baseDir = getFullPath(baseDir); 898 baseDir = getFullPath(baseDir);
979 contents = contents.map((entry) { 899 contents = contents.map((entry) {
980 entry = getFullPath(entry); 900 entry = getFullPath(entry);
981 if (!isBeneath(entry, baseDir)) { 901 if (!isBeneath(entry, baseDir)) {
982 throw 'Entry $entry is not inside $baseDir.'; 902 throw 'Entry $entry is not inside $baseDir.';
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
1028 948
1029 /** 949 /**
1030 * Exception thrown when an HTTP operation fails. 950 * Exception thrown when an HTTP operation fails.
1031 */ 951 */
1032 class PubHttpException implements Exception { 952 class PubHttpException implements Exception {
1033 final http.Response response; 953 final http.Response response;
1034 954
1035 const PubHttpException(this.response); 955 const PubHttpException(this.response);
1036 956
1037 String toString() => 'HTTP error ${response.statusCode}: ' 957 String toString() => 'HTTP error ${response.statusCode}: '
1038 '${response.reasonPhrase}'; 958 '${response.reasonPhrase}';
1039 } 959 }
1040 960
1041 /** 961 /**
1042 * Exception thrown when an operation times out. 962 * Exception thrown when an operation times out.
1043 */ 963 */
1044 class TimeoutException implements Exception { 964 class TimeoutException implements Exception {
1045 final String message; 965 final String message;
1046 966
1047 const TimeoutException(this.message); 967 const TimeoutException(this.message);
1048 968
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
1099 return new Directory(entry); 1019 return new Directory(entry);
1100 } 1020 }
1101 1021
1102 /** 1022 /**
1103 * Gets a [Uri] for [uri], which can either already be one, or be a [String]. 1023 * Gets a [Uri] for [uri], which can either already be one, or be a [String].
1104 */ 1024 */
1105 Uri _getUri(uri) { 1025 Uri _getUri(uri) {
1106 if (uri is Uri) return uri; 1026 if (uri is Uri) return uri;
1107 return new Uri.fromString(uri); 1027 return new Uri.fromString(uri);
1108 } 1028 }
OLDNEW
« no previous file with comments | « utils/pub/hosted_source.dart ('k') | utils/pub/log.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698