예제 #1
0
    def rename_location(self, location: Location, parent: Optional[QWidget] = None) -> None:
        if location.has_payload():
            self._show_rename_error_has_payload(location, parent)
        else:
            srcpath = location.get_stdio_name()
            srcbasename = os.path.basename(srcpath)
            srcdir = os.path.dirname(srcpath)

            dialog = RenameDialog(parent)
            dialog.set_basename(srcbasename)
            dialog.exec()

            if dialog.result() == QDialog.Accepted:
                oldpath = srcpath
                newpath = os.path.join(srcdir, dialog.get_new_basename())

                if oldpath == newpath:
                    logger.debug("FilesystemOperations.rename_location: source and destination are the same, "
                                 "skipping: \"%s\" to \"%s\"", oldpath, newpath)
                elif os.path.exists(newpath):
                    self._show_rename_error_file_exists(location, parent)
                else:
                    try:
                        self._rename(oldpath, newpath)
                    except OSError as err:
                        self._show_rename_error_os_error(location, err, traceback.format_exc(), parent)
예제 #2
0
    def rename_location(self,
                        location: Location,
                        parent: Optional[QWidget] = None) -> None:
        if location.has_payload():
            self._show_rename_error_has_payload(location, parent)
        else:
            srcpath = location.get_stdio_name()
            srcbasename = os.path.basename(srcpath)
            srcdir = os.path.dirname(srcpath)

            dialog = RenameDialog(parent)
            dialog.set_basename(srcbasename)
            dialog.exec()

            if dialog.result() == QDialog.Accepted:
                oldpath = srcpath
                newpath = os.path.join(srcdir, dialog.get_new_basename())

                if oldpath == newpath:
                    logger.debug(
                        "FilesystemOperations.rename_location: source and destination are the same, "
                        "skipping: \"%s\" to \"%s\"", oldpath, newpath)
                elif os.path.exists(newpath):
                    self._show_rename_error_file_exists(location, parent)
                else:
                    try:
                        self._rename(oldpath, newpath)
                    except OSError as err:
                        self._show_rename_error_os_error(
                            location, err, traceback.format_exc(), parent)
예제 #3
0
    def test_from_human_path(self):
        result = Location.from_human(".")
        expected = Location.from_path(os.getcwd())
        self.assertEqual(result, expected)

        result = Location.from_human("")
        expected = Location.from_path(os.getcwd())
        self.assertEqual(result, expected)
예제 #4
0
    def test_from_human_path(self):
        result = Location.from_human(".")
        expected = Location.from_path(os.getcwd())
        self.assertEqual(result, expected)

        result = Location.from_human("")
        expected = Location.from_path(os.getcwd())
        self.assertEqual(result, expected)
예제 #5
0
 def get_stdio_name(self, location: Location) -> str:
     if not location.has_payload():
         return location.get_path()
     else:
         if location._payloads[-1].path:
             parent = location.parent()
             outdir = self._archive_manager.get_extractor_content_dir(parent)
             return os.path.join(outdir, location._payloads[-1].path)
         else:
             outdir = self._archive_manager.get_extractor_content_dir(location)
             return outdir
예제 #6
0
 def on_return_pressed(self) -> None:
     try:
         completition = self._popup.get_current_completion()
         self._popup.hide()
         if completition is not None:
             location = Location.from_path(completition)
         else:
             location = Location.from_human(self.text())
     except Exception:
         logger.warning("unparsable location entered: %s", self.text())
     else:
         self._controller.set_location(location)
         self._popup.hide()
예제 #7
0
    def on_metadata_requested(self, location: Location) -> None:
        if self._close:
            return

        abspath = self.vfs.get_stdio_name(location)
        cached_metadata = self.cache.retrieve_metadata(abspath)

        try:
            stat = os.lstat(abspath)
            metadata: Dict[str, Any] = {}

        except FileNotFoundError as err:
            error_message = "".join(
                traceback.format_exception(etype=type(err),
                                           value=err,
                                           tb=err.__traceback__))
            metadata = {
                'location': location.as_url(),
                'path': abspath,
                'mtime': 0,
                'type': "error",
                'error_message': error_message
            }
            self.sig_metadata_ready.emit(location, metadata)

        else:
            if cached_metadata is not None and \
               (("mtime" in cached_metadata) and (stat.st_mtime == cached_metadata["mtime"])):
                self.sig_metadata_ready.emit(location, cached_metadata)
            else:
                try:
                    metadata.update(
                        self._create_generic_metadata(location, abspath))
                    metadata.update(
                        self._create_type_specific_metadata(location, abspath))
                except Exception as err:
                    error_message = "".join(
                        traceback.format_exception(etype=type(err),
                                                   value=err,
                                                   tb=err.__traceback__))
                    metadata = {
                        'location': location.as_url(),
                        'path': abspath,
                        'mtime': stat.st_mtime,
                        'type': "error",
                        'error_message': error_message
                    }

                self.cache.store_metadata(abspath, metadata)
                self.sig_metadata_ready.emit(location, metadata)
예제 #8
0
    def get_fileinfo(self, location: Location) -> FileInfo:
        if not location.has_payload():
            fi = FileInfo.from_path(location.get_path())
            fi._location = location
            return fi
        else:
            parent = location.parent()
            assert parent.has_payload()

            outdir = self._archive_manager.get_extractor_content_dir(parent)
            path = os.path.join(outdir, location._payloads[-1].path)

            fi = FileInfo.from_path(path)
            fi._location = location
            return fi
예제 #9
0
    def on_inotify_event(self, ev) -> None:
        try:
            logger.debug(
                "inotify-event: name: '%s'  mask: %s", ev.name,
                ", ".join([str(x) for x in inotify_flags.from_mask(ev.mask)]))

            location = Location.join(self.location, ev.name)

            if ev.mask & inotify_flags.CREATE:
                self.sig_file_added.emit(self.vfs.get_fileinfo(location))
            elif ev.mask & inotify_flags.DELETE:
                self.sig_file_removed.emit(location)
            elif ev.mask & inotify_flags.DELETE_SELF:
                pass  # directory itself has disappeared
            elif ev.mask & inotify_flags.MOVE_SELF:
                pass  # directory itself has moved
            elif ev.mask & inotify_flags.MODIFY or ev.mask & inotify_flags.ATTRIB:
                self.sig_file_modified.emit(self.vfs.get_fileinfo(location))
            elif ev.mask & inotify_flags.MOVED_FROM:
                self.sig_file_removed.emit(location)
            elif ev.mask & inotify_flags.MOVED_TO:
                self.sig_file_added.emit(self.vfs.get_fileinfo(location))
            elif ev.mask & inotify_flags.CLOSE_WRITE:
                self.sig_file_closed.emit(self.vfs.get_fileinfo(location))
            else:
                # unhandled event
                print("ERROR: Unhandled flags:")
                for flag in inotify_flags.from_mask(ev.mask):
                    print('    ' + str(flag))
        except Exception as err:
            print(traceback.format_exc())
            print("DirectoryWatcher:", err)
예제 #10
0
    def test_collector(self):
        app = QApplication([])

        try:
            vfs = StdioFilesystem("/tmp")
            metadata_collector = MetaDataCollector(vfs)

            def on_metadata(filename, metadata):
                print(filename)
                print(metadata)
                print()

            metadata_collector.sig_metadata_ready.connect(on_metadata)

            metadata_collector.request_metadata(
                Location.from_path(
                    "dirtools/fileview/icons/noun_409399_cc.png"))

            QTimer.singleShot(500, metadata_collector.close)
            QTimer.singleShot(1500, app.quit)

            app.exec()
        except Exception as err:
            print(err)
        finally:
            metadata_collector.close()
            vfs.close()
예제 #11
0
    def test_location_parent(self):
        parent_texts = [
            ("file:///home/juser/test.rar//rar:file_inside.rar",
             ("file", "/home/juser/test.rar", [Payload("rar", "")])),
            ("file:///home/juser/test.rar", ("file", "/home/juser", [])),
            ("file:///home/juser/test.rar//rar", ("file", "/home/juser", [])),
            ("file:///tmp/", ("file", "/", [])),
            ("file:///home/juser/test.rar//rar:file_inside.rar//rar:file.txt",
             ("file", "/home/juser/test.rar",
              [Payload("rar", "file_inside.rar"),
               Payload("rar", "")])),
            ("file:///home/juser/test.rar//rar:file_inside.rar//rar",
             ("file", "/home/juser/test.rar", [Payload("rar", "")])),
            ("file:///test.rar//rar:one//rar:two//rar:three",
             ("file", "/test.rar", [
                 Payload("rar", "one"),
                 Payload("rar", "two"),
                 Payload("rar", "")
             ]))
        ]

        for text, (protocol, abspath, payloads) in parent_texts:
            location = Location.from_url(text)
            location = location.parent()
            self.assertEqual(location._protocol, protocol, text)
            self.assertEqual(location._path, abspath, text)
            self.assertEqual(location._payloads, payloads, text)
예제 #12
0
    def extract(self, location: Location, directory_watcher, stdio) -> Optional[ArchiveExtractor]:
        extractor = self._extractors.get(location, None)
        if extractor is not None:
            return extractor  # extraction already running or queued

        outdir = self._make_extractor_outdir(location)

        if not os.path.isdir(outdir):
            extractor = ArchiveExtractor(stdio.get_stdio_name(location.origin()), outdir)
            self._extractors[location] = extractor
            extractor.sig_started.connect(lambda extractor:
                                          self._on_archive_extractor_started(extractor))
            extractor.sig_finished.connect(lambda extractor, d=directory_watcher:
                                           self._on_archive_extractor_finished(extractor, d))

            if self.get_running_extractor_count() < self._max_extractors:
                extractor.start()
            else:
                self._queued_extractors.append(extractor)

            return extractor
        else:
            status_file = os.path.join(outdir, "status.json")
            status = ExtractorStatus.from_file(status_file)

            if status.status() == ExtractorResult.FAILURE:
                def send_message(dw=directory_watcher, message=status.message()):
                    dw.sig_message.emit(status.message())

                # FIXME: this is a bit of a crude hack to
                # communicate the message to the user
                QTimer.singleShot(0, send_message)
                logger.error("%s: archive exist, but is broken: %s", location, status.message())

            return None
예제 #13
0
    def from_path(path: str) -> 'FileInfo':
        logger.debug("FileInfo.from_path: %s", path)

        fi = FileInfo()

        fi._abspath = os.path.abspath(path)
        fi._location = Location.from_path(fi._abspath)
        fi._dirname = os.path.dirname(fi._abspath)
        fi._basename = os.path.basename(fi._abspath)
        fi._ext = os.path.splitext(fi._abspath)[1]

        try:
            fi._stat = os.lstat(fi._abspath)
            fi._have_access = os.access(fi._abspath, os.R_OK)
            fi._error = FileInfoError.NO_ERROR
        except (FileNotFoundError, NotADirectoryError):
            fi._error = FileInfoError.FILENOTFOUND
        except PermissionError:
            fi._error = FileInfoError.PERMISSIONDENIED
        except OSError as err:
            if err.errno == errno.EIO:
                fi._error = FileInfoError.IO
            else:
                fi._error = FileInfoError.UNKNOWN
        except Exception as err:
            fi._error = FileInfoError.UNKNOWN
        else:
            fi._isdir = os.path.isdir(fi._abspath)
            fi._isfile = stat.S_ISREG(fi._stat.st_mode)
            fi._issymlink = stat.S_ISLNK(fi._stat.st_mode)

        return fi
예제 #14
0
    def test_location_parent(self):
        parent_texts = [
            ("file:///home/juser/test.rar//rar:file_inside.rar",
             ("file", "/home/juser/test.rar", [Payload("rar", "")])),

            ("file:///home/juser/test.rar",
             ("file", "/home/juser", [])),

            ("file:///home/juser/test.rar//rar",
             ("file", "/home/juser", [])),

            ("file:///tmp/",
             ("file", "/", [])),

            ("file:///home/juser/test.rar//rar:file_inside.rar//rar:file.txt",
             ("file", "/home/juser/test.rar", [Payload("rar", "file_inside.rar"), Payload("rar", "")])),

            ("file:///home/juser/test.rar//rar:file_inside.rar//rar",
             ("file", "/home/juser/test.rar", [Payload("rar", "")])),

            ("file:///test.rar//rar:one//rar:two//rar:three",
             ("file", "/test.rar", [Payload("rar", "one"), Payload("rar", "two"), Payload("rar", "")]))
        ]

        for text, (protocol, abspath, payloads) in parent_texts:
            location = Location.from_url(text)
            location = location.parent()
            self.assertEqual(location._protocol, protocol, text)
            self.assertEqual(location._path, abspath, text)
            self.assertEqual(location._payloads, payloads, text)
예제 #15
0
    def test_collector(self):
        app = QApplication([])

        try:
            vfs = StdioFilesystem("/tmp")
            metadata_collector = MetaDataCollector(vfs)

            def on_metadata(filename, metadata):
                print(filename)
                print(metadata)
                print()

            metadata_collector.sig_metadata_ready.connect(on_metadata)

            metadata_collector.request_metadata(Location.from_path("dirtools/fileview/icons/noun_409399_cc.png"))

            QTimer.singleShot(500, metadata_collector.close)
            QTimer.singleShot(1500, app.quit)

            app.exec()
        except Exception as err:
            print(err)
        finally:
            metadata_collector.close()
            vfs.close()
예제 #16
0
    def from_path(path: str) -> 'FileInfo':
        logger.debug("FileInfo.from_path: %s", path)

        fi = FileInfo()

        fi._abspath = os.path.abspath(path)
        fi._location = Location.from_path(fi._abspath)
        fi._dirname = os.path.dirname(fi._abspath)
        fi._basename = os.path.basename(fi._abspath)
        fi._ext = os.path.splitext(fi._abspath)[1]

        try:
            fi._stat = os.lstat(fi._abspath)
            fi._have_access = os.access(fi._abspath, os.R_OK)
            fi._error = FileInfoError.NO_ERROR
        except (FileNotFoundError, NotADirectoryError):
            fi._error = FileInfoError.FILENOTFOUND
        except PermissionError:
            fi._error = FileInfoError.PERMISSIONDENIED
        except OSError as err:
            if err.errno == errno.EIO:
                fi._error = FileInfoError.IO
            else:
                fi._error = FileInfoError.UNKNOWN
        except Exception as err:
            fi._error = FileInfoError.UNKNOWN
        else:
            fi._isdir = os.path.isdir(fi._abspath)
            fi._isfile = stat.S_ISREG(fi._stat.st_mode)
            fi._issymlink = stat.S_ISLNK(fi._stat.st_mode)

        return fi
예제 #17
0
    def _set_directory_location(self, location: Location) -> None:
        self.file_collection.clear()

        if self._directory_watcher is not None:
            self._directory_watcher.close()
        self._directory_watcher = self.app.vfs.opendir(location)

        if hasattr(self._directory_watcher, 'sig_file_added'):
            self._directory_watcher.sig_file_added.connect(
                self.file_collection.add_fileinfo)

        if hasattr(self._directory_watcher, 'sig_file_removed'):
            self._directory_watcher.sig_file_removed.connect(
                self.file_collection.remove_file)

        if hasattr(self._directory_watcher, 'sig_file_modified'):
            self._directory_watcher.sig_file_modified.connect(
                self.file_collection.modify_file)

        if hasattr(self._directory_watcher, 'sig_file_closed'):
            self._directory_watcher.sig_file_closed.connect(
                self.file_collection.close_file)

        if hasattr(self._directory_watcher, 'sig_finished'):
            self._directory_watcher.sig_finished.connect(self._on_finished)

        if hasattr(self._directory_watcher, 'sig_scandir_finished'):
            self._directory_watcher.sig_scandir_finished.connect(
                self._on_scandir_finished)

        if hasattr(self._directory_watcher, 'sig_message'):
            self._directory_watcher.sig_message.connect(
                self._on_directory_watcher_message)

        self._directory_watcher.start()

        if location.protocol() == "search":
            abspath, query = location.search_query()
            search_location = Location.from_path(abspath)
            self.location = search_location
            self._gui._window.set_location(search_location)
            self._gui._window.search_lineedit.setText(query)
            self._gui._window.search_toolbar.show()
        else:
            self.location = location
            self._gui._window.set_location(self.location)
예제 #18
0
    def on_metadata_requested(self, location: Location) -> None:
        if self._close:
            return

        abspath = self.vfs.get_stdio_name(location)
        cached_metadata = self.cache.retrieve_metadata(abspath)

        try:
            stat = os.lstat(abspath)
            metadata: Dict[str, Any] = {}

        except FileNotFoundError as err:
            error_message = "".join(traceback.format_exception(etype=type(err),
                                                               value=err,
                                                               tb=err.__traceback__))
            metadata = {
                'location': location.as_url(),
                'path': abspath,
                'mtime': 0,
                'type': "error",
                'error_message': error_message
            }
            self.sig_metadata_ready.emit(location, metadata)

        else:
            if cached_metadata is not None and \
               (("mtime" in cached_metadata) and (stat.st_mtime == cached_metadata["mtime"])):
                self.sig_metadata_ready.emit(location, cached_metadata)
            else:
                try:
                    metadata.update(self._create_generic_metadata(location, abspath))
                    metadata.update(self._create_type_specific_metadata(location, abspath))
                except Exception as err:
                    error_message = "".join(traceback.format_exception(etype=type(err),
                                                                       value=err,
                                                                       tb=err.__traceback__))
                    metadata = {
                        'location': location.as_url(),
                        'path': abspath,
                        'mtime': stat.st_mtime,
                        'type': "error",
                        'error_message': error_message
                    }

                self.cache.store_metadata(abspath, metadata)
                self.sig_metadata_ready.emit(location, metadata)
예제 #19
0
파일: history.py 프로젝트: Grumbel/dirtool
 def append(self, location: Location) -> None:
     insertion_time = time.time()
     c = self._db.cursor()
     c.execute("BEGIN")
     group_id = (c.execute("SELECT max(group_id) FROM history").fetchone()[0] or 0) + 1
     c.execute("INSERT INTO history (group_id, date, location) VALUES (?, ?, ?)",
               (group_id, insertion_time, location.as_url()))
     c.execute("COMMIT")
     self._db.commit()
예제 #20
0
    def _make_extractor_outdir(self, location: Location) -> str:
        assert location._payloads[-1].protocol == "archive"

        origin = location.origin()
        origin._payloads.append(Payload("archive", ""))

        loc_hash = hashlib.md5(origin.as_url().encode()).hexdigest()
        outdir = os.path.join(self._extractor_dir, loc_hash)
        return outdir
예제 #21
0
    def start_search(self, query):
        if self.location is None:
            abspath = "/tmp"
        else:
            abspath = self.app.vfs.get_stdio_name(self.location)

        location = Location.from_search_query(abspath, query)
        self.set_location(location)

        self._gui._window.file_view.setFocus()
예제 #22
0
 def _show_rename_error_file_exists(self, location: Location, parent: Optional[QWidget]):
     msg = QMessageBox(parent)
     msg.setIcon(QMessageBox.Critical)
     msg.setWindowTitle("Rename Error")
     msg.setTextFormat(Qt.RichText)
     msg.setText("<b>Failed to rename \"{}\".</b>"
                 .format(html.escape(location.as_human())))
     msg.setInformativeText("Can't rename file, filenname already exists.")
     msg.setStandardButtons(QMessageBox.Ok)
     msg.exec()
예제 #23
0
    def _create_generic_metadata(self, location: Location, abspath: str) -> Dict[str, Any]:
        metadata: Dict[str, Any] = {}

        metadata['location'] = location.as_url()
        metadata['path'] = abspath

        stat = os.lstat(abspath)
        metadata['mtime'] = stat.st_mtime

        return metadata
예제 #24
0
    def _create_generic_metadata(self, location: Location,
                                 abspath: str) -> Dict[str, Any]:
        metadata: Dict[str, Any] = {}

        metadata['location'] = location.as_url()
        metadata['path'] = abspath

        stat = os.lstat(abspath)
        metadata['mtime'] = stat.st_mtime

        return metadata
예제 #25
0
 def _show_rename_error_file_exists(self, location: Location,
                                    parent: Optional[QWidget]):
     msg = QMessageBox(parent)
     msg.setIcon(QMessageBox.Critical)
     msg.setWindowTitle("Rename Error")
     msg.setTextFormat(Qt.RichText)
     msg.setText("<b>Failed to rename \"{}\".</b>".format(
         html.escape(location.as_human())))
     msg.setInformativeText("Can't rename file, filenname already exists.")
     msg.setStandardButtons(QMessageBox.Ok)
     msg.exec()
예제 #26
0
 def test_ancestry(self):
     location = Location.from_url("file:///home/juser/test.rar//rar:bar/foo.zip//zip:bar.png")
     result = location.ancestry()
     expected = [
         Location.from_url('file:///'),
         Location.from_url('file:///home'),
         Location.from_url('file:///home/juser'),
         Location.from_url('file:///home/juser/test.rar//rar'),
         Location.from_url('file:///home/juser/test.rar//rar:bar'),
         Location.from_url('file:///home/juser/test.rar//rar:bar/foo.zip//zip'),
         Location.from_url('file:///home/juser/test.rar//rar:bar/foo.zip//zip:bar.png')
     ]
     self.assertEqual(result, expected)
예제 #27
0
    def test_location_join(self):
        join_texts = [
            ("file:///home/juser/test.rar//rar", "foobar",
             ("file", "/home/juser/test.rar", [Payload("rar", "foobar")])),
            ("file:///home/juser/test.rar//rar:foo.rar//rar", "foobar.png",
             ("file", "/home/juser/test.rar",
              [Payload("rar", "foo.rar"),
               Payload("rar", "foobar.png")])),
            ("file:///home/juser/test.rar//rar:foo.rar//rar:foobar", "bar.png",
             ("file", "/home/juser/test.rar",
              [Payload("rar", "foo.rar"),
               Payload("rar", "foobar/bar.png")])),
        ]

        for base_text, join_text, (protocol, abspath, payloads) in join_texts:
            base = Location.from_url(base_text)
            result = Location.join(base, join_text)

            self.assertEqual(result._protocol, protocol, base_text)
            self.assertEqual(result._path, abspath, base_text)
            self.assertEqual(result._payloads, payloads, base_text)
예제 #28
0
 def append(self, location: Location) -> None:
     insertion_time = time.time()
     c = self._db.cursor()
     c.execute("BEGIN")
     group_id = (
         c.execute("SELECT max(group_id) FROM history").fetchone()[0]
         or 0) + 1
     c.execute(
         "INSERT INTO history (group_id, date, location) VALUES (?, ?, ?)",
         (group_id, insertion_time, location.as_url()))
     c.execute("COMMIT")
     self._db.commit()
예제 #29
0
def main(argv: List[str]) -> None:
    args = parse_args(argv[1:])

    if args.debug:
        logging.basicConfig(level=logging.DEBUG)
    else:
        logging.basicConfig(level=logging.WARNING)

    if args.profile:
        activate_profiler(True)

    app = FileViewApplication()

    if args.FILE == []:
        app.show_location(Location.from_path(os.getcwd()))
    elif args.FILE == ["-"]:
        if args.null:
            app.show_location(Location.from_url("stream0:///stdin"))
        else:
            app.show_location(Location.from_url("stream:///stdin"))
    elif len(args.FILE) == 1 and os.path.isdir(args.FILE[0]):
        app.show_location(Location.from_human(args.FILE[0]))
    elif args.recursive:
        files = expand_directories(args.FILE, args.recursive)
        app.show_files([Location.from_path(f) for f in files])
    else:
        app.show_files([Location.from_human(f) for f in args.FILE])

    sys.exit(app.run())
예제 #30
0
def main(argv: List[str]) -> None:
    args = parse_args(argv[1:])

    if args.debug:
        logging.basicConfig(level=logging.DEBUG)
    else:
        logging.basicConfig(level=logging.WARNING)

    if args.profile:
        activate_profiler(True)

    app = FileViewApplication()

    if args.FILE == []:
        app.show_location(Location.from_path(os.getcwd()))
    elif args.FILE == ["-"]:
        if args.null:
            app.show_location(Location.from_url("stream0:///stdin"))
        else:
            app.show_location(Location.from_url("stream:///stdin"))
    elif len(args.FILE) == 1 and os.path.isdir(args.FILE[0]):
        app.show_location(Location.from_human(args.FILE[0]))
    elif args.recursive:
        files = expand_directories(args.FILE, args.recursive)
        app.show_files([Location.from_path(f) for f in files])
    else:
        app.show_files([Location.from_human(f) for f in args.FILE])

    sys.exit(app.run())
예제 #31
0
    def process(self) -> None:
        fileinfos = []

        logger.debug("DirectoryWatcher.process: gather directory content")
        for entry in os.listdir(self.path):
            location = Location.join(self.location, entry)
            fileinfo = self.vfs.get_fileinfo(location)
            fileinfos.append(fileinfo)

            if self._close:
                return

        self.sig_scandir_finished.emit(fileinfos)
예제 #32
0
    def test_location_join(self):
        join_texts = [
            ("file:///home/juser/test.rar//rar",
             "foobar",
             ("file", "/home/juser/test.rar", [Payload("rar", "foobar")])),

            ("file:///home/juser/test.rar//rar:foo.rar//rar",
             "foobar.png",
             ("file", "/home/juser/test.rar", [Payload("rar", "foo.rar"), Payload("rar", "foobar.png")])),

            ("file:///home/juser/test.rar//rar:foo.rar//rar:foobar",
             "bar.png",
             ("file", "/home/juser/test.rar", [Payload("rar", "foo.rar"), Payload("rar", "foobar/bar.png")])),
        ]

        for base_text, join_text, (protocol, abspath, payloads) in join_texts:
            base = Location.from_url(base_text)
            result = Location.join(base, join_text)

            self.assertEqual(result._protocol, protocol, base_text)
            self.assertEqual(result._path, abspath, base_text)
            self.assertEqual(result._payloads, payloads, base_text)
예제 #33
0
        def create_bookmarks_menu():
            bookmarks = self.controller.app.bookmarks

            entries = bookmarks.get_entries()

            self.bookmarks_menu.clear()

            if self.controller.location is None:
                action = self.bookmarks_menu.addAction(QIcon.fromTheme("user-bookmarks"), "Can't bookmark file lists")
                action.setEnabled(False)
            elif self.controller.location in entries:
                self.bookmarks_menu.addAction(
                    QIcon.fromTheme("edit-delete"), "Remove This Location's Bookmark",
                    lambda loc=self.controller.location:
                    bookmarks.remove(loc))
            else:
                self.bookmarks_menu.addAction(
                    QIcon.fromTheme("bookmark-new"), "Bookmark This Location",
                    lambda loc=self.controller.location:
                    bookmarks.append(loc))
            self.bookmarks_menu.addSeparator()

            self.bookmarks_menu.addDoubleAction(
                QIcon.fromTheme("folder"), "View Bookmarks",
                lambda: self.controller.set_location(Location("bookmarks", "/", [])),
                lambda: self.controller.new_controller().set_location(Location("bookmarks", "/", [])))

            self.bookmarks_menu.addSeparator()

            icon = QIcon.fromTheme("folder")
            for entry in entries:
                action = self.bookmarks_menu.addDoubleAction(
                    icon, entry.as_url(),
                    lambda entry=entry: self.controller.set_location(entry),
                    lambda entry=entry: self.controller.app.show_location(entry))

                if not entry.exists():
                    action.setEnabled(False)
예제 #34
0
    def test_from_human(self):
        humans = [
            ("/", "file:///"),
            ("/tmp/file.rar://rar", "file:///tmp/file.rar%3A//rar"),
            ("/tmp/file", "file:///tmp/file"),
            ("file:///tmp/file2", "file:///tmp/file2"),
            ("file:///tmp/file.rar//rar:foo.bar",
             "file:///tmp/file.rar//rar:foo.bar"),
            ("file:///tmp/file spacetest", "file:///tmp/file%20spacetest"),
        ]

        for human, expected in humans:
            location = Location.from_human(human)
            self.assertEqual(location.as_url(), expected)
예제 #35
0
 def test_ancestry(self):
     location = Location.from_url(
         "file:///home/juser/test.rar//rar:bar/foo.zip//zip:bar.png")
     result = location.ancestry()
     expected = [
         Location.from_url('file:///'),
         Location.from_url('file:///home'),
         Location.from_url('file:///home/juser'),
         Location.from_url('file:///home/juser/test.rar//rar'),
         Location.from_url('file:///home/juser/test.rar//rar:bar'),
         Location.from_url(
             'file:///home/juser/test.rar//rar:bar/foo.zip//zip'),
         Location.from_url(
             'file:///home/juser/test.rar//rar:bar/foo.zip//zip:bar.png')
     ]
     self.assertEqual(result, expected)
예제 #36
0
 def _show_rename_error_os_error(self, location: Location, err: OSError,
                                 tb: str, parent: Optional[QWidget]):
     msg = QMessageBox(parent)
     msg.setIcon(QMessageBox.Critical)
     msg.setWindowTitle("Rename Error")
     msg.setTextFormat(Qt.RichText)
     msg.setText("<b>Failed to rename \"<tt>{}</tt>\".</b>".format(
         html.escape(location.as_human())))
     msg.setInformativeText(
         "A failure occured while trying to rename the file.\n\n{}\n\n{}  →\n{}\n"
         .format(err.strerror, err.filename, err.filename2))
     msg.setDetailedText(tb)
     msg.setStandardButtons(QMessageBox.Ok)
     msg.exec()
예제 #37
0
    def opendir(self, location: Location) -> Union['DirectoryWatcher', 'ArchiveDirectoryWatcher']:
        """Create a watcher object for the given directory. The caller is
        responsible for .close()`ing it."""

        if not location.has_payload():
            directory_watcher = DirectoryWatcher(self, location)
            return directory_watcher
        else:
            directory_watcher = DirectoryWatcher(self, location)
            extractor = self._archive_manager.extract(location, directory_watcher, self)
            if extractor is None:
                return directory_watcher
            else:
                return ArchiveDirectoryWatcher(directory_watcher, extractor)
예제 #38
0
    def test_basename(self):
        testcases = [
            ("file:///home/juser/test.rar//rar:bar/foo.zip//zip:bar.png",
             "bar.png"),
            ("file:///home/juser/test.rar//rar:bar/foo.zip//zip",
             "foo.zip//zip"),
            ("file:///home/juser/foo.zip//zip:test.rar", "test.rar"),
            ("file:///home/juser/test.rar", "test.rar"),
        ]

        for url, expected in testcases:
            location = Location.from_url(url)
            result = location.basename()
            self.assertEqual(result, expected)
예제 #39
0
    def test_location_init(self):
        ok_texts = [
            ("file:///home/juser/test.rar//rar:file_inside.rar",
             ("file", "/home/juser/test.rar", [Payload("rar", "file_inside.rar")])),

            ("file:///home/juser/test.rar",
             ("file", "/home/juser/test.rar", [])),

            ("file:///home/juser/test.rar//rar",
             ("file", "/home/juser/test.rar", [Payload("rar", "")])),

            ("file:///tmp/",
             ("file", "/tmp", [])),

            ("file:///home/juser/test.rar//rar:file_inside.rar//rar:file.txt",
             ("file", "/home/juser/test.rar", [Payload("rar", "file_inside.rar"), Payload("rar", "file.txt")])),

            ("file:///test.rar//rar:one//rar:two//rar:three",
             ("file", "/test.rar", [Payload("rar", "one"), Payload("rar", "two"), Payload("rar", "three")]))
        ]

        for text, (protocol, abspath, payloads) in ok_texts:
            location = Location.from_url(text)
            self.assertEqual(location._protocol, protocol)
            self.assertEqual(location._path, abspath)
            self.assertEqual(location._payloads, payloads)

        fail_texts = [
            "/home/juser/test.rar",
            "file://test.rar",
            "file:///test.rar//rar:oeu//"
            "file:///test.rar///rar:foo"
        ]

        for text in fail_texts:
            with self.assertRaises(Exception) as context:
                Location.from_string(text)
예제 #40
0
    def test_location_init(self):
        ok_texts = [
            ("file:///home/juser/test.rar//rar:file_inside.rar",
             ("file", "/home/juser/test.rar",
              [Payload("rar", "file_inside.rar")])),
            ("file:///home/juser/test.rar", ("file", "/home/juser/test.rar",
                                             [])),
            ("file:///home/juser/test.rar//rar",
             ("file", "/home/juser/test.rar", [Payload("rar", "")])),
            ("file:///tmp/", ("file", "/tmp", [])),
            ("file:///home/juser/test.rar//rar:file_inside.rar//rar:file.txt",
             ("file", "/home/juser/test.rar",
              [Payload("rar", "file_inside.rar"),
               Payload("rar", "file.txt")])),
            ("file:///test.rar//rar:one//rar:two//rar:three",
             ("file", "/test.rar", [
                 Payload("rar", "one"),
                 Payload("rar", "two"),
                 Payload("rar", "three")
             ]))
        ]

        for text, (protocol, abspath, payloads) in ok_texts:
            location = Location.from_url(text)
            self.assertEqual(location._protocol, protocol)
            self.assertEqual(location._path, abspath)
            self.assertEqual(location._payloads, payloads)

        fail_texts = [
            "/home/juser/test.rar", "file://test.rar",
            "file:///test.rar//rar:oeu//"
            "file:///test.rar///rar:foo"
        ]

        for text in fail_texts:
            with self.assertRaises(Exception) as context:
                Location.from_string(text)
예제 #41
0
 def _on_activated(self, fd: int) -> None:
     while True:
         try:
             filename: str = next(self.readliner)
         except StopIteration:
             self.socket_notifier.setEnabled(False)
             self.socket_notifier = None
             self.sig_end_of_stream.emit()
             return
         else:
             if filename is not None:
                 location = Location.from_path(filename)
                 self.sig_file_added.emit(self.vfs.get_fileinfo(location))
             else:
                 return
예제 #42
0
    def on_text_edited(self, text) -> None:
        p = self.palette()

        try:
            location = Location.from_human(text)
            if location.exists():
                p.setColor(QPalette.Text, Qt.black)
            else:
                p.setColor(QPalette.Text, Qt.red)
        except Exception:
            p.setColor(QPalette.Text, Qt.red)

        self.setPalette(p)

        self._controller._path_completion.request_completions(text)
예제 #43
0
 def _show_rename_error_os_error(self, location: Location, err: OSError, tb: str,
                                 parent: Optional[QWidget]):
     msg = QMessageBox(parent)
     msg.setIcon(QMessageBox.Critical)
     msg.setWindowTitle("Rename Error")
     msg.setTextFormat(Qt.RichText)
     msg.setText(
         "<b>Failed to rename \"<tt>{}</tt>\".</b>"
         .format(html.escape(location.as_human())))
     msg.setInformativeText(
         "A failure occured while trying to rename the file.\n\n{}\n\n{}  →\n{}\n"
         .format(err.strerror, err.filename, err.filename2))
     msg.setDetailedText(tb)
     msg.setStandardButtons(QMessageBox.Ok)
     msg.exec()
예제 #44
0
    def test_origin(self):
        testcases = [
            (Location.from_url("file:///home/juser/test.rar//rar:bar/foo1.zip//zip:bar.png"),
             Location.from_url("file:///home/juser/test.rar//rar:bar/foo1.zip")),

            (Location.from_url("file:///home/juser/test.rar//rar:bar/foo2.zip//zip"),
             Location.from_url("file:///home/juser/test.rar//rar:bar/foo2.zip")),

            (Location.from_url("file:///home/juser/test.rar//rar:bar/foo3.zip//zip:"),
             Location.from_url("file:///home/juser/test.rar//rar:bar/foo3.zip")),

            (Location.from_url("file:///home/juser/foo4.zip//zip:test.rar"),
             Location.from_url("file:///home/juser/foo4.zip")),

            (Location.from_url("file:///home/juser/test5.rar"),
             None)
        ]

        for location, expected in testcases:
            result = location.origin()
            self.assertEqual(result, expected)
예제 #45
0
    def get_entries(self) -> List['Location']:
        try:
            with open(self.config_filename, "r") as fin:
                lines = fin.read().splitlines()

                result = []
                for line in lines:
                    try:
                        result.append(Location.from_url(line))
                    except Exception as err:
                        logger.warning("ignoring bookmark entry: %s: %s", line, err)

                return sorted(result)

        except FileNotFoundError:
            return []
예제 #46
0
    def test_origin(self):
        testcases = [
            (Location.from_url(
                "file:///home/juser/test.rar//rar:bar/foo1.zip//zip:bar.png"),
             Location.from_url("file:///home/juser/test.rar//rar:bar/foo1.zip")
             ),
            (Location.from_url(
                "file:///home/juser/test.rar//rar:bar/foo2.zip//zip"),
             Location.from_url("file:///home/juser/test.rar//rar:bar/foo2.zip")
             ),
            (Location.from_url(
                "file:///home/juser/test.rar//rar:bar/foo3.zip//zip:"),
             Location.from_url("file:///home/juser/test.rar//rar:bar/foo3.zip")
             ),
            (Location.from_url("file:///home/juser/foo4.zip//zip:test.rar"),
             Location.from_url("file:///home/juser/foo4.zip")),
            (Location.from_url("file:///home/juser/test5.rar"), None)
        ]

        for location, expected in testcases:
            result = location.origin()
            self.assertEqual(result, expected)
예제 #47
0
    def get_entries(self, limit: Optional[int] = None) -> List[Location]:
        c = self._db.cursor()
        c.execute("SELECT group_id, date, location "
                  "FROM history "
                  "ORDER BY date DESC" +
                  (" LIMIT {}".format(limit) if limit is not None else ""))

        results: List[Location] = []
        for group_id, date, location_url in c.fetchall():
            try:
                loc = Location.from_url(location_url)
            except Exception:
                logging.exception("Location parsing failed")
            else:
                results.append(loc)

        return results
예제 #48
0
    def get_entries(self) -> List['Location']:
        try:
            with open(self.config_filename, "r") as fin:
                lines = fin.read().splitlines()

                result = []
                for line in lines:
                    try:
                        result.append(Location.from_url(line))
                    except Exception as err:
                        logger.warning("ignoring bookmark entry: %s: %s", line,
                                       err)

                return sorted(result)

        except FileNotFoundError:
            return []
예제 #49
0
파일: history.py 프로젝트: Grumbel/dirtool
    def get_entries(self, limit: Optional[int] = None) -> List[Location]:
        c = self._db.cursor()
        c.execute("SELECT group_id, date, location "
                  "FROM history "
                  "ORDER BY date DESC" +
                  (" LIMIT {}".format(limit) if limit is not None else ""))

        results: List[Location] = []
        for group_id, date, location_url in c.fetchall():
            try:
                loc = Location.from_url(location_url)
            except Exception:
                logging.exception("Location parsing failed")
            else:
                results.append(loc)

        return results
예제 #50
0
    def test_basename(self):
        testcases = [
            ("file:///home/juser/test.rar//rar:bar/foo.zip//zip:bar.png",
             "bar.png"),

            ("file:///home/juser/test.rar//rar:bar/foo.zip//zip",
             "foo.zip//zip"),

            ("file:///home/juser/foo.zip//zip:test.rar",
             "test.rar"),

            ("file:///home/juser/test.rar",
             "test.rar"),
        ]

        for url, expected in testcases:
            location = Location.from_url(url)
            result = location.basename()
            self.assertEqual(result, expected)
예제 #51
0
    def opendir(self, location: Location) -> Any:
        if location.protocol() == "history":
            return HistoryProvider(self._app)

        elif location.protocol() == "bookmarks":
            return BookmarksProvider(self._app)

        elif location.protocol() == "file":
            return self._stdio_fs.opendir(location)

        elif location.protocol() == "stream":
            return FileListStream.from_location(self._app, "\n", location)

        elif location.protocol() == "stream0":
            return FileListStream.from_location(self._app, "\0", location)

        elif location.protocol() == "search":
            abspath, query = location.search_query()
            return SearchStream(abspath, query)

        else:
            raise Exception("unknown protocol: {}", location.protocol())
예제 #52
0
    def test_pure(self):
        testcases = [
            ("file:///home/juser/test.rar//rar:bar/foo.zip//zip:bar.png",
             "file:///home/juser/test.rar//rar:bar/foo.zip//zip:bar.png"),

            ("file:///home/juser/test.rar//rar:bar/foo2.zip//zip",
             "file:///home/juser/test.rar//rar:bar/foo2.zip"),

            ("file:///home/juser/test.rar//rar:bar/foo3.zip//zip:",
             "file:///home/juser/test.rar//rar:bar/foo3.zip"),

            ("file:///home/juser/foo.zip//zip:test.rar",
             "file:///home/juser/foo.zip//zip:test.rar"),

            ("file:///home/juser/test.rar",
             "file:///home/juser/test.rar")
        ]

        for url, expected in testcases:
            location = Location.from_url(url)
            result = location.pure()
            self.assertEqual(result.as_url(), expected)
예제 #53
0
    def test_from_human(self):
        humans = [
            ("/",
             "file:///"),

            ("/tmp/file.rar://rar",
             "file:///tmp/file.rar%3A//rar"),

            ("/tmp/file",
             "file:///tmp/file"),

            ("file:///tmp/file2",
             "file:///tmp/file2"),

            ("file:///tmp/file.rar//rar:foo.bar",
             "file:///tmp/file.rar//rar:foo.bar"),

            ("file:///tmp/file spacetest",
             "file:///tmp/file%20spacetest"),
        ]

        for human, expected in humans:
            location = Location.from_human(human)
            self.assertEqual(location.as_url(), expected)
예제 #54
0
 def set_location(self, location: Location):
     self.location_lineedit.set_location(location)
     self.location_buttonbar.set_location(location)
     self.setWindowTitle("{} - dt-fileview".format(location.as_human()))
예제 #55
0
 def request(filename: str) -> None:
     nonlocal num_requests
     metadata_collector.request_metadata(Location.from_path(filename))
     num_requests += 1
예제 #56
0
 def _on_button_context_menu(self, button: LocationButton, location: Location, pos) -> None:
     fileinfo = self._controller.app.vfs.get_fileinfo(location.pure())
     menu = ItemContextMenu(self._controller, [fileinfo])
     menu.exec(button.mapToGlobal(pos))