Show More
@@ -488,6 +488,228 b' def popen4(cmd, env=None, newlines=False' | |||||
488 | env=env) |
|
488 | env=env) | |
489 | return p.stdin, p.stdout, p.stderr, p |
|
489 | return p.stdin, p.stdout, p.stderr, p | |
490 |
|
490 | |||
|
491 | class fileobjectproxy(object): | |||
|
492 | """A proxy around file objects that tells a watcher when events occur. | |||
|
493 | ||||
|
494 | This type is intended to only be used for testing purposes. Think hard | |||
|
495 | before using it in important code. | |||
|
496 | """ | |||
|
497 | __slots__ = ( | |||
|
498 | r'_orig', | |||
|
499 | r'_observer', | |||
|
500 | ) | |||
|
501 | ||||
|
502 | def __init__(self, fh, observer): | |||
|
503 | object.__setattr__(self, '_orig', fh) | |||
|
504 | object.__setattr__(self, '_observer', observer) | |||
|
505 | ||||
|
506 | def __getattribute__(self, name): | |||
|
507 | ours = { | |||
|
508 | # IOBase | |||
|
509 | r'close', | |||
|
510 | # closed if a property | |||
|
511 | r'fileno', | |||
|
512 | r'flush', | |||
|
513 | r'isatty', | |||
|
514 | r'readable', | |||
|
515 | r'readline', | |||
|
516 | r'readlines', | |||
|
517 | r'seek', | |||
|
518 | r'seekable', | |||
|
519 | r'tell', | |||
|
520 | r'truncate', | |||
|
521 | r'writable', | |||
|
522 | r'writelines', | |||
|
523 | # RawIOBase | |||
|
524 | r'read', | |||
|
525 | r'readall', | |||
|
526 | r'readinto', | |||
|
527 | r'write', | |||
|
528 | # BufferedIOBase | |||
|
529 | # raw is a property | |||
|
530 | r'detach', | |||
|
531 | # read defined above | |||
|
532 | r'read1', | |||
|
533 | # readinto defined above | |||
|
534 | # write defined above | |||
|
535 | } | |||
|
536 | ||||
|
537 | # We only observe some methods. | |||
|
538 | if name in ours: | |||
|
539 | return object.__getattribute__(self, name) | |||
|
540 | ||||
|
541 | return getattr(object.__getattribute__(self, r'_orig'), name) | |||
|
542 | ||||
|
543 | def __delattr__(self, name): | |||
|
544 | return delattr(object.__getattribute__(self, r'_orig'), name) | |||
|
545 | ||||
|
546 | def __setattr__(self, name, value): | |||
|
547 | return setattr(object.__getattribute__(self, r'_orig'), name, value) | |||
|
548 | ||||
|
549 | def __iter__(self): | |||
|
550 | return object.__getattribute__(self, r'_orig').__iter__() | |||
|
551 | ||||
|
552 | def _observedcall(self, name, *args, **kwargs): | |||
|
553 | # Call the original object. | |||
|
554 | orig = object.__getattribute__(self, r'_orig') | |||
|
555 | res = getattr(orig, name)(*args, **kwargs) | |||
|
556 | ||||
|
557 | # Call a method on the observer of the same name with arguments | |||
|
558 | # so it can react, log, etc. | |||
|
559 | observer = object.__getattribute__(self, r'_observer') | |||
|
560 | fn = getattr(observer, name, None) | |||
|
561 | if fn: | |||
|
562 | fn(res, *args, **kwargs) | |||
|
563 | ||||
|
564 | return res | |||
|
565 | ||||
|
566 | def close(self, *args, **kwargs): | |||
|
567 | return object.__getattribute__(self, r'_observedcall')( | |||
|
568 | r'close', *args, **kwargs) | |||
|
569 | ||||
|
570 | def fileno(self, *args, **kwargs): | |||
|
571 | return object.__getattribute__(self, r'_observedcall')( | |||
|
572 | r'fileno', *args, **kwargs) | |||
|
573 | ||||
|
574 | def flush(self, *args, **kwargs): | |||
|
575 | return object.__getattribute__(self, r'_observedcall')( | |||
|
576 | r'flush', *args, **kwargs) | |||
|
577 | ||||
|
578 | def isatty(self, *args, **kwargs): | |||
|
579 | return object.__getattribute__(self, r'_observedcall')( | |||
|
580 | r'isatty', *args, **kwargs) | |||
|
581 | ||||
|
582 | def readable(self, *args, **kwargs): | |||
|
583 | return object.__getattribute__(self, r'_observedcall')( | |||
|
584 | r'readable', *args, **kwargs) | |||
|
585 | ||||
|
586 | def readline(self, *args, **kwargs): | |||
|
587 | return object.__getattribute__(self, r'_observedcall')( | |||
|
588 | r'readline', *args, **kwargs) | |||
|
589 | ||||
|
590 | def readlines(self, *args, **kwargs): | |||
|
591 | return object.__getattribute__(self, r'_observedcall')( | |||
|
592 | r'readlines', *args, **kwargs) | |||
|
593 | ||||
|
594 | def seek(self, *args, **kwargs): | |||
|
595 | return object.__getattribute__(self, r'_observedcall')( | |||
|
596 | r'seek', *args, **kwargs) | |||
|
597 | ||||
|
598 | def seekable(self, *args, **kwargs): | |||
|
599 | return object.__getattribute__(self, r'_observedcall')( | |||
|
600 | r'seekable', *args, **kwargs) | |||
|
601 | ||||
|
602 | def tell(self, *args, **kwargs): | |||
|
603 | return object.__getattribute__(self, r'_observedcall')( | |||
|
604 | r'tell', *args, **kwargs) | |||
|
605 | ||||
|
606 | def truncate(self, *args, **kwargs): | |||
|
607 | return object.__getattribute__(self, r'_observedcall')( | |||
|
608 | r'truncate', *args, **kwargs) | |||
|
609 | ||||
|
610 | def writable(self, *args, **kwargs): | |||
|
611 | return object.__getattribute__(self, r'_observedcall')( | |||
|
612 | r'writable', *args, **kwargs) | |||
|
613 | ||||
|
614 | def writelines(self, *args, **kwargs): | |||
|
615 | return object.__getattribute__(self, r'_observedcall')( | |||
|
616 | r'writelines', *args, **kwargs) | |||
|
617 | ||||
|
618 | def read(self, *args, **kwargs): | |||
|
619 | return object.__getattribute__(self, r'_observedcall')( | |||
|
620 | r'read', *args, **kwargs) | |||
|
621 | ||||
|
622 | def readall(self, *args, **kwargs): | |||
|
623 | return object.__getattribute__(self, r'_observedcall')( | |||
|
624 | r'readall', *args, **kwargs) | |||
|
625 | ||||
|
626 | def readinto(self, *args, **kwargs): | |||
|
627 | return object.__getattribute__(self, r'_observedcall')( | |||
|
628 | r'readinto', *args, **kwargs) | |||
|
629 | ||||
|
630 | def write(self, *args, **kwargs): | |||
|
631 | return object.__getattribute__(self, r'_observedcall')( | |||
|
632 | r'write', *args, **kwargs) | |||
|
633 | ||||
|
634 | def detach(self, *args, **kwargs): | |||
|
635 | return object.__getattribute__(self, r'_observedcall')( | |||
|
636 | r'detach', *args, **kwargs) | |||
|
637 | ||||
|
638 | def read1(self, *args, **kwargs): | |||
|
639 | return object.__getattribute__(self, r'_observedcall')( | |||
|
640 | r'read1', *args, **kwargs) | |||
|
641 | ||||
|
642 | DATA_ESCAPE_MAP = {pycompat.bytechr(i): br'\x%02x' % i for i in range(256)} | |||
|
643 | DATA_ESCAPE_MAP.update({ | |||
|
644 | b'\\': b'\\\\', | |||
|
645 | b'\r': br'\r', | |||
|
646 | b'\n': br'\n', | |||
|
647 | }) | |||
|
648 | DATA_ESCAPE_RE = remod.compile(br'[\x00-\x08\x0a-\x1f\\\x7f-\xff]') | |||
|
649 | ||||
|
650 | def escapedata(s): | |||
|
651 | return DATA_ESCAPE_RE.sub(lambda m: DATA_ESCAPE_MAP[m.group(0)], s) | |||
|
652 | ||||
|
653 | class fileobjectobserver(object): | |||
|
654 | """Logs file object activity.""" | |||
|
655 | def __init__(self, fh, name, reads=True, writes=True, logdata=False): | |||
|
656 | self.fh = fh | |||
|
657 | self.name = name | |||
|
658 | self.logdata = logdata | |||
|
659 | self.reads = reads | |||
|
660 | self.writes = writes | |||
|
661 | ||||
|
662 | def _writedata(self, data): | |||
|
663 | if not self.logdata: | |||
|
664 | self.fh.write('\n') | |||
|
665 | return | |||
|
666 | ||||
|
667 | # Simple case writes all data on a single line. | |||
|
668 | if b'\n' not in data: | |||
|
669 | self.fh.write(': %s\n' % escapedata(data)) | |||
|
670 | return | |||
|
671 | ||||
|
672 | # Data with newlines is written to multiple lines. | |||
|
673 | self.fh.write(':\n') | |||
|
674 | lines = data.splitlines(True) | |||
|
675 | for line in lines: | |||
|
676 | self.fh.write('%s> %s\n' % (self.name, escapedata(line))) | |||
|
677 | ||||
|
678 | def read(self, res, size=-1): | |||
|
679 | if not self.reads: | |||
|
680 | return | |||
|
681 | ||||
|
682 | self.fh.write('%s> read(%d) -> %d' % (self.name, size, len(res))) | |||
|
683 | self._writedata(res) | |||
|
684 | ||||
|
685 | def readline(self, res, limit=-1): | |||
|
686 | if not self.reads: | |||
|
687 | return | |||
|
688 | ||||
|
689 | self.fh.write('%s> readline() -> %d' % (self.name, len(res))) | |||
|
690 | self._writedata(res) | |||
|
691 | ||||
|
692 | def write(self, res, data): | |||
|
693 | if not self.writes: | |||
|
694 | return | |||
|
695 | ||||
|
696 | self.fh.write('%s> write(%d) -> %r' % (self.name, len(data), res)) | |||
|
697 | self._writedata(data) | |||
|
698 | ||||
|
699 | def flush(self, res): | |||
|
700 | if not self.writes: | |||
|
701 | return | |||
|
702 | ||||
|
703 | self.fh.write('%s> flush() -> %r\n' % (self.name, res)) | |||
|
704 | ||||
|
705 | def makeloggingfileobject(logh, fh, name, reads=True, writes=True, | |||
|
706 | logdata=False): | |||
|
707 | """Turn a file object into a logging file object.""" | |||
|
708 | ||||
|
709 | observer = fileobjectobserver(logh, name, reads=reads, writes=writes, | |||
|
710 | logdata=logdata) | |||
|
711 | return fileobjectproxy(fh, observer) | |||
|
712 | ||||
491 | def version(): |
|
713 | def version(): | |
492 | """Return version information if available.""" |
|
714 | """Return version information if available.""" | |
493 | try: |
|
715 | try: |
General Comments 0
You need to be logged in to leave comments.
Login now