예제 #1
0
 def get_souce_href(self) -> str:
     return make_href(
         name=self.name,
         uri=get_uri(
             full_file_name=self.full_file_name, camera_details=self.camera_details
         ),
     )
예제 #2
0
    def move_log_file(self, rpd_file: Union[Photo, Video]) -> None:
        """
        Move (rename) the associate XMP file using the pre-generated
        name
        """

        try:
            if rpd_file.log_extension:
                ext = rpd_file.log_extension
            else:
                ext = '.LOG'
        except AttributeError:
            ext = '.LOG'

        try:
            rpd_file.download_log_full_name = self._move_associate_file(
                extension=ext,
                full_base_name=rpd_file.download_full_base_name,
                temp_associate_file=rpd_file.temp_log_full_name)
        except (OSError, FileNotFoundError) as e:
            self.problems.append(
                RenamingAssociateFileProblem(source=make_href(
                    name=os.path.basename(rpd_file.download_log_full_name),
                    uri=get_uri(full_file_name=rpd_file.download_log_full_name,
                                camera_details=rpd_file.camera_details)),
                                             exception=e))
            logging.error("Failed to move file's associated LOG file %s",
                          rpd_file.download_log_full_name)
예제 #3
0
    def notify_download_failure_file_error(self, rpd_file: Union[Photo, Video],
                                           inst: Exception) -> None:
        """
        Handle cases where file failed to download
        """
        uri = get_uri(full_file_name=rpd_file.full_file_name,
                      camera_details=rpd_file.camera_details)
        device = make_href(name=rpd_file.device_display_name,
                           uri=rpd_file.device_uri)

        problem = RenamingFileProblem(file_type=rpd_file.title,
                                      destination=rpd_file.download_name,
                                      folder=rpd_file.download_path,
                                      name=rpd_file.name,
                                      uri=uri,
                                      device=device,
                                      exception=inst)
        self.problems.append(problem)

        rpd_file.status = DownloadStatus.download_failed

        try:
            msg = "Failed to create file {}: {} {}".format(
                rpd_file.download_full_file_name, inst.errno, inst.strerror)
            logging.error(msg)
        except AttributeError:
            logging.error("Failed to create file %s: %s ",
                          rpd_file.download_full_file_name, str(inst))
예제 #4
0
 def _destination(self, rpd_file: RPDFile, name: str) -> str:
     if rpd_file.download_subfolder:
         return make_href(
             name=name,
             uri=get_uri(full_file_name=os.path.join(
                 rpd_file.download_folder, rpd_file.download_subfolder,
                 name)),
         )
     else:
         return name
예제 #5
0
    def notify_file_already_exists(
        self, rpd_file: Union[Photo, Video], identifier: Optional[str] = None
    ) -> None:
        """
        Notify user that the download file already exists
        """

        # get information on when the existing file was last modified
        try:
            modification_time = os.path.getmtime(rpd_file.download_full_file_name)
            dt = datetime.fromtimestamp(modification_time)
            date = dt.strftime("%x")
            time = dt.strftime("%X")
        except Exception:
            logging.error(
                "Could not determine the file modification time of %s",
                rpd_file.download_full_file_name,
            )
            date = time = ""

        source = rpd_file.get_souce_href()

        device = make_href(name=rpd_file.device_display_name, uri=rpd_file.device_uri)

        if not identifier:
            problem = FileAlreadyExistsProblem(
                file_type_capitalized=rpd_file.title_capitalized,
                file_type=rpd_file.title,
                name=rpd_file.download_name,
                uri=get_uri(full_file_name=rpd_file.download_full_file_name),
                source=source,
                device=device,
                date=date,
                time=time,
            )

            rpd_file.status = DownloadStatus.download_failed
        else:
            problem = IdentifierAddedProblem(
                file_type_capitalized=rpd_file.title_capitalized,
                file_type=rpd_file.title,
                name=rpd_file.download_name,
                uri=get_uri(full_file_name=rpd_file.download_full_file_name),
                source=source,
                device=device,
                date=date,
                time=time,
                identifier=identifier,
            )

            rpd_file.status = DownloadStatus.downloaded_with_warning

        self.problems.append(problem)
예제 #6
0
    def move_thm_file(self, rpd_file: Union[Photo, Video]) -> None:
        """
        Move (rename) the THM thumbnail file using the pre-generated name
        """

        try:
            if rpd_file.thm_extension:
                ext = rpd_file.thm_extension
            else:
                ext = ".THM"
        except AttributeError:
            ext = ".THM"

        try:
            rpd_file.download_thm_full_name = self._move_associate_file(
                extension=ext,
                full_base_name=rpd_file.download_full_base_name,
                temp_associate_file=rpd_file.temp_thm_full_name,
            )
        except (OSError, FileNotFoundError) as e:
            self.problems.append(
                RenamingAssociateFileProblem(
                    source=make_href(
                        name=os.path.basename(rpd_file.download_thm_full_name),
                        uri=get_uri(
                            full_file_name=rpd_file.download_thm_full_name,
                            camera_details=rpd_file.camera_details,
                        ),
                    ),
                    exception=e,
                )
            )

            logging.error(
                "Failed to move video THM file %s", rpd_file.download_thm_full_name
            )
예제 #7
0
    def move_file(self, rpd_file: Union[Photo, Video]) -> bool:
        """
        Having generated the file name and subfolder names, move
        the file
        :param rpd_file: photo or video being worked on
        :return: True if move succeeded, False otherwise
        """

        move_succeeded = False

        rpd_file.download_path = os.path.join(
            rpd_file.download_folder, rpd_file.download_subfolder
        )
        rpd_file.download_full_file_name = os.path.join(
            rpd_file.download_path, rpd_file.download_name
        )
        rpd_file.download_full_base_name = os.path.splitext(
            rpd_file.download_full_file_name
        )[0]

        if not os.path.isdir(rpd_file.download_path):
            try:
                os.makedirs(rpd_file.download_path)
            except OSError as inst:
                if inst.errno != errno.EEXIST:
                    logging.error(
                        "Failed to create download subfolder: %s",
                        rpd_file.download_path,
                    )
                    logging.error(inst)

                    problem = SubfolderCreationProblem(
                        folder=make_href(
                            name=rpd_file.download_subfolder,
                            uri=get_uri(path=rpd_file.download_path),
                        ),
                        exception=inst,
                    )
                    self.problems.append(problem)

        # Move temp file to subfolder

        add_unique_identifier = False
        try:
            if os.path.exists(rpd_file.download_full_file_name):
                raise OSError(
                    errno.EEXIST, "File exists: %s" % rpd_file.download_full_file_name
                )
            logging.debug(
                "Renaming %s to %s .....",
                rpd_file.temp_full_file_name,
                rpd_file.download_full_file_name,
            )
            os.rename(rpd_file.temp_full_file_name, rpd_file.download_full_file_name)
            logging.debug("....successfully renamed file")
            move_succeeded = True
            if rpd_file.status != DownloadStatus.downloaded_with_warning:
                rpd_file.status = DownloadStatus.downloaded
        except OSError as inst:
            if inst.errno == errno.EEXIST:
                add_unique_identifier = self.download_file_exists(rpd_file)
            else:
                self.notify_download_failure_file_error(rpd_file, inst)
        except Exception as inst:
            # all other errors, including PermissionError
            self.notify_download_failure_file_error(rpd_file, inst)

        if add_unique_identifier:
            move_succeeded = self.add_unique_identifier(rpd_file)

        return move_succeeded
예제 #8
0
 def _destination(self, rpd_file: RPDFile, name: str) -> str:
     return make_href(
         name=name,
         uri=get_uri(path=os.path.join(rpd_file.download_folder, name)))
 def get_current_href(self) -> str:
     return make_href(name=self.get_current_name(), uri=self.get_uri())
    def do_backup(self, data: BackupFileData) -> None:
        rpd_file = data.rpd_file
        backup_succeeded = False
        self.scan_id = rpd_file.scan_id
        self.verify_file = data.verify_file

        mdata_exceptions = None

        if not (data.move_succeeded and data.do_backup):
            backup_full_file_name = ""
        else:
            self.total_reached = False

            if data.path_suffix is None:
                dest_base_dir = self.path
            else:
                dest_base_dir = os.path.join(self.path, data.path_suffix)

            dest_dir = os.path.join(dest_base_dir, rpd_file.download_subfolder)
            backup_full_file_name = os.path.join(dest_dir,
                                                 rpd_file.download_name)

            if not os.path.isdir(dest_dir):
                # create the subfolders on the backup path
                try:
                    logging.debug(
                        "Creating subfolder %s on backup device %s...",
                        dest_dir,
                        self.device_name,
                    )
                    os.makedirs(dest_dir)
                    logging.debug("...backup subfolder created")
                except (OSError, PermissionError, FileNotFoundError) as inst:
                    # There is a minuscule chance directory may have been
                    # created by another process between the time it
                    # takes to query and the time it takes to create a
                    # new directory. Ignore that error.
                    if inst.errno != errno.EEXIST:
                        logging.error(
                            "Failed to create backup subfolder: %s",
                            rpd_file.download_path,
                        )
                        logging.error(inst)

                        self.problems.append(
                            BackupSubfolderCreationProblem(
                                folder=make_href(
                                    name=rpd_file.download_subfolder,
                                    uri=get_uri(path=dest_dir),
                                ),
                                exception=inst,
                            ))

            backup_already_exists = os.path.exists(backup_full_file_name)

            if backup_already_exists:
                try:
                    modification_time = os.path.getmtime(backup_full_file_name)
                    dt = datetime.fromtimestamp(modification_time)
                    date = dt.strftime("%x")
                    time = dt.strftime("%X")
                except Exception:
                    logging.error(
                        "Could not determine the file modification time of %s",
                        backup_full_file_name,
                    )
                    date = time = ""

                source = rpd_file.get_souce_href()
                device = make_href(name=rpd_file.device_display_name,
                                   uri=rpd_file.device_uri)

                if data.backup_duplicate_overwrite:
                    self.problems.append(
                        BackupOverwrittenProblem(
                            file_type_capitalized=rpd_file.title_capitalized,
                            file_type=rpd_file.title,
                            name=rpd_file.download_name,
                            uri=get_uri(full_file_name=backup_full_file_name),
                            source=source,
                            device=device,
                            date=date,
                            time=time,
                        ))
                    msg = "Overwriting backup file %s" % backup_full_file_name
                else:
                    self.problems.append(
                        BackupAlreadyExistsProblem(
                            file_type_capitalized=rpd_file.title_capitalized,
                            file_type=rpd_file.title,
                            name=rpd_file.download_name,
                            uri=get_uri(full_file_name=backup_full_file_name),
                            source=source,
                            device=device,
                            date=date,
                            time=time,
                        ))
                    msg = (
                        "Skipping backup of file %s because it already exists"
                        % backup_full_file_name)
                logging.warning(msg)

            if not backup_already_exists or data.backup_duplicate_overwrite:
                logging.debug(
                    "Backing up file %s on device %s...",
                    data.download_count,
                    self.device_name,
                )
                source = rpd_file.download_full_file_name
                destination = backup_full_file_name
                backup_succeeded = self.copy_from_filesystem(
                    source, destination, rpd_file)
                if backup_succeeded and self.verify_file:
                    md5 = hashlib.md5(
                        open(backup_full_file_name).read()).hexdigest()
                    if md5 != rpd_file.md5:
                        pass
                if backup_succeeded:
                    logging.debug(
                        "...backing up file %s on device %s succeeded",
                        data.download_count,
                        self.device_name,
                    )

                if backup_succeeded:
                    mdata_exceptions = copy_file_metadata(
                        rpd_file.download_full_file_name,
                        backup_full_file_name)
            if not backup_succeeded:
                if rpd_file.status == DownloadStatus.download_failed:
                    rpd_file.status = DownloadStatus.download_and_backup_failed
                else:
                    rpd_file.status = DownloadStatus.backup_problem
            else:
                # backup any THM, audio or XMP files
                if rpd_file.download_thm_full_name:
                    self.backup_associate_file(dest_dir,
                                               rpd_file.download_thm_full_name)
                if rpd_file.download_audio_full_name:
                    self.backup_associate_file(
                        dest_dir, rpd_file.download_audio_full_name)
                if rpd_file.download_xmp_full_name:
                    self.backup_associate_file(dest_dir,
                                               rpd_file.download_xmp_full_name)
                if rpd_file.download_log_full_name:
                    self.backup_associate_file(dest_dir,
                                               rpd_file.download_log_full_name)

        self.total_downloaded += rpd_file.size
        bytes_not_downloaded = rpd_file.size - self.amount_downloaded
        if bytes_not_downloaded and data.do_backup:
            self.content = pickle.dumps(
                BackupResults(
                    scan_id=self.scan_id,
                    device_id=self.device_id,
                    total_downloaded=self.total_downloaded,
                    chunk_downloaded=bytes_not_downloaded,
                ),
                pickle.HIGHEST_PROTOCOL,
            )
            self.send_message_to_sink()

        self.content = pickle.dumps(
            BackupResults(
                scan_id=self.scan_id,
                device_id=self.device_id,
                backup_succeeded=backup_succeeded,
                do_backup=data.do_backup,
                rpd_file=rpd_file,
                backup_full_file_name=backup_full_file_name,
                mdata_exceptions=mdata_exceptions,
            ),
            pickle.HIGHEST_PROTOCOL,
        )
        self.send_message_to_sink()