From d6a1181f3227a4d6005c11b3348e76217f85232e Mon Sep 17 00:00:00 2001 From: Roberto Ciano Date: Mon, 10 Apr 2017 19:26:04 +0200 Subject: [PATCH 1/7] set file's attribute to true instead of permanently removing it --- gdrivefs/gdtool/drive.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/gdrivefs/gdtool/drive.py b/gdrivefs/gdtool/drive.py index e8560a8..9ecfb94 100644 --- a/gdrivefs/gdtool/drive.py +++ b/gdrivefs/gdtool/drive.py @@ -770,10 +770,15 @@ def remove_entry(self, normalized_entry): client = self.__auth.get_client() - args = { 'fileId': normalized_entry.id } + args = { + 'fileId': normalized_entry.id, + 'body': { + 'trashed': True + } + } try: - result = client.files().delete(**args).execute() + result = client.files().update(**args).execute() except Exception as e: if e.__class__.__name__ == 'HttpError' and \ str(e).find('File not found') != -1: From 68e1b3af0e15fc07a6b447dfaebc238ab423d70d Mon Sep 17 00:00:00 2001 From: Roberto Ciano Date: Tue, 11 Apr 2017 18:38:01 +0200 Subject: [PATCH 2/7] use APIv2 syntax for trashing a file --- gdrivefs/gdtool/drive.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/gdrivefs/gdtool/drive.py b/gdrivefs/gdtool/drive.py index 9ecfb94..3025251 100644 --- a/gdrivefs/gdtool/drive.py +++ b/gdrivefs/gdtool/drive.py @@ -771,14 +771,11 @@ def remove_entry(self, normalized_entry): client = self.__auth.get_client() args = { - 'fileId': normalized_entry.id, - 'body': { - 'trashed': True - } + 'fileId': normalized_entry.id } try: - result = client.files().update(**args).execute() + result = client.files().trash(**args).execute() except Exception as e: if e.__class__.__name__ == 'HttpError' and \ str(e).find('File not found') != -1: From 1d3fb58fa22ce9af4297d2052e0d557402c47c94 Mon Sep 17 00:00:00 2001 From: Roberto Ciano Date: Tue, 11 Apr 2017 22:20:26 +0200 Subject: [PATCH 3/7] introduce delete_to_trash mount variable to switch between file trashing and file deletion --- gdrivefs/conf.py | 5 +++++ gdrivefs/gdtool/drive.py | 11 +++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/gdrivefs/conf.py b/gdrivefs/conf.py index 5310a3d..33071d2 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 is "delete_to_trash": + value = bool(int(value)) setattr(Conf, key, value) diff --git a/gdrivefs/gdtool/drive.py b/gdrivefs/gdtool/drive.py index 3025251..bb25b89 100644 --- a/gdrivefs/gdtool/drive.py +++ b/gdrivefs/gdtool/drive.py @@ -769,13 +769,20 @@ def remove_entry(self, normalized_entry): _logger.info("Removing entry with ID [%s].", normalized_entry.id) client = self.__auth.get_client() - + args = { 'fileId': normalized_entry.id } + + delete_to_trash = gdrivefs.conf.Conf.get('delete_to_trash') try: - result = client.files().trash(**args).execute() + if delete_to_trash: + _logger.debug("Moving file to trash") + result = client.files().trash(**args).execute() + else: + _logger.debug("Deleting file permanently") + result = client.files().delete(**args).execute() except Exception as e: if e.__class__.__name__ == 'HttpError' and \ str(e).find('File not found') != -1: From ed2174d9cf0b2f62b176d6c7cb897afdf01f5ea1 Mon Sep 17 00:00:00 2001 From: Roberto Ciano Date: Tue, 11 Apr 2017 22:32:51 +0200 Subject: [PATCH 4/7] fix string comparison by using == instead of is --- gdrivefs/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gdrivefs/conf.py b/gdrivefs/conf.py index 33071d2..3f63c72 100644 --- a/gdrivefs/conf.py +++ b/gdrivefs/conf.py @@ -57,7 +57,7 @@ def get(key): def set(key, value): if key not in Conf.__dict__: raise KeyError(key) - elif key is "delete_to_trash": + elif key == "delete_to_trash": value = bool(int(value)) setattr(Conf, key, value) From 28b9697ee1edb9f5c3c1c400d15b9a8b666e2cd5 Mon Sep 17 00:00:00 2001 From: Roberto Ciano Date: Tue, 11 Apr 2017 22:55:48 +0200 Subject: [PATCH 5/7] remove TODO comment --- gdrivefs/gdfs/gdfuse.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/gdrivefs/gdfs/gdfuse.py b/gdrivefs/gdfs/gdfuse.py index 81c9add..a174e42 100644 --- a/gdrivefs/gdfs/gdfuse.py +++ b/gdrivefs/gdfs/gdfuse.py @@ -667,8 +667,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: From a07613a977c91532ca728e9c00ab02be2d6a0344 Mon Sep 17 00:00:00 2001 From: Roberto Ciano Date: Tue, 11 Apr 2017 23:32:39 +0200 Subject: [PATCH 6/7] create delegate method that either calls remove_entry or trash_entry based on the delete_to_trash config variable --- gdrivefs/gdfs/gdfuse.py | 4 ++-- gdrivefs/gdtool/drive.py | 42 ++++++++++++++++++++++++---------------- 2 files changed, 27 insertions(+), 19 deletions(-) diff --git a/gdrivefs/gdfs/gdfuse.py b/gdrivefs/gdfs/gdfuse.py index a174e42..66f228b 100644 --- a/gdrivefs/gdfs/gdfuse.py +++ b/gdrivefs/gdfs/gdfuse.py @@ -508,7 +508,7 @@ def rmdir(self, filepath): raise FuseOSError(ENOTEMPTY) try: - gd.remove_entry(normalized_entry) + gd.remove_or_trash_entry(normalized_entry) except (NameError): raise FuseOSError(ENOENT) except: @@ -704,7 +704,7 @@ def unlink(self, file_path): gd = get_gdrive() try: - gd.remove_entry(normalized_entry) + gd.remove_or_trash_entry(normalized_entry) except NameError: raise FuseOSError(ENOENT) except: diff --git a/gdrivefs/gdtool/drive.py b/gdrivefs/gdtool/drive.py index bb25b89..4697a3c 100644 --- a/gdrivefs/gdtool/drive.py +++ b/gdrivefs/gdtool/drive.py @@ -763,26 +763,16 @@ def rename(self, normalized_entry, new_filename): return self.update_entry(normalized_entry, filename=filename_stripped, is_hidden=is_hidden) - @_marshall - def remove_entry(self, normalized_entry): - - _logger.info("Removing entry with ID [%s].", normalized_entry.id) - - client = self.__auth.get_client() - - args = { - 'fileId': normalized_entry.id - } - - delete_to_trash = gdrivefs.conf.Conf.get('delete_to_trash') + def remove_or_trash_entry(self, normalized_entry): + """Delegates to either remove_entry or trash_entry based on the + delete_to_trash configuration variable + """ try: - if delete_to_trash: - _logger.debug("Moving file to trash") - result = client.files().trash(**args).execute() + if gdrivefs.conf.Conf.get('delete_to_trash'): + self.trash_entry(normalized_entry) else: - _logger.debug("Deleting file permanently") - result = client.files().delete(**args).execute() + self.remove_entry(normalized_entry) except Exception as e: if e.__class__.__name__ == 'HttpError' and \ str(e).find('File not found') != -1: @@ -792,6 +782,24 @@ def remove_entry(self, normalized_entry): normalized_entry.id) raise + @_marshall + 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 } + + 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) + + client = self.__auth.get_client() + args = { 'fileId': normalized_entry.id } + + client.files().delete(**args).execute() _logger.info("Entry deleted successfully.") _THREAD_STORAGE = None From 2b6fc6680edf5c8a9e85cbb8389eb6659418e18e Mon Sep 17 00:00:00 2001 From: Roberto Ciano Date: Sat, 22 Apr 2017 22:19:02 +0200 Subject: [PATCH 7/7] move delegation method into own module gdutility and rename it to smart_delete --- gdrivefs/gdfs/gdfuse.py | 6 ++++-- gdrivefs/gdtool/drive.py | 19 ------------------- gdrivefs/gdtool/gdutility.py | 20 ++++++++++++++++++++ 3 files changed, 24 insertions(+), 21 deletions(-) create mode 100644 gdrivefs/gdtool/gdutility.py diff --git a/gdrivefs/gdfs/gdfuse.py b/gdrivefs/gdfs/gdfuse.py index 66f228b..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_or_trash_entry(normalized_entry) + smart_delete(normalized_entry) except (NameError): raise FuseOSError(ENOENT) except: @@ -704,7 +706,7 @@ def unlink(self, file_path): gd = get_gdrive() try: - gd.remove_or_trash_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 4697a3c..fc7183b 100644 --- a/gdrivefs/gdtool/drive.py +++ b/gdrivefs/gdtool/drive.py @@ -763,25 +763,6 @@ def rename(self, normalized_entry, new_filename): return self.update_entry(normalized_entry, filename=filename_stripped, is_hidden=is_hidden) - def remove_or_trash_entry(self, normalized_entry): - """Delegates to either remove_entry or trash_entry based on the - delete_to_trash configuration variable - """ - - try: - if gdrivefs.conf.Conf.get('delete_to_trash'): - self.trash_entry(normalized_entry) - else: - self.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 - @_marshall def trash_entry(self, normalized_entry): _logger.info("Trashing entry with ID [%s]", normalized_entry.id) 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