Skip to content

Commit 0da9db6

Browse files
authored
Merge pull request #21 from smartondev/18-quick-sync
#18 quick sync mode
2 parents 918297a + 7ea941e commit 0da9db6

4 files changed

Lines changed: 55 additions & 29 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
- Enh #9: Dry mode
1111
- Enh: Cleaner log messages
1212
- Enh #12: OAUTH supports for free plans
13+
- Enh #18: Quick syncing gmail backup mode
1314

1415
## 0.4.0
1516

docs/cli-parameters.md

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,27 @@
44
|----------------------------------|----------|-----------------------------------------------------------------------------|
55
| `--log-level` | string | Set logging level: `finest`, `debug`, `info` (default), `error`, `critical` |
66
| `--batch-size` | integer | Concurrent threads count, default: 5 |
7-
| `--service-account-key-filepath` | filepath | JSON or P12 service account file path (REQUIRED) |
7+
| `--service-account-key-filepath` | filepath | JSON or P12 service account file path |
88
| `--service-account-email` | string | Service account email address, required only for P12 type |
9+
| `--credentials-filepath` | string | OAUTH credentials json |
910
| `--timzone` | string | Timezone |
1011
| `--workdir` | string | Storage directory path, default: `./data` |
12+
| `--dry` | | Dry mode (not modify on server, not modify in local storage) |
1113
| `<service>` | service | Service ID, eg. gmail |
1214

1315
## `service` types
1416

1517
Currently only `gmail` is supported.
1618

17-
### `gmail`
19+
### `gmail` service
20+
21+
`backup` parameters
22+
23+
| parameter | type | description |
24+
|---------------------|--------|----------------------------------------------------------------------------------------------------------------|
25+
| `--email` | string | email account for backup (REQUIRED) |
26+
| `--quick-sync-days` | int | Quick syncing mode. The value is number of retroactive days. (It does not delete messages from local storage.) |
27+
28+
`restore` parameters
1829

1930
...

gwb/gmail.py

Lines changed: 36 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import threading
1010
import time
1111
import collections
12-
from datetime import datetime
12+
from datetime import datetime, timedelta
1313

1414
from google.auth.transport.requests import Request
1515
from google.oauth2.credentials import Credentials
@@ -253,7 +253,7 @@ def __backup_messages(self, message, stored_messages: dict[str, dict[int, LinkIn
253253
return
254254
logging.exception(f'{message_id} {e}')
255255

256-
def __get_all_messages_from_server(self, email=None):
256+
def __get_all_messages_from_server(self, email: str | None = None, q: str | None = 'label:all'):
257257
if email is None:
258258
email = self.email
259259
service = self.__get_service(email)
@@ -267,7 +267,7 @@ def __get_all_messages_from_server(self, email=None):
267267
logging.debug(f'Loading {page}. from server...')
268268
# print('.', end='')
269269
data = service.users().messages() \
270-
.list(userId='me', pageToken=next_page_token, maxResults=1000, q='label:all').execute()
270+
.list(userId='me', pageToken=next_page_token, maxResults=1000, q=q).execute()
271271
logging.debug(f'{page} successfully loaded')
272272
# print(data)
273273
# exit(-1)
@@ -335,7 +335,7 @@ def __storage_put(self, link: LinkInterface, data: Data) -> bool:
335335
return True
336336
return self.storage.put(link, data)
337337

338-
def backup(self) -> bool:
338+
def backup(self, quick_sync_days: int | None = None) -> bool:
339339
logging.info(f'Starting backup for {self.email}')
340340
self.__error_count = 0
341341

@@ -350,6 +350,10 @@ def backup(self) -> bool:
350350
if not self.__backup_labels(labels_link):
351351
logging.error('Backup finished with storing labels failed')
352352
return False
353+
if quick_sync_days is not None and quick_sync_days < 1:
354+
quick_sync_days = None
355+
if quick_sync_days is not None:
356+
logging.info(f'Quick syncing, going back {quick_sync_days} days')
353357

354358
stored_messages: dict[str, dict[int, LinkInterface]] = stored_data_all.find(
355359
f=lambda l: l.id() not in Gmail.object_ids_special and (l.is_metadata() or l.is_object()),
@@ -367,7 +371,11 @@ def backup(self) -> bool:
367371
logging.log(global_properties.log_finest, f'{message_id} is usable from backup storage')
368372
logging.info(f'Stored messages: {len(stored_messages)}')
369373

370-
messages_from_server = self.__get_all_messages_from_server()
374+
q = 'label:all'
375+
if quick_sync_days is not None:
376+
date = datetime.now() - timedelta(days=quick_sync_days)
377+
q = f"label:all after:{date.strftime('%Y/%m/%d')}"
378+
messages_from_server = self.__get_all_messages_from_server(q=q)
371379
logging.info('Processing...')
372380
with concurrent.futures.ThreadPoolExecutor(max_workers=self.batch_size) as executor:
373381
for message_id in messages_from_server:
@@ -379,29 +387,31 @@ def backup(self) -> bool:
379387
logging.error('Backup failed with ' + str(self.__error_count) + ' errors')
380388
return False
381389

382-
logging.info('Mark as deletes...')
383-
for message_id in stored_messages:
384-
links = stored_messages[message_id]
385-
logging.debug(f'{message_id} mark as deleted in local storage...')
386-
meta_link = links.get(0)
387-
if meta_link is None:
388-
continue
389-
logging.debug(f'{message_id} - {meta_link}')
390-
if self.__storage_remove(meta_link):
391-
logging.debug(f'{message_id} metadata mark as deleted successfully')
392-
message_link = links.get(1)
393-
if message_link is None:
394-
logging.info(f'{message_id} marked as deleted')
395-
else:
396-
if self.__storage_remove(message_link):
397-
logging.debug(f'{message_id} object mark as deleted successfully')
390+
if quick_sync_days is None:
391+
logging.info('Mark as deletes...')
392+
for message_id in stored_messages:
393+
links = stored_messages[message_id]
394+
logging.debug(f'{message_id} mark as deleted in local storage...')
395+
meta_link = links.get(0)
396+
if meta_link is None:
397+
continue
398+
logging.debug(f'{message_id} - {meta_link}')
399+
if self.__storage_remove(meta_link):
400+
logging.debug(f'{message_id} metadata mark as deleted successfully')
401+
message_link = links.get(1)
402+
if message_link is None:
398403
logging.info(f'{message_id} marked as deleted')
399404
else:
400-
logging.error(f'{message_id} object mark as deleted fail')
401-
else:
402-
logging.error(f'{message_id} mark as deleted failed')
403-
404-
logging.info('Mark as deleted: complete')
405+
if self.__storage_remove(message_link):
406+
logging.debug(f'{message_id} object mark as deleted successfully')
407+
logging.info(f'{message_id} marked as deleted')
408+
else:
409+
logging.error(f'{message_id} object mark as deleted fail')
410+
else:
411+
logging.error(f'{message_id} mark as deleted failed')
412+
logging.info('Mark as deleted: complete')
413+
else:
414+
logging.info('Quick syncing mode, skip deletion for locale storage')
405415
logging.info(f'Backup finished for {self.email}')
406416
return True
407417

gwb/gwbackupy.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ def parse_arguments():
4747

4848
gmail_backup_parser = gmail_command_parser.add_parser('backup', help='Backup gmail')
4949
gmail_backup_parser.add_argument('--email', type=str, help='Email of the account', required=True)
50+
gmail_backup_parser.add_argument('--quick-sync-days', type=int,
51+
default=None,
52+
help='Quick sync number of days back. (It does not delete messages from local '
53+
'storage.)')
5054

5155
gmail_restore_parser = gmail_command_parser.add_parser('restore', help='Restore gmail')
5256
gmail_restore_parser.add_argument('--email', type=str, help='Email from which restore', required=True)
@@ -91,7 +95,7 @@ def cli_startup():
9195
storage=storage,
9296
dry_mode=args.dry)
9397
if args.command == 'backup':
94-
if gmail.backup():
98+
if gmail.backup(quick_sync_days=args.quick_sync_days):
9599
exit(0)
96100
else:
97101
exit(1)

0 commit comments

Comments
 (0)