Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(633)

Side by Side Diff: utils/pub/io.dart

Issue 13116020: Clean up the semantics of io.dart operations w.r.t. symlinks. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Code review changes Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « utils/pub/entrypoint.dart ('k') | utils/pub/oauth2.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « utils/pub/entrypoint.dart ('k') | utils/pub/oauth2.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698