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

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

Issue 11512011: Handle relative paths where the trailing directory has an extension. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Fix merge bug. 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 | « no previous file | utils/tests/pub/path/path_posix_test.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 /// A comprehensive, cross-platform path manipulation library. 5 /// A comprehensive, cross-platform path manipulation library.
6 library path; 6 library path;
7 7
8 import 'dart:io' as io; 8 import 'dart:io' as io;
9 9
10 /// An internal builder for the current OS so we can provide a straight 10 /// An internal builder for the current OS so we can provide a straight
(...skipping 316 matching lines...) Expand 10 before | Expand all | Expand 10 after
327 pathParsed.removeTrailingSeparator(); 327 pathParsed.removeTrailingSeparator();
328 328
329 return pathParsed.toString(); 329 return pathParsed.toString();
330 } 330 }
331 331
332 /// Removes a trailing extension from the last part of [path]. 332 /// Removes a trailing extension from the last part of [path].
333 /// 333 ///
334 /// builder.withoutExtension('path/to/foo.dart'); // -> 'path/to/foo' 334 /// builder.withoutExtension('path/to/foo.dart'); // -> 'path/to/foo'
335 String withoutExtension(String path) { 335 String withoutExtension(String path) {
336 var parsed = _parse(path); 336 var parsed = _parse(path);
337 parsed.extension = null; 337 if (parsed.hasTrailingSeparator) return parsed.toString();
338
339 if (!parsed.parts.isEmpty) {
340 parsed.parts[parsed.parts.length - 1] = parsed.basenameWithoutExtension;
341 }
342
338 return parsed.toString(); 343 return parsed.toString();
339 } 344 }
340 345
341 _ParsedPath _parse(String path) { 346 _ParsedPath _parse(String path) {
342 var before = path; 347 var before = path;
343 348
344 // Remove the root prefix, if any. 349 // Remove the root prefix, if any.
345 var root = style.getRoot(path); 350 var root = style.getRoot(path);
346 if (root != null) path = path.substring(root.length); 351 if (root != null) path = path.substring(root.length);
347 352
348 // Split the parts on path separators. 353 // Split the parts on path separators.
349 var parts = []; 354 var parts = [];
350 var separators = []; 355 var separators = [];
351 var start = 0; 356 var start = 0;
352 for (var match in style.separatorPattern.allMatches(path)) { 357 for (var match in style.separatorPattern.allMatches(path)) {
353 parts.add(path.substring(start, match.start)); 358 parts.add(path.substring(start, match.start));
354 separators.add(match[0]); 359 separators.add(match[0]);
355 start = match.end; 360 start = match.end;
356 } 361 }
357 362
358 // Add the final part, if any. 363 // Add the final part, if any.
359 if (start < path.length) { 364 if (start < path.length) {
360 parts.add(path.substring(start)); 365 parts.add(path.substring(start));
361 separators.add(''); 366 separators.add('');
362 } 367 }
363 368
364 // Separate out the file extension. 369 return new _ParsedPath(style, root, parts, separators);
365 var extension = '';
366 if (parts.length > 0) {
367 var file = parts.last;
368 if (file != '..') {
369 var lastDot = file.lastIndexOf('.');
370
371 // If there is a dot (and it's not the first character, like '.bashrc').
372 if (lastDot > 0) {
373 parts[parts.length - 1] = file.substring(0, lastDot);
374 extension = file.substring(lastDot);
375 }
376 }
377 }
378
379 return new _ParsedPath(style, root, parts, separators, extension);
380 } 370 }
381 } 371 }
382 372
383 /// An enum type describing a "flavor" of path. 373 /// An enum type describing a "flavor" of path.
384 class Style { 374 class Style {
385 /// POSIX-style paths use "/" (forward slash) as separators. Absolute paths 375 /// POSIX-style paths use "/" (forward slash) as separators. Absolute paths
386 /// start with "/". Used by UNIX, Linux, Mac OS X, and others. 376 /// start with "/". Used by UNIX, Linux, Mac OS X, and others.
387 static final posix = new Style._('posix', '/', '/', '/'); 377 static final posix = new Style._('posix', '/', '/', '/');
388 378
389 /// Windows paths use "\" (backslash) as separators. Absolute paths start with 379 /// Windows paths use "\" (backslash) as separators. Absolute paths start with
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
431 /// The [Style] that was used to parse this path. 421 /// The [Style] that was used to parse this path.
432 Style style; 422 Style style;
433 423
434 /// The absolute root portion of the path, or `null` if the path is relative. 424 /// The absolute root portion of the path, or `null` if the path is relative.
435 /// On POSIX systems, this will be `null` or "/". On Windows, it can be 425 /// On POSIX systems, this will be `null` or "/". On Windows, it can be
436 /// `null`, "//" for a UNC path, or something like "C:\" for paths with drive 426 /// `null`, "//" for a UNC path, or something like "C:\" for paths with drive
437 /// letters. 427 /// letters.
438 String root; 428 String root;
439 429
440 /// The path-separated parts of the path. All but the last will be 430 /// The path-separated parts of the path. All but the last will be
441 /// directories. The last could be a directory, or could be the file name 431 /// directories.
442 /// without its extension.
443 List<String> parts; 432 List<String> parts;
444 433
445 /// The path separators following each part. The last one will be an empty 434 /// The path separators following each part. The last one will be an empty
446 /// string unless the path ends with a trailing separator. 435 /// string unless the path ends with a trailing separator.
447 List<String> separators; 436 List<String> separators;
448 437
449 /// The file's extension, or "" if it doesn't have one. 438 /// The file extension of the last part, or "" if it doesn't have one.
450 String extension; 439 String get extension => _splitExtension()[1];
451 440
452 /// `true` if the path ends with a trailing separator. 441 /// `true` if the path ends with a trailing separator.
453 bool get hasTrailingSeparator { 442 bool get hasTrailingSeparator {
454 if (separators.length == 0) return false; 443 if (separators.length == 0) return false;
455 return separators[separators.length - 1] != ''; 444 return separators[separators.length - 1] != '';
456 } 445 }
457 446
458 /// `true` if this is an absolute path. 447 /// `true` if this is an absolute path.
459 bool get isAbsolute => root != null; 448 bool get isAbsolute => root != null;
460 449
461 _ParsedPath(this.style, this.root, this.parts, this.separators, 450 _ParsedPath(this.style, this.root, this.parts, this.separators);
462 this.extension);
463 451
464 String get basename { 452 String get basename {
465 if (parts.length == 0) return extension; 453 if (parts.length == 0) return extension;
466 if (hasTrailingSeparator) return ''; 454 if (hasTrailingSeparator) return '';
467 return '${parts.last}$extension'; 455 return parts.last;
468 } 456 }
469 457
470 String get basenameWithoutExtension { 458 String get basenameWithoutExtension => _splitExtension()[0];
471 if (parts.length == 0) return '';
472 if (hasTrailingSeparator) return '';
473 return parts.last;
474 }
475 459
476 void removeTrailingSeparator() { 460 void removeTrailingSeparator() {
477 if (separators.length > 0) { 461 if (separators.length > 0) {
478 separators[separators.length - 1] = ''; 462 separators[separators.length - 1] = '';
479 } 463 }
480 } 464 }
481 465
482 void normalize() { 466 void normalize() {
483 // Handle '.', '..', and empty parts. 467 // Handle '.', '..', and empty parts.
484 var leadingDoubles = 0; 468 var leadingDoubles = 0;
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
517 separators = newSeparators; 501 separators = newSeparators;
518 502
519 removeTrailingSeparator(); 503 removeTrailingSeparator();
520 } 504 }
521 505
522 String toString() { 506 String toString() {
523 var builder = new StringBuffer(); 507 var builder = new StringBuffer();
524 if (root != null) builder.add(root); 508 if (root != null) builder.add(root);
525 for (var i = 0; i < parts.length; i++) { 509 for (var i = 0; i < parts.length; i++) {
526 builder.add(parts[i]); 510 builder.add(parts[i]);
527 if (extension != null && i == parts.length - 1) builder.add(extension);
528 builder.add(separators[i]); 511 builder.add(separators[i]);
529 } 512 }
530 513
531 return builder.toString(); 514 return builder.toString();
532 } 515 }
516
517 /// Splits the last part of the path into a two-element list. The first is
518 /// the name of the file without any extension. The second is the extension
519 /// or "" if it has none.
520 List<String> _splitExtension() {
521 if (parts.isEmpty) return ['', ''];
522 if (hasTrailingSeparator) return ['', ''];
523
524 var file = parts.last;
525 if (file == '..') return ['..', ''];
526
527 var lastDot = file.lastIndexOf('.');
528
529 // If there is no dot, or it's the first character, like '.bashrc', it
530 // doesn't count.
531 if (lastDot <= 0) return [file, ''];
532
533 return [file.substring(0, lastDot), file.substring(lastDot)];
534 }
533 } 535 }
OLDNEW
« no previous file with comments | « no previous file | utils/tests/pub/path/path_posix_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698