Chromium Code Reviews| Index: utils/pub/io.dart |
| diff --git a/utils/pub/io.dart b/utils/pub/io.dart |
| index e3fc8e0202c4b84edcfc59abe54584009037bf9d..ff9465a94f40eef66b96dfd17683e0af34514b0a 100644 |
| --- a/utils/pub/io.dart |
| +++ b/utils/pub/io.dart |
| @@ -10,6 +10,10 @@ |
| #import('dart:io'); |
| #import('dart:uri'); |
| +#import('utils.dart'); |
| + |
| +bool _isGitInstalledCache; |
| + |
| /** Gets the current working directory. */ |
| String get workingDir => new File('.').fullPathSync(); |
| @@ -128,7 +132,7 @@ Future<File> writeTextFile(file, String contents) { |
| * Asynchronously deletes [file], which can be a [String] or a [File]. Returns a |
| * [Future] that completes when the deletion is done. |
| */ |
| -Future<Directory> deleteFile(file) { |
| +Future<File> deleteFile(file) { |
| return new File(_getPath(file)).delete(); |
| } |
| @@ -268,8 +272,8 @@ Future<File> createSymlink(from, to) { |
| // command is not.) I'm using a junction point (/j) here instead of a soft |
| // link (/d) because the latter requires some privilege shenanigans that |
| // I'm not sure how to specify from the command line. |
| - command = 'cmd'; |
| - args = ['/c', 'mklink', '/j', to, from]; |
| + command = 'mklink'; |
| + args = ['/j', to, from]; |
| } |
| return runProcess(command, args).transform((result) { |
| @@ -350,6 +354,16 @@ Future<PubProcessResult> runProcess(String executable, List<String> args, |
| bool pipeStderr = false]) { |
| int exitCode; |
| + // TODO(rnystrom): Should dart:io just handle this? |
| + // Spawning a process on Windows will not look for the executable in the |
| + // system path. So, if executable looks like it needs that (i.e. it doesn't |
| + // have any path separators in it), then spawn it through a shell. |
| + if ((Platform.operatingSystem == "windows") && |
| + (executable.indexOf('\\') == -1)) { |
| + args = flatten(["/c", executable, args]); |
| + executable = "cmd"; |
| + } |
| + |
| final options = new ProcessOptions(); |
| if (workingDir != null) { |
| options.workingDirectory = _getDirectory(workingDir).path; |
| @@ -406,11 +420,11 @@ Future<PubProcessResult> runProcess(String executable, List<String> args, |
| * Tests whether or not the git command-line app is available for use. |
| */ |
| Future<bool> get isGitInstalled { |
| - // TODO(rnystrom): We could cache this after the first check. We aren't right |
| - // now because Future.immediate() will invoke its callback synchronously. |
| - // That does bad things in cases where the caller expects futures to always |
| - // be async. In particular, withGit() in the pub tests which calls |
| - // expectAsync() will fail horribly if the test isn't actually async. |
| + if (_isGitInstalledCache != null) { |
| + // TODO(rnystrom): The sleep is to pump the message queue. Can use |
| + // Future.immediate() when #3356 is fixed. |
| + return sleep(0).transform((_) => _isGitInstalledCache); |
| + } |
| var completer = new Completer<bool>(); |
| @@ -437,8 +451,14 @@ Future<bool> get isGitInstalled { |
| * directory or a path. Returns whether or not the extraction was successful. |
| */ |
| Future<bool> extractTarGz(InputStream stream, destination) { |
| + if (Platform.operatingSystem == "windows") { |
| + return _extractTarGzWindows(stream, destination); |
| + } |
| + |
| + destination = _getPath(destination); |
|
nweiz
2012/09/18 23:07:12
Why not do this before passing it in to _extractTa
Bob Nystrom
2012/09/19 15:57:54
Done.
|
| + |
| var process = Process.start("tar", |
| - ["--extract", "--gunzip", "--directory", _getPath(destination)]); |
| + ["--extract", "--gunzip", "--directory", destination]); |
| var completer = new Completer<int>(); |
| stream.pipe(process.stdin); |
| @@ -450,6 +470,34 @@ Future<bool> extractTarGz(InputStream stream, destination) { |
| return completer.future.transform((exitCode) => exitCode == 0); |
| } |
| +Future<bool> _extractTarGzWindows(InputStream stream, dest) { |
| + dest = _getPath(dest); |
| + |
| + // Find 7zip. |
| + var scriptDir = new Path(new Options().script).directoryPath; |
| + |
| + // Note: This line of code gets munged by create_sdk.py to be the correct |
| + // relative path to 7zip in the SDK. |
| + var pathTo7zip = '../../third_party/7zip/7za.exe'; |
| + |
| + var command = scriptDir.append(pathTo7zip).canonicalize().toNativePath(); |
| + |
| + // 7zip can't unarchive from gzip -> tar -> destination all in one step so |
| + // we spawn it twice and pipe them together. |
| + var completer = new Completer<int>(); |
| + var gzipProcess = Process.start(command, ["e", "-si", "-tgzip", '-so']); |
| + var tarProcess = Process.start(command, ["e", "-si", "-ttar", '-o"$dest"']); |
| + |
| + stream.pipe(gzipProcess.stdin); |
| + gzipProcess.stdout.pipe(tarProcess.stdin); |
| + |
| + tarProcess.onExit = completer.complete; |
| + gzipProcess.onError = completer.completeException; |
| + gzipProcess.onError = completer.completeException; |
| + |
| + return completer.future.transform((exitCode) => exitCode == 0); |
| +} |
| + |
| /** |
| * Contains the results of invoking a [Process] and waiting for it to complete. |
| */ |