174 self.deleteFileDone.emit(deviceFileName) |
174 self.deleteFileDone.emit(deviceFileName) |
175 except Exception as exc: |
175 except Exception as exc: |
176 self.error.emit("delete", str(exc)) |
176 self.error.emit("delete", str(exc)) |
177 |
177 |
178 def __rsync(self, hostDirectory, deviceDirectory, mirror=True, |
178 def __rsync(self, hostDirectory, deviceDirectory, mirror=True, |
179 localDevice=False): |
179 localDevice=False, indentLevel=0): |
180 """ |
180 """ |
181 Private method to synchronize a local directory to the device. |
181 Private method to synchronize a local directory to the device. |
182 |
182 |
183 @param hostDirectory name of the local directory |
183 @param hostDirectory name of the local directory |
184 @type str |
184 @type str |
187 @param mirror flag indicating to mirror the local directory to |
187 @param mirror flag indicating to mirror the local directory to |
188 the device directory |
188 the device directory |
189 @type bool |
189 @type bool |
190 @param localDevice flag indicating device access via local file system |
190 @param localDevice flag indicating device access via local file system |
191 @type bool |
191 @type bool |
|
192 @param indentLevel indentation level for progress messages |
|
193 @type int |
192 @return list of errors |
194 @return list of errors |
193 @rtype list of str |
195 @rtype list of str |
194 """ |
196 """ |
|
197 indent = 4 * " " |
195 errors = [] |
198 errors = [] |
196 |
199 |
197 if not os.path.isdir(hostDirectory): |
200 if not os.path.isdir(hostDirectory): |
198 return [self.tr( |
201 return [self.tr( |
199 "The given name '{0}' is not a directory or does not exist.") |
202 "The given name '{0}' is not a directory or does not exist.") |
200 .format(hostDirectory) |
203 .format(hostDirectory) |
201 ] |
204 ] |
202 |
205 |
|
206 indentStr = indentLevel * indent |
203 self.rsyncProgressMessage.emit( |
207 self.rsyncProgressMessage.emit( |
204 self.tr("Synchronizing <b>{0}</b>.").format(deviceDirectory) |
208 self.tr("{1}Synchronizing <b>{0}</b>.") |
|
209 .format(deviceDirectory, indentStr) |
205 ) |
210 ) |
206 |
211 |
207 doneMessage = self.tr("Done synchronizing <b>{0}</b>.").format( |
212 doneMessage = self.tr("{1}Done synchronizing <b>{0}</b>.").format( |
208 deviceDirectory) |
213 deviceDirectory, indentStr) |
209 |
214 |
210 sourceDict = {} |
215 sourceDict = {} |
211 sourceFiles = listdirStat(hostDirectory) |
216 sourceFiles = listdirStat(hostDirectory) |
212 for name, nstat in sourceFiles: |
217 for name, nstat in sourceFiles: |
213 sourceDict[name] = nstat |
218 sourceDict[name] = nstat |
242 destinationSet = set(destinationDict.keys()) |
247 destinationSet = set(destinationDict.keys()) |
243 sourceSet = set(sourceDict.keys()) |
248 sourceSet = set(sourceDict.keys()) |
244 toAdd = sourceSet - destinationSet # add to dev |
249 toAdd = sourceSet - destinationSet # add to dev |
245 toDelete = destinationSet - sourceSet # delete from dev |
250 toDelete = destinationSet - sourceSet # delete from dev |
246 toUpdate = destinationSet.intersection(sourceSet) # update files |
251 toUpdate = destinationSet.intersection(sourceSet) # update files |
|
252 indentStr = (indentLevel + 1) * indent |
247 |
253 |
248 if localDevice: |
254 if localDevice: |
249 for sourceBasename in toAdd: |
255 for sourceBasename in toAdd: |
250 # name exists in source but not in device |
256 # name exists in source but not in device |
251 sourceFilename = os.path.join(hostDirectory, sourceBasename) |
257 sourceFilename = os.path.join(hostDirectory, sourceBasename) |
252 destFilename = os.path.join(deviceDirectory, sourceBasename) |
258 destFilename = os.path.join(deviceDirectory, sourceBasename) |
253 self.rsyncProgressMessage.emit( |
259 self.rsyncProgressMessage.emit( |
254 self.tr("Adding <b>{0}</b>...").format(destFilename)) |
260 self.tr("{1}Adding <b>{0}</b>...") |
|
261 .format(destFilename, indentStr)) |
255 if os.path.isfile(sourceFilename): |
262 if os.path.isfile(sourceFilename): |
256 shutil.copy2(sourceFilename, destFilename) |
263 shutil.copy2(sourceFilename, destFilename) |
257 elif os.path.isdir(sourceFilename): |
264 elif os.path.isdir(sourceFilename): |
258 # recurse |
265 # recurse |
259 errs = self.__rsync(sourceFilename, destFilename, |
266 errs = self.__rsync(sourceFilename, destFilename, |
260 mirror=mirror, localDevice=localDevice) |
267 mirror=mirror, localDevice=localDevice, |
|
268 indentLevel=indentLevel + 1) |
261 # just note issues but ignore them otherwise |
269 # just note issues but ignore them otherwise |
262 errors.extend(errs) |
270 errors.extend(errs) |
263 |
271 |
264 if mirror: |
272 if mirror: |
265 for destBasename in toDelete: |
273 for destBasename in toDelete: |
280 if os.path.isdir(sourceFilename): |
288 if os.path.isdir(sourceFilename): |
281 if os.path.isdir(destFilename): |
289 if os.path.isdir(destFilename): |
282 # both are directories => recurs |
290 # both are directories => recurs |
283 errs = self.__rsync(sourceFilename, destFilename, |
291 errs = self.__rsync(sourceFilename, destFilename, |
284 mirror=mirror, |
292 mirror=mirror, |
285 localDevice=localDevice) |
293 localDevice=localDevice, |
|
294 indentLevel=indentLevel + 1) |
286 # just note issues but ignore them otherwise |
295 # just note issues but ignore them otherwise |
287 errors.extend(errs) |
296 errors.extend(errs) |
288 else: |
297 else: |
289 self.rsyncProgressMessage.emit( |
298 self.rsyncProgressMessage.emit( |
290 self.tr("Source <b>{0}</b> is a directory and" |
299 self.tr("Source <b>{0}</b> is a directory and" |
309 shutil.copy2(sourceFilename, destFilename) |
318 shutil.copy2(sourceFilename, destFilename) |
310 else: |
319 else: |
311 for sourceBasename in toAdd: |
320 for sourceBasename in toAdd: |
312 # name exists in source but not in device |
321 # name exists in source but not in device |
313 sourceFilename = os.path.join(hostDirectory, sourceBasename) |
322 sourceFilename = os.path.join(hostDirectory, sourceBasename) |
314 destFilename = deviceDirectory + "/" + sourceBasename |
323 if deviceDirectory == "/": |
|
324 destFilename = "/" + sourceBasename |
|
325 else: |
|
326 destFilename = deviceDirectory + "/" + sourceBasename |
315 self.rsyncProgressMessage.emit( |
327 self.rsyncProgressMessage.emit( |
316 self.tr("Adding <b>{0}</b>...").format(destFilename)) |
328 self.tr("{1}Adding <b>{0}</b>...") |
|
329 .format(destFilename, indentStr)) |
317 if os.path.isfile(sourceFilename): |
330 if os.path.isfile(sourceFilename): |
318 try: |
331 try: |
319 self.__commandsInterface.put(sourceFilename, |
332 self.__commandsInterface.put(sourceFilename, |
320 destFilename) |
333 destFilename) |
321 except Exception as exc: |
334 except Exception as exc: |
322 # just note issues but ignore them otherwise |
335 # just note issues but ignore them otherwise |
323 errors.append(str(exc)) |
336 errors.append(str(exc)) |
324 elif os.path.isdir(sourceFilename): |
337 elif os.path.isdir(sourceFilename): |
325 # recurse |
338 # recurse |
326 errs = self.__rsync(sourceFilename, destFilename, |
339 errs = self.__rsync(sourceFilename, destFilename, |
327 mirror=mirror) |
340 mirror=mirror, |
|
341 indentLevel=indentLevel + 1) |
328 # just note issues but ignore them otherwise |
342 # just note issues but ignore them otherwise |
329 errors.extend(errs) |
343 errors.extend(errs) |
330 |
344 |
331 if mirror: |
345 if mirror: |
332 for destBasename in toDelete: |
346 for destBasename in toDelete: |
333 # name exists in device but not local, delete |
347 # name exists in device but not local, delete |
334 destFilename = deviceDirectory + "/" + destBasename |
348 if deviceDirectory == "/": |
|
349 destFilename = "/" + sourceBasename |
|
350 else: |
|
351 destFilename = deviceDirectory + "/" + destBasename |
335 self.rsyncProgressMessage.emit( |
352 self.rsyncProgressMessage.emit( |
336 self.tr("Removing <b>{0}</b>...").format(destFilename)) |
353 self.tr("{1}Removing <b>{0}</b>...") |
|
354 .format(destFilename, indentStr)) |
337 try: |
355 try: |
338 self.__commandsInterface.rmrf(destFilename, |
356 self.__commandsInterface.rmrf(destFilename, |
339 recursive=True, |
357 recursive=True, |
340 force=True) |
358 force=True) |
341 except Exception as exc: |
359 except Exception as exc: |
345 for sourceBasename in toUpdate: |
363 for sourceBasename in toUpdate: |
346 # names exist in both; do an update |
364 # names exist in both; do an update |
347 sourceStat = sourceDict[sourceBasename] |
365 sourceStat = sourceDict[sourceBasename] |
348 destStat = destinationDict[sourceBasename] |
366 destStat = destinationDict[sourceBasename] |
349 sourceFilename = os.path.join(hostDirectory, sourceBasename) |
367 sourceFilename = os.path.join(hostDirectory, sourceBasename) |
350 destFilename = deviceDirectory + "/" + sourceBasename |
368 if deviceDirectory == "/": |
|
369 destFilename = "/" + sourceBasename |
|
370 else: |
|
371 destFilename = deviceDirectory + "/" + sourceBasename |
351 destMode = destStat[0] |
372 destMode = destStat[0] |
352 if os.path.isdir(sourceFilename): |
373 if os.path.isdir(sourceFilename): |
353 if stat.S_ISDIR(destMode): |
374 if stat.S_ISDIR(destMode): |
354 # both are directories => recurs |
375 # both are directories => recurs |
355 errs = self.__rsync(sourceFilename, destFilename, |
376 errs = self.__rsync(sourceFilename, destFilename, |
356 mirror=mirror) |
377 mirror=mirror, |
|
378 indentLevel=indentLevel + 1) |
357 # just note issues but ignore them otherwise |
379 # just note issues but ignore them otherwise |
358 errors.extend(errs) |
380 errors.extend(errs) |
359 else: |
381 else: |
360 self.rsyncProgressMessage.emit( |
382 self.rsyncProgressMessage.emit( |
361 self.tr("Source <b>{0}</b> is a directory and" |
383 self.tr("Source <b>{0}</b> is a directory and" |
372 .format(sourceFilename, destFilename) |
394 .format(sourceFilename, destFilename) |
373 ) |
395 ) |
374 else: |
396 else: |
375 if sourceStat[8] > destStat[8]: # mtime |
397 if sourceStat[8] > destStat[8]: # mtime |
376 self.rsyncProgressMessage.emit( |
398 self.rsyncProgressMessage.emit( |
377 self.tr("Updating <b>{0}</b>...") |
399 self.tr("{1}Updating <b>{0}</b>...") |
378 .format(destFilename) |
400 .format(destFilename, indentStr) |
379 ) |
401 ) |
380 try: |
402 try: |
381 self.__commandsInterface.put(sourceFilename, |
403 self.__commandsInterface.put(sourceFilename, |
382 destFilename) |
404 destFilename) |
383 except Exception as exc: |
405 except Exception as exc: |