486 out = out.replace(b"\r", b"\n") |
488 out = out.replace(b"\r", b"\n") |
487 with open(hostFileName, "wb") as hostFile: |
489 with open(hostFileName, "wb") as hostFile: |
488 hostFile.write(out) |
490 hostFile.write(out) |
489 return True |
491 return True |
490 |
492 |
|
493 def fileSystemInfo(self): |
|
494 """ |
|
495 Public method to obtain information about the currently mounted file |
|
496 systems. |
|
497 |
|
498 @return tuple of tuples containing the file system name, the total |
|
499 size, the used size and the free size |
|
500 @rtype tuple of tuples of (str, int, int, int) |
|
501 """ |
|
502 commands = [ |
|
503 "import os", |
|
504 "\n".join([ |
|
505 "def fsinfo():", |
|
506 " infolist = []", |
|
507 " fsnames = os.listdir('/')", |
|
508 " for fs in fsnames:", |
|
509 " fs = '/' + fs", |
|
510 " infolist.append((fs, os.statvfs(fs)))", |
|
511 " return infolist", |
|
512 ]), |
|
513 "print(fsinfo())", |
|
514 ] |
|
515 out, err = self.__execute(commands) |
|
516 if err: |
|
517 raise IOError(self.__shortError(err)) |
|
518 infolist = ast.literal_eval(out.decode("utf-8")) |
|
519 if infolist is None: |
|
520 return None |
|
521 else: |
|
522 filesystemInfos = [] |
|
523 for fs, info in infolist: |
|
524 totalSize = info[2] * info[1] |
|
525 freeSize = info[4] * info[1] |
|
526 usedSize = totalSize - freeSize |
|
527 filesystemInfos.append((fs, totalSize, usedSize, freeSize)) |
|
528 |
|
529 return tuple(filesystemInfos) |
|
530 |
|
531 ################################################################## |
|
532 ## non-filesystem related methods below |
|
533 ################################################################## |
|
534 |
491 def version(self): |
535 def version(self): |
492 """ |
536 """ |
493 Public method to get the MicroPython version information of the |
537 Public method to get the MicroPython version information of the |
494 connected device. |
538 connected device. |
495 |
539 |
496 @return dictionary containing the version information |
540 @return dictionary containing the version information |
497 @rtype dict |
541 @rtype dict |
498 @exception ValueError raised to indicate that the device might not be |
542 @exception IOError raised to indicate an issue with the device |
499 running MicroPython or there was an issue parsing the output |
|
500 """ |
543 """ |
501 commands = [ |
544 commands = [ |
502 "import os", |
545 "import os", |
503 "print(os.uname())", |
546 "print(os.uname())", |
504 ] |
547 ] |
505 try: |
548 out, err = self.__execute(commands) |
506 out, err = self.__execute(commands) |
549 if err: |
507 if err: |
550 raise IOError(self.__shortError(err)) |
508 raise ValueError(self.__shortError(err)) |
|
509 except ValueError: |
|
510 # just re-raise it |
|
511 raise |
|
512 except Exception: |
|
513 # Raise a value error to indicate being unable to find something |
|
514 # on the device that will return parseable information about the |
|
515 # version. It doesn't matter what the error is, it just needs to |
|
516 # report a failure with the expected ValueError exception. |
|
517 raise ValueError("Unable to determine version information.") |
|
518 |
551 |
519 rawOutput = out.decode("utf-8").strip() |
552 rawOutput = out.decode("utf-8").strip() |
520 rawOutput = rawOutput[1:-1] |
553 rawOutput = rawOutput[1:-1] |
521 items = rawOutput.split(",") |
554 items = rawOutput.split(",") |
522 result = {} |
555 result = {} |
523 for item in items: |
556 for item in items: |
524 key, value = item.strip().split("=") |
557 key, value = item.strip().split("=") |
525 result[key.strip()] = value.strip()[1:-1] |
558 result[key.strip()] = value.strip()[1:-1] |
526 return result |
559 return result |
|
560 |
|
561 def getImplementation(self): |
|
562 """ |
|
563 Public method to get some implementation information of the connected |
|
564 device. |
|
565 |
|
566 @return dictionary containing the implementation information |
|
567 @rtype dict |
|
568 @exception IOError raised to indicate an issue with the device |
|
569 """ |
|
570 commands = [ |
|
571 "import sys", |
|
572 "res = {}", |
|
573 "\n".join([ |
|
574 "try:", |
|
575 " res['name'] = sys.implementation.name", |
|
576 "except AttributeError:", |
|
577 " res['name'] = 'unknown'", |
|
578 ]), |
|
579 "\n".join([ |
|
580 "try:", |
|
581 " res['version'] = '.'.join((str(i) for i in" |
|
582 " sys.implementation.version))", |
|
583 "except AttributeError:", |
|
584 " res['version'] = 'unknown'", |
|
585 ]), |
|
586 "print(res)", |
|
587 ] |
|
588 out, err = self.__execute(commands) |
|
589 if err: |
|
590 raise IOError(self.__shortError(err)) |
|
591 return ast.literal_eval(out.decode("utf-8")) |
527 |
592 |
528 def syncTime(self): |
593 def syncTime(self): |
529 """ |
594 """ |
530 Public method to set the time of the connected device to the local |
595 Public method to set the time of the connected device to the local |
531 computer's time. |
596 computer's time. |
609 has been completed |
674 has been completed |
610 @signal rsyncProgressMessage(msg) emitted to send a message about what |
675 @signal rsyncProgressMessage(msg) emitted to send a message about what |
611 rsync is doing |
676 rsync is doing |
612 @signal removeDirectoryDone() emitted after a directory has been deleted |
677 @signal removeDirectoryDone() emitted after a directory has been deleted |
613 @signal createDirectoryDone() emitted after a directory was created |
678 @signal createDirectoryDone() emitted after a directory was created |
|
679 @signal fsinfoDone(fsinfo) emitted after the file system information was |
|
680 obtained |
|
681 |
614 @signal synchTimeDone() emitted after the time was synchronizde to the |
682 @signal synchTimeDone() emitted after the time was synchronizde to the |
615 device |
683 device |
616 @signal showTimeDone(dateTime) emitted after the date and time was fetched |
684 @signal showTimeDone(dateTime) emitted after the date and time was fetched |
617 from the connected device |
685 from the connected device |
618 @signal showVersionDone(versionInfo) emitted after the version information |
686 @signal showVersionDone(versionInfo) emitted after the version information |
619 was fetched from the connected device |
687 was fetched from the connected device |
|
688 @signal showImplementationDone(name,version) emitted after the |
|
689 implementation information has been obtained |
620 |
690 |
621 @signal error(exc) emitted with a failure message to indicate a failure |
691 @signal error(exc) emitted with a failure message to indicate a failure |
622 during the most recent operation |
692 during the most recent operation |
623 """ |
693 """ |
624 longListFiles = pyqtSignal(tuple) |
694 longListFiles = pyqtSignal(tuple) |
629 deleteFileDone = pyqtSignal(str) |
699 deleteFileDone = pyqtSignal(str) |
630 rsyncDone = pyqtSignal(str, str) |
700 rsyncDone = pyqtSignal(str, str) |
631 rsyncProgressMessage = pyqtSignal(str) |
701 rsyncProgressMessage = pyqtSignal(str) |
632 removeDirectoryDone = pyqtSignal() |
702 removeDirectoryDone = pyqtSignal() |
633 createDirectoryDone = pyqtSignal() |
703 createDirectoryDone = pyqtSignal() |
|
704 fsinfoDone = pyqtSignal(tuple) |
|
705 |
634 synchTimeDone = pyqtSignal() |
706 synchTimeDone = pyqtSignal() |
635 showTimeDone = pyqtSignal(str) |
707 showTimeDone = pyqtSignal(str) |
636 showVersionDone = pyqtSignal(dict) |
708 showVersionDone = pyqtSignal(dict) |
|
709 showImplementationDone = pyqtSignal(str, str) |
637 |
710 |
638 error = pyqtSignal(str, str) |
711 error = pyqtSignal(str, str) |
639 |
712 |
640 def __init__(self, port, parent=None): |
713 def __init__(self, port, parent=None): |
641 """ |
714 """ |
647 @type QObject |
720 @type QObject |
648 """ |
721 """ |
649 super(MicroPythonFileManager, self).__init__(parent) |
722 super(MicroPythonFileManager, self).__init__(parent) |
650 |
723 |
651 self.__serialPort = port |
724 self.__serialPort = port |
652 self.__serial = MicroPythonSerialPort(parent=self) |
725 self.__serial = MicroPythonSerialPort( |
|
726 timeout=Preferences.getMicroPython("SerialTimeout"), |
|
727 parent=self) |
653 self.__fs = MicroPythonFileSystem(parent=self) |
728 self.__fs = MicroPythonFileSystem(parent=self) |
654 |
729 |
655 @pyqtSlot() |
730 @pyqtSlot() |
656 def connect(self): |
731 def connectToDevice(self): |
657 """ |
732 """ |
658 Public slot to start the manager. |
733 Public slot to start the manager. |
659 """ |
734 """ |
660 self.__serial.openSerialLink(self.__serialPort) |
735 self.__serial.openSerialLink(self.__serialPort) |
661 self.__fs.setSerial(self.__serial) |
736 self.__fs.setSerial(self.__serial) |
662 |
737 |
663 @pyqtSlot() |
738 @pyqtSlot() |
664 def disconnect(self): |
739 def disconnectFromDevice(self): |
665 """ |
740 """ |
666 Public slot to stop the thread. |
741 Public slot to stop the thread. |
667 """ |
742 """ |
668 self.__serial.closeSerialLink() |
743 self.__serial.closeSerialLink() |
|
744 |
|
745 @pyqtSlot() |
|
746 def handlePreferencesChanged(self): |
|
747 """ |
|
748 Public slot to handle a change of the preferences. |
|
749 """ |
|
750 self.__serial.setTimeout(Preferences.getMicroPython("SerialTimeout")) |
669 |
751 |
670 @pyqtSlot(str) |
752 @pyqtSlot(str) |
671 def lls(self, dirname): |
753 def lls(self, dirname): |
672 """ |
754 """ |
673 Public slot to get a long listing of the given directory. |
755 Public slot to get a long listing of the given directory. |
943 self.__fs.rmdir(dirname) |
1025 self.__fs.rmdir(dirname) |
944 self.removeDirectoryDone.emit() |
1026 self.removeDirectoryDone.emit() |
945 except Exception as exc: |
1027 except Exception as exc: |
946 self.error.emit("rmdir", str(exc)) |
1028 self.error.emit("rmdir", str(exc)) |
947 |
1029 |
|
1030 def fileSystemInfo(self): |
|
1031 """ |
|
1032 Public method to obtain information about the currently mounted file |
|
1033 systems. |
|
1034 """ |
|
1035 try: |
|
1036 fsinfo = self.__fs.fileSystemInfo() |
|
1037 self.fsinfoDone.emit(fsinfo) |
|
1038 except Exception as exc: |
|
1039 self.error.emit("fileSystemInfo", str(exc)) |
|
1040 |
948 ################################################################## |
1041 ################################################################## |
949 ## some non-filesystem related methods below |
1042 ## some non-filesystem related methods below |
950 ################################################################## |
1043 ################################################################## |
951 |
1044 |
952 @pyqtSlot() |
1045 @pyqtSlot() |
981 try: |
1074 try: |
982 versionInfo = self.__fs.version() |
1075 versionInfo = self.__fs.version() |
983 self.showVersionDone.emit(versionInfo) |
1076 self.showVersionDone.emit(versionInfo) |
984 except Exception as exc: |
1077 except Exception as exc: |
985 self.error.emit("showVersion", str(exc)) |
1078 self.error.emit("showVersion", str(exc)) |
|
1079 |
|
1080 @pyqtSlot() |
|
1081 def showImplementation(self): |
|
1082 """ |
|
1083 Public slot to obtain some implementation related information. |
|
1084 """ |
|
1085 try: |
|
1086 impInfo = self.__fs.getImplementation() |
|
1087 if impInfo["name"] == "micropython": |
|
1088 name = "MicroPython" |
|
1089 elif impInfo["name"] == "circuitpython": |
|
1090 name = "CircuitPython" |
|
1091 elif impInfo["name"] == "unknown": |
|
1092 name = self.tr("unknown") |
|
1093 else: |
|
1094 name = impInfo["name"] |
|
1095 if impInfo["version"] == "unknown": |
|
1096 version = self.tr("unknown") |
|
1097 else: |
|
1098 version = impInfo["version"] |
|
1099 self.showImplementationDone.emit(name, version) |
|
1100 except Exception as exc: |
|
1101 self.error.emit("showVersion", str(exc)) |