Adapted the Code Metrics dialog to support remote files and directories. server

Fri, 16 Feb 2024 11:45:08 +0100

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Fri, 16 Feb 2024 11:45:08 +0100
branch
server
changeset 10576
0cf5ebf17411
parent 10575
abde60847db6
child 10577
b9edebd77c91

Adapted the Code Metrics dialog to support remote files and directories.

src/eric7/DataViews/CodeMetrics.py file | annotate | diff | comparison | revisions
src/eric7/DataViews/CodeMetricsDialog.py file | annotate | diff | comparison | revisions
src/eric7/QScintilla/Editor.py file | annotate | diff | comparison | revisions
src/eric7/RemoteServer/EricServerFileSystemRequestHandler.py file | annotate | diff | comparison | revisions
src/eric7/RemoteServerInterface/EricServerFileSystemInterface.py file | annotate | diff | comparison | revisions
--- a/src/eric7/DataViews/CodeMetrics.py	Fri Feb 16 09:32:27 2024 +0100
+++ b/src/eric7/DataViews/CodeMetrics.py	Fri Feb 16 11:45:08 2024 +0100
@@ -24,6 +24,8 @@
 from dataclasses import dataclass
 
 from eric7 import Utilities
+from eric7.EricWidgets.EricApplication import ericApp
+from eric7.SystemUtilities import FileSystemUtilities
 
 KEYWORD = token.NT_OFFSET + 1
 COMMENT = tokenize.COMMENT
@@ -226,7 +228,16 @@
     @rtype SourceStat
     """
     try:
-        text = Utilities.readEncodedFile(filename)[0]
+        if FileSystemUtilities.isRemoteFileName(filename):
+            remotefsInterface = (
+                ericApp().getObject("EricServer").getServiceInterface("FileSystem")
+            )
+            bText = remotefsInterface.readFile(
+                FileSystemUtilities.plainFileName(filename)
+            )
+            text = Utilities.decode(bText)[0]
+        else:
+            text = Utilities.readEncodedFile(filename)[0]
     except (OSError, UnicodeError):
         return SourceStat()
 
--- a/src/eric7/DataViews/CodeMetricsDialog.py	Fri Feb 16 09:32:27 2024 +0100
+++ b/src/eric7/DataViews/CodeMetricsDialog.py	Fri Feb 16 11:45:08 2024 +0100
@@ -56,6 +56,10 @@
 
         self.cancelled = False
 
+        self.__remotefsInterface = (
+            ericApp().getObject("EricServer").getServiceInterface("FileSystem")
+        )
+
         self.__menu = QMenu(self)
         self.__menu.addAction(self.tr("Collapse All"), self.__resultCollapse)
         self.__menu.addAction(self.tr("Expand All"), self.__resultExpand)
@@ -153,15 +157,26 @@
         loc = QLocale()
         if isinstance(fn, list):
             files = fn
-        elif os.path.isdir(fn):
+        elif FileSystemUtilities.isRemoteFileName(
+            fn
+        ) and self.__remotefsInterface.isdir(fn):
+            files = [
+                FileSystemUtilities.remoteFileName(f)
+                for f in self.__remotefsInterface.direntries(fn, True, "*.py", False)
+            ]
+        elif FileSystemUtilities.isPlainFileName(fn) and os.path.isdir(fn):
             files = FileSystemUtilities.direntries(fn, True, "*.py", False)
         else:
             files = [fn]
         files.sort()
         # check for missing files
         for f in files[:]:
-            if not os.path.exists(f):
-                files.remove(f)
+            if FileSystemUtilities.isRemoteFileName(f):
+                if not self.__remotefsInterface.exists(f):
+                    files.remove(f)
+            else:
+                if not os.path.exists(f):
+                    files.remove(f)
 
         self.checkProgress.setMaximum(len(files))
         QApplication.processEvents()
--- a/src/eric7/QScintilla/Editor.py	Fri Feb 16 09:32:27 2024 +0100
+++ b/src/eric7/QScintilla/Editor.py	Fri Feb 16 11:45:08 2024 +0100
@@ -265,9 +265,9 @@
         self.project = ericApp().getObject("Project")
         self.setFileName(fn)
 
-        self.__remotefsInterface = ericApp().getObject(
-            "EricServer"
-        ).getServiceInterface("FileSystem")
+        self.__remotefsInterface = (
+            ericApp().getObject("EricServer").getServiceInterface("FileSystem")
+        )
 
         # clear some variables
         self.lastHighlight = None  # remember the last highlighted line
@@ -3730,8 +3730,7 @@
                 path = ""
             else:
                 path = (
-                    Preferences.getMultiProject("Workspace")
-                    or OSUtilities.getHomeDir()
+                    Preferences.getMultiProject("Workspace") or OSUtilities.getHomeDir()
                 )
 
         if self.fileName:
@@ -3775,12 +3774,9 @@
                 if ex:
                     fpath = fpath.with_suffix(ex)
             if (
-                (
-                    FileSystemUtilities.isRemoteFileName(str(fpath))
-                    and self.__remotefsInterface.exists(str(fpath))
-                )
-                or (FileSystemUtilities.isPlainFileName(str(fpath)) and fpath.exists())
-            ):
+                FileSystemUtilities.isRemoteFileName(str(fpath))
+                and self.__remotefsInterface.exists(str(fpath))
+            ) or (FileSystemUtilities.isPlainFileName(str(fpath)) and fpath.exists()):
                 res = EricMessageBox.yesNo(
                     self,
                     title,
@@ -6515,11 +6511,6 @@
         )
         self.coverageHideAnnotationMenuAct.setEnabled(len(self.notcoveredMarkers) > 0)
 
-        # disable actions not supporting eric-ide server
-        self.codeMetricsAct.setEnabled(
-            False if fn is None else FileSystemUtilities.isPlainFileName(fn)
-        )
-
         # TODO: disable action in Radon plugin for server files
         self.showMenu.emit("Show", self.menuShow, self)
 
@@ -7056,9 +7047,9 @@
 
         if fn:
             if FileSystemUtilities.isRemoteFileName(fn):
-                coverageInterface = ericApp().getObject(
-                    "EricServer"
-                ).getServiceInterface("Coverage")
+                coverageInterface = (
+                    ericApp().getObject("EricServer").getServiceInterface("Coverage")
+                )
                 ok, error = coverageInterface.loadCoverageData(fn)
                 if not ok and not silent:
                     EricMessageBox.critical(
@@ -8317,9 +8308,7 @@
                 signal if there was an attribute change.
         @type bool
         """
-        if self.fileName == "" or FileSystemUtilities.isDeviceFileName(
-            self.fileName
-        ):
+        if self.fileName == "" or FileSystemUtilities.isDeviceFileName(self.fileName):
             return
 
         readOnly = self.checkReadOnly()
@@ -8348,7 +8337,8 @@
             or (
                 FileSystemUtilities.isRemoteFileName(self.fileName)
                 and not self.__remotefsInterface.access(
-                    FileSystemUtilities.plainFileName(self.fileName), "write")
+                    FileSystemUtilities.plainFileName(self.fileName), "write"
+                )
             )
             or self.isReadOnly()
         )
@@ -8438,9 +8428,9 @@
             ):
                 plainFilename = FileSystemUtilities.plainFileName(filename)
                 if self.__remotefsInterface.exists(plainFilename):
-                    mtime = self.__remotefsInterface.stat(
-                        plainFilename, ["st_mtime"]
-                    )["st_mtime"]
+                    mtime = self.__remotefsInterface.stat(plainFilename, ["st_mtime"])[
+                        "st_mtime"
+                    ]
                     return mtime != self.lastModified
 
             elif (
--- a/src/eric7/RemoteServer/EricServerFileSystemRequestHandler.py	Fri Feb 16 09:32:27 2024 +0100
+++ b/src/eric7/RemoteServer/EricServerFileSystemRequestHandler.py	Fri Feb 16 11:45:08 2024 +0100
@@ -13,6 +13,8 @@
 import stat
 import time
 
+from eric7.SystemUtilities import FileSystemUtilities
+
 from .EricRequestCategory import EricRequestCategory
 
 
@@ -41,9 +43,9 @@
             "Stat": self.__stat,
             "Exists": self.__exists,
             "Access": self.__access,
-
             "ReadFile": self.__readFile,
             "WriteFile": self.__writeFile,
+            "DirEntries": self.__dirEntries,
         }
 
     def handleRequest(self, request, params, reqestUuid):
@@ -303,7 +305,7 @@
                 data = f.read()
             return {
                 "ok": True,
-                "filedata": str(base64.b85encode(data), encoding="ascii")
+                "filedata": str(base64.b85encode(data), encoding="ascii"),
             }
         except OSError as err:
             return {
@@ -351,3 +353,25 @@
                 "ok": False,
                 "error": str(err),
             }
+
+    def __dirEntries(self, params):
+        """
+        Private method to get a list of all files and directories of a given directory.
+
+        @param params dictionary containing the request data
+        @type dict
+        @return dictionary containing the reply data
+        @rtype dict
+        """
+        directory = params["directory"]
+        result = FileSystemUtilities.direntries(
+            directory,
+            filesonly=params["files_only"],
+            pattern=params["pattern"],
+            followsymlinks=params["follow_symlinks"],
+            ignore=params["ignore"],
+        )
+        return {
+            "ok": True,
+            "result": result,
+        }
--- a/src/eric7/RemoteServerInterface/EricServerFileSystemInterface.py	Fri Feb 16 09:32:27 2024 +0100
+++ b/src/eric7/RemoteServerInterface/EricServerFileSystemInterface.py	Fri Feb 16 11:45:08 2024 +0100
@@ -9,6 +9,7 @@
 
 import base64
 import contextlib
+import stat
 
 from PyQt6.QtCore import QEventLoop, QObject
 
@@ -166,6 +167,72 @@
 
         return listedDirectory, separator, listing
 
+    def direntries(
+        self, directory, filesonly=False, pattern=None, followsymlinks=True, ignore=None
+    ):
+        """
+        Public method to get a list of all files and directories of a given directory.
+
+        @param directory root of the tree to check
+        @type str
+        @param filesonly flag indicating that only files are wanted (defaults to False)
+        @type bool (optional)
+        @param pattern a filename pattern or list of filename patterns to check
+            against (defaults to None)
+        @type str or list of str (optional)
+        @param followsymlinks flag indicating whether symbolic links should be
+            followed (defaults to True)
+        @type bool (optional)
+        @param ignore list of entries to be ignored (defaults to None)
+        @type list of str (optional)
+        @return list of all files and directories in the tree rooted at path.
+            The names are expanded to start with the given directory name.
+        @rtype list of str
+        @exception OSError raised in case the server reported an issue
+        """
+        loop = QEventLoop()
+        ok = False
+        error = ""
+        result = []
+
+        def callback(reply, params):
+            """
+            Function to handle the server reply
+
+            @param reply name of the server reply
+            @type str
+            @param params dictionary containing the reply data
+            @type dict
+            """
+            nonlocal result, ok, error
+
+            if reply == "DirEntries":
+                ok = params["ok"]
+                if ok:
+                    result = params["result"]
+                else:
+                    error = params["error"]
+                loop.quit()
+
+        self.__serverInterface.sendJson(
+            category=EricRequestCategory.FileSystem,
+            request="DirEntries",
+            params={
+                "directory": FileSystemUtilities.plainFileName(directory),
+                "files_only": filesonly,
+                "pattern": [] if pattern is None else pattern,
+                "follow_symlinks": followsymlinks,
+                "ignore": [] if ignore is None else ignore,
+            },
+            callback=callback,
+        )
+
+        loop.exec()
+        if not ok:
+            raise OSError(error)
+
+        return result
+
     def stat(self, filename, stNames):
         """
         Public method to get the status of a file.
@@ -218,6 +285,30 @@
 
         return stResult
 
+    def isdir(self, name):
+        """
+        Public method to check, if the given name is a directory.
+
+        @param name name to be checked
+        @type str
+        @return flag indicating a directory
+        @rtype bool
+        """
+        result = self.stat(name, ["st_mode"])
+        return stat.S_ISDIR(result["st_mode"])
+
+    def isfile(self, name):
+        """
+        Public method to check, if the given name is a regular file.
+
+        @param name name to be checked
+        @type str
+        @return flag indicating a regular file
+        @rtype bool
+        """
+        result = self.stat(name, ["st_mode"])
+        return stat.S_ISREG(result["st_mode"])
+
     def exists(self, name):
         """
         Public method the existence of a file or directory.

eric ide

mercurial