comparison multimerge.py @ 1:74f172565752

Initial import.
author Matti Hamalainen <ccr@tnsp.org>
date Mon, 04 Jul 2016 12:49:37 +0300
parents
children 34c3a08a4a37
comparison
equal deleted inserted replaced
0:c0e97f27f929 1:74f172565752
1 #!/usr/bin/python
2 import os
3 import sys
4 import signal
5 import re
6 import time
7 import datetime
8 import httplib2
9 import ConfigParser
10 import oauth2client
11 from oauth2client import client
12 from oauth2client import tools
13 from googleapiclient import discovery
14
15
16 ###
17 ### Misc. helper functions
18 ###
19
20 ## Wrapper for print() that does not break when redirecting stdin/out
21 ## because of piped output not having a defined encoding. We default
22 ## to UTF-8 encoding in output here.
23 def gcm_print(smsg):
24 gcm_msgbuf.append(smsg.encode("UTF-8"))
25 if sys.stdout.encoding != None:
26 print(smsg.encode(sys.stdout.encoding))
27 else:
28 print(smsg.encode("UTF-8"))
29
30
31 ## Fatal errors
32 def gcm_fatal(smsg):
33 gcm_print(u"ERROR: "+ smsg)
34 sys.exit(1)
35
36
37 ## Debug messages
38 def gcm_debug(smsg):
39 if cfg.debug:
40 gcm_print(u"DBG: "+ smsg)
41 else:
42 gcm_msgbuf.append(u"DBG: "+ smsg.encode("UTF-8"))
43
44
45 ## Handle SIGINT signals here
46 def gcm_signal_handler(signal, frame):
47 gcm_print("\nQuitting due to SIGINT / Ctrl+C!")
48 sys.exit(0)
49
50
51 def gcm_get_credentials(mcfg):
52 store = oauth2client.file.Storage(mcfg.credential_file)
53 credentials = store.get()
54 if not credentials or credentials.invalid:
55 flow = client.flow_from_clientsecrets(mcfg.secret_file, mcfg.scope)
56 flow.user_agent = mcfg.app_name
57 credentials = tools.run_flow(flow, store, mcfg)
58 if not credentials or credentials.invalid:
59 gcm_fatal("Failed to authenticate / invalid credentials.")
60 return credentials
61
62
63 def gcm_dump_events(events):
64 for event in events:
65 ev_start = event["start"].get("dateTime", event["start"].get("date"))
66 ev_end = event["end"].get("dateTime", event["end"].get("date"))
67 gcm_print(u"{0:25} - {1:25} : {2}".format(ev_start, ev_end, event["summary"]))
68
69
70 class GCMSettings(dict):
71 def __init__(self):
72 self.m_data = {}
73 self.m_saveable = {}
74 self.m_translate = {}
75
76 def __getattr__(self, name):
77 if name in self.m_data:
78 return self.m_data[name]
79 else:
80 gcm_fatal("GCMSettings.__getattr__(): No such attribute '"+ name +"'.")
81
82 def mtranslate(self, name, value):
83 if name in self.m_translate and self.m_translate[name]:
84 return self.m_translate[name](value)
85 else:
86 return value
87
88 def mdef(self, name, saveable, validate, translate, value):
89 self.m_saveable[name] = saveable
90 self.m_data[name] = self.mtranslate(name, value)
91
92 def mset(self, name, value):
93 if name in self.m_data:
94 self.m_data[name] = self.mtranslate(name, value)
95 else:
96 gcm_fatal("GCMSettings.mset(): No such attribute '"+ name +"'.")
97
98 def mget(self, name):
99 if name in self.m_data:
100 return self.m_data[name]
101 else:
102 return None
103
104
105 ###
106 ### Main program starts
107 ###
108 gcm_msgbuf = []
109 signal.signal(signal.SIGINT, gcm_signal_handler)
110
111
112 ## Settings
113 cfg = GCMSettings()
114
115 cfg.mdef("debug", True, gcm_is_bool, gcm_trans_bool, False)
116
117 cfg.mdef("source_regex", True, gcm_is_string, None, "^R:\s*(.*?)\s*\(\s*(.+?)\s*\)\s*$")
118 cfg.mdef("source_regmap", False, gcm_is_list, gcm_trans_list, [1, 2])
119 cfg.mdef("source_regmap_len", False, None, None, len(cfg.source_regmap))
120
121 cfg.mdef("dest_name", True, gcm_is_string, None, u"Raahen kansainvälisyystoiminta")
122 cfg.mdef("dest_id", True, gcm_is_string, None, None)
123
124 cfg.mdef("noauth_local_webserver", False, None, None, True)
125 #cfg.mdef("auth_host_name", False, None, None, "localhost")
126 #cfg.mdef("auth_host_port", False, None, None, [8080, 8090])
127 cfg.mdef("logging_level", True, gcm_is_log_level, gcm_trans_log_level, "ERROR")
128
129 # No need to touch these
130 cfg.mdef("app_name", False, None, None, "Google Calendar MultiMerge")
131 cfg.mdef("scope", False, None, None, "https://www.googleapis.com/auth/calendar")
132 #cfg.mdef("scope", False, None, None, "https://www.googleapis.com/auth/calendar.readonly")
133 cfg.mdef("secret_file", True, gcm_is_filename, None, "client_secret.json")
134 cfg.mdef("credential_file", True, gcm_is_filename, None, "client_credentials.json")
135
136 ## Initialize and authorize API connection
137 credentials = gcm_get_credentials(cfg)
138 http = credentials.authorize(httplib2.Http())
139 service = discovery.build("calendar", "v3", http=http)
140
141
142 ## Fetch complete calendar list
143 gcm_debug("Fetching available calendars ..")
144 calendars = []
145 calPageToken = None
146 while True:
147 # We want everything except deleted and hidden calendars
148 calResult = service.calendarList().list(
149 showHidden=False,
150 showDeleted=False,
151 pageToken=calPageToken
152 ).execute()
153
154 calendars.extend(calResult.get("items", []))
155 calPageToken = calResult.get("nextPageToken")
156 if not calPageToken:
157 break
158
159 if len(calendars) == 0:
160 gcm_fatal("No calendars found?")
161
162