Chromium Code Reviews| Index: utils/pub/io.dart |
| diff --git a/utils/pub/io.dart b/utils/pub/io.dart |
| index 845b5b4c60e26b9ca8b3b655bf172a9078db542f..d98c55c5de49c711d7da83549e7467430061df70 100644 |
| --- a/utils/pub/io.dart |
| +++ b/utils/pub/io.dart |
| @@ -11,6 +11,9 @@ |
| #import('../lib/file_system.dart', prefix: 'fs'); |
| +/** Gets the current working directory. */ |
| +String get workingDir() => new File('.').fullPathSync(); |
| + |
| /** |
| * Joins a number of path string parts into a single path. Handles |
| * platform-specific path separators. Parts can be [String], [Directory], or |
| @@ -47,6 +50,21 @@ String basename(file) { |
| } |
| /** |
| + * Asynchronously determines if [file], which can be a [String] file path or a |
| + * [File], exists on the file system. Returns a [Future] that completes with |
| + * the result. |
| + */ |
| +Future<bool> fileExists(file) { |
| + final completer = new Completer<bool>(); |
| + |
| + file = new File(_getPath(file)); |
| + file.onError = (error) => completer.completeException(error); |
| + file.exists((exists) => completer.complete(exists)); |
| + |
| + return completer.future; |
| +} |
| + |
| +/** |
| * Reads the contents of the text file [file], which can either be a [String] or |
| * a [File]. |
| */ |
| @@ -110,12 +128,31 @@ Future<Directory> createTempDir(dir) { |
| * [Directory]. Returns a [Future] that completes when the deletion is done. |
| */ |
| Future<Directory> deleteDir(dir) { |
| + // TODO(rnystrom): Hack! Temporary! Right now, dart:io's Directory delete |
| + // method can't handle directories with symlinks, which is exactly what pub |
| + // creates and deletes. Instead, we'll just shell out to 'rm'. Remove this |
| + // when dartbug.com/2646 is fixed. |
| + dir = _getDirectory(dir); |
| + |
| + // Sanity check! |
| + if (dir.path == '/' || |
| + dir.path == '.' || |
| + dir.path == '..' || |
| + dir.path == '~' || |
| + dir.path == '*') throw "(O.o) I don't think you want to do that!"; |
| + |
| + return runProcess('rm', ['-rf', dir.path]).transform((result) => dir); |
|
nweiz
2012/04/25 17:50:47
s/result/_/. That's more concise and consistent wi
Bob Nystrom
2012/04/25 22:20:29
Done.
|
| + // End hack! |
| + |
| + // Real code: |
| + /* |
| final completer = new Completer<Directory>(); |
| dir = _getDirectory(dir); |
| dir.onError = (error) => completer.completeException(error); |
| dir.deleteRecursively(() => completer.complete(dir)); |
| return completer.future; |
| + */ |
| } |
| /** |
| @@ -153,14 +190,73 @@ Future<List<String>> listDir(dir, |
| } |
| /** |
| + * Asynchronously determines if [dir], which can be a [String] directory path |
| + * or a [Directory], exists on the file system. Returns a [Future] that |
| + * completes with the result. |
| + */ |
| +Future<bool> dirExists(dir) { |
|
nweiz
2012/04/25 17:50:47
It bothers me that this and fileExists are separat
Bob Nystrom
2012/04/25 22:20:29
Leaving this for now per our discussion.
|
| + final completer = new Completer<bool>(); |
| + |
| + dir = _getDirectory(dir); |
| + dir.onError = (error) => completer.completeException(error); |
| + dir.exists((exists) => completer.complete(exists)); |
| + |
| + return completer.future; |
| +} |
| + |
| +/** |
| + * "Cleans" [dir]. If that directory already exists, it will be deleted. Then a |
| + * new empty directory will be created. Returns a [Future] that completes when |
| + * the new clean directory is created. |
| + */ |
| +Future<Directory> cleanDir(dir) { |
| + return dirExists(dir).chain((exists) { |
| + if (exists) { |
| + // Delete it first. |
| + return deleteDir(dir).chain((_) => createDir(dir)); |
| + } else { |
| + // Just create it. |
| + return createDir(dir); |
| + } |
| + }); |
| +} |
| + |
| +/** |
| + * Creates a new symlink that creates an alias from [from] to [to], both of |
| + * which can be a [String], [File], or [Directory]. Returns a [Future] which |
| + * completes to the symlink file (i.e. [to]). |
| + */ |
| +Future<File> createSymlink(from, to) { |
| + // TODO(rnystrom): What should this do on Windows? |
| + from = _getPath(from); |
| + to = _getPath(to); |
| + |
| + return runProcess('ln', ['-s', from, to]).transform((result) { |
| + // TODO(rnystrom): Check exit code and output? |
|
nweiz
2012/04/25 17:50:47
Shouldn't runProcess be responsible for exit code
Bob Nystrom
2012/04/25 22:20:29
runProcess returns the exit code, but it doesn't t
nweiz
2012/04/25 22:30:09
I suppose that's reasonable.
|
| + return new File(to); |
| + }); |
| +} |
| + |
| +/** |
| + * Given [entry] which may be a [String], [File], or [Directory] relative to |
| + * the current working directory, returns its full canonicalized path. |
| + */ |
| +// TODO(rnystrom): Should this be async? |
| +String getFullPath(entry) => new File(_getPath(entry)).fullPathSync(); |
| + |
| +/** |
| * Spawns and runs the process located at [executable], passing in [args]. |
| * Returns a [Future] that will complete the results of the process after it |
| * has ended. |
| */ |
| -Future<ProcessResult> runProcess(String executable, List<String> args) { |
| +Future<ProcessResult> runProcess(String executable, List<String> args, |
| + [String workingDir]) { |
| int exitCode; |
| - final process = new Process.start(executable, args); |
| + final options = new ProcessOptions(); |
| + if (workingDir != null) options.workingDirectory = workingDir; |
| + |
| + final process = new Process.start(executable, args, options); |
| final outStream = new StringInputStream(process.stdout); |
| final processStdout = <String>[]; |