OLD | NEW |
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 /// Helper functionality to make working with IO easier. | 5 /// Helper functionality to make working with IO easier. |
6 library io; | 6 library io; |
7 | 7 |
8 import 'dart:async'; | 8 import 'dart:async'; |
9 import 'dart:io'; | 9 import 'dart:io'; |
10 import 'dart:isolate'; | 10 import 'dart:isolate'; |
11 import 'dart:json'; | 11 import 'dart:json'; |
12 import 'dart:uri'; | 12 import 'dart:uri'; |
13 | 13 |
14 import '../../pkg/path/lib/path.dart' as path; | 14 import '../../pkg/path/lib/path.dart' as path; |
15 import 'log.dart' as log; | 15 import 'log.dart' as log; |
16 import 'utils.dart'; | 16 import 'utils.dart'; |
17 | 17 |
18 bool _isGitInstalledCache; | |
19 | |
20 /// The cached Git command. | |
21 String _gitCommandCache; | |
22 | |
23 final NEWLINE_PATTERN = new RegExp("\r\n?|\n\r?"); | 18 final NEWLINE_PATTERN = new RegExp("\r\n?|\n\r?"); |
24 | 19 |
25 /// Joins a number of path string parts into a single path. Handles | 20 /// Joins a number of path string parts into a single path. Handles |
26 /// platform-specific path separators. Parts can be [String], [Directory], or | 21 /// platform-specific path separators. Parts can be [String], [Directory], or |
27 /// [File] objects. | 22 /// [File] objects. |
28 String join(part1, [part2, part3, part4, part5, part6, part7, part8]) { | 23 String join(part1, [part2, part3, part4, part5, part6, part7, part8]) { |
29 var parts = [part1, part2, part3, part4, part5, part6, part7, part8] | 24 var parts = [part1, part2, part3, part4, part5, part6, part7, part8] |
30 .mappedBy((part) => part == null ? null : _getPath(part)).toList(); | 25 .mappedBy((part) => part == null ? null : _getPath(part)).toList(); |
31 | 26 |
32 return path.join(parts[0], parts[1], parts[2], parts[3], parts[4], parts[5], | 27 return path.join(parts[0], parts[1], parts[2], parts[3], parts[4], parts[5], |
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
177 /// exist, creates them. Returns a [Future] that completes once all the | 172 /// exist, creates them. Returns a [Future] that completes once all the |
178 /// directories are created. | 173 /// directories are created. |
179 Future<Directory> ensureDir(path) { | 174 Future<Directory> ensureDir(path) { |
180 path = _getPath(path); | 175 path = _getPath(path); |
181 log.fine("Ensuring directory $path exists."); | 176 log.fine("Ensuring directory $path exists."); |
182 if (path == '.') return new Future.immediate(new Directory('.')); | 177 if (path == '.') return new Future.immediate(new Directory('.')); |
183 | 178 |
184 return dirExists(path).then((exists) { | 179 return dirExists(path).then((exists) { |
185 if (exists) { | 180 if (exists) { |
186 log.fine("Directory $path already exists."); | 181 log.fine("Directory $path already exists."); |
187 return new Future.immediate(new Directory(path)); | 182 return new Directory(path); |
188 } | 183 } |
189 | 184 |
190 return ensureDir(dirname(path)).then((_) { | 185 return ensureDir(dirname(path)).then((_) { |
191 return createDir(path).catchError((asyncError) { | 186 return createDir(path).catchError((asyncError) { |
192 if (asyncError.error is! DirectoryIOException) throw asyncError; | 187 if (asyncError.error is! DirectoryIOException) throw asyncError; |
193 // Error 17 means the directory already exists (or 183 on Windows). | 188 // Error 17 means the directory already exists (or 183 on Windows). |
194 if (asyncError.error.osError.errorCode == 17 || | 189 if (asyncError.error.osError.errorCode == 17 || |
195 asyncError.error.osError.errorCode == 183) { | 190 asyncError.error.osError.errorCode == 183) { |
196 log.fine("Got 'already exists' error when creating directory."); | 191 log.fine("Got 'already exists' error when creating directory."); |
197 return _getDirectory(path); | 192 return _getDirectory(path); |
(...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
404 if (exists) return createSymlink(from, to); | 399 if (exists) return createSymlink(from, to); |
405 | 400 |
406 // It's OK for the self link (i.e. the root package) to not have a lib | 401 // It's OK for the self link (i.e. the root package) to not have a lib |
407 // directory since it may just be a leaf application that only has | 402 // directory since it may just be a leaf application that only has |
408 // code in bin or web. | 403 // code in bin or web. |
409 if (!isSelfLink) { | 404 if (!isSelfLink) { |
410 log.warning('Warning: Package "$name" does not have a "lib" directory so ' | 405 log.warning('Warning: Package "$name" does not have a "lib" directory so ' |
411 'you will not be able to import any libraries from it.'); | 406 'you will not be able to import any libraries from it.'); |
412 } | 407 } |
413 | 408 |
414 return new Future.immediate(to); | 409 return to; |
415 }); | 410 }); |
416 } | 411 } |
417 | 412 |
418 /// Given [entry] which may be a [String], [File], or [Directory] relative to | 413 /// Given [entry] which may be a [String], [File], or [Directory] relative to |
419 /// the current working directory, returns its full canonicalized path. | 414 /// the current working directory, returns its full canonicalized path. |
420 String getFullPath(entry) => path.absolute(_getPath(entry)); | 415 String getFullPath(entry) => path.absolute(_getPath(entry)); |
421 | 416 |
422 /// Returns whether or not [entry] is an absolute path. | 417 /// Returns whether or not [entry] is an absolute path. |
423 bool isAbsolute(entry) => path.isAbsolute(_getPath(entry)); | 418 bool isAbsolute(entry) => path.isAbsolute(_getPath(entry)); |
424 | 419 |
(...skipping 339 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
764 var tempDir; | 759 var tempDir; |
765 return createTempDir().then((dir) { | 760 return createTempDir().then((dir) { |
766 tempDir = dir; | 761 tempDir = dir; |
767 return fn(tempDir.path); | 762 return fn(tempDir.path); |
768 }).whenComplete(() { | 763 }).whenComplete(() { |
769 log.fine('Cleaning up temp directory ${tempDir.path}.'); | 764 log.fine('Cleaning up temp directory ${tempDir.path}.'); |
770 return deleteDir(tempDir); | 765 return deleteDir(tempDir); |
771 }); | 766 }); |
772 } | 767 } |
773 | 768 |
774 /// Tests whether or not the git command-line app is available for use. | |
775 Future<bool> get isGitInstalled { | |
776 if (_isGitInstalledCache != null) { | |
777 // TODO(rnystrom): The sleep is to pump the message queue. Can use | |
778 // Future.immediate() when #3356 is fixed. | |
779 return sleep(0).then((_) => _isGitInstalledCache); | |
780 } | |
781 | |
782 return _gitCommand.then((git) => git != null); | |
783 } | |
784 | |
785 /// Run a git process with [args] from [workingDir]. | |
786 Future<PubProcessResult> runGit(List<String> args, | |
787 {String workingDir, Map<String, String> environment}) { | |
788 return _gitCommand.then((git) => runProcess(git, args, | |
789 workingDir: workingDir, environment: environment)); | |
790 } | |
791 | |
792 /// Returns the name of the git command-line app, or null if Git could not be | |
793 /// found on the user's PATH. | |
794 Future<String> get _gitCommand { | |
795 // TODO(nweiz): Just use Future.immediate once issue 3356 is fixed. | |
796 if (_gitCommandCache != null) { | |
797 return sleep(0).then((_) => _gitCommandCache); | |
798 } | |
799 | |
800 return _tryGitCommand("git").then((success) { | |
801 if (success) return new Future.immediate("git"); | |
802 | |
803 // Git is sometimes installed on Windows as `git.cmd` | |
804 return _tryGitCommand("git.cmd").then((success) { | |
805 if (success) return "git.cmd"; | |
806 return null; | |
807 }); | |
808 }).then((command) { | |
809 _gitCommandCache = command; | |
810 return command; | |
811 }); | |
812 } | |
813 | |
814 /// Checks whether [command] is the Git command for this computer. | |
815 Future<bool> _tryGitCommand(String command) { | |
816 var completer = new Completer<bool>(); | |
817 | |
818 // If "git --version" prints something familiar, git is working. | |
819 var future = runProcess(command, ["--version"]); | |
820 | |
821 future.then((results) { | |
822 var regex = new RegExp("^git version"); | |
823 completer.complete(results.stdout.length == 1 && | |
824 regex.hasMatch(results.stdout[0])); | |
825 }).catchError((err) { | |
826 // If the process failed, they probably don't have it. | |
827 completer.complete(false); | |
828 }); | |
829 | |
830 return completer.future; | |
831 } | |
832 | |
833 /// Extracts a `.tar.gz` file from [stream] to [destination], which can be a | 769 /// Extracts a `.tar.gz` file from [stream] to [destination], which can be a |
834 /// directory or a path. Returns whether or not the extraction was successful. | 770 /// directory or a path. Returns whether or not the extraction was successful. |
835 Future<bool> extractTarGz(InputStream stream, destination) { | 771 Future<bool> extractTarGz(InputStream stream, destination) { |
836 destination = _getPath(destination); | 772 destination = _getPath(destination); |
837 | 773 |
838 log.fine("Extracting .tar.gz stream to $destination."); | 774 log.fine("Extracting .tar.gz stream to $destination."); |
839 | 775 |
840 if (Platform.operatingSystem == "windows") { | 776 if (Platform.operatingSystem == "windows") { |
841 return _extractTarGzWindows(stream, destination); | 777 return _extractTarGzWindows(stream, destination); |
842 } | 778 } |
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1030 Directory _getDirectory(entry) { | 966 Directory _getDirectory(entry) { |
1031 if (entry is Directory) return entry; | 967 if (entry is Directory) return entry; |
1032 return new Directory(entry); | 968 return new Directory(entry); |
1033 } | 969 } |
1034 | 970 |
1035 /// Gets a [Uri] for [uri], which can either already be one, or be a [String]. | 971 /// Gets a [Uri] for [uri], which can either already be one, or be a [String]. |
1036 Uri _getUri(uri) { | 972 Uri _getUri(uri) { |
1037 if (uri is Uri) return uri; | 973 if (uri is Uri) return uri; |
1038 return new Uri.fromString(uri); | 974 return new Uri.fromString(uri); |
1039 } | 975 } |
OLD | NEW |