src/eric7/MicroPython/CircuitPythonDevices.py

branch
eric7
changeset 9738
4ae976ee5339
parent 9653
e67609152c5e
child 9740
90072e10ae9b
diff -r 5e05b2089daf -r 4ae976ee5339 src/eric7/MicroPython/CircuitPythonDevices.py
--- a/src/eric7/MicroPython/CircuitPythonDevices.py	Thu Feb 02 13:42:50 2023 +0100
+++ b/src/eric7/MicroPython/CircuitPythonDevices.py	Thu Feb 02 18:01:00 2023 +0100
@@ -11,6 +11,7 @@
 import shutil
 
 from PyQt6.QtCore import pyqtSlot
+from PyQt6.QtWidgets import QMenu
 
 from eric7 import Preferences
 from eric7.EricWidgets import EricFileDialog, EricMessageBox
@@ -27,7 +28,7 @@
 
     DeviceVolumeName = "CIRCUITPY"
 
-    def __init__(self, microPythonWidget, deviceType, parent=None):
+    def __init__(self, microPythonWidget, deviceType, boardName, parent=None):
         """
         Constructor
 
@@ -35,11 +36,14 @@
         @type MicroPythonWidget
         @param deviceType device type assigned to this device interface
         @type str
+        @param boardName name of the board
+        @type str
         @param parent reference to the parent object
         @type QObject
         """
         super().__init__(microPythonWidget, deviceType, parent)
 
+        self.__boardName = boardName
         self.__workspace = self.__findWorkspace()
 
         self.__nonUF2devices = {
@@ -164,6 +168,27 @@
             self.__workspace = self.__findWorkspace(silent=silent)
             return self.__workspace
 
+    def __findDeviceDirectories(self, directories):
+        """
+        Private method to find the device directories associated with the
+        current board name.
+
+        @param directories list of directories to be checked
+        @type list of str
+        @return list of associated directories
+        @rtype list of str
+        """
+        boardDirectories = []
+        for directory in directories:
+            bootFile = os.path.join(directory, "boot_out.txt")
+            if os.path.exists(bootFile):
+                with open(bootFile, "r") as f:
+                    line = f.readline()
+                if self.__boardName in line:
+                    boardDirectories.append(directory)
+
+        return boardDirectories
+
     def __findWorkspace(self, silent=False):
         """
         Private method to find the workspace directory.
@@ -183,7 +208,13 @@
             if len(deviceDirectories) == 1:
                 return deviceDirectories[0]
             else:
-                return self.selectDeviceDirectory(deviceDirectories)
+                boardDirectories = self.__findDeviceDirectories(deviceDirectories)
+                if len(boardDirectories) == 1:
+                    return boardDirectories[0]
+                elif len(boardDirectories) > 1:
+                    return self.selectDeviceDirectory(boardDirectories)
+                else:
+                    return self.selectDeviceDirectory(deviceDirectories)
         else:
             # return the default workspace and give the user a warning (unless
             # silent mode is selected)
@@ -210,15 +241,23 @@
         """
         connected = self.microPython.isConnected()
 
+        self.__libraryMenu = QMenu(self.tr("Library Management"))
+        act = self.__libraryMenu.addAction(
+            self.tr("Install Library Files"), self.__installLibraryFiles
+        )
+        act.setEnabled(self.__deviceVolumeMounted())
+        act = self.__libraryMenu.addAction(
+            self.tr("Install Library Package"),
+            lambda: self.__installLibraryFiles(packageMode=True),
+        )
+        act.setEnabled(self.__deviceVolumeMounted())
+
         act = menu.addAction(
             self.tr("Flash CircuitPython Firmware"), self.__flashCircuitPython
         )
         act.setEnabled(not connected)
         menu.addSeparator()
-        act = menu.addAction(
-            self.tr("Install Library Files"), self.__installLibraryFiles
-        )
-        act.setEnabled(self.__deviceVolumeMounted())
+        menu.addMenu(self.__libraryMenu)
 
     def hasFlashMenuEntry(self):
         """
@@ -265,14 +304,23 @@
         )
 
     @pyqtSlot()
-    def __installLibraryFiles(self):
+    def __installLibraryFiles(self, packageMode=False):
         """
         Private slot to install Python files into the onboard library.
+
+        @param packageMode flag indicating to install a library package
+            (defaults to False)
+        @type bool (optional)
         """
+        title = (
+            self.tr("Install Library Package")
+            if packageMode
+            else self.tr("Install Library Files")
+        )
         if not self.__deviceVolumeMounted():
             EricMessageBox.critical(
                 self.microPython,
-                self.tr("Install Library Files"),
+                title,
                 self.tr(
                     """The device volume "<b>{0}</b>" is not available."""
                     """ Ensure it is mounted properly and try again."""
@@ -285,20 +333,32 @@
         if not os.path.isdir(target):
             os.makedirs(target)
 
-        libraryFiles = EricFileDialog.getOpenFileNames(
-            self.microPython,
-            self.tr("Install Library Files"),
-            os.path.expanduser("~"),
-            self.tr(
-                "Compiled Python Files (*.mpy);;"
-                "Python Files (*.py);;"
-                "All Files (*)"
-            ),
-        )
+        if packageMode:
+            libraryPackage = EricFileDialog.getExistingDirectory(
+                self.microPython,
+                title,
+                os.path.expanduser("~"),
+                EricFileDialog.Option(0),
+            )
+            if libraryPackage:
+                target = os.path.join(target, os.path.basename(libraryPackage))
+                shutil.rmtree(target, ignore_errors=True)
+                shutil.copytree(libraryPackage, target)
+        else:
+            libraryFiles = EricFileDialog.getOpenFileNames(
+                self.microPython,
+                title,
+                os.path.expanduser("~"),
+                self.tr(
+                    "Compiled Python Files (*.mpy);;"
+                    "Python Files (*.py);;"
+                    "All Files (*)"
+                ),
+            )
 
-        for libraryFile in libraryFiles:
-            if os.path.exists(libraryFile):
-                shutil.copy2(libraryFile, target)
+            for libraryFile in libraryFiles:
+                if os.path.exists(libraryFile):
+                    shutil.copy2(libraryFile, target)
 
     def getDocumentationUrl(self):
         """
@@ -329,7 +389,7 @@
         ]
 
 
-def createDevice(microPythonWidget, deviceType, vid, pid):
+def createDevice(microPythonWidget, deviceType, vid, pid, boardName):
     """
     Function to instantiate a MicroPython device object.
 
@@ -341,7 +401,9 @@
     @type int
     @param pid product ID
     @type int
+    @param boardName name of the board
+    @type str
     @return reference to the instantiated device object
     @rtype CircuitPythonDevice
     """
-    return CircuitPythonDevice(microPythonWidget, deviceType)
+    return CircuitPythonDevice(microPythonWidget, deviceType, boardName)

eric ide

mercurial