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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: utils/pub/io.dart
diff --git a/utils/pub/io.dart b/utils/pub/io.dart
new file mode 100644
index 0000000000000000000000000000000000000000..57788941f869367b875edde519cc355b4307de81
--- /dev/null
+++ b/utils/pub/io.dart
@@ -0,0 +1,253 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * Helper functionality to make working with IO easier.
+ */
+#library('pub_io');
+
+#import('dart:io');
+
+#import('../lib/file_system.dart', prefix: 'fs');
+
+/**
+ * Joins a number of path string parts into a single path. Handles
+ * platform-specific path separators. Parts can be [String], [Directory], or
+ * [File] objects.
+ */
+String join(part1, [part2, part3, part4]) {
+ final parts = _getPath(part1).split('/');
+
+ for (final part in [part2, part3, part4]) {
+ if (part == null) continue;
+
+ for (final piece in _getPath(part).split('/')) {
+ 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
+ parts.last() != '.' && parts.last() != '..') {
+ parts.removeLast();
+ } else if (piece != '') {
+ if (parts.length > 0 && parts.last() == '.') {
+ parts.removeLast();
+ }
+ parts.add(piece);
+ }
+ }
+ }
+
+ return Strings.join(parts, new Platform().pathSeparator());
+}
+
+/**
+ * Gets the basename, the file name without any leading directory path, for
+ * [file], which can either be a [String], [File], or [Directory].
+ */
+String basename(file) {
+ return fs.basename(_getPath(file));
+}
+
+/**
+ * Reads the contents of the text file [file], which can either be a [String] or
+ * a [File].
+ */
+Future<String> readTextFile(file) {
+ file = new File(_getPath(file));
+ final completer = new Completer<String>();
+ file.onError = (error) => completer.completeException(error);
+ file.readAsText(Encoding.UTF_8, (text) {
+ 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
+ });
+
+ return completer.future;
+}
+
+/**
+ * Creates [file] (which can either be a [String] or a [File]), and writes
+ * [contents] to it. Completes when the file is written and closed.
+ */
+Future<File> writeTextFile(file, String contents) {
+ file = new File(_getPath(file));
+ final completer = new Completer<File>();
+ file.onError = (error) => completer.completeException(error);
+ file.open(FileMode.WRITE, (opened) {
+ opened.onError = (error) => completer.completeException(error);
+ opened.onNoPendingWrites = () {
+ opened.close(() {
+ completer.complete(file);
+ });
+ };
+ opened.writeString(contents);
+ });
+
+ return completer.future;
+}
+
+/**
+ * Creates a directory [dir]. Returns a [Future] that completes when the
+ * directory is created.
+ */
+Future<Directory> createDir(dir) {
+ final completer = new Completer<Directory>();
+ dir = _getDirectory(dir);
+ dir.onError = (error) => completer.completeException(error);
+ dir.create(() {
+ completer.complete(dir);
+ });
+
+ return completer.future;
+}
+
+/**
+ * Creates a temp directory whose name will be based on [dir] with a unique
+ * suffix appended to it. Returns a [Future] that completes when the directory
+ * is created.
+ */
+Future<Directory> createTempDir(dir) {
+ final completer = new Completer<Directory>();
+ dir = _getDirectory(dir);
+ dir.onError = (error) => completer.completeException(error);
+ dir.createTemp(() {
+ completer.complete(dir);
+ });
+
+ return completer.future;
+}
+
+/**
+ * Asynchronously recursively deletes [dir], which can be a [String] or a
+ * [Directory]. Returns a [Future] that completes when the deletion is done.
+ */
+Future<Directory> deleteDir(dir) {
+ final completer = new Completer<Directory>();
+ dir = _getDirectory(dir);
+ dir.onError = (error) => completer.completeException(error);
+ dir.deleteRecursively(() {
+ completer.complete(dir);
+ });
+
+ return completer.future;
+}
+
+/**
+ * Asynchronously lists the contents of [dir], which can be a [String] directory
+ * path or a [Directory]. If [recursive] is `true`, lists subdirectory contents
+ * (defaults to `false`). If [includeSpecialFiles] is `true`, includes "hidden"
+ * files like `.DS_Store` (defaults to `false`).
+ */
+Future<List<String>> listDir(dir,
+ [bool recursive = false, bool includeSpecialFiles = false]) {
+ final completer = new Completer<List<String>>();
+ final contents = <String>[];
+
+ dir = _getDirectory(dir);
+
+ 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.
+ if (done) completer.complete(contents);
+ };
+
+ dir.onError = (error) {
+ completer.completeException(error);
+ };
+
+ dir.onDir = (file) {
+ contents.add(file);
+ };
+
+ dir.onFile = (file) {
+ if (!includeSpecialFiles) {
+ 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.
+ }
+
+ contents.add(file);
+ };
+
+ dir.list(recursive: recursive);
+
+ return completer.future;
+}
+
+/**
+ * Spawns and runs the process located at [executable], passing in [args].
+ * Returns a [Future] that will complete the results of the process after it
+ * has ended.
+ */
+Future<ProcessResult> runProcess(String executable, List<String> args) {
+ 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.
+ var error;
nweiz 2012/04/17 20:08:46 Unused variable
Bob Nystrom 2012/04/18 18:09:18 Done.
+
+ final process = new Process.start(executable, args);
+
+ final outStream = new StringInputStream(process.stdout);
+ final processStdout = <String>[];
+
+ final errStream = new StringInputStream(process.stderr);
+ final processStderr = <String>[];
+ bool processDone = false;
nweiz 2012/04/17 20:08:46 var or final
Bob Nystrom 2012/04/18 18:09:18 Unused.
+
+ final completer = new Completer<ProcessResult>();
+
+ checkComplete() {
+ // Wait until the process is done and its output streams are closed.
+ if (!outStream.closed) return;
+ if (!errStream.closed) return;
+ if (exitCode == null) return;
+
+ completer.complete(new ProcessResult(
+ processStdout, processStderr, exitCode));
+ }
+
+ outStream.onLine = () {
+ processStdout.add(outStream.readLine());
+ };
+
+ outStream.onClosed = checkComplete;
+ outStream.onError = (error) => completer.completeException(error);
+
+ errStream.onLine = () {
+ processStderr.add(errStream.readLine());
+ };
+
+ errStream.onClosed = checkComplete;
+ errStream.onError = (error) => completer.completeException(error);
+
+ process.onExit = (actualExitCode) {
+ exitCode = actualExitCode;
+ checkComplete();
+ };
+
+ process.onError = (error) => completer.completeException(error);
+
+ return completer.future;
+}
+
+/**
+ * Contains the results of invoking a [Process] and waiting for it to complete.
+ */
+class ProcessResult {
+ final List<String> stdout;
+ final List<String> stderr;
+ final int exitCode;
+
+ const ProcessResult(this.stdout, this.stderr, this.exitCode);
+}
+
+/**
+ * Gets the path string for [entry], which can either already be a path string,
+ * or be a [File] or [Directory]. Allows working generically with "file-like"
+ * objects.
+ */
+String _getPath(entry) {
+ if (entry is String) return entry;
+ if (entry is File) return entry.name;
+ if (entry is Directory) return entry.path;
+ throw 'Entry $entry is not a supported type.';
+}
+
+/**
+ * Gets a [Directory] for [entry], which can either already be one, or be a
+ * [String].
+ */
+Directory _getDirectory(entry) {
+ if (entry is Directory) return entry;
+ return new Directory(entry);
+}

Powered by Google App Engine
This is Rietveld 408576698