From b24851ca05e719b6093512db46cdf0abb1665e78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gina=20H=C3=A4u=C3=9Fge?= Date: Mon, 3 Apr 2017 11:44:20 +0200 Subject: [PATCH] New events: FileAdded, FileRemoved, FolderAdded, FolderRemoved Closes #1092 --- docs/events/index.rst | 69 +++++++++++++++++++++--- src/octoprint/events.py | 5 ++ src/octoprint/filemanager/__init__.py | 76 +++++++++++++++++++++++---- src/octoprint/filemanager/storage.py | 11 ++-- src/octoprint/server/__init__.py | 2 + 5 files changed, 143 insertions(+), 20 deletions(-) diff --git a/docs/events/index.rst b/docs/events/index.rst index 802ed385..b471193f 100644 --- a/docs/events/index.rst +++ b/docs/events/index.rst @@ -152,7 +152,7 @@ File handling ------------- Upload - A file has been uploaded. + A file has been uploaded through the web interface. Payload: * ``name``: the file's name @@ -165,19 +165,74 @@ Upload Still available for reasons of backwards compatibility. Will be removed with 1.4.0. +FileAdded + A file has been added to a storage. + + Payload: + * ``storage``: the storage's identifier + * ``path``: the file's path within its storage location + * ``name``: the file's name + * ``type``: the file's type, a list of the path within the type hierarchy, e.g. ``["machinecode", "gcode"]`` or + ``["model", "stl"]`` + + .. note:: + + A copied file triggers this for its new path. A moved file first triggers ``FileRemoved`` for its original + path and then ``FileAdded`` for the new one. + +FileRemoved + A file has been removed from a storage. + + Payload: + * ``storage``: the storage's identifier + * ``path``: the file's path within its storage location + * ``name``: the file's name + * ``type``: the file's type, a list of the path within the type hierarchy, e.g. ``["machinecode", "gcode"]`` or + ``["model", "stl"]`` + + .. note:: + + A moved file first triggers ``FileRemoved`` for its original path and then ``FileAdded`` for the new one. + +FolderAdded + A folder has been added to a storage. + + Payload: + * ``storage``: the storage's identifier + * ``path``: the folders's path within its storage location + * ``name``: the folders's name + + .. note:: + + A copied folder triggers this for its new path. A moved folder first triggers ``FolderRemoved`` for its original + path and then ``FolderAdded`` for the new one. + +FolderRemoved + A folder has been removed from a storage. + + Payload: + * ``storage``: the storage's identifier + * ``path``: the folders's path within its storage location + * ``name``: the folders's name + + .. note:: + + A moved folder first triggers ``FolderRemoved`` for its original path and then ``FolderAdded`` for the new one. + UpdatedFiles A file list was modified. Payload: - * ``type``: the type of file list that was modified. Currently only ``printables`` and ``gcode`` (DEPRECATED) are supported here. + * ``type``: the type of file list that was modified. Only ``printables`` is supported here. See the deprecation + note below. - .. note:: + .. deprecated:: 1.2.0 + + The ``gcode`` modification type has been superceeded by ``printables``. It is currently still available for + reasons of backwards compatibility and will also be sent on modification of ``printables``. It will however + be removed with 1.4.0. - The type ``gcode`` has been renamed to ``printables`` with the introduction of a new file management layer that - supports STL files as first class citizens as well. For reasons of backwards compatibility the ``UpdatedFiles`` - event for printable files will be fired twice, once with ``type`` set to ``gcode``, once set to ``printables``. - Support for the ``gcode`` type will be removed in the next release after version 1.2.0. MetadataAnalysisStarted The metadata analysis of a file has started. diff --git a/src/octoprint/events.py b/src/octoprint/events.py index 6426011a..367fd985 100644 --- a/src/octoprint/events.py +++ b/src/octoprint/events.py @@ -53,6 +53,11 @@ class Events(object): METADATA_ANALYSIS_FINISHED = "MetadataAnalysisFinished" METADATA_STATISTICS_UPDATED = "MetadataStatisticsUpdated" + FILE_ADDED = "FileAdded", + FILE_REMOVED = "FileRemoved", + FOLDER_ADDED = "FolderAdded", + FOLDER_REMOVED = "FolderRemoved", + # SD Upload TRANSFER_STARTED = "TransferStarted" TRANSFER_DONE = "TransferDone" diff --git a/src/octoprint/filemanager/__init__.py b/src/octoprint/filemanager/__init__.py index de06893b..35c9075e 100644 --- a/src/octoprint/filemanager/__init__.py +++ b/src/octoprint/filemanager/__init__.py @@ -409,30 +409,47 @@ class FileManager(object): queue_entry = self._analysis_queue_entry(destination, path) self._analysis_queue.dequeue(queue_entry) - file_path = self._storage(destination).add_file(path, file_object, links=links, printer_profile=printer_profile, allow_overwrite=allow_overwrite) + path_in_storage = self._storage(destination).add_file(path, file_object, links=links, printer_profile=printer_profile, allow_overwrite=allow_overwrite) if analysis is None: - queue_entry = self._analysis_queue_entry(destination, file_path, printer_profile=printer_profile) + queue_entry = self._analysis_queue_entry(destination, path_in_storage, printer_profile=printer_profile) if queue_entry: self._analysis_queue.enqueue(queue_entry, high_priority=True) else: self._add_analysis_result(destination, path, analysis) + _, name = self._storage(destination).split_path(path_in_storage) + eventManager().fire(Events.FILE_ADDED, dict(storage=destination, + path=path_in_storage, + name=name, + type=get_file_type(name))) eventManager().fire(Events.UPDATED_FILES, dict(type="printables")) - return file_path + return path_in_storage def remove_file(self, destination, path): queue_entry = self._analysis_queue_entry(destination, path) self._analysis_queue.dequeue(queue_entry) self._storage(destination).remove_file(path) + + _, name = self._storage(destination).split_path(path) + eventManager().fire(Events.FILE_REMOVED, dict(storage=destination, + path=path, + name=name, + type=get_file_type(name))) eventManager().fire(Events.UPDATED_FILES, dict(type="printables")) def copy_file(self, destination, source, dst): - path = self._storage(destination).copy_file(source, dst) - if not self.has_analysis(destination, path): - queue_entry = self._analysis_queue_entry(destination, path) + path_in_storage = self._storage(destination).copy_file(source, dst) + if not self.has_analysis(destination, path_in_storage): + queue_entry = self._analysis_queue_entry(destination, path_in_storage) if queue_entry: self._analysis_queue.enqueue(queue_entry) + + _, name = self._storage(destination).split_path(path_in_storage) + eventManager().fire(Events.FILE_ADDED, dict(storage=destination, + path=path_in_storage, + name=name, + type=get_file_type(name))) eventManager().fire(Events.UPDATED_FILES, dict(type="printables")) def move_file(self, destination, source, dst): @@ -443,23 +460,52 @@ class FileManager(object): queue_entry = self._analysis_queue_entry(destination, path) if queue_entry: self._analysis_queue.enqueue(queue_entry) + + source_path_in_storage = self._storage(destination).path_in_storage(source) + _, source_name = self._storage(destination).split_path(source_path_in_storage) + dst_path_in_storage = self._storage(destination).path_in_storage(dst) + _, dst_name = self._storage(destination).split_path(dst_path_in_storage) + + eventManager().fire(Events.FILE_REMOVED, dict(storage=destination, + path=source_path_in_storage, + name=source_name, + type=get_file_type(source_name))) + eventManager().fire(Events.FILE_ADDED, dict(storage=destination, + path=dst_path_in_storage, + name=dst_name, + type=get_file_type(dst_name))) eventManager().fire(Events.UPDATED_FILES, dict(type="printables")) def add_folder(self, destination, path, ignore_existing=True): - folder_path = self._storage(destination).add_folder(path, ignore_existing=ignore_existing) + path_in_storage = self._storage(destination).add_folder(path, ignore_existing=ignore_existing) + + _, name = self._storage(destination).split_path(path_in_storage) + eventManager().fire(Events.FOLDER_ADDED, dict(storage=destination, + path=path_in_storage, + name=name)) eventManager().fire(Events.UPDATED_FILES, dict(type="printables")) - return folder_path + return path_in_storage def remove_folder(self, destination, path, recursive=True): self._analysis_queue.dequeue_folder(destination, path) self._analysis_queue.pause() self._storage(destination).remove_folder(path, recursive=recursive) self._analysis_queue.resume() + + _, name = self._storage(destination).split_path(path) + eventManager().fire(Events.FOLDER_REMOVED, dict(storage=destination, + path=path, + name=name)) eventManager().fire(Events.UPDATED_FILES, dict(type="printables")) def copy_folder(self, destination, source, dst): - self._storage(destination).copy_folder(source, dst) + path_in_storage = self._storage(destination).copy_folder(source, dst) self._determine_analysis_backlog(destination, self._storage(destination), root=dst) + + _, name = self._storage(destination).split_path(path_in_storage) + eventManager().fire(Events.FOLDER_ADDED, dict(storage=destination, + path=path_in_storage, + name=name)) eventManager().fire(Events.UPDATED_FILES, dict(type="printables")) def move_folder(self, destination, source, dst): @@ -468,6 +514,18 @@ class FileManager(object): self._storage(destination).move_folder(source, dst) self._determine_analysis_backlog(destination, self._storage(destination), root=dst) self._analysis_queue.resume() + + source_path_in_storage = self._storage(destination).path_in_storage(source) + _, source_name = self._storage(destination).split_path(source_path_in_storage) + dst_path_in_storage = self._storage(destination).path_in_storage(destination) + _, dst_name = self._storage(destination).split_path(dst_path_in_storage) + + eventManager().fire(Events.FOLDER_REMOVED, dict(storage=destination, + path=source_path_in_storage, + name=source_name)) + eventManager().fire(Events.FOLDER_ADDED, dict(storage=destination, + path=dst_path_in_storage, + name=dst_name)) eventManager().fire(Events.UPDATED_FILES, dict(type="printables")) def has_analysis(self, destination, path): diff --git a/src/octoprint/filemanager/storage.py b/src/octoprint/filemanager/storage.py index 9a74e3dc..aa8755db 100644 --- a/src/octoprint/filemanager/storage.py +++ b/src/octoprint/filemanager/storage.py @@ -29,7 +29,6 @@ class StorageInterface(object): Interface of storage adapters for OctoPrint. """ - @property def analysis_backlog(self): """ @@ -155,7 +154,9 @@ class StorageInterface(object): def add_folder(self, path, ignore_existing=True): """ - Adds a folder as ``path``. The ``path`` will be sanitized. + Adds a folder as ``path`` + + The ``path`` will be sanitized. :param string path: the path of the new folder :param bool ignore_existing: if set to True, no error will be raised if the folder to be added already exists @@ -165,7 +166,7 @@ class StorageInterface(object): def remove_folder(self, path, recursive=True): """ - Removes the folder at ``path``. + Removes the folder at ``path`` :param string path: the path of the folder to remove :param bool recursive: if set to True, contained folders and files will also be removed, otherwise and error will @@ -212,7 +213,9 @@ class StorageInterface(object): def remove_file(self, path): """ - Removes the file at ``path``. Will also take care of deleting the corresponding entries + Removes the file at ``path`` + + Will also take care of deleting the corresponding entries in the metadata and deleting all links pointing to the file. :param string path: path of the file to remove diff --git a/src/octoprint/server/__init__.py b/src/octoprint/server/__init__.py index 92fb80fc..79ec3169 100644 --- a/src/octoprint/server/__init__.py +++ b/src/octoprint/server/__init__.py @@ -194,8 +194,10 @@ class Server(object): eventManager = events.eventManager() analysisQueue = octoprint.filemanager.analysis.AnalysisQueue() slicingManager = octoprint.slicing.SlicingManager(self._settings.getBaseFolder("slicingProfiles"), printerProfileManager) + storage_managers = dict() storage_managers[octoprint.filemanager.FileDestinations.LOCAL] = octoprint.filemanager.storage.LocalFileStorage(self._settings.getBaseFolder("uploads")) + fileManager = octoprint.filemanager.FileManager(analysisQueue, slicingManager, printerProfileManager, initial_storage_managers=storage_managers) appSessionManager = util.flask.AppSessionManager() pluginLifecycleManager = LifecycleManager(pluginManager)