Mercurial > hg > gcmultimerge
comparison multimerge.py @ 77:e5e7b6e9bd44
Implement debug levels in the main code.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Wed, 13 Jul 2016 12:33:12 +0300 |
parents | a63cc3633adb |
children | 784cac877428 |
comparison
equal
deleted
inserted
replaced
76:a63cc3633adb | 77:e5e7b6e9bd44 |
---|---|
36 "id", "iCalUID", "etag", "sequence", "gcm_cal_id", | 36 "id", "iCalUID", "etag", "sequence", "gcm_cal_id", |
37 "created", "updated", "htmlLink", "organizer", "creator", | 37 "created", "updated", "htmlLink", "organizer", "creator", |
38 ] | 38 ] |
39 | 39 |
40 gcm_log_levels = ["CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG"] | 40 gcm_log_levels = ["CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG"] |
41 | |
42 | |
43 def gcm_get_log_level(): | |
44 return gcm_log_levels.index(cfg.logging_level) | |
41 | 45 |
42 | 46 |
43 ## Wrapper for print() that does not break when redirecting stdin/out | 47 ## Wrapper for print() that does not break when redirecting stdin/out |
44 ## because of piped output not having a defined encoding. We default | 48 ## because of piped output not having a defined encoding. We default |
45 ## to UTF-8 encoding in output here. | 49 ## to UTF-8 encoding in output here. |
69 gcm_print(u"FATAL: Oh crap, e-mail sending failed: {0}".format(str(e))) | 73 gcm_print(u"FATAL: Oh crap, e-mail sending failed: {0}".format(str(e))) |
70 sys.exit(1) | 74 sys.exit(1) |
71 | 75 |
72 | 76 |
73 ## Debug messages | 77 ## Debug messages |
74 def gcm_debug(smsg): | 78 def gcm_check_debug(level): |
75 if cfg.debug: | 79 return cfg.debug and gcm_get_log_level() >= level |
76 gcm_print(u"DBG: "+ smsg) | 80 |
81 def gcm_debug(level, smsg): | |
82 if gcm_check_debug(level): | |
83 gcm_print(u"DBG: {0}".format(smsg)) | |
77 else: | 84 else: |
78 gcm_msgbuf.append(u"DBG: {0}".format(smsg)) | 85 gcm_msgbuf.append(u"DBG: {0}".format(smsg)) |
79 | 86 |
80 | 87 |
81 ## Handler for SIGINT signals | 88 ## Handler for SIGINT signals |
248 def mread(self, cfgparser, sect): | 255 def mread(self, cfgparser, sect): |
249 for name in self.m_saveable: | 256 for name in self.m_saveable: |
250 if cfgparser.has_option(sect, name): | 257 if cfgparser.has_option(sect, name): |
251 value = cfgparser.get(sect, name) | 258 value = cfgparser.get(sect, name) |
252 self.mset(name, value) | 259 self.mset(name, value) |
253 gcm_debug(u"{0} -> '{1}' == {2}".format(name, value, self.mget(name))) | 260 gcm_debug(4, u"{0} -> '{1}' == {2}".format(name, value, self.mget(name))) |
254 | 261 |
255 def is_str(self, mvalue): | 262 def is_str(self, mvalue): |
256 return isinstance(mvalue, basestring) | 263 return isinstance(mvalue, basestring) |
257 | 264 |
258 def is_string(self, mvalue): | 265 def is_string(self, mvalue): |
364 cfg.mdef("credential_file", True, cfg.is_filename, None, "client_credentials.json") | 371 cfg.mdef("credential_file", True, cfg.is_filename, None, "client_credentials.json") |
365 | 372 |
366 | 373 |
367 ## Read, parse and validate configuration file | 374 ## Read, parse and validate configuration file |
368 if len(sys.argv) > 1: | 375 if len(sys.argv) > 1: |
369 gcm_debug(u"Reading configuration from '{0}'.".format(sys.argv[1])) | 376 gcm_debug(3, u"Reading configuration from '{0}'.".format(sys.argv[1])) |
370 try: | 377 try: |
371 cfgparser = ConfigParser.RawConfigParser() | 378 cfgparser = ConfigParser.RawConfigParser() |
372 cfgparser.readfp(codecs.open(sys.argv[1], "r", "UTF-8")) | 379 cfgparser.readfp(codecs.open(sys.argv[1], "r", "UTF-8")) |
373 except Exception as e: | 380 except Exception as e: |
374 gcm_fatal(u"Failed to read configuration file '{0}': {1}".format(sys.argv[1], str(e))) | 381 gcm_fatal(u"Failed to read configuration file '{0}': {1}".format(sys.argv[1], str(e))) |
419 http = credentials.authorize(httplib2.Http()) | 426 http = credentials.authorize(httplib2.Http()) |
420 service = discovery.build("calendar", "v3", http=http) | 427 service = discovery.build("calendar", "v3", http=http) |
421 | 428 |
422 | 429 |
423 ## Fetch complete calendar list | 430 ## Fetch complete calendar list |
424 gcm_debug(u"Fetching available calendars ..") | 431 gcm_debug(3, u"Fetching available calendars ..") |
425 calendars = [] | 432 calendars = [] |
426 cal_token = None | 433 cal_token = None |
427 while True: | 434 while True: |
428 # We want everything except deleted and hidden calendars | 435 # We want everything except deleted and hidden calendars |
429 result = service.calendarList().list( | 436 result = service.calendarList().list( |
438 break | 445 break |
439 | 446 |
440 if len(calendars) == 0: | 447 if len(calendars) == 0: |
441 gcm_fatal(u"No calendars found?") | 448 gcm_fatal(u"No calendars found?") |
442 | 449 |
443 gcm_debug(u"{0} calendars total found.".format(len(calendars))) | 450 gcm_debug(3, u"{0} calendars total found.".format(len(calendars))) |
444 | 451 |
445 | 452 |
446 ## Filter desired SOURCE calendars based on specified regexp | 453 ## Filter desired SOURCE calendars based on specified regexp |
447 src_re = re.compile(cfg.source_regex, re.UNICODE) | 454 src_re = re.compile(cfg.source_regex, re.UNICODE) |
448 dst_re = re.compile(cfg.dest_regex, re.UNICODE) | 455 dst_re = re.compile(cfg.dest_regex, re.UNICODE) |
463 if mre: | 470 if mre: |
464 calendar["gcm_title"] = mre.group(cfg.source_regmap[0]) | 471 calendar["gcm_title"] = mre.group(cfg.source_regmap[0]) |
465 calendar["gcm_id"] = mre.group(cfg.source_regmap[1]) | 472 calendar["gcm_id"] = mre.group(cfg.source_regmap[1]) |
466 src_calendars.append(calendar) | 473 src_calendars.append(calendar) |
467 | 474 |
468 gcm_debug(u"{0} source calendars found.".format(len(src_calendars))) | 475 gcm_debug(3, u"{0} source calendars found.".format(len(src_calendars))) |
469 | 476 |
470 | 477 |
471 ## Check if we have destination calendar ID | 478 ## Check if we have destination calendar ID |
472 if not dst_calendar: | 479 if not dst_calendar: |
473 gcm_fatal(u"Could not find target/destination calendar ID for '"+ cfg.dest_name +"'.") | 480 gcm_fatal(u"Could not find target/destination calendar ID for '"+ cfg.dest_name +"'.") |
474 else: | 481 else: |
475 gcm_debug(u"Target calendar '{0}' id {1}.".format(dst_calendar["summary"], dst_calendar["id"])) | 482 gcm_debug(3, u"Target calendar '{0}' id {1}.".format(dst_calendar["summary"], dst_calendar["id"])) |
476 | 483 |
477 | 484 |
478 ## Fetch colors | 485 ## Fetch colors |
479 try: | 486 try: |
480 colors = service.colors().get().execute() | 487 colors = service.colors().get().execute() |
481 except Exception as e: | 488 except Exception as e: |
482 gcm_fatal(u"Failed to fetch calendar color settings:\n\n{0}".format(str(e))) | 489 gcm_fatal(u"Failed to fetch calendar color settings:\n\n{0}".format(str(e))) |
483 | 490 |
484 | 491 |
485 ## Now, we fetch and collect events | 492 ## Now, we fetch and collect events |
486 gcm_debug(u"Fetching calendar events .. ") | 493 gcm_debug(3, u"Fetching calendar events .. ") |
487 src_events = [] | 494 src_events = [] |
488 for calendar in src_calendars: | 495 for calendar in src_calendars: |
489 gcm_debug(u"- "+calendar["id"]) | 496 gcm_debug(4, u"- "+calendar["id"]) |
490 try: | 497 try: |
491 result = service.events().list( | 498 result = service.events().list( |
492 timeZone="EEST", | 499 timeZone="EEST", |
493 calendarId=calendar["id"], | 500 calendarId=calendar["id"], |
494 singleEvents=True, | 501 singleEvents=True, |
498 except Exception as e: | 505 except Exception as e: |
499 gcm_fatal(u"Failed to fetch calendar events for {0}:\n\n{1}\n\nERROR: {2}\n".format(calendar["id"], calendar, str(e))) | 506 gcm_fatal(u"Failed to fetch calendar events for {0}:\n\n{1}\n\nERROR: {2}\n".format(calendar["id"], calendar, str(e))) |
500 | 507 |
501 c_found = None | 508 c_found = None |
502 if "colorId" in calendar and calendar["colorId"] in colors["calendar"]: | 509 if "colorId" in calendar and calendar["colorId"] in colors["calendar"]: |
503 gcm_debug(u"Calendar color: {0}".format(colors["calendar"][calendar["colorId"]])) | 510 gcm_debug(4, u"Calendar color: {0}".format(colors["calendar"][calendar["colorId"]])) |
504 c_found = gcm_find_nearest_color(colors["event"], colors["calendar"][calendar["colorId"]], 100) | 511 c_found = gcm_find_nearest_color(colors["event"], colors["calendar"][calendar["colorId"]], 100) |
505 if c_found: | 512 if c_found: |
506 gcm_debug(u"Found nearest event color ID: {0}, {1}".format(c_found, colors["event"][c_found])) | 513 gcm_debug(4, u"Found nearest event color ID: {0}, {1}".format(c_found, colors["event"][c_found])) |
507 else: | 514 else: |
508 gcm_debug(u"No matching event color found!") | 515 gcm_debug(4, u"No matching event color found!") |
509 | 516 |
510 # Add events, if any, to main list | 517 # Add events, if any, to main list |
511 events = gcm_generate_ids(result.get("items", []), calendar["id"], "___") | 518 events = gcm_generate_ids(result.get("items", []), calendar["id"], "___") |
512 if events: | 519 if events: |
513 for event in events: | 520 for event in events: |
514 if c_found != None: | 521 if c_found != None: |
515 event["colorId"] = c_found | 522 event["colorId"] = c_found |
516 event["summary"] = u"[{1}] {0}".format(event["summary"], calendar["gcm_id"]) | 523 event["summary"] = u"[{1}] {0}".format(event["summary"], calendar["gcm_id"]) |
517 src_events.extend(events) | 524 src_events.extend(events) |
518 if cfg.debug: | 525 if gcm_check_debug(4): |
519 gcm_dump_events(events) | 526 gcm_dump_events(events) |
520 | 527 |
521 | 528 |
522 ## Get current events | 529 ## Get current events |
523 gcm_debug(u"Fetching current target calendar events {0}".format(cfg.dest_id)) | 530 gcm_debug(3, u"Fetching current target calendar events {0}".format(cfg.dest_id)) |
524 result = service.events().list( | 531 result = service.events().list( |
525 calendarId=cfg.dest_id, | 532 calendarId=cfg.dest_id, |
526 singleEvents=True, | 533 singleEvents=True, |
527 showDeleted=True, | 534 showDeleted=True, |
528 ).execute() | 535 ).execute() |
529 | 536 |
530 dst_events = gcm_generate_ids(result.get("items", []), "", "") | 537 dst_events = gcm_generate_ids(result.get("items", []), "", "") |
531 gcm_debug(u"Found {0} event(s).".format(len(dst_events))) | 538 gcm_debug(3, u"Found {0} event(s).".format(len(dst_events))) |
532 | 539 |
533 | 540 |
534 ## Start merging events .. | 541 ## Start merging events .. |
535 gcm_debug(u"Re-merging events to target calendar ..") | 542 gcm_debug(3, u"Re-merging events to target calendar ..") |
536 dst_ids = frozenset(map(lambda x: x["gcm_id"], dst_events)) | 543 dst_ids = frozenset(map(lambda x: x["gcm_id"], dst_events)) |
537 src_ids = frozenset(map(lambda x: x["gcm_id"], src_events)) | 544 src_ids = frozenset(map(lambda x: x["gcm_id"], src_events)) |
538 | 545 |
539 for event in src_events: | 546 for event in src_events: |
540 # Does the event exist already in the target? | 547 # Does the event exist already in the target? |
541 if event["gcm_id"] in dst_ids: | 548 if event["gcm_id"] in dst_ids: |
542 # Check if event NEEDS updating .. aka compare data | 549 # Check if event NEEDS updating .. aka compare data |
543 gcm_debug(u"Event {0} : {1} exists, checking ..".format(event["id"], event["gcm_id"])) | 550 gcm_debug(4, u"Event {0} : {1} exists, checking ..".format(event["id"], event["gcm_id"])) |
544 d_event = gcm_get_event_by_gcm_id(dst_events, event["gcm_id"]) | 551 d_event = gcm_get_event_by_gcm_id(dst_events, event["gcm_id"]) |
545 if not gcm_compare_events(event, d_event): | 552 if not gcm_compare_events(event, d_event): |
546 # Seems we need to update | 553 # Seems we need to update |
547 gcm_debug(u"Updating event {0} : {1}..".format(event["id"], event["gcm_id"])) | 554 gcm_debug(4, u"Updating event {0} : {1}..".format(event["id"], event["gcm_id"])) |
548 try: | 555 try: |
549 event.pop("sequence", None) | 556 event.pop("sequence", None) |
550 event.pop("id", None) | 557 event.pop("id", None) |
551 event["iCalUID"] = event["gcm_id"] | 558 event["iCalUID"] = event["gcm_id"] |
552 new_event = service.events().update(calendarId=cfg.dest_id, eventId=d_event["id"], body=event).execute() | 559 new_event = service.events().update(calendarId=cfg.dest_id, eventId=d_event["id"], body=event).execute() |
553 except Exception as e: | 560 except Exception as e: |
554 gcm_fatal(u"Failed to update event {0}:\n\n{1}\n\nERROR: {2}\n".format(event["gcm_id"], event, str(e))) | 561 gcm_fatal(u"Failed to update event {0}:\n\n{1}\n\nERROR: {2}\n".format(event["gcm_id"], event, str(e))) |
555 else: | 562 else: |
556 gcm_debug(u"No need to update event {0} : {1}.".format(event["id"], event["gcm_id"])) | 563 gcm_debug(4, u"No need to update event {0} : {1}.".format(event["id"], event["gcm_id"])) |
557 else: | 564 else: |
558 ## Event does not seem to exist. Insert new event. | 565 ## Event does not seem to exist. Insert new event. |
559 gcm_debug(u"Inserting new event {0}".format(event["gcm_id"])) | 566 gcm_debug(4, u"Inserting new event {0}".format(event["gcm_id"])) |
560 event.pop("id", None) | 567 event.pop("id", None) |
561 event["iCalUID"] = event["gcm_id"] # Replace Google generated ID with our own | 568 event["iCalUID"] = event["gcm_id"] # Replace Google generated ID with our own |
562 try: | 569 try: |
563 new_event = service.events().insert(calendarId=cfg.dest_id, body=event).execute() | 570 new_event = service.events().insert(calendarId=cfg.dest_id, body=event).execute() |
564 except Exception as e: | 571 except Exception as e: |
565 gcm_fatal(u"Failed to insert new event:\n\n{0}\n\nERROR: {1}\n".format(event, str(e))) | 572 gcm_fatal(u"Failed to insert new event:\n\n{0}\n\nERROR: {1}\n".format(event, str(e))) |
566 | 573 |
567 | 574 |
568 ## Remove "stale" events | 575 ## Remove "stale" events |
569 gcm_debug(u"Purging stale events ..") | 576 gcm_debug(3, u"Purging stale events ..") |
570 for event in dst_events: | 577 for event in dst_events: |
571 gcm_debug(u"Checking event {0}".format(event["gcm_id"])) | 578 gcm_debug(4, u"Checking event {0}".format(event["gcm_id"])) |
572 if not event["gcm_id"] in src_ids and event["status"] != u"cancelled": | 579 if not event["gcm_id"] in src_ids and event["status"] != u"cancelled": |
573 gcm_debug(u"Deleting event {0}".format(event["gcm_id"])) | 580 gcm_debug(4, u"Deleting event {0}".format(event["gcm_id"])) |
574 try: | 581 try: |
575 service.events().delete(calendarId=cfg.dest_id, eventId=event["id"]).execute() | 582 service.events().delete(calendarId=cfg.dest_id, eventId=event["id"]).execute() |
576 except Exception as e: | 583 except Exception as e: |
577 gcm_fatal(u"Failed to delete stale event:\n{0}\n\nERROR: {1}\n".format(event, str(e))) | 584 gcm_fatal(u"Failed to delete stale event:\n{0}\n\nERROR: {1}\n".format(event, str(e))) |
578 | 585 |
579 ## | 586 ## |
580 ## Finally, update the calendar name with timestamp | 587 ## Finally, update the calendar name with timestamp |
581 ## | 588 ## |
582 t_time = time.localtime() | 589 t_time = time.localtime() |
583 t_str = time.strftime("%d.%m.%Y %H:%M", t_time) | 590 t_str = time.strftime("%d.%m.%Y %H:%M", t_time) |
584 gcm_debug(u"Updating target calendar name timestamp {0}".format(t_str)) | 591 gcm_debug(3, u"Updating target calendar name timestamp {0}".format(t_str)) |
585 | 592 |
586 try: | 593 try: |
587 dst_calendar["summary"] = cfg.dest_name.format(t_str) | 594 dst_calendar["summary"] = cfg.dest_name.format(t_str) |
588 new_calendar = service.calendars().update(calendarId=cfg.dest_id, body=dst_calendar).execute() | 595 new_calendar = service.calendars().update(calendarId=cfg.dest_id, body=dst_calendar).execute() |
589 except Exception as e: | 596 except Exception as e: |
590 gcm_fatal(u"Failed to update target calendar:\n{0}\n\nERROR: {1}\n".format(dst_calendar, str(e))) | 597 gcm_fatal(u"Failed to update target calendar:\n{0}\n\nERROR: {1}\n".format(dst_calendar, str(e))) |
591 | 598 |
592 | 599 |
593 gcm_debug(u"Finished.") | 600 gcm_debug(3, u"Finished.") |