Fri, 23 Feb 2024 16:52:01 +0100
Adapted the project 'Add Files' and 'Add Directory' functions to work with remote projects.
--- a/src/eric7/EricWidgets/EricPathPicker.py Fri Feb 23 16:50:50 2024 +0100 +++ b/src/eric7/EricWidgets/EricPathPicker.py Fri Feb 23 16:52:01 2024 +0100 @@ -22,8 +22,11 @@ ) from eric7.EricGui import EricPixmapCache +from eric7.RemoteServerInterface import EricServerFileDialog +from eric7.SystemUtilities import FileSystemUtilities from . import EricFileDialog +from .EricApplication import ericApp from .EricCompleters import EricDirCompleter, EricFileCompleter @@ -83,6 +86,8 @@ self.__mode = EricPathPicker.DefaultMode self.__editorEnabled = True + self.__remote = False + self.__remotefsInterface = None self._completer = None self.__filters = "" @@ -187,6 +192,30 @@ """ return self.__mode + def setRemote(self, remote): + """ + Public method to set the remote mode of the path picker. + + @param remote flag indicating the remote mode + @type bool + """ + self.__remote = remote + if remote: + self.__remotefsInterface = ( + ericApp().getObject("EricServer").getServiceInterface("FileSystem") + ) + else: + self.__remotefsInterface = None + + def isRemote(self): + """ + Public method to get the path picker remote mode. + + @return flag indicating the remote mode + @rtype bool + """ + return self.__remote + def setPickerEnabled(self, enable): """ Public method to set the enabled state of the file dialog button. @@ -290,10 +319,15 @@ else: return self._editorText() else: - if toNative: - return os.path.expanduser(QDir.toNativeSeparators(self._editorText())) + if self.__remote: + return self.__remotefsInterface.expanduser(self._editorText()) else: - return os.path.expanduser(self._editorText()) + if toNative: + return os.path.expanduser( + QDir.toNativeSeparators(self._editorText()) + ) + else: + return os.path.expanduser(self._editorText()) def setEditText(self, fpath, toNative=True): """ @@ -370,6 +404,39 @@ """ return self.paths()[-1] + def strPaths(self): + """ + Public method to get the list of entered paths as strings. + + @return entered paths + @rtype list of str + """ + if self.__mode in ( + EricPathPickerModes.OPEN_FILES_MODE, + EricPathPickerModes.OPEN_FILES_AND_DIRS_MODE, + ): + return self.text().split(";") + else: + return [self.text()] + + def firstStrPath(self): + """ + Public method to get the first path of a list of entered paths as a string. + + @return first path + @rtype pathlib.Path + """ + return self.strPaths()[0] + + def lastStrPath(self): + """ + Public method to get the last path of a list of entered paths as a string. + + @return last path + @rtype pathlib.Path + """ + return self.strPaths()[-1] + def setEditorEnabled(self, enable): """ Public method to set the path editor's enabled state. @@ -534,76 +601,138 @@ directory = self._editorText() if not directory and self.__defaultDirectory: directory = self.__defaultDirectory - directory = ( - os.path.expanduser(directory.split(";")[0]) - if self.__mode - in ( - EricPathPickerModes.OPEN_FILES_MODE, - EricPathPickerModes.OPEN_FILES_AND_DIRS_MODE, + if self.__remote: + directory = ( + self.__remotefsInterface.expanduser(directory.split(";")[0]) + if self.__mode == EricPathPickerModes.OPEN_FILES_MODE + else self.__remotefsInterface.expanduser(directory) ) - else os.path.expanduser(directory) - ) - if not os.path.isabs(directory) and self.__defaultDirectory: - directory = os.path.join(self.__defaultDirectory, directory) - directory = QDir.fromNativeSeparators(directory) + else: + directory = ( + os.path.expanduser(directory.split(";")[0]) + if self.__mode + in ( + EricPathPickerModes.OPEN_FILES_MODE, + EricPathPickerModes.OPEN_FILES_AND_DIRS_MODE, + ) + else os.path.expanduser(directory) + ) + if not os.path.isabs(directory) and self.__defaultDirectory: + directory = os.path.join(self.__defaultDirectory, directory) + directory = QDir.fromNativeSeparators(directory) if self.__mode == EricPathPickerModes.OPEN_FILE_MODE: - fpath = EricFileDialog.getOpenFileName( - self, windowTitle, directory, self.__filters - ) - fpath = QDir.toNativeSeparators(fpath) + if self.__remote: + fpath = EricServerFileDialog.getOpenFileName( + self, windowTitle, directory, self.__filters + ) + else: + fpath = EricFileDialog.getOpenFileName( + self, windowTitle, directory, self.__filters + ) + fpath = QDir.toNativeSeparators(fpath) elif self.__mode == EricPathPickerModes.OPEN_FILES_MODE: - fpaths = EricFileDialog.getOpenFileNames( - self, windowTitle, directory, self.__filters - ) - fpath = ";".join([QDir.toNativeSeparators(fpath) for fpath in fpaths]) + if self.__remote: + fpaths = EricServerFileDialog.getOpenFileNames( + self, windowTitle, directory, self.__filters + ) + fpath = ";".join(fpaths) + else: + fpaths = EricFileDialog.getOpenFileNames( + self, windowTitle, directory, self.__filters + ) + fpath = ";".join([QDir.toNativeSeparators(fpath) for fpath in fpaths]) elif self.__mode == EricPathPickerModes.OPEN_FILES_AND_DIRS_MODE: + # that is not supported for 'remote' pickers fpaths = EricFileDialog.getOpenFileAndDirNames( self, windowTitle, directory, self.__filters ) fpath = ";".join([QDir.toNativeSeparators(fpath) for fpath in fpaths]) elif self.__mode == EricPathPickerModes.SAVE_FILE_MODE: - fpath = EricFileDialog.getSaveFileName( - self, - windowTitle, - directory, - self.__filters, - EricFileDialog.DontConfirmOverwrite, - ) - fpath = QDir.toNativeSeparators(fpath) + if self.__remote: + fpath = EricServerFileDialog.getSaveFileName( + self, + windowTitle, + directory, + self.__filters, + ) + else: + fpath = EricFileDialog.getSaveFileName( + self, + windowTitle, + directory, + self.__filters, + EricFileDialog.DontConfirmOverwrite, + ) + fpath = QDir.toNativeSeparators(fpath) elif self.__mode == EricPathPickerModes.SAVE_FILE_ENSURE_EXTENSION_MODE: - fpath, selectedFilter = EricFileDialog.getSaveFileNameAndFilter( - self, - windowTitle, - directory, - self.__filters, - None, - EricFileDialog.DontConfirmOverwrite, - ) - fpath = pathlib.Path(fpath) - if not fpath.suffix: - ex = selectedFilter.split("(*")[1].split(")")[0].split()[0] - if ex: - fpath = fpath.with_suffix(ex) + if self.__remote: + fpath, selectedFilter = EricServerFileDialog.getSaveFileNameAndFilter( + self, + windowTitle, + directory, + self.__filters, + ) + fn, ext = self.__remotefsInterface.splitext(fpath) + if not ext: + ex = selectedFilter.split("(*")[1].split(")")[0].split()[0] + if ex: + fpath = f"{fn}{ex}" + else: + fpath, selectedFilter = EricFileDialog.getSaveFileNameAndFilter( + self, + windowTitle, + directory, + self.__filters, + None, + EricFileDialog.DontConfirmOverwrite, + ) + fpath = pathlib.Path(fpath) + if not fpath.suffix: + ex = selectedFilter.split("(*")[1].split(")")[0].split()[0] + if ex: + fpath = fpath.with_suffix(ex) elif self.__mode == EricPathPickerModes.SAVE_FILE_OVERWRITE_MODE: - fpath = EricFileDialog.getSaveFileName( - self, windowTitle, directory, self.__filters - ) - fpath = QDir.toNativeSeparators(fpath) + if self.__remote: + fpath = EricServerFileDialog.getSaveFileName( + self, + windowTitle, + directory, + self.__filters, + ) + else: + fpath = EricFileDialog.getSaveFileName( + self, windowTitle, directory, self.__filters + ) + fpath = QDir.toNativeSeparators(fpath) elif self.__mode == EricPathPickerModes.DIRECTORY_MODE: - fpath = EricFileDialog.getExistingDirectory( - self, windowTitle, directory, EricFileDialog.ShowDirsOnly - ) - fpath = QDir.toNativeSeparators(fpath) - while fpath.endswith(os.sep): - fpath = fpath[:-1] + if self.__remote: + fpath = EricServerFileDialog.getExistingDirectory( + self, windowTitle, directory, True + ) + while fpath.endswith(self.__remotefsInterface.separator()): + fpath = fpath[:-1] + else: + fpath = EricFileDialog.getExistingDirectory( + self, windowTitle, directory, EricFileDialog.ShowDirsOnly + ) + fpath = QDir.toNativeSeparators(fpath) + while fpath.endswith(os.sep): + fpath = fpath[:-1] elif self.__mode == EricPathPickerModes.DIRECTORY_SHOW_FILES_MODE: - fpath = EricFileDialog.getExistingDirectory( - self, windowTitle, directory, EricFileDialog.DontUseNativeDialog - ) - fpath = QDir.toNativeSeparators(fpath) - while fpath.endswith(os.sep): - fpath = fpath[:-1] + if self.__remote: + fpath = EricServerFileDialog.getExistingDirectory( + self, windowTitle, directory, False + ) + while fpath.endswith(self.__remotefsInterface): + fpath = fpath[:-1] + else: + fpath = EricFileDialog.getExistingDirectory( + self, windowTitle, directory, EricFileDialog.DontUseNativeDialog + ) + fpath = QDir.toNativeSeparators(fpath) + while fpath.endswith(os.sep): + fpath = fpath[:-1] if fpath: self._setEditorText(str(fpath)) @@ -766,3 +895,17 @@ for index in range(self._editor.count()): paths.append(pathlib.Path(self._editor.itemText(index))) return paths + + def getRemotePathItems(self): + """ + Public method to get the list of remembered remote paths. + + @return list of remembered paths + @rtype list of str + """ + paths = [] + for index in range(self._editor.count()): + paths.append( + FileSystemUtilities.remoteFileName(self._editor.itemText(index)) + ) + return paths
--- a/src/eric7/Project/AddDirectoryDialog.py Fri Feb 23 16:50:50 2024 +0100 +++ b/src/eric7/Project/AddDirectoryDialog.py Fri Feb 23 16:52:01 2024 +0100 @@ -8,9 +8,10 @@ """ from PyQt6.QtCore import pyqtSlot -from PyQt6.QtWidgets import QDialog +from PyQt6.QtWidgets import QDialog, QDialogButtonBox from eric7.EricWidgets.EricPathPicker import EricPathPickerModes +from eric7.SystemUtilities import FileSystemUtilities from .Ui_AddDirectoryDialog import Ui_AddDirectoryDialog @@ -42,13 +43,23 @@ self.setObjectName(name) self.setupUi(self) + self.__remoteMode = ( + bool(startdir) and FileSystemUtilities.isRemoteFileName(startdir) + ) or FileSystemUtilities.isRemoteFileName(pro.getProjectPath()) + self.sourceDirPicker.setMode(EricPathPickerModes.DIRECTORY_MODE) self.sourceDirPicker.setDefaultDirectory(startdir) + self.sourceDirPicker.setRemote(self.__remoteMode) + self.targetDirPicker.setMode(EricPathPickerModes.DIRECTORY_MODE) self.targetDirPicker.setDefaultDirectory(startdir) + self.targetDirPicker.setRemote(self.__remoteMode) self.__project = pro - self.targetDirPicker.setText(self.__project.getProjectPath()) + if startdir: + self.targetDirPicker.setText(startdir) + else: + self.targetDirPicker.setText(pro.getProjectPath()) if fileTypeFilter and fileTypeFilter != "TRANSLATIONS": self.filterComboBox.addItem( @@ -65,6 +76,8 @@ ) self.filterComboBox.setCurrentIndex(0) + self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setEnabled(False) + msh = self.minimumSizeHint() self.resize(max(self.width(), msh.width()), msh.height()) @@ -103,6 +116,10 @@ if directory.startswith(self.__project.getProjectPath()): self.targetDirPicker.setText(directory) + self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setEnabled( + bool(directory) + ) + def getData(self): """ Public slot to retrieve the dialogs data.
--- a/src/eric7/Project/AddFileDialog.py Fri Feb 23 16:50:50 2024 +0100 +++ b/src/eric7/Project/AddFileDialog.py Fri Feb 23 16:52:01 2024 +0100 @@ -10,9 +10,11 @@ import os from PyQt6.QtCore import pyqtSlot -from PyQt6.QtWidgets import QDialog +from PyQt6.QtWidgets import QDialog, QDialogButtonBox +from eric7.EricWidgets.EricApplication import ericApp from eric7.EricWidgets.EricPathPicker import EricPathPickerModes +from eric7.SystemUtilities import FileSystemUtilities from .Ui_AddFileDialog import Ui_AddFileDialog @@ -42,9 +44,16 @@ self.setObjectName(name) self.setupUi(self) + self.__remoteMode = ( + bool(startdir) and FileSystemUtilities.isRemoteFileName(startdir) + ) or FileSystemUtilities.isRemoteFileName(pro.getProjectPath()) + self.sourceFilesPicker.setMode(EricPathPickerModes.OPEN_FILES_MODE) + self.sourceFilesPicker.setRemote(self.__remoteMode) + self.targetDirPicker.setMode(EricPathPickerModes.DIRECTORY_MODE) self.targetDirPicker.setDefaultDirectory(startdir) + self.targetDirPicker.setRemote(self.__remoteMode) if startdir: self.targetDirPicker.setText(startdir) @@ -57,6 +66,8 @@ if self.fileTypeFilter is not None: self.sourcecodeCheckBox.hide() + self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setEnabled(False) + msh = self.minimumSizeHint() self.resize(max(self.width(), msh.width()), msh.height()) @@ -66,12 +77,16 @@ Private slot to perform actions before the source files selection dialog is shown. """ - path = self.targetDirPicker.text() - if not path: - path = self.startdir - self.sourceFilesPicker.setDefaultDirectory(path) + targetPath = self.targetDirPicker.text() + if not targetPath: + targetPath = self.startdir + self.sourceFilesPicker.setDefaultDirectory(targetPath) - caption = self.tr("Select Files") + caption = ( + self.tr("Select Files") + if self.__remoteMode + else self.tr("Select Remote Files") + ) if self.fileTypeFilter is None: dfilter = self.__project.getFileCategoryFilterString(withAll=True) elif ( @@ -103,14 +118,23 @@ @param sfile the text of the source file picker @type str """ - sfile = str(self.sourceFilesPicker.firstPath()) + sfile = self.sourceFilesPicker.firstStrPath() if sfile.startswith(self.__project.getProjectPath()): - if os.path.isdir(sfile): - directory = sfile + if self.__remoteMode: + fsInterface = ( + ericApp().getObject("EricServer").getServiceInterface("FileSystem") + ) + directory = ( + sfile if fsInterface.isdir(sfile) else fsInterface.dirname(sfile) + ) else: - directory = os.path.dirname(sfile) + directory = ( + sfile if os.path.isdir(sfile) else os.path.dirname(sfile) + ) self.targetDirPicker.setText(directory) + self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setEnabled(bool(sfile)) + def getData(self): """ Public slot to retrieve the dialogs data. @@ -120,7 +144,7 @@ @rtype tuple of (list of string, string, boolean) """ return ( - [str(p) for p in self.sourceFilesPicker.paths()], + self.sourceFilesPicker.strPaths(), self.targetDirPicker.text(), self.sourcecodeCheckBox.isChecked(), )
--- a/src/eric7/Project/Project.py Fri Feb 23 16:50:50 2024 +0100 +++ b/src/eric7/Project/Project.py Fri Feb 23 16:52:01 2024 +0100 @@ -2035,7 +2035,6 @@ @param startdir start directory for the selection dialog @type str """ - # TODO: adapt to remote server from .AddFileDialog import AddFileDialog if not startdir: @@ -2045,17 +2044,37 @@ if dlg.exec() == QDialog.DialogCode.Accepted: fnames, target, isSource = dlg.getData() if target != "": + isRemote = FileSystemUtilities.isRemoteFileName(target) for fn in fnames: - targetfile = os.path.join(target, os.path.basename(fn)) - if not FileSystemUtilities.samepath(os.path.dirname(fn), target): + targetfile = ( + self.__remotefsInterface.join( + target, self.__remotefsInterface.basename(fn) + ) + if isRemote + else os.path.join(target, os.path.basename(fn)) + ) + if not FileSystemUtilities.samepath( + self.__remotefsInterface.dirname(fn) + if isRemote + else os.path.dirname(fn), + target + ): try: - if not os.path.isdir(target): - os.makedirs(target) - - if os.path.exists(targetfile): + if isRemote: + if not self.__remotefsInterface.isdir(target): + self.__remotefsInterface.makedirs(target) + else: + if not os.path.isdir(target): + os.makedirs(target) + + if ( + not isRemote and os.path.exists(targetfile) + ) or ( + isRemote and self.__remotefsInterface.exists(targetfile) + ): res = EricMessageBox.yesNo( self.ui, - self.tr("Add file"), + self.tr("Add File"), self.tr( "<p>The file <b>{0}</b> already" " exists.</p><p>Overwrite it?</p>" @@ -2065,11 +2084,14 @@ if not res: return # don't overwrite - shutil.copy(fn, target) + if isRemote: + self.__remotefsInterface.shutilCopy(fn, target) + else: + shutil.copy(fn, target) except OSError as why: EricMessageBox.critical( self.ui, - self.tr("Add file"), + self.tr("Add File"), self.tr( "<p>The selected file <b>{0}</b> could" " not be added to <b>{1}</b>.</p>" @@ -2111,15 +2133,20 @@ ignorePatterns.append(pattern) files = [] + isRemote = FileSystemUtilities.isRemoteFileName(target) for pattern in patterns: - sstring = "{0}{1}{2}".format(source, os.sep, pattern) - files.extend(glob.glob(sstring)) + if isRemote: + sstring = self.__remotefsInterface.join(source, pattern) + files.extend(self.__remotefsInterface.glob(sstring)) + else: + sstring = os.path.join(source, pattern) + files.extend(glob.glob(sstring)) if len(files) == 0: if not quiet: EricMessageBox.information( self.ui, - self.tr("Add directory"), + self.tr("Add Directory"), self.tr( "<p>The source directory doesn't contain" " any files belonging to the selected category.</p>" @@ -2127,15 +2154,20 @@ ) return - if not FileSystemUtilities.samepath(target, source) and not os.path.isdir( - target + if not FileSystemUtilities.samepath(target, source) and not ( + (not isRemote and os.path.isdir(target)) or ( + isRemote and self.__remotefsInterface.isdir(target) + ) ): try: - os.makedirs(target) + if isRemote: + self.__remotefsInterface.makedirs(target) + else: + os.makedirs(target) except OSError as why: EricMessageBox.critical( self.ui, - self.tr("Add directory"), + self.tr("Add Directory"), self.tr( "<p>The target directory <b>{0}</b> could not be" " created.</p><p>Reason: {1}</p>" @@ -2148,13 +2180,23 @@ if fnmatch.fnmatch(file, pattern): continue - targetfile = os.path.join(target, os.path.basename(file)) + targetfile = ( + self.__remotefsInterface.join( + target, self.__remotefsInterface.basename(file) + ) + if isRemote + else os.path.join(target, os.path.basename(file)) + ) if not FileSystemUtilities.samepath(target, source): try: - if os.path.exists(targetfile): + if ( + not isRemote and os.path.exists(targetfile) + ) or ( + isRemote and self.__remotefsInterface.exists(targetfile) + ): res = EricMessageBox.yesNo( self.ui, - self.tr("Add directory"), + self.tr("Add Directory"), self.tr( "<p>The file <b>{0}</b> already exists.</p>" "<p>Overwrite it?</p>" @@ -2165,7 +2207,10 @@ continue # don't overwrite, carry on with next file - shutil.copy(file, target) + if isRemote: + self.__remotefsInterface.shutilCopy(file,target ) + else: + shutil.copy(file, target) except OSError: continue self.appendFile(targetfile) @@ -2202,16 +2247,28 @@ if filetype == "__IGNORE__" ] - # now recurse into subdirectories - with os.scandir(source) as dirEntriesIterator: - for dirEntry in dirEntriesIterator: - if dirEntry.is_dir() and not any( - fnmatch.fnmatch(dirEntry.name, ignore_pattern) + # now recurs into subdirectories + if FileSystemUtilities.isRemoteFileName(target): + for entry in self.__remotefsInterface.listdir(source)[2]: + if entry["is_dir"] and not any( + fnmatch.fnmatch(entry["name"], ignore_pattern) for ignore_pattern in ignore_patterns ): self.__addRecursiveDirectory( - filetype, dirEntry.path, os.path.join(target, dirEntry.name) + filetype, + entry["path"], + self.__remotefsInterface.join(target, entry["name"]), ) + else: + with os.scandir(source) as dirEntriesIterator: + for dirEntry in dirEntriesIterator: + if dirEntry.is_dir() and not any( + fnmatch.fnmatch(dirEntry.name, ignore_pattern) + for ignore_pattern in ignore_patterns + ): + self.__addRecursiveDirectory( + filetype, dirEntry.path, os.path.join(target, dirEntry.name) + ) @pyqtSlot() def addDirectory(self, fileTypeFilter=None, startdir=None):
--- a/src/eric7/Project/ProjectBrowserModel.py Fri Feb 23 16:50:50 2024 +0100 +++ b/src/eric7/Project/ProjectBrowserModel.py Fri Feb 23 16:52:01 2024 +0100 @@ -369,12 +369,14 @@ FileSystemUtilities.toNativeSeparators(f.absoluteFilePath()), parentItem.getProjectTypes()[0], False, + fsInterface=self.__remotefsInterface, ) if f.isDir() else ProjectBrowserFileItem( parentItem, FileSystemUtilities.toNativeSeparators(f.absoluteFilePath()), parentItem.getProjectTypes()[0], + fsInterface=self.__remotefsInterface, ) ) if self.project.vcs is not None: @@ -587,6 +589,7 @@ self.__projectBrowser.getProjectBrowserFilter(typeString), False, bold, + fsInterface=self.__remotefsInterface, ) else: if typeString == "SOURCES": @@ -600,6 +603,7 @@ False, bold, sourceLanguage=sourceLanguage, + fsInterface=self.__remotefsInterface, ) self.__addVCSStatus(itm, fname) if additionalTypeStrings: @@ -762,12 +766,14 @@ FileSystemUtilities.toNativeSeparators(f.absoluteFilePath()), itm.getProjectTypes()[0], False, + fsInterface=self.__remotefsInterface, ) if f.isDir() else ProjectBrowserFileItem( itm, FileSystemUtilities.toNativeSeparators(f.absoluteFilePath()), itm.getProjectTypes()[0], + fsInterface=self.__remotefsInterface, ) ) self._addItem(node, itm)
--- a/src/eric7/RemoteServer/EricServerFileSystemRequestHandler.py Fri Feb 23 16:50:50 2024 +0100 +++ b/src/eric7/RemoteServer/EricServerFileSystemRequestHandler.py Fri Feb 23 16:52:01 2024 +0100 @@ -10,6 +10,7 @@ import base64 import contextlib import os +import shutil import stat import time @@ -48,6 +49,8 @@ "ReadFile": self.__readFile, "WriteFile": self.__writeFile, "DirEntries": self.__dirEntries, + "ExpandUser": self.__expanduser, + "ShutilCopy": self.__shutilCopy, } def handleRequest(self, request, params, reqestUuid): @@ -400,3 +403,37 @@ "ok": True, "result": result, } + + def __expanduser(self, params): + """ + Private method to replace an initial component of ~ or ~user replaced. + + @param params dictionary containing the request data + @type dict + @return dictionary containing the reply data + @rtype dict + """ + return { + "ok": True, + "name": os.path.expanduser(params["name"]) + } + + def __shutilCopy(self, params): + """ + Private method to copy a source file to a destination file or directory. + + @param params dictionary containing the request data + @type dict + @return dictionary containing the reply data + @rtype dict + """ + try: + return { + "ok": True, + "dst": shutil.copy(params["src_name"], params["dst_name"]), + } + except OSError as err: + return { + "ok": False, + "error": str(err), + }
--- a/src/eric7/RemoteServerInterface/EricServerFileSystemInterface.py Fri Feb 23 16:50:50 2024 +0100 +++ b/src/eric7/RemoteServerInterface/EricServerFileSystemInterface.py Fri Feb 23 16:52:01 2024 +0100 @@ -246,6 +246,9 @@ if not ok: raise OSError(error) + for entry in listing: + entry["path"] = FileSystemUtilities.remoteFileName(entry["path"]) + return listedDirectory, separator, listing def direntries( @@ -353,9 +356,13 @@ dirname, pattern=basename, recursive=recursive, filesonly=True ) result = ( - entries + [FileSystemUtilities.remoteFileName(e) for e in entries] if includeHidden - else [e for e in entries if not e.startswith(".")] + else [ + FileSystemUtilities.remoteFileName(e) + for e in entries + if not e.startswith(".") + ] ) return result @@ -770,6 +777,49 @@ else: return False, "Not connected to an 'eric-ide' server." + def expanduser(self, name): + """ + Public method to expand an initial '~' or '~user' component. + + @param name path name to be expanded + @type str + @return expanded path name + @rtype str + """ + loop = QEventLoop() + ok = False + expandedName = name + + 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 ok, expandedName + + if reply == "ExpandUser": + ok = params["ok"] + expandedName = params["name"] + loop.quit() + + if self.__serverInterface.isServerConnected(): + self.__serverInterface.sendJson( + category=EricRequestCategory.FileSystem, + request="ExpandUser", + params={"name": FileSystemUtilities.plainFileName(name)}, + callback=callback, + ) + + loop.exec() + if FileSystemUtilities.isRemoteFileName(name): + return FileSystemUtilities.remoteFileName(expandedName) + else: + return expandedName + ####################################################################### ## Methods for splitting or joining remote path names. ## @@ -1100,3 +1150,52 @@ self.writeFile(filename, data, withBackup=withBackup) return encoding + + ####################################################################### + ## Methods implementing some 'shutil' like functionality. + ####################################################################### + + def shutilCopy(self, srcName, dstName): + loop = QEventLoop() + ok = False + error = "" + dst = "" + + 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 ok, error, dst + + if reply == "ShutilCopy": + ok = params["ok"] + if ok: + dst = params["dst"] + else: + error = params["error"] + loop.quit() + + if not self.__serverInterface.isServerConnected(): + raise OSError("Not connected to an 'eric-ide' server.") + + else: + self.__serverInterface.sendJson( + category=EricRequestCategory.FileSystem, + request="ShutilCopy", + params={ + "src_name": FileSystemUtilities.plainFileName(srcName), + "dst_name": FileSystemUtilities.plainFileName(dstName), + }, + callback=callback, + ) + + loop.exec() + if not ok: + raise OSError(error) + + return dst