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)
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)
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)
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
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()
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)
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
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)
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()
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)
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
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
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)
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()
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)
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)
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()
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
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()
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()
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
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()
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)
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)
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()
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())
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)
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)
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)
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)
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()
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)
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)
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)
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)
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
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)
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()
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)
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 []
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)
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
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())
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)
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()))
def request(filename: str) -> None: nonlocal num_requests metadata_collector.request_metadata(Location.from_path(filename)) num_requests += 1
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))