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

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

Issue 10091014: Start implementing pub object model. Rudimentary package cache class, and a simple pub command to l… (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Packages now only load their dependencies on-demand (and asynchronously). Created 8 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
OLDNEW
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 /**
6 * Helper functionality to make working with IO easier.
7 */
8 #library('pub_io');
9
10 #import('dart:io');
11
12 #import('../lib/file_system.dart', prefix: 'fs');
13
14 /**
15 * Joins a number of path string parts into a single path. Handles
16 * platform-specific path separators. Parts can be [String], [Directory], or
17 * [File] objects.
18 */
19 String join(part1, [part2, part3, part4]) {
20 final parts = _getPath(part1).split('/');
21
22 for (final part in [part2, part3, part4]) {
23 if (part == null) continue;
24
25 for (final piece in _getPath(part).split('/')) {
26 if (piece == '..' && parts.length > 0 &&
nweiz 2012/04/17 20:08:46 Unless you have a good reason to try and clean up
Bob Nystrom 2012/04/18 18:09:18 This is mostly copied from file_system and I have
27 parts.last() != '.' && parts.last() != '..') {
28 parts.removeLast();
29 } else if (piece != '') {
30 if (parts.length > 0 && parts.last() == '.') {
31 parts.removeLast();
32 }
33 parts.add(piece);
34 }
35 }
36 }
37
38 return Strings.join(parts, new Platform().pathSeparator());
39 }
40
41 /**
42 * Gets the basename, the file name without any leading directory path, for
43 * [file], which can either be a [String], [File], or [Directory].
44 */
45 String basename(file) {
46 return fs.basename(_getPath(file));
47 }
48
49 /**
50 * Reads the contents of the text file [file], which can either be a [String] or
51 * a [File].
52 */
53 Future<String> readTextFile(file) {
54 file = new File(_getPath(file));
55 final completer = new Completer<String>();
56 file.onError = (error) => completer.completeException(error);
57 file.readAsText(Encoding.UTF_8, (text) {
58 completer.complete(text);
nweiz 2012/04/17 20:08:46 I don't understand your heuristic for when you use
Bob Nystrom 2012/04/18 18:09:18 It was apparently based on astrology. Made less cr
59 });
60
61 return completer.future;
62 }
63
64 /**
65 * Creates [file] (which can either be a [String] or a [File]), and writes
66 * [contents] to it. Completes when the file is written and closed.
67 */
68 Future<File> writeTextFile(file, String contents) {
69 file = new File(_getPath(file));
70 final completer = new Completer<File>();
71 file.onError = (error) => completer.completeException(error);
72 file.open(FileMode.WRITE, (opened) {
73 opened.onError = (error) => completer.completeException(error);
74 opened.onNoPendingWrites = () {
75 opened.close(() {
76 completer.complete(file);
77 });
78 };
79 opened.writeString(contents);
80 });
81
82 return completer.future;
83 }
84
85 /**
86 * Creates a directory [dir]. Returns a [Future] that completes when the
87 * directory is created.
88 */
89 Future<Directory> createDir(dir) {
90 final completer = new Completer<Directory>();
91 dir = _getDirectory(dir);
92 dir.onError = (error) => completer.completeException(error);
93 dir.create(() {
94 completer.complete(dir);
95 });
96
97 return completer.future;
98 }
99
100 /**
101 * Creates a temp directory whose name will be based on [dir] with a unique
102 * suffix appended to it. Returns a [Future] that completes when the directory
103 * is created.
104 */
105 Future<Directory> createTempDir(dir) {
106 final completer = new Completer<Directory>();
107 dir = _getDirectory(dir);
108 dir.onError = (error) => completer.completeException(error);
109 dir.createTemp(() {
110 completer.complete(dir);
111 });
112
113 return completer.future;
114 }
115
116 /**
117 * Asynchronously recursively deletes [dir], which can be a [String] or a
118 * [Directory]. Returns a [Future] that completes when the deletion is done.
119 */
120 Future<Directory> deleteDir(dir) {
121 final completer = new Completer<Directory>();
122 dir = _getDirectory(dir);
123 dir.onError = (error) => completer.completeException(error);
124 dir.deleteRecursively(() {
125 completer.complete(dir);
126 });
127
128 return completer.future;
129 }
130
131 /**
132 * Asynchronously lists the contents of [dir], which can be a [String] directory
133 * path or a [Directory]. If [recursive] is `true`, lists subdirectory contents
134 * (defaults to `false`). If [includeSpecialFiles] is `true`, includes "hidden"
135 * files like `.DS_Store` (defaults to `false`).
136 */
137 Future<List<String>> listDir(dir,
138 [bool recursive = false, bool includeSpecialFiles = false]) {
139 final completer = new Completer<List<String>>();
140 final contents = <String>[];
141
142 dir = _getDirectory(dir);
143
144 dir.onDone = (done) {
nweiz 2012/04/17 20:08:46 nit: extra space after "Done". What are the seman
Bob Nystrom 2012/04/18 18:09:18 Done.
145 if (done) completer.complete(contents);
146 };
147
148 dir.onError = (error) {
149 completer.completeException(error);
150 };
151
152 dir.onDir = (file) {
153 contents.add(file);
154 };
155
156 dir.onFile = (file) {
157 if (!includeSpecialFiles) {
158 if (basename(file) == '.DS_Store') return;
nweiz 2012/04/17 20:08:46 The documentation implies that this is going to fi
Bob Nystrom 2012/04/18 18:09:18 Clarified docs.
159 }
160
161 contents.add(file);
162 };
163
164 dir.list(recursive: recursive);
165
166 return completer.future;
167 }
168
169 /**
170 * Spawns and runs the process located at [executable], passing in [args].
171 * Returns a [Future] that will complete the results of the process after it
172 * has ended.
173 */
174 Future<ProcessResult> runProcess(String executable, List<String> args) {
175 var exitCode;
nweiz 2012/04/17 20:08:46 Explicitly type this because it's not being initia
Bob Nystrom 2012/04/18 18:09:18 Done.
176 var error;
nweiz 2012/04/17 20:08:46 Unused variable
Bob Nystrom 2012/04/18 18:09:18 Done.
177
178 final process = new Process.start(executable, args);
179
180 final outStream = new StringInputStream(process.stdout);
181 final processStdout = <String>[];
182
183 final errStream = new StringInputStream(process.stderr);
184 final processStderr = <String>[];
185 bool processDone = false;
nweiz 2012/04/17 20:08:46 var or final
Bob Nystrom 2012/04/18 18:09:18 Unused.
186
187 final completer = new Completer<ProcessResult>();
188
189 checkComplete() {
190 // Wait until the process is done and its output streams are closed.
191 if (!outStream.closed) return;
192 if (!errStream.closed) return;
193 if (exitCode == null) return;
194
195 completer.complete(new ProcessResult(
196 processStdout, processStderr, exitCode));
197 }
198
199 outStream.onLine = () {
200 processStdout.add(outStream.readLine());
201 };
202
203 outStream.onClosed = checkComplete;
204 outStream.onError = (error) => completer.completeException(error);
205
206 errStream.onLine = () {
207 processStderr.add(errStream.readLine());
208 };
209
210 errStream.onClosed = checkComplete;
211 errStream.onError = (error) => completer.completeException(error);
212
213 process.onExit = (actualExitCode) {
214 exitCode = actualExitCode;
215 checkComplete();
216 };
217
218 process.onError = (error) => completer.completeException(error);
219
220 return completer.future;
221 }
222
223 /**
224 * Contains the results of invoking a [Process] and waiting for it to complete.
225 */
226 class ProcessResult {
227 final List<String> stdout;
228 final List<String> stderr;
229 final int exitCode;
230
231 const ProcessResult(this.stdout, this.stderr, this.exitCode);
232 }
233
234 /**
235 * Gets the path string for [entry], which can either already be a path string,
236 * or be a [File] or [Directory]. Allows working generically with "file-like"
237 * objects.
238 */
239 String _getPath(entry) {
240 if (entry is String) return entry;
241 if (entry is File) return entry.name;
242 if (entry is Directory) return entry.path;
243 throw 'Entry $entry is not a supported type.';
244 }
245
246 /**
247 * Gets a [Directory] for [entry], which can either already be one, or be a
248 * [String].
249 */
250 Directory _getDirectory(entry) {
251 if (entry is Directory) return entry;
252 return new Directory(entry);
253 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698