| Index: tool/input_sdk/lib/io/directory_impl.dart
|
| diff --git a/tool/input_sdk/lib/io/directory_impl.dart b/tool/input_sdk/lib/io/directory_impl.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..52cf54824ecf4e8ed14a4b5491ade076c4a32471
|
| --- /dev/null
|
| +++ b/tool/input_sdk/lib/io/directory_impl.dart
|
| @@ -0,0 +1,428 @@
|
| +// 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.
|
| +
|
| +part of dart.io;
|
| +
|
| +class _Directory extends FileSystemEntity implements Directory {
|
| + final String path;
|
| +
|
| + _Directory(this.path) {
|
| + if (path is! String) {
|
| + throw new ArgumentError('${Error.safeToString(path)} '
|
| + 'is not a String');
|
| + }
|
| + }
|
| +
|
| + external static _current();
|
| + external static _setCurrent(path);
|
| + external static _createTemp(String path);
|
| + external static String _systemTemp();
|
| + external static _exists(String path);
|
| + external static _create(String path);
|
| + external static _deleteNative(String path, bool recursive);
|
| + external static _rename(String path, String newPath);
|
| + external static void _fillWithDirectoryListing(
|
| + List<FileSystemEntity> list, String path, bool recursive,
|
| + bool followLinks);
|
| +
|
| + static Directory get current {
|
| + var result = _current();
|
| + if (result is OSError) {
|
| + throw new FileSystemException(
|
| + "Getting current working directory failed", "", result);
|
| + }
|
| + return new _Directory(result);
|
| + }
|
| +
|
| + static void set current(path) {
|
| + if (path is Directory) path = path.path;
|
| + var result = _setCurrent(path);
|
| + if (result is ArgumentError) throw result;
|
| + if (result is OSError) {
|
| + throw new FileSystemException(
|
| + "Setting current working directory failed", path, result);
|
| + }
|
| + }
|
| +
|
| + Uri get uri {
|
| + return new Uri.directory(path);
|
| + }
|
| +
|
| + Future<bool> exists() {
|
| + return _IOService._dispatch(_DIRECTORY_EXISTS, [path]).then((response) {
|
| + if (_isErrorResponse(response)) {
|
| + throw _exceptionOrErrorFromResponse(response, "Exists failed");
|
| + }
|
| + return response == 1;
|
| + });
|
| + }
|
| +
|
| + bool existsSync() {
|
| + var result = _exists(path);
|
| + if (result is OSError) {
|
| + throw new FileSystemException("Exists failed", path, result);
|
| + }
|
| + return (result == 1);
|
| + }
|
| +
|
| + Directory get absolute => new Directory(_absolutePath);
|
| +
|
| + Future<FileStat> stat() => FileStat.stat(path);
|
| +
|
| + FileStat statSync() => FileStat.statSync(path);
|
| +
|
| + // Compute the index of the first directory in the list that exists. If
|
| + // none of the directories exist dirsToCreate.length is returned.
|
| + Future<int> _computeExistingIndex(List dirsToCreate) {
|
| + var future;
|
| + var notFound = dirsToCreate.length;
|
| + for (var i = 0; i < dirsToCreate.length; i++) {
|
| + if (future == null) {
|
| + future = dirsToCreate[i].exists().then((e) => e ? i : notFound);
|
| + } else {
|
| + future = future.then((index) {
|
| + if (index != notFound) {
|
| + return new Future.value(index);
|
| + }
|
| + return dirsToCreate[i].exists().then((e) => e ? i : notFound);
|
| + });
|
| + }
|
| + }
|
| + if (future == null) {
|
| + return new Future.value(notFound);
|
| + } else {
|
| + return future;
|
| + }
|
| + }
|
| +
|
| + Future<Directory> create({bool recursive: false}) {
|
| + if (recursive) {
|
| + return exists().then((exists) {
|
| + if (exists) return this;
|
| + if (path != parent.path) {
|
| + return parent.create(recursive: true).then((_) {
|
| + return create();
|
| + });
|
| + } else {
|
| + return create();
|
| + }
|
| + });
|
| + } else {
|
| + return _IOService._dispatch(_DIRECTORY_CREATE, [path]).then((response) {
|
| + if (_isErrorResponse(response)) {
|
| + throw _exceptionOrErrorFromResponse(response, "Creation failed");
|
| + }
|
| + return this;
|
| + });
|
| + }
|
| + }
|
| +
|
| + void createSync({bool recursive: false}) {
|
| + if (recursive) {
|
| + if (existsSync()) return;
|
| + if (path != parent.path) {
|
| + parent.createSync(recursive: true);
|
| + }
|
| + }
|
| + var result = _create(path);
|
| + if (result is OSError) {
|
| + throw new FileSystemException("Creation failed", path, result);
|
| + }
|
| + }
|
| +
|
| + static Directory get systemTemp => new Directory(_systemTemp());
|
| +
|
| + Future<Directory> createTemp([String prefix]) {
|
| + if (prefix == null) prefix = '';
|
| + if (path == '') {
|
| + throw new ArgumentError(
|
| + "Directory.createTemp called with an empty path. "
|
| + "To use the system temp directory, use Directory.systemTemp");
|
| + }
|
| + String fullPrefix;
|
| + if (path.endsWith('/') || (Platform.isWindows && path.endsWith('\\'))) {
|
| + fullPrefix = "$path$prefix";
|
| + } else {
|
| + fullPrefix = "$path${Platform.pathSeparator}$prefix";
|
| + }
|
| + return _IOService._dispatch(_DIRECTORY_CREATE_TEMP, [fullPrefix])
|
| + .then((response) {
|
| + if (_isErrorResponse(response)) {
|
| + throw _exceptionOrErrorFromResponse(
|
| + response, "Creation of temporary directory failed");
|
| + }
|
| + return new Directory(response);
|
| + });
|
| + }
|
| +
|
| + Directory createTempSync([String prefix]) {
|
| + if (prefix == null) prefix = '';
|
| + if (path == '') {
|
| + throw new ArgumentError(
|
| + "Directory.createTemp called with an empty path. "
|
| + "To use the system temp directory, use Directory.systemTemp");
|
| + }
|
| + String fullPrefix;
|
| + if (path.endsWith('/') || (Platform.isWindows && path.endsWith('\\'))) {
|
| + fullPrefix = "$path$prefix";
|
| + } else {
|
| + fullPrefix = "$path${Platform.pathSeparator}$prefix";
|
| + }
|
| + var result = _createTemp(fullPrefix);
|
| + if (result is OSError) {
|
| + throw new FileSystemException("Creation of temporary directory failed",
|
| + fullPrefix,
|
| + result);
|
| + }
|
| + return new Directory(result);
|
| + }
|
| +
|
| + Future<Directory> _delete({bool recursive: false}) {
|
| + return _IOService._dispatch(_DIRECTORY_DELETE, [path, recursive])
|
| + .then((response) {
|
| + if (_isErrorResponse(response)) {
|
| + throw _exceptionOrErrorFromResponse(response, "Deletion failed");
|
| + }
|
| + return this;
|
| + });
|
| + }
|
| +
|
| + void _deleteSync({bool recursive: false}) {
|
| + var result = _deleteNative(path, recursive);
|
| + if (result is OSError) {
|
| + throw new FileSystemException("Deletion failed", path, result);
|
| + }
|
| + }
|
| +
|
| + Future<Directory> rename(String newPath) {
|
| + return _IOService._dispatch(_DIRECTORY_RENAME, [path, newPath])
|
| + .then((response) {
|
| + if (_isErrorResponse(response)) {
|
| + throw _exceptionOrErrorFromResponse(response, "Rename failed");
|
| + }
|
| + return new Directory(newPath);
|
| + });
|
| + }
|
| +
|
| + Directory renameSync(String newPath) {
|
| + if (newPath is !String) {
|
| + throw new ArgumentError();
|
| + }
|
| + var result = _rename(path, newPath);
|
| + if (result is OSError) {
|
| + throw new FileSystemException("Rename failed", path, result);
|
| + }
|
| + return new Directory(newPath);
|
| + }
|
| +
|
| + Stream<FileSystemEntity> list({bool recursive: false,
|
| + bool followLinks: true}) {
|
| + return new _AsyncDirectoryLister(
|
| + FileSystemEntity._ensureTrailingPathSeparators(path),
|
| + recursive,
|
| + followLinks).stream;
|
| + }
|
| +
|
| + List<FileSystemEntity> listSync(
|
| + {bool recursive: false, bool followLinks: true}) {
|
| + if (recursive is! bool || followLinks is! bool) {
|
| + throw new ArgumentError();
|
| + }
|
| + var result = <FileSystemEntity>[];
|
| + _fillWithDirectoryListing(
|
| + result,
|
| + FileSystemEntity._ensureTrailingPathSeparators(path),
|
| + recursive,
|
| + followLinks);
|
| + return result;
|
| + }
|
| +
|
| + String toString() => "Directory: '$path'";
|
| +
|
| + bool _isErrorResponse(response) =>
|
| + response is List && response[0] != _SUCCESS_RESPONSE;
|
| +
|
| + _exceptionOrErrorFromResponse(response, String message) {
|
| + assert(_isErrorResponse(response));
|
| + switch (response[_ERROR_RESPONSE_ERROR_TYPE]) {
|
| + case _ILLEGAL_ARGUMENT_RESPONSE:
|
| + return new ArgumentError();
|
| + case _OSERROR_RESPONSE:
|
| + var err = new OSError(response[_OSERROR_RESPONSE_MESSAGE],
|
| + response[_OSERROR_RESPONSE_ERROR_CODE]);
|
| + return new FileSystemException(message, path, err);
|
| + default:
|
| + return new Exception("Unknown error");
|
| + }
|
| + }
|
| +}
|
| +
|
| +abstract class _AsyncDirectoryListerOps {
|
| + external factory _AsyncDirectoryListerOps(int pointer);
|
| +
|
| + int getPointer();
|
| +}
|
| +
|
| +class _AsyncDirectoryLister {
|
| + static const int LIST_FILE = 0;
|
| + static const int LIST_DIRECTORY = 1;
|
| + static const int LIST_LINK = 2;
|
| + static const int LIST_ERROR = 3;
|
| + static const int LIST_DONE = 4;
|
| +
|
| + static const int RESPONSE_TYPE = 0;
|
| + static const int RESPONSE_PATH = 1;
|
| + static const int RESPONSE_COMPLETE = 1;
|
| + static const int RESPONSE_ERROR = 2;
|
| +
|
| + final String path;
|
| + final bool recursive;
|
| + final bool followLinks;
|
| +
|
| + StreamController controller;
|
| + bool canceled = false;
|
| + bool nextRunning = false;
|
| + bool closed = false;
|
| + _AsyncDirectoryListerOps _ops;
|
| + Completer closeCompleter = new Completer();
|
| +
|
| + _AsyncDirectoryLister(this.path, this.recursive, this.followLinks) {
|
| + controller = new StreamController(onListen: onListen,
|
| + onResume: onResume,
|
| + onCancel: onCancel,
|
| + sync: true);
|
| + }
|
| +
|
| + // Calling this function will increase the reference count on the native
|
| + // object that implements the async directory lister operations. It should
|
| + // only be called to pass the pointer to the IO Service, which will decrement
|
| + // the reference count when it is finished with it.
|
| + int _pointer() {
|
| + return (_ops == null) ? null : _ops.getPointer();
|
| + }
|
| +
|
| + Stream get stream => controller.stream;
|
| +
|
| + void onListen() {
|
| + _IOService._dispatch(_DIRECTORY_LIST_START, [path, recursive, followLinks])
|
| + .then((response) {
|
| + if (response is int) {
|
| + _ops = new _AsyncDirectoryListerOps(response);
|
| + next();
|
| + } else if (response is Error) {
|
| + controller.addError(response, response.stackTrace);
|
| + close();
|
| + } else {
|
| + error(response);
|
| + close();
|
| + }
|
| + });
|
| + }
|
| +
|
| + void onResume() {
|
| + if (!nextRunning) {
|
| + next();
|
| + }
|
| + }
|
| +
|
| + Future onCancel() {
|
| + canceled = true;
|
| + // If we are active, but not requesting, close.
|
| + if (!nextRunning) {
|
| + close();
|
| + }
|
| +
|
| + return closeCompleter.future;
|
| + }
|
| +
|
| + void next() {
|
| + if (canceled) {
|
| + close();
|
| + return;
|
| + }
|
| + if (controller.isPaused || nextRunning) {
|
| + return;
|
| + }
|
| + var pointer = _pointer();
|
| + if (pointer == null) {
|
| + return;
|
| + }
|
| + nextRunning = true;
|
| + _IOService._dispatch(_DIRECTORY_LIST_NEXT, [pointer]).then((result) {
|
| + nextRunning = false;
|
| + if (result is List) {
|
| + next();
|
| + assert(result.length % 2 == 0);
|
| + for (int i = 0; i < result.length; i++) {
|
| + assert(i % 2 == 0);
|
| + switch (result[i++]) {
|
| + case LIST_FILE:
|
| + controller.add(new File(result[i]));
|
| + break;
|
| + case LIST_DIRECTORY:
|
| + controller.add(new Directory(result[i]));
|
| + break;
|
| + case LIST_LINK:
|
| + controller.add(new Link(result[i]));
|
| + break;
|
| + case LIST_ERROR:
|
| + error(result[i]);
|
| + break;
|
| + case LIST_DONE:
|
| + canceled = true;
|
| + return;
|
| + }
|
| + }
|
| + } else {
|
| + controller.addError(new FileSystemException("Internal error"));
|
| + }
|
| + });
|
| + }
|
| +
|
| + void _cleanup() {
|
| + controller.close();
|
| + closeCompleter.complete();
|
| + _ops = null;
|
| + }
|
| +
|
| + void close() {
|
| + if (closed) {
|
| + return;
|
| + }
|
| + if (nextRunning) {
|
| + return;
|
| + }
|
| + closed = true;
|
| +
|
| + var pointer = _pointer();
|
| + if (pointer == null) {
|
| + _cleanup();
|
| + } else {
|
| + _IOService._dispatch(_DIRECTORY_LIST_STOP, [pointer])
|
| + .whenComplete(_cleanup);
|
| + }
|
| + }
|
| +
|
| + void error(message) {
|
| + var errorType =
|
| + message[RESPONSE_ERROR][_ERROR_RESPONSE_ERROR_TYPE];
|
| + if (errorType == _ILLEGAL_ARGUMENT_RESPONSE) {
|
| + controller.addError(new ArgumentError());
|
| + } else if (errorType == _OSERROR_RESPONSE) {
|
| + var responseError = message[RESPONSE_ERROR];
|
| + var err = new OSError(
|
| + responseError[_OSERROR_RESPONSE_MESSAGE],
|
| + responseError[_OSERROR_RESPONSE_ERROR_CODE]);
|
| + var errorPath = message[RESPONSE_PATH];
|
| + if (errorPath == null) errorPath = path;
|
| + controller.addError(
|
| + new FileSystemException("Directory listing failed",
|
| + errorPath,
|
| + err));
|
| + } else {
|
| + controller.addError(
|
| + new FileSystemException("Internal error"));
|
| + }
|
| + }
|
| +}
|
|
|