def move_new_soundpack(self):
        # Find the soundpack in the self.extract_dir
        # Move the soundpack from that location into self.soundpacks_dir

        self.moving_new_soundpack = True

        main_window = self.get_main_window()
        status_bar = main_window.statusBar()

        status_bar.showMessage(_('Finding the soundpack'))

        next_scans = deque()
        current_scan = scandir(self.extract_dir)

        soundpack_dir = None

        while True:
            try:
                entry = next(current_scan)
                if entry.is_dir():
                    next_scans.append(entry.path)
                elif entry.is_file():
                    dirname, basename = os.path.split(entry.path)
                    if basename == 'soundpack.txt':
                        soundpack_dir = dirname
                        entry = None
                        break
            except StopIteration:
                if len(next_scans) > 0:
                    current_scan = scandir(next_scans.popleft())
                else:
                    break

        for item in current_scan:
            pass

        if soundpack_dir is None:
            status_bar.showMessage(_('Soundpack installation cancelled - There '
                'is no soundpack in the downloaded archive'))
            delete_path(self.extract_dir)
            self.moving_new_soundpack = False

            self.finish_install_new_soundpack()
        else:
            soundpack_dir_name = os.path.basename(soundpack_dir)
            target_dir = os.path.join(self.soundpacks_dir, soundpack_dir_name)
            if os.path.exists(target_dir):
                status_bar.showMessage(_('Soundpack installation cancelled - '
                    'There is already a {basename} directory in '
                    '{soundpacks_dir}').format(basename=soundpack_dir_name,
                        soundpacks_dir=self.soundpacks_dir))
            else:
                shutil.move(soundpack_dir, self.soundpacks_dir)
                status_bar.showMessage(_('Soundpack installation completed'))

            delete_path(self.extract_dir)
            self.moving_new_soundpack = False

            self.game_dir_changed(self.game_dir)
            self.finish_install_new_soundpack()
Пример #2
0
    def prune_auto_backups(self):
        max_auto_backups = max(int(get_config_value('max_auto_backups', '6')),
                               1)

        search_start = (_('auto') + '_').lower()

        backup_dir = os.path.join(self.game_dir, 'save_backups')
        if not os.path.isdir(backup_dir):
            return

        auto_backups = []

        for entry in scandir(backup_dir):
            filename, ext = os.path.splitext(entry.name)
            if entry.is_file() and ext.lower() == '.zip':
                filename_lower = filename.lower()

                if filename_lower.startswith(search_start):
                    auto_backups.append({
                        'path':
                        entry.path,
                        'modified':
                        datetime.fromtimestamp(entry.stat().st_mtime)
                    })

        if len(auto_backups) >= max_auto_backups:
            # Remove backups to have a total of max_auto_backups - 1
            auto_backups.sort(key=lambda x: x['modified'])
            remove_count = len(auto_backups) - max_auto_backups + 1

            to_remove = auto_backups[:remove_count]

            for backup in to_remove:
                delete_path(backup['path'])
Пример #3
0
    def finish_restore_backup(self):
        main_window = self.get_main_window()
        status_bar = main_window.statusBar()

        status_bar.removeWidget(self.extracting_label)
        status_bar.removeWidget(self.extracting_speed_label)
        status_bar.removeWidget(self.extracting_size_label)
        status_bar.removeWidget(self.extracting_progress_bar)

        status_bar.busy -= 1

        self.extracting_backup = False

        if self.extracting_zipfile is not None:
            self.extracting_zipfile.close()

        if self.temp_save_dir is not None:
            delete_path(self.temp_save_dir)

        self.enable_tab()
        self.get_main_tab().enable_tab()
        self.get_soundpacks_tab().enable_tab()
        self.get_settings_tab().enable_tab()
        self.get_mods_tab().enable_tab()
        self.get_backups_tab().enable_tab()

        self.restore_button.setText(_('Restore backup'))

        self.get_main_tab().game_dir_group_box.update_saves()
Пример #4
0
                def completed():
                    save_dir = os.path.join(self.game_dir, 'save')
                    delete_path(save_dir)
                    if self.temp_save_dir is not None:
                        retry_rename(self.temp_save_dir, save_dir)
                    self.temp_save_dir = None

                    self.finish_restore_backup()
                    self.extracting_thread = None
Пример #5
0
        def timeout():
            self.extracting_progress_bar.setValue(self.extracting_index)

            if self.extracting_index == len(self.extracting_infolist):
                self.extracting_timer.stop()

                main_window = self.get_main_window()
                status_bar = main_window.statusBar()

                status_bar.removeWidget(self.extracting_label)
                status_bar.removeWidget(self.extracting_progress_bar)

                status_bar.busy -= 1

                self.extracting_new_soundpack = False

                self.extracting_zipfile.close()
                self.extracting_zipfile = None

                if self.downloaded_file.lower().endswith('.7z'):
                    self.extracting_archive = None

                if self.install_type == 'direct_download':
                    download_dir = os.path.dirname(self.downloaded_file)
                    delete_path(download_dir)

                self.move_new_soundpack()

            else:
                extracting_element = self.extracting_infolist[
                    self.extracting_index]

                self.extracting_label.setText(
                    _('Extracting {0}').format(extracting_element.filename))

                if self.downloaded_file.lower().endswith('.7z'):
                    destination = os.path.join(
                        self.extract_dir,
                        *extracting_element.filename.split('/'))
                    dest_dir = os.path.dirname(destination)
                    if not os.path.isdir(dest_dir):
                        os.makedirs(dest_dir)
                    with open(destination, 'wb') as f:
                        f.write(extracting_element.read())
                else:
                    self.extracting_zipfile.extract(extracting_element,
                                                    self.extract_dir)

                self.extracting_index += 1
    def delete_existing(self):
        selection_model = self.installed_lv.selectionModel()
        if selection_model is None or not selection_model.hasSelection():
            return

        selected = selection_model.currentIndex()
        selected_info = self.soundpacks[selected.row()]

        confirm_msgbox = QMessageBox()
        confirm_msgbox.setWindowTitle(_('Delete soundpack'))
        confirm_msgbox.setText(_('This will delete the soundpack directory. It '
            'cannot be undone.'))
        confirm_msgbox.setInformativeText(_('Are you sure you want to '
            'delete the {view} soundpack?').format(view=selected_info['VIEW']))
        confirm_msgbox.addButton(_('Delete the soundpack'),
            QMessageBox.YesRole)
        confirm_msgbox.addButton(_('I want to keep the soundpack'),
            QMessageBox.NoRole)
        confirm_msgbox.setIcon(QMessageBox.Warning)

        if confirm_msgbox.exec() == 0:
            main_window = self.get_main_window()
            status_bar = main_window.statusBar()

            if not delete_path(selected_info['path']):
                status_bar.showMessage(_('Soundpack deletion cancelled'))
            else:
                self.soundpacks_model.removeRows(selected.row(), 1)
                self.soundpacks.remove(selected_info)

                status_bar.showMessage(_('Soundpack deleted'))
Пример #7
0
    def http_finished(self):
        self.downloading_file.close()

        if self.download_aborted:
            download_dir = os.path.dirname(self.downloaded_file)
            delete_path(download_dir)
        else:
            redirect = self.http_reply.attribute(
                QNetworkRequest.RedirectionTargetAttribute)
            if redirect is not None:
                download_dir = os.path.dirname(self.downloaded_file)
                delete_path(download_dir)
                os.makedirs(download_dir)

                redirected_url = urljoin(
                    self.http_reply.request().url().toString(),
                    redirect.toString())

                self.downloading_file = open(self.downloaded_file, 'wb')

                self.download_last_read = datetime.utcnow()
                self.download_last_bytes_read = 0
                self.download_speed_count = 0
                self.download_aborted = False

                self.progress_bar.setValue(0)

                self.http_reply = self.qnam.get(
                    QNetworkRequest(QUrl(redirected_url)))
                self.http_reply.finished.connect(self.http_finished)
                self.http_reply.readyRead.connect(self.http_ready_read)
                self.http_reply.downloadProgress.connect(self.dl_progress)
            else:
                # Download completed
                if getattr(sys, 'frozen', False):
                    # Launch self.downloaded_file and close

                    subprocess.Popen([self.downloaded_file])

                    self.updated = True
                    self.done(0)
Пример #8
0
    def delete_button_clicked(self):
        selection_model = self.backups_table.selectionModel()
        if selection_model is None or not selection_model.hasSelection():
            return

        selected = selection_model.currentIndex()
        table_item = self.backups_table.item(selected.row(), 0)
        selected_info = self.backups[table_item]

        if not os.path.isfile(selected_info['path']):
            return

        confirm_msgbox = QMessageBox()
        confirm_msgbox.setWindowTitle(_('Delete backup'))
        confirm_msgbox.setText(
            _('This will delete the backup file. It '
              'cannot be undone.'))
        confirm_msgbox.setInformativeText(
            _('Are you sure you want to '
              'delete the <strong>{filename}</strong> backup?').format(
                  filename=selected_info['path']))
        confirm_msgbox.addButton(_('Delete the backup'), QMessageBox.YesRole)
        confirm_msgbox.addButton(_('I want to keep the backup'),
                                 QMessageBox.NoRole)
        confirm_msgbox.setIcon(QMessageBox.Warning)

        if confirm_msgbox.exec() == 0:
            main_window = self.get_main_window()
            status_bar = main_window.statusBar()

            if not delete_path(selected_info['path']):
                status_bar.showMessage(_('Backup deletion cancelled'))
            else:
                self.backups_table.removeRow(selected.row())
                del self.backups[table_item]

                status_bar.showMessage(_('Backup deleted'))
    def download_http_finished(self):
        self.downloading_file.close()

        main_window = self.get_main_window()

        status_bar = main_window.statusBar()
        status_bar.removeWidget(self.downloading_label)
        status_bar.removeWidget(self.dowloading_speed_label)
        status_bar.removeWidget(self.downloading_size_label)
        status_bar.removeWidget(self.downloading_progress_bar)

        status_bar.busy -= 1

        if self.download_aborted:
            download_dir = os.path.dirname(self.downloaded_file)
            delete_path(download_dir)

            self.downloading_new_soundpack = False
        else:
            redirect = self.download_http_reply.attribute(
                QNetworkRequest.RedirectionTargetAttribute)
            if redirect is not None:
                download_dir = os.path.dirname(self.downloaded_file)
                delete_path(download_dir)
                os.makedirs(download_dir)

                self.downloading_file = open(self.downloaded_file, 'wb')

                status_bar.busy += 1

                redirected_url = urljoin(
                    self.download_http_reply.request().url().toString(),
                    redirect.toString())

                downloading_label = QLabel()
                downloading_label.setText(_('Downloading: {0}').format(
                    redirected_url))
                status_bar.addWidget(downloading_label, 100)
                self.downloading_label = downloading_label

                dowloading_speed_label = QLabel()
                status_bar.addWidget(dowloading_speed_label)
                self.dowloading_speed_label = dowloading_speed_label

                downloading_size_label = QLabel()
                status_bar.addWidget(downloading_size_label)
                self.downloading_size_label = downloading_size_label

                progress_bar = QProgressBar()
                status_bar.addWidget(progress_bar)
                self.downloading_progress_bar = progress_bar
                progress_bar.setMinimum(0)

                self.download_last_read = datetime.utcnow()
                self.download_last_bytes_read = 0
                self.download_speed_count = 0

                progress_bar.setValue(0)

                request = QNetworkRequest(QUrl(redirected_url))
                request.setRawHeader(b'User-Agent', cons.FAKE_USER_AGENT)

                self.download_http_reply = self.qnam.get(request)
                self.download_http_reply.finished.connect(
                    self.download_http_finished)
                self.download_http_reply.readyRead.connect(
                    self.download_http_ready_read)
                self.download_http_reply.downloadProgress.connect(
                    self.download_dl_progress)
            else:
                # Test downloaded file
                status_bar.showMessage(_('Testing downloaded file archive'))

                if self.downloaded_file.lower().endswith('.7z'):
                    try:
                        with open(self.downloaded_file, 'rb') as f:
                            archive = Archive7z(f)
                    except FormatError:
                        status_bar.clearMessage()
                        status_bar.showMessage(_('Selected file is a '
                            'bad archive file'))

                        self.finish_install_new_soundpack()
                        return
                    except NoPasswordGivenError:
                        status_bar.clearMessage()
                        status_bar.showMessage(_('Selected file is a '
                            'password protected archive file'))

                        self.finish_install_new_soundpack()
                        return
                else:
                    archive_exception = None
                    if self.downloaded_file.lower().endswith('.zip'):
                        archive_class = zipfile.ZipFile
                        archive_exception = zipfile.BadZipFile
                        test_method = 'testzip'
                    elif self.downloaded_file.lower().endswith('.rar'):
                        archive_class = rarfile.RarFile
                        archive_exception = rarfile.Error
                        test_method = 'testrar'
                    else:
                        extension = os.path.splitext(self.downloaded_file)[1]
                        status_bar.clearMessage()
                        status_bar.showMessage(
                            _('Unknown downloaded archive format ({extension})'
                            ).format(extension=extension))

                        self.finish_install_new_soundpack()
                        return

                    try:
                        with archive_class(self.downloaded_file) as z:
                            test = getattr(z, test_method)
                            if test() is not None:
                                status_bar.clearMessage()
                                status_bar.showMessage(
                                    _('Downloaded archive is invalid'))

                                self.finish_install_new_soundpack()
                                return
                    except archive_exception:
                        status_bar.clearMessage()
                        status_bar.showMessage(_('Selected file is a '
                            'bad archive file'))

                        self.finish_install_new_soundpack()
                        return

                status_bar.clearMessage()
                self.downloading_new_soundpack = False
                self.extract_new_soundpack()
    def install_new(self):
        if not self.installing_new_soundpack:
            selection_model = self.repository_lv.selectionModel()
            if selection_model is None or not selection_model.hasSelection():
                return

            selected = selection_model.currentIndex()
            selected_info = self.repo_soundpacks[selected.row()]

            # Is it already installed?
            for soundpack in self.soundpacks:
                if soundpack['NAME'] == selected_info['name']:
                    confirm_msgbox = QMessageBox()
                    confirm_msgbox.setWindowTitle(_('Soundpack already present'
                        ))
                    confirm_msgbox.setText(_('It seems this soundpack is '
                        'already installed. The launcher will not overwrite '
                        'the soundpack if it has the same directory name. You '
                        'might want to delete the soundpack first if you want '
                        'to update it. Also, there can only be a single '
                        'soundpack with the same name value available in the '
                        'game.'))
                    confirm_msgbox.setInformativeText(_('Are you sure you want '
                        'to install the {view} soundpack?').format(
                            view=selected_info['viewname']))
                    confirm_msgbox.addButton(_('Install the soundpack'),
                        QMessageBox.YesRole)
                    confirm_msgbox.addButton(_('Do not install again'),
                        QMessageBox.NoRole)
                    confirm_msgbox.setIcon(QMessageBox.Warning)

                    if confirm_msgbox.exec() == 1:
                        return
                    break

            self.install_type = selected_info['type']

            if selected_info['type'] == 'direct_download':
                if self.http_reply is not None and self.http_reply.isRunning():
                    self.http_reply_aborted = True
                    self.http_reply.abort()

                self.installing_new_soundpack = True
                self.download_aborted = False

                download_dir = tempfile.mkdtemp(prefix=cons.TEMP_PREFIX)

                download_url = selected_info['url']

                url = QUrl(download_url)
                file_info = QFileInfo(url.path())
                file_name = file_info.fileName()

                self.downloaded_file = os.path.join(download_dir, file_name)
                self.downloading_file = open(self.downloaded_file, 'wb')

                main_window = self.get_main_window()

                status_bar = main_window.statusBar()
                status_bar.clearMessage()

                status_bar.busy += 1

                downloading_label = QLabel()
                downloading_label.setText(_('Downloading: {0}').format(
                    selected_info['url']))
                status_bar.addWidget(downloading_label, 100)
                self.downloading_label = downloading_label

                dowloading_speed_label = QLabel()
                status_bar.addWidget(dowloading_speed_label)
                self.dowloading_speed_label = dowloading_speed_label

                downloading_size_label = QLabel()
                status_bar.addWidget(downloading_size_label)
                self.downloading_size_label = downloading_size_label

                progress_bar = QProgressBar()
                status_bar.addWidget(progress_bar)
                self.downloading_progress_bar = progress_bar
                progress_bar.setMinimum(0)

                self.download_last_read = datetime.utcnow()
                self.download_last_bytes_read = 0
                self.download_speed_count = 0

                self.downloading_new_soundpack = True

                request = QNetworkRequest(QUrl(url))
                request.setRawHeader(b'User-Agent', cons.FAKE_USER_AGENT)

                self.download_http_reply = self.qnam.get(request)
                self.download_http_reply.finished.connect(
                    self.download_http_finished)
                self.download_http_reply.readyRead.connect(
                    self.download_http_ready_read)
                self.download_http_reply.downloadProgress.connect(
                    self.download_dl_progress)

                self.install_new_button.setText(_('Cancel soundpack '
                    'installation'))
                self.installed_lv.setEnabled(False)
                self.repository_lv.setEnabled(False)

                self.get_main_tab().disable_tab()
                self.get_mods_tab().disable_tab()
                self.get_settings_tab().disable_tab()
                self.get_backups_tab().disable_tab()
            elif selected_info['type'] == 'browser_download':
                bd_dialog = BrowserDownloadDialog('soundpack',
                    selected_info['url'], selected_info.get('expected_filename',
                        None))
                bd_dialog.exec()

                if bd_dialog.downloaded_path is not None:
                    self.installing_new_soundpack = True
                    self.downloaded_file = bd_dialog.downloaded_path

                    self.install_new_button.setText(_('Cancel soundpack '
                        'installation'))
                    self.installed_lv.setEnabled(False)
                    self.repository_lv.setEnabled(False)

                    self.get_main_tab().disable_tab()
                    self.get_mods_tab().disable_tab()
                    self.get_settings_tab().disable_tab()
                    self.get_backups_tab().disable_tab()

                    main_window = self.get_main_window()
                    status_bar = main_window.statusBar()

                    # Test downloaded file
                    status_bar.showMessage(_('Testing downloaded file archive'))

                    if self.downloaded_file.lower().endswith('.7z'):
                        try:
                            with open(self.downloaded_file, 'rb') as f:
                                archive = Archive7z(f)
                        except FormatError:
                            status_bar.clearMessage()
                            status_bar.showMessage(_('Selected file is a '
                                'bad archive file'))

                            self.finish_install_new_soundpack()
                            return
                        except NoPasswordGivenError:
                            status_bar.clearMessage()
                            status_bar.showMessage(_('Selected file is a '
                                'password protected archive file'))

                            self.finish_install_new_soundpack()
                            return
                    else:
                        archive_exception = None
                        if self.downloaded_file.lower().endswith('.zip'):
                            archive_class = zipfile.ZipFile
                            archive_exception = zipfile.BadZipFile
                            test_method = 'testzip'
                        elif self.downloaded_file.lower().endswith('.rar'):
                            archive_class = rarfile.RarFile
                            archive_exception = rarfile.Error
                            test_method = 'testrar'
                        else:
                            extension = os.path.splitext(self.downloaded_file
                                )[1]
                            status_bar.clearMessage()
                            status_bar.showMessage(
                                _('Unknown downloaded archive format '
                                '({extension})').format(extension=extension))

                            self.finish_install_new_soundpack()
                            return

                        try:
                            with archive_class(self.downloaded_file) as z:
                                test = getattr(z, test_method)
                                if test() is not None:
                                    status_bar.clearMessage()
                                    status_bar.showMessage(
                                        _('Downloaded archive is invalid'))

                                    self.finish_install_new_soundpack()
                                    return
                        except archive_exception:
                            status_bar.clearMessage()
                            status_bar.showMessage(_('Selected file is a '
                                'bad archive file'))

                            self.finish_install_new_soundpack()
                            return

                    status_bar.clearMessage()
                    self.extract_new_soundpack()

        else:
            main_window = self.get_main_window()
            status_bar = main_window.statusBar()

            # Cancel installation
            if self.downloading_new_soundpack:
                self.download_aborted = True
                self.download_http_reply.abort()
            elif self.extracting_new_soundpack:
                self.extracting_timer.stop()

                status_bar.removeWidget(self.extracting_label)
                status_bar.removeWidget(self.extracting_progress_bar)

                status_bar.busy -= 1

                self.extracting_new_soundpack = False

                self.extracting_zipfile.close()

                download_dir = os.path.dirname(self.downloaded_file)
                delete_path(download_dir)

                if os.path.isdir(self.extract_dir):
                    delete_path(self.extract_dir)

            status_bar.showMessage(_('Soundpack installation cancelled'))

            self.finish_install_new_soundpack()
Пример #11
0
    def backup_saves(self, name, single=False):
        main_window = self.get_main_window()
        status_bar = main_window.statusBar()

        if self.game_dir is None:
            status_bar.showMessage(_('Game directory not found'))
            if self.after_backup is not None:
                self.after_backup()
                self.after_backup = None
            return

        save_dir = os.path.join(self.game_dir, 'save')
        if not os.path.isdir(save_dir):
            status_bar.showMessage(_('Save directory not found'))
            if self.after_backup is not None:
                self.after_backup()
                self.after_backup = None
            return
        self.save_dir = save_dir

        backup_dir = os.path.join(self.game_dir, 'save_backups')
        if not os.path.isdir(backup_dir):
            if os.path.isfile(backup_dir):
                os.remove(backup_dir)

            os.makedirs(backup_dir)

        if single:
            backup_filename = name + '.zip'
            self.backup_path = os.path.join(backup_dir, backup_filename)
            if os.path.isfile(self.backup_path):
                if not delete_path(self.backup_path):
                    status_bar.showMessage(_('Could not delete previous '
                        'backup archive'))
                    return
        else:
            '''
            Finding a backup filename which does not already exists or is the
            next backup name based on an incremental counter placed at the end
            of the filename without the extension.
            '''

            name_lower = name.lower()
            name_key = alphanum_key(name_lower)
            if len(name_key) > 1 and isinstance(name_key[-1:][0], int):
                name_key = name_key[:-1]

            duplicate_name = False
            duplicate_basename = False
            max_counter = 0

            for entry in scandir(backup_dir):
                filename, ext = os.path.splitext(entry.name)
                if entry.is_file() and ext.lower() == '.zip':
                    filename_lower = filename.lower()

                    if filename_lower == name_lower:
                        duplicate_name = True
                    else:
                        filename_key = alphanum_key(filename_lower)

                        counter = filename_key[-1:][0]
                        if len(filename_key) > 1 and isinstance(counter, int):
                            filename_key = filename_key[:-1]

                            if name_key == filename_key:
                                duplicate_basename = True
                                max_counter = max(max_counter, counter)

            if duplicate_basename:
                name_key = alphanum_key(name)
                if len(name_key) > 1 and isinstance(name_key[-1:][0], int):
                    name_key = name_key[:-1]

                name_key.append(max_counter + 1)
                backup_filename = ''.join(map(lambda x: str(x), name_key))
            elif duplicate_name:
                backup_filename = name + '2'
            else:
                backup_filename = name

            backup_filename = backup_filename + '.zip'

            self.backup_path = os.path.join(backup_dir, backup_filename)

        self.backup_file = None

        status_bar.clearMessage()
        status_bar.busy += 1

        compressing_label = QLabel()
        status_bar.addWidget(compressing_label, 100)
        self.compressing_label = compressing_label

        self.compressing_progress_bar = None
        self.compressing_speed_label = None
        self.compressing_size_label = None

        timer = QTimer(self)
        self.compressing_timer = timer

        self.backup_searching = True
        self.backup_compressing = False

        self.backup_files = deque()
        self.backup_file_sizes = {}

        self.backup_scan = None
        self.next_backup_scans = deque()

        self.total_backup_size = 0
        self.total_files = 0

        self.disable_tab()
        self.get_main_tab().disable_tab()
        self.get_soundpacks_tab().disable_tab()
        self.get_settings_tab().disable_tab()
        self.get_mods_tab().disable_tab()
        self.get_backups_tab().disable_tab()

        if self.manual_backup:
            self.backup_current_button.setText(_('Cancel backup'))
            self.backup_current_button.setEnabled(True)

        compressing_label.setText(_('Searching for save files'))

        def timeout():
            if self.backup_scan is None:
                self.backup_scan = scandir(self.save_dir)
            else:
                try:
                    entry = next(self.backup_scan)

                    if entry.is_file():
                        self.compressing_label.setText(
                            _('Found {filename} in {path}').format(
                                filename=entry.name,
                                path=os.path.dirname(entry.path)))
                        self.backup_files.append(entry.path)
                        self.total_backup_size += entry.stat().st_size
                        self.backup_file_sizes[entry.path
                            ] = entry.stat().st_size
                        self.total_files += 1
                    elif entry.is_dir():
                        self.next_backup_scans.append(entry.path)
                except StopIteration:
                    try:
                        self.backup_scan = scandir(
                            self.next_backup_scans.popleft())
                    except IndexError:
                        self.backup_searching = False
                        self.backup_compressing = True

                        self.compressing_label.setText(
                            _('Compressing save files'))

                        compressing_speed_label = QLabel()
                        compressing_speed_label.setText(_('{bytes_sec}/s'
                            ).format(bytes_sec=sizeof_fmt(0)))
                        status_bar.addWidget(compressing_speed_label)
                        self.compressing_speed_label = (
                            compressing_speed_label)

                        compressing_size_label = QLabel()
                        compressing_size_label.setText(
                            '{bytes_read}/{total_bytes}'
                            .format(bytes_read=sizeof_fmt(0),
                                    total_bytes=sizeof_fmt(self.total_backup_size))
                        )
                        status_bar.addWidget(compressing_size_label)
                        self.compressing_size_label = (
                            compressing_size_label)

                        progress_bar = QProgressBar()
                        progress_bar.setRange(0, self.total_backup_size)
                        progress_bar.setValue(0)
                        status_bar.addWidget(progress_bar)
                        self.compressing_progress_bar = progress_bar

                        self.comp_size = 0
                        self.comp_files = 0
                        self.last_comp_bytes = 0
                        self.last_comp = datetime.utcnow()
                        self.next_backup_file = None

                        if self.compressing_timer is not None:
                            self.compressing_timer.stop()
                            self.compressing_timer = None

                        self.backup_saves_step2()

        timer.timeout.connect(timeout)
        timer.start(0)
Пример #12
0
 def completed():
     self.finish_backup_saves()
     delete_path(self.backup_path)
     self.compress_thread = None
Пример #13
0
    def backup_current_clicked(self):
        if self.manual_backup and self.backup_searching:
            if (self.compressing_timer is not None and
                self.compressing_timer.isActive()):
                self.compressing_timer.stop()

            self.backup_searching = False

            self.finish_backup_saves()

            main_window = self.get_main_window()
            status_bar = main_window.statusBar()

            status_bar.showMessage(_('Manual backup cancelled'))

        elif self.manual_backup and self.backup_compressing:
            class WaitingThread(QThread):
                completed = pyqtSignal()

                def __init__(self, wthread):
                    super(WaitingThread, self).__init__()

                    self.wthread = wthread

                def __del__(self):
                    self.wait()

                def run(self):
                    self.wthread.wait()
                    self.completed.emit()

            if self.compress_thread is not None:
                self.backup_current_button.setEnabled(False)
                self.compress_thread.quit()

                def completed():
                    self.finish_backup_saves()
                    delete_path(self.backup_path)
                    self.compress_thread = None

                waiting_thread = WaitingThread(self.compress_thread)
                waiting_thread.completed.connect(completed)
                self.waiting_thread = waiting_thread

                waiting_thread.start()
            else:
                self.finish_backup_saves()
                delete_path(self.backup_path)
                self.compress_thread = None

            self.backup_compressing = False

            main_window = self.get_main_window()
            status_bar = main_window.statusBar()

            status_bar.showMessage(_('Manual backup cancelled'))
        else:
            self.manual_backup = True

            name = safe_filename(self.name_le.text())
            if name == '':
                name = _('manual_backup')
            self.name_le.setText(name)

            set_config_value('last_manual_backup_name', name)

            self.backup_saves(name)
Пример #14
0
    def restore_backup(self):
        selection_model = self.backups_table.selectionModel()
        if selection_model is None or not selection_model.hasSelection():
            return

        selected = selection_model.currentIndex()
        table_item = self.backups_table.item(selected.row(), 0)
        selected_info = self.backups[table_item]

        model = selection_model.model()
        backup_name = model.data(model.index(selected.row(), 0))

        if not os.path.isfile(selected_info['path']):
            return

        main_window = self.get_main_window()
        status_bar = main_window.statusBar()

        self.temp_save_dir = None
        save_dir = os.path.join(self.game_dir, 'save')
        if os.path.isdir(save_dir):
            temp_save_dir = os.path.join(self.game_dir, 'save-{0}'.format(
                '%08x' % random.randrange(16**8)))
            while os.path.exists(temp_save_dir):
                temp_save_dir = os.path.join(self.game_dir, 'save-{0}'.format(
                    '%08x' % random.randrange(16**8)))

            if not retry_rename(save_dir, temp_save_dir):
                status_bar.showMessage(_('Could not rename the save directory'))
                return
            self.temp_save_dir = temp_save_dir
        elif os.path.isfile(save_dir):
            if not delete_path(save_dir):
                status_bar.showMessage(_('Could not remove the save file'))
                return

        # Extract the backup archive

        self.extracting_backup = True

        self.extract_dir = self.game_dir

        status_bar.clearMessage()
        status_bar.busy += 1

        self.total_extract_size = selected_info['actual_size']

        extracting_label = QLabel()
        extracting_label.setText(_('Extracting backup'))
        status_bar.addWidget(extracting_label, 100)
        self.extracting_label = extracting_label

        extracting_speed_label = QLabel()
        extracting_speed_label.setText(_('{bytes_sec}/s'
            ).format(bytes_sec=sizeof_fmt(0)))
        status_bar.addWidget(extracting_speed_label)
        self.extracting_speed_label = extracting_speed_label

        extracting_size_label = QLabel()
        extracting_size_label.setText(
            '{bytes_read}/{total_bytes}'
            .format(bytes_read=sizeof_fmt(0), total_bytes=sizeof_fmt(self.total_extract_size))
        )
        status_bar.addWidget(extracting_size_label)
        self.extracting_size_label = (
            extracting_size_label)

        progress_bar = QProgressBar()
        progress_bar.setRange(0, self.total_extract_size)
        progress_bar.setValue(0)
        status_bar.addWidget(progress_bar)
        self.extracting_progress_bar = progress_bar

        self.extract_size = 0
        self.extract_files = 0
        self.last_extract_bytes = 0
        self.last_extract = datetime.utcnow()
        self.next_backup_file = None

        self.disable_tab()
        self.get_main_tab().disable_tab()
        self.get_soundpacks_tab().disable_tab()
        self.get_settings_tab().disable_tab()
        self.get_mods_tab().disable_tab()
        self.get_backups_tab().disable_tab()

        self.restore_button.setEnabled(True)
        self.restore_button.setText(_('Cancel restore backup'))

        class ExtractingThread(QThread):
            completed = pyqtSignal()

            def __init__(self, zfile, element, dir):
                super(ExtractingThread, self).__init__()

                self.zfile = zfile
                self.element = element
                self.dir = dir

            def __del__(self):
                self.wait()

            def run(self):
                self.zfile.extract(self.element, self.dir)
                self.completed.emit()

        def extract_next_file():
            try:
                if self.extracting_backup:
                    extracting_element = self.extracting_infolist.popleft()
                    self.extracting_label.setText(_('Extracting {filename}'
                        ).format(filename=extracting_element.filename))
                    self.next_extract_file = extracting_element

                    extracting_thread = ExtractingThread(
                        self.extracting_zipfile, extracting_element,
                        self.extract_dir)
                    extracting_thread.completed.connect(completed_extract)
                    self.extracting_thread = extracting_thread

                    extracting_thread.start()

            except IndexError:
                self.extracting_backup = False
                self.extracting_thread = None

                self.finish_restore_backup()

                main_window = self.get_main_window()
                status_bar = main_window.statusBar()

                status_bar.showMessage(_('{backup_name} backup restored'
                    ).format(backup_name=backup_name))

        def completed_extract():
            self.extract_size += self.next_extract_file.file_size
            self.extracting_progress_bar.setValue(self.extract_size)

            self.extracting_size_label.setText(
                '{bytes_read}/{total_bytes}'
                .format(bytes_read=sizeof_fmt(self.extract_size),
                        total_bytes=sizeof_fmt(self.total_extract_size))
            )

            delta_bytes = self.extract_size - self.last_extract_bytes
            delta_time = datetime.utcnow() - self.last_extract
            if delta_time.total_seconds() == 0:
                delta_time = timedelta.resolution

            bytes_secs = delta_bytes / delta_time.total_seconds()
            self.extracting_speed_label.setText(_('{bytes_sec}/s'
                ).format(bytes_sec=sizeof_fmt(bytes_secs)))

            self.last_extract_bytes = self.extract_size
            self.last_extract = datetime.utcnow()

            extract_next_file()

        self.extracting_zipfile = zipfile.ZipFile(selected_info['path'])
        self.extracting_infolist = deque(self.extracting_zipfile.infolist())
        extract_next_file()
Пример #15
0
    def restore_button_clicked(self):
        class WaitingThread(QThread):
            completed = pyqtSignal()

            def __init__(self, wthread):
                super(WaitingThread, self).__init__()

                self.wthread = wthread

            def __del__(self):
                self.wait()

            def run(self):
                self.wthread.wait()
                self.completed.emit()

        if self.backup_searching:
            if (self.compressing_timer is not None and
                self.compressing_timer.isActive()):
                self.compressing_timer.stop()

            self.backup_searching = False

            self.finish_backup_saves()

            main_window = self.get_main_window()
            status_bar = main_window.statusBar()

            status_bar.showMessage(_('Restore backup cancelled'))

            self.restore_button.setText(_('Restore backup'))

        elif self.backup_compressing:
            if self.compress_thread is not None:
                self.backup_current_button.setEnabled(False)
                self.compress_thread.quit()

                def completed():
                    self.finish_backup_saves()
                    delete_path(self.backup_path)
                    self.compress_thread = None

                waiting_thread = WaitingThread(self.compress_thread)
                waiting_thread.completed.connect(completed)
                self.waiting_thread = waiting_thread

                waiting_thread.start()
            else:
                self.finish_backup_saves()
                delete_path(self.backup_path)
                self.compress_thread = None

            self.backup_compressing = False

            main_window = self.get_main_window()
            status_bar = main_window.statusBar()

            status_bar.showMessage(_('Restore backup cancelled'))

            self.restore_button.setText(_('Restore backup'))
        elif self.extracting_backup:
            if self.extracting_thread is not None:
                self.restore_button.setEnabled(False)
                self.extracting_thread.quit()

                def completed():
                    save_dir = os.path.join(self.game_dir, 'save')
                    delete_path(save_dir)
                    if self.temp_save_dir is not None:
                        retry_rename(self.temp_save_dir, save_dir)
                    self.temp_save_dir = None

                    self.finish_restore_backup()
                    self.extracting_thread = None

                waiting_thread = WaitingThread(self.extracting_thread)
                waiting_thread.completed.connect(completed)
                self.waiting_thread = waiting_thread

                waiting_thread.start()
            else:
                self.finish_restore_backup()
                self.extracting_thread = None

            self.extracting_backup = False

            main_window = self.get_main_window()
            status_bar = main_window.statusBar()

            status_bar.showMessage(_('Restore backup cancelled'))
        else:
            selection_model = self.backups_table.selectionModel()
            if selection_model is None or not selection_model.hasSelection():
                return

            selected = selection_model.currentIndex()
            table_item = self.backups_table.item(selected.row(), 0)
            selected_info = self.backups[table_item]

            if not os.path.isfile(selected_info['path']):
                return

            backup_previous = not config_true(get_config_value(
                'do_not_backup_previous', 'False'))

            if backup_previous:
                '''
                If restoring the before_last_restore, we rename it to make sure
                we make a proper backup first.
                '''
                model = selection_model.model()
                backup_name = model.data(model.index(selected.row(), 0))

                before_last_restore_name = _('before_last_restore')

                if backup_name.lower() == before_last_restore_name.lower():
                    backup_dir = os.path.join(self.game_dir, 'save_backups')

                    name_lower = backup_name.lower()
                    name_key = alphanum_key(name_lower)
                    max_counter = 1

                    for entry in scandir(backup_dir):
                        filename, ext = os.path.splitext(entry.name)
                        if ext.lower() == '.zip':
                            filename_lower = filename.lower()

                            filename_key = alphanum_key(filename_lower)

                            counter = filename_key[-1:][0]
                            if len(filename_key) > 1 and isinstance(counter,
                                int):
                                filename_key = filename_key[:-1]

                                if name_key == filename_key:
                                    max_counter = max(max_counter, counter)

                    new_backup_name = (before_last_restore_name +
                        str(max_counter + 1))
                    new_backup_path = os.path.join(backup_dir,
                        new_backup_name + '.zip')

                    if not retry_rename(selected_info['path'], new_backup_path):
                        return

                    selected_info['path'] = new_backup_path

                def next_step():
                    self.restore_backup()

                self.after_backup = next_step

                self.backup_saves(before_last_restore_name, True)

                self.restore_button.setEnabled(True)
                self.restore_button.setText(_('Cancel restore backup'))
            else:
                self.restore_backup()