Ejemplo n.º 1
0
 def _on_special_file_event(self, path, event_type, new_path):
     logger.debug("Special file event obtained for path %s, type %s", path,
                  event_type)
     special_dirname, special_filename = op.split(path)
     filename = special_filename.rsplit('.', 1)[0]  # cut off '.download'
     if not self._is_deleting and self._current_share_name == filename and (
             event_type in (DELETE, MOVE) or not op.exists(path)):
         to_cancel = True
         special_dirname = ensure_unicode(special_dirname)
         rel_special_dir = self._relpath(special_dirname)
         with self._special_event_lock:
             self._special_event_no += 1
         if event_type == MOVE:
             new_dir, new_file = op.split(new_path)
             if special_filename == new_file:  # folder moved locally
                 new_dir = ensure_unicode(new_dir)
                 rel_new_dir = self._relpath(new_dir)
                 self._sync.update_special_paths.emit(
                     rel_special_dir, rel_new_dir)
                 self._change_folder_uuid_local(new_dir)
                 self._update_spec_files(new_path, self._is_folder)
                 to_cancel = False
         if event_type == DELETE or to_cancel:
             folder_deleted = not op.isdir(special_dirname)
             folder_excluded = self._sync.is_dir_excluded(rel_special_dir)
             self.cancel_share_download(filename,
                                        folder_deleted=folder_deleted,
                                        folder_excluded=folder_excluded)
Ejemplo n.º 2
0
def get_url():
    filename = config.get_main_option("filename")
    if filename is None:
        filename = ensure_unicode(
            join(get_patches_dir(get_data_dir(), create=True), 'patches.db'))
    url = config.get_main_option("sqlalchemy.url")
    url = ensure_unicode(url)
    url = url.format(filename=FilePath(filename))
    return url
Ejemplo n.º 3
0
    def show_tray_notification(self, text, title=""):
        if not title:
            title = tr('Pvtbox')
        # Convert strings to unicode
        if type(text) in (str, str):
            text = ensure_unicode(text)
        if type(title) in (str, str):
            title = ensure_unicode(title)

        logger.info("show_tray_notification: %s, title: %s", text, title)
        if self._tray.supportsMessages():
            self._tray.showMessage(title, text)
        else:
            logger.warning("tray does not supports messages")
Ejemplo n.º 4
0
    def __init__(self,
                 cfg,
                 web_api,
                 filename,
                 ss_client,
                 tracker=None,
                 parent=None,
                 network_speed_calculator=None,
                 db=None):
        """
        Constructor

        @param web_api Client_API class instance [Client_API]
        @param ss_client Instance of signalling.SignalServerClient
        @param tracker Instance of stat_tracking.Tracker
        """

        QObject.__init__(self, parent=parent)

        self._cfg = cfg
        # Client_API class instance
        self._web_api = web_api
        # Signalling server client instance
        self._ss_client = ss_client
        self._tracker = tracker
        self._network_speed_calculator = network_speed_calculator
        self._db = db
        self._filename = ensure_unicode(filename)
        self.task_to_report = {}

        self._downloader = HttpDownloader(
            network_speed_calculator=self._network_speed_calculator)
        self._set_callbacks()

        # Download tasks info as task_id: info
        self.download_tasks_info = {}

        self._last_progress_report_time = 0
        self._last_length = 0.0
        self._was_stopped = False
        self._empty_progress = (None, 0, 0)

        self._open_uploads_file()

        self._uploads_deleted = \
            self._uploads_excluded = \
            self._uploads_not_synced = set()

        self._on_server_connect_signal.connect(self._on_server_connect)
        self._upload_task_completed_signal.connect(
            self._on_upload_task_completed)
        self._upload_task_error_signal.connect(self._on_upload_task_error)
        self._upload_task_progress_signal.connect(
            self._on_upload_task_progress)
        self._on_upload_added_signal.connect(self._on_upload_added)
        self._on_upload_cancel_signal.connect(self._on_upload_cancel)

        self._check_upload_path_timer = QTimer(self)
        self._check_upload_path_timer.setInterval(10 * 1000)
        self._check_upload_path_timer.timeout.connect(self._check_upload_paths)
Ejemplo n.º 5
0
    def _get_icons_info(self, file_list, added, removed):
        icons_info = []
        try:
            for path, is_dir, created_time, was_updated in file_list:
                if path not in added:
                    icons_info.append((None, None, None))
                    continue

                elif path in self._files:
                    icons_info.append(self._files[path])
                    continue

                abs_path = op.join(self._config.sync_directory, path)
                abs_path = ensure_unicode(abs_path)
                abs_path = FilePath(abs_path)           # .longpath doesn't work
                mime, _ = mimetypes.guess_type(path)
                image = QImage(abs_path)
                if image.isNull():
                    image = None
                icons_info.append((image, mime, QFileInfo(abs_path)))
        except Exception as e:
            logger.error("Icons info error: %s", e)

        self._icons_info_ready.emit(
            icons_info, file_list, added, removed)
Ejemplo n.º 6
0
    def start(self):
        self._loop = asyncio.new_event_loop()
        asyncio.set_event_loop(self._loop)
        self._factory = WebSocketServerFactory(
            "ws://127.0.0.1", loop=self._loop)
        self._factory.protocol = IPCWebSocketProtocol
        coro = self._factory.loop.create_server(self._factory, '127.0.0.1', 0)
        self._server = self._factory.loop.run_until_complete(coro)

        _, port = self._server.sockets[0].getsockname()
        self._factory.setSessionParameters(url="ws://127.0.0.1:{}".format(port))

        if get_platform() == 'Darwin':
            port_path = join(
                HOME_DIR,
                'Library',
                'Containers',
                'net.pvtbox.Pvtbox.PvtboxFinderSync',
                'Data',
                'pvtbox.port')
        else:
            port_path = join(
                get_cfg_dir(),
                'pvtbox.port')
        port_path = ensure_unicode(port_path)
        self._loop.call_soon_threadsafe(
            self._write_opened_port_to_accessible_file, port, port_path)

        if get_platform() == 'Darwin':
            port_path = join(
                HOME_DIR,
                'Library',
                'Containers',
                'net.pvtbox.Pvtbox.PvtboxShareExtension',
                'Data',
                'pvtbox.port')
            port_path = ensure_unicode(port_path)
            self._loop.call_soon_threadsafe(
                self._write_opened_port_to_accessible_file, port, port_path)

        self._factory.loop.run_forever()
Ejemplo n.º 7
0
def get_shared_reply():
    paths = params.get_shared_paths_func()
    if paths is None:
        return None

    paths = list(
        map(
            lambda path: FilePath(
                ensure_unicode(join(params.cfg.sync_directory, path))).
            longpath, paths))

    cmd = dict(cmd="shared", paths=paths)
    return json.dumps(cmd)
Ejemplo n.º 8
0
 def _relpath(self, path, data_dir=None):
     rel_path = None
     if not data_dir:
         data_dir = FilePath(
             self._cfg.sync_directory if self._cfg else get_data_dir())
     if not path:
         path = FilePath(data_dir)
     if path in data_dir:
         rel_path = op.relpath(path, data_dir)
         if rel_path == os.curdir:
             rel_path = ""
         rel_path = ensure_unicode(rel_path)
     return rel_path
Ejemplo n.º 9
0
def get_offline_status(paths):
    if not params.cfg.smart_sync:
        return 2  # no smart sync

    rel_paths = list()
    for path in paths:
        path = ensure_unicode(path)
        try:
            # Name of the file relative to the root directory
            root, rel_path = get_relpath(path)
            if not rel_path:
                raise SharePathException()

            rel_paths.append(rel_path)
        except SharePathException:
            logger.warning("Incorrect path %s", path)
            return 2  # no smart sync

    return params.sync.get_offline_status(rel_paths, timeout=0.5)
Ejemplo n.º 10
0
    def file_event_create(self, event_uuid, file_name, file_size, folder_uuid,
                          diff_file_size, file_hash):
        '''
        'file_event_create' request of file event registration API.
        Registers file creation on API server

        @return Server reply in the form
            {'result': status, 'info': server_message, data: useful_data}
        '''

        data = {
            "event_uuid": event_uuid,
            "file_name": ensure_unicode(file_name),
            "file_size": file_size,
            "folder_uuid": folder_uuid if folder_uuid else "",
            "diff_file_size": diff_file_size,
            "hash": file_hash,
        }

        return self.create_event_request(action='file_event_create', data=data)
Ejemplo n.º 11
0
    def _update_file_list_item_widget(self, widget, rel_path, created_time,
                                      was_updated, icon_info):
        abs_path = op.join(self._config.sync_directory, rel_path)
        abs_path = ensure_unicode(abs_path)
        abs_path = FilePath(abs_path).longpath

        widget.created_time = created_time
        widget.was_updated = was_updated
        widget.file_name_label.setText(
            elided(rel_path, widget.file_name_label))
        widget.time_delta_label.setText(get_added_time_string(
            created_time, was_updated, False))

        self._set_icon_label(icon_info, widget.icon_label)
        get_link_button = widget.get_link_button
        get_link_button.rel_path = rel_path
        get_link_button.abs_path = abs_path
        if self._is_shared(rel_path):
            if not get_link_button.icon():
                get_link_button.setIcon(QIcon(':images/getLink.png'))
        elif get_link_button.icon():
            get_link_button.setIcon(QIcon())
Ejemplo n.º 12
0
    def _start_service(self):
        if not self._starting_service:
            self._starting_service = True
            self._stop_service()
            logger.debug("Starting service...")
            options = dict(shell=True) \
                if is_launched_from_code() else dict(shell=False)
            platform = get_platform()
            if platform == 'Darwin':
                options['close_fds'] = True

            from_code = is_launched_from_code()
            if not from_code:
                self._args = map(lambda a: a.strip('"'), self._args)
            args = get_service_start_command() + \
                   list(map(lambda a: ensure_unicode(a),
                            self._args))
            cmd = ' '.join(args) if from_code else \
                list(args)
            if "--logging-disabled" not in self._args:
                self._reopen_stderr_log()
            else:
                self._stderr_log = None

            logger.debug("Service start command: %s", cmd)
            self._service_process = subprocess.Popen(
                cmd, stderr=self._stderr_log, **options)
            if not self._start_only:
                self._loop.call_later(
                    self.start_service_timeout, self._drop_starting_service)
            if self._starting_service_signal:
                self._starting_service_signal.emit()

        if not self._start_only:
            self._loop.call_later(
                self.connect_to_service_interval, self._connect_to_service)
Ejemplo n.º 13
0
    def _on_upload_task_completed(self, upload_id_str, elapsed, total_str):
        """
        Slot to be called on upload task download completion

        @param upload_id_str ID of upload task [string]
        @param elapsed Time elapsed from download starting (in seconds) [float]
        @param total_str Size of file being downloaded (in bytes) [string]
        """

        upload_id = int(upload_id_str)
        state = self.download_tasks_info[upload_id]['state']

        upload_name = self.download_tasks_info[upload_id]['upload_name']
        if state == 'cancelled':
            logger.debug("Upload task %s cancelled", upload_id)
            self._on_upload_failed(upload_id)
            # Tray notification
            self.upload_cancelled.emit(upload_name)
            return
        elif state == 'paused':
            self.download_tasks_info[upload_id]['elapsed'] += elapsed
            return

        elapsed += self.download_tasks_info[upload_id]['elapsed']
        total = int(total_str)
        bps_avg = int(total / elapsed) if elapsed > 0 else 0
        bps_avg = "{:,}".format(bps_avg)
        logger.info(
            "Upload task ID '%s' complete (downloaded %s bytes in %s seconds"
            "(%s Bps))", upload_id_str, total_str, elapsed, bps_avg)

        # Calculate checksum
        tmp_fn = self.download_tasks_info[upload_id]['tmp_fn']
        checksum = self.download_tasks_info[upload_id]['upload_md5']
        try:
            logger.debug("Calculating checksum for upload task ID '%s'...",
                         upload_id)
            checksum_calculated = hashfile(tmp_fn)
        except Exception as e:
            logger.error("Failed to calculate checksum of '%s' (%s)", tmp_fn,
                         e)
            self._on_upload_failed(upload_id)
            return

        if self._tracker:
            self._tracker.http_download(upload_id, total, elapsed,
                                        checksum_calculated == checksum)

        # Validate checksum
        if checksum_calculated != checksum:
            logger.error("MD5 checkfum of '%s' is '%s' instead of '%s'",
                         tmp_fn, checksum_calculated, checksum)
            self._on_upload_failed(upload_id)
            return

        # Move file to its location
        path = self._check_upload_path(upload_id)
        if path is None:
            return
        path = FilePath(op.join(path, upload_name))
        fullpath = ensure_unicode(op.join(self._cfg.sync_directory, path))
        fullpath = FilePath(fullpath).longpath
        dirname = op.dirname(fullpath)
        if not op.isdir(dirname):
            logger.warning(
                "Destination directory %s"
                "does not exist for upload %s", dirname, fullpath)
            self._on_upload_failed(upload_id)
            return

        try:
            try:
                logger.info("Moving downloaded file '%s' to '%s'...", tmp_fn,
                            fullpath)
                # Create necessary directories
                make_dirs(fullpath)
                # Move file
                shutil.move(src=tmp_fn, dst=fullpath)
            except OSError as e:
                if e.errno != errno.EACCES:
                    raise e
                logger.warning(
                    "Can't move downloaded file '%s' into '%s' (%s)", tmp_fn,
                    dirname, e)
                fullpath = get_next_name(fullpath)
                shutil.move(src=tmp_fn, dst=fullpath)
        except Exception as e:
            logger.error("Failed to move downloaded file '%s' into '%s' (%s)",
                         tmp_fn, dirname, e)
            self._on_upload_failed(upload_id)
            return

        self.download_status.emit(*self._empty_progress,
                                  [{}, {}, [upload_id_str]], {})
        self._on_upload_complete(upload_id)
Ejemplo n.º 14
0
    def _on_sync_folder_location_button_clicked(self):
        selected_folder = QFileDialog.getExistingDirectory(
            self._dialog, tr('Choose Pvtbox folder location'),
            get_parent_dir(FilePath(self._cfg.sync_directory)))
        selected_folder = ensure_unicode(selected_folder)

        try:
            if not selected_folder:
                raise self._MigrationFailed("Folder is not selected")

            if len(selected_folder + "/Pvtbox") > self._max_root_len:
                if not self._migrate:
                    msgbox(tr("Destination path too long. "
                              "Please select shorter path."),
                           tr("Path too long"),
                           parent=self._dialog)
                raise self._MigrationFailed("Destination path too long")

            free_space = get_free_space(selected_folder)
            selected_folder = get_data_dir(dir_parent=selected_folder,
                                           create=False)
            if FilePath(selected_folder) == FilePath(self._cfg.sync_directory):
                raise self._MigrationFailed("Same path selected")

            if FilePath(selected_folder) in FilePath(self._cfg.sync_directory):
                msgbox(tr("Can't migrate into existing Pvtbox folder.\n"
                          "Please choose other location"),
                       tr("Invalid Pvtbox folder location"),
                       parent=self._dialog)
                raise self._MigrationFailed(
                    "Can't migrate into existing Pvtbox folder")

            if self._size and free_space < self._size:
                logger.debug(
                    "No disk space in %s. Free space: %s. Needed: %s.",
                    selected_folder, free_space, self._size)
                msgbox(tr(
                    "Insufficient disk space for migration to\n{}.\n"
                    "Please clean disk", selected_folder),
                       tr("No disk space"),
                       parent=self._dialog)
                raise self._MigrationFailed(
                    "Insufficient disk space for migration")

            self._migration_cancelled = False
            dialog = QProgressDialog(self._dialog)
            dialog.setWindowTitle(tr('Migrating to new Pvtbox folder'))
            dialog.setWindowIcon(QIcon(':/images/icon.svg'))
            dialog.setModal(True)
            dialog.setMinimum(0)
            dialog.setMaximum(100)
            dialog.setMinimumSize(400, 80)
            dialog.setAutoClose(False)

            def progress(value):
                logger.debug("Migration dialog progress received: %s", value)
                dialog.setValue(value)

            def migration_failed(error):
                logger.warning("Migration failed with error: %s", error)
                msgbox(error,
                       tr('Migration to new Pvtbox folder error'),
                       parent=dialog)
                dialog.cancel()
                self._migration_cancelled = True
                done()

            def cancel():
                logger.debug("Migration dialog cancelled")
                self._migration_cancelled = True
                self._migration.cancel()

            def done():
                logger.debug("Migration done")
                try:
                    self._migration.progress.disconnect(progress)
                    self._migration.failed.disconnect(migration_failed)
                    self._migration.done.disconnect(done)
                    dialog.canceled.disconnect(cancel)
                except Exception as e:
                    logger.warning("Can't disconnect signal %s", e)
                dialog.hide()
                dialog.done(QDialog.Accepted)
                dialog.close()

            self._migration = SyncDirMigration(self._cfg, parent=self._dialog)
            self._migration.progress.connect(progress, Qt.QueuedConnection)
            self._migration.failed.connect(migration_failed,
                                           Qt.QueuedConnection)
            self._migration.done.connect(done, Qt.QueuedConnection)
            dialog.canceled.connect(cancel)
            self._exit_service()
            old_dir = self._cfg.sync_directory
            self._migration.migrate(old_dir, selected_folder)

            def on_finished():
                logger.info("Migration dialog closed")
                if not self._migration_cancelled:
                    logger.debug("Setting new location")
                    self._ui.location_edit.setText(FilePath(selected_folder))

                    disable_file_logging(logger)
                    shutil.rmtree(op.join(old_dir, '.pvtbox'),
                                  ignore_errors=True)
                    set_root_directory(FilePath(selected_folder))
                    enable_file_logging(logger)

                    make_dir_hidden(get_patches_dir(selected_folder))

                self._start_service()

            dialog.finished.connect(on_finished)
            dialog.show()

        except self._MigrationFailed as e:
            logger.warning("Sync dir migration failed. Reason: %s", e)
        finally:
            if self._migrate:
                self._dialog.accept()
Ejemplo n.º 15
0
    def _create_file_list_item_widget(self, rel_path, created_time,
                                      was_updated, icon_info):
        abs_path = op.join(self._config.sync_directory, rel_path)
        abs_path = ensure_unicode(abs_path)
        abs_path = FilePath(abs_path).longpath
        widget = QWidget(parent=self._ui.file_list)
        widget.created_time = created_time
        widget.was_updated = was_updated

        widget.mouseReleaseEvent = lambda _: \
            qt_reveal_file_in_file_manager(
                widget.get_link_button.abs_path)

        main_layout = QHBoxLayout(widget)

        icon_label = QLabel(widget)
        widget.icon_label = icon_label
        main_layout.addWidget(icon_label)

        vertical_layout = QVBoxLayout()
        main_layout.addLayout(vertical_layout)

        file_name_label = QLabel(widget)
        widget.file_name_label = file_name_label
        vertical_layout.addWidget(file_name_label)

        horizontal_layout = QHBoxLayout()
        vertical_layout.addLayout(horizontal_layout)

        time_delta_label = QLabel(widget)
        widget.time_delta_label = time_delta_label
        horizontal_layout.addWidget(time_delta_label, alignment=Qt.AlignTop)

        get_link_button = QPushButton(widget)
        widget.get_link_button = get_link_button
        horizontal_layout.addWidget(get_link_button, alignment=Qt.AlignTop)

        self._set_icon_label(icon_info, icon_label)

        file_name_label.setFixedSize(304, 24)
        file_name_label.setFont(QFont('Noto Sans', 10 * self._dp))
        file_name_label.setAlignment(Qt.AlignTop | Qt.AlignLeft)
        file_name_label.setText(
            elided(rel_path, file_name_label))

        time_delta_label.setText(get_added_time_string(
            created_time, was_updated, False))
        time_delta_label.setFont(QFont('Noto Sans', 8 * self._dp, italic=True))
        time_delta_label.setMinimumSize(time_delta_label.width(), 24)
        time_delta_label.setAlignment(Qt.AlignTop | Qt.AlignLeft)
        time_delta_label.setStyleSheet('color: #A792A9;')

        get_link_button.setText('   {}  '.format(tr('Get link')))
        get_link_button.setFlat(True)
        get_link_button.setChecked(True)
        get_link_button.setMinimumSize(120, 24)
        get_link_button.setFont(QFont("Noto Sans", 8 * self._dp, italic=True))
        get_link_button.setMouseTracking(True)
        self._setup_get_link_button(get_link_button, rel_path, abs_path)

        return widget
Ejemplo n.º 16
0
def offline_paths(paths, is_offline=True, is_recursive=True):
    """
    Makes given paths offline as is_offline flag
    @param paths paths [list]
    @param is_offline flag [bool]
    @return None
    """
    def process_error(error, error_info=''):
        msg = {
            INCORRECT_PATH:
            "Failed to change offline status '%s'. Incorrect path",
            NOT_IN_SYNC: "Path for changing offline status not in sync '%s'",
        }
        logger.error(msg[error], paths)
        if params.tracker:
            tracker_errors = {
                INCORRECT_PATH: params.tracker.INCORRECT_PATH,
                NOT_IN_SYNC: params.tracker.NOT_IN_SYNC,
            }
            params.tracker.share_error(0, tracker_errors[error],
                                       time.time() - start_time)

    start_time = time.time()

    timeout = 10 * 60  # seconds
    message_timeout = 2  # seconds

    step = 0
    command_str = tr("add to offline") if is_offline \
        else tr("remove from offline")

    for path in paths:
        path = ensure_unicode(path)
        try:
            # Name of the file relative to the root directory
            root, rel_path = get_relpath(path)
            if not rel_path:
                raise SharePathException()
        except SharePathException:
            process_error(INCORRECT_PATH)
            return

        if rel_path.endswith(FILE_LINK_SUFFIX):
            rel_path = rel_path[:-len(FILE_LINK_SUFFIX)]
            if not rel_path:
                process_error(INCORRECT_PATH)
                return

        logger.info("Offline on=%s, path '%s'...", is_offline, rel_path)
        while True:
            # Wait if file not in db yet
            try:
                if op.isfile(path):
                    uuid = params.sync.get_file_uuid(rel_path)
                elif op.isdir(path):
                    uuid = params.sync.get_folder_uuid(rel_path)
                else:
                    process_error(INCORRECT_PATH)
                    return

            except (FileNotFound, FileInProcessing, FileEventsDBError):
                uuid = None

            if uuid or (time.time() - start_time > timeout and node_synced):
                break

            if step == message_timeout:
                filename = op.basename(path)
                Application.show_tray_notification(
                    tr("Prepare {}.\n"
                       "Action will be completed after {} synced").format(
                           command_str, filename))
            step += 1
            time.sleep(1)

        if not uuid:
            process_error(NOT_IN_SYNC)
            Application.show_tray_notification(
                tr("Can't {}.\n"
                   "{} not in sync").format(command_str, path))
            return

        try:
            params.sync.file_added_to_indexing.emit(FilePath(path))
            success = params.sync.make_offline(uuid,
                                               is_offline,
                                               is_recursive=is_recursive)
        except FileEventsDBError:
            success = False
        if not success:
            params.sync.file_removed_from_indexing.emit(FilePath(path))
            Application.show_tray_notification(
                tr("Can't {} for path: {}.").format(command_str, path))
Ejemplo n.º 17
0
    def migrate(self, old_dir, new_dir):
        logger.info("Starting sync dir migration from %s, to %s",
                    old_dir, new_dir)
        old_dir = FilePath(old_dir).longpath
        new_dir = FilePath(new_dir).longpath
        old_files = get_filelist(old_dir)
        old_dirs = get_dir_list(old_dir)
        total_count = len(old_files) + len(old_dirs) + 1
        progress = 0
        sent_progress = 0
        logger.debug("Migration progress: %s/%s (%s%%)", 0, total_count, sent_progress)
        count = 1

        copied_dirs = []
        copied_files = []

        make_dirs(new_dir, is_folder=True)
        copied_dirs.append(new_dir)
        logger.debug("Migration progress: %s/%s (%s%%)", count, total_count, sent_progress)
        self.progress.emit(sent_progress)

        for dir in old_dirs:
            if self._cancelled.isSet():
                self._delete(dirs=copied_dirs)
                logger.debug("Migration done because cancelled")
                self.done.emit()
                return

            new_dir_path = ensure_unicode(op.join(
                new_dir, op.relpath(dir, start=old_dir)))

            try:
                make_dirs(new_dir_path, is_folder=True)
            except Exception as e:
                logger.error("Make dirs error: %s", e)
                self.failed.emit(str(e))
                self._delete(dirs=copied_dirs)
                return

            copied_dirs.append(new_dir_path)
            count += 1
            progress = int(count / total_count * 100)
            if progress > sent_progress:
                sent_progress = progress
                self.progress.emit(sent_progress)
            logger.debug("Migration progress: %s/%s (%s%%)", count, total_count, sent_progress)

        for file in old_files:
            if self._cancelled.isSet():
                self._delete(dirs=copied_dirs, files=copied_files)
                logger.debug("Migration done because cancelled")
                self.done.emit()
                return

            if file in HIDDEN_FILES:
                continue

            new_file_path = ensure_unicode(op.join(
                new_dir, op.relpath(file, start=old_dir)))

            logger.info("Copying file %s, to %s",
                        file, new_file_path)
            try:
                copy_file(file, new_file_path, preserve_file_date=True)
            except Exception as e:
                logger.error("Copy file error: %s", e)
                self.failed.emit(str(e))
                self._delete(dirs=copied_dirs, files=copied_files)
                return

            copied_files.append(new_file_path)
            count += 1
            progress = int(count / total_count * 100)
            if progress > sent_progress:
                sent_progress = progress
                self.progress.emit(sent_progress)
            logger.debug("Migration progress: %s/%s (%s%%)", count, total_count, sent_progress)

        logger.debug("Saving new config")
        self._cfg.set_settings(dict(sync_directory=FilePath(new_dir)))
        self._cfg.sync()
        logger.info("New config saved")

        logger.debug("Updating shortcuts")
        create_shortcuts(new_dir)
        remove_shortcuts(old_dir)
        logger.debug("Resetting custom folder icons")
        reset_all_custom_folder_icons(old_dir)

        logger.debug("Migration done")
        self.done.emit()

        logger.info("Migration thread end")
Ejemplo n.º 18
0
def collaboration_path_settings(paths):
    """
    Prepares opening of collaboration settings dialog for given paths

    @param paths Path (1 element list) to folder with (potential)
        collaboration [list]
    @return None
    """
    def process_error(error, error_info=''):
        msg = {
            INCORRECT_PATH:
                "Failed to open collaboration settings '%s'. Incorrect path",
            NOT_IN_SYNC:
                "Path for collaboration settings not in sync '%s'",
        }
        logger.error(msg[error], paths)
        if params.tracker:
            tracker_errors = {
                INCORRECT_PATH: params.tracker.INCORRECT_PATH,
                NOT_IN_SYNC: params.tracker.NOT_IN_SYNC,
            }
            params.tracker.share_error(
                0,
                tracker_errors[error],
                time.time() - start_time)

    start_time = time.time()

    timeout = 10 * 60  # seconds
    message_timeout = 2  # seconds

    step = 0
    if len(paths) != 1:
        process_error(INCORRECT_PATH)
        return

    path = ensure_unicode(paths[0])
    if not op.isdir(path):
        process_error(INCORRECT_PATH)
        return

    try:
        # Name of the file relative to the root directory
        root, rel_path = get_relpath(path)
        if not rel_path or '/' in rel_path:
            raise SharePathException()
    except SharePathException:
        process_error(INCORRECT_PATH)
        return

    logger.info("Collaboration settings path '%s'...", rel_path)

    while True:
        # Wait if file not in db yet
        try:
            uuid = params.sync.get_folder_uuid(rel_path)
        except (FileNotFound, FileInProcessing, FileEventsDBError):
            uuid = None

        if uuid or (time.time() - start_time > timeout and node_synced):
            break

        if step == message_timeout:
            filename = op.basename(path)
            Application.show_tray_notification(
                tr("Prepare open collaboration settings.\n"
                   "Dialog will be opened after {} synced").format(
                    filename))
        step += 1
        time.sleep(1)

    if not uuid:
        process_error(NOT_IN_SYNC)
        Application.show_tray_notification(
            tr("Can't open collaboration settings.\n"
               "{} not in sync").format(path))
        return

    logger.debug("Collaboration settings requested for path %s, uuid %s",
                 rel_path, uuid)
    signals.show_collaboration_settings.emit(rel_path, uuid)