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,
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):
errMsg = str(e).replace('.', '')
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)
api, _, _ = API.getVersion(api)
audience = f'https://{api}.googleapis.com/'
key_type = jsonDict.get('key_type', 'default')
if key_type == 'default':
signer = _getSigner(jsonDict)
if signer is None:
return (True, JWTCredentials.from_service_account_info(jsonDict, audience=audience))
if key_type == 'yubikey':
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))
return (True, JWTCredentials._from_signer_and_info(signer, jsonDict, audience=audience))
except (IndexError, KeyError, SyntaxError, TypeError, ValueError) as e:
invalidOauth2serviceJsonExit(str(e))
invalidOauth2serviceJsonExit(Msg.NO_DATA)
@@ -615,19 +627,14 @@ def getSvcAcctCredentials(scopesOrAPI, userEmail, softErrors=False, forceOauth=F
else:
GM.Globals[GM.CURRENT_SVCACCT_API] = ''
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:
try:
if key_type == 'default':
credentials = google.oauth2.service_account.Credentials.from_service_account_info(GM.Globals[GM.OAUTH2SERVICE_JSON_DATA])
elif key_type == 'yubikey':
yksigner = yubikey.YubiKey(GM.Globals[GM.OAUTH2SERVICE_JSON_DATA])
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])
if signer is None:
credentials = google.oauth2.service_account.Credentials.from_service_account_info(svcacct_info)
else:
credentials = google.oauth2.service_account.Credentials._from_signer_and_info(signer, svcacct_info)
except (ValueError, IndexError, KeyError) as e:
if softErrors:
return None
@@ -636,19 +643,10 @@ def getSvcAcctCredentials(scopesOrAPI, userEmail, softErrors=False, forceOauth=F
else:
audience = f'https://{scopesOrAPI}.googleapis.com/'
try:
if key_type == 'default':
credentials = JWTCredentials.from_service_account_info(GM.Globals[GM.OAUTH2SERVICE_JSON_DATA],
audience=audience)
elif key_type == 'yubikey':
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)
if signer is None:
credentials = JWTCredentials.from_service_account_info(svcacct_info, audience=audience)
else:
credentials = JWTCredentials._from_signer_and_info(signer, svcacct_info, audience=audience)
credentials.project_id = GM.Globals[GM.OAUTH2SERVICE_JSON_DATA]['project_id']
except (ValueError, IndexError, KeyError) as e:
if softErrors:

View File

@@ -60,8 +60,18 @@ from gam.constants import (
FN_GAM_CFG, GAM,
)
def SetGlobalVariables():
REGEX_CHARS = '^$*+|$[{('
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):
@@ -110,7 +120,7 @@ def SetGlobalVariables():
Cmd.Backup()
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]])
Ind.Increment()
for section in [configparser.DEFAULTSECT]+sorted(GM.Globals[GM.PARSER].sections()):
@@ -139,7 +149,7 @@ def SetGlobalVariables():
if (data is not None) and writeFile(dstFile, data, continueOnError=True):
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('',
[Ent.Singular(Ent.CONFIG_FILE), GM.Globals[GM.GAM_CFG_FILE],
Ent.Singular(Ent.SECTION), sectionName,
@@ -153,16 +163,16 @@ def SetGlobalVariables():
else:
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()
if value in TRUE_VALUES:
return True
if value in FALSE_VALUES:
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
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)
if not value and (itemName == 'csv_output_field_delimiter'):
return ' '
@@ -170,25 +180,25 @@ def SetGlobalVariables():
return None
if len(value) == 1:
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 ''
def _getCfgChoice(sectionName, itemName):
def _getCfgChoice(status, sectionName, itemName):
value = _stripStringQuotes(GM.Globals[GM.PARSER].get(sectionName, itemName)).lower()
choices = GC.VAR_INFO[itemName][GC.VAR_CHOICES]
if value in choices:
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 ''
def _getCfgLocale(sectionName, itemName):
def _getCfgLocale(status, sectionName, itemName):
value = _stripStringQuotes(GM.Globals[GM.PARSER].get(sectionName, itemName)).lower().replace('_', '-')
if value in LOCALE_CODES_MAP:
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 ''
def _getCfgNumber(sectionName, itemName):
def _getCfgNumber(status, sectionName, itemName):
value = GM.Globals[GM.PARSER].get(sectionName, itemName)
minVal, maxVal = GC.VAR_INFO[itemName][GC.VAR_LIMITS]
try:
@@ -199,14 +209,14 @@ def SetGlobalVariables():
number = minVal
else:
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
except ValueError:
pass
_printValueError(sectionName, itemName, value, f'{Msg.EXPECTED}: {integerLimits(minVal, maxVal)}')
_printValueError(status, sectionName, itemName, value, f'{Msg.EXPECTED}: {integerLimits(minVal, maxVal)}')
return 0
def _getCfgHeaderFilter(sectionName, itemName):
def _getCfgHeaderFilter(status, sectionName, itemName):
value = GM.Globals[GM.PARSER].get(sectionName, itemName)
headerFilters = []
if not value or (len(value) == 2 and _stringInQuotes(value)):
@@ -217,32 +227,22 @@ def SetGlobalVariables():
try:
headerFilters.append(re.compile(filterStr, re.IGNORECASE))
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:
_printValueError(sectionName, itemName, f'"{value}"', f'{Msg.INVALID_LIST}: {filters}')
_printValueError(status, sectionName, itemName, f'"{value}"', f'{Msg.INVALID_LIST}: {filters}')
return headerFilters
def _getCfgHeaderFilterFromForce(sectionName, itemName):
def _getCfgHeaderFilterFromForce(status, sectionName, itemName):
headerFilters = []
for filterStr in GC.Values[itemName]:
try:
headerFilters.append(re.compile(fr'^{filterStr}$'))
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
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)
rowFilters = []
if not value:
@@ -251,13 +251,13 @@ def SetGlobalVariables():
try:
filterDict = json.loads(value.encode('unicode-escape').decode(UTF8))
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
else:
filterDict = {}
status, filterList = shlexSplitListStatus(value)
if not status:
_printValueError(sectionName, itemName, f'"{value}"', f'{Msg.FAILED_TO_PARSE_AS_LIST}: {str(filterList)}')
splitOk, filterList = shlexSplitListStatus(value)
if not splitOk:
_printValueError(status, sectionName, itemName, f'"{value}"', f'{Msg.FAILED_TO_PARSE_AS_LIST}: {str(filterList)}')
return rowFilters
for filterVal in filterList:
if not filterVal:
@@ -267,7 +267,7 @@ def SetGlobalVariables():
column = filterTokens[0]
filterStr = ':'.join(filterTokens[1:])
except ValueError:
_printValueError(sectionName, itemName, f'"{filterVal}"', f'{Msg.EXPECTED}: column:filter')
_printValueError(status, sectionName, itemName, f'"{filterVal}"', f'{Msg.EXPECTED}: column:filter')
continue
filterDict[column] = filterStr
for column, filterStr in filterDict.items():
@@ -280,7 +280,7 @@ def SetGlobalVariables():
try:
columnPat = re.compile(columnPat, re.IGNORECASE)
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
anyMatch = True
mg = ROW_FILTER_ANY_ALL_PATTERN.match(filterStr)
@@ -298,12 +298,12 @@ def SetGlobalVariables():
if valid:
rowFilters.append((columnPat, anyMatch, filterType, mg.group(2), filterValue))
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'}:
if mg.group(3).isdigit():
rowFilters.append((columnPat, anyMatch, filterType, mg.group(2), int(mg.group(3))))
else:
_printValueError(sectionName, itemName, f'"{column}": "{filterStr}"', f'{Msg.EXPECTED}: <Number>')
_printValueError(status, sectionName, itemName, f'"{column}": "{filterStr}"', f'{Msg.EXPECTED}: <Number>')
continue
mg = ROW_FILTER_TEXT_PATTERN.match(filterStr)
if mg:
@@ -328,12 +328,12 @@ def SetGlobalVariables():
if valid1 and valid2:
rowFilters.append((columnPat, anyMatch, filterType, mg.group(2), filterValue1, filterValue2))
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
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))))
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
mg = ROW_FILTER_TIMEOFDAYRANGE_PATTERN.match(filterStr)
if mg:
@@ -357,7 +357,7 @@ def SetGlobalVariables():
elif filterValue in FALSE_VALUES:
rowFilters.append((columnPat, anyMatch, filterType, False))
else:
_printValueError(sectionName, itemName, f'"{column}": "{filterStr}"', f'{Msg.EXPECTED}: <Boolean>')
_printValueError(status, sectionName, itemName, f'"{column}": "{filterStr}"', f'{Msg.EXPECTED}: <Boolean>')
continue
mg = ROW_FILTER_RE_PATTERN.match(filterStr)
if mg:
@@ -370,7 +370,7 @@ def SetGlobalVariables():
flags = re.IGNORECASE
rowFilters.append((columnPat, anyMatch, filterType, re.compile(mg.group(2), flags)))
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
mg = ROW_FILTER_DATA_PATTERN.match(filterStr)
if mg:
@@ -386,19 +386,19 @@ def SetGlobalVariables():
rowFilters.append((columnPat, anyMatch, filterType, getEntitiesFromCSVFile(False, returnSet=True)))
Cmd.RestoreArguments()
continue
_printValueError(sectionName, itemName, f'"{column}": "{filterStr}"', f'{Msg.EXPECTED}: <RowValueFilter>')
_printValueError(status, sectionName, itemName, f'"{column}": "{filterStr}"', f'{Msg.EXPECTED}: <RowValueFilter>')
return rowFilters
def _getCfgSection(sectionName, itemName):
def _getCfgSection(status, sectionName, itemName):
value = _stripStringQuotes(GM.Globals[GM.PARSER].get(sectionName, itemName))
if (not value) or (value.upper() == configparser.DEFAULTSECT):
return configparser.DEFAULTSECT
if GM.Globals[GM.PARSER].has_section(value):
return value
_printValueError(sectionName, itemName, value, Msg.NOT_FOUND)
_printValueError(status, sectionName, itemName, value, Msg.NOT_FOUND)
return configparser.DEFAULTSECT
def _getCfgPassword(sectionName, itemName):
def _getCfgPassword(status, sectionName, itemName):
value = GM.Globals[GM.PARSER].get(sectionName, itemName)
if isinstance(value, bytes):
return value
@@ -409,59 +409,59 @@ def SetGlobalVariables():
return value
return ''
def _validateLicenseSKUs(sectionName, itemName, skuList):
def _validateLicenseSKUs(status, sectionName, itemName, skuList):
GM.Globals[GM.LICENSE_SKUS] = []
for sku in skuList.split(','):
if '/' not in sku:
productId, sku = SKU.getProductAndSKU(sku)
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:
(productId, sku) = sku.split('/')
if (productId, sku) not in GM.Globals[GM.LICENSE_SKUS]:
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()
validAPIs = API.getAPIsList()
for api in apiList.split(','):
if api in validAPIs:
GM.Globals[GM.DEVELOPER_PREVIEW_APIS].add(api)
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)
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))
if itemName == GC.DOMAIN:
value = value.strip()
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 itemName == GC.LICENSE_SKUS and value:
_validateLicenseSKUs(sectionName, itemName, value)
_validateLicenseSKUs(status, sectionName, itemName, 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:
_validateGCPOrgId(sectionName, itemName, value)
_validateGCPOrgId(status, sectionName, itemName, 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 ''
def _getCfgStringList(sectionName, itemName):
def _getCfgStringList(status, sectionName, itemName):
value = GM.Globals[GM.PARSER].get(sectionName, itemName)
stringlist = []
if not value or (len(value) == 2 and _stringInQuotes(value)):
return stringlist
splitStatus, stringlist = shlexSplitListStatus(value)
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
def _getCfgTimezone(sectionName, itemName):
def _getCfgTimezone(status, sectionName, itemName):
value = _stripStringQuotes(GM.Globals[GM.PARSER].get(sectionName, itemName))
if value.lower() in {'utc', 'z'}:
GM.Globals[GM.CONVERT_TO_LOCAL_TIME] = False
@@ -472,11 +472,11 @@ def SetGlobalVariables():
try:
return arrow.now(value).tzinfo
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
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)))
if (not dirPath) and (itemName in {GC.GMAIL_CSE_INCERT_DIR, GC.GMAIL_CSE_INKEY_DIR, GC.INPUT_DIR}):
return dirPath
@@ -487,10 +487,10 @@ def SetGlobalVariables():
dirPath = os.path.join(GM.Globals[GM.GAM_CFG_PATH], dirPath)
return dirPath
def _getCfgFile(sectionName, itemName):
def _getCfgFile(status, sectionName, itemName):
value = os.path.expanduser(_stripStringQuotes(GM.Globals[GM.PARSER].get(sectionName, itemName)))
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:
value = os.path.join(GM.Globals[GM.GAM_PATH], GC.FN_CACERTS_PEM)
return value
@@ -541,11 +541,11 @@ def SetGlobalVariables():
elif varType not in [GC.TYPE_BOOLEAN, GC.TYPE_INTEGER, GC.TYPE_FLOAT, GC.TYPE_PASSWORD]:
cfgValue = _quoteStringIfLeadingTrailingBlanks(cfgValue)
if varType == GC.TYPE_FILE:
expdValue = _getCfgFile(sectName, itemName)
expdValue = _getCfgFile(None, sectName, itemName)
if cfgValue not in ("''", expdValue):
cfgValue = f'{cfgValue} ; {expdValue}'
elif varType == GC.TYPE_DIRECTORY:
expdValue = _getCfgDirectory(sectName, itemName)
expdValue = _getCfgDirectory(None, sectName, itemName)
if cfgValue not in ("''", expdValue):
cfgValue = f'{cfgValue} ; {expdValue}'
elif (itemName == GC.SECTION) and (sectName != configparser.DEFAULTSECT):
@@ -568,7 +568,7 @@ def SetGlobalVariables():
Msg.INVALID_PATH],
'\n'))
def _chkCfgFiles(sectionName):
def _chkCfgFiles(status, sectionName):
for itemName, itemEntry in GC.VAR_INFO.items():
if itemEntry[GC.VAR_TYPE] == GC.TYPE_FILE:
fileName = GC.Values[itemName]
@@ -644,9 +644,6 @@ def SetGlobalVariables():
GM.Globals[stdtype][GM.REDIRECT_MULTIPROCESS] = multi
GM.Globals[stdtype][GM.REDIRECT_QUEUE] = 'stdout' if stdtype == GM.STDOUT else 'stderr'
MULTIPROCESS_EXIT_COMP_PATTERN = re.compile(r'^rc([<>]=?|=|!=)(.+)$', re.IGNORECASE)
MULTIPROCESS_EXIT_RANGE_PATTERN = re.compile(r'^rcrange(=|!=)(\S+)/(\S+)$', re.IGNORECASE)
def _setMultiprocessExit():
rcStr = getString(Cmd.OB_STRING)
mg = MULTIPROCESS_EXIT_COMP_PATTERN.match(rcStr)
@@ -663,6 +660,26 @@ def SetGlobalVariables():
return
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]:
homePath = os.path.expanduser('~')
GM.Globals[GM.GAM_CFG_PATH] = os.environ.get(EV_GAMCFGDIR, None)
@@ -694,7 +711,13 @@ def SetGlobalVariables():
else:
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])
status = {'errors': False}
def _selectConfigSection(status):
"""Determine which config section to use and process select/filter commands.
Returns (sectionName, inputFilterSectionName, outputFilterSectionName).
"""
inputFilterSectionName = outputFilterSectionName = None
GM.Globals[GM.GAM_CFG_SECTION] = os.environ.get(EV_GAMCFGSECTION, None)
if GM.Globals[GM.GAM_CFG_SECTION]:
@@ -706,7 +729,7 @@ def SetGlobalVariables():
Cmd.Backup()
usageErrorExit(formatKeyValueList('', [EV_GAMCFGSECTION, sectionName, 'select', Msg.NOT_ALLOWED], ''))
else:
sectionName = _getCfgSection(configparser.DEFAULTSECT, GC.SECTION)
sectionName = _getCfgSection(status, configparser.DEFAULTSECT, GC.SECTION)
# select <SectionName> [save] [verify [variables <RESearchPattern>]]
if checkArgumentPresent(Cmd.SELECT_CMD):
sectionName = _selectSection()
@@ -728,7 +751,7 @@ def SetGlobalVariables():
GM.Globals[GM.GAM_CFG_SECTION_NAME] = sectionName
# showsections
if checkArgumentPresent(Cmd.SHOWSECTIONS_CMD):
_showSections()
_showSections(sectionName)
# selectfilter|selectoutputfilter|selectinputfilter <SectionName>
while True:
filterCommand = getChoice([Cmd.SELECTFILTER_CMD, Cmd.SELECTOUTPUTFILTER_CMD, Cmd.SELECTINPUTFILTER_CMD], defaultChoice=None)
@@ -738,21 +761,26 @@ def SetGlobalVariables():
outputFilterSectionName = _selectSection()
else:
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
value = GM.Globals[GM.PARSER].get(configparser.DEFAULTSECT, GC.TODRIVE_NOBROWSER)
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)
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
for section in [sectionName, configparser.DEFAULTSECT]:
value = GM.Globals[GM.PARSER].get(section, GC.TODRIVE_SHEET_TIMESTAMP)
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)
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
for section in [configparser.DEFAULTSECT, sectionName]:
if GM.Globals[GM.PARSER].has_option(section, GC.CMDLOG_MAX__BACKUPS):
@@ -771,96 +799,88 @@ def SetGlobalVariables():
break
itemEntry = GC.VAR_INFO[itemName]
checkArgumentPresent('=')
varType = itemEntry[GC.VAR_TYPE]
if varType == GC.TYPE_BOOLEAN:
match varType:
case GC.TYPE_BOOLEAN:
value = TRUE if getBoolean(None) else FALSE
elif varType == GC.TYPE_CHARACTER:
case GC.TYPE_CHARACTER:
value = getCharacter()
elif varType == GC.TYPE_CHOICE:
case GC.TYPE_CHOICE:
value = getChoice(itemEntry[GC.VAR_CHOICES])
elif varType == GC.TYPE_INTEGER:
case GC.TYPE_INTEGER:
minVal, maxVal = itemEntry[GC.VAR_LIMITS]
value = str(getInteger(minVal=minVal, maxVal=maxVal))
elif varType == GC.TYPE_FLOAT:
case GC.TYPE_FLOAT:
minVal, maxVal = itemEntry[GC.VAR_LIMITS]
value = str(getFloat(minVal=minVal, maxVal=maxVal))
elif varType == GC.TYPE_LOCALE:
case GC.TYPE_LOCALE:
value = getLanguageCode(LOCALE_CODES_MAP)
elif varType == GC.TYPE_PASSWORD:
case GC.TYPE_PASSWORD:
minLen, maxLen = itemEntry[GC.VAR_LIMITS]
value = getString(Cmd.OB_STRING, checkBlank=True, minLen=minLen, maxLen=maxLen)
if value and value.startswith("b'") and value.endswith("'"):
value = bytes(value[2:-1], UTF8)
elif varType == GC.TYPE_TIMEZONE:
case GC.TYPE_TIMEZONE:
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))
value = _quoteStringIfLeadingTrailingBlanks(getString(Cmd.OB_STRING, minLen=minLen, maxLen=maxLen))
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)
prevOauth2serviceJson = GC.Values.get(GC.OAUTH2SERVICE_JSON, None)
# Assign global variables, directories, timezone first as other variables depend on them
for itemName, itemEntry in sorted(GC.VAR_INFO.items()):
varType = itemEntry[GC.VAR_TYPE]
if varType == GC.TYPE_DIRECTORY:
GC.Values[itemName] = _getCfgDirectory(sectionName, itemName)
GC.Values[itemName] = _getCfgDirectory(status, sectionName, itemName)
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])
# Everything else except row filters
for itemName, itemEntry in sorted(GC.VAR_INFO.items()):
varType = itemEntry[GC.VAR_TYPE]
if varType == GC.TYPE_BOOLEAN:
GC.Values[itemName] = _getCfgBoolean(sectionName, itemName)
elif varType == GC.TYPE_CHARACTER:
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)
handler = _CFG_TYPE_HANDLERS.get(varType)
if handler:
GC.Values[itemName] = handler(status, sectionName, itemName)
# Row filters
for itemName, itemEntry in sorted(GC.VAR_INFO.items()):
varType = itemEntry[GC.VAR_TYPE]
if varType == GC.TYPE_ROWFILTER:
GC.Values[itemName] = _getCfgRowFilter(sectionName, itemName)
GC.Values[itemName] = _getCfgRowFilter(status, sectionName, itemName)
# Process selectfilter|selectoutputfilter|selectinputfilter
if inputFilterSectionName:
GC.Values[GC.CSV_INPUT_ROW_FILTER] = _getCfgRowFilter(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_DROP_FILTER] = _getCfgRowFilter(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_LIMIT] = _getCfgNumber(inputFilterSectionName, GC.CSV_INPUT_ROW_LIMIT)
GC.Values[GC.CSV_INPUT_ROW_FILTER] = _getCfgRowFilter(status, inputFilterSectionName, GC.CSV_INPUT_ROW_FILTER)
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(status, inputFilterSectionName, GC.CSV_INPUT_ROW_DROP_FILTER)
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(status, inputFilterSectionName, GC.CSV_INPUT_ROW_LIMIT)
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]:
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:
GC.Values[GC.CSV_OUTPUT_HEADER_FILTER] = _getCfgHeaderFilter(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_ORDER] = _getCfgStringList(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_ROW_FILTER] = _getCfgRowFilter(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_DROP_FILTER] = _getCfgRowFilter(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_LIMIT] = _getCfgNumber(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_HEADER_FILTER] = _getCfgHeaderFilter(status, outputFilterSectionName, GC.CSV_OUTPUT_HEADER_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(status, outputFilterSectionName, GC.CSV_OUTPUT_HEADER_ORDER)
GC.Values[GC.CSV_OUTPUT_HEADER_REQUIRED] = _getCfgStringList(status, outputFilterSectionName, GC.CSV_OUTPUT_HEADER_REQUIRED)
GC.Values[GC.CSV_OUTPUT_ROW_FILTER] = _getCfgRowFilter(status, outputFilterSectionName, GC.CSV_OUTPUT_ROW_FILTER)
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(status, outputFilterSectionName, GC.CSV_OUTPUT_ROW_DROP_FILTER)
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(status, outputFilterSectionName, GC.CSV_OUTPUT_ROW_LIMIT)
GC.Values[GC.CSV_OUTPUT_SORT_HEADERS] = _getCfgStringList(status, outputFilterSectionName, GC.CSV_OUTPUT_SORT_HEADERS)
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']:
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
GC.Values[GC.DOMAIN] = GC.Values[GC.DOMAIN].lower()
if not GC.Values[GC.SMTP_FQDN]:
@@ -894,6 +914,10 @@ def SetGlobalVariables():
GM.Globals[GM.OAUTH2SERVICE_JSON_DATA] = {}
GM.Globals[GM.OAUTH2SERVICE_CLIENT_ID] = None
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>)
if checkArgumentPresent(Cmd.MULTIPROCESSEXIT_CMD):
_setMultiprocessExit()
@@ -909,7 +933,8 @@ def SetGlobalVariables():
while checkArgumentPresent(Cmd.REDIRECT_CMD):
myarg = getChoice(['csv', 'stdout', 'stderr'])
filename = re.sub(r'{{Section}}', sectionName, getString(Cmd.OB_FILE_NAME, checkBlank=True))
if myarg == 'csv':
match myarg:
case 'csv':
multi = False
mode = DEFAULT_FILE_WRITE_MODE
writeHeader = True
@@ -947,7 +972,7 @@ def SetGlobalVariables():
if checkArgumentPresent('todrive'):
GM.Globals[GM.CSVFILE][GM.REDIRECT_QUEUE_CSVPF].GetTodriveParameters()
GM.Globals[GM.CSV_TODRIVE] = GM.Globals[GM.CSVFILE][GM.REDIRECT_QUEUE_CSVPF].todrive.copy()
elif myarg == 'stdout':
case 'stdout':
if filename.lower() == 'null':
multi = checkArgumentPresent('multiprocess')
_setSTDFile(GM.STDOUT, 'null', DEFAULT_FILE_WRITE_MODE, multi)
@@ -955,7 +980,7 @@ def SetGlobalVariables():
multi = checkArgumentPresent('multiprocess')
mode = DEFAULT_FILE_APPEND_MODE if checkArgumentPresent('append') else DEFAULT_FILE_WRITE_MODE
_setSTDFile(GM.STDOUT, filename, mode, multi)
else: # myarg == 'stderr'
case 'stderr':
if filename.lower() == 'null':
multi = checkArgumentPresent('multiprocess')
_setSTDFile(GM.STDERR, 'null', DEFAULT_FILE_WRITE_MODE, multi)
@@ -983,6 +1008,10 @@ def SetGlobalVariables():
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)
initAPICallsRateCheck()
def _finalizeConfig(status, sectionName):
"""Finalize config: filter inheritance, DASA validation, env vars, return."""
# Main process
# 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
@@ -996,16 +1025,16 @@ def SetGlobalVariables():
# Child process
# Inherit main process output header/row filters/limit, print defaults if not locally defined
else:
if not GC.Values[GC.CSV_OUTPUT_HEADER_FILTER]:
GC.Values[GC.CSV_OUTPUT_HEADER_FILTER] = GM.Globals[GM.CSV_OUTPUT_HEADER_FILTER][:]
if not GC.Values[GC.CSV_OUTPUT_HEADER_DROP_FILTER]:
GC.Values[GC.CSV_OUTPUT_HEADER_DROP_FILTER] = GM.Globals[GM.CSV_OUTPUT_HEADER_DROP_FILTER][:]
if not GC.Values[GC.CSV_OUTPUT_HEADER_FORCE]:
GC.Values[GC.CSV_OUTPUT_HEADER_FORCE] = GM.Globals[GM.CSV_OUTPUT_HEADER_FORCE][:]
if not GC.Values[GC.CSV_OUTPUT_HEADER_ORDER]:
GC.Values[GC.CSV_OUTPUT_HEADER_ORDER] = GM.Globals[GM.CSV_OUTPUT_HEADER_ORDER][:]
if not GC.Values[GC.CSV_OUTPUT_HEADER_REQUIRED]:
GC.Values[GC.CSV_OUTPUT_HEADER_REQUIRED] = GM.Globals[GM.CSV_OUTPUT_HEADER_REQUIRED][:]
_CHILD_INHERIT_LIST_ITEMS = [
(GC.CSV_OUTPUT_HEADER_FILTER, GM.CSV_OUTPUT_HEADER_FILTER),
(GC.CSV_OUTPUT_HEADER_DROP_FILTER, GM.CSV_OUTPUT_HEADER_DROP_FILTER),
(GC.CSV_OUTPUT_HEADER_FORCE, GM.CSV_OUTPUT_HEADER_FORCE),
(GC.CSV_OUTPUT_HEADER_ORDER, GM.CSV_OUTPUT_HEADER_ORDER),
(GC.CSV_OUTPUT_HEADER_REQUIRED, GM.CSV_OUTPUT_HEADER_REQUIRED),
]
for gcItem, gmItem in _CHILD_INHERIT_LIST_ITEMS:
if not GC.Values[gcItem]:
GC.Values[gcItem] = GM.Globals[gmItem][:]
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_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]
if not GC.Values[GC.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]:
GC.Values[GC.PRINT_AGU_DOMAINS] = GM.Globals[GM.PRINT_AGU_DOMAINS]
if not GC.Values[GC.PRINT_CROS_OUS]:
GC.Values[GC.PRINT_CROS_OUS] = GM.Globals[GM.PRINT_CROS_OUS]
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]
_CHILD_INHERIT_SCALAR_ITEMS = [
(GC.PRINT_AGU_DOMAINS, GM.PRINT_AGU_DOMAINS),
(GC.PRINT_CROS_OUS, GM.PRINT_CROS_OUS),
(GC.PRINT_CROS_OUS_AND_CHILDREN, 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_GOT_NL] = GM.Globals[GM.SHOW_GETTINGS_GOT_NL]
# 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()):
_chkCfgDirectories(sectionName)
if not Cmd.PeekArgumentPresent(['checkconn', 'checkconnection', 'comment', 'oauth', 'oauth2', 'version']):
_chkCfgFiles(sectionName)
_chkCfgFiles(status, sectionName)
if status['errors']:
sys.exit(CONFIG_ERROR_RC)
if GC.Values[GC.NO_CACHE]:
@@ -1066,3 +1097,15 @@ def SetGlobalVariables():
# We're done, nothing else to do
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)