diff --git a/gdrivefs/conf.py b/gdrivefs/conf.py index 5310a3d..3f63c72 100644 --- a/gdrivefs/conf.py +++ b/gdrivefs/conf.py @@ -42,6 +42,9 @@ class Conf(object): default_perm_file_editable = '666' default_perm_file_noneditable = '444' + # Move files to trash instead of deleting them permanently + delete_to_trash = False + # How many extra entries to retrieve when an entry is accessed that is not # currently cached. max_readahead_entries = 10 @@ -54,5 +57,7 @@ def get(key): def set(key, value): if key not in Conf.__dict__: raise KeyError(key) + elif key == "delete_to_trash": + value = bool(int(value)) setattr(Conf, key, value) diff --git a/gdrivefs/gdfs/gdfuse.py b/gdrivefs/gdfs/gdfuse.py index 81c9add..c7201a2 100644 --- a/gdrivefs/gdfs/gdfuse.py +++ b/gdrivefs/gdfs/gdfuse.py @@ -40,6 +40,8 @@ from gdrivefs.errors import GdNotFoundError from gdrivefs.time_support import get_flat_normal_fs_time_from_epoch +from gdrivefs.gdtool.gdutility import smart_delete + _logger = logging.getLogger(__name__) # TODO: make sure strip_extension and split_path are used when each are relevant @@ -508,7 +510,7 @@ def rmdir(self, filepath): raise FuseOSError(ENOTEMPTY) try: - gd.remove_entry(normalized_entry) + smart_delete(normalized_entry) except (NameError): raise FuseOSError(ENOENT) except: @@ -667,8 +669,7 @@ def truncate(self, filepath, length, fh=None): @dec_hint(['file_path']) def unlink(self, file_path): """Remove a file.""" -# TODO: Change to simply move to "trash". Have a FUSE option to elect this -# behavior. + path_relations = PathRelations.get_instance() try: @@ -705,7 +706,7 @@ def unlink(self, file_path): gd = get_gdrive() try: - gd.remove_entry(normalized_entry) + smart_delete(normalized_entry) except NameError: raise FuseOSError(ENOENT) except: diff --git a/gdrivefs/gdtool/drive.py b/gdrivefs/gdtool/drive.py index e8560a8..fc7183b 100644 --- a/gdrivefs/gdtool/drive.py +++ b/gdrivefs/gdtool/drive.py @@ -764,25 +764,23 @@ def rename(self, normalized_entry, new_filename): is_hidden=is_hidden) @_marshall - def remove_entry(self, normalized_entry): - - _logger.info("Removing entry with ID [%s].", normalized_entry.id) + def trash_entry(self, normalized_entry): + _logger.info("Trashing entry with ID [%s]", normalized_entry.id) client = self.__auth.get_client() - args = { 'fileId': normalized_entry.id } - try: - result = client.files().delete(**args).execute() - except Exception as e: - if e.__class__.__name__ == 'HttpError' and \ - str(e).find('File not found') != -1: - raise NameError(normalized_entry.id) + client.files().trash(**args).execute() + _logger.info("Entry trashed successfully.") + + @_marshall + def remove_entry(self, normalized_entry): + _logger.info("Removing entry with ID [%s].", normalized_entry.id) - _logger.exception("Could not send delete for entry with ID [%s].", - normalized_entry.id) - raise + client = self.__auth.get_client() + args = { 'fileId': normalized_entry.id } + client.files().delete(**args).execute() _logger.info("Entry deleted successfully.") _THREAD_STORAGE = None diff --git a/gdrivefs/gdtool/gdutility.py b/gdrivefs/gdtool/gdutility.py new file mode 100644 index 0000000..e28b99b --- /dev/null +++ b/gdrivefs/gdtool/gdutility.py @@ -0,0 +1,20 @@ +from drive import get_gdrive +import gdrivefs.config + +def smart_delete(normalized_entry): + """Deletes a given file permanently or moves it to the trash based on the config + """ + drive = get_gdrive() + try: + if gdrivefs.conf.Conf.get('delete_to_trash'): + drive.trash_entry(normalized_entry) + else: + drive.remove_entry(normalized_entry) + except Exception as e: + if e.__class__.__name__ == 'HttpError' and \ + str(e).find('File not found') != -1: + raise NameError(normalized_entry.id) + + _logger.exception("Could not send delete for entry with ID [%s].", + normalized_entry.id) + raise