src/eric7/RemoteServerInterface/EricServerFileSystemInterface.py

branch
server
changeset 10610
bb0149571d94
parent 10605
b6f5e27daeb5
child 10631
00f5aae565a3
equal deleted inserted replaced
10605:b6f5e27daeb5 10610:bb0149571d94
18 from eric7 import Utilities 18 from eric7 import Utilities
19 from eric7.RemoteServer.EricRequestCategory import EricRequestCategory 19 from eric7.RemoteServer.EricRequestCategory import EricRequestCategory
20 from eric7.SystemUtilities import FileSystemUtilities 20 from eric7.SystemUtilities import FileSystemUtilities
21 21
22 22
23 class EricServerNotConnectedError(OSError):
24 """
25 Class defining a special OSError indicating a missing server connection.
26 """
27
28 def __init__(self):
29 """
30 Constructor
31 """
32 super().__init("Not connected to an 'eric-ide' server.")
33
34
23 class EricServerFileSystemInterface(QObject): 35 class EricServerFileSystemInterface(QObject):
24 """ 36 """
25 Class implementing the file system interface to the eric-ide server. 37 Class implementing the file system interface to the eric-ide server.
26 """ 38 """
27 39
28 _MagicCheck = re.compile("([*?[])") 40 _MagicCheck = re.compile("([*?[])")
29 41
42 NotConnectedMessage = "Not connected to an 'eric-ide' server."
43
30 def __init__(self, serverInterface): 44 def __init__(self, serverInterface):
31 """ 45 """
32 Constructor 46 Constructor
33 47
34 @param serverInterface reference to the eric-ide server interface 48 @param serverInterface reference to the eric-ide server interface
141 callback=callback, 155 callback=callback,
142 ) 156 )
143 157
144 loop.exec() 158 loop.exec()
145 159
146 return cwd 160 return FileSystemUtilities.remoteFileName(cwd)
147 161
148 def chdir(self, directory): 162 def chdir(self, directory):
149 """ 163 """
150 Public method to change the current working directory of the eric-ide server. 164 Public method to change the current working directory of the eric-ide server.
151 165
185 199
186 loop.exec() 200 loop.exec()
187 return ok, error 201 return ok, error
188 202
189 else: 203 else:
190 return False, "Not connected to an 'eric-ide' server." 204 return False, EricServerFileSystemInterface.NotConnectedMessage
191 205
192 def listdir(self, directory=""): 206 def listdir(self, directory=""):
193 """ 207 """
194 Public method to get a directory listing. 208 Public method to get a directory listing.
195 209
196 @param directory directory to be listed. An empty directory means to list 210 @param directory directory to be listed. An empty directory means to list
197 the eric-ide server current directory. (defaults to "") 211 the eric-ide server current directory. (defaults to "")
198 @type str (optional) 212 @type str (optional)
199 @return tuple containing the listed directory, the path separartor and the 213 @return tuple containing the listed directory, the path separator and the
200 directory listing. Each directory listing entry contains a dictionary 214 directory listing. Each directory listing entry contains a dictionary
201 with the relevant data. 215 with the relevant data.
202 @rtype tuple of (str, str, dict) 216 @rtype tuple of (str, str, dict)
203 @exception OSError raised in case the server reported an issue 217 @exception OSError raised in case the server reported an issue
204 """ 218 """
328 342
329 loop.exec() 343 loop.exec()
330 if not ok: 344 if not ok:
331 raise OSError(error) 345 raise OSError(error)
332 346
333 return result 347 return [FileSystemUtilities.remoteFileName(r) for r in result]
334 348
335 def glob(self, pathname, recursive=False, includeHidden=False): 349 def glob(self, pathname, recursive=False, includeHidden=False):
336 """ 350 """
337 Public method to get a list of of all files matching a given pattern 351 Public method to get a list of of all files matching a given pattern
338 like 'glob.glob()'. 352 like 'glob.glob()'.
585 599
586 loop.exec() 600 loop.exec()
587 return ok, error 601 return ok, error
588 602
589 else: 603 else:
590 return False, "Not connected to an 'eric-ide' server." 604 return False, EricServerFileSystemInterface.NotConnectedMessage
591 605
592 def makedirs(self, directory, exist_ok=False): 606 def makedirs(self, directory, exist_ok=False):
593 """ 607 """
594 Public method to create a new directory on the eric-ide serverincluding all 608 Public method to create a new directory on the eric-ide serverincluding all
595 intermediate-level directories. 609 intermediate-level directories.
636 650
637 loop.exec() 651 loop.exec()
638 return ok, error 652 return ok, error
639 653
640 else: 654 else:
641 return False, "Not connected to an 'eric-ide' server." 655 return False, EricServerFileSystemInterface.NotConnectedMessage
642 656
643 def rmdir(self, directory): 657 def rmdir(self, directory):
644 """ 658 """
645 Public method to delete a directory on the eric-ide server. 659 Public method to delete a directory on the eric-ide server.
646 660
680 694
681 loop.exec() 695 loop.exec()
682 return ok, error 696 return ok, error
683 697
684 else: 698 else:
685 return False, "Not connected to an 'eric-ide' server." 699 return False, EricServerFileSystemInterface.NotConnectedMessage
686 700
687 def replace(self, oldName, newName): 701 def replace(self, oldName, newName):
688 """ 702 """
689 Public method to rename a file or directory. 703 Public method to rename a file or directory.
690 704
729 743
730 loop.exec() 744 loop.exec()
731 return ok, error 745 return ok, error
732 746
733 else: 747 else:
734 return False, "Not connected to an 'eric-ide' server." 748 return False, EricServerFileSystemInterface.NotConnectedMessage
735 749
736 def remove(self, filename): 750 def remove(self, filename):
737 """ 751 """
738 Public method to delete a file on the eric-ide server. 752 Public method to delete a file on the eric-ide server.
739 753
773 787
774 loop.exec() 788 loop.exec()
775 return ok, error 789 return ok, error
776 790
777 else: 791 else:
778 return False, "Not connected to an 'eric-ide' server." 792 return False, EricServerFileSystemInterface.NotConnectedMessage
779 793
780 def expanduser(self, name): 794 def expanduser(self, name):
781 """ 795 """
782 Public method to expand an initial '~' or '~user' component. 796 Public method to expand an initial '~' or '~user' component.
783 797
833 847
834 @return path separator 848 @return path separator
835 @rtype str 849 @rtype str
836 """ 850 """
837 return self.__serverPathSep 851 return self.__serverPathSep
852
853 def isabs(self, p):
854 """
855 Public method to chack a path for being an absolute path.
856
857 @param p path to be checked
858 @type str
859 @return flag indicating an absolute path
860 @rtype bool
861 """
862 if self.__serverInterface.isServerConnected():
863 if self.__serverPathSep == "\\":
864 s = FileSystemUtilities.plainFileName(p)[:3].replace("/", "\\")
865 return s.startswith("\\)") or s.startswith(":\\", 1)
866 else:
867 return FileSystemUtilities.plainFileName(p).startswith("/")
868 else:
869 return os.path.isabs(p)
870
871 def abspath(self, p):
872 """
873 Public method to convert the given path to an absolute path.
874
875 @param p path to be converted
876 @type str
877 @return absolute path
878 @rtype str
879 """
880 if self.__serverInterface.isServerConnected():
881 p = FileSystemUtilities.plainFileName(p)
882 if not self.isabs(p):
883 p = self.join(self.getcwd(), p)
884 return FileSystemUtilities.remoteFileName(p)
885 else:
886 return os.path.abspath(p)
838 887
839 def join(self, a, *p): 888 def join(self, a, *p):
840 """ 889 """
841 Public method to join two or more path name components using the path separator 890 Public method to join two or more path name components using the path separator
842 of the server side. 891 of the server side.
988 @param create flag indicating to create an empty file, if it does not exist 1037 @param create flag indicating to create an empty file, if it does not exist
989 (defaults to False) 1038 (defaults to False)
990 @type bool (optional) 1039 @type bool (optional)
991 @return bytes data read from the eric-ide server 1040 @return bytes data read from the eric-ide server
992 @rtype bytes 1041 @rtype bytes
1042 @exception EricServerNotConnectedError raised to indicate a missing server
1043 connection
993 @exception OSError raised in case the server reported an issue 1044 @exception OSError raised in case the server reported an issue
994 """ 1045 """
995 loop = QEventLoop() 1046 loop = QEventLoop()
996 ok = False 1047 ok = False
997 error = "" 1048 error = ""
1017 else: 1068 else:
1018 error = params["error"] 1069 error = params["error"]
1019 loop.quit() 1070 loop.quit()
1020 1071
1021 if not self.__serverInterface.isServerConnected(): 1072 if not self.__serverInterface.isServerConnected():
1022 raise OSError("Not connected to an 'eric-ide' server.") 1073 raise EricServerNotConnectedError()
1023 1074
1024 else: 1075 else:
1025 self.__serverInterface.sendJson( 1076 self.__serverInterface.sendJson(
1026 category=EricRequestCategory.FileSystem, 1077 category=EricRequestCategory.FileSystem,
1027 request="ReadFile", 1078 request="ReadFile",
1047 @param data data to be written 1098 @param data data to be written
1048 @type bytes 1099 @type bytes
1049 @param withBackup flag indicating to create a backup file first 1100 @param withBackup flag indicating to create a backup file first
1050 (defaults to False) 1101 (defaults to False)
1051 @type bool (optional) 1102 @type bool (optional)
1103 @exception EricServerNotConnectedError raised to indicate a missing server
1104 connection
1052 @exception OSError raised in case the server reported an issue 1105 @exception OSError raised in case the server reported an issue
1053 """ 1106 """
1054 loop = QEventLoop() 1107 loop = QEventLoop()
1055 ok = False 1108 ok = False
1056 error = "" 1109 error = ""
1071 with contextlib.suppress(KeyError): 1124 with contextlib.suppress(KeyError):
1072 error = params["error"] 1125 error = params["error"]
1073 loop.quit() 1126 loop.quit()
1074 1127
1075 if not self.__serverInterface.isServerConnected(): 1128 if not self.__serverInterface.isServerConnected():
1076 raise OSError("Not connected to an 'eric-ide' server.") 1129 raise EricServerNotConnectedError
1077 1130
1078 else: 1131 else:
1079 self.__serverInterface.sendJson( 1132 self.__serverInterface.sendJson(
1080 category=EricRequestCategory.FileSystem, 1133 category=EricRequestCategory.FileSystem,
1081 request="WriteFile", 1134 request="WriteFile",
1154 ####################################################################### 1207 #######################################################################
1155 ## Methods implementing some 'shutil' like functionality. 1208 ## Methods implementing some 'shutil' like functionality.
1156 ####################################################################### 1209 #######################################################################
1157 1210
1158 def shutilCopy(self, srcName, dstName): 1211 def shutilCopy(self, srcName, dstName):
1212 """
1213 Public method to copy a source file to a given destination file or directory.
1214
1215 @param srcName name of the source file
1216 @type str
1217 @param dstName name of the destination file or directory
1218 @type str
1219 @return name of the destination file
1220 @rtype str
1221 @exception EricServerNotConnectedError raised to indicate a missing server
1222 connection
1223 @exception OSError raised to indicate an issue
1224 """
1159 loop = QEventLoop() 1225 loop = QEventLoop()
1160 ok = False 1226 ok = False
1161 error = "" 1227 error = ""
1162 dst = "" 1228 dst = ""
1163 1229
1179 else: 1245 else:
1180 error = params["error"] 1246 error = params["error"]
1181 loop.quit() 1247 loop.quit()
1182 1248
1183 if not self.__serverInterface.isServerConnected(): 1249 if not self.__serverInterface.isServerConnected():
1184 raise OSError("Not connected to an 'eric-ide' server.") 1250 raise EricServerNotConnectedError
1185 1251
1186 else: 1252 else:
1187 self.__serverInterface.sendJson( 1253 self.__serverInterface.sendJson(
1188 category=EricRequestCategory.FileSystem, 1254 category=EricRequestCategory.FileSystem,
1189 request="ShutilCopy", 1255 request="ShutilCopy",
1197 loop.exec() 1263 loop.exec()
1198 if not ok: 1264 if not ok:
1199 raise OSError(error) 1265 raise OSError(error)
1200 1266
1201 return dst 1267 return dst
1268
1269 def shutilRmtree(self, pathname, ignore_errors=False):
1270 """
1271 Public method to delete an entire directory tree.
1272
1273 @param pathname name of the directory to be deleted
1274 @type str
1275 @param ignore_errors flag indicating to ignore error resulting from failed
1276 removals (defaults to False)
1277 @type bool (optional)
1278 @exception EricServerNotConnectedError raised to indicate a missing server
1279 connection
1280 @exception OSError raised to indicate an issue
1281 """
1282 loop = QEventLoop()
1283 ok = False
1284 error = ""
1285
1286 def callback(reply, params):
1287 """
1288 Function to handle the server reply
1289
1290 @param reply name of the server reply
1291 @type str
1292 @param params dictionary containing the reply data
1293 @type dict
1294 """
1295 nonlocal ok, error
1296
1297 if reply == "ShutilRmtree":
1298 ok = params["ok"]
1299 if not ok:
1300 error = params["error"]
1301 loop.quit()
1302
1303 if not self.__serverInterface.isServerConnected():
1304 raise EricServerNotConnectedError
1305
1306 else:
1307 self.__serverInterface.sendJson(
1308 category=EricRequestCategory.FileSystem,
1309 request="ShutilRmtree",
1310 params={
1311 "name": FileSystemUtilities.plainFileName(pathname),
1312 "ignore_errors": ignore_errors,
1313 },
1314 callback=callback,
1315 )
1316
1317 loop.exec()
1318 if not ok:
1319 raise OSError(error)
1320
1321 #######################################################################
1322 ## Utility methods.
1323 #######################################################################
1324
1325 def compactPath(self, longPath, width, measure=len):
1326 """
1327 Public method to return a compacted path fitting inside the given width.
1328
1329 @param longPath path to be compacted
1330 @type str
1331 @param width width for the compacted path
1332 @type int
1333 @param measure reference to a function used to measure the length of the
1334 string (defaults to len)
1335 @type function (optional)
1336 @return compacted path
1337 @rtype str
1338 """
1339 if measure(longPath) <= width:
1340 return longPath
1341
1342 ellipsis = "..."
1343
1344 head, tail = self.split(longPath)
1345 mid = len(head) // 2
1346 head1 = head[:mid]
1347 head2 = head[mid:]
1348 while head1:
1349 # head1 is same size as head2 or one shorter
1350 cpath = self.join(f"{head1}{ellipsis}{head2}", tail)
1351 if measure(cpath) <= width:
1352 return cpath
1353 head1 = head1[:-1]
1354 head2 = head2[1:]
1355 cpath = self.join(ellipsis, tail)
1356 if measure(cpath) <= width:
1357 return cpath
1358 remoteMarker = FileSystemUtilities.remoteFileName("")
1359 if width <= len(remoteMarker):
1360 return f"{remoteMarker}{ellipsis}{tail}"
1361 while tail:
1362 cpath = f"{remoteMarker}{ellipsis}{tail}"
1363 if measure(cpath) <= width:
1364 return cpath
1365 tail = tail[1:]
1366 return ""

eric ide

mercurial