Initial commit

This commit is contained in:
alexpete
2021-03-05 11:26:34 -08:00
commit a10351f38d
27091 changed files with 5521199 additions and 0 deletions
+194
View File
@@ -0,0 +1,194 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
from Params import Params
from util import *
class PackageEnv(Params):
def __init__(self, platform, type, json_file):
super(PackageEnv, self).__init__()
self.__cur_dir = os.path.dirname(os.path.abspath(__file__))
global_env_file = os.path.join(self.__cur_dir, json_file)
with open(global_env_file, 'r') as source:
data = json.load(source)
self.__global_env = data.get('global_env')
platform_env_file = os.path.join(self.__cur_dir, 'Platform', platform, json_file)
if not os.path.exists(platform_env_file):
print(f'{platform_env_file} is not found.')
# Search restricted platform folders
engine_root = self.get('ENGINE_ROOT')
# Use real path in case engine root is a symlink path
if os.name == 'posix' and os.path.islink(engine_root):
engine_root = os.readlink(engine_root)
rel_path = os.path.relpath(self.__cur_dir, engine_root)
platform_env_file = os.path.join(engine_root, 'restricted', platform, rel_path, json_file)
if not os.path.exists(platform_env_file):
ly_build_error(f'{platform_env_file} is not found.')
with open(platform_env_file, 'r') as source:
data = json.load(source)
types = data.get('types')
if type not in types:
ly_build_error(f'Package type {type} is not supported')
self.__platform = platform
self.__platform_env = data.get('local_env')
self.__platform_env.update(self.__global_env)
self.__type = type
self.__type_env = types.get(type)
def get_platform(self):
return self.__platform
def get_type(self):
return self.__type
def get_platform_env(self):
return self.__platform_env
def get_type_env(self):
return self.__type_env
def __get_platform_value(self, key):
key = key.upper()
value = self.__platform_env.get(key)
if value is None:
ly_build_error(f'{key} is not defined in global env nor in local env')
return value
def __get_type_value(self, key):
key = key.upper()
value = self.__type_env.get(key)
if value is None:
ly_build_error(f'{key} is not defined in package type {self.__type} for platform {self.__platform}')
return value
def __evaluate_boolean(self, v):
return str(v).lower() in ['1', 'true']
def __get_engine_root(self):
def validate_engine_root(engine_root):
if not os.path.isdir(engine_root):
return False
return os.path.exists(os.path.join(engine_root, 'engineroot.txt'))
workspace = os.getenv('WORKSPACE')
if workspace is not None:
print(f'Environment variable WORKSPACE={workspace} detected')
if validate_engine_root(workspace):
print(f'Setting ENGINE_ROOT to {workspace}')
return workspace
print('Cannot locate ENGINE_ROOT with Environment variable WORKSPACE')
engine_root = os.getenv('ENGINE_ROOT', '')
if validate_engine_root(engine_root):
return engine_root
print('Environment variable ENGINE_ROOT is not set or invalid, checking ENGINE_ROOT in env json file')
engine_root = self.__global_env.get('ENGINE_ROOT')
if validate_engine_root(engine_root):
return engine_root
# Set engine_root based on script location
engine_root = os.path.dirname(os.path.dirname(os.path.dirname(self.__cur_dir)))
print(f'ENGINE_ROOT from env json file is invalid, defaulting to {engine_root}')
if validate_engine_root(engine_root):
return engine_root
else:
error('Cannot Locate ENGINE_ROOT')
def __get_thirdparty_home(self):
third_party_home = os.getenv('LY_3RDPARTY_PATH', '')
if os.path.exists(third_party_home):
print(f'LY_3RDPARTY_PATH found, using {third_party_home} as 3rdParty path.')
return third_party_home
third_party_home = self.__get_platform_value('THIRDPARTY_HOME')
if os.path.isdir(third_party_home):
return third_party_home
# Set engine_root based on script location
print('THIRDPARTY_HOME is not valid, looking for THIRD_PARTY_HOME')
# Finding THIRD_PARTY_HOME
cur_dir = self.__get_engine_root()
last_dir = None
while last_dir != cur_dir:
third_party_home = os.path.join(cur_dir, '3rdParty')
print(f'Cheking THIRDPARTY_HOME {third_party_home}')
if os.path.exists(os.path.join(third_party_home, '3rdParty.txt')):
print(f'Setting THIRDPARTY_HOME to {third_party_home}')
return third_party_home
last_dir = cur_dir
cur_dir = os.path.dirname(cur_dir)
error('Cannot locate THIRDPARTY_HOME')
def __get_package_name_pattern(self):
package_name_pattern = self.__get_platform_value('PACKAGE_NAME_PATTERN')
if os.getenv('PACKAGE_NAME_PATTERN') is not None:
package_name_pattern = os.getenv('PACKAGE_NAME_PATTERN')
return package_name_pattern
def __get_branch_name(self):
branch_name = self.__get_platform_value('BRANCH_NAME')
if os.getenv('BRANCH_NAME') is not None:
branch_name = os.getenv('BRANCH_NAME')
branch_name = branch_name.replace('/', '_').replace('\\', '_')
return branch_name
def __get_build_number(self):
build_number = self.__get_platform_value('BUILD_NUMBER')
if os.getenv('BUILD_NUMBER') is not None:
build_number = os.getenv('BUILD_NUMBER')
return build_number
def __get_scrub_params(self):
return self.__get_type_value('SCRUB_PARAMS')
def __get_validator_platforms(self):
return self.__get_type_value('VALIDATOR_PLATFORMS')
def __get_package_targets(self):
return self.__get_type_value('PACKAGE_TARGETS')
def __get_build_targets(self):
return self.__get_type_value('BUILD_TARGETS')
def __get_asset_processor_path(self):
return self.__get_type_value('ASSET_PROCESSOR_PATH')
def __get_asset_game_folders(self):
return self.__get_type_value('ASSET_GAME_FOLDERS')
def __get_asset_platform(self):
return self.__get_type_value('ASSET_PLATFORM')
def __get_bootstrap_cfg_game_folder(self):
return self.__get_type_value('BOOTSTRAP_CFG_GAME_FOLDER')
def __get_skip_build(self):
skip_build = os.getenv('SKIP_BUILD')
if skip_build is None:
skip_build = self.__get_type_value('SKIP_BUILD')
return self.__evaluate_boolean(skip_build)
def __get_skip_scrubbing(self):
skip_scrubbing = os.getenv('SKIP_SCRUBBING')
if skip_scrubbing is None:
skip_scrubbing = self.__type_env.get('SKIP_SCRUBBING', 'False')
return self.__evaluate_boolean(skip_scrubbing)
def __get_internal_s3_bucket(self):
return self.__get_platform_value('INTERNAL_S3_BUCKET')
def __get_qa_s3_bucket(self):
return self.__get_platform_value('QA_S3_BUCKET')
def __get_s3_prefix(self):
return self.__get_platform_value('S3_PREFIX')
+83
View File
@@ -0,0 +1,83 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
import os
import sys
import re
from util import ly_build_error
class Params(object):
def __init__(self):
# Cache params
self.__params = {}
def get(self, param_name):
param_value = self.__params.get(param_name)
if param_value is not None:
return param_value
# Call __get_${param_name} function
func = getattr(self, '_{}__get_{}'.format(self.__class__.__name__, param_name.lower()), None)
if func is not None:
param_value = func()
# Replace all ${env} in value
if isinstance(param_value, str):
param_value = self.__process_string(param_name, param_value)
elif isinstance(param_value, list):
param_value = self.__process_list(param_name, param_value)
elif isinstance(param_value, dict):
param_value = self.__process_dict(param_name, param_value)
# Cache param
self.__params[param_name] = param_value
return param_value
ly_build_error('method __get_{} is not defined in class {}'.format(param_name.lower(), self.__class__.__name__))
def set(self, param_name, param_value):
self.__params[param_name] = param_value
def exists(self, param_name):
try:
self.get(param_name)
except LyBuildError:
return False
return True
def __process_string(self, param_name, param_value):
# Find all param with format ${param}
params = re.findall('\${(\w+)}', param_value)
# Avoid using the same param name in value, like 'WORKSPACE': '${WORKSPACE} some string'
if param_name in params:
ly_build_error('The use of same parameter name({}) in value is not allowed'.format(param_name))
# Replace ${param} with actual value
for param in params:
param_value = param_value.replace('${' + param + '}', self.get(param))
return param_value
def __process_list(self, param_name, param_value):
processed_list = []
for entry in param_value:
if isinstance(entry, str):
entry = self.__process_string(param_name, entry)
elif isinstance(entry, list):
entry = self.__process_list(param_name, entry)
elif isinstance(entry, dict):
entry = self.__process_dict(param_name, entry)
processed_list.append(entry)
return processed_list
def __process_dict(self, param_name, param_value):
for key in param_value:
if isinstance(param_value[key], str):
param_value[key] = self.__process_string(param_name, param_value[key])
elif isinstance(param_value[key], list):
param_value[key] = self.__process_list(param_name, param_value[key])
elif isinstance(param_value[key], dict):
param_value[key] = self.__process_dict(param_name, param_value[key])
return param_value
@@ -0,0 +1,19 @@
{
"local_env": {
"S3_PREFIX": "${BRANCH_NAME}/3rdParty"
},
"types": {
"3rdParty_all": {
"PACKAGE_TARGETS":[
{
"FILE_LIST": "3rdParty.json",
"FILE_LIST_TYPE": "3rdParty",
"PACKAGE_NAME": "${PACKAGE_NAME_PATTERN}-3rdParty-all-${BUILD_NUMBER}.zip"
}
],
"BOOTSTRAP_CFG_GAME_FOLDER":"CMakeTestbed",
"SKIP_BUILD": 1,
"SKIP_SCRUBBING": 1
}
}
}
@@ -0,0 +1,45 @@
{
"@3rdParty": {
"3rdParty.txt": "#include",
"AWS/AWSNativeSDK/1.7.167-az.2/**": "#include",
"AWS/GameLift/3.4.0/**": "#include",
"Blast/1.1.6-az.1/**": "#include",
"benchmark/1.5.0/**": "#include",
"cityhash/1.1-az.1/**": "#include",
"civetweb/civetweb-20160922-az.2/**": "#include",
"Clang/6.0.1-az/**": "#include",
"DirectXShaderCompiler/1.0.1-az.1/**": "#include",
"dyad/0.2.0-17-amazon/**": "#include",
"etc2comp/2017_04_24-az.2/**": "#include",
"expat/2.1.0-pkg.3/**": "#include",
"FbxSdk/2016.1.2-az.1/**": "#include",
"glad/2.0.0-beta/**": "#include",
"googletest/1.8.1-az.3/**": "#include",
"jsmn/78b1dca/**": "#include",
"libav/11.7/**": "#include",
"LibTomCrypt/1.17-az.2/**": "#include",
"LibTomMath/0.42.0-az.2/**": "#include",
"lz4/r128-pkg.3/**": "#include",
"Lzma/unknown-pkg.3/**": "#include",
"LZSS/unknown-pkg.3/**": "#include",
"md5/2.0-pkg.3/**": "#include",
"mikkelsen/1.0.0-az.2/**": "#include",
"nvapi/R361-developer_V2/**": "#include",
"NvCloth/1.1.6-az.4/**": "#include",
"OpenSSL/1.1.1b-noasm-az/**": "#include",
"p4api/2019.1/**": "#include",
"PhysX/4.1.0.25992954-az.1/**": "#include",
"poly2tri/0.3.3-az.2/**": "#include",
"PVRTexTool/2016_r1.1/**": "#include",
"Qt/5.15.1.2-az/**": "#include",
"RadTelemetry/3.5.0.17/**": "#include",
"rapidjson/rapidjson-1.1.0/**": "#include",
"rapidxml/1.13-modified.1/**": "#include",
"SQLite/v3.32.2/**": "#include",
"tiff/3.9.5-az.3/**": "#include",
"unwind/1.2.1/**": "#include",
"Wwise/2019.2.8.7432/**": "#include",
"xxhash/0.7.4/**": "#include",
"zstd/1.35-pkg.1/**": "#include"
}
}
@@ -0,0 +1,28 @@
{
"local_env": {},
"types":{
"all":{
"PACKAGE_TARGETS":[
{
"FILE_LIST": "all.json",
"FILE_LIST_TYPE": "All",
"PACKAGE_NAME": "${PACKAGE_NAME_PATTERN}-mac-all-${BUILD_NUMBER}.zip"
}
],
"BOOTSTRAP_CFG_GAME_FOLDER":"CMakeTestbed",
"SKIP_BUILD": 0,
"BUILD_TARGETS":[
{
"BUILD_CONFIG_FILENAME": "build_config.json",
"PLATFORM": "Mac",
"TYPE": "profile"
},
{
"BUILD_CONFIG_FILENAME": "build_config.json",
"PLATFORM": "iOS",
"TYPE": "profile"
}
]
}
}
}
@@ -0,0 +1,63 @@
{
"local_env": {
"S3_PREFIX": "${BRANCH_NAME}/Windows"
},
"types":{
"all":{
"PACKAGE_TARGETS":[
{
"FILE_LIST": "all.json",
"FILE_LIST_TYPE": "All",
"PACKAGE_NAME": "${PACKAGE_NAME_PATTERN}-windows-all-${BUILD_NUMBER}.zip"
},
{
"FILE_LIST": "symbols.json",
"FILE_LIST_TYPE": "All",
"PACKAGE_NAME": "${PACKAGE_NAME_PATTERN}-windows-all-symbols-${BUILD_NUMBER}.zip"
}
],
"BOOTSTRAP_CFG_GAME_FOLDER":"CMakeTestbed",
"SKIP_BUILD": 0,
"BUILD_TARGETS":[
{
"BUILD_CONFIG_FILENAME": "build_config.json",
"PLATFORM": "Windows",
"TYPE": "profile_vs2017"
},
{
"BUILD_CONFIG_FILENAME": "build_config.json",
"PLATFORM": "Windows",
"TYPE": "profile_vs2019"
}
]
},
"atom":{
"PACKAGE_TARGETS":[
{
"FILE_LIST": "atom.json",
"FILE_LIST_TYPE": "Windows",
"PACKAGE_NAME": "${PACKAGE_NAME_PATTERN}-windows-atom-${BUILD_NUMBER}.zip"
},
{
"FILE_LIST": "symbols.json",
"FILE_LIST_TYPE": "All",
"PACKAGE_NAME": "${PACKAGE_NAME_PATTERN}-windows-atom-symbols-${BUILD_NUMBER}.zip"
}
],
"BOOTSTRAP_CFG_GAME_FOLDER":"AtomSampleViewer;AtomTest",
"SKIP_BUILD": 1,
"BUILD_TARGETS":[
{
"BUILD_CONFIG_FILENAME": "build_config.json",
"PLATFORM": "Windows",
"TYPE": "profile_vs2017_atom"
},
{
"BUILD_CONFIG_FILENAME": "build_config.json",
"PLATFORM": "Windows",
"TYPE": "profile_vs2019_atom"
}
]
}
}
}
@@ -0,0 +1,198 @@
{
"@3rdParty": {
"**/.owner": "#exclude",
"3rdParty.txt": "#move:3rdParty",
"OpenEXR/**": "#move:3rdParty",
"CMake/3.19.1/**": "#move:3rdParty",
"Redistributables":{
"WwiseLTX": {
"LTX_2018.1.2.6762": {
"**": "#move:dev/Tools/Redistributables/WwiseLTX/LTX_2018.1.2.6762",
"*.app.zip": "#exclude",
"WwiseLauncher.pkg": "#exclude"
}
},
"FbxSdk": {
"2016.1.2": {
"*win*": "#move:dev/Tools/Redistributables/FbxSdk/2016.1.2-az.1",
"*vs2013*": "#exclude"
}
}
}
},
"@lyengine": {
"**/*.pyc": "#exclude",
"*": "#include",
"AtomTest":
{
"**":"#include",
"**/*.ma":"#exclude",
"**/*.max":"#exclude",
"**/*.mb":"#exclude",
"**/*.psd":"#exclude"
},
"AtomSampleViewer":
{
"**":"#include",
"**/*.ma":"#exclude",
"**/*.max":"#exclude",
"**/*.mb":"#exclude",
"**/*.psd":"#exclude"
},
"cmake/**": "#include",
"Code": {
"CryEngine/**": "#include",
"Framework/**": "#include",
"LauncherUnified/**": "#include",
"Sandbox/**": "#include",
"Tools": {
"Android/**": "#include",
"AWSNativeSDKInit/**": "#include",
"AssetProcessor*/**": "#include",
"AssetBundler/**": "#include",
"AzTestRunner/**": "#include",
"CrashHandler/**": "#include",
"CryCommonTools/**": "#include",
"CrySCompileServer/**": "#include",
"CryXML/**": "#include",
"DeltaCataloger/**": "#include",
"GemRegistry/**": "#include",
"GridHub/**": "#include",
"HLSLCrossCompiler/**": "#include",
"HLSLCrossCompilerMETAL/**": "#include",
"LyIdentity/**": "#include",
"LyMetrics/**": "#include",
"News/**": "#include",
"PythonBindingsExample/**": "#include",
"RC/**": "#include",
"RemoteConsole/**": "#include",
"SceneAPI/**": "#include",
"SerializeContextTools/**": "#include",
"ShaderCacheGen/**": "#include",
"SharedQMLResource/**": "#include",
"Woodpecker/**": "#include",
"CMakeLists.txt": "#include"
},
"CMakeLists.txt": "#include"
},
"ctest_scripts/**": "#include",
"Editor/**": "#include",
"Engine/**": "#include",
"Gems": {
"Achievements": "#include",
"AssetMemoryAnalyzer": "#include",
"AssetValidation": "#include",
"Atom": "#include",
"AtomLyIntegration": "#include",
"AudioEngineWwise": "#include",
"AudioSystem": "#include",
"AutomatedLauncherTesting": "#include",
"Blast": "#include",
"Camera": "#include",
"CameraFramework": "#include",
"CertificateManager": "#include",
"ChatPlay": "#include",
"Clouds": "#include",
"CrashReporting": "#include",
"CustomAssetExample": "#include",
"DebugDraw": "#include",
"EditorPythonBindings": "#include",
"EMotionFX": "#include",
"ExpressionEvaluation": "#include",
"FastNoise": "#include",
"GameEffectSystem": "#include",
"GameLift": "#include",
"GameState": "#include",
"GameStateSamples": "#include",
"Gestures": "#include",
"GradientSignal": "#include",
"GraphCanvas": "#include",
"GraphModel": "#include",
"HttpRequestor": "#include",
"ImageProcessing": "#include",
"ImGui": "#include",
"InAppPurchases": "#include",
"LandscapeCanvas": "#include",
"LegacyTerrain": "#include",
"LmbrCentral": "#include",
"LocalUser": "#include",
"LyShine": "#include",
"LyShineExamples": "#include",
"Maestro": "#include",
"MessagePopup": "#include",
"Metastream": "#include",
"Microphone": "#include",
"Multiplayer": "#include",
"MultiplayerImGui": "#include",
"NvCloth": "#include",
"PhysX": "#include",
"PhysXDebug": "#include",
"Presence": "#include",
"QtForPython": "#include",
"RADTelemetry": "#include",
"RenderToTexture": "#include",
"SaveData": "#include",
"SceneLoggingExample": "#include",
"SceneProcessing": "#include",
"ScriptCanvas": "#include",
"ScriptCanvasDeveloper": "#include",
"ScriptCanvasDiagnosticLibrary": "#include",
"ScriptCanvasPhysics": "#include",
"ScriptCanvasTesting": "#include",
"ScriptedEntityTweener": "#include",
"ScriptEvents": "#include",
"SliceFavorites": "#include",
"StartingPointCamera": "#include",
"StartingPointInput": "#include",
"StartingPointMovement": "#include",
"Substance": "#include",
"SurfaceData": "#include",
"SVOGI": "#include",
"TestAssetBuilder": "#include",
"TextureAtlas": "#include",
"TickBusOrderViewer": "#include",
"TouchBending": "#include",
"Twitch": "#include",
"Vegetation": "#include",
"VideoPlayback": "#include",
"VideoPlaybackBink": "#include",
"VideoPlaybackFramework": "#include",
"VirtualGamepad": "#include",
"Visibility": "#include",
"Water": "#include",
"WhiteBox": "#include",
"CMakeLists.txt": "#include"
},
"Tools": {
"3dsmax/**": "#include",
"7za.exe": "#include",
"7za_legal_notice.txt": "#include",
"AWSNativeSDK": {
"**": "#include",
"Upgrader/restricted_platforms.py": "#exclude"
},
"AWSPythonSDK/**": "#include",
"Crashpad/**": "#include",
"CrySCompileServer/**": "#include",
"PakShaders/**": "#include",
"Python/**": "#include",
"Redistributables": {
"**": "#include",
"ANGLE/**": "#exclude",
"D3DCompiler/**": "#exclude",
"DbgHelp/**": "#exclude",
"FFMpeg/**": "#exclude",
"LuaCompiler/**": "#exclude",
"MSVC90/**": "#exclude",
"OpenGL32/**": "#exclude",
"SSLEAY/**": "#exclude"
},
"RemoteConsole/**": "#include",
"__init__.py": "#include",
"lmbr_aws/**": "#include",
"maxscript/**": "#include",
"maya/**": "#include",
"photoshop/**": "#include"
}
}
}
+166
View File
@@ -0,0 +1,166 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
import os
import re
import fnmatch
__all__ = ["glob", "iglob", "escape"]
def glob(pathname, recursive=False):
"""Return a list of paths matching a pathname pattern.
The pattern may contain simple shell-style wildcards a la
fnmatch. However, unlike fnmatch, filenames starting with a
dot are special cases that are not matched by '*' and '?'
patterns.
If recursive is true, the pattern '**' will match any files and
zero or more directories and subdirectories.
"""
return list(iglob(pathname, recursive=recursive))
def iglob(pathname, recursive=False):
"""Return an iterator which yields the paths matching a pathname pattern.
The pattern may contain simple shell-style wildcards a la
fnmatch. However, unlike fnmatch, filenames starting with a
dot are special cases that are not matched by '*' and '?'
patterns.
If recursive is true, the pattern '**' will match any files and
zero or more directories and subdirectories.
"""
it = _iglob(pathname, recursive, False)
if recursive and _isrecursive(pathname):
s = next(it) # skip empty string
assert not s
return it
def _iglob(pathname, recursive, dironly):
dirname, basename = os.path.split(pathname)
if not has_magic(pathname):
assert not dironly
if basename:
if os.path.lexists(pathname):
yield pathname
else:
# Patterns ending with a slash should match only directories
if os.path.isdir(dirname):
yield pathname
return
if not dirname:
if recursive and _isrecursive(basename):
yield _glob2(dirname, basename, dironly)
else:
yield _glob1(dirname, basename, dironly)
return
# `os.path.split()` returns the argument itself as a dirname if it is a
# drive or UNC path. Prevent an infinite recursion if a drive or UNC path
# contains magic characters (i.e. r'\\?\C:').
if dirname != pathname and has_magic(dirname):
dirs = _iglob(dirname, recursive, True)
else:
dirs = [dirname]
if has_magic(basename):
if recursive and _isrecursive(basename):
glob_in_dir = _glob2
else:
glob_in_dir = _glob1
else:
glob_in_dir = _glob0
for dirname in dirs:
for name in glob_in_dir(dirname, basename, dironly):
yield os.path.join(dirname, name)
# These 2 helper functions non-recursively glob inside a literal directory.
# They return a list of basenames. _glob1 accepts a pattern while _glob0
# takes a literal basename (so it only has to check for its existence).
def _glob1(dirname, pattern, dironly):
names = list(_iterdir(dirname, dironly))
return fnmatch.filter(names, pattern)
def _glob0(dirname, basename, dironly):
if not basename:
# `os.path.split()` returns an empty basename for paths ending with a
# directory separator. 'q*x/' should match only directories.
if os.path.isdir(dirname):
return [basename]
else:
if os.path.lexists(os.path.join(dirname, basename)):
return [basename]
return []
# Following functions are not public but can be used by third-party code.
def glob0(dirname, pattern):
return _glob0(dirname, pattern, False)
def glob1(dirname, pattern):
return _glob1(dirname, pattern, False)
# This helper function recursively yields relative pathnames inside a literal
# directory.
def _glob2(dirname, pattern, dironly):
assert _isrecursive(pattern)
return [pattern[:0]] + list(_rlistdir(dirname, dironly))
# If dironly is false, yields all file names inside a directory.
# If dironly is true, yields only directory names.
def _iterdir(dirname, dironly):
if not dirname:
if isinstance(dirname, bytes):
dirname = bytes(os.curdir, 'ASCII')
else:
dirname = os.curdir
try:
for entry in os.listdir(dirname):
yield entry
except OSError:
return
# Recursively yields relative pathnames inside a literal directory.
def _rlistdir(dirname, dironly):
if not os.path.islink(dirname):
names = list(_iterdir(dirname, dironly))
for x in names:
yield x
path = os.path.join(dirname, x) if dirname else x
for y in _rlistdir(path, dironly):
yield os.path.join(x, y)
magic_check = re.compile('([*?[])')
magic_check_bytes = re.compile(b'([*?[])')
def has_magic(s):
if isinstance(s, bytes):
match = magic_check_bytes.search(s)
else:
match = magic_check.search(s)
return match is not None
def _ishidden(path):
return path[0] in ('.', b'.'[0])
def _isrecursive(pattern):
if isinstance(pattern, bytes):
return pattern == b'**'
else:
return pattern == '**'
def escape(pathname):
"""Escape all special characters.
"""
# Escaping is done by wrapping any of "*?[" between square brackets.
# Metacharacters do not work in the drive part and shouldn't be escaped.
drive, pathname = os.path.splitdrive(pathname)
if isinstance(pathname, bytes):
pathname = magic_check_bytes.sub(br'[\1]', pathname)
else:
pathname = magic_check.sub(r'[\1]', pathname)
return drive + pathname
+127
View File
@@ -0,0 +1,127 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
from __future__ import absolute_import
import os
import re
import json
import sys
try:
import six
except ImportError:
import pip
pip.main(['install', 'six', '--ignore-installed', '-q'])
import six
from pathlib import Path
this_file_path = os.path.dirname(os.path.realpath(__file__))
def convert_glob_pattern_to_regex_pattern(glob_pattern):
# switch to forward slashes because way easier to pattern match against
pattern = re.sub(r'\\', r'/', glob_pattern)
# Replace the dots and question marks
pattern = re.sub(r'\.', r'\\.', pattern)
pattern = re.sub(r'\?', r'.', pattern)
# Handle the * vs ** expansions
pattern = re.sub(r'([^*])\*($|[^*])', r'\1[^/\\\\]*\2', pattern)
pattern = re.sub(r'\*\*/', r'(.*/)?', pattern)
pattern = re.sub(r'\*\*', r'.*', pattern)
# replace the forward slashes with [/\\] so it works on PC/unix
pattern = re.sub(r'([^^])/', r'\1[/\\\\]', pattern)
return pattern
# Convert the package json into a pair of regexes we can use to look for includes and excludes
def convert_glob_list_to_regex_list(filelist, prefix):
includes = []
excludes = []
for key, value in six.iteritems(filelist):
glob_pattern = os.path.join(prefix, key)
if isinstance(value, dict):
(sub_includes, sub_excludes) = convert_glob_list_to_regex_list(value, glob_pattern)
includes.extend(sub_includes)
excludes.extend(sub_excludes)
else:
# Simulate what glob would do with file walking to scope the * within a directory
# and ** across directories
regex_pattern = convert_glob_pattern_to_regex_pattern(os.path.normpath(glob_pattern))
# Deal with the commands. include/exclude are straight forward. Moves/renames are to be considered
# includes, and we will stick with validating the original contents for now
if value == "#include":
includes.append(regex_pattern)
elif value == "#exclude":
excludes.append(regex_pattern)
elif value.startswith('#move:'):
includes.append(regex_pattern)
elif value.startswith('#rename:'):
includes.append(regex_pattern)
else:
pass
return (includes, excludes)
def generate_excludes_for_platform(root, platform):
if platform == 'all':
platform_exclusions_filename = os.path.join(this_file_path, 'platform_exclusions.json')
with open(platform_exclusions_filename, 'r') as platform_exclusions_file:
platform_exclusions = json.load(platform_exclusions_file)
else:
# Use real path in case engine root is a symlink path
if os.name == 'posix' and os.path.islink(root):
root = os.readlink(root)
cur_dir = os.path.dirname(os.path.abspath(__file__))
relative_folder = os.path.relpath(cur_dir, root)
platform_exclusions_filename = os.path.join(root, 'restricted', platform, relative_folder, platform.lower() + '_exclusions.json')
with open(platform_exclusions_filename, 'r') as platform_exclusions_file:
platform_exclusions = json.load(platform_exclusions_file)
if platform not in platform_exclusions:
raise KeyError('No {} found in {}'.format(platform, platform_exclusions_filename))
if '@lyengine' not in platform_exclusions[platform]:
raise KeyError('No {}/@lyengine found in {}'.format(platform, package_file_list))
(_, excludes) = convert_glob_list_to_regex_list(platform_exclusions[platform]['@lyengine'], root)
del _
return excludes
def generate_include_exclude_regexes(package_platform, package_type, root, prohibited_platforms):
# The general contents will be indicated by the package file
if package_type == 'all':
package_file_list = os.path.join(this_file_path, 'package_filelists', 'all.json')
else:
# Search non-restricted platform first
package_file_list = os.path.join(this_file_path, 'Platform', package_platform, 'package_filelists', f'{package_type}.json')
if not os.path.exists(filelist):
# Use real path in case engine root is a symlink path
if os.name == 'posix' and os.path.islink(root):
root = os.readlink(root)
rel_path = os.path.relpath(cur_dir, root)
package_file_list = os.path.join(root, 'restricted', package_platform, rel_path, 'package_filelists',
f'{package_type}.json')
with open(package_file_list, 'r') as package_file:
package = json.load(package_file)
if '@lyengine' not in package:
raise KeyError('No @lyengine found in {}'.format(package_file_list))
(includes_list, excludes_list) = convert_glob_list_to_regex_list(package['@lyengine'], root)
prohibited_platforms.append('all')
# Add the exclusions of each prohibited platform
for p in prohibited_platforms:
excludes_list.extend(generate_excludes_for_platform(root, p))
includes = re.compile('|'.join(includes_list), re.IGNORECASE)
excludes = re.compile('|'.join(excludes_list), re.IGNORECASE)
return (includes, excludes)
def generate_exclude_regexes_for_platform(root, platform):
return re.compile('|'.join(generate_excludes_for_platform(root, platform)), re.IGNORECASE)
+302
View File
@@ -0,0 +1,302 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
import os
import sys
import glob_to_regex
import zipfile
import timeit
import stat
import progressbar
from optparse import OptionParser
from PackageEnv import PackageEnv
cur_dir = cur_dir = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, f'{cur_dir}/../../../Tools/build/JenkinsScripts/build')
from ci_build import build
from util import *
from glob3 import glob
def package(options):
package_env = PackageEnv(options.platform, options.type, options.package_env)
engine_root = package_env.get('ENGINE_ROOT')
if not package_env.get('SKIP_SCRUBBING'):
# Ask the validator code to tell us which files need to be removed from the package
prohibited_file_mask = get_prohibited_file_mask(options.platform, engine_root)
# Scrub files. This is destructive, but is necessary to allow the current file existance checks to work properly. Better to copy and then build, or to
# mask on sync, but this is what we have for now
scrub_files(package_env, prohibited_file_mask)
# validate files
validate_restricted_files(options.platform, options.type, package_env)
# Override values in bootstrap.cfg for PC package
override_bootstrap_cfg(package_env)
if not package_env.get('SKIP_BUILD'):
print(package_env.get('SKIP_BUILD'))
print('SKIP_BUILD is False, running CMake build...')
cmake_build(package_env)
# TODO Compile Assets
#if package_env.exists('ASSET_PROCESSOR_PATH'):
# compile_assets(package_env)
#create packages
package_targets = package_env.get('PACKAGE_TARGETS')
for package_target in package_targets:
create_package(package_env, package_target)
upload_package(package_env, package_target)
def get_python_path(package_env):
if sys.platform == 'win32':
return os.path.join(package_env.get('ENGINE_ROOT'), 'python', 'python.cmd')
else:
return os.path.join(package_env.get('ENGINE_ROOT'), 'python', 'python.sh')
def override_bootstrap_cfg(package_env):
print('Override values in bootstrap.cfg')
engine_root = package_env.get('ENGINE_ROOT')
bootstrap_path = os.path.join(engine_root, 'bootstrap.cfg')
replace_values = {'sys_game_folder':'{}'.format(package_env.get('BOOTSTRAP_CFG_GAME_FOLDER'))}
try:
with open(bootstrap_path, 'r') as bootstrap_cfg:
content = bootstrap_cfg.read()
except:
error('Cannot read file {}'.format(bootstrap_path))
content = content.split('\n')
new_content = []
for line in content:
if not line.startswith('--'):
strs = line.split('=')
if len(strs):
key = strs[0].strip(' ')
if key in replace_values:
line = '{}={}'.format(key, replace_values[key])
new_content.append(line)
try:
with open(bootstrap_path, 'w') as out:
out.write('\n'.join(new_content))
except:
error('Cannot write to file {}'.format(bootstrap_path))
print('{} updated with value {}'.format(bootstrap_path, replace_values))
def get_prohibited_file_mask(platform, engine_root):
sys.path.append(os.path.join(engine_root, 'Tools', 'build', 'JenkinsScripts', 'distribution', 'scrubbing'))
from validator_data_LEGAL_REVIEW_REQUIRED import get_prohibited_platforms_for_package
# The list of prohibited platforms is controlled by the validator on a per-package basis
prohibited_platforms = get_prohibited_platforms_for_package(platform)
prohibited_platforms.append('all')
excludes_list = []
for p in prohibited_platforms:
platform_excludes = glob_to_regex.generate_excludes_for_platform(engine_root, p)
excludes_list.extend(platform_excludes)
prohibited_file_mask = re.compile('|'.join(excludes_list), re.IGNORECASE)
return prohibited_file_mask
def scrub_files(package_env, prohibited_file_mask):
print('Perform the Code Scrubbing')
engine_root = package_env.get('ENGINE_ROOT')
success = True
for dirname, subFolders, files in os.walk(engine_root):
for filename in files:
full_path = os.path.join(dirname, filename)
if prohibited_file_mask.match(full_path):
try:
print('Deleting: {}'.format(full_path))
os.chmod(full_path, stat.S_IWRITE)
os.unlink(full_path)
except:
e = sys.exc_info()[0]
sys.stderr.write('Error: could not delete {} ... aborting.\n'.format(full_path))
sys.stderr.write('{}\n'.format(str(e)))
success = False
if not success:
sys.stderr.write('ERROR: scrub_files failed\n')
sys.exit(1)
def validate_restricted_files(package_platform, package_type, package_env):
print('Perform the Code Scrubbing')
engine_root = package_env.get('ENGINE_ROOT')
# Run validator
success = True
validator_path = os.path.join(engine_root, 'Tools/build/JenkinsScripts/distribution/scrubbing/validator.py')
python = get_python_path(package_env)
args = [python, validator_path, '--package_platform', package_platform, '--package_type', package_type, engine_root]
return_code = safe_execute_system_call(args)
if return_code != 0:
success = False
if not success:
error('Restricted file validator failed.')
print('Restricted file validator completed successfully.')
def cmake_build(package_env):
build_targets = package_env.get('BUILD_TARGETS')
for build_target in build_targets:
build(build_target['BUILD_CONFIG_FILENAME'], build_target['PLATFORM'], build_target['TYPE'])
def create_package(package_env, package_target):
print('Creating zipfile for package target {}'.format(package_target))
cur_dir = os.path.dirname(os.path.abspath(__file__))
file_list_type = package_target['FILE_LIST_TYPE']
if file_list_type == 'All':
filelist = os.path.join(cur_dir, 'package_filelists', package_target['FILE_LIST'])
else:
# Search non-restricted platform first
filelist = os.path.join(cur_dir, 'Platform', file_list_type, 'package_filelists', package_target['FILE_LIST'])
if not os.path.exists(filelist):
engine_root = package_env.get('ENGINE_ROOT')
# Use real path in case engine root is a symlink path
if os.name == 'posix' and os.path.islink(engine_root):
engine_root = os.readlink(engine_root)
rel_path = os.path.relpath(cur_dir, engine_root)
filelist = os.path.join(engine_root, 'restricted', file_list_type, rel_path, 'package_filelists', package_target['FILE_LIST'])
with open(filelist, 'r') as source:
data = json.load(source)
lyengine = package_env.get('ENGINE_ROOT')
print('Calculating filelists...')
files = {}
if '@lyengine' in data:
files.update(filter_files(data['@lyengine'], lyengine))
if '@3rdParty' in data:
files.update(filter_files(data['@3rdParty'], package_env.get('THIRDPARTY_HOME')))
package_path = os.path.join(lyengine, package_target['PACKAGE_NAME'])
print('Creating zipfile at {}'.format(package_path))
start = timeit.default_timer()
with progressbar.ProgressBar(max_value=len(files), redirect_stderr=True) as bar:
with zipfile.ZipFile(package_path, 'w', compression=zipfile.ZIP_DEFLATED, allowZip64=True) as myzip:
i = 0
bar.update(i)
last_bar_update = timeit.default_timer()
for f in files:
if os.path.islink(f):
zipInfo = zipfile.ZipInfo(files[f])
zipInfo.create_system = 3
# long type of hex val of '0xA1ED0000L',
# say, symlink attr magic...
zipInfo.external_attr |= 0xA0000000
myzip.writestr(zipInfo, os.readlink(f))
else:
myzip.write(f, files[f])
i += 1
# Update progress bar every 2 minutes
if int(timeit.default_timer() - last_bar_update) > 120:
last_bar_update = timeit.default_timer()
bar.update(i)
bar.update(i)
stop = timeit.default_timer()
total_time = int(stop - start)
print('{} is created. Total time: {} seconds.'.format(package_path, total_time))
def get_MD5(file_path):
from hashlib import md5
chunk_size = 200 * 1024
h = md5()
with open(file_path, 'rb') as f:
while True:
chunk = f.read(chunk_size)
if len(chunk):
h.update(chunk)
else:
break
return h.hexdigest()
md5_file = '{}.MD5'.format(package_path)
print('Creating MD5 file at {}'.format(md5_file))
start = timeit.default_timer()
with open(md5_file, 'w') as output:
output.write(get_MD5(package_path))
stop = timeit.default_timer()
total_time = int(stop - start)
print('{} is created. Total time: {} seconds.'.format(md5_file, total_time))
def upload_package(package_env, package_target):
package_name = package_target['PACKAGE_NAME']
engine_root = package_env.get('ENGINE_ROOT')
internal_s3_bucket = package_env.get('INTERNAL_S3_BUCKET')
qa_s3_bucket = package_env.get('QA_S3_BUCKET')
s3_prefix = package_env.get('S3_PREFIX')
print(f'Uploading {package_name} to S3://{internal_s3_bucket}/{s3_prefix}/{package_name}')
cmd = ['aws', 's3', 'cp', os.path.join(engine_root, package_name), f's3://{internal_s3_bucket}/{s3_prefix}/{package_name}']
execute_system_call(cmd, stdout=subprocess.DEVNULL)
print(f'Uploading {package_name} to S3://{qa_s3_bucket}/{s3_prefix}/{package_name}')
cmd = ['aws', 's3', 'cp', os.path.join(engine_root, package_name), f's3://{qa_s3_bucket}/{s3_prefix}/{package_name}', '--acl', 'bucket-owner-full-control']
execute_system_call(cmd, stdout=subprocess.DEVNULL)
def filter_files(data, base, prefix='', support_symlinks=True):
includes = {}
excludes = set()
for key, value in data.items():
pattern = os.path.join(base, prefix, key)
if not isinstance(value, dict):
pattern = os.path.normpath(pattern)
result = glob(pattern, recursive=True)
files = [x for x in result if os.path.isfile(x) or (support_symlinks and os.path.islink(x))]
if value == "#exclude":
excludes.update(files)
elif value == "#include":
for file in files:
includes[file] = os.path.relpath(file, base)
else:
if value.startswith('#move:'):
for file in files:
file_name = os.path.relpath(file, os.path.join(base, prefix))
dst_dir = value.replace('#move:', '').strip(' ')
includes[file] = os.path.join(dst_dir, file_name)
elif value.startswith('#rename:'):
for file in files:
dst_file = value.replace('#rename:', '').strip(' ')
includes[file] = dst_file
else:
warn('Unknown directive {} for pattern {}'.format(value, pattern))
else:
includes.update(filter_files(value, base, os.path.join(prefix, key), support_symlinks))
for exclude in excludes:
try:
includes.pop(exclude)
except KeyError:
pass
return includes
def parse_args():
parser = OptionParser()
parser.add_option("--platform", dest="platform", default='consoles', help="Target platform to package")
parser.add_option("--type", dest="type", default='consoles', help="Package type")
parser.add_option("--package_env", dest="package_env", default="package_env.json",
help="JSON file that defines package environment variables")
(options, args) = parser.parse_args()
return options, args
if __name__ == "__main__":
(options, args) = parse_args()
package(options)
+11
View File
@@ -0,0 +1,11 @@
{
"global_env":{
"ENGINE_ROOT":"",
"THIRDPARTY_HOME":"",
"BRANCH_NAME":"",
"PACKAGE_NAME_PATTERN":"${BRANCH_NAME}-spectra",
"BUILD_NUMBER":"0",
"INTERNAL_S3_BUCKET": "ly-spectra-packages",
"QA_S3_BUCKET": "amazon.ly.lionbridgeshare/ly-spectra-packages"
}
}
@@ -0,0 +1,7 @@
{
"@lyengine": {
"**": "#include",
"**/*.pyc": "#exclude",
"**/*.pdb": "#exclude"
}
}
@@ -0,0 +1,6 @@
{
"@lyengine": {
"**/*.pdb": "#include",
"Tools/Crashpad/**": "#exclude"
}
}
@@ -0,0 +1,12 @@
{
"all": {
"@lyengine": {
"**/Gems/Atom/RHI/DX12/External/pix/**": "#exclude",
"**/.idea/**": "#exclude",
"**/*.csproj*": "#exclude",
"**/.owner": "#exclude",
"**/WinPixEventRuntime.dll": "#exclude",
"**/XenonConsole.exe": "#exclude"
}
}
}
+62
View File
@@ -0,0 +1,62 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
import json
import os
import re
import sys
import subprocess
class LyBuildError(Exception):
def __init__(self, message):
super(LyBuildError, self).__init__(message)
def ly_build_error(message):
raise LyBuildError(message)
def error(message):
print(('Error: {}'.format(message)))
exit(1)
# Exit with status code 0 means it won't fail the whole build process
def safe_exit_with_error(message):
print(('Error: {}'.format(message)))
exit(0)
def warn(message):
print(('Warning: {}'.format(message)))
def execute_system_call(command, **kwargs):
print(('Executing subprocess.check_call({})'.format(command)))
try:
subprocess.check_call(command, **kwargs)
except subprocess.CalledProcessError as e:
print((e.output))
error('Executing subprocess.check_call({}) failed with error {}'.format(command, e))
except FileNotFoundError as e:
error("File Not Found - Failed to call {} with error {}".format(command, e))
def safe_execute_system_call(command, **kwargs):
print(('Executing subprocess.check_call({})'.format(command)))
try:
subprocess.check_call(command, **kwargs)
except subprocess.CalledProcessError as e:
print((e.output))
warn('Executing subprocess.check_call({}) failed'.format(command))
return e.returncode
return 0