You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Tools/build/JenkinsScripts/distribution/Installer/BuildInstallerUtils.py

207 lines
7.8 KiB
Python

#
# 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 shutil
import uuid
from urllib.parse import urlparse
download_url_base = "http://gamedev.amazon.com/lumberyard/releases/"
def set_download_url_base(url):
global download_url_base
download_url_base = url
def is_url(potential_url):
return urlparse(potential_url)[0] == 'https'
def get_package_name(package_path):
path_to_file = package_path
if is_url(package_path):
# index 2 is everything that isn't a parameter in the URL after the high level domain
# see https://docs.python.org/2/library/urlparse.html#urlparse.urlparse for more info
path_to_file = urlparse(package_path)[2]
return os.path.basename(path_to_file)
def get_ly_version_from_package(args, unpacked_location):
version = None
path_to_default_settings = os.path.join(unpacked_location, 'dev/_WAF_/default_settings.json')
verbose_print(args.verbose, 'Searching for Lumberyard version in {}'.format(path_to_default_settings))
with open(path_to_default_settings) as default_settings_file:
default_settings_data = json.load(default_settings_file)
default_settings_file.close()
for build_option in default_settings_data['Build Options']:
if 'attribute' in build_option and 'default_value' in build_option:
if build_option['attribute'] == 'version':
version = build_option['default_value']
if version is None:
verbose_print(args.verbose, 'Version not found in package')
raise Exception('Version was not available in default settings.json')
return version
def append_trailing_slash_to_url(url):
if not url.endswith(tuple(['/', '\\'])):
url += '/'
return url
def generate_target_url(base_target_url, version, build_id, suppress_version_in_path, append_build_id):
output_url = base_target_url
if append_build_id:
output_url = append_trailing_slash_to_url(output_url)
output_url += build_id
if not suppress_version_in_path:
output_url = append_trailing_slash_to_url(output_url)
output_url += '{}/installer'.format(version)
return output_url
# PRODUCT & UPGRADE/PATCH GUID CREATION
def create_id(name, seed, version, build_id):
"""
Generate the Product GUID using the name, the version, and a changelist value.
@param name - Name of the product.
@param seed - String used to create a unique GUID.
@param version - The version of the product in the form "PRODUCT.MAJOR.MINOR.PATCH".
@param build_id - An optional identifier for the build to be used in GUID generation.
@return - A GUID for this version of the product.
"""
# Temporary. Replace the download_url_base with wherever we pass in to the public host or host url.
uuid_seed = download_url_base + seed + name + version
if build_id is not None:
uuid_seed += build_id
return str(uuid.uuid3(uuid.NAMESPACE_URL, uuid_seed)).upper()
# END PRODUCT & UPGRADE/PATCH GUID CREATION
def replace_leading_numbers(source_string):
pattern = re.compile(r'^[0-9]')
return pattern.sub('N', source_string)
def strip_special_characters(source_string):
"""
Remove all non-alphanumeric characters from the given sourceString.
@return - A new string that is a copy of the original, containing only
letters and numbers.
"""
if source_string.isalnum():
return source_string
pattern = re.compile(r'[\W_]+')
return pattern.sub('', source_string)
def check_for_empty_subfolders(package_root, allowed_empty_folders):
# find empty folders
empty_folders_found = []
for root, dirs, files in os.walk(package_root):
if dirs == [] and files == []:
empty_folders_found.append(os.path.normpath(os.path.relpath(root, package_root)))
if allowed_empty_folders is not None:
whitelist_root = 'Whitelist'
whitelist_folders = []
assert (os.path.exists(allowed_empty_folders)), 'The whitelist file specified at {} does not exist.'.format(allowed_empty_folders)
with open(allowed_empty_folders, 'r') as source:
json_whitelist = json.load(source)
try:
for allowed_folder in json_whitelist[whitelist_root]:
whitelist_folders.append(os.path.normpath(allowed_folder))
except KeyError:
print('Unknown json root {}, please check the json root specified.'.format(whitelist_root))
exit(1)
assert (len(whitelist_folders) > 0), 'The whitelist in the file specified at {} is empty. Either populate the list or omit the argument.'.format(allowed_empty_folders)
for folder in empty_folders_found:
assert (folder in whitelist_folders), 'The empty folder {} could not be found in the whitelist of empty folders.'.format(folder)
def get_immediate_subdirectories(root_dir):
"""
Create a list of all directories that exist in the given directory, without
recursing through the subdirectories' children.
@param root_dir - The directory to search for subdirectories.
@return - A list of subdirectories in this directory, excluding their children.
"""
directories = []
for directory in os.listdir(root_dir):
if os.path.isdir(os.path.join(root_dir, directory)):
directories.append(directory)
return directories
def get_file_names_in_directory(directory, file_extension=None):
"""
Create a list of all files in a directory. If given a file extension, it
will list all files with that extension.
@param directory - The directory to gather files from.
@param file_extension - (Optional) The type of files to find. Must be a
string in the ".extension" format. (Default None)
@retun - A list of names of all files in this directory (that match the given
extension if provided).
"""
file_list = []
if file_extension:
for file in os.listdir(directory):
if file.endswith(file_extension):
file_list.append(os.path.basename(file))
else:
for file in os.listdir(directory):
file_list.append(os.path.basename(file))
return file_list
# VERBOSE RELATED FUNCTIONS
def verbose_print(isVerbose, message):
if isVerbose:
print(message)
def find_file_in_package(packageRoot, fileToFind, pathFilters=None):
"""
Searchs the package path for a file.
@param packageRoot: Path to the root of content.
@param fileToFind: Name of the file to find.
@param pathFilters: Path filter to apply to find.
@return: The full path to the file if found, otherwise None.
"""
for root, dirs, files in os.walk(packageRoot):
if fileToFind in files:
if pathFilters is None or any(pathFilter in root for pathFilter in pathFilters):
return os.path.join(root, fileToFind)
return None
def safe_shutil_file_copy(src, dst):
# need to remove the old version of dst if it already exists due to a bug
# in shutil.copy that causes both the src and dst files to be zeroed out
# if they are identical files.
if os.path.exists(dst):
os.remove(dst)
shutil.copy(src, dst)
def create_version_file(buildId, installerPath):
with open(os.path.join(installerPath, 'version.txt'), 'w') as versionFile:
versionFile.write(buildId)