OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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'; |
(...skipping 10 matching lines...) Expand all Loading... |
21 export '../../pkg/http/lib/http.dart' show ByteStream; | 21 export '../../pkg/http/lib/http.dart' show ByteStream; |
22 | 22 |
23 /// Returns whether or not [entry] is nested somewhere within [dir]. This just | 23 /// Returns whether or not [entry] is nested somewhere within [dir]. This just |
24 /// performs a path comparison; it doesn't look at the actual filesystem. | 24 /// performs a path comparison; it doesn't look at the actual filesystem. |
25 bool isBeneath(String entry, String dir) { | 25 bool isBeneath(String entry, String dir) { |
26 var relative = path.relative(entry, from: dir); | 26 var relative = path.relative(entry, from: dir); |
27 return !path.isAbsolute(relative) && path.split(relative)[0] != '..'; | 27 return !path.isAbsolute(relative) && path.split(relative)[0] != '..'; |
28 } | 28 } |
29 | 29 |
30 /// Determines if a file or directory exists at [path]. | 30 /// Determines if a file or directory exists at [path]. |
31 bool entryExists(String path) => dirExists(path) || fileExists(path); | 31 bool entryExists(String path) => |
| 32 dirExists(path) || fileExists(path) || linkExists(path); |
32 | 33 |
33 /// Determines if [file] exists on the file system. Will also return `true` if | 34 /// Returns whether [link] exists on the file system. This will return `true` |
34 /// [file] points to a symlink, even a directory symlink. | 35 /// for any symlink, regardless of what it points at or whether it's broken. |
35 bool fileExists(String file) => | 36 bool linkExists(String path) => new Link(path).existsSync(); |
36 new File(file).existsSync() || new Link(file).existsSync(); | 37 |
| 38 /// Returns whether [file] exists on the file system. This will return `true` |
| 39 /// for a symlink only if that symlink is unbroken and points to a file. |
| 40 bool fileExists(String file) => new File(file).existsSync(); |
37 | 41 |
38 /// Reads the contents of the text file [file]. | 42 /// Reads the contents of the text file [file]. |
39 String readTextFile(String file) => | 43 String readTextFile(String file) => |
40 new File(file).readAsStringSync(encoding: Encoding.UTF_8); | 44 new File(file).readAsStringSync(encoding: Encoding.UTF_8); |
41 | 45 |
42 /// Reads the contents of the binary file [file]. | 46 /// Reads the contents of the binary file [file]. |
43 List<int> readBinaryFile(String file) { | 47 List<int> readBinaryFile(String file) { |
44 log.io("Reading binary file $file."); | 48 log.io("Reading binary file $file."); |
45 var contents = new File(file).readAsBytesSync(); | 49 var contents = new File(file).readAsBytesSync(); |
46 log.io("Read ${contents.length} bytes from $file."); | 50 log.io("Read ${contents.length} bytes from $file."); |
47 return contents; | 51 return contents; |
48 } | 52 } |
49 | 53 |
50 /// Creates [file] and writes [contents] to it. | 54 /// Creates [file] and writes [contents] to it. |
51 /// | 55 /// |
52 /// If [dontLogContents] is true, the contents of the file will never be logged. | 56 /// If [dontLogContents] is true, the contents of the file will never be logged. |
53 String writeTextFile(String file, String contents, {dontLogContents: false}) { | 57 String writeTextFile(String file, String contents, {dontLogContents: false}) { |
54 // Sanity check: don't spew a huge file. | 58 // Sanity check: don't spew a huge file. |
55 log.io("Writing ${contents.length} characters to text file $file."); | 59 log.io("Writing ${contents.length} characters to text file $file."); |
56 if (!dontLogContents && contents.length < 1024 * 1024) { | 60 if (!dontLogContents && contents.length < 1024 * 1024) { |
57 log.fine("Contents:\n$contents"); | 61 log.fine("Contents:\n$contents"); |
58 } | 62 } |
59 | 63 |
60 new File(file).writeAsStringSync(contents); | 64 new File(file).writeAsStringSync(contents); |
61 return file; | 65 return file; |
62 } | 66 } |
63 | 67 |
64 /// Deletes [file]. | |
65 void deleteFile(String file) { | |
66 new File(file).deleteSync(); | |
67 } | |
68 | |
69 /// Creates [file] and writes [contents] to it. | 68 /// Creates [file] and writes [contents] to it. |
70 String writeBinaryFile(String file, List<int> contents) { | 69 String writeBinaryFile(String file, List<int> contents) { |
71 log.io("Writing ${contents.length} bytes to binary file $file."); | 70 log.io("Writing ${contents.length} bytes to binary file $file."); |
72 new File(file).openSync(mode: FileMode.WRITE) | 71 new File(file).openSync(mode: FileMode.WRITE) |
73 ..writeListSync(contents, 0, contents.length) | 72 ..writeListSync(contents, 0, contents.length) |
74 ..closeSync(); | 73 ..closeSync(); |
75 log.fine("Wrote text file $file."); | 74 log.fine("Wrote text file $file."); |
76 return file; | 75 return file; |
77 } | 76 } |
78 | 77 |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
119 /// Creates a temp directory whose name will be based on [dir] with a unique | 118 /// Creates a temp directory whose name will be based on [dir] with a unique |
120 /// suffix appended to it. If [dir] is not provided, a temp directory will be | 119 /// suffix appended to it. If [dir] is not provided, a temp directory will be |
121 /// created in a platform-dependent temporary location. Returns the path of the | 120 /// created in a platform-dependent temporary location. Returns the path of the |
122 /// created directory. | 121 /// created directory. |
123 String createTempDir([dir = '']) { | 122 String createTempDir([dir = '']) { |
124 var tempDir = new Directory(dir).createTempSync(); | 123 var tempDir = new Directory(dir).createTempSync(); |
125 log.io("Created temp directory ${tempDir.path}"); | 124 log.io("Created temp directory ${tempDir.path}"); |
126 return tempDir.path; | 125 return tempDir.path; |
127 } | 126 } |
128 | 127 |
129 /// Recursively deletes [dir]. | |
130 void deleteDir(String dir) { | |
131 log.io("Deleting directory $dir."); | |
132 new Directory(dir).deleteSync(recursive: true); | |
133 } | |
134 | |
135 /// Asynchronously lists the contents of [dir]. If [recursive] is `true`, lists | 128 /// Asynchronously lists the contents of [dir]. If [recursive] is `true`, lists |
136 /// subdirectory contents (defaults to `false`). If [includeHiddenFiles] is | 129 /// subdirectory contents (defaults to `false`). If [includeHiddenFiles] is |
137 /// `true`, includes files and directories beginning with `.` (defaults to | 130 /// `true`, includes files and directories beginning with `.` (defaults to |
138 /// `false`). | 131 /// `false`). |
139 /// | 132 /// |
140 /// If [dir] is a string, the returned paths are guaranteed to begin with it. | 133 /// If [dir] is a string, the returned paths are guaranteed to begin with it. |
141 Future<List<String>> listDir(String dir, | 134 Future<List<String>> listDir(String dir, |
142 {bool recursive: false, bool includeHiddenFiles: false}) { | 135 {bool recursive: false, bool includeHiddenFiles: false}) { |
143 Future<List<String>> doList(String dir, Set<String> listedDirectories) { | 136 Future<List<String>> doList(String dir, Set<String> listedDirectories) { |
144 var contents = <String>[]; | 137 var contents = <String>[]; |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
192 return Future.wait(children).then((childContents) { | 185 return Future.wait(children).then((childContents) { |
193 contents.addAll(flatten(childContents)); | 186 contents.addAll(flatten(childContents)); |
194 return contents; | 187 return contents; |
195 }); | 188 }); |
196 }); | 189 }); |
197 } | 190 } |
198 | 191 |
199 return doList(dir, new Set<String>()); | 192 return doList(dir, new Set<String>()); |
200 } | 193 } |
201 | 194 |
202 /// Determines if [dir] exists on the file system. | 195 /// Returns whether [dir] exists on the file system. This will return `true` for |
| 196 /// a symlink only if that symlink is unbroken and points to a directory. |
203 bool dirExists(String dir) => new Directory(dir).existsSync(); | 197 bool dirExists(String dir) => new Directory(dir).existsSync(); |
204 | 198 |
| 199 /// Deletes whatever's at [path], whether it's a file, directory, or symlink. If |
| 200 /// it's a directory, it will be deleted recursively. |
| 201 void deleteEntry(String path) { |
| 202 if (linkExists(path)) { |
| 203 log.io("Deleting link $path."); |
| 204 new Link(path).deleteSync(); |
| 205 } else if (dirExists(path)) { |
| 206 log.io("Deleting directory $path."); |
| 207 new Directory(path).deleteSync(recursive: true); |
| 208 } else { |
| 209 log.io("Deleting file $path."); |
| 210 new File(path).deleteSync(); |
| 211 } |
| 212 } |
| 213 |
205 /// "Cleans" [dir]. If that directory already exists, it will be deleted. Then a | 214 /// "Cleans" [dir]. If that directory already exists, it will be deleted. Then a |
206 /// new empty directory will be created. | 215 /// new empty directory will be created. |
207 void cleanDir(String dir) { | 216 void cleanDir(String dir) { |
208 if (dirExists(dir)) { | 217 if (entryExists(dir)) deleteEntry(dir); |
209 // Delete it first. | |
210 deleteDir(dir); | |
211 } else if (fileExists(dir)) { | |
212 // If there is a non-directory there (file or symlink), delete it. | |
213 deleteFile(dir); | |
214 } | |
215 | |
216 // Just create it. | |
217 createDir(dir); | 218 createDir(dir); |
218 } | 219 } |
219 | 220 |
220 /// Renames (i.e. moves) the directory [from] to [to]. | 221 /// Renames (i.e. moves) the directory [from] to [to]. |
221 void renameDir(String from, String to) { | 222 void renameDir(String from, String to) { |
222 log.io("Renaming directory $from to $to."); | 223 log.io("Renaming directory $from to $to."); |
223 new Directory(from).renameSync(to); | 224 new Directory(from).renameSync(to); |
224 } | 225 } |
225 | 226 |
226 /// Creates a new symlink at path [symlink] that points to [target]. Returns a | 227 /// Creates a new symlink at path [symlink] that points to [target]. Returns a |
(...skipping 348 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
575 /// returned by [fn] completes, the temporary directory and all its contents | 576 /// returned by [fn] completes, the temporary directory and all its contents |
576 /// will be deleted. [fn] can also return `null`, in which case the temporary | 577 /// will be deleted. [fn] can also return `null`, in which case the temporary |
577 /// directory is deleted immediately afterwards. | 578 /// directory is deleted immediately afterwards. |
578 /// | 579 /// |
579 /// Returns a future that completes to the value that the future returned from | 580 /// Returns a future that completes to the value that the future returned from |
580 /// [fn] completes to. | 581 /// [fn] completes to. |
581 Future withTempDir(Future fn(String path)) { | 582 Future withTempDir(Future fn(String path)) { |
582 return defer(() { | 583 return defer(() { |
583 var tempDir = createTempDir(); | 584 var tempDir = createTempDir(); |
584 return new Future.of(() => fn(tempDir)) | 585 return new Future.of(() => fn(tempDir)) |
585 .whenComplete(() => deleteDir(tempDir)); | 586 .whenComplete(() => deleteEntry(tempDir)); |
586 }); | 587 }); |
587 } | 588 } |
588 | 589 |
589 /// Extracts a `.tar.gz` file from [stream] to [destination]. Returns whether | 590 /// Extracts a `.tar.gz` file from [stream] to [destination]. Returns whether |
590 /// or not the extraction was successful. | 591 /// or not the extraction was successful. |
591 Future<bool> extractTarGz(Stream<List<int>> stream, String destination) { | 592 Future<bool> extractTarGz(Stream<List<int>> stream, String destination) { |
592 log.fine("Extracting .tar.gz stream to $destination."); | 593 log.fine("Extracting .tar.gz stream to $destination."); |
593 | 594 |
594 if (Platform.operatingSystem == "windows") { | 595 if (Platform.operatingSystem == "windows") { |
595 return _extractTarGzWindows(stream, destination); | 596 return _extractTarGzWindows(stream, destination); |
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
765 const PubProcessResult(this.stdout, this.stderr, this.exitCode); | 766 const PubProcessResult(this.stdout, this.stderr, this.exitCode); |
766 | 767 |
767 bool get success => exitCode == 0; | 768 bool get success => exitCode == 0; |
768 } | 769 } |
769 | 770 |
770 /// Gets a [Uri] for [uri], which can either already be one, or be a [String]. | 771 /// Gets a [Uri] for [uri], which can either already be one, or be a [String]. |
771 Uri _getUri(uri) { | 772 Uri _getUri(uri) { |
772 if (uri is Uri) return uri; | 773 if (uri is Uri) return uri; |
773 return Uri.parse(uri); | 774 return Uri.parse(uri); |
774 } | 775 } |
OLD | NEW |