OLD | NEW |
---|---|
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 part of dart.io; | 5 part of dart.io; |
6 | 6 |
7 class FileSystemEntityType { | 7 class FileSystemEntityType { |
8 static const FILE = const FileSystemEntityType._internal(0); | 8 static const FILE = const FileSystemEntityType._internal(0); |
9 static const DIRECTORY = const FileSystemEntityType._internal(1); | 9 static const DIRECTORY = const FileSystemEntityType._internal(1); |
10 static const LINK = const FileSystemEntityType._internal(2); | 10 static const LINK = const FileSystemEntityType._internal(2); |
(...skipping 299 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
310 * Identical to [:FileStat.statSync(this.path):]. | 310 * Identical to [:FileStat.statSync(this.path):]. |
311 * | 311 * |
312 * Returns a [FileStat] object containing the data returned by stat(). | 312 * Returns a [FileStat] object containing the data returned by stat(). |
313 * | 313 * |
314 * If the call fails, returns a [FileStat] object with .type set to | 314 * If the call fails, returns a [FileStat] object with .type set to |
315 * FileSystemEntityType.NOT_FOUND and the other fields invalid. | 315 * FileSystemEntityType.NOT_FOUND and the other fields invalid. |
316 */ | 316 */ |
317 FileStat statSync(); | 317 FileStat statSync(); |
318 | 318 |
319 | 319 |
320 | |
321 Stream<FileSystemEvent> watch({int events: FileSystemEvent.ALL_EVENTS, | |
322 bool recursive: false}) | |
323 => new _FileSystemWatcher(path, events, recursive).stream; | |
324 | |
325 | |
320 /** | 326 /** |
321 * Finds the type of file system object that a path points to. Returns | 327 * Finds the type of file system object that a path points to. Returns |
322 * a [:Future<FileSystemEntityType>:] that completes with the result. | 328 * a [:Future<FileSystemEntityType>:] that completes with the result. |
323 * | 329 * |
324 * [FileSystemEntityType] has the constant instances FILE, DIRECTORY, | 330 * [FileSystemEntityType] has the constant instances FILE, DIRECTORY, |
325 * LINK, and NOT_FOUND. [type] will return LINK only if the optional | 331 * LINK, and NOT_FOUND. [type] will return LINK only if the optional |
326 * named argument [followLinks] is false, and [path] points to a link. | 332 * named argument [followLinks] is false, and [path] points to a link. |
327 * If the path does not point to a file system object, or any other error | 333 * If the path does not point to a file system object, or any other error |
328 * occurs in looking up the path, NOT_FOUND is returned. The only | 334 * occurs in looking up the path, NOT_FOUND is returned. The only |
329 * error or exception that may be put on the returned future is ArgumentError, | 335 * error or exception that may be put on the returned future is ArgumentError, |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
383 (_getTypeSync(path, true) == FileSystemEntityType.FILE._type); | 389 (_getTypeSync(path, true) == FileSystemEntityType.FILE._type); |
384 | 390 |
385 /** | 391 /** |
386 * Synchronously checks if typeSync(path) returns | 392 * Synchronously checks if typeSync(path) returns |
387 * FileSystemEntityType.DIRECTORY. | 393 * FileSystemEntityType.DIRECTORY. |
388 */ | 394 */ |
389 static bool isDirectorySync(String path) => | 395 static bool isDirectorySync(String path) => |
390 (_getTypeSync(path, true) == FileSystemEntityType.DIRECTORY._type); | 396 (_getTypeSync(path, true) == FileSystemEntityType.DIRECTORY._type); |
391 | 397 |
392 | 398 |
393 static _throwIfError(Object result, String msg) { | 399 static _throwIfError(Object result, String msg, [String path]) { |
394 if (result is OSError) { | 400 if (result is OSError) { |
395 throw new FileException(msg, result); | 401 throw new FileException(msg, result, path); |
396 } else if (result is ArgumentError) { | 402 } else if (result is ArgumentError) { |
397 throw result; | 403 throw result; |
398 } | 404 } |
399 } | 405 } |
400 } | 406 } |
407 | |
408 | |
409 /** | |
410 * Base event class emitted by FileSystemWatcher. | |
411 */ | |
412 class FileSystemEvent { | |
413 static const int CREATE_EVENT = 1 << 0; | |
Søren Gjesse
2013/08/26 07:51:55
How about removing the _EVENT prefix?
Anders Johnsen
2013/09/03 11:36:23
Done.
| |
414 static const int MODIFY_EVENT = 1 << 1; | |
415 static const int DELETE_EVENT = 1 << 2; | |
416 static const int MOVE_EVENT = 1 << 3; | |
Søren Gjesse
2013/08/26 07:51:55
Two spaces after =.
Anders Johnsen
2013/09/03 11:36:23
Done.
| |
417 static const int ALL_EVENTS = | |
418 CREATE_EVENT | MODIFY_EVENT | DELETE_EVENT | MOVE_EVENT; | |
419 | |
420 static const int _MODIFY_ATTRIBUTES_EVENT = 1 << 4; | |
Søren Gjesse
2013/08/26 07:51:55
Add empty line.
Anders Johnsen
2013/09/03 11:36:23
Done.
| |
421 /** | |
422 * The type of event. See [FileSystemEvent] for a list of events. | |
423 */ | |
424 final int type; | |
425 | |
426 /** | |
427 * The path that triggered the event. | |
Søren Gjesse
2013/08/26 07:51:55
Some doc on whether this is absolute or maybe ŕela
Anders Johnsen
2013/09/03 11:36:23
Done.
| |
428 */ | |
429 final String path; | |
430 | |
431 FileSystemEvent._(this.type, this.path); | |
432 } | |
433 | |
434 | |
435 /** | |
436 * File system event for newly created file system objects. | |
437 */ | |
438 class FileSystemCreateEvent extends FileSystemEvent { | |
439 FileSystemCreateEvent._(path) | |
440 : super._(FileSystemEvent.CREATE_EVENT, path); | |
441 | |
442 String toString() => "FileSystemCreateEvent('$path')"; | |
443 } | |
444 | |
445 | |
446 /** | |
447 * File system event for modifications of file system objects. | |
448 */ | |
449 class FileSystemModifyEvent extends FileSystemEvent { | |
450 /** | |
451 * If the content was changed and not only the attributes, [contentChanged] | |
452 * is `true`. | |
453 */ | |
454 final bool contentChanged; | |
455 | |
456 FileSystemModifyEvent._(path, this.contentChanged) | |
457 : super._(FileSystemEvent.MODIFY_EVENT, path); | |
458 | |
459 String toString() => | |
460 "FileSystemModifyEvent('$path', contentChanged=$contentChanged)"; | |
461 } | |
462 | |
463 | |
464 /** | |
465 * File system event for deletion of file system objects. | |
466 */ | |
467 class FileSystemDeleteEvent extends FileSystemEvent { | |
468 FileSystemDeleteEvent._(path) | |
469 : super._(FileSystemEvent.DELETE_EVENT, path); | |
470 | |
471 String toString() => "FileSystemDeleteEvent('$path')"; | |
472 } | |
473 | |
474 | |
475 /** | |
476 * File system event for moving of file system objects. | |
477 */ | |
478 class FileSystemMoveEvent extends FileSystemEvent { | |
479 /** | |
480 * If the underlaying implementation is able to identify the destination of | |
481 * the moved file, [destination] will be set. Otherwise, it will be `null`. | |
482 */ | |
483 final String destination; | |
484 | |
485 FileSystemMoveEvent._(path, this.destination) | |
486 : super._(FileSystemEvent.MOVE_EVENT, path); | |
487 | |
488 String toString() { | |
489 var buffer = new StringBuffer(); | |
490 buffer.write("FileSystemMoveEvent('$path'"); | |
491 if (destination != null) buffer.write(", '$destination'"); | |
492 buffer.write(')'); | |
493 return buffer.toString(); | |
494 } | |
495 } | |
496 | |
497 | |
498 class _FileSystemWatcher { | |
499 final String _path; | |
500 final int _events; | |
501 | |
502 StreamController _controller; | |
503 int _id; | |
504 _RawSocket _socket; | |
505 | |
506 _FileSystemWatcher(this._path, this._events, bool recursive) { | |
507 | |
508 _controller = new StreamController( | |
509 onListen: () { | |
510 print("in listen"); | |
Søren Gjesse
2013/08/26 07:51:55
Debug print.
Anders Johnsen
2013/09/03 11:36:23
Done.
| |
511 _id = _watchPath(_path, _events, recursive); | |
512 FileSystemEntity._throwIfError(_id, "Failed to watch path", _path); | |
513 _listen(); | |
514 }, | |
515 onCancel: () { | |
516 if (_socket != null) { | |
517 _socket.close(); | |
518 } | |
519 }); | |
520 } | |
521 | |
522 void _stop() { | |
523 _controller.close(); | |
524 _unwatchPath(_id); | |
525 } | |
526 | |
527 void _listen() { | |
Søren Gjesse
2013/08/26 07:51:55
I think we should do _NativeSocket setup the same
Anders Johnsen
2013/09/03 11:36:23
I've tried to simplify as much as possible.
| |
528 int socketId = _getSocketId(_id); | |
529 var native = new _NativeSocket.normal(); | |
530 native.isClosedWrite = true; | |
531 native.setSocketId(socketId); | |
532 _socket = new _RawSocket(native); | |
533 print(socketId); | |
Søren Gjesse
2013/08/26 07:51:55
Debug print.
Anders Johnsen
2013/09/03 11:36:23
Done.
| |
534 _socket.expand((event) { | |
535 print(event); | |
536 var events = []; | |
537 var pair = {}; | |
538 if (event == RawSocketEvent.READ) { | |
539 String getPath(event) { | |
540 var path = _path; | |
541 if (event[2] != null) { | |
542 path += Platform.pathSeparator; | |
543 path += event[2]; | |
544 } | |
545 return path; | |
546 } | |
547 while (_socket.available() > 0) { | |
548 for (var event in _readEvents(_id)) { | |
549 print(event); | |
Søren Gjesse
2013/08/26 07:51:55
Debug print.
Anders Johnsen
2013/09/03 11:36:23
Done.
| |
550 var path = getPath(event); | |
551 if ((event[0] & FileSystemEvent.CREATE_EVENT) != 0) { | |
552 events.add(new FileSystemCreateEvent._(path)); | |
553 } | |
554 if ((event[0] & FileSystemEvent.MODIFY_EVENT) != 0) { | |
555 events.add(new FileSystemModifyEvent._(path, true)); | |
556 } | |
557 if ((event[0] & FileSystemEvent._MODIFY_ATTRIBUTES_EVENT) != 0) { | |
558 events.add(new FileSystemModifyEvent._(path, false)); | |
559 } | |
560 if ((event[0] & FileSystemEvent.MOVE_EVENT) != 0) { | |
561 int link = event[3]; | |
562 if (link > 0) { | |
563 if (pair.containsKey(link)) { | |
564 events.add( | |
565 new FileSystemMoveEvent._(getPath(pair[link]), path)); | |
566 pair.remove(link); | |
567 } else { | |
568 pair[link] = event; | |
569 } | |
570 } else { | |
571 events.add(new FileSystemMoveEvent._(path, null)); | |
572 } | |
573 } | |
574 if ((event[0] & FileSystemEvent.DELETE_EVENT) != 0) { | |
575 events.add(new FileSystemDeleteEvent._(path)); | |
576 } | |
577 } | |
578 } | |
579 for (var event in pair.values) { | |
580 events.add(new FileSystemMoveEvent._(getPath(event), null)); | |
581 } | |
582 } else if (event == RawSocketEvent.CLOSED) { | |
583 _stop(); | |
584 } else if (event == RawSocketEvent.READ_CLOSED) { | |
585 } else { | |
586 assert(false); | |
587 } | |
588 print(events); | |
589 return events; | |
590 }).where((event) => (event.type & _events) != 0).listen(_controller.add); | |
591 } | |
592 | |
593 Stream<FileSystemEvent> get stream => _controller.stream; | |
594 | |
595 external _watchPath(String path, int events, bool recursive); | |
596 external void _unwatchPath(int id); | |
597 external int _getSocketId(int id); | |
598 external List _readEvents(int id); | |
599 } | |
OLD | NEW |