diff --git a/src/gam/__init__.py b/src/gam/__init__.py index b6845d24..ce9aa2f2 100755 --- a/src/gam/__init__.py +++ b/src/gam/__init__.py @@ -228,373 +228,22 @@ def redactable_debug_print(*args): # Multiprocessing lock mplock = None -# stdin/stdout/stderr — extracted to gam.util.output -from util.output import readStdin # noqa: E402 -from util.output import stdErrorExit # noqa: E402 -from util.output import writeStdout # noqa: E402 -from util.output import flushStdout # noqa: E402 -from util.output import writeStderr # noqa: E402 -from util.output import flushStderr # noqa: E402 -from util.output import setSysExitRC # noqa: E402 -from util.output import stderrErrorMsg # noqa: E402 -from util.output import stderrWarningMsg # noqa: E402 -from util.output import systemErrorExit # noqa: E402 -from util.output import printErrorMessage # noqa: E402 -from util.output import printWarningMessage # noqa: E402 -from util.output import supportsColoredText # noqa: E402 -from util.output import createColoredText # noqa: E402 -from util.output import createRedText # noqa: E402 -from util.output import createGreenText # noqa: E402 -from util.output import createYellowText # noqa: E402 -from util.output import executeBatch # noqa: E402 -from util.output import _stripControlCharsFromName # noqa: E402 -from util.output import currentCount # noqa: E402 -from util.output import currentCountNL # noqa: E402 -from util.output import formatKeyValueList # noqa: E402 - -# File I/O — extracted to gam.util.fileio -from util.fileio import cleanFilename # noqa: E402 -from util.fileio import setFilePath # noqa: E402 -from util.fileio import uniqueFilename # noqa: E402 -from util.fileio import cleanFilepath # noqa: E402 -from util.fileio import fileErrorMessage # noqa: E402 -from util.fileio import fdErrorMessage # noqa: E402 -from util.fileio import setEncoding # noqa: E402 -from util.fileio import StringIOobject # noqa: E402 -from util.fileio import openFile # noqa: E402 -from util.fileio import closeFile # noqa: E402 -from util.fileio import readFile # noqa: E402 -from util.fileio import writeFile # noqa: E402 -from util.fileio import writeFileReturnError # noqa: E402 -from util.fileio import deleteFile # noqa: E402 -from util.fileio import getGDocSheetDataRetryWarning # noqa: E402 -from util.fileio import getGDocSheetDataFailedExit # noqa: E402 -from util.fileio import incrAPICallsRetryData # noqa: E402 -from util.fileio import initAPICallsRateCheck # noqa: E402 -from util.fileio import checkAPICallsRate # noqa: E402 -from util.fileio import openGAMCommandLog # noqa: E402 -from util.fileio import writeGAMCommandLog # noqa: E402 -from util.fileio import closeGAMCommandLog # noqa: E402 - -# Display / warning / action — extracted to gam.util.display -from util.display import badRequestWarning # noqa: E402 -from util.display import emptyQuery # noqa: E402 -from util.display import invalidQuery # noqa: E402 -from util.display import invalidMember # noqa: E402 -from util.display import invalidUserSchema # noqa: E402 -from util.display import userServiceNotEnabledWarning # noqa: E402 -from util.display import userAlertsServiceNotEnabledWarning # noqa: E402 -from util.display import userAnalyticsServiceNotEnabledWarning # noqa: E402 -from util.display import userCalServiceNotEnabledWarning # noqa: E402 -from util.display import userChatServiceNotEnabledWarning # noqa: E402 -from util.display import userContactDelegateServiceNotEnabledWarning # noqa: E402 -from util.display import userDriveServiceNotEnabledWarning # noqa: E402 -from util.display import userKeepServiceNotEnabledWarning # noqa: E402 -from util.display import userGmailServiceNotEnabledWarning # noqa: E402 -from util.display import userLookerStudioServiceNotEnabledWarning # noqa: E402 -from util.display import userPeopleServiceNotEnabledWarning # noqa: E402 -from util.display import userTasksServiceNotEnabledWarning # noqa: E402 -from util.display import userYouTubeServiceNotEnabledWarning # noqa: E402 -from util.display import entityServiceNotApplicableWarning # noqa: E402 -from util.display import entityDoesNotExistWarning # noqa: E402 -from util.display import entityListDoesNotExistWarning # noqa: E402 -from util.display import entityDoesNotHaveItemWarning # noqa: E402 -from util.display import entityDuplicateWarning # noqa: E402 -from util.display import entityActionFailedWarning # noqa: E402 -from util.display import entityModifierItemValueListActionFailedWarning # noqa: E402 -from util.display import entityModifierActionFailedWarning # noqa: E402 -from util.display import entityModifierNewValueActionFailedWarning # noqa: E402 -from util.display import entityNumEntitiesActionFailedWarning # noqa: E402 -from util.display import entityActionNotPerformedWarning # noqa: E402 -from util.display import entityItemValueListActionNotPerformedWarning # noqa: E402 -from util.display import entityModifierItemValueListActionNotPerformedWarning # noqa: E402 -from util.display import entityNumEntitiesActionNotPerformedWarning # noqa: E402 -from util.display import entityBadRequestWarning # noqa: E402 -from util.display import printGettingAllAccountEntities # noqa: E402 -from util.display import printGotAccountEntities # noqa: E402 -from util.display import setGettingAllEntityItemsForWhom # noqa: E402 -from util.display import printGettingAllEntityItemsForWhom # noqa: E402 -from util.display import printGotEntityItemsForWhom # noqa: E402 -from util.display import printGettingEntityItem # noqa: E402 -from util.display import printGettingEntityItemForWhom # noqa: E402 -from util.display import stderrEntityMessage # noqa: E402 -from util.display import FIRST_ITEM_MARKER # noqa: E402 -from util.display import LAST_ITEM_MARKER # noqa: E402 -from util.display import TOTAL_ITEMS_MARKER # noqa: E402 -from util.display import getPageMessage # noqa: E402 -from util.display import getPageMessageForWhom # noqa: E402 -from util.display import printLine # noqa: E402 -from util.display import printBlankLine # noqa: E402 -from util.display import printKeyValueList # noqa: E402 -from util.display import printKeyValueListWithCount # noqa: E402 -from util.display import printKeyValueDict # noqa: E402 -from util.display import printKeyValueWithCRsNLs # noqa: E402 -from util.display import printJSONKey # noqa: E402 -from util.display import printJSONValue # noqa: E402 -from util.display import printEntity # noqa: E402 -from util.display import printEntityMessage # noqa: E402 -from util.display import printEntitiesCount # noqa: E402 -from util.display import printEntityKVList # noqa: E402 -from util.display import performAction # noqa: E402 -from util.display import performActionNumItems # noqa: E402 -from util.display import performActionModifierNumItems # noqa: E402 -from util.display import actionPerformedNumItems # noqa: E402 -from util.display import actionFailedNumItems # noqa: E402 -from util.display import actionNotPerformedNumItemsWarning # noqa: E402 -from util.display import entityPerformAction # noqa: E402 -from util.display import entityPerformActionNumItems # noqa: E402 -from util.display import entityPerformActionModifierNumItems # noqa: E402 -from util.display import entityPerformActionNumItemsModifier # noqa: E402 -from util.display import entityPerformActionSubItemModifierNumItems # noqa: E402 -from util.display import entityPerformActionSubItemModifierNumItemsModifierNewValue # noqa: E402 -from util.display import entityPerformActionModifierNumItemsModifier # noqa: E402 -from util.display import entityPerformActionModifierItemValueList # noqa: E402 -from util.display import entityPerformActionModifierNewValue # noqa: E402 -from util.display import entityPerformActionModifierNewValueItemValueList # noqa: E402 -from util.display import entityPerformActionItemValue # noqa: E402 -from util.display import entityPerformActionInfo # noqa: E402 -from util.display import entityActionPerformed # noqa: E402 -from util.display import entityActionPerformedMessage # noqa: E402 -from util.display import entityNumItemsActionPerformed # noqa: E402 -from util.display import entityModifierActionPerformed # noqa: E402 -from util.display import entityModifierItemValueListActionPerformed # noqa: E402 -from util.display import entityModifierNewValueActionPerformed # noqa: E402 -from util.display import entityModifierNewValueItemValueListActionPerformed # noqa: E402 -from util.display import entityModifierNewValueKeyValueActionPerformed # noqa: E402 - -from util.errors import invalidClientSecretsJsonExit # noqa: E402 -from util.errors import invalidOauth2serviceJsonExit # noqa: E402 -from util.errors import invalidOauth2TxtExit # noqa: E402 -from util.errors import expiredRevokedOauth2TxtExit # noqa: E402 -from util.errors import invalidDiscoveryJsonExit # noqa: E402 -from util.errors import entityActionFailedExit # noqa: E402 -from util.errors import entityDoesNotExistExit # noqa: E402 -from util.errors import entityDoesNotHaveItemExit # noqa: E402 -from util.errors import entityIsNotUniqueExit # noqa: E402 -from util.errors import usageErrorExit # noqa: E402 -from util.errors import csvFieldErrorExit # noqa: E402 -from util.errors import csvDataAlreadySavedErrorExit # noqa: E402 +# Imports used by __init__.py's own dispatch tables and functions +from util.output import setSysExitRC, systemErrorExit, printErrorMessage # noqa: E402 +from util.output import writeStderr, formatKeyValueList # noqa: E402 from util.errors import unknownArgumentExit # noqa: E402 -from util.errors import expectedArgumentExit # noqa: E402 -from util.errors import blankArgumentExit # noqa: E402 -from util.errors import emptyArgumentExit # noqa: E402 -from util.errors import invalidArgumentExit # noqa: E402 -from util.errors import missingArgumentExit # noqa: E402 -from util.errors import deprecatedArgument # noqa: E402 -from util.errors import deprecatedArgumentExit # noqa: E402 -from util.errors import deprecatedCommandExit # noqa: E402 -from util.errors import formatChoiceList # noqa: E402 -from util.errors import invalidChoiceExit # noqa: E402 -from util.errors import missingChoiceExit # noqa: E402 - -from util.args import * # noqa: E402,F403 - re-exports ~155 symbols - -from util.connection import getLocalGoogleTimeOffset # noqa: E402 -from util.connection import _getServerTLSUsed # noqa: E402 -from util.connection import getOSPlatform # noqa: E402 -from util.connection import inspect_untrusted_cert # noqa: E402 -from util.connection import doCheckConnection # noqa: E402 -from util.connection import doComment # noqa: E402 -from util.connection import doVersion # noqa: E402 -from util.connection import doUsage # noqa: E402 -from util.connection import MACOS_CODENAMES # noqa: E402 - -# API transport, service builders, and call wrappers — extracted to gam.util.api -from util.api import handleServerError # noqa: E402 -from util.api import getHttpObj # noqa: E402 -from util.api import _force_user_agent # noqa: E402 -from util.api import transportAgentRequest # noqa: E402 -from util.api import transportAuthorizedHttp # noqa: E402 -from util.api import transportCreateRequest # noqa: E402 -from util.api import doGAMCheckForUpdates # noqa: E402 -from util.api import signjwtJWTCredentials # noqa: E402 -from util.api import signjwtCredentials # noqa: E402 -from util.api import get_adc_request # noqa: E402 -from util.api import signjwtSignJwt # noqa: E402 -from util.api import handleOAuthTokenError # noqa: E402 -from util.api import getOauth2TxtCredentials # noqa: E402 -from util.api import _getValueFromOAuth # noqa: E402 -from util.api import _getAdminEmail # noqa: E402 -from util.api import writeClientCredentials # noqa: E402 -from util.api import shortenURL # noqa: E402 -from util.api import runSqliteQuery # noqa: E402 -from util.api import refreshCredentialsWithReauth # noqa: E402 -from util.api import getClientCredentials # noqa: E402 -from util.api import waitOnFailure # noqa: E402 -from util.api import clearServiceCache # noqa: E402 -from util.api import getAPIService # noqa: E402 -from util.api import getService # noqa: E402 -from util.api import defaultSvcAcctScopes # noqa: E402 -from util.api import _getSvcAcctData # noqa: E402 -from util.api import getSvcAcctCredentials # noqa: E402 -from util.api import getGDataOAuthToken # noqa: E402 -from util.api import checkGDataError # noqa: E402 -from util.api import callGData # noqa: E402 -from util.api import callGDataPages # noqa: E402 -from util.api import checkGAPIError # noqa: E402 -from util.api import callGAPI # noqa: E402 -from util.api import _showGAPIpagesResult # noqa: E402 -from util.api import callGAPIpages # noqa: E402 -from util.api import yieldGAPIpages # noqa: E402 -from util.api import callGAPIitems # noqa: E402 -from util.api import readDiscoveryFile # noqa: E402 -from util.api import buildGAPIObject # noqa: E402 -from util.api import buildGAPIServiceObject # noqa: E402 -from util.api import buildGAPIObjectNoAuthentication # noqa: E402 -from util.api import initGDataObject # noqa: E402 -from util.api import getGDataUserCredentials # noqa: E402 -from util.api import getContactsObject # noqa: E402 -from util.api import getContactsQuery # noqa: E402 -from util.api import getEmailAuditObject # noqa: E402 -from util.api import _processGAPIpagesResult # noqa: E402 -from util.api import _finalizeGAPIpagesResult # noqa: E402 -from util.api import _setMaxArgResults # noqa: E402 -from util.api import writeGotMessage # noqa: E402 -from util.api import getSaUser # noqa: E402 -from util.api import chooseSaAPI # noqa: E402 - -# Entity resolution — extracted to gam.util.entity -from util.entity import getUserEmailFromID # noqa: E402 -from util.entity import getGroupEmailFromID # noqa: E402 -from util.entity import getServiceAccountEmailFromID # noqa: E402 -from util.entity import convertUIDtoEmailAddressWithType # noqa: E402 -from util.entity import NON_EMAIL_MEMBER_PREFIXES # noqa: E402 -from util.entity import convertUIDtoEmailAddress # noqa: E402 -from util.entity import convertEmailAddressToUID # noqa: E402 -from util.entity import convertUserIDtoEmail # noqa: E402 -from util.entity import splitEmailAddressOrUID # noqa: E402 -from util.entity import convertOrgUnitIDtoPath # noqa: E402 -from util.entity import shlexSplitList # noqa: E402 -from util.entity import shlexSplitListStatus # noqa: E402 -from util.entity import getQueries # noqa: E402 -from util.entity import _validateDeviceQuery # noqa: E402 -from util.entity import getDeviceQueries # noqa: E402 -from util.entity import convertEntityToList # noqa: E402 -from util.entity import GROUP_ROLES_MAP # noqa: E402 -from util.entity import ALL_GROUP_ROLES # noqa: E402 -from util.entity import _getRoleVerification # noqa: E402 -from util.entity import _getCIRoleVerification # noqa: E402 -from util.entity import _checkMemberStatusIsSuspendedIsArchived # noqa: E402 -from util.entity import _checkMemberIsSuspendedIsArchived # noqa: E402 -from util.entity import _checkMemberRole # noqa: E402 -from util.entity import _checkMemberRoleIsSuspendedIsArchived # noqa: E402 -from util.entity import _checkMemberCategory # noqa: E402 -from util.entity import _checkCIMemberCategory # noqa: E402 -from util.entity import getCIGroupMemberRoleFixType # noqa: E402 -from util.entity import getCIGroupTransitiveMemberRoleFixType # noqa: E402 -from util.entity import convertGroupCloudIDToEmail # noqa: E402 -from util.entity import convertGroupEmailToCloudID # noqa: E402 -from util.entity import CIGROUP_DISCUSSION_FORUM_LABEL # noqa: E402 -from util.entity import CIGROUP_DYNAMIC_LABEL # noqa: E402 -from util.entity import CIGROUP_SECURITY_LABEL # noqa: E402 -from util.entity import CIGROUP_LOCKED_LABEL # noqa: E402 -from util.entity import getCIGroupMembershipGraph # noqa: E402 -from util.entity import checkGroupExists # noqa: E402 -from util.entity import getItemsToModify # noqa: E402 -from util.entity import splitEntityList # noqa: E402 -from util.entity import splitEntityListShlex # noqa: E402 -from util.entity import fileDataErrorExit # noqa: E402 -from util.entity import getEntitiesFromFile # noqa: E402 -from util.entity import getEntitiesFromCSVFile # noqa: E402 -from util.entity import getEntitiesFromCSVbyField # noqa: E402 -from util.entity import mapEntityType # noqa: E402 -from util.entity import getEntityArgument # noqa: E402 -from util.entity import getEntityToModify # noqa: E402 -from util.entity import getEntitySelector # noqa: E402 -from util.entity import getEntitySelection # noqa: E402 -from util.entity import getEntityList # noqa: E402 -from util.entity import getNormalizedEmailAddressEntity # noqa: E402 -from util.entity import getUserObjectEntity # noqa: E402 -from util.entity import _validateUserGetObjectList # noqa: E402 -from util.entity import _validateUserGetMessageIds # noqa: E402 -from util.entity import checkUserExists # noqa: E402 -from util.entity import checkUserSuspended # noqa: E402 - -# CSV Print Framework — extracted to gam.util.csv_pf -from util.csv_pf import addFieldToFieldsList # noqa: E402 -from util.csv_pf import _getFieldsList # noqa: E402 -from util.csv_pf import _getRawFields # noqa: E402 -from util.csv_pf import CheckInputRowFilterHeaders # noqa: E402 -from util.csv_pf import RowFilterMatch # noqa: E402 -from util.csv_pf import getFieldsList # noqa: E402 -from util.csv_pf import getFieldsFromFieldsList # noqa: E402 -from util.csv_pf import getItemFieldsFromFieldsList # noqa: E402 -from util.csv_pf import CSVPrintFile # noqa: E402 -from util.csv_pf import writeEntityNoHeaderCSVFile # noqa: E402 -from util.csv_pf import getTodriveOnly # noqa: E402 -from util.csv_pf import DEFAULT_SKIP_OBJECTS # noqa: E402 -from util.csv_pf import cleanJSON # noqa: E402 -from util.csv_pf import flattenJSON # noqa: E402 -from util.csv_pf import showJSON # noqa: E402 -from util.csv_pf import FormatJSONQuoteChar # noqa: E402 -from util.csv_pf import RI_ENTITY # noqa: E402 -from util.csv_pf import RI_I # noqa: E402 -from util.csv_pf import RI_COUNT # noqa: E402 -from util.csv_pf import RI_J # noqa: E402 -from util.csv_pf import RI_JCOUNT # noqa: E402 -from util.csv_pf import RI_ITEM # noqa: E402 -from util.csv_pf import RI_ROLE # noqa: E402 -from util.csv_pf import RI_OPTION # noqa: E402 -from util.csv_pf import batchRequestID # noqa: E402 -# OrgUnit helpers — extracted to gam.util.orgunits -from util.orgunits import getOrgUnitItem # noqa: E402 -from util.orgunits import getTopLevelOrgId # noqa: E402 -from util.orgunits import getOrgUnitId # noqa: E402 -from util.orgunits import getAllParentOrgUnitsForUser # noqa: E402 -# GDoc/GSheet/Storage/CSV readers — extracted to gam.util.gdoc -from util.gdoc import GDOC_FORMAT_MIME_TYPES # noqa: E402 -from util.gdoc import getGDocData # noqa: E402 -from util.gdoc import HTML_TITLE_PATTERN # noqa: E402 -from util.gdoc import getGSheetData # noqa: E402 -from util.gdoc import BUCKET_OBJECT_PATTERNS # noqa: E402 -from util.gdoc import getBucketObjectName # noqa: E402 -from util.gdoc import GCS_FORMAT_MIME_TYPES # noqa: E402 -from util.gdoc import getStorageFileData # noqa: E402 -from util.gdoc import openCSVFileReader # noqa: E402 -# Configuration — extracted to gam.util.config +from util.args import getArgument, getChoice, getInteger, getStringReturnInList # noqa: E402 +from util.args import checkArgumentPresent, normalizeEmailAddressOrUID, NO_DEFAULT # noqa: E402 +from util.connection import doCheckConnection, doComment, doVersion, doUsage # noqa: E402 +from util.entity import getEntityArgument, getEntityList, getEntityToModify # noqa: E402 from util.config import SetGlobalVariables # noqa: E402 -# Batch/multiprocess infrastructure — extracted to gam.util.batch -from util.batch import NullHandler # noqa: E402 -from util.batch import initializeLogging # noqa: E402 -from util.batch import saveNonPickleableValues # noqa: E402 -from util.batch import restoreNonPickleableValues # noqa: E402 -from util.batch import CSVFileQueueHandler # noqa: E402 -from util.batch import initializeCSVFileQueueHandler # noqa: E402 -from util.batch import terminateCSVFileQueueHandler # noqa: E402 -from util.batch import StdQueueHandler # noqa: E402 -from util.batch import initializeStdQueueHandler # noqa: E402 -from util.batch import batchWriteStderr # noqa: E402 -from util.batch import writeStdQueueHandler # noqa: E402 -from util.batch import terminateStdQueueHandler # noqa: E402 -from util.batch import ProcessGAMCommandMulti # noqa: E402 -from util.batch import checkChildProcessRC # noqa: E402 -from util.batch import initGamWorker # noqa: E402 -from util.batch import MultiprocessGAMCommands # noqa: E402 -from util.batch import threadBatchWorker # noqa: E402 -from util.batch import ThreadBatchGAMCommands # noqa: E402 -from util.batch import _getShowCommands # noqa: E402 -from util.batch import _getSkipRows # noqa: E402 -from util.batch import _getMaxRows # noqa: E402 -from util.batch import doBatch # noqa: E402 -from util.batch import doThreadBatch # noqa: E402 -from util.batch import doAutoBatch # noqa: E402 -from util.batch import getSubFields # noqa: E402 -from util.batch import processSubFields # noqa: E402 -from util.batch import doCSV # noqa: E402 -from util.batch import doCSVTest # noqa: E402 -from util.batch import doLoop # noqa: E402 -from util.batch import _doList # noqa: E402 -from util.batch import doListType # noqa: E402 -from util.batch import doListCrOS # noqa: E402 -from util.batch import doListUser # noqa: E402 -from util.batch import _showCount # noqa: E402 -from util.batch import showCountCrOS # noqa: E402 -from util.batch import showCountUser # noqa: E402 +from util.fileio import closeGAMCommandLog, writeGAMCommandLog # noqa: E402 +from util.batch import ( # noqa: E402 + batchWriteStderr, doBatch, doThreadBatch, doAutoBatch, + doCSV, doCSVTest, doLoop, doListType, doListCrOS, doListUser, + showCountCrOS, showCountUser, +) -# Command module re-exports for routing tables -# Command function references (lazy-loaded at first call) -# These replace the old `from gam.cmd.X import func` re-exports -# gam.cmd.admin # Command module imports from gam.cmd.admin import ( @@ -1504,46 +1153,7 @@ def doResetYubiKeyPIV(): yk.reset_piv() -# Audit command utilities -def ACLRuleDict(rule): - if rule['scope']['type'] != 'default': - return {'Scope': f'{rule["scope"]["type"]}:{rule["scope"]["value"]}', 'Role': rule['role']} - return {'Scope': f'{rule["scope"]["type"]}', 'Role': rule['role']} -def ACLRuleKeyValueList(rule): - if rule['scope']['type'] != 'default': - return ['Scope', f'{rule["scope"]["type"]}:{rule["scope"]["value"]}', 'Role', rule['role']] - return ['Scope', f'{rule["scope"]["type"]}', 'Role', rule['role']] - -def formatACLRule(rule): - return formatKeyValueList('(', ACLRuleKeyValueList(rule), ')') - -def formatACLScopeRole(scope, role): - if role: - return formatKeyValueList('(', ['Scope', scope, 'Role', role], ')') - return formatKeyValueList('(', ['Scope', scope], ')') - -def normalizeRuleId(ruleId): - ruleIdParts = ruleId.split(':', 1) - if (len(ruleIdParts) == 1) or not ruleIdParts[1]: - if ruleIdParts[0] == 'default': - return ruleId - if ruleIdParts[0] == 'domain': - return f'domain:{GC.Values[GC.DOMAIN]}' - return f'user:{normalizeEmailAddressOrUID(ruleIdParts[0], noUid=True)}' - if ruleIdParts[0] in {'user', 'group'}: - return f'{ruleIdParts[0]}:{normalizeEmailAddressOrUID(ruleIdParts[1], noUid=True)}' - return ruleId - -def makeRoleRuleIdBody(role, ruleId): - ruleIdParts = ruleId.split(':', 1) - if len(ruleIdParts) == 1: - if ruleIdParts[0] == 'default': - return {'role': role, 'scope': {'type': ruleIdParts[0]}} - if ruleIdParts[0] == 'domain': - return {'role': role, 'scope': {'type': ruleIdParts[0], 'value': GC.Values[GC.DOMAIN]}} - return {'role': role, 'scope': {'type': 'user', 'value': ruleIdParts[0]}} - return {'role': role, 'scope': {'type': ruleIdParts[0], 'value': ruleIdParts[1]}} BUILDING_ADDRESS_FIELD_MAP = { 'address': 'addressLines', diff --git a/src/gam/__main__.py b/src/gam/__main__.py index c7689f98..e871f7be 100644 --- a/src/gam/__main__.py +++ b/src/gam/__main__.py @@ -22,9 +22,10 @@ import platform import sys import gam +from gam.util.batch import initializeLogging def main(): - gam.initializeLogging() + initializeLogging() rc = gam.ProcessGAMCommand(sys.argv) try: sys.stdout.flush() diff --git a/src/gam/gamlib/yubikey.py b/src/gam/gamlib/yubikey.py index e191302d..e6ee8e24 100644 --- a/src/gam/gamlib/yubikey.py +++ b/src/gam/gamlib/yubikey.py @@ -25,10 +25,7 @@ import string import sys from gam import mplock - -from gam import systemErrorExit -from gam import readStdin -from gam import writeStdout +from gam.util.output import systemErrorExit, readStdin, writeStdout from gam.gamlib import glmsgs as Msg diff --git a/src/gam/util/args.py b/src/gam/util/args.py index 17191909..be6a98da 100644 --- a/src/gam/util/args.py +++ b/src/gam/util/args.py @@ -76,6 +76,7 @@ import calendar import datetime import json import re +import shlex import sys import arrow @@ -1629,3 +1630,22 @@ def substituteQueryTimes(queries, queryTimes): def _getFilterDateTime(): filterDate = getYYYYMMDD(returnDateTime=True) return (filterDate, filterDate.replace(tzinfo='UTC')) + +def shlexSplitList(entity, dataDelimiter=' ,'): + lexer = shlex.shlex(entity, posix=True) + lexer.whitespace = dataDelimiter + lexer.whitespace_split = True + try: + return list(lexer) + except ValueError as e: + Cmd.Backup() + usageErrorExit(str(e)) + +def shlexSplitListStatus(entity, dataDelimiter=' ,'): + lexer = shlex.shlex(entity, posix=True) + lexer.whitespace = dataDelimiter + lexer.whitespace_split = True + try: + return (True, list(lexer)) + except ValueError as e: + return (False, str(e)) diff --git a/src/gam/util/config.py b/src/gam/util/config.py index eef6fb4b..58406eaf 100644 --- a/src/gam/util/config.py +++ b/src/gam/util/config.py @@ -37,70 +37,38 @@ from util.args import integerLimits from util.args import LOCALE_CODES_MAP from util.args import LANGUAGE_CODES_MAP from util.args import TIMEZONE_FORMAT_REQUIRED +from util.args import ( + checkArgumentPresent, getArgument, getBoolean, getCharacter, getChoice, + getFloat, getInteger, getLanguageCode, getREPattern, getString, + shlexSplitList, shlexSplitListStatus, + Cmd, FALSE, FALSE_VALUES, TRUE, TRUE_FALSE, TRUE_VALUES, UTF8, +) from util.csv_pf import CSVPrintFile +from util.display import printKeyValueList, printLine from util.entity import getEntitiesFromCSVFile from util.entity import getEntitiesFromFile -from util.fileio import initAPICallsRateCheck -from util.fileio import openGAMCommandLog -from util.fileio import StringIOobject - - -def _getMain(): - return sys.modules['gam'] +from util.errors import formatChoiceList, usageErrorExit, USAGE_ERROR_RC +from util.fileio import ( + initAPICallsRateCheck, openGAMCommandLog, StringIOobject, + deleteFile, fileErrorMessage, openFile, readFile, setFilePath, writeFile, + FILE_ERROR_RC, +) +from util.output import ( + ERROR_PREFIX, WARNING, WARNING_PREFIX, + formatKeyValueList, printErrorMessage, stderrErrorMsg, systemErrorExit, + writeStderr, +) +from gam.constants import ( + CONFIG_ERROR_RC, DEFAULT_FILE_APPEND_MODE, DEFAULT_FILE_READ_MODE, + DEFAULT_FILE_WRITE_MODE, EV_GAMCFGDIR, EV_GAMCFGSECTION, EV_OLDGAMPATH, + FN_GAM_CFG, GAM, +) def SetGlobalVariables(): - _main = _getMain() - Cmd = _main.Cmd - checkArgumentPresent = _main.checkArgumentPresent - getBoolean = _main.getBoolean - getCharacter = _main.getCharacter - getChoice = _main.getChoice - getString = _main.getString - getInteger = _main.getInteger - getFloat = _main.getFloat - getLanguageCode = _main.getLanguageCode - getREPattern = _main.getREPattern - getArgument = _main.getArgument - systemErrorExit = _main.systemErrorExit - stderrErrorMsg = _main.stderrErrorMsg - printErrorMessage = _main.printErrorMessage - printKeyValueList = _main.printKeyValueList - printLine = _main.printLine - writeStderr = _main.writeStderr - openFile = _main.openFile - readFile = _main.readFile - writeFile = _main.writeFile - deleteFile = _main.deleteFile - fileErrorMessage = _main.fileErrorMessage - setFilePath = _main.setFilePath - usageErrorExit = _main.usageErrorExit - formatChoiceList = _main.formatChoiceList - formatKeyValueList = _main.formatKeyValueList - shlexSplitList = _main.shlexSplitList - shlexSplitListStatus = _main.shlexSplitListStatus - FN_GAM_CFG = _main.FN_GAM_CFG - UTF8 = _main.UTF8 - USAGE_ERROR_RC = _main.USAGE_ERROR_RC - CONFIG_ERROR_RC = _main.CONFIG_ERROR_RC - FILE_ERROR_RC = _main.FILE_ERROR_RC - # Constants from __init__.py needed by SetGlobalVariables - GAM = _main.GAM - TRUE = _main.TRUE - FALSE = _main.FALSE - TRUE_VALUES = _main.TRUE_VALUES - FALSE_VALUES = _main.FALSE_VALUES - TRUE_FALSE = _main.TRUE_FALSE - ERROR_PREFIX = _main.ERROR_PREFIX - WARNING = _main.WARNING - WARNING_PREFIX = _main.WARNING_PREFIX - EV_GAMCFGDIR = _main.EV_GAMCFGDIR - EV_GAMCFGSECTION = _main.EV_GAMCFGSECTION - EV_OLDGAMPATH = _main.EV_OLDGAMPATH - DEFAULT_FILE_APPEND_MODE = _main.DEFAULT_FILE_APPEND_MODE - DEFAULT_FILE_READ_MODE = _main.DEFAULT_FILE_READ_MODE - DEFAULT_FILE_WRITE_MODE = _main.DEFAULT_FILE_WRITE_MODE - redactable_debug_print = _main.redactable_debug_print + # redactable_debug_print is defined in gam.__init__ — access at call time + # to avoid circular import (gam imports from us during init) + redactable_debug_print = sys.modules['gam'].redactable_debug_print def _stringInQuotes(value): diff --git a/src/gam/util/connection.py b/src/gam/util/connection.py index cf56b8d2..8cd350c5 100644 --- a/src/gam/util/connection.py +++ b/src/gam/util/connection.py @@ -21,29 +21,30 @@ from gamlib import glglobals as GM from gamlib import glmsgs as Msg from gamlib import glverlibs +from gam.constants import ( + FN_GAMCOMMANDS_TXT, GAM, GAM_URL, GAM_WIKI, + GOOGLE_TIMECHECK_LOCATION, MAX_LOCAL_GOOGLE_TIME_OFFSET, NETWORK_ERROR_RC, + SECONDS_PER_DAY, SECONDS_PER_HOUR, SECONDS_PER_MINUTE, +) +from util.args import ISOformatTimeStamp, getArgument, getString, todaysTime +from util.display import printBlankLine, printKeyValueList +from util.errors import unknownArgumentExit +from util.output import ( + createGreenText, createRedText, createYellowText, + flushStdout, stderrWarningMsg, systemErrorExit, writeStdout, +) +from util.api import doGAMCheckForUpdates, getHttpObj, getService, handleServerError, waitOnFailure -class _InstanceProxy: - """Lazy proxy that delegates attribute access to a named instance in the gam module.""" - def __init__(self, name): - self._name = name - def __getattr__(self, attr): - return getattr(getattr(sys.modules['gam'], self._name), attr) - -Cmd = _InstanceProxy('Cmd') - -def _getEnt(): - return sys.modules['gam'].Ent - -def _getMain(): - return sys.modules['gam'] +# gam.__init__ attributes that can't be imported at module level +# (connection.py is imported BY __init__.py during init) +_gam = lambda: sys.modules['gam'] # --- Constants --- def _buildTimeOffsetUnits(): - m = _getMain() - return [('day', m.SECONDS_PER_DAY), ('hour', m.SECONDS_PER_HOUR), - ('minute', m.SECONDS_PER_MINUTE), ('second', 1)] + return [('day', SECONDS_PER_DAY), ('hour', SECONDS_PER_HOUR), + ('minute', SECONDS_PER_MINUTE), ('second', 1)] MACOS_CODENAMES = { 10: { @@ -70,31 +71,30 @@ MACOS_CODENAMES = { # --- Functions --- def getLocalGoogleTimeOffset(testLocation=None): - m = _getMain() if testLocation is None: - testLocation = m.GOOGLE_TIMECHECK_LOCATION + testLocation = GOOGLE_TIMECHECK_LOCATION TIME_OFFSET_UNITS = _buildTimeOffsetUnits() # If local time is well off, it breaks https because the server certificate will be seen as too old or new and thus invalid; http doesn't have that issue. # Try with http first, if time is close (] def doVersion(checkForArgs=True): - m = _getMain() - Ent = _getEnt() + Ent = _gam().Ent + Cmd = _gam().Cmd forceCheck = 0 extended = noOffsetError = timeOffset = simple = False - testLocation = m.GOOGLE_TIMECHECK_LOCATION + testLocation = GOOGLE_TIMECHECK_LOCATION if checkForArgs: while Cmd.ArgumentsRemaining(): - myarg = m.getArgument() + myarg = getArgument() if myarg == 'check': forceCheck = 1 elif myarg == 'checkrc': @@ -306,46 +303,45 @@ def doVersion(checkForArgs=True): elif myarg == 'nooffseterror': noOffsetError = True elif myarg == 'location': - testLocation = m.getString(Cmd.OB_HOST_NAME) + testLocation = getString(Cmd.OB_HOST_NAME) else: - m.unknownArgumentExit() + unknownArgumentExit() if simple: - m.writeStdout(m.__version__) + writeStdout(_gam().__version__) return - m.writeStdout((f'{m.GAM} {m.__version__} - {m.GAM_URL} - {GM.Globals[GM.GAM_TYPE]}\n' - f'{m.__author__}\n' + writeStdout((f'{GAM} {_gam().__version__} - {GAM_URL} - {GM.Globals[GM.GAM_TYPE]}\n' + f'{_gam().__author__}\n' f'Python {sys.version_info[0]}.{sys.version_info[1]}.{sys.version_info[2]} {struct.calcsize("P")*8}-bit {sys.version_info[3]}\n' f'{getOSPlatform()} {platform.machine()}\n' f'Path: {GM.Globals[GM.GAM_PATH]}\n' f'{Ent.Singular(Ent.CONFIG_FILE)}: {GM.Globals[GM.GAM_CFG_FILE]}, {Ent.Singular(Ent.SECTION)}: {GM.Globals[GM.GAM_CFG_SECTION_NAME]}, ' f'{GC.CUSTOMER_ID}: {GC.Values[GC.CUSTOMER_ID]}, {GC.DOMAIN}: {GC.Values[GC.DOMAIN]}\n' - f'Time: {m.ISOformatTimeStamp(m.todaysTime())}\n' + f'Time: {ISOformatTimeStamp(todaysTime())}\n' )) if sys.platform.startswith('win') and str(struct.calcsize('P')*8).find('32') != -1 and platform.machine().find('64') != -1: - m.printKeyValueList([Msg.UPDATE_GAM_TO_64BIT]) + printKeyValueList([Msg.UPDATE_GAM_TO_64BIT]) if timeOffset: offsetSeconds, offsetFormatted = getLocalGoogleTimeOffset(testLocation) - m.printKeyValueList([Msg.YOUR_SYSTEM_TIME_DIFFERS_FROM_GOOGLE.format(testLocation, offsetFormatted)]) - if offsetSeconds > m.MAX_LOCAL_GOOGLE_TIME_OFFSET: + printKeyValueList([Msg.YOUR_SYSTEM_TIME_DIFFERS_FROM_GOOGLE.format(testLocation, offsetFormatted)]) + if offsetSeconds > MAX_LOCAL_GOOGLE_TIME_OFFSET: if not noOffsetError: - m.systemErrorExit(m.NETWORK_ERROR_RC, Msg.PLEASE_CORRECT_YOUR_SYSTEM_TIME) - m.stderrWarningMsg(Msg.PLEASE_CORRECT_YOUR_SYSTEM_TIME) + systemErrorExit(NETWORK_ERROR_RC, Msg.PLEASE_CORRECT_YOUR_SYSTEM_TIME) + stderrWarningMsg(Msg.PLEASE_CORRECT_YOUR_SYSTEM_TIME) if forceCheck: - m.doGAMCheckForUpdates(forceCheck) + doGAMCheckForUpdates(forceCheck) if extended: - m.printKeyValueList([ssl.OPENSSL_VERSION]) + printKeyValueList([ssl.OPENSSL_VERSION]) tls_ver, cipher_name = _getServerTLSUsed(testLocation) for lib in glverlibs.GAM_VER_LIBS: try: - m.writeStdout(f'{lib} {lib_version(lib)}\n') + writeStdout(f'{lib} {lib_version(lib)}\n') except: pass - m.printKeyValueList([f'{testLocation} connects using {tls_ver} {cipher_name}']) + printKeyValueList([f'{testLocation} connects using {tls_ver} {cipher_name}']) # gam help def doUsage(): - m = _getMain() - m.printBlankLine() + printBlankLine() doVersion(checkForArgs=False) - m.writeStdout(Msg.HELP_SYNTAX.format(os.path.join(GM.Globals[GM.GAM_PATH], m.FN_GAMCOMMANDS_TXT))) - m.writeStdout(Msg.HELP_WIKI.format(m.GAM_WIKI)) + writeStdout(Msg.HELP_SYNTAX.format(os.path.join(GM.Globals[GM.GAM_PATH], FN_GAMCOMMANDS_TXT))) + writeStdout(Msg.HELP_WIKI.format(GAM_WIKI)) diff --git a/src/gam/util/entity.py b/src/gam/util/entity.py index 71a9c8a3..f252c371 100644 --- a/src/gam/util/entity.py +++ b/src/gam/util/entity.py @@ -227,24 +227,7 @@ def convertOrgUnitIDtoPath(cd, orgUnitId): GM.Globals[GM.MAP_ORGUNIT_ID_TO_NAME][orgUnitId] = orgUnitPath return orgUnitPath -def shlexSplitList(entity, dataDelimiter=' ,'): - lexer = shlex.shlex(entity, posix=True) - lexer.whitespace = dataDelimiter - lexer.whitespace_split = True - try: - return list(lexer) - except ValueError as e: - _getMain().Cmd.Backup() - _getMain().usageErrorExit(str(e)) - -def shlexSplitListStatus(entity, dataDelimiter=' ,'): - lexer = shlex.shlex(entity, posix=True) - lexer.whitespace = dataDelimiter - lexer.whitespace_split = True - try: - return (True, list(lexer)) - except ValueError as e: - return (False, str(e)) +from util.args import shlexSplitList, shlexSplitListStatus # noqa: E402,F401 - moved to args, re-exported for compat def getQueries(myarg): if myarg in {'query', 'filter'}: