diff --git a/sdk/lib/io/directory.dart b/sdk/lib/io/directory.dart index a7fe5202e48..3cbf4d50c8d 100644 --- a/sdk/lib/io/directory.dart +++ b/sdk/lib/io/directory.dart @@ -108,6 +108,15 @@ abstract class Directory implements FileSystemEntity { */ Directory renameSync(String newPath); + /** + * Returns a [Directory] instance whose path is the absolute path to [this]. + * + * The absolute path is computed by prefixing + * a relative path with the current working directory, and returning + * an absolute path unchanged. + */ + Directory get absolute; + /** * Lists the sub-directories and files of this [Directory]. * Optionally recurses into sub-directories. diff --git a/sdk/lib/io/directory_impl.dart b/sdk/lib/io/directory_impl.dart index 685720e5721..61a226a56bb 100644 --- a/sdk/lib/io/directory_impl.dart +++ b/sdk/lib/io/directory_impl.dart @@ -74,6 +74,8 @@ class _Directory extends FileSystemEntity implements Directory { return (result == 1); } + Directory get absolute => new Directory(_absolutePath); + Future stat() => FileStat.stat(path); FileStat statSync() => FileStat.statSync(path); diff --git a/sdk/lib/io/file.dart b/sdk/lib/io/file.dart index d5579ca67df..4f9d3f5171e 100644 --- a/sdk/lib/io/file.dart +++ b/sdk/lib/io/file.dart @@ -98,6 +98,15 @@ abstract class File implements FileSystemEntity { */ int lengthSync(); + /** + * Returns a [File] instance whose path is the absolute path to [this]. + * + * The absolute path is computed by prefixing + * a relative path with the current working directory, and returning + * an absolute path unchanged. + */ + File get absolute; + /** * Get the last-modified time of the file. Returns a * [:Future:] that completes with a [DateTime] object for the diff --git a/sdk/lib/io/file_impl.dart b/sdk/lib/io/file_impl.dart index d803c950ef4..86acf777491 100644 --- a/sdk/lib/io/file_impl.dart +++ b/sdk/lib/io/file_impl.dart @@ -267,6 +267,8 @@ class _File extends FileSystemEntity implements File { return result; } + File get absolute => new File(_absolutePath); + Future stat() => FileStat.stat(path); FileStat statSync() => FileStat.statSync(path); diff --git a/sdk/lib/io/file_system_entity.dart b/sdk/lib/io/file_system_entity.dart index 0887175e859..ab2b7d30c61 100644 --- a/sdk/lib/io/file_system_entity.dart +++ b/sdk/lib/io/file_system_entity.dart @@ -343,6 +343,45 @@ abstract class FileSystemEntity { }); } + static final RegExp _absoluteWindowsPathPattern = + new RegExp(r'^(\\\\|[a-zA-Z]:[/\\])'); + + /** + * Returns a [bool] indicating whether this object's path is absolute. + * + * On Windows, a path is absolute if it starts with \\ or a drive letter + * between a and z (upper or lower case) followed by :\ or :/. + * On non-Windows, a path is absolute if it starts with /. + */ + bool get isAbsolute { + if (Platform.isWindows) { + return path.startsWith(_absoluteWindowsPathPattern); + } else { + return path.startsWith('/'); + } + } + + /** + * Returns a [FileSystemEntity] whose path is the absolute path to [this]. + * The type of the returned instance is the type of [this]. + * + * The absolute path is computed by prefixing + * a relative path with the current working directory, and returning + * an absolute path unchanged. + */ + FileSystemEntity get absolute; + + String get _absolutePath { + if (isAbsolute) return path; + String current = Directory.current.path; + if (current.endsWith('/') || + (Platform.isWindows && current.endsWith('\\'))) { + return '$current$path'; + } else { + return '$current${Platform.pathSeparator}$path'; + } + } + /** * Synchronously checks whether two paths refer to the same object in the diff --git a/sdk/lib/io/link.dart b/sdk/lib/io/link.dart index 3df3fc9f1d5..83cd22379a1 100644 --- a/sdk/lib/io/link.dart +++ b/sdk/lib/io/link.dart @@ -84,6 +84,15 @@ abstract class Link implements FileSystemEntity { */ Link renameSync(String newPath); + /** + * Returns a [Link] instance whose path is the absolute path to [this]. + * + * The absolute path is computed by prefixing + * a relative path with the current working directory, and returning + * an absolute path unchanged. + */ + Link get absolute; + /** * Gets the target of the link. Returns a future that completes with * the path to the target. @@ -127,6 +136,8 @@ class _Link extends FileSystemEntity implements Link { bool existsSync() => FileSystemEntity.isLinkSync(path); + Link get absolute => new Link(_absolutePath); + Future stat() => FileStat.stat(path); FileStat statSync() => FileStat.statSync(path); diff --git a/tests/standalone/io/file_absolute_path_test.dart b/tests/standalone/io/file_absolute_path_test.dart new file mode 100644 index 00000000000..e2785bf1b3b --- /dev/null +++ b/tests/standalone/io/file_absolute_path_test.dart @@ -0,0 +1,66 @@ +// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. +// +// Dart test program for testing FileSystemEntity.absolute + +import "package:expect/expect.dart"; +import 'dart:io'; + +main() { + if (Platform.isWindows) { + testWindows(); + try { + Directory.current = 'C:\\'; + } catch (e) { + return; + } + testWindows(); + } else { + testPosix(); + Directory.current = '.'; + testPosix(); + Directory.current = '/'; + testPosix(); + + } +} + +testWindows() { + String current = Directory.current.path; + for (String relative in ['abd', '..', '.', 'efg/hij', 'abc/']) { + if (current.endsWith('\\')) { + Expect.equals(new File(relative).absolute.path, '$current$relative'); + } else { + Expect.equals(new File(relative).absolute.path, '$current\\$relative'); + } + Expect.isTrue(new File(relative).absolute.isAbsolute); + } + for (String absolute in ['c:/abd', 'D:\\rf', '\\\\a_share\\folder', + '\\\\?\\c:\\prefixed\path\\']) { + Expect.isTrue(new File(absolute).absolute.path == absolute); + Expect.isTrue(new File(absolute).absolute.isAbsolute); + } +} + +testPosix() { + String current = Directory.current.path; + print(Directory.current.path); + for (String relative in ['abd', '..', '.', 'efg/hij', 'abc/']) { + if (current.endsWith('/')) { + Expect.equals(new File(relative).absolute.path, '$current$relative'); + } else { + Expect.equals(new File(relative).absolute.path, '$current/$relative'); + } + Expect.isTrue(new File(relative).absolute.isAbsolute); + Expect.equals(new Directory(relative).absolute.path, + new Link(relative).absolute.path); + Expect.isTrue(new File(relative).absolute is File); + Expect.isTrue(new Directory(relative).absolute is Directory); + Expect.isTrue(new Link(relative).absolute is Link); + } + for (String absolute in ['/abd', '/', '/./..\\', '/efg/hij', '/abc/']) { + Expect.equals(new File(absolute).absolute.path, absolute); + Expect.isTrue(new File(absolute).absolute.isAbsolute); + } +}