Phase 5b - SetGlobalVariables modernization and single func size reduction

This commit is contained in:
Jay Lee
2026-07-04 14:06:19 -04:00
parent 7d6dffc138
commit 0e1505f210
2 changed files with 802 additions and 761 deletions

View File

@@ -217,6 +217,23 @@ def _getIAMSigner(service_account_info):
return google.auth.iam.Signer(request, credentials, return google.auth.iam.Signer(request, credentials,
service_account_info['client_email']) service_account_info['client_email'])
def _getSigner(service_account_info):
'''Return a signer for the given key_type, or None for default keys.
key_type is read from service_account_info:
- "default": Returns None (caller should use from_service_account_info)
- "yubikey": Returns a YubiKey hardware signer
- "signjwt": Returns an IAM signBlob signer via ADC
'''
key_type = service_account_info.get('key_type', 'default')
if key_type == 'default':
return None
if key_type == 'yubikey':
return yubikey.YubiKey(service_account_info)
if key_type == 'signjwt':
return _getIAMSigner(service_account_info)
return None
def handleOAuthTokenError(e, softErrors, displayError=False, i=0, count=0): def handleOAuthTokenError(e, softErrors, displayError=False, i=0, count=0):
errMsg = str(e).replace('.', '') errMsg = str(e).replace('.', '')
if ((errMsg in API.OAUTH2_TOKEN_ERRORS) or if ((errMsg in API.OAUTH2_TOKEN_ERRORS) or
@@ -258,15 +275,10 @@ def getOauth2TxtCredentials(exitOnError=True, api=None, noDASA=False, refreshOnl
jsonDict = json.loads(jsonData) jsonDict = json.loads(jsonData)
api, _, _ = API.getVersion(api) api, _, _ = API.getVersion(api)
audience = f'https://{api}.googleapis.com/' audience = f'https://{api}.googleapis.com/'
key_type = jsonDict.get('key_type', 'default') signer = _getSigner(jsonDict)
if key_type == 'default': if signer is None:
return (True, JWTCredentials.from_service_account_info(jsonDict, audience=audience)) return (True, JWTCredentials.from_service_account_info(jsonDict, audience=audience))
if key_type == 'yubikey': return (True, JWTCredentials._from_signer_and_info(signer, jsonDict, audience=audience))
yksigner = yubikey.YubiKey(jsonDict)
return (True, JWTCredentials._from_signer_and_info(yksigner, jsonDict, audience=audience))
if key_type == 'signjwt':
sjsigner = _getIAMSigner(jsonDict)
return (True, JWTCredentials._from_signer_and_info(sjsigner, jsonDict, audience=audience))
except (IndexError, KeyError, SyntaxError, TypeError, ValueError) as e: except (IndexError, KeyError, SyntaxError, TypeError, ValueError) as e:
invalidOauth2serviceJsonExit(str(e)) invalidOauth2serviceJsonExit(str(e))
invalidOauth2serviceJsonExit(Msg.NO_DATA) invalidOauth2serviceJsonExit(Msg.NO_DATA)
@@ -615,19 +627,14 @@ def getSvcAcctCredentials(scopesOrAPI, userEmail, softErrors=False, forceOauth=F
else: else:
GM.Globals[GM.CURRENT_SVCACCT_API] = '' GM.Globals[GM.CURRENT_SVCACCT_API] = ''
GM.Globals[GM.CURRENT_SVCACCT_API_SCOPES] = scopesOrAPI GM.Globals[GM.CURRENT_SVCACCT_API_SCOPES] = scopesOrAPI
key_type = GM.Globals[GM.OAUTH2SERVICE_JSON_DATA].get('key_type', 'default') svcacct_info = GM.Globals[GM.OAUTH2SERVICE_JSON_DATA]
signer = _getSigner(svcacct_info)
if not GM.Globals[GM.CURRENT_SVCACCT_API] or scopesOrAPI not in API.JWT_APIS or forceOauth: if not GM.Globals[GM.CURRENT_SVCACCT_API] or scopesOrAPI not in API.JWT_APIS or forceOauth:
try: try:
if key_type == 'default': if signer is None:
credentials = google.oauth2.service_account.Credentials.from_service_account_info(GM.Globals[GM.OAUTH2SERVICE_JSON_DATA]) credentials = google.oauth2.service_account.Credentials.from_service_account_info(svcacct_info)
elif key_type == 'yubikey': else:
yksigner = yubikey.YubiKey(GM.Globals[GM.OAUTH2SERVICE_JSON_DATA]) credentials = google.oauth2.service_account.Credentials._from_signer_and_info(signer, svcacct_info)
credentials = google.oauth2.service_account.Credentials._from_signer_and_info(yksigner,
GM.Globals[GM.OAUTH2SERVICE_JSON_DATA])
elif key_type == 'signjwt':
sjsigner = _getIAMSigner(GM.Globals[GM.OAUTH2SERVICE_JSON_DATA])
credentials = google.oauth2.service_account.Credentials._from_signer_and_info(sjsigner,
GM.Globals[GM.OAUTH2SERVICE_JSON_DATA])
except (ValueError, IndexError, KeyError) as e: except (ValueError, IndexError, KeyError) as e:
if softErrors: if softErrors:
return None return None
@@ -636,19 +643,10 @@ def getSvcAcctCredentials(scopesOrAPI, userEmail, softErrors=False, forceOauth=F
else: else:
audience = f'https://{scopesOrAPI}.googleapis.com/' audience = f'https://{scopesOrAPI}.googleapis.com/'
try: try:
if key_type == 'default': if signer is None:
credentials = JWTCredentials.from_service_account_info(GM.Globals[GM.OAUTH2SERVICE_JSON_DATA], credentials = JWTCredentials.from_service_account_info(svcacct_info, audience=audience)
audience=audience) else:
elif key_type == 'yubikey': credentials = JWTCredentials._from_signer_and_info(signer, svcacct_info, audience=audience)
yksigner = yubikey.YubiKey(GM.Globals[GM.OAUTH2SERVICE_JSON_DATA])
credentials = JWTCredentials._from_signer_and_info(yksigner,
GM.Globals[GM.OAUTH2SERVICE_JSON_DATA],
audience=audience)
elif key_type == 'signjwt':
sjsigner = _getIAMSigner(GM.Globals[GM.OAUTH2SERVICE_JSON_DATA])
credentials = JWTCredentials._from_signer_and_info(sjsigner,
GM.Globals[GM.OAUTH2SERVICE_JSON_DATA],
audience=audience)
credentials.project_id = GM.Globals[GM.OAUTH2SERVICE_JSON_DATA]['project_id'] credentials.project_id = GM.Globals[GM.OAUTH2SERVICE_JSON_DATA]['project_id']
except (ValueError, IndexError, KeyError) as e: except (ValueError, IndexError, KeyError) as e:
if softErrors: if softErrors:

View File

@@ -60,19 +60,29 @@ from gam.constants import (
FN_GAM_CFG, GAM, FN_GAM_CFG, GAM,
) )
REGEX_CHARS = '^$*+|$[{('
def SetGlobalVariables(): ROW_FILTER_ANY_ALL_PATTERN = re.compile(r'^(any:|all:)(.+)$', re.IGNORECASE)
ROW_FILTER_COMP_PATTERN = re.compile(r'^(date|time|count|length|number)\s*([<>]=?|=|!=)(.+)$', re.IGNORECASE)
ROW_FILTER_RANGE_PATTERN = re.compile(r'^(daterange|timerange|countrange|lengthrange|numberrange)(=|!=)(\S+)/(\S+)$', re.IGNORECASE)
ROW_FILTER_TIMEOFDAYRANGE_PATTERN = re.compile(r'^(timeofdayrange)(=|!=)(\d\d):(\d\d)/(\d\d):(\d\d)$', re.IGNORECASE)
ROW_FILTER_BOOL_PATTERN = re.compile(r'^(boolean):(.+)$', re.IGNORECASE)
ROW_FILTER_TEXT_PATTERN = re.compile(r'^(text)([<>]=?|=|!=)(.*)$', re.IGNORECASE)
ROW_FILTER_TEXTRANGE_PATTERN = re.compile(r'^(textrange)(=|!=)(.*)/(.*)$', re.IGNORECASE)
ROW_FILTER_RE_PATTERN = re.compile(r'^(regex|regexcs|notregex|notregexcs):(.*)$', re.IGNORECASE)
ROW_FILTER_DATA_PATTERN = re.compile(r'^(data|notdata):(list|file|csvfile) +(.+)$', re.IGNORECASE)
MULTIPROCESS_EXIT_COMP_PATTERN = re.compile(r'^rc([<>]=?|=|!=)(.+)$', re.IGNORECASE)
MULTIPROCESS_EXIT_RANGE_PATTERN = re.compile(r'^rcrange(=|!=)(\S+)/(\S+)$', re.IGNORECASE)
def _stringInQuotes(value): def _stringInQuotes(value):
return (len(value) > 1) and (((value.startswith('"') and value.endswith('"'))) or ((value.startswith("'") and value.endswith("'")))) return (len(value) > 1) and (((value.startswith('"') and value.endswith('"'))) or ((value.startswith("'") and value.endswith("'"))))
def _stripStringQuotes(value): def _stripStringQuotes(value):
if _stringInQuotes(value): if _stringInQuotes(value):
return value[1:-1] return value[1:-1]
return value return value
def _quoteStringIfLeadingTrailingBlanks(value): def _quoteStringIfLeadingTrailingBlanks(value):
if not value: if not value:
return "''" return "''"
if _stringInQuotes(value): if _stringInQuotes(value):
@@ -81,7 +91,7 @@ def SetGlobalVariables():
return value return value
return f"'{value}'" return f"'{value}'"
def _getDefault(itemName, itemEntry, oldGamPath): def _getDefault(itemName, itemEntry, oldGamPath):
if GC.VAR_SIGFILE in itemEntry: if GC.VAR_SIGFILE in itemEntry:
GC.Defaults[itemName] = itemEntry[GC.VAR_SFFT][os.path.isfile(os.path.join(oldGamPath, itemEntry[GC.VAR_SIGFILE]))] GC.Defaults[itemName] = itemEntry[GC.VAR_SFFT][os.path.isfile(os.path.join(oldGamPath, itemEntry[GC.VAR_SIGFILE]))]
elif GC.VAR_ENVVAR in itemEntry: elif GC.VAR_ENVVAR in itemEntry:
@@ -101,7 +111,7 @@ def SetGlobalVariables():
value = _quoteStringIfLeadingTrailingBlanks(value) value = _quoteStringIfLeadingTrailingBlanks(value)
GC.Defaults[itemName] = value GC.Defaults[itemName] = value
def _selectSection(): def _selectSection():
value = getString(Cmd.OB_SECTION_NAME, minLen=0) value = getString(Cmd.OB_SECTION_NAME, minLen=0)
if (not value) or (value.upper() == configparser.DEFAULTSECT): if (not value) or (value.upper() == configparser.DEFAULTSECT):
return configparser.DEFAULTSECT return configparser.DEFAULTSECT
@@ -110,14 +120,14 @@ def SetGlobalVariables():
Cmd.Backup() Cmd.Backup()
usageErrorExit(formatKeyValueList('', [Ent.Singular(Ent.SECTION), value, Msg.NOT_FOUND], '')) usageErrorExit(formatKeyValueList('', [Ent.Singular(Ent.SECTION), value, Msg.NOT_FOUND], ''))
def _showSections(): def _showSections(sectionName):
printKeyValueList([Ent.Singular(Ent.CONFIG_FILE), GM.Globals[GM.GAM_CFG_FILE]]) printKeyValueList([Ent.Singular(Ent.CONFIG_FILE), GM.Globals[GM.GAM_CFG_FILE]])
Ind.Increment() Ind.Increment()
for section in [configparser.DEFAULTSECT]+sorted(GM.Globals[GM.PARSER].sections()): for section in [configparser.DEFAULTSECT]+sorted(GM.Globals[GM.PARSER].sections()):
printKeyValueList([f'{section}{" *" if section == sectionName else ""}']) printKeyValueList([f'{section}{" *" if section == sectionName else ""}'])
Ind.Decrement() Ind.Decrement()
def _checkMakeDir(itemName): def _checkMakeDir(itemName):
if not os.path.isdir(GC.Defaults[itemName]): if not os.path.isdir(GC.Defaults[itemName]):
try: try:
os.makedirs(GC.Defaults[itemName]) os.makedirs(GC.Defaults[itemName])
@@ -126,7 +136,7 @@ def SetGlobalVariables():
if not os.path.isdir(GC.Defaults[itemName]): if not os.path.isdir(GC.Defaults[itemName]):
systemErrorExit(FILE_ERROR_RC, e) systemErrorExit(FILE_ERROR_RC, e)
def _copyCfgFile(srcFile, targetDir, oldGamPath): def _copyCfgFile(srcFile, targetDir, oldGamPath):
if (not srcFile) or os.path.isabs(srcFile): if (not srcFile) or os.path.isabs(srcFile):
return return
dstFile = os.path.join(GC.Defaults[targetDir], srcFile) dstFile = os.path.join(GC.Defaults[targetDir], srcFile)
@@ -139,7 +149,7 @@ def SetGlobalVariables():
if (data is not None) and writeFile(dstFile, data, continueOnError=True): if (data is not None) and writeFile(dstFile, data, continueOnError=True):
printKeyValueList([Act.PerformedName(Act.COPY), srcFile, Msg.TO, dstFile]) printKeyValueList([Act.PerformedName(Act.COPY), srcFile, Msg.TO, dstFile])
def _printValueError(sectionName, itemName, value, errMessage, sysRC=CONFIG_ERROR_RC): def _printValueError(status, sectionName, itemName, value, errMessage, sysRC=CONFIG_ERROR_RC):
kvlMsg = formatKeyValueList('', kvlMsg = formatKeyValueList('',
[Ent.Singular(Ent.CONFIG_FILE), GM.Globals[GM.GAM_CFG_FILE], [Ent.Singular(Ent.CONFIG_FILE), GM.Globals[GM.GAM_CFG_FILE],
Ent.Singular(Ent.SECTION), sectionName, Ent.Singular(Ent.SECTION), sectionName,
@@ -153,16 +163,16 @@ def SetGlobalVariables():
else: else:
writeStderr(formatKeyValueList(Ind.Spaces(), [WARNING, kvlMsg], '\n')) writeStderr(formatKeyValueList(Ind.Spaces(), [WARNING, kvlMsg], '\n'))
def _getCfgBoolean(sectionName, itemName): def _getCfgBoolean(status, sectionName, itemName):
value = GM.Globals[GM.PARSER].get(sectionName, itemName).lower() value = GM.Globals[GM.PARSER].get(sectionName, itemName).lower()
if value in TRUE_VALUES: if value in TRUE_VALUES:
return True return True
if value in FALSE_VALUES: if value in FALSE_VALUES:
return False return False
_printValueError(sectionName, itemName, value, f'{Msg.EXPECTED}: {formatChoiceList(TRUE_FALSE)}') _printValueError(status, sectionName, itemName, value, f'{Msg.EXPECTED}: {formatChoiceList(TRUE_FALSE)}')
return False return False
def _getCfgCharacter(sectionName, itemName): def _getCfgCharacter(status, sectionName, itemName):
value = codecs.escape_decode(bytes(_stripStringQuotes(GM.Globals[GM.PARSER].get(sectionName, itemName)), UTF8))[0].decode(UTF8) value = codecs.escape_decode(bytes(_stripStringQuotes(GM.Globals[GM.PARSER].get(sectionName, itemName)), UTF8))[0].decode(UTF8)
if not value and (itemName == 'csv_output_field_delimiter'): if not value and (itemName == 'csv_output_field_delimiter'):
return ' ' return ' '
@@ -170,25 +180,25 @@ def SetGlobalVariables():
return None return None
if len(value) == 1: if len(value) == 1:
return value return value
_printValueError(sectionName, itemName, f'"{value}"', f'{Msg.EXPECTED}: {integerLimits(1, 1, Msg.STRING_LENGTH)}') _printValueError(status, sectionName, itemName, f'"{value}"', f'{Msg.EXPECTED}: {integerLimits(1, 1, Msg.STRING_LENGTH)}')
return '' return ''
def _getCfgChoice(sectionName, itemName): def _getCfgChoice(status, sectionName, itemName):
value = _stripStringQuotes(GM.Globals[GM.PARSER].get(sectionName, itemName)).lower() value = _stripStringQuotes(GM.Globals[GM.PARSER].get(sectionName, itemName)).lower()
choices = GC.VAR_INFO[itemName][GC.VAR_CHOICES] choices = GC.VAR_INFO[itemName][GC.VAR_CHOICES]
if value in choices: if value in choices:
return choices[value] return choices[value]
_printValueError(sectionName, itemName, f'"{value}"', f'{Msg.EXPECTED}: {",".join(choices)}') _printValueError(status, sectionName, itemName, f'"{value}"', f'{Msg.EXPECTED}: {",".join(choices)}')
return '' return ''
def _getCfgLocale(sectionName, itemName): def _getCfgLocale(status, sectionName, itemName):
value = _stripStringQuotes(GM.Globals[GM.PARSER].get(sectionName, itemName)).lower().replace('_', '-') value = _stripStringQuotes(GM.Globals[GM.PARSER].get(sectionName, itemName)).lower().replace('_', '-')
if value in LOCALE_CODES_MAP: if value in LOCALE_CODES_MAP:
return LOCALE_CODES_MAP[value] return LOCALE_CODES_MAP[value]
_printValueError(sectionName, itemName, f'"{value}"', f'{Msg.EXPECTED}: {",".join(LOCALE_CODES_MAP)}') _printValueError(status, sectionName, itemName, f'"{value}"', f'{Msg.EXPECTED}: {",".join(LOCALE_CODES_MAP)}')
return '' return ''
def _getCfgNumber(sectionName, itemName): def _getCfgNumber(status, sectionName, itemName):
value = GM.Globals[GM.PARSER].get(sectionName, itemName) value = GM.Globals[GM.PARSER].get(sectionName, itemName)
minVal, maxVal = GC.VAR_INFO[itemName][GC.VAR_LIMITS] minVal, maxVal = GC.VAR_INFO[itemName][GC.VAR_LIMITS]
try: try:
@@ -199,14 +209,14 @@ def SetGlobalVariables():
number = minVal number = minVal
else: else:
number = maxVal number = maxVal
_printValueError(sectionName, itemName, value, f'{Msg.EXPECTED}: {integerLimits(minVal, maxVal)}, {Msg.USED}: {number}', sysRC=0) _printValueError(status, sectionName, itemName, value, f'{Msg.EXPECTED}: {integerLimits(minVal, maxVal)}, {Msg.USED}: {number}', sysRC=0)
return number return number
except ValueError: except ValueError:
pass pass
_printValueError(sectionName, itemName, value, f'{Msg.EXPECTED}: {integerLimits(minVal, maxVal)}') _printValueError(status, sectionName, itemName, value, f'{Msg.EXPECTED}: {integerLimits(minVal, maxVal)}')
return 0 return 0
def _getCfgHeaderFilter(sectionName, itemName): def _getCfgHeaderFilter(status, sectionName, itemName):
value = GM.Globals[GM.PARSER].get(sectionName, itemName) value = GM.Globals[GM.PARSER].get(sectionName, itemName)
headerFilters = [] headerFilters = []
if not value or (len(value) == 2 and _stringInQuotes(value)): if not value or (len(value) == 2 and _stringInQuotes(value)):
@@ -217,32 +227,22 @@ def SetGlobalVariables():
try: try:
headerFilters.append(re.compile(filterStr, re.IGNORECASE)) headerFilters.append(re.compile(filterStr, re.IGNORECASE))
except re.error as e: except re.error as e:
_printValueError(sectionName, itemName, f'"{filterStr}"', f'{Msg.INVALID_RE}: {e}') _printValueError(status, sectionName, itemName, f'"{filterStr}"', f'{Msg.INVALID_RE}: {e}')
else: else:
_printValueError(sectionName, itemName, f'"{value}"', f'{Msg.INVALID_LIST}: {filters}') _printValueError(status, sectionName, itemName, f'"{value}"', f'{Msg.INVALID_LIST}: {filters}')
return headerFilters return headerFilters
def _getCfgHeaderFilterFromForce(sectionName, itemName): def _getCfgHeaderFilterFromForce(status, sectionName, itemName):
headerFilters = [] headerFilters = []
for filterStr in GC.Values[itemName]: for filterStr in GC.Values[itemName]:
try: try:
headerFilters.append(re.compile(fr'^{filterStr}$')) headerFilters.append(re.compile(fr'^{filterStr}$'))
except re.error as e: except re.error as e:
_printValueError(sectionName, itemName, f'"{filterStr}"', f'{Msg.INVALID_RE}: {e}') _printValueError(status, sectionName, itemName, f'"{filterStr}"', f'{Msg.INVALID_RE}: {e}')
return headerFilters return headerFilters
ROW_FILTER_ANY_ALL_PATTERN = re.compile(r'^(any:|all:)(.+)$', re.IGNORECASE)
ROW_FILTER_COMP_PATTERN = re.compile(r'^(date|time|count|length|number)\s*([<>]=?|=|!=)(.+)$', re.IGNORECASE)
ROW_FILTER_RANGE_PATTERN = re.compile(r'^(daterange|timerange|countrange|lengthrange|numberrange)(=|!=)(\S+)/(\S+)$', re.IGNORECASE)
ROW_FILTER_TIMEOFDAYRANGE_PATTERN = re.compile(r'^(timeofdayrange)(=|!=)(\d\d):(\d\d)/(\d\d):(\d\d)$', re.IGNORECASE)
ROW_FILTER_BOOL_PATTERN = re.compile(r'^(boolean):(.+)$', re.IGNORECASE)
ROW_FILTER_TEXT_PATTERN = re.compile(r'^(text)([<>]=?|=|!=)(.*)$', re.IGNORECASE)
ROW_FILTER_TEXTRANGE_PATTERN = re.compile(r'^(textrange)(=|!=)(.*)/(.*)$', re.IGNORECASE)
ROW_FILTER_RE_PATTERN = re.compile(r'^(regex|regexcs|notregex|notregexcs):(.*)$', re.IGNORECASE)
ROW_FILTER_DATA_PATTERN = re.compile(r'^(data|notdata):(list|file|csvfile) +(.+)$', re.IGNORECASE)
REGEX_CHARS = '^$*+|$[{('
def _getCfgRowFilter(sectionName, itemName): def _getCfgRowFilter(status, sectionName, itemName):
value = GM.Globals[GM.PARSER].get(sectionName, itemName) value = GM.Globals[GM.PARSER].get(sectionName, itemName)
rowFilters = [] rowFilters = []
if not value: if not value:
@@ -251,13 +251,13 @@ def SetGlobalVariables():
try: try:
filterDict = json.loads(value.encode('unicode-escape').decode(UTF8)) filterDict = json.loads(value.encode('unicode-escape').decode(UTF8))
except (IndexError, KeyError, SyntaxError, TypeError, ValueError) as e: except (IndexError, KeyError, SyntaxError, TypeError, ValueError) as e:
_printValueError(sectionName, itemName, f'"{value}"', f'{Msg.FAILED_TO_PARSE_AS_JSON}: {str(e)}') _printValueError(status, sectionName, itemName, f'"{value}"', f'{Msg.FAILED_TO_PARSE_AS_JSON}: {str(e)}')
return rowFilters return rowFilters
else: else:
filterDict = {} filterDict = {}
status, filterList = shlexSplitListStatus(value) splitOk, filterList = shlexSplitListStatus(value)
if not status: if not splitOk:
_printValueError(sectionName, itemName, f'"{value}"', f'{Msg.FAILED_TO_PARSE_AS_LIST}: {str(filterList)}') _printValueError(status, sectionName, itemName, f'"{value}"', f'{Msg.FAILED_TO_PARSE_AS_LIST}: {str(filterList)}')
return rowFilters return rowFilters
for filterVal in filterList: for filterVal in filterList:
if not filterVal: if not filterVal:
@@ -267,7 +267,7 @@ def SetGlobalVariables():
column = filterTokens[0] column = filterTokens[0]
filterStr = ':'.join(filterTokens[1:]) filterStr = ':'.join(filterTokens[1:])
except ValueError: except ValueError:
_printValueError(sectionName, itemName, f'"{filterVal}"', f'{Msg.EXPECTED}: column:filter') _printValueError(status, sectionName, itemName, f'"{filterVal}"', f'{Msg.EXPECTED}: column:filter')
continue continue
filterDict[column] = filterStr filterDict[column] = filterStr
for column, filterStr in filterDict.items(): for column, filterStr in filterDict.items():
@@ -280,7 +280,7 @@ def SetGlobalVariables():
try: try:
columnPat = re.compile(columnPat, re.IGNORECASE) columnPat = re.compile(columnPat, re.IGNORECASE)
except re.error as e: except re.error as e:
_printValueError(sectionName, itemName, f'"{column}"', f'{Msg.INVALID_RE}: {e}') _printValueError(status, sectionName, itemName, f'"{column}"', f'{Msg.INVALID_RE}: {e}')
continue continue
anyMatch = True anyMatch = True
mg = ROW_FILTER_ANY_ALL_PATTERN.match(filterStr) mg = ROW_FILTER_ANY_ALL_PATTERN.match(filterStr)
@@ -298,12 +298,12 @@ def SetGlobalVariables():
if valid: if valid:
rowFilters.append((columnPat, anyMatch, filterType, mg.group(2), filterValue)) rowFilters.append((columnPat, anyMatch, filterType, mg.group(2), filterValue))
else: else:
_printValueError(sectionName, itemName, f'"{column}": "{filterStr}"', f'{Msg.EXPECTED}: {filterValue}') _printValueError(status, sectionName, itemName, f'"{column}": "{filterStr}"', f'{Msg.EXPECTED}: {filterValue}')
else: # filterType in {'count', 'length', 'number'}: else: # filterType in {'count', 'length', 'number'}:
if mg.group(3).isdigit(): if mg.group(3).isdigit():
rowFilters.append((columnPat, anyMatch, filterType, mg.group(2), int(mg.group(3)))) rowFilters.append((columnPat, anyMatch, filterType, mg.group(2), int(mg.group(3))))
else: else:
_printValueError(sectionName, itemName, f'"{column}": "{filterStr}"', f'{Msg.EXPECTED}: <Number>') _printValueError(status, sectionName, itemName, f'"{column}": "{filterStr}"', f'{Msg.EXPECTED}: <Number>')
continue continue
mg = ROW_FILTER_TEXT_PATTERN.match(filterStr) mg = ROW_FILTER_TEXT_PATTERN.match(filterStr)
if mg: if mg:
@@ -328,12 +328,12 @@ def SetGlobalVariables():
if valid1 and valid2: if valid1 and valid2:
rowFilters.append((columnPat, anyMatch, filterType, mg.group(2), filterValue1, filterValue2)) rowFilters.append((columnPat, anyMatch, filterType, mg.group(2), filterValue1, filterValue2))
else: else:
_printValueError(sectionName, itemName, f'"{column}": "{filterStr}"', f'{Msg.EXPECTED}: {filterValue1}/{filterValue2}') _printValueError(status, sectionName, itemName, f'"{column}": "{filterStr}"', f'{Msg.EXPECTED}: {filterValue1}/{filterValue2}')
else: #countrange|lengthrange|numberrange else: #countrange|lengthrange|numberrange
if mg.group(3).isdigit() and mg.group(4).isdigit(): if mg.group(3).isdigit() and mg.group(4).isdigit():
rowFilters.append((columnPat, anyMatch, filterType, mg.group(2), int(mg.group(3)), int(mg.group(4)))) rowFilters.append((columnPat, anyMatch, filterType, mg.group(2), int(mg.group(3)), int(mg.group(4))))
else: else:
_printValueError(sectionName, itemName, f'"{column}": "{filterStr}"', f'{Msg.EXPECTED}: <Number>/<Number>') _printValueError(status, sectionName, itemName, f'"{column}": "{filterStr}"', f'{Msg.EXPECTED}: <Number>/<Number>')
continue continue
mg = ROW_FILTER_TIMEOFDAYRANGE_PATTERN.match(filterStr) mg = ROW_FILTER_TIMEOFDAYRANGE_PATTERN.match(filterStr)
if mg: if mg:
@@ -357,7 +357,7 @@ def SetGlobalVariables():
elif filterValue in FALSE_VALUES: elif filterValue in FALSE_VALUES:
rowFilters.append((columnPat, anyMatch, filterType, False)) rowFilters.append((columnPat, anyMatch, filterType, False))
else: else:
_printValueError(sectionName, itemName, f'"{column}": "{filterStr}"', f'{Msg.EXPECTED}: <Boolean>') _printValueError(status, sectionName, itemName, f'"{column}": "{filterStr}"', f'{Msg.EXPECTED}: <Boolean>')
continue continue
mg = ROW_FILTER_RE_PATTERN.match(filterStr) mg = ROW_FILTER_RE_PATTERN.match(filterStr)
if mg: if mg:
@@ -370,7 +370,7 @@ def SetGlobalVariables():
flags = re.IGNORECASE flags = re.IGNORECASE
rowFilters.append((columnPat, anyMatch, filterType, re.compile(mg.group(2), flags))) rowFilters.append((columnPat, anyMatch, filterType, re.compile(mg.group(2), flags)))
except re.error as e: except re.error as e:
_printValueError(sectionName, itemName, f'"{column}": "{filterStr}"', f'{Msg.INVALID_RE}: {e}') _printValueError(status, sectionName, itemName, f'"{column}": "{filterStr}"', f'{Msg.INVALID_RE}: {e}')
continue continue
mg = ROW_FILTER_DATA_PATTERN.match(filterStr) mg = ROW_FILTER_DATA_PATTERN.match(filterStr)
if mg: if mg:
@@ -386,19 +386,19 @@ def SetGlobalVariables():
rowFilters.append((columnPat, anyMatch, filterType, getEntitiesFromCSVFile(False, returnSet=True))) rowFilters.append((columnPat, anyMatch, filterType, getEntitiesFromCSVFile(False, returnSet=True)))
Cmd.RestoreArguments() Cmd.RestoreArguments()
continue continue
_printValueError(sectionName, itemName, f'"{column}": "{filterStr}"', f'{Msg.EXPECTED}: <RowValueFilter>') _printValueError(status, sectionName, itemName, f'"{column}": "{filterStr}"', f'{Msg.EXPECTED}: <RowValueFilter>')
return rowFilters return rowFilters
def _getCfgSection(sectionName, itemName): def _getCfgSection(status, sectionName, itemName):
value = _stripStringQuotes(GM.Globals[GM.PARSER].get(sectionName, itemName)) value = _stripStringQuotes(GM.Globals[GM.PARSER].get(sectionName, itemName))
if (not value) or (value.upper() == configparser.DEFAULTSECT): if (not value) or (value.upper() == configparser.DEFAULTSECT):
return configparser.DEFAULTSECT return configparser.DEFAULTSECT
if GM.Globals[GM.PARSER].has_section(value): if GM.Globals[GM.PARSER].has_section(value):
return value return value
_printValueError(sectionName, itemName, value, Msg.NOT_FOUND) _printValueError(status, sectionName, itemName, value, Msg.NOT_FOUND)
return configparser.DEFAULTSECT return configparser.DEFAULTSECT
def _getCfgPassword(sectionName, itemName): def _getCfgPassword(status, sectionName, itemName):
value = GM.Globals[GM.PARSER].get(sectionName, itemName) value = GM.Globals[GM.PARSER].get(sectionName, itemName)
if isinstance(value, bytes): if isinstance(value, bytes):
return value return value
@@ -409,59 +409,59 @@ def SetGlobalVariables():
return value return value
return '' return ''
def _validateLicenseSKUs(sectionName, itemName, skuList): def _validateLicenseSKUs(status, sectionName, itemName, skuList):
GM.Globals[GM.LICENSE_SKUS] = [] GM.Globals[GM.LICENSE_SKUS] = []
for sku in skuList.split(','): for sku in skuList.split(','):
if '/' not in sku: if '/' not in sku:
productId, sku = SKU.getProductAndSKU(sku) productId, sku = SKU.getProductAndSKU(sku)
if not productId: if not productId:
_printValueError(sectionName, itemName, sku, f'{Msg.EXPECTED}: {",".join(SKU.getSortedSKUList())}') _printValueError(status, sectionName, itemName, sku, f'{Msg.EXPECTED}: {",".join(SKU.getSortedSKUList())}')
else: else:
(productId, sku) = sku.split('/') (productId, sku) = sku.split('/')
if (productId, sku) not in GM.Globals[GM.LICENSE_SKUS]: if (productId, sku) not in GM.Globals[GM.LICENSE_SKUS]:
GM.Globals[GM.LICENSE_SKUS].append((productId, sku)) GM.Globals[GM.LICENSE_SKUS].append((productId, sku))
def _validateDeveloperPreviewAPIs(sectionName, itemName, apiList): def _validateDeveloperPreviewAPIs(status, sectionName, itemName, apiList):
GM.Globals[GM.DEVELOPER_PREVIEW_APIS] = set() GM.Globals[GM.DEVELOPER_PREVIEW_APIS] = set()
validAPIs = API.getAPIsList() validAPIs = API.getAPIsList()
for api in apiList.split(','): for api in apiList.split(','):
if api in validAPIs: if api in validAPIs:
GM.Globals[GM.DEVELOPER_PREVIEW_APIS].add(api) GM.Globals[GM.DEVELOPER_PREVIEW_APIS].add(api)
else: else:
_printValueError(sectionName, itemName, api, f'{Msg.EXPECTED}: {",".join(sorted(validAPIs))}') _printValueError(status, sectionName, itemName, api, f'{Msg.EXPECTED}: {",".join(sorted(validAPIs))}')
def _validateGCPOrgId(sectionName, itemName, gcpOrgId): def _validateGCPOrgId(status, sectionName, itemName, gcpOrgId):
mg = re.match(r'organizations/\d+', gcpOrgId) mg = re.match(r'organizations/\d+', gcpOrgId)
if not mg: if not mg:
_printValueError(sectionName, itemName, gcpOrgId, f'{Msg.EXPECTED}: "organizations/<Number>"') _printValueError(status, sectionName, itemName, gcpOrgId, f'{Msg.EXPECTED}: "organizations/<Number>"')
def _getCfgString(sectionName, itemName): def _getCfgString(status, sectionName, itemName):
value = _stripStringQuotes(GM.Globals[GM.PARSER].get(sectionName, itemName)) value = _stripStringQuotes(GM.Globals[GM.PARSER].get(sectionName, itemName))
if itemName == GC.DOMAIN: if itemName == GC.DOMAIN:
value = value.strip() value = value.strip()
minLen, maxLen = GC.VAR_INFO[itemName].get(GC.VAR_LIMITS, (None, None)) minLen, maxLen = GC.VAR_INFO[itemName].get(GC.VAR_LIMITS, (None, None))
if ((minLen is None) or (len(value) >= minLen)) and ((maxLen is None) or (len(value) <= maxLen)): if ((minLen is None) or (len(value) >= minLen)) and ((maxLen is None) or (len(value) <= maxLen)):
if itemName == GC.LICENSE_SKUS and value: if itemName == GC.LICENSE_SKUS and value:
_validateLicenseSKUs(sectionName, itemName, value) _validateLicenseSKUs(status, sectionName, itemName, value)
elif itemName == GC.DEVELOPER_PREVIEW_APIS and value: elif itemName == GC.DEVELOPER_PREVIEW_APIS and value:
_validateDeveloperPreviewAPIs(sectionName, itemName, value.lower()) _validateDeveloperPreviewAPIs(status, sectionName, itemName, value.lower())
elif itemName == GC.GCP_ORG_ID and value: elif itemName == GC.GCP_ORG_ID and value:
_validateGCPOrgId(sectionName, itemName, value) _validateGCPOrgId(status, sectionName, itemName, value)
return value return value
_printValueError(sectionName, itemName, f'"{value}"', f'{Msg.EXPECTED}: {integerLimits(minLen, maxLen, Msg.STRING_LENGTH)}') _printValueError(status, sectionName, itemName, f'"{value}"', f'{Msg.EXPECTED}: {integerLimits(minLen, maxLen, Msg.STRING_LENGTH)}')
return '' return ''
def _getCfgStringList(sectionName, itemName): def _getCfgStringList(status, sectionName, itemName):
value = GM.Globals[GM.PARSER].get(sectionName, itemName) value = GM.Globals[GM.PARSER].get(sectionName, itemName)
stringlist = [] stringlist = []
if not value or (len(value) == 2 and _stringInQuotes(value)): if not value or (len(value) == 2 and _stringInQuotes(value)):
return stringlist return stringlist
splitStatus, stringlist = shlexSplitListStatus(value) splitStatus, stringlist = shlexSplitListStatus(value)
if not splitStatus: if not splitStatus:
_printValueError(sectionName, itemName, f'"{value}"', f'{Msg.INVALID_LIST}: {stringlist}') _printValueError(status, sectionName, itemName, f'"{value}"', f'{Msg.INVALID_LIST}: {stringlist}')
return stringlist return stringlist
def _getCfgTimezone(sectionName, itemName): def _getCfgTimezone(status, sectionName, itemName):
value = _stripStringQuotes(GM.Globals[GM.PARSER].get(sectionName, itemName)) value = _stripStringQuotes(GM.Globals[GM.PARSER].get(sectionName, itemName))
if value.lower() in {'utc', 'z'}: if value.lower() in {'utc', 'z'}:
GM.Globals[GM.CONVERT_TO_LOCAL_TIME] = False GM.Globals[GM.CONVERT_TO_LOCAL_TIME] = False
@@ -472,11 +472,11 @@ def SetGlobalVariables():
try: try:
return arrow.now(value).tzinfo return arrow.now(value).tzinfo
except (arrow.parser.ParserError, OverflowError): except (arrow.parser.ParserError, OverflowError):
_printValueError(sectionName, itemName, value, f'{Msg.EXPECTED}: {TIMEZONE_FORMAT_REQUIRED}') _printValueError(status, sectionName, itemName, value, f'{Msg.EXPECTED}: {TIMEZONE_FORMAT_REQUIRED}')
GM.Globals[GM.CONVERT_TO_LOCAL_TIME] = False GM.Globals[GM.CONVERT_TO_LOCAL_TIME] = False
return arrow.now('utc').tzinfo return arrow.now('utc').tzinfo
def _getCfgDirectory(sectionName, itemName): def _getCfgDirectory(status, sectionName, itemName):
dirPath = os.path.expanduser(_stripStringQuotes(GM.Globals[GM.PARSER].get(sectionName, itemName))) dirPath = os.path.expanduser(_stripStringQuotes(GM.Globals[GM.PARSER].get(sectionName, itemName)))
if (not dirPath) and (itemName in {GC.GMAIL_CSE_INCERT_DIR, GC.GMAIL_CSE_INKEY_DIR, GC.INPUT_DIR}): if (not dirPath) and (itemName in {GC.GMAIL_CSE_INCERT_DIR, GC.GMAIL_CSE_INKEY_DIR, GC.INPUT_DIR}):
return dirPath return dirPath
@@ -487,15 +487,15 @@ def SetGlobalVariables():
dirPath = os.path.join(GM.Globals[GM.GAM_CFG_PATH], dirPath) dirPath = os.path.join(GM.Globals[GM.GAM_CFG_PATH], dirPath)
return dirPath return dirPath
def _getCfgFile(sectionName, itemName): def _getCfgFile(status, sectionName, itemName):
value = os.path.expanduser(_stripStringQuotes(GM.Globals[GM.PARSER].get(sectionName, itemName))) value = os.path.expanduser(_stripStringQuotes(GM.Globals[GM.PARSER].get(sectionName, itemName)))
if value and not os.path.isabs(value): if value and not os.path.isabs(value):
value = os.path.expanduser(os.path.join(_getCfgDirectory(sectionName, GC.CONFIG_DIR), value)) value = os.path.expanduser(os.path.join(_getCfgDirectory(status, sectionName, GC.CONFIG_DIR), value))
elif not value and itemName == GC.CACERTS_PEM: elif not value and itemName == GC.CACERTS_PEM:
value = os.path.join(GM.Globals[GM.GAM_PATH], GC.FN_CACERTS_PEM) value = os.path.join(GM.Globals[GM.GAM_PATH], GC.FN_CACERTS_PEM)
return value return value
def _readGamCfgFile(config, fileName): def _readGamCfgFile(config, fileName):
try: try:
with open(fileName, DEFAULT_FILE_READ_MODE, encoding=GM.Globals[GM.SYS_ENCODING]) as f: with open(fileName, DEFAULT_FILE_READ_MODE, encoding=GM.Globals[GM.SYS_ENCODING]) as f:
config.read_file(f) config.read_file(f)
@@ -508,7 +508,7 @@ def SetGlobalVariables():
except IOError as e: except IOError as e:
systemErrorExit(FILE_ERROR_RC, fileErrorMessage(fileName, e, Ent.CONFIG_FILE)) systemErrorExit(FILE_ERROR_RC, fileErrorMessage(fileName, e, Ent.CONFIG_FILE))
def _writeGamCfgFile(config, fileName, action): def _writeGamCfgFile(config, fileName, action):
GM.Globals[GM.SECTION] = None # No need to save section for inner gams GM.Globals[GM.SECTION] = None # No need to save section for inner gams
try: try:
with open(fileName, DEFAULT_FILE_WRITE_MODE, encoding=GM.Globals[GM.SYS_ENCODING]) as f: with open(fileName, DEFAULT_FILE_WRITE_MODE, encoding=GM.Globals[GM.SYS_ENCODING]) as f:
@@ -517,7 +517,7 @@ def SetGlobalVariables():
except IOError as e: except IOError as e:
stderrErrorMsg(fileErrorMessage(fileName, e, Ent.CONFIG_FILE)) stderrErrorMsg(fileErrorMessage(fileName, e, Ent.CONFIG_FILE))
def _verifyValues(sectionName, inputFilterSectionName, outputFilterSectionName): def _verifyValues(sectionName, inputFilterSectionName, outputFilterSectionName):
itemNamePattern = getREPattern() if checkArgumentPresent('variables') else None itemNamePattern = getREPattern() if checkArgumentPresent('variables') else None
printKeyValueList([Ent.Singular(Ent.SECTION), sectionName]) # Do not use printEntity printKeyValueList([Ent.Singular(Ent.SECTION), sectionName]) # Do not use printEntity
Ind.Increment() Ind.Increment()
@@ -541,11 +541,11 @@ def SetGlobalVariables():
elif varType not in [GC.TYPE_BOOLEAN, GC.TYPE_INTEGER, GC.TYPE_FLOAT, GC.TYPE_PASSWORD]: elif varType not in [GC.TYPE_BOOLEAN, GC.TYPE_INTEGER, GC.TYPE_FLOAT, GC.TYPE_PASSWORD]:
cfgValue = _quoteStringIfLeadingTrailingBlanks(cfgValue) cfgValue = _quoteStringIfLeadingTrailingBlanks(cfgValue)
if varType == GC.TYPE_FILE: if varType == GC.TYPE_FILE:
expdValue = _getCfgFile(sectName, itemName) expdValue = _getCfgFile(None, sectName, itemName)
if cfgValue not in ("''", expdValue): if cfgValue not in ("''", expdValue):
cfgValue = f'{cfgValue} ; {expdValue}' cfgValue = f'{cfgValue} ; {expdValue}'
elif varType == GC.TYPE_DIRECTORY: elif varType == GC.TYPE_DIRECTORY:
expdValue = _getCfgDirectory(sectName, itemName) expdValue = _getCfgDirectory(None, sectName, itemName)
if cfgValue not in ("''", expdValue): if cfgValue not in ("''", expdValue):
cfgValue = f'{cfgValue} ; {expdValue}' cfgValue = f'{cfgValue} ; {expdValue}'
elif (itemName == GC.SECTION) and (sectName != configparser.DEFAULTSECT): elif (itemName == GC.SECTION) and (sectName != configparser.DEFAULTSECT):
@@ -553,7 +553,7 @@ def SetGlobalVariables():
printLine(f'{Ind.Spaces()}{itemName} = {cfgValue}') printLine(f'{Ind.Spaces()}{itemName} = {cfgValue}')
Ind.Decrement() Ind.Decrement()
def _chkCfgDirectories(sectionName): def _chkCfgDirectories(sectionName):
for itemName, itemEntry in GC.VAR_INFO.items(): for itemName, itemEntry in GC.VAR_INFO.items():
if itemEntry[GC.VAR_TYPE] == GC.TYPE_DIRECTORY: if itemEntry[GC.VAR_TYPE] == GC.TYPE_DIRECTORY:
dirPath = GC.Values[itemName] dirPath = GC.Values[itemName]
@@ -568,7 +568,7 @@ def SetGlobalVariables():
Msg.INVALID_PATH], Msg.INVALID_PATH],
'\n')) '\n'))
def _chkCfgFiles(sectionName): def _chkCfgFiles(status, sectionName):
for itemName, itemEntry in GC.VAR_INFO.items(): for itemName, itemEntry in GC.VAR_INFO.items():
if itemEntry[GC.VAR_TYPE] == GC.TYPE_FILE: if itemEntry[GC.VAR_TYPE] == GC.TYPE_FILE:
fileName = GC.Values[itemName] fileName = GC.Values[itemName]
@@ -604,7 +604,7 @@ def SetGlobalVariables():
'\n')) '\n'))
status['errors'] = True status['errors'] = True
def _setCSVFile(fileName, mode, encoding, writeHeader, multi, delayOpen): def _setCSVFile(fileName, mode, encoding, writeHeader, multi, delayOpen):
if fileName != '-': if fileName != '-':
fileName = setFilePath(fileName, GC.DRIVE_DIR) fileName = setFilePath(fileName, GC.DRIVE_DIR)
GM.Globals[GM.CSVFILE][GM.REDIRECT_NAME] = fileName GM.Globals[GM.CSVFILE][GM.REDIRECT_NAME] = fileName
@@ -617,7 +617,7 @@ def SetGlobalVariables():
GM.Globals[GM.CSVFILE][GM.REDIRECT_FD] = openFile(fileName, mode, newline='', GM.Globals[GM.CSVFILE][GM.REDIRECT_FD] = openFile(fileName, mode, newline='',
encoding=encoding, errors='backslashreplace') encoding=encoding, errors='backslashreplace')
def _setSTDFile(stdtype, fileName, mode, multi): def _setSTDFile(stdtype, fileName, mode, multi):
if stdtype == GM.STDOUT: if stdtype == GM.STDOUT:
GM.Globals[GM.SAVED_STDOUT] = None GM.Globals[GM.SAVED_STDOUT] = None
GM.Globals[stdtype][GM.REDIRECT_STD] = False GM.Globals[stdtype][GM.REDIRECT_STD] = False
@@ -644,10 +644,7 @@ def SetGlobalVariables():
GM.Globals[stdtype][GM.REDIRECT_MULTIPROCESS] = multi GM.Globals[stdtype][GM.REDIRECT_MULTIPROCESS] = multi
GM.Globals[stdtype][GM.REDIRECT_QUEUE] = 'stdout' if stdtype == GM.STDOUT else 'stderr' GM.Globals[stdtype][GM.REDIRECT_QUEUE] = 'stdout' if stdtype == GM.STDOUT else 'stderr'
MULTIPROCESS_EXIT_COMP_PATTERN = re.compile(r'^rc([<>]=?|=|!=)(.+)$', re.IGNORECASE) def _setMultiprocessExit():
MULTIPROCESS_EXIT_RANGE_PATTERN = re.compile(r'^rcrange(=|!=)(\S+)/(\S+)$', re.IGNORECASE)
def _setMultiprocessExit():
rcStr = getString(Cmd.OB_STRING) rcStr = getString(Cmd.OB_STRING)
mg = MULTIPROCESS_EXIT_COMP_PATTERN.match(rcStr) mg = MULTIPROCESS_EXIT_COMP_PATTERN.match(rcStr)
if mg: if mg:
@@ -663,6 +660,26 @@ def SetGlobalVariables():
return return
usageErrorExit(f'{Msg.EXPECTED}: (rc<Operator><Value>)|(rcrange<Operator><Value>/Value>)') usageErrorExit(f'{Msg.EXPECTED}: (rc<Operator><Value>)|(rcrange<Operator><Value>/Value>)')
_CFG_TYPE_HANDLERS = {
GC.TYPE_BOOLEAN: _getCfgBoolean,
GC.TYPE_CHARACTER: _getCfgCharacter,
GC.TYPE_CHOICE: _getCfgChoice,
GC.TYPE_INTEGER: _getCfgNumber,
GC.TYPE_FLOAT: _getCfgNumber,
GC.TYPE_HEADERFILTER: _getCfgHeaderFilter,
GC.TYPE_LOCALE: _getCfgLocale,
GC.TYPE_PASSWORD: _getCfgPassword,
GC.TYPE_STRING: _getCfgString,
GC.TYPE_STRINGLIST: _getCfgStringList,
GC.TYPE_HEADERFORCEREQUIRED: _getCfgStringList,
GC.TYPE_HEADERORDER: _getCfgStringList,
GC.TYPE_FILE: _getCfgFile,
}
def _initConfigParser():
"""Initialize config parser if not already done."""
if not GM.Globals[GM.PARSER]: if not GM.Globals[GM.PARSER]:
homePath = os.path.expanduser('~') homePath = os.path.expanduser('~')
GM.Globals[GM.GAM_CFG_PATH] = os.environ.get(EV_GAMCFGDIR, None) GM.Globals[GM.GAM_CFG_PATH] = os.environ.get(EV_GAMCFGDIR, None)
@@ -694,7 +711,13 @@ def SetGlobalVariables():
else: else:
GM.Globals[GM.PARSER] = configparser.RawConfigParser(defaults=collections.OrderedDict(sorted(list(GC.Defaults.items()), key=lambda t: t[0]))) GM.Globals[GM.PARSER] = configparser.RawConfigParser(defaults=collections.OrderedDict(sorted(list(GC.Defaults.items()), key=lambda t: t[0])))
_readGamCfgFile(GM.Globals[GM.PARSER], GM.Globals[GM.GAM_CFG_FILE]) _readGamCfgFile(GM.Globals[GM.PARSER], GM.Globals[GM.GAM_CFG_FILE])
status = {'errors': False}
def _selectConfigSection(status):
"""Determine which config section to use and process select/filter commands.
Returns (sectionName, inputFilterSectionName, outputFilterSectionName).
"""
inputFilterSectionName = outputFilterSectionName = None inputFilterSectionName = outputFilterSectionName = None
GM.Globals[GM.GAM_CFG_SECTION] = os.environ.get(EV_GAMCFGSECTION, None) GM.Globals[GM.GAM_CFG_SECTION] = os.environ.get(EV_GAMCFGSECTION, None)
if GM.Globals[GM.GAM_CFG_SECTION]: if GM.Globals[GM.GAM_CFG_SECTION]:
@@ -706,7 +729,7 @@ def SetGlobalVariables():
Cmd.Backup() Cmd.Backup()
usageErrorExit(formatKeyValueList('', [EV_GAMCFGSECTION, sectionName, 'select', Msg.NOT_ALLOWED], '')) usageErrorExit(formatKeyValueList('', [EV_GAMCFGSECTION, sectionName, 'select', Msg.NOT_ALLOWED], ''))
else: else:
sectionName = _getCfgSection(configparser.DEFAULTSECT, GC.SECTION) sectionName = _getCfgSection(status, configparser.DEFAULTSECT, GC.SECTION)
# select <SectionName> [save] [verify [variables <RESearchPattern>]] # select <SectionName> [save] [verify [variables <RESearchPattern>]]
if checkArgumentPresent(Cmd.SELECT_CMD): if checkArgumentPresent(Cmd.SELECT_CMD):
sectionName = _selectSection() sectionName = _selectSection()
@@ -728,7 +751,7 @@ def SetGlobalVariables():
GM.Globals[GM.GAM_CFG_SECTION_NAME] = sectionName GM.Globals[GM.GAM_CFG_SECTION_NAME] = sectionName
# showsections # showsections
if checkArgumentPresent(Cmd.SHOWSECTIONS_CMD): if checkArgumentPresent(Cmd.SHOWSECTIONS_CMD):
_showSections() _showSections(sectionName)
# selectfilter|selectoutputfilter|selectinputfilter <SectionName> # selectfilter|selectoutputfilter|selectinputfilter <SectionName>
while True: while True:
filterCommand = getChoice([Cmd.SELECTFILTER_CMD, Cmd.SELECTOUTPUTFILTER_CMD, Cmd.SELECTINPUTFILTER_CMD], defaultChoice=None) filterCommand = getChoice([Cmd.SELECTFILTER_CMD, Cmd.SELECTOUTPUTFILTER_CMD, Cmd.SELECTINPUTFILTER_CMD], defaultChoice=None)
@@ -738,21 +761,26 @@ def SetGlobalVariables():
outputFilterSectionName = _selectSection() outputFilterSectionName = _selectSection()
else: else:
inputFilterSectionName = _selectSection() inputFilterSectionName = _selectSection()
return sectionName, inputFilterSectionName, outputFilterSectionName
def _fixupTodriveAndConfig(status, sectionName, inputFilterSectionName, outputFilterSectionName):
"""Handle todrive defaults, fix mistyped keywords, and process config command."""
# Handle todrive_nobrowser and todrive_noemail if not present # Handle todrive_nobrowser and todrive_noemail if not present
value = GM.Globals[GM.PARSER].get(configparser.DEFAULTSECT, GC.TODRIVE_NOBROWSER) value = GM.Globals[GM.PARSER].get(configparser.DEFAULTSECT, GC.TODRIVE_NOBROWSER)
if value == '': if value == '':
GM.Globals[GM.PARSER].set(configparser.DEFAULTSECT, GC.TODRIVE_NOBROWSER, str(_getCfgBoolean(configparser.DEFAULTSECT, GC.NO_BROWSER)).lower()) GM.Globals[GM.PARSER].set(configparser.DEFAULTSECT, GC.TODRIVE_NOBROWSER, str(_getCfgBoolean(status, configparser.DEFAULTSECT, GC.NO_BROWSER)).lower())
value = GM.Globals[GM.PARSER].get(configparser.DEFAULTSECT, GC.TODRIVE_NOEMAIL) value = GM.Globals[GM.PARSER].get(configparser.DEFAULTSECT, GC.TODRIVE_NOEMAIL)
if value == '': if value == '':
GM.Globals[GM.PARSER].set(configparser.DEFAULTSECT, GC.TODRIVE_NOEMAIL, str(not _getCfgBoolean(configparser.DEFAULTSECT, GC.NO_BROWSER)).lower()) GM.Globals[GM.PARSER].set(configparser.DEFAULTSECT, GC.TODRIVE_NOEMAIL, str(not _getCfgBoolean(status, configparser.DEFAULTSECT, GC.NO_BROWSER)).lower())
# Handle todrive_sheet_timestamp and todrive_sheet_timeformat if not present # Handle todrive_sheet_timestamp and todrive_sheet_timeformat if not present
for section in [sectionName, configparser.DEFAULTSECT]: for section in [sectionName, configparser.DEFAULTSECT]:
value = GM.Globals[GM.PARSER].get(section, GC.TODRIVE_SHEET_TIMESTAMP) value = GM.Globals[GM.PARSER].get(section, GC.TODRIVE_SHEET_TIMESTAMP)
if value == 'copy': if value == 'copy':
GM.Globals[GM.PARSER].set(section, GC.TODRIVE_SHEET_TIMESTAMP, str(_getCfgBoolean(section, GC.TODRIVE_TIMESTAMP)).lower()) GM.Globals[GM.PARSER].set(section, GC.TODRIVE_SHEET_TIMESTAMP, str(_getCfgBoolean(status, section, GC.TODRIVE_TIMESTAMP)).lower())
value = GM.Globals[GM.PARSER].get(section, GC.TODRIVE_SHEET_TIMEFORMAT) value = GM.Globals[GM.PARSER].get(section, GC.TODRIVE_SHEET_TIMEFORMAT)
if value == 'copy': if value == 'copy':
GM.Globals[GM.PARSER].set(section, GC.TODRIVE_SHEET_TIMEFORMAT, _getCfgString(section, GC.TODRIVE_TIMEFORMAT)) GM.Globals[GM.PARSER].set(section, GC.TODRIVE_SHEET_TIMEFORMAT, _getCfgString(status, section, GC.TODRIVE_TIMEFORMAT))
# Fix mistyped keyword cmdlog_max__backups # Fix mistyped keyword cmdlog_max__backups
for section in [configparser.DEFAULTSECT, sectionName]: for section in [configparser.DEFAULTSECT, sectionName]:
if GM.Globals[GM.PARSER].has_option(section, GC.CMDLOG_MAX__BACKUPS): if GM.Globals[GM.PARSER].has_option(section, GC.CMDLOG_MAX__BACKUPS):
@@ -771,96 +799,88 @@ def SetGlobalVariables():
break break
itemEntry = GC.VAR_INFO[itemName] itemEntry = GC.VAR_INFO[itemName]
checkArgumentPresent('=') checkArgumentPresent('=')
varType = itemEntry[GC.VAR_TYPE] match varType:
if varType == GC.TYPE_BOOLEAN: case GC.TYPE_BOOLEAN:
value = TRUE if getBoolean(None) else FALSE value = TRUE if getBoolean(None) else FALSE
elif varType == GC.TYPE_CHARACTER: case GC.TYPE_CHARACTER:
value = getCharacter() value = getCharacter()
elif varType == GC.TYPE_CHOICE: case GC.TYPE_CHOICE:
value = getChoice(itemEntry[GC.VAR_CHOICES]) value = getChoice(itemEntry[GC.VAR_CHOICES])
elif varType == GC.TYPE_INTEGER: case GC.TYPE_INTEGER:
minVal, maxVal = itemEntry[GC.VAR_LIMITS] minVal, maxVal = itemEntry[GC.VAR_LIMITS]
value = str(getInteger(minVal=minVal, maxVal=maxVal)) value = str(getInteger(minVal=minVal, maxVal=maxVal))
elif varType == GC.TYPE_FLOAT: case GC.TYPE_FLOAT:
minVal, maxVal = itemEntry[GC.VAR_LIMITS] minVal, maxVal = itemEntry[GC.VAR_LIMITS]
value = str(getFloat(minVal=minVal, maxVal=maxVal)) value = str(getFloat(minVal=minVal, maxVal=maxVal))
elif varType == GC.TYPE_LOCALE: case GC.TYPE_LOCALE:
value = getLanguageCode(LOCALE_CODES_MAP) value = getLanguageCode(LOCALE_CODES_MAP)
elif varType == GC.TYPE_PASSWORD: case GC.TYPE_PASSWORD:
minLen, maxLen = itemEntry[GC.VAR_LIMITS] minLen, maxLen = itemEntry[GC.VAR_LIMITS]
value = getString(Cmd.OB_STRING, checkBlank=True, minLen=minLen, maxLen=maxLen) value = getString(Cmd.OB_STRING, checkBlank=True, minLen=minLen, maxLen=maxLen)
if value and value.startswith("b'") and value.endswith("'"): if value and value.startswith("b'") and value.endswith("'"):
value = bytes(value[2:-1], UTF8) value = bytes(value[2:-1], UTF8)
elif varType == GC.TYPE_TIMEZONE: case GC.TYPE_TIMEZONE:
value = getString(Cmd.OB_STRING, checkBlank=True) value = getString(Cmd.OB_STRING, checkBlank=True)
else: # GC.TYPE_STRING, GC.TYPE_STRINGLIST case _: # GC.TYPE_STRING, GC.TYPE_STRINGLIST
minLen, maxLen = itemEntry.get(GC.VAR_LIMITS, (0, None)) minLen, maxLen = itemEntry.get(GC.VAR_LIMITS, (0, None))
value = _quoteStringIfLeadingTrailingBlanks(getString(Cmd.OB_STRING, minLen=minLen, maxLen=maxLen)) value = _quoteStringIfLeadingTrailingBlanks(getString(Cmd.OB_STRING, minLen=minLen, maxLen=maxLen))
GM.Globals[GM.PARSER].set(sectionName, itemName, value) GM.Globals[GM.PARSER].set(sectionName, itemName, value)
def _assignConfigValues(status, sectionName, inputFilterSectionName, outputFilterSectionName):
"""Assign all GC.Values from config: directories, timezone, types, row filters, filter overrides."""
prevExtraArgsTxt = GC.Values.get(GC.EXTRA_ARGS, None) prevExtraArgsTxt = GC.Values.get(GC.EXTRA_ARGS, None)
prevOauth2serviceJson = GC.Values.get(GC.OAUTH2SERVICE_JSON, None) prevOauth2serviceJson = GC.Values.get(GC.OAUTH2SERVICE_JSON, None)
# Assign global variables, directories, timezone first as other variables depend on them # Assign global variables, directories, timezone first as other variables depend on them
for itemName, itemEntry in sorted(GC.VAR_INFO.items()): for itemName, itemEntry in sorted(GC.VAR_INFO.items()):
varType = itemEntry[GC.VAR_TYPE] varType = itemEntry[GC.VAR_TYPE]
if varType == GC.TYPE_DIRECTORY: if varType == GC.TYPE_DIRECTORY:
GC.Values[itemName] = _getCfgDirectory(sectionName, itemName) GC.Values[itemName] = _getCfgDirectory(status, sectionName, itemName)
elif varType == GC.TYPE_TIMEZONE: elif varType == GC.TYPE_TIMEZONE:
GC.Values[itemName] = _getCfgTimezone(sectionName, itemName) GC.Values[itemName] = _getCfgTimezone(status, sectionName, itemName)
GM.Globals[GM.DATETIME_NOW] = arrow.now(GC.Values[GC.TIMEZONE]) GM.Globals[GM.DATETIME_NOW] = arrow.now(GC.Values[GC.TIMEZONE])
# Everything else except row filters # Everything else except row filters
for itemName, itemEntry in sorted(GC.VAR_INFO.items()): for itemName, itemEntry in sorted(GC.VAR_INFO.items()):
varType = itemEntry[GC.VAR_TYPE] varType = itemEntry[GC.VAR_TYPE]
if varType == GC.TYPE_BOOLEAN: handler = _CFG_TYPE_HANDLERS.get(varType)
GC.Values[itemName] = _getCfgBoolean(sectionName, itemName) if handler:
elif varType == GC.TYPE_CHARACTER: GC.Values[itemName] = handler(status, sectionName, itemName)
GC.Values[itemName] = _getCfgCharacter(sectionName, itemName)
elif varType == GC.TYPE_CHOICE:
GC.Values[itemName] = _getCfgChoice(sectionName, itemName)
elif varType in [GC.TYPE_INTEGER, GC.TYPE_FLOAT]:
GC.Values[itemName] = _getCfgNumber(sectionName, itemName)
elif varType == GC.TYPE_HEADERFILTER:
GC.Values[itemName] = _getCfgHeaderFilter(sectionName, itemName)
elif varType == GC.TYPE_LOCALE:
GC.Values[itemName] = _getCfgLocale(sectionName, itemName)
elif varType == GC.TYPE_PASSWORD:
GC.Values[itemName] = _getCfgPassword(sectionName, itemName)
elif varType == GC.TYPE_STRING:
GC.Values[itemName] = _getCfgString(sectionName, itemName)
elif varType in {GC.TYPE_STRINGLIST, GC.TYPE_HEADERFORCEREQUIRED, GC.TYPE_HEADERORDER}:
GC.Values[itemName] = _getCfgStringList(sectionName, itemName)
elif varType == GC.TYPE_FILE:
GC.Values[itemName] = _getCfgFile(sectionName, itemName)
# Row filters # Row filters
for itemName, itemEntry in sorted(GC.VAR_INFO.items()): for itemName, itemEntry in sorted(GC.VAR_INFO.items()):
varType = itemEntry[GC.VAR_TYPE] varType = itemEntry[GC.VAR_TYPE]
if varType == GC.TYPE_ROWFILTER: if varType == GC.TYPE_ROWFILTER:
GC.Values[itemName] = _getCfgRowFilter(sectionName, itemName) GC.Values[itemName] = _getCfgRowFilter(status, sectionName, itemName)
# Process selectfilter|selectoutputfilter|selectinputfilter # Process selectfilter|selectoutputfilter|selectinputfilter
if inputFilterSectionName: if inputFilterSectionName:
GC.Values[GC.CSV_INPUT_ROW_FILTER] = _getCfgRowFilter(inputFilterSectionName, GC.CSV_INPUT_ROW_FILTER) GC.Values[GC.CSV_INPUT_ROW_FILTER] = _getCfgRowFilter(status, inputFilterSectionName, GC.CSV_INPUT_ROW_FILTER)
GC.Values[GC.CSV_INPUT_ROW_FILTER_MODE] = _getCfgChoice(inputFilterSectionName, GC.CSV_INPUT_ROW_FILTER_MODE) GC.Values[GC.CSV_INPUT_ROW_FILTER_MODE] = _getCfgChoice(status, inputFilterSectionName, GC.CSV_INPUT_ROW_FILTER_MODE)
GC.Values[GC.CSV_INPUT_ROW_DROP_FILTER] = _getCfgRowFilter(inputFilterSectionName, GC.CSV_INPUT_ROW_DROP_FILTER) GC.Values[GC.CSV_INPUT_ROW_DROP_FILTER] = _getCfgRowFilter(status, inputFilterSectionName, GC.CSV_INPUT_ROW_DROP_FILTER)
GC.Values[GC.CSV_INPUT_ROW_DROP_FILTER_MODE] = _getCfgChoice(inputFilterSectionName, GC.CSV_INPUT_ROW_DROP_FILTER_MODE) GC.Values[GC.CSV_INPUT_ROW_DROP_FILTER_MODE] = _getCfgChoice(status, inputFilterSectionName, GC.CSV_INPUT_ROW_DROP_FILTER_MODE)
GC.Values[GC.CSV_INPUT_ROW_LIMIT] = _getCfgNumber(inputFilterSectionName, GC.CSV_INPUT_ROW_LIMIT) GC.Values[GC.CSV_INPUT_ROW_LIMIT] = _getCfgNumber(status, inputFilterSectionName, GC.CSV_INPUT_ROW_LIMIT)
if outputFilterSectionName: if outputFilterSectionName:
GC.Values[GC.CSV_OUTPUT_HEADER_FORCE] = _getCfgStringList(outputFilterSectionName, GC.CSV_OUTPUT_HEADER_FORCE) GC.Values[GC.CSV_OUTPUT_HEADER_FORCE] = _getCfgStringList(status, outputFilterSectionName, GC.CSV_OUTPUT_HEADER_FORCE)
if GC.Values[GC.CSV_OUTPUT_HEADER_FORCE]: if GC.Values[GC.CSV_OUTPUT_HEADER_FORCE]:
GC.Values[GC.CSV_OUTPUT_HEADER_FILTER] = _getCfgHeaderFilterFromForce(outputFilterSectionName, GC.CSV_OUTPUT_HEADER_FORCE) GC.Values[GC.CSV_OUTPUT_HEADER_FILTER] = _getCfgHeaderFilterFromForce(status, outputFilterSectionName, GC.CSV_OUTPUT_HEADER_FORCE)
else: else:
GC.Values[GC.CSV_OUTPUT_HEADER_FILTER] = _getCfgHeaderFilter(outputFilterSectionName, GC.CSV_OUTPUT_HEADER_FILTER) GC.Values[GC.CSV_OUTPUT_HEADER_FILTER] = _getCfgHeaderFilter(status, outputFilterSectionName, GC.CSV_OUTPUT_HEADER_FILTER)
GC.Values[GC.CSV_OUTPUT_HEADER_DROP_FILTER] = _getCfgHeaderFilter(outputFilterSectionName, GC.CSV_OUTPUT_HEADER_DROP_FILTER) GC.Values[GC.CSV_OUTPUT_HEADER_DROP_FILTER] = _getCfgHeaderFilter(status, outputFilterSectionName, GC.CSV_OUTPUT_HEADER_DROP_FILTER)
GC.Values[GC.CSV_OUTPUT_HEADER_ORDER] = _getCfgStringList(outputFilterSectionName, GC.CSV_OUTPUT_HEADER_ORDER) GC.Values[GC.CSV_OUTPUT_HEADER_ORDER] = _getCfgStringList(status, outputFilterSectionName, GC.CSV_OUTPUT_HEADER_ORDER)
GC.Values[GC.CSV_OUTPUT_HEADER_REQUIRED] = _getCfgStringList(outputFilterSectionName, GC.CSV_OUTPUT_HEADER_REQUIRED) GC.Values[GC.CSV_OUTPUT_HEADER_REQUIRED] = _getCfgStringList(status, outputFilterSectionName, GC.CSV_OUTPUT_HEADER_REQUIRED)
GC.Values[GC.CSV_OUTPUT_ROW_FILTER] = _getCfgRowFilter(outputFilterSectionName, GC.CSV_OUTPUT_ROW_FILTER) GC.Values[GC.CSV_OUTPUT_ROW_FILTER] = _getCfgRowFilter(status, outputFilterSectionName, GC.CSV_OUTPUT_ROW_FILTER)
GC.Values[GC.CSV_OUTPUT_ROW_FILTER_MODE] = _getCfgChoice(outputFilterSectionName, GC.CSV_OUTPUT_ROW_FILTER_MODE) GC.Values[GC.CSV_OUTPUT_ROW_FILTER_MODE] = _getCfgChoice(status, outputFilterSectionName, GC.CSV_OUTPUT_ROW_FILTER_MODE)
GC.Values[GC.CSV_OUTPUT_ROW_DROP_FILTER] = _getCfgRowFilter(outputFilterSectionName, GC.CSV_OUTPUT_ROW_DROP_FILTER) GC.Values[GC.CSV_OUTPUT_ROW_DROP_FILTER] = _getCfgRowFilter(status, outputFilterSectionName, GC.CSV_OUTPUT_ROW_DROP_FILTER)
GC.Values[GC.CSV_OUTPUT_ROW_DROP_FILTER_MODE] = _getCfgChoice(outputFilterSectionName, GC.CSV_OUTPUT_ROW_DROP_FILTER_MODE) GC.Values[GC.CSV_OUTPUT_ROW_DROP_FILTER_MODE] = _getCfgChoice(status, outputFilterSectionName, GC.CSV_OUTPUT_ROW_DROP_FILTER_MODE)
GC.Values[GC.CSV_OUTPUT_ROW_LIMIT] = _getCfgNumber(outputFilterSectionName, GC.CSV_OUTPUT_ROW_LIMIT) GC.Values[GC.CSV_OUTPUT_ROW_LIMIT] = _getCfgNumber(status, outputFilterSectionName, GC.CSV_OUTPUT_ROW_LIMIT)
GC.Values[GC.CSV_OUTPUT_SORT_HEADERS] = _getCfgStringList(outputFilterSectionName, GC.CSV_OUTPUT_SORT_HEADERS) GC.Values[GC.CSV_OUTPUT_SORT_HEADERS] = _getCfgStringList(status, outputFilterSectionName, GC.CSV_OUTPUT_SORT_HEADERS)
elif GC.Values[GC.CSV_OUTPUT_HEADER_FORCE]: elif GC.Values[GC.CSV_OUTPUT_HEADER_FORCE]:
GC.Values[GC.CSV_OUTPUT_HEADER_FILTER] = _getCfgHeaderFilterFromForce(sectionName, GC.CSV_OUTPUT_HEADER_FORCE) GC.Values[GC.CSV_OUTPUT_HEADER_FILTER] = _getCfgHeaderFilterFromForce(status, sectionName, GC.CSV_OUTPUT_HEADER_FORCE)
if status['errors']: if status['errors']:
sys.exit(CONFIG_ERROR_RC) sys.exit(CONFIG_ERROR_RC)
return prevExtraArgsTxt, prevOauth2serviceJson
def _applyRuntimeDefaults(prevExtraArgsTxt, prevOauth2serviceJson):
"""Apply runtime defaults: domain cleanup, inheritance, lockfile, debug, extra args."""
# Global values cleanup # Global values cleanup
GC.Values[GC.DOMAIN] = GC.Values[GC.DOMAIN].lower() GC.Values[GC.DOMAIN] = GC.Values[GC.DOMAIN].lower()
if not GC.Values[GC.SMTP_FQDN]: if not GC.Values[GC.SMTP_FQDN]:
@@ -894,6 +914,10 @@ def SetGlobalVariables():
GM.Globals[GM.OAUTH2SERVICE_JSON_DATA] = {} GM.Globals[GM.OAUTH2SERVICE_JSON_DATA] = {}
GM.Globals[GM.OAUTH2SERVICE_CLIENT_ID] = None GM.Globals[GM.OAUTH2SERVICE_CLIENT_ID] = None
Cmd.SetEncoding(GM.Globals[GM.SYS_ENCODING]) Cmd.SetEncoding(GM.Globals[GM.SYS_ENCODING])
def _processRedirects(sectionName):
"""Process multiprocessexit and redirect csv/stdout/stderr commands."""
# multiprocessexit (rc<Operator><Number>)|(rcrange=<Number>/<Number>)|(rcrange!=<Number>/<Number>) # multiprocessexit (rc<Operator><Number>)|(rcrange=<Number>/<Number>)|(rcrange!=<Number>/<Number>)
if checkArgumentPresent(Cmd.MULTIPROCESSEXIT_CMD): if checkArgumentPresent(Cmd.MULTIPROCESSEXIT_CMD):
_setMultiprocessExit() _setMultiprocessExit()
@@ -909,7 +933,8 @@ def SetGlobalVariables():
while checkArgumentPresent(Cmd.REDIRECT_CMD): while checkArgumentPresent(Cmd.REDIRECT_CMD):
myarg = getChoice(['csv', 'stdout', 'stderr']) myarg = getChoice(['csv', 'stdout', 'stderr'])
filename = re.sub(r'{{Section}}', sectionName, getString(Cmd.OB_FILE_NAME, checkBlank=True)) filename = re.sub(r'{{Section}}', sectionName, getString(Cmd.OB_FILE_NAME, checkBlank=True))
if myarg == 'csv': match myarg:
case 'csv':
multi = False multi = False
mode = DEFAULT_FILE_WRITE_MODE mode = DEFAULT_FILE_WRITE_MODE
writeHeader = True writeHeader = True
@@ -947,7 +972,7 @@ def SetGlobalVariables():
if checkArgumentPresent('todrive'): if checkArgumentPresent('todrive'):
GM.Globals[GM.CSVFILE][GM.REDIRECT_QUEUE_CSVPF].GetTodriveParameters() GM.Globals[GM.CSVFILE][GM.REDIRECT_QUEUE_CSVPF].GetTodriveParameters()
GM.Globals[GM.CSV_TODRIVE] = GM.Globals[GM.CSVFILE][GM.REDIRECT_QUEUE_CSVPF].todrive.copy() GM.Globals[GM.CSV_TODRIVE] = GM.Globals[GM.CSVFILE][GM.REDIRECT_QUEUE_CSVPF].todrive.copy()
elif myarg == 'stdout': case 'stdout':
if filename.lower() == 'null': if filename.lower() == 'null':
multi = checkArgumentPresent('multiprocess') multi = checkArgumentPresent('multiprocess')
_setSTDFile(GM.STDOUT, 'null', DEFAULT_FILE_WRITE_MODE, multi) _setSTDFile(GM.STDOUT, 'null', DEFAULT_FILE_WRITE_MODE, multi)
@@ -955,7 +980,7 @@ def SetGlobalVariables():
multi = checkArgumentPresent('multiprocess') multi = checkArgumentPresent('multiprocess')
mode = DEFAULT_FILE_APPEND_MODE if checkArgumentPresent('append') else DEFAULT_FILE_WRITE_MODE mode = DEFAULT_FILE_APPEND_MODE if checkArgumentPresent('append') else DEFAULT_FILE_WRITE_MODE
_setSTDFile(GM.STDOUT, filename, mode, multi) _setSTDFile(GM.STDOUT, filename, mode, multi)
else: # myarg == 'stderr' case 'stderr':
if filename.lower() == 'null': if filename.lower() == 'null':
multi = checkArgumentPresent('multiprocess') multi = checkArgumentPresent('multiprocess')
_setSTDFile(GM.STDERR, 'null', DEFAULT_FILE_WRITE_MODE, multi) _setSTDFile(GM.STDERR, 'null', DEFAULT_FILE_WRITE_MODE, multi)
@@ -983,6 +1008,10 @@ def SetGlobalVariables():
elif not GM.Globals[GM.CSVFILE]: elif not GM.Globals[GM.CSVFILE]:
_setCSVFile('-', GM.Globals[GM.STDOUT].get(GM.REDIRECT_MODE, DEFAULT_FILE_WRITE_MODE), GC.Values[GC.CHARSET], True, False, False) _setCSVFile('-', GM.Globals[GM.STDOUT].get(GM.REDIRECT_MODE, DEFAULT_FILE_WRITE_MODE), GC.Values[GC.CHARSET], True, False, False)
initAPICallsRateCheck() initAPICallsRateCheck()
def _finalizeConfig(status, sectionName):
"""Finalize config: filter inheritance, DASA validation, env vars, return."""
# Main process # Main process
# Clear input row filters/limit from parser, children can define but shouldn't inherit global value # Clear input row filters/limit from parser, children can define but shouldn't inherit global value
# Clear output header/row filters/limit from parser, children can define or they will inherit global value if not defined # Clear output header/row filters/limit from parser, children can define or they will inherit global value if not defined
@@ -996,16 +1025,16 @@ def SetGlobalVariables():
# Child process # Child process
# Inherit main process output header/row filters/limit, print defaults if not locally defined # Inherit main process output header/row filters/limit, print defaults if not locally defined
else: else:
if not GC.Values[GC.CSV_OUTPUT_HEADER_FILTER]: _CHILD_INHERIT_LIST_ITEMS = [
GC.Values[GC.CSV_OUTPUT_HEADER_FILTER] = GM.Globals[GM.CSV_OUTPUT_HEADER_FILTER][:] (GC.CSV_OUTPUT_HEADER_FILTER, GM.CSV_OUTPUT_HEADER_FILTER),
if not GC.Values[GC.CSV_OUTPUT_HEADER_DROP_FILTER]: (GC.CSV_OUTPUT_HEADER_DROP_FILTER, GM.CSV_OUTPUT_HEADER_DROP_FILTER),
GC.Values[GC.CSV_OUTPUT_HEADER_DROP_FILTER] = GM.Globals[GM.CSV_OUTPUT_HEADER_DROP_FILTER][:] (GC.CSV_OUTPUT_HEADER_FORCE, GM.CSV_OUTPUT_HEADER_FORCE),
if not GC.Values[GC.CSV_OUTPUT_HEADER_FORCE]: (GC.CSV_OUTPUT_HEADER_ORDER, GM.CSV_OUTPUT_HEADER_ORDER),
GC.Values[GC.CSV_OUTPUT_HEADER_FORCE] = GM.Globals[GM.CSV_OUTPUT_HEADER_FORCE][:] (GC.CSV_OUTPUT_HEADER_REQUIRED, GM.CSV_OUTPUT_HEADER_REQUIRED),
if not GC.Values[GC.CSV_OUTPUT_HEADER_ORDER]: ]
GC.Values[GC.CSV_OUTPUT_HEADER_ORDER] = GM.Globals[GM.CSV_OUTPUT_HEADER_ORDER][:] for gcItem, gmItem in _CHILD_INHERIT_LIST_ITEMS:
if not GC.Values[GC.CSV_OUTPUT_HEADER_REQUIRED]: if not GC.Values[gcItem]:
GC.Values[GC.CSV_OUTPUT_HEADER_REQUIRED] = GM.Globals[GM.CSV_OUTPUT_HEADER_REQUIRED][:] GC.Values[gcItem] = GM.Globals[gmItem][:]
if not GC.Values[GC.CSV_OUTPUT_ROW_FILTER]: if not GC.Values[GC.CSV_OUTPUT_ROW_FILTER]:
GC.Values[GC.CSV_OUTPUT_ROW_FILTER] = GM.Globals[GM.CSV_OUTPUT_ROW_FILTER][:] GC.Values[GC.CSV_OUTPUT_ROW_FILTER] = GM.Globals[GM.CSV_OUTPUT_ROW_FILTER][:]
GC.Values[GC.CSV_OUTPUT_ROW_FILTER_MODE] = GM.Globals[GM.CSV_OUTPUT_ROW_FILTER_MODE] GC.Values[GC.CSV_OUTPUT_ROW_FILTER_MODE] = GM.Globals[GM.CSV_OUTPUT_ROW_FILTER_MODE]
@@ -1014,12 +1043,14 @@ def SetGlobalVariables():
GC.Values[GC.CSV_OUTPUT_ROW_DROP_FILTER_MODE] = GM.Globals[GM.CSV_OUTPUT_ROW_DROP_FILTER_MODE] GC.Values[GC.CSV_OUTPUT_ROW_DROP_FILTER_MODE] = GM.Globals[GM.CSV_OUTPUT_ROW_DROP_FILTER_MODE]
if not GC.Values[GC.CSV_OUTPUT_ROW_LIMIT]: if not GC.Values[GC.CSV_OUTPUT_ROW_LIMIT]:
GC.Values[GC.CSV_OUTPUT_ROW_LIMIT] = GM.Globals[GM.CSV_OUTPUT_ROW_LIMIT] GC.Values[GC.CSV_OUTPUT_ROW_LIMIT] = GM.Globals[GM.CSV_OUTPUT_ROW_LIMIT]
if not GC.Values[GC.PRINT_AGU_DOMAINS]: _CHILD_INHERIT_SCALAR_ITEMS = [
GC.Values[GC.PRINT_AGU_DOMAINS] = GM.Globals[GM.PRINT_AGU_DOMAINS] (GC.PRINT_AGU_DOMAINS, GM.PRINT_AGU_DOMAINS),
if not GC.Values[GC.PRINT_CROS_OUS]: (GC.PRINT_CROS_OUS, GM.PRINT_CROS_OUS),
GC.Values[GC.PRINT_CROS_OUS] = GM.Globals[GM.PRINT_CROS_OUS] (GC.PRINT_CROS_OUS_AND_CHILDREN, GM.PRINT_CROS_OUS_AND_CHILDREN),
if not GC.Values[GC.PRINT_CROS_OUS_AND_CHILDREN]: ]
GC.Values[GC.PRINT_CROS_OUS_AND_CHILDREN] = GM.Globals[GM.PRINT_CROS_OUS_AND_CHILDREN] for gcItem, gmItem in _CHILD_INHERIT_SCALAR_ITEMS:
if not GC.Values[gcItem]:
GC.Values[gcItem] = GM.Globals[gmItem]
GC.Values[GC.SHOW_GETTINGS] = GM.Globals[GM.SHOW_GETTINGS] GC.Values[GC.SHOW_GETTINGS] = GM.Globals[GM.SHOW_GETTINGS]
GC.Values[GC.SHOW_GETTINGS_GOT_NL] = GM.Globals[GM.SHOW_GETTINGS_GOT_NL] GC.Values[GC.SHOW_GETTINGS_GOT_NL] = GM.Globals[GM.SHOW_GETTINGS_GOT_NL]
# customer_id, domain and admin_email must be set when enable_dasa = true # customer_id, domain and admin_email must be set when enable_dasa = true
@@ -1042,7 +1073,7 @@ def SetGlobalVariables():
if (Cmd.Location() == 1) or (Cmd.ArgumentsRemaining()): if (Cmd.Location() == 1) or (Cmd.ArgumentsRemaining()):
_chkCfgDirectories(sectionName) _chkCfgDirectories(sectionName)
if not Cmd.PeekArgumentPresent(['checkconn', 'checkconnection', 'comment', 'oauth', 'oauth2', 'version']): if not Cmd.PeekArgumentPresent(['checkconn', 'checkconnection', 'comment', 'oauth', 'oauth2', 'version']):
_chkCfgFiles(sectionName) _chkCfgFiles(status, sectionName)
if status['errors']: if status['errors']:
sys.exit(CONFIG_ERROR_RC) sys.exit(CONFIG_ERROR_RC)
if GC.Values[GC.NO_CACHE]: if GC.Values[GC.NO_CACHE]:
@@ -1066,3 +1097,15 @@ def SetGlobalVariables():
# We're done, nothing else to do # We're done, nothing else to do
return False return False
def SetGlobalVariables():
_initConfigParser()
status = {'errors': False}
sectionName, inputFilterSectionName, outputFilterSectionName = _selectConfigSection(status)
_fixupTodriveAndConfig(status, sectionName, inputFilterSectionName, outputFilterSectionName)
prevExtraArgsTxt, prevOauth2serviceJson = _assignConfigValues(status, sectionName, inputFilterSectionName, outputFilterSectionName)
_applyRuntimeDefaults(prevExtraArgsTxt, prevOauth2serviceJson)
_processRedirects(sectionName)
return _finalizeConfig(status, sectionName)