| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 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 | 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 | 5 |
| 6 // Used for holding error code and error message for failed OS system calls. | 6 // Used for holding error code and error message for failed OS system calls. |
| 7 class _OSStatus { | 7 class _OSStatus { |
| 8 int _errorCode; | 8 int _errorCode; |
| 9 String _errorMessage; | 9 String _errorMessage; |
| 10 } | 10 } |
| 11 | 11 |
| 12 | 12 |
| 13 class _DirectoryListingIsolate extends Isolate { | |
| 14 | |
| 15 _DirectoryListingIsolate() : super.heavy(); | |
| 16 | |
| 17 void main() { | |
| 18 port.receive((message, replyTo) { | |
| 19 bool started = _list(message['dir'], | |
| 20 message['recursive'], | |
| 21 message['dirPort'], | |
| 22 message['filePort'], | |
| 23 message['donePort'], | |
| 24 message['errorPort']); | |
| 25 replyTo.send(started); | |
| 26 port.close(); | |
| 27 }); | |
| 28 } | |
| 29 | |
| 30 bool _list(String dir, | |
| 31 bool recursive, | |
| 32 SendPort dirPort, | |
| 33 SendPort filePort, | |
| 34 SendPort donePort, | |
| 35 SendPort errorPort) native "Directory_List"; | |
| 36 } | |
| 37 | |
| 38 | |
| 39 class _DirectoryOperation { | |
| 40 abstract void execute(ReceivePort port); | |
| 41 | |
| 42 void set replyPort(SendPort port) { | |
| 43 _replyPort = port; | |
| 44 } | |
| 45 | |
| 46 SendPort _replyPort; | |
| 47 } | |
| 48 | |
| 49 | |
| 50 class _DirExitOperation extends _DirectoryOperation { | |
| 51 void execute(ReceivePort port) { | |
| 52 port.close(); | |
| 53 } | |
| 54 } | |
| 55 | |
| 56 | |
| 57 class _DirExistsOperation extends _DirectoryOperation { | |
| 58 _DirExistsOperation(String this._path); | |
| 59 | |
| 60 void execute(ReceivePort port) { | |
| 61 _replyPort.send(_Directory._exists(_path), port.toSendPort()); | |
| 62 } | |
| 63 | |
| 64 String _path; | |
| 65 } | |
| 66 | |
| 67 | |
| 68 class _DirCreateOperation extends _DirectoryOperation { | |
| 69 _DirCreateOperation(String this._path); | |
| 70 | |
| 71 void execute(ReceivePort port) { | |
| 72 _replyPort.send(_Directory._create(_path), port.toSendPort()); | |
| 73 } | |
| 74 | |
| 75 String _path; | |
| 76 } | |
| 77 | |
| 78 | |
| 79 class _DirCreateTempOperation extends _DirectoryOperation { | |
| 80 _DirCreateTempOperation(String this._path); | |
| 81 | |
| 82 void execute(ReceivePort port) { | |
| 83 var status = new _OSStatus(); | |
| 84 var result = _Directory._createTemp(_path, status); | |
| 85 if (result == null) { | |
| 86 _replyPort.send(status, port.toSendPort()); | |
| 87 } else { | |
| 88 _replyPort.send(result, port.toSendPort()); | |
| 89 } | |
| 90 } | |
| 91 | |
| 92 String _path; | |
| 93 } | |
| 94 | |
| 95 | |
| 96 class _DirDeleteOperation extends _DirectoryOperation { | |
| 97 _DirDeleteOperation(String this._path, bool this._recursive); | |
| 98 | |
| 99 void execute(ReceivePort port) { | |
| 100 _replyPort.send(_Directory._delete(_path, _recursive), port.toSendPort()); | |
| 101 } | |
| 102 | |
| 103 String _path; | |
| 104 bool _recursive; | |
| 105 } | |
| 106 | |
| 107 | |
| 108 class _DirectoryOperationIsolate extends Isolate { | |
| 109 _DirectoryOperationIsolate() : super.heavy(); | |
| 110 | |
| 111 void handleOperation(_DirectoryOperation message, SendPort ignored) { | |
| 112 message.execute(port); | |
| 113 port.receive(handleOperation); | |
| 114 } | |
| 115 | |
| 116 void main() { | |
| 117 port.receive(handleOperation); | |
| 118 } | |
| 119 } | |
| 120 | |
| 121 | |
| 122 class _DirectoryOperationScheduler { | |
| 123 _DirectoryOperationScheduler() : _queue = new Queue(); | |
| 124 | |
| 125 void schedule(SendPort port) { | |
| 126 assert(_isolate != null); | |
| 127 if (_queue.isEmpty()) { | |
| 128 port.send(new _DirExitOperation()); | |
| 129 _isolate = null; | |
| 130 } else { | |
| 131 port.send(_queue.removeFirst()); | |
| 132 } | |
| 133 } | |
| 134 | |
| 135 void scheduleWrap(void callback(result, ignored)) { | |
| 136 return (result, replyTo) { | |
| 137 callback(result, replyTo); | |
| 138 schedule(replyTo); | |
| 139 }; | |
| 140 } | |
| 141 | |
| 142 void enqueue(_DirectoryOperation operation, void callback(result, ignored)) { | |
| 143 ReceivePort replyPort = new ReceivePort.singleShot(); | |
| 144 replyPort.receive(scheduleWrap(callback)); | |
| 145 operation.replyPort = replyPort.toSendPort(); | |
| 146 _queue.addLast(operation); | |
| 147 if (_isolate == null) { | |
| 148 _isolate = new _DirectoryOperationIsolate(); | |
| 149 _isolate.spawn().then((port) { | |
| 150 schedule(port); | |
| 151 }); | |
| 152 } | |
| 153 } | |
| 154 | |
| 155 Queue<_DirectoryOperation> _queue; | |
| 156 _DirectoryOperationIsolate _isolate; | |
| 157 } | |
| 158 | |
| 159 | |
| 160 class _Directory implements Directory { | 13 class _Directory implements Directory { |
| 14 static final kCreateRequest = 0; |
| 15 static final kDeleteRequest = 1; |
| 16 static final kExistsRequest = 2; |
| 17 static final kCreateTempRequest = 3; |
| 18 static final kListRequest = 4; |
| 161 | 19 |
| 162 _Directory(String this._path) | 20 _Directory(String this._path); |
| 163 : _scheduler = new _DirectoryOperationScheduler(); | |
| 164 | 21 |
| 165 static String _createTemp(String template, | 22 static String _createTemp(String template, |
| 166 _OSStatus status) native "Directory_CreateTemp"; | 23 _OSStatus status) native "Directory_CreateTemp"; |
| 167 static int _exists(String path) native "Directory_Exists"; | 24 static int _exists(String path) native "Directory_Exists"; |
| 168 static bool _create(String path) native "Directory_Create"; | 25 static bool _create(String path) native "Directory_Create"; |
| 169 static bool _delete(String path, bool recursive) native "Directory_Delete"; | 26 static bool _delete(String path, bool recursive) native "Directory_Delete"; |
| 27 static SendPort _newServicePort() native "Directory_NewServicePort"; |
| 170 | 28 |
| 171 void exists() { | 29 void exists() { |
| 172 var operation = new _DirExistsOperation(_path); | 30 if (_directoryService == null) { |
| 173 _scheduler.enqueue(operation, (result, ignored) { | 31 _directoryService = _newServicePort(); |
| 32 } |
| 33 List request = new List(2); |
| 34 request[0] = kExistsRequest; |
| 35 request[1] = _path; |
| 36 _directoryService.call(request).receive((result, replyTo) { |
| 174 var handler = | 37 var handler = |
| 175 (_existsHandler != null) ? _existsHandler : (result) => null; | 38 (_existsHandler != null) ? _existsHandler : (result) => null; |
| 176 if (result < 0) { | 39 if (result < 0) { |
| 177 if (_errorHandler != null) { | 40 if (_errorHandler != null) { |
| 178 _errorHandler("Diretory exists test failed: $_path"); | 41 _errorHandler("Diretory exists test failed: $_path"); |
| 179 } | 42 } |
| 180 } else { | 43 } else { |
| 181 handler(result == 1); | 44 handler(result == 1); |
| 182 } | 45 } |
| 183 }); | 46 }); |
| 184 } | 47 } |
| 185 | 48 |
| 186 bool existsSync() { | 49 bool existsSync() { |
| 187 int exists = _exists(_path); | 50 int exists = _exists(_path); |
| 188 if (exists < 0) { | 51 if (exists < 0) { |
| 189 throw new DirectoryException("Diretory exists test failed: $_path"); | 52 throw new DirectoryException("Diretory exists test failed: $_path"); |
| 190 } | 53 } |
| 191 return (exists == 1); | 54 return (exists == 1); |
| 192 } | 55 } |
| 193 | 56 |
| 194 void create() { | 57 void create() { |
| 195 var operation = new _DirCreateOperation(_path); | 58 if (_directoryService == null) { |
| 196 _scheduler.enqueue(operation, (result, ignored) { | 59 _directoryService = _newServicePort(); |
| 197 var handler = (_createHandler != null) ? _createHandler : () => null; | 60 } |
| 61 List request = new List(2); |
| 62 request[0] = kCreateRequest; |
| 63 request[1] = _path; |
| 64 _directoryService.call(request).receive((result, replyTo) { |
| 198 if (result) { | 65 if (result) { |
| 199 handler(); | 66 if (_createHandler != null) _createHandler(); |
| 200 } else if (_errorHandler != null) { | 67 } else if (_errorHandler != null) { |
| 201 _errorHandler("Directory creation failed: $_path"); | 68 _errorHandler("Directory creation failed: $_path"); |
| 202 } | 69 } |
| 203 }); | 70 }); |
| 204 } | 71 } |
| 205 | 72 |
| 206 void createSync() { | 73 void createSync() { |
| 207 if (!_create(_path)) { | 74 if (!_create(_path)) { |
| 208 throw new DirectoryException("Directory creation failed: $_path"); | 75 throw new DirectoryException("Directory creation failed: $_path"); |
| 209 } | 76 } |
| 210 } | 77 } |
| 211 | 78 |
| 212 void createTemp() { | 79 void createTemp() { |
| 213 var operation = new _DirCreateTempOperation(_path); | 80 if (_directoryService == null) { |
| 214 _scheduler.enqueue(operation, (result, ignored) { | 81 _directoryService = _newServicePort(); |
| 215 var handler = | 82 } |
| 216 (_createTempHandler != null) ? _createTempHandler : () => null; | 83 List request = new List(2); |
| 217 if (result is !_OSStatus) { | 84 request[0] = kCreateTempRequest; |
| 85 request[1] = _path; |
| 86 _directoryService.call(request).receive((result, replyTo) { |
| 87 if (result is !List) { |
| 218 _path = result; | 88 _path = result; |
| 219 handler(); | 89 if (_createTempHandler != null) _createTempHandler(); |
| 220 } else if (_errorHandler !== null) { | 90 } else if (_errorHandler != null) { |
| 221 _errorHandler("Could not create temporary directory [$_path]: " + | 91 _errorHandler("Could not create temporary directory [$_path]: " + |
| 222 "${result._errorMessage}"); | 92 "${result[1]}"); |
| 223 } | 93 } |
| 224 }); | 94 }); |
| 225 } | 95 } |
| 226 | 96 |
| 227 void createTempSync() { | 97 void createTempSync() { |
| 228 var status = new _OSStatus(); | 98 var status = new _OSStatus(); |
| 229 var result = _createTemp(path, status); | 99 var result = _createTemp(path, status); |
| 230 if (result != null) { | 100 if (result != null) { |
| 231 _path = result; | 101 _path = result; |
| 232 } else { | 102 } else { |
| 233 throw new DirectoryException( | 103 throw new DirectoryException( |
| 234 "Could not create temporary directory [$_path]: " + | 104 "Could not create temporary directory [$_path]: " + |
| 235 "${status._errorMessage}", | 105 "${status._errorMessage}", |
| 236 status._errorCode); | 106 status._errorCode); |
| 237 } | 107 } |
| 238 } | 108 } |
| 239 | 109 |
| 240 void delete([bool recursive = false]) { | 110 void delete([bool recursive = false]) { |
| 241 var operation = new _DirDeleteOperation(_path, recursive); | 111 if (_directoryService == null) { |
| 242 _scheduler.enqueue(operation, (result, ignored) { | 112 _directoryService = _newServicePort(); |
| 243 var handler = (_deleteHandler != null) ? _deleteHandler : () => null; | 113 } |
| 114 List request = new List(3); |
| 115 request[0] = kDeleteRequest; |
| 116 request[1] = _path; |
| 117 request[2] = recursive; |
| 118 _directoryService.call(request).receive((result, replyTo) { |
| 244 if (result) { | 119 if (result) { |
| 245 handler(); | 120 if (_deleteHandler != null) _deleteHandler(); |
| 246 } else if (_errorHandler != null) { | 121 } else if (_errorHandler != null) { |
| 247 if (recursive) { | 122 if (recursive) { |
| 248 _errorHandler("Recursive directory deletion failed: $_path"); | 123 _errorHandler("Recursive directory deletion failed: $_path"); |
| 249 } else { | 124 } else { |
| 250 _errorHandler("Non-recursive directory deletion failed: $_path"); | 125 _errorHandler("Non-recursive directory deletion failed: $_path"); |
| 251 } | 126 } |
| 252 } | 127 } |
| 253 }); | 128 }); |
| 254 } | 129 } |
| 255 | 130 |
| 256 void deleteSync([bool recursive = false]) { | 131 void deleteSync([bool recursive = false]) { |
| 257 if (!_delete(_path, recursive)) { | 132 if (!_delete(_path, recursive)) { |
| 258 throw new DirectoryException("Directory deletion failed: $_path"); | 133 throw new DirectoryException("Directory deletion failed: $_path"); |
| 259 } | 134 } |
| 260 } | 135 } |
| 261 | 136 |
| 262 void list([bool recursive = false]) { | 137 void list([bool recursive = false]) { |
| 263 new _DirectoryListingIsolate().spawn().then((port) { | 138 final int kListDirectory = 0; |
| 264 // Build a map of parameters to the directory listing isolate. | 139 final int kListFile = 1; |
| 265 Map listingParameters = new Map(); | 140 final int kListError = 2; |
| 266 listingParameters['dir'] = _path; | 141 final int kListDone = 3; |
| 267 listingParameters['recursive'] = recursive; | |
| 268 | 142 |
| 269 // Setup ports to receive messages from listing. | 143 List request = new List(3); |
| 270 // TODO(ager): Do not explicitly transform to send ports when | 144 request[0] = kListRequest; |
| 271 // implicit conversions are implemented. | 145 request[1] = _path; |
| 272 ReceivePort dirPort; | 146 request[2] = recursive; |
| 273 ReceivePort filePort; | 147 ReceivePort responsePort = new ReceivePort(); |
| 274 ReceivePort donePort; | 148 // Use a separate directory service port for each listing as |
| 275 ReceivePort errorPort; | 149 // listing operations on the same directory can run in parallel. |
| 276 if (_dirHandler !== null) { | 150 _newServicePort().send(request, responsePort.toSendPort()); |
| 277 dirPort = new ReceivePort(); | 151 responsePort.receive((message, replyTo) { |
| 278 dirPort.receive((String dir, ignored) { | 152 if (message is !List || message[0] is !int) { |
| 279 _dirHandler(dir); | 153 responsePort.close(); |
| 280 }); | 154 if (_errorHandler != null) _errorHandler("Internal error"); |
| 281 listingParameters['dirPort'] = dirPort.toSendPort(); | 155 return; |
| 282 } | 156 } |
| 283 if (_fileHandler !== null) { | 157 switch (message[0]) { |
| 284 filePort = new ReceivePort(); | 158 case kListDirectory: |
| 285 filePort.receive((String file, ignored) { | 159 if (_dirHandler != null) _dirHandler(message[1]); |
| 286 _fileHandler(file); | 160 break; |
| 287 }); | 161 case kListFile: |
| 288 listingParameters['filePort'] = filePort.toSendPort(); | 162 if (_fileHandler != null) _fileHandler(message[1]); |
| 163 break; |
| 164 case kListError: |
| 165 if (_errorHandler != null) _errorHandler(message[1]); |
| 166 break; |
| 167 case kListDone: |
| 168 responsePort.close(); |
| 169 if (_doneHandler != null) _doneHandler(message[1]); |
| 170 break; |
| 289 } | 171 } |
| 290 if (_doneHandler !== null) { | |
| 291 donePort = new ReceivePort.singleShot(); | |
| 292 donePort.receive((bool completed, ignored) { | |
| 293 _doneHandler(completed); | |
| 294 }); | |
| 295 listingParameters['donePort'] = donePort.toSendPort(); | |
| 296 } | |
| 297 if (_errorHandler !== null) { | |
| 298 errorPort = new ReceivePort.singleShot(); | |
| 299 errorPort.receive((String error, ignored) { | |
| 300 _errorHandler(error); | |
| 301 }); | |
| 302 listingParameters['errorPort'] = errorPort.toSendPort(); | |
| 303 } | |
| 304 | |
| 305 // Close ports when listing is done. | |
| 306 ReceivePort closePortsPort = new ReceivePort(); | |
| 307 closePortsPort.receive((message, replyTo) { | |
| 308 if (!message) { | |
| 309 errorPort.toSendPort().send( | |
| 310 "Failed to list directory: $_path recursive: $recursive"); | |
| 311 donePort.toSendPort().send(false); | |
| 312 } else { | |
| 313 _closePort(errorPort); | |
| 314 _closePort(donePort); | |
| 315 } | |
| 316 _closePort(dirPort); | |
| 317 _closePort(filePort); | |
| 318 _closePort(closePortsPort); | |
| 319 }); | |
| 320 | |
| 321 // Send the listing parameters to the isolate. | |
| 322 port.send(listingParameters, closePortsPort.toSendPort()); | |
| 323 }); | 172 }); |
| 324 } | 173 } |
| 325 | 174 |
| 326 void set dirHandler(void dirHandler(String dir)) { | 175 void set dirHandler(void dirHandler(String dir)) { |
| 327 _dirHandler = dirHandler; | 176 _dirHandler = dirHandler; |
| 328 } | 177 } |
| 329 | 178 |
| 330 void set fileHandler(void fileHandler(String file)) { | 179 void set fileHandler(void fileHandler(String file)) { |
| 331 _fileHandler = fileHandler; | 180 _fileHandler = fileHandler; |
| 332 } | 181 } |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 366 var _dirHandler; | 215 var _dirHandler; |
| 367 var _fileHandler; | 216 var _fileHandler; |
| 368 var _doneHandler; | 217 var _doneHandler; |
| 369 var _existsHandler; | 218 var _existsHandler; |
| 370 var _createHandler; | 219 var _createHandler; |
| 371 var _createTempHandler; | 220 var _createTempHandler; |
| 372 var _deleteHandler; | 221 var _deleteHandler; |
| 373 var _errorHandler; | 222 var _errorHandler; |
| 374 | 223 |
| 375 String _path; | 224 String _path; |
| 376 _DirectoryOperationScheduler _scheduler; | 225 SendPort _directoryService; |
| 377 } | 226 } |
| OLD | NEW |