Skip to content

Commit

Permalink
Revert "Merge branch 'personal' into io_failure_handling"
Browse files Browse the repository at this point in the history
This reverts commit 44918e1, reversing
changes made to c80228a.
  • Loading branch information
sleeptightAnsiC committed May 3, 2024
1 parent 44918e1 commit 325228f
Show file tree
Hide file tree
Showing 8 changed files with 60 additions and 141 deletions.
5 changes: 2 additions & 3 deletions ue4cli/CachedDataManager.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from .ConfigurationManager import ConfigurationManager
from .JsonDataManager import JsonDataManager
from .Utility import Utility
import os
import os, shutil

class CachedDataManager(object):
"""
Expand All @@ -14,7 +13,7 @@ def clearCache():
Clears any cached data we have stored about specific engine versions
"""
if os.path.exists(CachedDataManager._cacheDir()) == True:
Utility.removeDir(CachedDataManager._cacheDir())
shutil.rmtree(CachedDataManager._cacheDir())

@staticmethod
def getCachedDataKey(engineVersionHash, key):
Expand Down
23 changes: 6 additions & 17 deletions ue4cli/JsonDataManager.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from .UnrealManagerException import UnrealManagerException
from .Utility import Utility
from .UtilityException import UtilityException
import json, os
import json, os, platform

class JsonDataManager(object):
"""
Expand All @@ -13,19 +12,6 @@ def __init__(self, jsonFile):
Creates a new JsonDataManager instance for the specified JSON file
"""
self.jsonFile = jsonFile

def loads(self):
"""
Reads and loads owned jsonFile
"""
try:
path = self.jsonFile
file = Utility.readFile(path)
return json.loads(file)
except json.JSONDecodeError as e:
# FIXME: This is the only place outside of Utility class where we use UtilityException.
# Not worth to create new Exception class for only one single case, at least not now.
raise UtilityException(f'failed to load "{str(path)}" due to: ({type(e).__name__}) {str(e)}') from e

def getKey(self, key):
"""
Expand All @@ -42,7 +28,10 @@ def getDictionary(self):
Retrieves the entire data dictionary
"""
if os.path.exists(self.jsonFile):
return self.loads()
try:
return json.loads(Utility.readFile(self.jsonFile))
except json.JSONDecodeError as err:
raise UnrealManagerException('malformed JSON configuration file "{}" ({})'.format(self.jsonFile, err))
else:
return {}

Expand All @@ -62,7 +51,7 @@ def setDictionary(self, data):
# Create the directory containing the JSON file if it doesn't already exist
jsonDir = os.path.dirname(self.jsonFile)
if os.path.exists(jsonDir) == False:
Utility.makeDirs(jsonDir)
os.makedirs(jsonDir)

# Store the dictionary
Utility.writeFile(self.jsonFile, json.dumps(data))
14 changes: 5 additions & 9 deletions ue4cli/UE4BuildInterrogator.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,11 @@
from .UnrealManagerException import UnrealManagerException
from .CachedDataManager import CachedDataManager
from .Utility import Utility
from .UtilityException import UtilityException
from .JsonDataManager import JsonDataManager
import os, tempfile
import json, os, platform, shutil, tempfile

class UE4BuildInterrogator(object):

def __init__(self, engineRoot, engineVersion, engineVersionHash, runUBTFunc):
# WARN: os.path.realpath can potentially fail with OSError,
# but if it ever happens, this is most likely bug in our code
self.engineRoot = os.path.realpath(engineRoot)
self.engineSourceDir = 'Engine/Source/'
self.engineVersion = engineVersion
Expand Down Expand Up @@ -164,7 +160,7 @@ def _getThirdPartyLibs(self, platformIdentifier, configuration):
sentinelBackup = sentinelFile + '.bak'
renameSentinel = os.path.exists(sentinelFile) and os.environ.get('UE4CLI_SENTINEL_RENAME', '0') == '1'
if renameSentinel == True:
Utility.moveFile(sentinelFile, sentinelBackup)
shutil.move(sentinelFile, sentinelBackup)

# Invoke UnrealBuildTool in JSON export mode (make sure we specify gathering mode, since this is a prerequisite of JSON export)
# (Ensure we always perform sentinel file cleanup even when errors occur)
Expand All @@ -176,10 +172,10 @@ def _getThirdPartyLibs(self, platformIdentifier, configuration):
self.runUBTFunc('UE4Editor', platformIdentifier, configuration, args)
finally:
if renameSentinel == True:
Utility.moveFile(sentinelBackup, sentinelFile)
shutil.move(sentinelBackup, sentinelFile)

# Parse the JSON output
result = JsonDataManager(jsonFile).loads()
result = json.loads(Utility.readFile(jsonFile))

# Extract the list of third-party library modules
# (Note that since UE4.21, modules no longer have a "Type" field, so we must
Expand All @@ -192,7 +188,7 @@ def _getThirdPartyLibs(self, platformIdentifier, configuration):

# Remove the temp directory
try:
Utility.removeDir(tempDir)
shutil.rmtree(tempDir)
except:
pass

Expand Down
56 changes: 24 additions & 32 deletions ue4cli/UnrealManagerBase.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@
from .CachedDataManager import CachedDataManager
from .CMakeCustomFlags import CMakeCustomFlags
from .Utility import Utility
from .JsonDataManager import JsonDataManager
from .UtilityException import UtilityException
import glob, hashlib, json, os, re
import glob, hashlib, json, os, re, shutil, sys

class UnrealManagerBase(object):
"""
Expand Down Expand Up @@ -59,13 +57,13 @@ def setEngineRootOverride(self, rootDir):
# Set the new root directory
rootDir = os.path.abspath(rootDir)
ConfigurationManager.setConfigKey('rootDirOverride', rootDir)
Utility.printStderr('Setting engine root path override:', str(rootDir))
print('Set engine root path override: {}'.format(rootDir))

# Check that the specified directory is valid and warn the user if it is not
try:
self.getEngineVersion()
except:
raise UnrealManagerException('the specified directory does not appear to contain a valid version of the Unreal Engine.') from None
print('Warning: the specified directory does not appear to contain a valid version of the Unreal Engine.')

def clearEngineRootOverride(self):
"""
Expand Down Expand Up @@ -109,7 +107,7 @@ def getEngineVersion(self, outputFormat = 'full'):

# Verify that the requested output format is valid
if outputFormat not in formats:
raise UnrealManagerException(f'unreconised version output format "{str(outputFormat)}"')
raise Exception('unreconised version output format "{}"'.format(outputFormat))

return formats[outputFormat]

Expand Down Expand Up @@ -193,7 +191,7 @@ def getDescriptor(self, dir):
try:
return self.getPluginDescriptor(dir)
except:
raise UnrealManagerException(f'could not detect an Unreal project or plugin in the directory "{str(dir)}"') from None
raise UnrealManagerException('could not detect an Unreal project or plugin in the directory "{}"'.format(dir))

def isProject(self, descriptor):
"""
Expand Down Expand Up @@ -335,7 +333,8 @@ def generateProjectFiles(self, dir=os.getcwd(), args=[]):

# If the project is a pure Blueprint project, then we cannot generate project files
if os.path.exists(os.path.join(dir, 'Source')) == False:
raise UnrealManagerException('Pure Blueprint project, nothing to generate project files for.')
Utility.printStderr('Pure Blueprint project, nothing to generate project files for.')
return

# Generate the project files
genScript = self.getGenerateScript()
Expand All @@ -352,8 +351,8 @@ def cleanDescriptor(self, dir=os.getcwd()):

# Because performing a clean will also delete the engine build itself when using
# a source build, we simply delete the `Binaries` and `Intermediate` directories
Utility.removeDir(os.path.join(dir, 'Binaries'), ignore_errors=True)
Utility.removeDir(os.path.join(dir, 'Intermediate'), ignore_errors=True)
shutil.rmtree(os.path.join(dir, 'Binaries'), ignore_errors=True)
shutil.rmtree(os.path.join(dir, 'Intermediate'), ignore_errors=True)

# If we are cleaning a project, also clean any plugins
if self.isProject(descriptor):
Expand All @@ -372,12 +371,12 @@ def buildDescriptor(self, dir=os.getcwd(), configuration='Development', target='

# If the project or plugin is Blueprint-only, there is no C++ code to build
if os.path.exists(os.path.join(dir, 'Source')) == False:
raise UnrealManagerException(f'Pure Blueprint {str(descriptorType)}, nothing to build.')
Utility.printStderr('Pure Blueprint {}, nothing to build.'.format(descriptorType))
return

# Verify that the specified build configuration is valid
if configuration not in self.validBuildConfigurations():
raise UnrealManagerException(f'invalid build configuration "{str(configuration)}"')

raise UnrealManagerException('invalid build configuration "' + configuration + '"')
# Verify that the specified build target is valid
if target not in self.validBuildTargets():
raise UnrealManagerException('invalid build target "' + target + '"')
Expand Down Expand Up @@ -433,7 +432,7 @@ def packageProject(self, dir=os.getcwd(), configuration='Shipping', extraArgs=[]

# Verify that the specified build configuration is valid
if configuration not in self.validBuildConfigurations():
raise UnrealManagerException(f'invalid build configuration "{str(configuration)}"')
raise UnrealManagerException('invalid build configuration "' + configuration + '"')

# Strip out the `-NoCompileEditor` flag if the user has specified it, since the Development version
# of the Editor modules for the project are needed in order to run the commandlet that cooks content
Expand Down Expand Up @@ -563,12 +562,10 @@ def listAutomationTests(self, projectFile):
# Detect if the Editor terminated abnormally (i.e. not triggered by `automation quit`)
# In Unreal Engine 4.27.0, the exit method changed from RequestExit to RequestExitWithStatus
if 'PlatformMisc::RequestExit(' not in logOutput.stdout and 'PlatformMisc::RequestExitWithStatus(' not in logOutput.stdout:
Utility.printStderr("Warning: abnormal Editor termination detected!")
Utility.printStderr("printing stdout..")
print(logOutput.stdout)
Utility.printStderr("printing stderr..")
print(logOutput.stderr)
raise UnrealManagerException('failed to retrieve the list of automation tests!')
raise RuntimeError(
'failed to retrieve the list of automation tests!' +
' stdout was: "{}", stderr was: "{}"'.format(logOutput.stdout, logOutput.stderr)
)

return sorted(list(tests))

Expand All @@ -583,7 +580,7 @@ def automationTests(self, dir=os.getcwd(), args=[]):

# Verify that at least one argument was supplied
if len(args) == 0:
raise UnrealManagerException('at least one test name must be specified')
raise RuntimeError('at least one test name must be specified')

# Gather any additional arguments to pass directly to the Editor
extraArgs = []
Expand All @@ -594,12 +591,7 @@ def automationTests(self, dir=os.getcwd(), args=[]):

# Build the project if it isn't already built
Utility.printStderr('Ensuring project is built...')
try:
self.buildDescriptor(dir, suppressOutput=True)
except UnrealManagerException:
# FIXME: Ideally, we should NOT catch every UnrealManagerException here
# This is currently a limitation of our API that uses only one Exception class for multiple different cases
pass
self.buildDescriptor(dir, suppressOutput=True)

# Determine which arguments we are passing to the automation test commandlet
projectFile = self.getProjectDescriptor(dir)
Expand Down Expand Up @@ -637,7 +629,7 @@ def automationTests(self, dir=os.getcwd(), args=[]):
# Detect abnormal exit conditions (those not triggered by `automation quit`)
# In Unreal Engine 4.27.0, the exit method changed from RequestExit to RequestExitWithStatus
if 'PlatformMisc::RequestExit(' not in logOutput.stdout and 'PlatformMisc::RequestExitWithStatus(' not in logOutput.stdout:
raise UnrealManagerException('abnormal exit condition detected')
sys.exit(1)

# Since UE4 doesn't consistently produce accurate exit codes across all platforms, we need to rely on
# text-based heuristics to detect failed automation tests or errors related to not finding any tests to run
Expand All @@ -650,12 +642,12 @@ def automationTests(self, dir=os.getcwd(), args=[]):
]
for errorStr in errorStrings:
if errorStr in logOutput.stdout:
raise UnrealManagerException('abnormal exit condition detected')
sys.exit(1)

# If an explicit exit code was specified in the output text then identify it and propagate it
match = re.search('TEST COMPLETE\\. EXIT CODE: ([1-9]+)', logOutput.stdout + logOutput.stderr)
match = re.search('TEST COMPLETE\\. EXIT CODE: ([0-9]+)', logOutput.stdout + logOutput.stderr)
if match is not None:
raise UnrealManagerException('abnormal exit condition detected')
sys.exit(int(match.group(1)))

# "Protected" methods

Expand All @@ -670,7 +662,7 @@ def _getEngineVersionDetails(self):
Parses the JSON version details for the latest installed version of UE4
"""
versionFile = os.path.join(self.getEngineRoot(), 'Engine', 'Build', 'Build.version')
return JsonDataManager(versionFile).loads()
return json.loads(Utility.readFile(versionFile))

def _getEngineVersionHash(self):
"""
Expand Down
6 changes: 3 additions & 3 deletions ue4cli/UnrealManagerWindows.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ def getGenerateScript(self):
except:
pass

raise UnrealManagerException('could not detect the location of GenerateProjectFiles.bat or UnrealVersionSelector.exe. This typically indicates that .uproject files are not correctly associated with UE4.')
raise UnrealManagerException('could not detect the location of GenerateProjectFiles.bat or UnrealVersionSelector.exe.\nThis typically indicates that .uproject files are not correctly associated with UE4.')

def getRunUATScript(self):
return self.getEngineRoot() + '\\Engine\\Build\\BatchFiles\\RunUAT.bat'
Expand All @@ -52,7 +52,7 @@ def generateProjectFiles(self, dir=os.getcwd(), args=[]):
# If we are using our custom batch file, use the appropriate arguments
genScript = self.getGenerateScript()
projectFile = self.getProjectDescriptor(dir)
Utility.printStderr('Using project file:', projectFile)
print(projectFile)
if '.ue4\\GenerateProjectFiles.bat' in genScript:
Utility.run([genScript, projectFile], raiseOnError=True)
else:
Expand Down Expand Up @@ -91,7 +91,7 @@ def _customBatchScriptDir(self):
# If the script directory doesn't already exist, attempt to create it
scriptDir = os.path.join(os.environ['HOMEDRIVE'] + os.environ['HOMEPATH'], '.ue4')
try:
Utility.makeDirs(scriptDir)
os.makedirs(scriptDir)
except:
pass

Expand Down
Loading

0 comments on commit 325228f

Please sign in to comment.