src/eric7/Utilities/FtpUtilities.py

branch
eric7
changeset 9221
bf71ee032bb4
parent 9209
b99e7fd55fd3
child 9413
80c06d472826
equal deleted inserted replaced
9220:e9e7eca7efee 9221:bf71ee032bb4
16 16
17 class FtpDirLineParserError(Exception): 17 class FtpDirLineParserError(Exception):
18 """ 18 """
19 Exception class raised, if a parser issue was detected. 19 Exception class raised, if a parser issue was detected.
20 """ 20 """
21
21 pass 22 pass
22 23
23 24
24 class FtpDirLineParser(QObject): 25 class FtpDirLineParser(QObject):
25 """ 26 """
26 Class to parse lines returned by a FTP LIST command. 27 Class to parse lines returned by a FTP LIST command.
27 """ 28 """
29
28 MonthnamesNumbers = { 30 MonthnamesNumbers = {
29 "jan": 1, 31 "jan": 1,
30 "feb": 2, 32 "feb": 2,
31 "mar": 3, 33 "mar": 3,
32 "apr": 4, 34 "apr": 4,
37 "sep": 9, 39 "sep": 9,
38 "oct": 10, 40 "oct": 10,
39 "nov": 11, 41 "nov": 11,
40 "dec": 12, 42 "dec": 12,
41 } 43 }
42 44
43 def __init__(self, parent=None): 45 def __init__(self, parent=None):
44 """ 46 """
45 Constructor 47 Constructor
46 48
47 @param parent reference to the parent object (QObject) 49 @param parent reference to the parent object (QObject)
48 """ 50 """
49 super().__init__(parent) 51 super().__init__(parent)
50 52
51 self.__parseLine = self.__parseUnixLine 53 self.__parseLine = self.__parseUnixLine
52 self.__modeSwitchAllowed = True 54 self.__modeSwitchAllowed = True
53 55
54 def __ignoreLine(self, line): 56 def __ignoreLine(self, line):
55 """ 57 """
56 Private method to check, if the line should be ignored. 58 Private method to check, if the line should be ignored.
57 59
58 @param line to check (string) 60 @param line to check (string)
59 @return flag indicating to ignore the line (boolean) 61 @return flag indicating to ignore the line (boolean)
60 """ 62 """
61 return ( 63 return line.strip() == "" or line.strip().lower().startswith("total ")
62 line.strip() == "" or 64
63 line.strip().lower().startswith("total ")
64 )
65
66 def __parseUnixMode(self, modeString, urlInfo): 65 def __parseUnixMode(self, modeString, urlInfo):
67 """ 66 """
68 Private method to parse a Unix mode string modifying the 67 Private method to parse a Unix mode string modifying the
69 given URL info object. 68 given URL info object.
70 69
71 @param modeString mode string to be parsed (string) 70 @param modeString mode string to be parsed (string)
72 @param urlInfo reference to the URL info object (EricUrlInfo) 71 @param urlInfo reference to the URL info object (EricUrlInfo)
73 @exception FtpDirLineParserError Raised if the mode cannot be parsed. 72 @exception FtpDirLineParserError Raised if the mode cannot be parsed.
74 """ 73 """
75 if len(modeString) != 10: 74 if len(modeString) != 10:
76 raise FtpDirLineParserError( 75 raise FtpDirLineParserError("invalid mode string '{0}'".format(modeString))
77 "invalid mode string '{0}'".format(modeString)) 76
78
79 modeString = modeString.lower() 77 modeString = modeString.lower()
80 78
81 permission = 0 79 permission = 0
82 if modeString[1] != '-': 80 if modeString[1] != "-":
83 permission |= EricUrlPermission.READ_OWNER 81 permission |= EricUrlPermission.READ_OWNER
84 if modeString[2] != '-': 82 if modeString[2] != "-":
85 permission |= EricUrlPermission.WRITE_OWNER 83 permission |= EricUrlPermission.WRITE_OWNER
86 if modeString[3] != '-': 84 if modeString[3] != "-":
87 permission |= EricUrlPermission.EXE_OWNER 85 permission |= EricUrlPermission.EXE_OWNER
88 if modeString[4] != '-': 86 if modeString[4] != "-":
89 permission |= EricUrlPermission.READ_GROUP 87 permission |= EricUrlPermission.READ_GROUP
90 if modeString[5] != '-': 88 if modeString[5] != "-":
91 permission |= EricUrlPermission.WRITE_GROUP 89 permission |= EricUrlPermission.WRITE_GROUP
92 if modeString[6] != '-': 90 if modeString[6] != "-":
93 permission |= EricUrlPermission.EXE_GROUP 91 permission |= EricUrlPermission.EXE_GROUP
94 if modeString[7] != '-': 92 if modeString[7] != "-":
95 permission |= EricUrlPermission.READ_OTHER 93 permission |= EricUrlPermission.READ_OTHER
96 if modeString[8] != '-': 94 if modeString[8] != "-":
97 permission |= EricUrlPermission.WRITE_OTHER 95 permission |= EricUrlPermission.WRITE_OTHER
98 if modeString[9] != '-': 96 if modeString[9] != "-":
99 permission |= EricUrlPermission.EXE_OTHER 97 permission |= EricUrlPermission.EXE_OTHER
100 urlInfo.setPermissions(permission) 98 urlInfo.setPermissions(permission)
101 99
102 if modeString[0] == "d": 100 if modeString[0] == "d":
103 urlInfo.setDir(True) 101 urlInfo.setDir(True)
104 urlInfo.setFile(False) 102 urlInfo.setFile(False)
105 urlInfo.setSymLink(False) 103 urlInfo.setSymLink(False)
106 elif modeString[0] == "l": 104 elif modeString[0] == "l":
109 urlInfo.setSymLink(True) 107 urlInfo.setSymLink(True)
110 elif modeString[0] == "-": 108 elif modeString[0] == "-":
111 urlInfo.setDir(False) 109 urlInfo.setDir(False)
112 urlInfo.setFile(True) 110 urlInfo.setFile(True)
113 urlInfo.setSymLink(False) 111 urlInfo.setSymLink(False)
114 112
115 def __parseUnixTime(self, monthAbbreviation, day, yearOrTime, urlInfo): 113 def __parseUnixTime(self, monthAbbreviation, day, yearOrTime, urlInfo):
116 """ 114 """
117 Private method to parse a Unix date and time indication modifying 115 Private method to parse a Unix date and time indication modifying
118 the given URL info object. 116 the given URL info object.
119 117
120 118
121 Date time strings in Unix-style directory listings typically 119 Date time strings in Unix-style directory listings typically
122 have one of these formats: 120 have one of these formats:
123 <ul> 121 <ul>
124 <li>"Nov 23 02:33" (month name, day of month, time)</li> 122 <li>"Nov 23 02:33" (month name, day of month, time)</li>
125 <li>"May 26 2005" (month name, day of month, year)</li> 123 <li>"May 26 2005" (month name, day of month, year)</li>
126 </ul> 124 </ul>
127 125
128 @param monthAbbreviation abbreviation of the month name (string) 126 @param monthAbbreviation abbreviation of the month name (string)
129 @param day day of the month (string) 127 @param day day of the month (string)
130 @param yearOrTime string giving the year or a time (string) 128 @param yearOrTime string giving the year or a time (string)
131 @param urlInfo reference to the URL info object (EricUrlInfo) 129 @param urlInfo reference to the URL info object (EricUrlInfo)
132 @exception FtpDirLineParserError Raised if the month abbreviation is 130 @exception FtpDirLineParserError Raised if the month abbreviation is
133 not recognized. 131 not recognized.
134 """ 132 """
135 try: 133 try:
136 month = FtpDirLineParser.MonthnamesNumbers[ 134 month = FtpDirLineParser.MonthnamesNumbers[monthAbbreviation.lower()]
137 monthAbbreviation.lower()]
138 except KeyError: 135 except KeyError:
139 raise FtpDirLineParserError( 136 raise FtpDirLineParserError(
140 "illegal month abbreviation '{0}'".format( 137 "illegal month abbreviation '{0}'".format(monthAbbreviation)
141 monthAbbreviation)) 138 )
142 day = int(day) 139 day = int(day)
143 if ':' in yearOrTime: 140 if ":" in yearOrTime:
144 year = QDate.currentDate().year() 141 year = QDate.currentDate().year()
145 hour, minute = yearOrTime.split(':') 142 hour, minute = yearOrTime.split(":")
146 hour = int(hour) 143 hour = int(hour)
147 minute = int(minute) 144 minute = int(minute)
148 else: 145 else:
149 year = int(yearOrTime) 146 year = int(yearOrTime)
150 hour = 0 147 hour = 0
151 minute = 0 148 minute = 0
152 149
153 lastModified = QDateTime(QDate(year, month, day), QTime(hour, minute)) 150 lastModified = QDateTime(QDate(year, month, day), QTime(hour, minute))
154 urlInfo.setLastModified(lastModified) 151 urlInfo.setLastModified(lastModified)
155 152
156 def __splitUnixLine(self, line): 153 def __splitUnixLine(self, line):
157 """ 154 """
158 Private method to split a line of a Unix like directory listing. 155 Private method to split a line of a Unix like directory listing.
159 156
160 It splits the line into meta data, number of links, user, group, size, 157 It splits the line into meta data, number of links, user, group, size,
161 month, day, year or time and name. 158 month, day, year or time and name.
162 159
163 @param line directory line to split (string) 160 @param line directory line to split (string)
164 @return tuple of nine strings giving the meta data, 161 @return tuple of nine strings giving the meta data,
165 number of links, user, group, size, month, day, year or time 162 number of links, user, group, size, month, day, year or time
166 and name 163 and name
167 @exception FtpDirLineParserError Raised if the line is not of a 164 @exception FtpDirLineParserError Raised if the line is not of a
171 # Unix format variant. 168 # Unix format variant.
172 lineParts = line.split() 169 lineParts = line.split()
173 fieldCountWithoutUserID = 8 170 fieldCountWithoutUserID = 8
174 fieldCountWithUserID = fieldCountWithoutUserID + 1 171 fieldCountWithUserID = fieldCountWithoutUserID + 1
175 if len(lineParts) < fieldCountWithoutUserID: 172 if len(lineParts) < fieldCountWithoutUserID:
176 raise FtpDirLineParserError( 173 raise FtpDirLineParserError("line '{0}' cannot be parsed".format(line))
177 "line '{0}' cannot be parsed".format(line)) 174
178
179 # If we have a valid format (either with or without user id field), 175 # If we have a valid format (either with or without user id field),
180 # the field with index 5 is either the month abbreviation or a day. 176 # the field with index 5 is either the month abbreviation or a day.
181 try: 177 try:
182 int(lineParts[5]) 178 int(lineParts[5])
183 except ValueError: 179 except ValueError:
186 else: 182 else:
187 # Day 183 # Day
188 lineParts = line.split(None, fieldCountWithoutUserID - 1) 184 lineParts = line.split(None, fieldCountWithoutUserID - 1)
189 userFieldIndex = 2 185 userFieldIndex = 2
190 lineParts.insert(userFieldIndex, "") 186 lineParts.insert(userFieldIndex, "")
191 187
192 return lineParts 188 return lineParts
193 189
194 def __parseUnixLine(self, line): 190 def __parseUnixLine(self, line):
195 """ 191 """
196 Private method to parse a Unix style directory listing line. 192 Private method to parse a Unix style directory listing line.
197 193
198 @param line directory line to be parsed (string) 194 @param line directory line to be parsed (string)
199 @return URL info object containing the valid data (EricUrlInfo) 195 @return URL info object containing the valid data (EricUrlInfo)
200 """ 196 """
201 modeString, nlink, user, group, size, month, day, yearOrTime, name = ( 197 (
202 self.__splitUnixLine(line) 198 modeString,
203 ) 199 nlink,
204 200 user,
201 group,
202 size,
203 month,
204 day,
205 yearOrTime,
206 name,
207 ) = self.__splitUnixLine(line)
208
205 if name in [".", ".."]: 209 if name in [".", ".."]:
206 return None 210 return None
207 211
208 urlInfo = EricUrlInfo() 212 urlInfo = EricUrlInfo()
209 self.__parseUnixMode(modeString, urlInfo) 213 self.__parseUnixMode(modeString, urlInfo)
210 self.__parseUnixTime(month, day, yearOrTime, urlInfo) 214 self.__parseUnixTime(month, day, yearOrTime, urlInfo)
211 urlInfo.setOwner(user) 215 urlInfo.setOwner(user)
212 urlInfo.setGroup(group) 216 urlInfo.setGroup(group)
214 name = name.strip() 218 name = name.strip()
215 i = name.find(" -> ") 219 i = name.find(" -> ")
216 if i >= 0: 220 if i >= 0:
217 name = name[:i] 221 name = name[:i]
218 urlInfo.setName(name) 222 urlInfo.setName(name)
219 223
220 return urlInfo 224 return urlInfo
221 225
222 def __parseWindowsTime(self, date, time, urlInfo): 226 def __parseWindowsTime(self, date, time, urlInfo):
223 """ 227 """
224 Private method to parse a Windows date and time indication modifying 228 Private method to parse a Windows date and time indication modifying
225 the given URL info object. 229 the given URL info object.
226 230
227 Date time strings in Windows-style directory listings typically 231 Date time strings in Windows-style directory listings typically
228 have the format "10-23-12 03:25PM" (month-day_of_month-two_digit_year, 232 have the format "10-23-12 03:25PM" (month-day_of_month-two_digit_year,
229 hour:minute, am/pm). 233 hour:minute, am/pm).
230 234
231 @param date date string (string) 235 @param date date string (string)
232 @param time time string (string) 236 @param time time string (string)
233 @param urlInfo reference to the URL info object (EricUrlInfo) 237 @param urlInfo reference to the URL info object (EricUrlInfo)
234 @exception FtpDirLineParserError Raised if either of the strings is not 238 @exception FtpDirLineParserError Raised if either of the strings is not
235 recognized. 239 recognized.
236 """ 240 """
237 try: 241 try:
238 month, day, year = [int(part) for part in date.split('-')] 242 month, day, year = [int(part) for part in date.split("-")]
239 year = 1900 + year if year >= 70 else 2000 + year 243 year = 1900 + year if year >= 70 else 2000 + year
240 except (ValueError, IndexError): 244 except (ValueError, IndexError):
241 raise FtpDirLineParserError( 245 raise FtpDirLineParserError("illegal date string '{0}'".format(month))
242 "illegal date string '{0}'".format(month))
243 try: 246 try:
244 hour, minute, am_pm = time[0:2], time[3:5], time[5] 247 hour, minute, am_pm = time[0:2], time[3:5], time[5]
245 hour = int(hour) 248 hour = int(hour)
246 minute = int(minute) 249 minute = int(minute)
247 except (ValueError, IndexError): 250 except (ValueError, IndexError):
248 raise FtpDirLineParserError( 251 raise FtpDirLineParserError("illegal time string '{0}'".format(month))
249 "illegal time string '{0}'".format(month)) 252 if hour == 12 and am_pm == "A":
250 if hour == 12 and am_pm == 'A':
251 hour = 0 253 hour = 0
252 if hour != 12 and am_pm == 'P': 254 if hour != 12 and am_pm == "P":
253 hour += 12 255 hour += 12
254 256
255 lastModified = QDateTime(QDate(year, month, day), QTime(hour, minute)) 257 lastModified = QDateTime(QDate(year, month, day), QTime(hour, minute))
256 urlInfo.setLastModified(lastModified) 258 urlInfo.setLastModified(lastModified)
257 259
258 def __parseWindowsLine(self, line): 260 def __parseWindowsLine(self, line):
259 """ 261 """
260 Private method to parse a Windows style directory listing line. 262 Private method to parse a Windows style directory listing line.
261 263
262 @param line directory line to be parsed (string) 264 @param line directory line to be parsed (string)
263 @return URL info object containing the valid data (EricUrlInfo) 265 @return URL info object containing the valid data (EricUrlInfo)
264 @exception FtpDirLineParserError Raised if the line is not of a 266 @exception FtpDirLineParserError Raised if the line is not of a
265 recognized Windows format. 267 recognized Windows format.
266 """ 268 """
267 try: 269 try:
268 date, time, dirOrSize, name = line.split(None, 3) 270 date, time, dirOrSize, name = line.split(None, 3)
269 except ValueError: 271 except ValueError:
270 # "unpack list of wrong size" 272 # "unpack list of wrong size"
271 raise FtpDirLineParserError( 273 raise FtpDirLineParserError("line '{0}' cannot be parsed".format(line))
272 "line '{0}' cannot be parsed".format(line)) 274
273
274 if name in [".", ".."]: 275 if name in [".", ".."]:
275 return None 276 return None
276 277
277 urlInfo = EricUrlInfo() 278 urlInfo = EricUrlInfo()
278 self.__parseWindowsTime(date, time, urlInfo) 279 self.__parseWindowsTime(date, time, urlInfo)
279 if dirOrSize.lower() == "<dir>": 280 if dirOrSize.lower() == "<dir>":
280 urlInfo.setDir(True) 281 urlInfo.setDir(True)
281 urlInfo.setFile(False) 282 urlInfo.setFile(False)
283 urlInfo.setDir(False) 284 urlInfo.setDir(False)
284 urlInfo.setFile(True) 285 urlInfo.setFile(True)
285 try: 286 try:
286 urlInfo.setSize(int(dirOrSize)) 287 urlInfo.setSize(int(dirOrSize))
287 except ValueError: 288 except ValueError:
288 raise FtpDirLineParserError( 289 raise FtpDirLineParserError("illegal size '{0}'".format(dirOrSize))
289 "illegal size '{0}'".format(dirOrSize))
290 urlInfo.setName(name) 290 urlInfo.setName(name)
291 291
292 ext = os.path.splitext(name.lower())[1] 292 ext = os.path.splitext(name.lower())[1]
293 urlInfo.setSymLink(ext == ".lnk") 293 urlInfo.setSymLink(ext == ".lnk")
294 294
295 permissions = ( 295 permissions = (
296 EricUrlPermission.READ_OWNER | EricUrlPermission.WRITE_OWNER | 296 EricUrlPermission.READ_OWNER
297 EricUrlPermission.READ_GROUP | EricUrlPermission.WRITE_GROUP | 297 | EricUrlPermission.WRITE_OWNER
298 EricUrlPermission.READ_OTHER | EricUrlPermission.WRITE_OTHER 298 | EricUrlPermission.READ_GROUP
299 | EricUrlPermission.WRITE_GROUP
300 | EricUrlPermission.READ_OTHER
301 | EricUrlPermission.WRITE_OTHER
299 ) 302 )
300 if ext in [".exe", ".com", ".bat", ".cmd"]: 303 if ext in [".exe", ".com", ".bat", ".cmd"]:
301 permissions |= ( 304 permissions |= (
302 EricUrlPermission.EXE_OWNER | 305 EricUrlPermission.EXE_OWNER
303 EricUrlPermission.EXE_GROUP | 306 | EricUrlPermission.EXE_GROUP
304 EricUrlPermission.EXE_OTHER 307 | EricUrlPermission.EXE_OTHER
305 ) 308 )
306 urlInfo.setPermissions(permissions) 309 urlInfo.setPermissions(permissions)
307 310
308 return urlInfo 311 return urlInfo
309 312
310 def parseLine(self, line): 313 def parseLine(self, line):
311 """ 314 """
312 Public method to parse a directory listing line. 315 Public method to parse a directory listing line.
313 316
314 This implementation support Unix and Windows style directory 317 This implementation support Unix and Windows style directory
315 listings. It tries Unix style first and if that fails switches 318 listings. It tries Unix style first and if that fails switches
316 to Windows style. If that fails as well, an exception is raised. 319 to Windows style. If that fails as well, an exception is raised.
317 320
318 @param line directory line to be parsed (string) 321 @param line directory line to be parsed (string)
319 @return URL info object containing the valid data (EricUrlInfo) 322 @return URL info object containing the valid data (EricUrlInfo)
320 """ 323 """
321 if self.__ignoreLine(line): 324 if self.__ignoreLine(line):
322 return None 325 return None
323 326
324 try: 327 try:
325 return self.__parseLine(line) 328 return self.__parseLine(line)
326 except FtpDirLineParserError: 329 except FtpDirLineParserError:
327 if not self.__modeSwitchAllowed: 330 if not self.__modeSwitchAllowed:
328 raise 331 raise
329 332
330 self.__parseLine = self.__parseWindowsLine 333 self.__parseLine = self.__parseWindowsLine
331 self.__modeSwitchAllowed = False 334 self.__modeSwitchAllowed = False
332 return self.__parseLine(line) 335 return self.__parseLine(line)

eric ide

mercurial