774 @param deviceDirectory name of the directory on the device |
772 @param deviceDirectory name of the directory on the device |
775 @type str |
773 @type str |
776 @param mirror flag indicating to mirror the local directory to |
774 @param mirror flag indicating to mirror the local directory to |
777 the device directory |
775 the device directory |
778 @type bool |
776 @type bool |
779 @return tuple containing a list of messages and list of errors |
777 @return list of errors |
780 @rtype tuple of (list of str, list of str) |
778 @rtype list of str |
781 """ |
779 """ |
782 # TODO: get rid of messages and replace by rsyncProgressMessage signal |
|
783 messages = [] |
|
784 errors = [] |
780 errors = [] |
785 |
781 |
786 if not os.path.isdir(hostDirectory): |
782 if not os.path.isdir(hostDirectory): |
787 return ([], [self.tr( |
783 return [self.tr( |
788 "The given name '{0}' is not a directory or does not exist.") |
784 "The given name '{0}' is not a directory or does not exist.") |
789 .format(hostDirectory) |
785 .format(hostDirectory) |
790 ]) |
786 ] |
|
787 |
|
788 self.rsyncProgressMessage.emit( |
|
789 self.tr("Synchronizing <b>{0}</b>.").format(deviceDirectory) |
|
790 ) |
791 |
791 |
792 sourceDict = {} |
792 sourceDict = {} |
793 sourceFiles = listdirStat(hostDirectory) |
793 sourceFiles = listdirStat(hostDirectory) |
794 for name, nstat in sourceFiles: |
794 for name, nstat in sourceFiles: |
795 sourceDict[name] = nstat |
795 sourceDict[name] = nstat |
796 |
796 |
797 destinationDict = {} |
797 destinationDict = {} |
798 try: |
798 try: |
799 destinationFiles = self.__fs.lls(deviceDirectory, fullstat=True) |
799 destinationFiles = self.__fs.lls(deviceDirectory, fullstat=True) |
800 except Exception as exc: |
800 except Exception as exc: |
801 return ([], [str(exc)]) |
801 return [str(exc)] |
802 if destinationFiles is None: |
802 if destinationFiles is None: |
803 # the destination directory does not exist |
803 # the destination directory does not exist |
804 try: |
804 try: |
805 self.__fs.mkdir(deviceDirectory) |
805 self.__fs.mkdir(deviceDirectory) |
806 except Exception as exc: |
806 except Exception as exc: |
807 return ([], [str(exc)]) |
807 return [str(exc)] |
808 else: |
808 else: |
809 for name, nstat in destinationFiles: |
809 for name, nstat in destinationFiles: |
810 destinationDict[name] = nstat |
810 destinationDict[name] = nstat |
811 |
811 |
812 destinationSet = set(destinationDict.keys()) |
812 destinationSet = set(destinationDict.keys()) |
817 |
817 |
818 for sourceBasename in toAdd: |
818 for sourceBasename in toAdd: |
819 # name exists in source but not in device |
819 # name exists in source but not in device |
820 sourceFilename = os.path.join(hostDirectory, sourceBasename) |
820 sourceFilename = os.path.join(hostDirectory, sourceBasename) |
821 destFilename = deviceDirectory + "/" + sourceBasename |
821 destFilename = deviceDirectory + "/" + sourceBasename |
|
822 self.rsyncProgressMessage.emit( |
|
823 self.tr("Adding <b>{0}</b>...").format(destFilename)) |
822 if os.path.isfile(sourceFilename): |
824 if os.path.isfile(sourceFilename): |
823 try: |
825 try: |
824 self.__fs.put(sourceFilename, destFilename) |
826 self.__fs.put(sourceFilename, destFilename) |
825 except Exception as exc: |
827 except Exception as exc: |
826 messages.append(str(exc)) |
828 # just note issues but ignore them otherwise |
|
829 errors.append(str(exc)) |
827 if os.path.isdir(sourceFilename): |
830 if os.path.isdir(sourceFilename): |
828 # recurse |
831 # recurse |
829 msg, err = self.__rsync(sourceFilename, destFilename, |
832 errs = self.__rsync(sourceFilename, destFilename, |
830 mirror=mirror) |
833 mirror=mirror) |
831 messages.extend(msg) |
834 # just note issues but ignore them otherwise |
832 errors.extend(err) |
835 errors.extend(errs) |
833 |
836 |
834 if mirror: |
837 if mirror: |
835 for destBasename in toDelete: |
838 for destBasename in toDelete: |
836 # name exists in device but not local, delete |
839 # name exists in device but not local, delete |
837 destFilename = deviceDirectory + "/" + destBasename |
840 destFilename = deviceDirectory + "/" + destBasename |
|
841 self.rsyncProgressMessage.emit( |
|
842 self.tr("Removing <b>{0}</b>...").format(destFilename)) |
838 try: |
843 try: |
839 self.__fs.rmrf(destFilename, recursive=True, force=True) |
844 self.__fs.rmrf(destFilename, recursive=True, force=True) |
840 except Exception as exc: |
845 except Exception as exc: |
841 # ignore errors here |
846 # just note issues but ignore them otherwise |
842 messages.append(str(exc)) |
847 errors.append(str(exc)) |
843 |
848 |
844 for sourceBasename in toUpdate: |
849 for sourceBasename in toUpdate: |
845 # names exist in both; do an update |
850 # names exist in both; do an update |
846 sourceStat = sourceDict[sourceBasename] |
851 sourceStat = sourceDict[sourceBasename] |
847 destStat = destinationDict[sourceBasename] |
852 destStat = destinationDict[sourceBasename] |
848 sourceFilename = os.path.join(hostDirectory, sourceBasename) |
853 sourceFilename = os.path.join(hostDirectory, sourceBasename) |
849 destFilename = deviceDirectory + "/" + sourceBasename |
854 destFilename = deviceDirectory + "/" + sourceBasename |
850 destMode = destStat[0] |
855 destMode = destStat[0] |
851 if os.path.isdir(sourceFilename): |
856 if os.path.isdir(sourceFilename): |
852 if stat.S_ISDIR(destMode): |
857 if stat.S_ISDIR(destMode): |
853 # both are directories => recurse |
858 # both are directories => recurs |
854 msg, err = self.__rsync(sourceFilename, destFilename, |
859 errs = self.__rsync(sourceFilename, destFilename, |
855 mirror=mirror) |
860 mirror=mirror) |
856 messages.extend(msg) |
861 # just note issues but ignore them otherwise |
857 errors.extend(err) |
862 errors.extend(errs) |
858 else: |
863 else: |
859 messages.append(self.tr( |
864 self.rsyncProgressMessage.emit( |
860 "Source '{0}' is a directory and destination '{1}'" |
865 self.tr("Source <b>{0}</b> is a directory and" |
861 " is a file. Ignoring it." |
866 " destination <b>{1}</b> is a file. Ignoring" |
862 ).format(sourceFilename, destFilename)) |
867 " it.") |
|
868 .format(sourceFilename, destFilename) |
|
869 ) |
863 else: |
870 else: |
864 if stat.S_ISDIR(destMode): |
871 if stat.S_ISDIR(destMode): |
865 messages.append(self.tr( |
872 self.rsyncProgressMessage.emit( |
866 "Source '{0}' is a file and destination '{1}' is" |
873 self.tr("Source <b>{0}</b> is a file and destination" |
867 " a directory. Ignoring it." |
874 " <b>{1}</b> is a directory. Ignoring it.") |
868 ).format(sourceFilename, destFilename)) |
875 .format(sourceFilename, destFilename) |
|
876 ) |
869 else: |
877 else: |
870 if sourceStat[8] > destStat[8]: # mtime |
878 if sourceStat[8] > destStat[8]: # mtime |
871 messages.append(self.tr( |
879 self.rsyncProgressMessage.emit( |
872 "'{0}' is newer than '{1}' - copying" |
880 self.tr("Updating <b>{0}</b>...") |
873 ).format(sourceFilename, destFilename)) |
881 .format(destFilename) |
|
882 ) |
874 try: |
883 try: |
875 self.__fs.put(sourceFilename, destFilename) |
884 self.__fs.put(sourceFilename, destFilename) |
876 except Exception as exc: |
885 except Exception as exc: |
877 messages.append(str(exc)) |
886 errors.append(str(exc)) |
878 |
887 |
879 return messages, errors |
888 self.rsyncProgressMessage.emit( |
|
889 self.tr("Done synchronizing <b>{0}</b>.").format(deviceDirectory) |
|
890 ) |
|
891 |
|
892 return errors |
880 |
893 |
881 @pyqtSlot(str, str) |
894 @pyqtSlot(str, str) |
882 @pyqtSlot(str, str, bool) |
895 @pyqtSlot(str, str, bool) |
883 def rsync(self, hostDirectory, deviceDirectory, mirror=True): |
896 def rsync(self, hostDirectory, deviceDirectory, mirror=True): |
884 """ |
897 """ |