Define/use file processing routines; fix show filelist allfields

Define and use new file handling primitives to simply code and isolate
error handling.

Error message cleanup.

Google added a new object (userPermission) to the filesResource object
which broke showDriveFiles because it has an item named 'id' which
wiped out the file id. This fix makes compound column names for all
dictionary objects except for labels.
This commit is contained in:
Ross Scroggs
2015-11-21 09:50:11 -08:00
parent 7a9bda9b1b
commit b822608b15

View File

@ -28,7 +28,7 @@ __author__ = u'Jay Lee <jay0lee@gmail.com>'
__version__ = u'3.62' __version__ = u'3.62'
__license__ = u'Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)' __license__ = u'Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)'
import sys, os, time, datetime, random, socket, csv, platform, re, calendar, base64, string, subprocess import sys, os, time, datetime, random, socket, csv, platform, re, calendar, base64, string, StringIO, subprocess
import json import json
import httplib2 import httplib2
@ -206,6 +206,59 @@ def noPythonSSLExit():
def printLine(message): def printLine(message):
sys.stdout.write(message+u'\n') sys.stdout.write(message+u'\n')
#
# Open a file
#
def openFile(filename, mode='rb'):
try:
if filename != u'-':
return open(filename, mode)
if mode.startswith(u'r'):
return StringIO.StringIO(unicode(sys.stdin.read()))
return sys.stdout
except IOError as e:
systemErrorExit(6, e)
#
# Close a file
#
def closeFile(f):
try:
f.close()
return True
except IOError as e:
sys.stderr.write(u'{0}{1}\n'.format(ERROR_PREFIX, e))
return False
#
# Read a file
#
def readFile(filename, mode='rb', continueOnError=False, displayError=True):
try:
if filename != u'-':
with open(filename, mode) as f:
return f.read()
else:
return unicode(sys.stdin.read())
except IOError as e:
if continueOnError:
if displayError:
sys.stderr.write(u'{0}{1}\n'.format(WARNING_PREFIX, e))
return None
systemErrorExit(6, e)
#
# Write a file
#
def writeFile(filename, data, mode='wb', continueOnError=False, displayError=True):
try:
with open(filename, mode) as f:
f.write(data)
return True
except IOError as e:
if continueOnError:
if displayError:
sys.stderr.write(u'{0}{1}\n'.format(ERROR_PREFIX, e))
return False
systemErrorExit(6, e)
def setGamDirs(): def setGamDirs():
global gamPath, gamSiteConfigDir, gamUserConfigDir, gamDriveDir, gamCacheDir global gamPath, gamSiteConfigDir, gamUserConfigDir, gamDriveDir, gamCacheDir
gamPath = os.path.dirname(os.path.realpath(__file__)) gamPath = os.path.dirname(os.path.realpath(__file__))
@ -216,6 +269,8 @@ def setGamDirs():
else: else:
gamCacheDir = os.environ.get(u'GAMCACHEDIR', os.path.join(gamPath, u'gamcache')) gamCacheDir = os.environ.get(u'GAMCACHEDIR', os.path.join(gamPath, u'gamcache'))
gamDriveDir = os.environ.get(u'GAMDRIVEDIR', gamPath) gamDriveDir = os.environ.get(u'GAMDRIVEDIR', gamPath)
if not os.path.isfile(os.path.join(gamUserConfigDir, u'noupdatecheck.txt')):
doGAMCheckForUpdates()
def doGAMVersion(): def doGAMVersion():
import struct import struct
@ -227,33 +282,29 @@ def doGAMVersion():
platform.platform(), platform.machine(), platform.platform(), platform.machine(),
gamPath) gamPath)
def doGAMCheckForUpdates(): def doGAMCheckForUpdates(forceCheck=False):
import urllib2 import urllib2
if os.path.isfile(os.path.join(gamUserConfigDir, u'noupdatecheck.txt')):
return
try: try:
current_version = float(__version__) current_version = float(__version__)
except ValueError: except ValueError:
return return
if os.path.isfile(os.path.join(gamUserConfigDir, FN_LAST_UPDATE_CHECK_TXT)):
f = open(os.path.join(gamUserConfigDir, FN_LAST_UPDATE_CHECK_TXT), 'r')
last_check_time = int(f.readline())
f.close()
else:
last_check_time = 0
now_time = calendar.timegm(time.gmtime()) now_time = calendar.timegm(time.gmtime())
if last_check_time > now_time-604800: if not forceCheck:
return last_check_time = readFile(os.path.join(gamUserConfigDir, FN_LAST_UPDATE_CHECK_TXT), continueOnError=True, displayError=forceCheck)
if last_check_time == None:
last_check_time = 0
if last_check_time > now_time-604800:
return
try: try:
c = urllib2.urlopen(GAM_APPSPOT_LATEST_VERSION) c = urllib2.urlopen(GAM_APPSPOT_LATEST_VERSION)
try: try:
latest_version = float(c.read()) latest_version = float(c.read())
except ValueError: except ValueError:
return return
if forceCheck or (latest_version > current_version):
print u'Version: Check, Current: {0:.2f}, Latest: {1:.2f}'.format(current_version, latest_version)
if latest_version <= current_version: if latest_version <= current_version:
f = open(os.path.join(gamUserConfigDir, FN_LAST_UPDATE_CHECK_TXT), 'w') writeFile(os.path.join(gamUserConfigDir, FN_LAST_UPDATE_CHECK_TXT), str(now_time), continueOnError=True, displayError=forceCheck)
f.write(str(now_time))
f.close()
return return
a = urllib2.urlopen(GAM_APPSPOT_LATEST_VERSION_ANNOUNCEMENT) a = urllib2.urlopen(GAM_APPSPOT_LATEST_VERSION_ANNOUNCEMENT)
announcement = a.read() announcement = a.read()
@ -266,29 +317,23 @@ def doGAMCheckForUpdates():
webbrowser.open(GAM_RELEASES) webbrowser.open(GAM_RELEASES)
printLine(MESSAGE_GAM_EXITING_FOR_UPDATE) printLine(MESSAGE_GAM_EXITING_FOR_UPDATE)
sys.exit(0) sys.exit(0)
f = open(os.path.join(gamUserConfigDir, FN_LAST_UPDATE_CHECK_TXT), 'w') writeFile(os.path.join(gamUserConfigDir, FN_LAST_UPDATE_CHECK_TXT), str(now_time), continueOnError=True, displayError=forceCheck)
f.write(str(now_time)) except (urllib2.HTTPError, urllib2.URLError):
f.close()
except urllib2.HTTPError:
return
except urllib2.URLError:
return return
def checkErrorCode(e, service): def checkGDataError(e, service):
# First check for errors that need special handling # First check for errors that need special handling
if e[0].get('reason', '') in [u'Token invalid - Invalid token: Stateless token expired', u'Token invalid - Invalid token: Token not found']: if e[0].get(u'reason', u'') in [u'Token invalid - Invalid token: Stateless token expired', u'Token invalid - Invalid token: Token not found']:
keep_domain = service.domain keep_domain = service.domain
tryOAuth(service) tryOAuth(service)
service.domain = keep_domain service.domain = keep_domain
return False return False
if e[0]['body'][:34] in [u'Required field must not be blank: ', u'These characters are not allowed: ']: if e[0][u'body'].startswith(u'Required field must not be blank:') or e[0][u'body'].startswith(u'These characters are not allowed:'):
return e[0]['body'] return e[0]['body']
if e.error_code == 600 and e[0][u'body'] == u'Quota exceeded for the current request' or e[0][u'reason'] == u'Bad Gateway': if e.error_code == 600 and e[0][u'body'] == u'Quota exceeded for the current request' or e[0][u'reason'] == u'Bad Gateway':
return False return False
if e.error_code == 600 and e[0][u'reason'] == u'Token invalid - Invalid token: Token disabled, revoked, or expired.': if e.error_code == 600 and e[0][u'reason'] == u'Token invalid - Invalid token: Token disabled, revoked, or expired.':
return u'403 - Token disabled, revoked, or expired. Please delete and re-create oauth.txt' return u'403 - Token disabled, revoked, or expired. Please delete and re-create oauth.txt'
# We got a "normal" error, define the mapping below # We got a "normal" error, define the mapping below
error_code_map = { error_code_map = {
1000: False, 1000: False,
@ -325,8 +370,7 @@ def checkErrorCode(e, service):
1800: u'Group Cannot Contain Cycle', 1800: u'Group Cannot Contain Cycle',
1801: u'Invalid value %s' % getattr(e, u'invalidInput', u'<unknown>'), 1801: u'Invalid value %s' % getattr(e, u'invalidInput', u'<unknown>'),
} }
return u'{0} - {1}'.format(e.error_code, error_code_map.get(e.error_code, u'Unknown Error: {0}'.format(str(e))))
return u'%s - %s' % (e.error_code, error_code_map.get(e.error_code, u'Unknown Error: %s' % (str(e))))
def tryOAuth(gdataObject): def tryOAuth(gdataObject):
global domain global domain
@ -356,7 +400,7 @@ def callGData(service, function, soft_errors=False, throw_errors=[], **kwargs):
try: try:
return method(**kwargs) return method(**kwargs)
except gdata.apps.service.AppsForYourDomainException, e: except gdata.apps.service.AppsForYourDomainException, e:
terminating_error = checkErrorCode(e, service) terminating_error = checkGDataError(e, service)
if e.error_code in throw_errors: if e.error_code in throw_errors:
raise raise
if not terminating_error and n != retries: if not terminating_error and n != retries:
@ -369,13 +413,12 @@ def callGData(service, function, soft_errors=False, throw_errors=[], **kwargs):
if n > 3: if n > 3:
sys.stderr.write(u'attempt %s/%s\n' % (n+1, retries)) sys.stderr.write(u'attempt %s/%s\n' % (n+1, retries))
continue continue
sys.stderr.write(u'Error: %s' % terminating_error) sys.stderr.write(u'{0}{1}\n'.format(ERROR_PREFIX, terminating_error))
if soft_errors: if soft_errors:
if n != 1: if n != 1:
sys.stderr.write(u' - Giving up.\n') sys.stderr.write(u' - Giving up.\n')
return return
else: sys.exit(int(e.error_code))
sys.exit(int(e.error_code))
def callGAPI(service, function, silent_errors=False, soft_errors=False, throw_reasons=[], retry_reasons=[], **kwargs): def callGAPI(service, function, silent_errors=False, soft_errors=False, throw_reasons=[], retry_reasons=[], **kwargs):
method = getattr(service, function) method = getattr(service, function)
@ -398,7 +441,7 @@ def callGAPI(service, function, silent_errors=False, soft_errors=False, throw_re
time.sleep(1) time.sleep(1)
continue continue
if not silent_errors: if not silent_errors:
print u'ERROR: %s' % e.content sys.stderr.write(u'{0}{1}\n'.format(ERROR_PREFIX, e.content))
if soft_errors: if soft_errors:
return return
sys.exit(5) sys.exit(5)
@ -420,14 +463,14 @@ def callGAPI(service, function, silent_errors=False, soft_errors=False, throw_re
if n > 3: if n > 3:
sys.stderr.write(u'attempt %s/%s\n' % (n+1, retries)) sys.stderr.write(u'attempt %s/%s\n' % (n+1, retries))
continue continue
sys.stderr.write(u'Error %s: %s - %s\n\n' % (http_status, message, reason)) sys.stderr.write(u'{0}{1}: {2} - {3}\n'.format(ERROR_PREFIX, http_status, message, reason))
if soft_errors: if soft_errors:
if n != 1: if n != 1:
sys.stderr.write(u' - Giving up.\n') sys.stderr.write(u' - Giving up.\n')
return return
sys.exit(int(http_status)) sys.exit(int(http_status))
except oauth2client.client.AccessTokenRefreshError, e: except oauth2client.client.AccessTokenRefreshError, e:
sys.stderr.write(u'Error: Authentication Token Error - %s' % e) sys.stderr.write(u'{0}Authentication Token Error: {1}\n'.format(ERROR_PREFIX, e))
sys.exit(403) sys.exit(403)
except httplib2.CertificateValidationUnsupported: except httplib2.CertificateValidationUnsupported:
noPythonSSLExit() noPythonSSLExit()
@ -525,11 +568,9 @@ def getServiceFromDiscoveryDocument(api, version, http):
else: else:
pyinstaller_disc_file = None pyinstaller_disc_file = None
if os.path.isfile(disc_file): if os.path.isfile(disc_file):
with open(disc_file, 'rb') as f: discovery = readFile(disc_file)
discovery = f.read()
elif pyinstaller_disc_file: elif pyinstaller_disc_file:
with open(pyinstaller_disc_file, 'rb') as f: discovery = readFile(pyinstaller_disc_file)
discovery = f.read()
else: else:
systemErrorExit(4, MESSAGE_NO_DISCOVERY_INFORMATION.format(disc_file)) systemErrorExit(4, MESSAGE_NO_DISCOVERY_INFORMATION.format(disc_file))
return googleapiclient.discovery.build_from_document(discovery, base=u'https://www.googleapis.com', http=http) return googleapiclient.discovery.build_from_document(discovery, base=u'https://www.googleapis.com', http=http)
@ -582,9 +623,8 @@ def buildGAPIServiceObject(api, act_as=None, soft_errors=False):
oauth2servicefile = os.path.join(gamUserConfigDir, os.environ.get(u'OAUTHSERVICEFILE', 'oauth2service')) oauth2servicefile = os.path.join(gamUserConfigDir, os.environ.get(u'OAUTHSERVICEFILE', 'oauth2service'))
oauth2servicefilejson = u'%s.json' % oauth2servicefile oauth2servicefilejson = u'%s.json' % oauth2servicefile
oauth2servicefilep12 = u'%s.p12' % oauth2servicefile oauth2servicefilep12 = u'%s.p12' % oauth2servicefile
try: json_string = readFile(oauth2servicefilejson, continueOnError=True, displayError=True)
json_string = open(oauth2servicefilejson).read() if not json_string:
except IOError, e:
printLine(MESSAGE_WIKI_INSTRUCTIONS_OAUTH2SERVICE_JSON) printLine(MESSAGE_WIKI_INSTRUCTIONS_OAUTH2SERVICE_JSON)
printLine(GAM_WIKI_CREATE_CLIENT_SECRETS) printLine(GAM_WIKI_CREATE_CLIENT_SECRETS)
sys.exit(6) sys.exit(6)
@ -592,9 +632,7 @@ def buildGAPIServiceObject(api, act_as=None, soft_errors=False):
try: try:
SERVICE_ACCOUNT_EMAIL = json_data[u'web'][u'client_email'] SERVICE_ACCOUNT_EMAIL = json_data[u'web'][u'client_email']
SERVICE_ACCOUNT_CLIENT_ID = json_data[u'web'][u'client_id'] SERVICE_ACCOUNT_CLIENT_ID = json_data[u'web'][u'client_id']
f = file(oauth2servicefilep12, 'rb') key = readFile(oauth2servicefilep12)
key = f.read()
f.close()
except KeyError: except KeyError:
# new format with config and data in the .json file... # new format with config and data in the .json file...
SERVICE_ACCOUNT_EMAIL = json_data[u'client_email'] SERVICE_ACCOUNT_EMAIL = json_data[u'client_email']
@ -652,7 +690,7 @@ def buildDiscoveryObject(api):
try: try:
return json.loads(content) return json.loads(content)
except ValueError: except ValueError:
sys.stderr.write(u'Failed to parse as JSON: ' + content+u'\n') sys.stderr.write(u'{0}Failed to parse as JSON: {1}\n'.format(ERROR_PREFIX, content))
raise googleapiclient.errors.InvalidJsonError() raise googleapiclient.errors.InvalidJsonError()
def commonAppsObjInit(appsObj): def commonAppsObjInit(appsObj):
@ -685,7 +723,7 @@ def getResCalObject():
def geturl(url, dst): def geturl(url, dst):
import urllib2 import urllib2
u = urllib2.urlopen(url) u = urllib2.urlopen(url)
f = open(dst, 'wb') f = openFile(dst, 'wb')
meta = u.info() meta = u.info()
try: try:
file_size = int(meta.getheaders(u'Content-Length')[0]) file_size = int(meta.getheaders(u'Content-Length')[0])
@ -705,7 +743,7 @@ def geturl(url, dst):
status = r"%10d [unknown size]" % (file_size_dl) status = r"%10d [unknown size]" % (file_size_dl)
status = status + chr(8)*(len(status)+1) status = status + chr(8)*(len(status)+1)
print status, print status,
f.close() closeFile(f)
def showReport(): def showReport():
report = sys.argv[2].lower() report = sys.argv[2].lower()
@ -1181,8 +1219,7 @@ def doGetDomainInfo():
if (len(sys.argv) < 4) or (sys.argv[3] == u'logo'): if (len(sys.argv) < 4) or (sys.argv[3] == u'logo'):
doGetInstanceInfo() doGetInstanceInfo()
return return
else: domainName = sys.argv[3]
domainName = sys.argv[3]
cd = buildGAPIObject(u'directory') cd = buildGAPIObject(u'directory')
result = callGAPI(service=cd.domains(), function=u'get', customer=customerId, domainName=domainName) result = callGAPI(service=cd.domains(), function=u'get', customer=customerId, domainName=domainName)
if u'creationTime' in result: if u'creationTime' in result:
@ -2184,13 +2221,11 @@ def doPrintJobFetch():
fileName = u''.join(c if c in valid_chars else u'_' for c in fileName) fileName = u''.join(c if c in valid_chars else u'_' for c in fileName)
fileName = u'%s-%s' % (fileName, jobid) fileName = u'%s-%s' % (fileName, jobid)
_, content = cp._http.request(uri=fileUrl, method='GET') _, content = cp._http.request(uri=fileUrl, method='GET')
f = open(fileName, 'wb') if writeFile(fileName, content, continueOnError=True):
f.write(content) # ticket = callGAPI(service=cp.jobs(), function=u'getticket', jobid=jobid, use_cjt=True)
f.close() result = callGAPI(service=cp.jobs(), function=u'update', jobid=jobid, semantic_state_diff=ssd)
#ticket = callGAPI(service=cp.jobs(), function=u'getticket', jobid=jobid, use_cjt=True) checkCloudPrintResult(result)
result = callGAPI(service=cp.jobs(), function=u'update', jobid=jobid, semantic_state_diff=ssd) print u'Printed job %s to %s' % (jobid, fileName)
checkCloudPrintResult(result)
print u'Printed job %s to %s' % (jobid, fileName)
def doDelPrinter(): def doDelPrinter():
cp = buildGAPIObject(u'cloudprint') cp = buildGAPIObject(u'cloudprint')
@ -2331,9 +2366,7 @@ def doPrintJobSubmit():
mimetype = mimetypes.guess_type(filepath)[0] mimetype = mimetypes.guess_type(filepath)[0]
if mimetype == None: if mimetype == None:
mimetype = u'application/octet-stream' mimetype = u'application/octet-stream'
f = open(filepath, 'rb') filecontent = readFile(filepath)
filecontent = f.read()
f.close()
form_files[u'content'] = {u'filename': content, u'content': filecontent, u'mimetype': mimetype} form_files[u'content'] = {u'filename': content, u'content': filecontent, u'mimetype': mimetype}
#result = callGAPI(service=cp.printers(), function=u'submit', body=body) #result = callGAPI(service=cp.printers(), function=u'submit', body=body)
body, headers = encode_multipart(form_fields, form_files) body, headers = encode_multipart(form_fields, form_files)
@ -2641,9 +2674,8 @@ def doPhoto(users):
continue continue
else: else:
try: try:
f = open(filename, 'rb') with open(filename, 'rb') as f:
image_data = f.read() image_data = f.read()
f.close()
except IOError, e: except IOError, e:
print u' couldn\'t open %s: %s' % (filename, e.strerror) print u' couldn\'t open %s: %s' % (filename, e.strerror)
continue continue
@ -2675,9 +2707,7 @@ def getPhoto(users):
except KeyError: except KeyError:
print u' no photo for %s' % user print u' no photo for %s' % user
continue continue
photo_file = open(filename, 'wb') writeFile(filename, photo_data, continueOnError=True)
photo_file.write(photo_data)
photo_file.close()
def deletePhoto(users): def deletePhoto(users):
cd = buildGAPIObject(u'directory') cd = buildGAPIObject(u'directory')
@ -3025,13 +3055,21 @@ def showDriveFiles(users):
elif attrib_type is unicode or attrib_type is bool: elif attrib_type is unicode or attrib_type is bool:
a_file[attrib] = f_file[attrib] a_file[attrib] = f_file[attrib]
elif attrib_type is dict: elif attrib_type is dict:
for dict_attrib in f_file[attrib]: if attrib == u'labels':
if dict_attrib in [u'kind', u'etags', u'etag']: for dict_attrib in f_file[attrib]:
continue if dict_attrib not in titles:
if dict_attrib not in titles: titles.append(dict_attrib)
titles.append(dict_attrib) files_attr[0][dict_attrib] = dict_attrib
files_attr[0][dict_attrib] = dict_attrib a_file[dict_attrib] = f_file[attrib][dict_attrib]
a_file[dict_attrib] = f_file[attrib][dict_attrib] else:
for dict_attrib in f_file[attrib]:
if dict_attrib in [u'kind', u'etags', u'etag']:
continue
x_attrib = u'{0}.{1}'.format(attrib, dict_attrib)
if x_attrib not in titles:
titles.append(x_attrib)
files_attr[0][x_attrib] = x_attrib
a_file[x_attrib] = f_file[attrib][dict_attrib]
else: else:
print attrib_type print attrib_type
files_attr.append(a_file) files_attr.append(a_file)
@ -3492,9 +3530,7 @@ def downloadDriveFile(users):
filename = new_filename filename = new_filename
print convertUTF8(my_line % filename) print convertUTF8(my_line % filename)
_, content = drive._http.request(download_url) _, content = drive._http.request(download_url)
f = open(filename, 'wb') writeFile(filename, content, continueOnError=True)
f.write(content)
f.close()
def showDriveFileInfo(users): def showDriveFileInfo(users):
for user in users: for user in users:
@ -3516,7 +3552,7 @@ def showDriveFileInfo(users):
if setti == u'kind': if setti == u'kind':
continue continue
print convertUTF8(u' %s: %s' % (setti, settin[setti])) print convertUTF8(u' %s: %s' % (setti, settin[setti]))
print '' print u''
elif setting_type == u"<type 'dict'>": elif setting_type == u"<type 'dict'>":
print u'%s:' % setting print u'%s:' % setting
for settin in feed[setting]: for settin in feed[setting]:
@ -4384,9 +4420,7 @@ def getForward(users):
def doSignature(users): def doSignature(users):
import cgi import cgi
if sys.argv[4].lower() == u'file': if sys.argv[4].lower() == u'file':
fp = open(sys.argv[5], 'rb') signature = cgi.escape(readFile(sys.argv[5]).replace(u'\\n', u'&#xA;').replace(u'"', u"'"))
signature = cgi.escape(fp.read().replace(u'\\n', u'&#xA;').replace(u'"', u"'"))
fp.close()
else: else:
signature = cgi.escape(sys.argv[4]).replace(u'\\n', u'&#xA;').replace(u'"', u"'") signature = cgi.escape(sys.argv[4]).replace(u'\\n', u'&#xA;').replace(u'"', u"'")
xmlsig = u'''<?xml version="1.0" encoding="utf-8"?> xmlsig = u'''<?xml version="1.0" encoding="utf-8"?>
@ -4476,9 +4510,7 @@ def doVacation(users):
end_date = sys.argv[i+1] end_date = sys.argv[i+1]
i += 2 i += 2
elif sys.argv[i].lower() == u'file': elif sys.argv[i].lower() == u'file':
fp = open(sys.argv[i+1], 'rb') message = readFile(sys.argv[i+1])
message = fp.read()
fp.close()
i += 2 i += 2
else: else:
print u'ERROR: %s is not a valid argument for "gam <users> vacation"' % sys.argv[i] print u'ERROR: %s is not a valid argument for "gam <users> vacation"' % sys.argv[i]
@ -4916,9 +4948,6 @@ def doCreateUser():
except KeyError: except KeyError:
body[u'externalIds'] = [externalid,] body[u'externalIds'] = [externalid,]
i += 1 i += 1
# else:
# showUsage()
# sys.exit(2)
else: else:
if u'customSchemas' not in body: if u'customSchemas' not in body:
body[u'customSchemas'] = {} body[u'customSchemas'] = {}
@ -5963,7 +5992,7 @@ def doGetUserInfo(user_email=None):
for address in user[u'addresses']: for address in user[u'addresses']:
for key in address: for key in address:
print convertUTF8(u' %s: %s' % (key, address[key])) print convertUTF8(u' %s: %s' % (key, address[key]))
print '' print u''
if u'organizations' in user: if u'organizations' in user:
print u'Organizations:' print u'Organizations:'
for org in user[u'organizations']: for org in user[u'organizations']:
@ -6265,9 +6294,7 @@ def doSiteVerifyShow():
webserver_file_record = callGAPI(service=verif.webResource(), function=u'getToken', body={u'site':{u'type':u'SITE', u'identifier':u'http://%s/' % a_domain}, u'verificationMethod':u'FILE'}) webserver_file_record = callGAPI(service=verif.webResource(), function=u'getToken', body={u'site':{u'type':u'SITE', u'identifier':u'http://%s/' % a_domain}, u'verificationMethod':u'FILE'})
webserver_file_token = webserver_file_record[u'token'] webserver_file_token = webserver_file_record[u'token']
print u'Saving web server verification file to: %s' % webserver_file_token print u'Saving web server verification file to: %s' % webserver_file_token
f = open(webserver_file_token, 'wb') writeFile(webserver_file_token, u'google-site-verification: {0}'.format(webserver_file_token), continueOnError=True)
f.write(u'google-site-verification: %s' % webserver_file_token)
f.close()
print u'Verification File URL: http://%s/%s' % (a_domain, webserver_file_token) print u'Verification File URL: http://%s/%s' % (a_domain, webserver_file_token)
print print
webserver_meta_record = callGAPI(service=verif.webResource(), function=u'getToken', body={u'site':{u'type':u'SITE', u'identifier':u'http://%s/' % a_domain}, u'verificationMethod':u'META'}) webserver_meta_record = callGAPI(service=verif.webResource(), function=u'getToken', body={u'site':{u'type':u'SITE', u'identifier':u'http://%s/' % a_domain}, u'verificationMethod':u'META'})
@ -6472,7 +6499,7 @@ def doGenBackupCodes(users):
callGAPI(service=cd.verificationCodes(), function=u'generate', userKey=user) callGAPI(service=cd.verificationCodes(), function=u'generate', userKey=user)
codes = callGAPI(service=cd.verificationCodes(), function=u'list', userKey=user) codes = callGAPI(service=cd.verificationCodes(), function=u'list', userKey=user)
print u'Backup verification codes for %s' % user print u'Backup verification codes for %s' % user
print '' print u''
try: try:
i = 0 i = 0
while True: while True:
@ -6537,7 +6564,7 @@ def doGetTokens(users):
print u' %s: %s' % (item, token[item]) print u' %s: %s' % (item, token[item])
except UnicodeEncodeError: except UnicodeEncodeError:
print u' %s: %s' % (item, token[item][:-1]) print u' %s: %s' % (item, token[item][:-1])
print '' print u''
except KeyError: except KeyError:
print u' no tokens for %s' % user print u' no tokens for %s' % user
print u'' print u''
@ -6593,15 +6620,9 @@ def doUpdateInstance():
admin_secondary_email = sys.argv[4] admin_secondary_email = sys.argv[4]
callGData(service=adminObj, function=u'UpdateAdminSecondaryEmail', adminSecondaryEmail=admin_secondary_email) callGData(service=adminObj, function=u'UpdateAdminSecondaryEmail', adminSecondaryEmail=admin_secondary_email)
elif command == u'logo': elif command == u'logo':
logo_file = sys.argv[4] logoFile = sys.argv[4]
try: logoImage = readFile(logoFile)
fp = open(logo_file, 'rb') callGData(service=adminObj, function=u'UpdateDomainLogo', logoImage=logoImage)
logo_image = fp.read()
fp.close()
except IOError:
print u'Error: can\'t open file %s' % logo_file
sys.exit(11)
callGData(service=adminObj, function=u'UpdateDomainLogo', logoImage=logo_image)
elif command == u'mx_verify': elif command == u'mx_verify':
result = callGData(service=adminObj, function=u'UpdateMXVerificationStatus') result = callGData(service=adminObj, function=u'UpdateMXVerificationStatus')
print u'Verification Method: %s' % result[u'verificationMethod'] print u'Verification Method: %s' % result[u'verificationMethod']
@ -6645,15 +6666,9 @@ def doUpdateInstance():
sys.exit(2) sys.exit(2)
callGData(service=adminObj, function=u'UpdateSSOSettings', enableSSO=enableSSO, samlSignonUri=samlSignonUri, samlLogoutUri=samlLogoutUri, changePasswordUri=changePasswordUri, ssoWhitelist=ssoWhitelist, useDomainSpecificIssuer=useDomainSpecificIssuer) callGData(service=adminObj, function=u'UpdateSSOSettings', enableSSO=enableSSO, samlSignonUri=samlSignonUri, samlLogoutUri=samlLogoutUri, changePasswordUri=changePasswordUri, ssoWhitelist=ssoWhitelist, useDomainSpecificIssuer=useDomainSpecificIssuer)
elif command == u'sso_key': elif command == u'sso_key':
key_file = sys.argv[4] keyFile = sys.argv[4]
try: keyData = readFile(keyFile)
fp = open(key_file, 'rb') callGData(service=adminObj, function=u'UpdateSSOKey', signingKey=keyData)
key_data = fp.read()
fp.close()
except IOError:
print u'Error: can\'t open file %s' % logo_file
sys.exit(11)
callGData(service=adminObj, function=u'UpdateSSOKey', signingKey=key_data)
elif command == u'user_migrations': elif command == u'user_migrations':
value = sys.argv[4].lower() value = sys.argv[4].lower()
if value not in [u'true', u'false']: if value not in [u'true', u'false']:
@ -6729,7 +6744,7 @@ def doGetInstanceInfo():
target_file = sys.argv[4] target_file = sys.argv[4]
url = 'http://www.google.com/a/cpanel/%s/images/logo.gif' % (domain) url = 'http://www.google.com/a/cpanel/%s/images/logo.gif' % (domain)
geturl(url, target_file) geturl(url, target_file)
sys.exit(0) return
print u'Google Apps Domain: %s' % domain print u'Google Apps Domain: %s' % domain
cd = buildGAPIObject(u'directory') cd = buildGAPIObject(u'directory')
if customerId != MY_CUSTOMER: if customerId != MY_CUSTOMER:
@ -6920,7 +6935,6 @@ def doDeleteOrg():
def output_csv(csv_list, titles, list_type, todrive): def output_csv(csv_list, titles, list_type, todrive):
csv.register_dialect(u'nixstdout', lineterminator=u'\n') csv.register_dialect(u'nixstdout', lineterminator=u'\n')
if todrive: if todrive:
import StringIO
string_file = StringIO.StringIO() string_file = StringIO.StringIO()
writer = csv.DictWriter(string_file, fieldnames=titles, dialect=u'nixstdout', quoting=csv.QUOTE_MINIMAL) writer = csv.DictWriter(string_file, fieldnames=titles, dialect=u'nixstdout', quoting=csv.QUOTE_MINIMAL)
else: else:
@ -7908,7 +7922,7 @@ def doStatusActivityRequests():
print u' Url%s: %s' % (i, results[u'fileUrl%s' % i]) print u' Url%s: %s' % (i, results[u'fileUrl%s' % i])
except KeyError: except KeyError:
pass pass
print '' print u''
except IndexError: except IndexError:
results = callGData(service=audit, function=u'getAllAccountInformationRequestsStatus') results = callGData(service=audit, function=u'getAllAccountInformationRequestsStatus')
print u'Current Activity Requests:' print u'Current Activity Requests:'
@ -8350,8 +8364,7 @@ def doDeleteOAuth():
try: try:
credentials.revoke_uri = oauth2client.GOOGLE_REVOKE_URI credentials.revoke_uri = oauth2client.GOOGLE_REVOKE_URI
except AttributeError: except AttributeError:
print u'Error: Authorization doesn\'t exist' systemErrorExit(1, u'Authorization doesn\'t exist')
sys.exit(1)
disable_ssl_certificate_validation = False disable_ssl_certificate_validation = False
if os.path.isfile(os.path.join(gamUserConfigDir, u'noverifyssl.txt')): if os.path.isfile(os.path.join(gamUserConfigDir, u'noverifyssl.txt')):
disable_ssl_certificate_validation = True disable_ssl_certificate_validation = True
@ -8368,7 +8381,7 @@ def doDeleteOAuth():
try: try:
credentials.revoke(http) credentials.revoke(http)
except oauth2client.client.TokenRevokeError, e: except oauth2client.client.TokenRevokeError, e:
print u'Error: %s' % e sys.stderr.write(u'{0}{1}\n'.format(ERROR_PREFIX, e.message))
os.remove(oauth2file) os.remove(oauth2file)
class cmd_flags(object): class cmd_flags(object):
@ -8555,6 +8568,8 @@ def batch_worker():
q.task_done() q.task_done()
def run_batch(items): def run_batch(items):
import Queue, threading
global q
total_items = len(items) total_items = len(items)
current_item = 0 current_item = 0
python_cmd = [sys.executable.lower(),] python_cmd = [sys.executable.lower(),]
@ -8564,8 +8579,7 @@ def run_batch(items):
num_worker_threads = int(os.environ.get(u'GAM_THREADS', '5')) num_worker_threads = int(os.environ.get(u'GAM_THREADS', '5'))
except TypeError: except TypeError:
num_worker_threads = 5 num_worker_threads = 5
import Queue, threading num_worker_threads = min(total_items, num_worker_threads)
global q
q = Queue.Queue(maxsize=num_worker_threads) # q.put() gets blocked when trying to create more items than there are workers q = Queue.Queue(maxsize=num_worker_threads) # q.put() gets blocked when trying to create more items than there are workers
print u'starting %s worker threads...' % num_worker_threads print u'starting %s worker threads...' % num_worker_threads
for i in range(num_worker_threads): for i in range(num_worker_threads):
@ -8591,10 +8605,9 @@ try:
if os.name == u'nt': if os.name == u'nt':
sys.argv = win32_unicode_argv() # cleanup sys.argv on Windows sys.argv = win32_unicode_argv() # cleanup sys.argv on Windows
setGamDirs() setGamDirs()
doGAMCheckForUpdates()
if sys.argv[1].lower() == u'batch': if sys.argv[1].lower() == u'batch':
import shlex import shlex
f = file(sys.argv[2], 'rb') f = openFile(sys.argv[2])
items = list() items = list()
for line in f: for line in f:
argv = shlex.split(line) argv = shlex.split(line)
@ -8606,16 +8619,12 @@ try:
if argv[0] == u'gam': if argv[0] == u'gam':
argv = argv[1:] argv = argv[1:]
items.append(argv) items.append(argv)
closeFile(f)
run_batch(items) run_batch(items)
sys.exit(0) sys.exit(0)
elif sys.argv[1].lower() == u'csv': elif sys.argv[1].lower() == u'csv':
csv_filename = sys.argv[2] csv_filename = sys.argv[2]
if csv_filename == u'-': f = openFile(csv_filename)
import StringIO
input_string = unicode(sys.stdin.read())
f = StringIO.StringIO(input_string)
else:
f = file(csv_filename, 'rb')
input_file = csv.DictReader(f) input_file = csv.DictReader(f)
if sys.argv[3].lower() != 'gam': if sys.argv[3].lower() != 'gam':
print 'ERROR: "gam csv <filename>" should be followed by a full GAM command...' print 'ERROR: "gam csv <filename>" should be followed by a full GAM command...'
@ -8632,6 +8641,7 @@ try:
else: else:
systemErrorExit(2, MESSAGE_HEADER_NOT_FOUND_IN_CSV_HEADERS.format(arg[1:], ','.join(row.keys()))) systemErrorExit(2, MESSAGE_HEADER_NOT_FOUND_IN_CSV_HEADERS.format(arg[1:], ','.join(row.keys())))
items.append(argv) items.append(argv)
closeFile(f)
run_batch(items) run_batch(items)
sys.exit(0) sys.exit(0)
elif sys.argv[1].lower() == u'version': elif sys.argv[1].lower() == u'version':