From ae60bd0167483bad342bcaae9fa2638ee5df91d9 Mon Sep 17 00:00:00 2001 From: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> Date: Fri, 16 Jul 2021 14:33:39 -0700 Subject: [PATCH 01/12] [installer/2106-font] revert back to default install bootstrapper font Signed-off-by: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> --- .../Windows/Packaging/BootstrapperTheme.xml.in | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cmake/Platform/Windows/Packaging/BootstrapperTheme.xml.in b/cmake/Platform/Windows/Packaging/BootstrapperTheme.xml.in index 8d8416539e..c670ef3d9a 100644 --- a/cmake/Platform/Windows/Packaging/BootstrapperTheme.xml.in +++ b/cmake/Platform/Windows/Packaging/BootstrapperTheme.xml.in @@ -4,15 +4,15 @@ #(loc.WindowTitle) - Open Sans + Segoe UI - Open Sans + Segoe UI - Open Sans + Segoe UI - Open Sans + Segoe UI - Open Sans + Segoe UI From 679ecf480197d234cc86fd123c5535a33c25d474 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Fri, 16 Jul 2021 17:40:27 -0500 Subject: [PATCH 02/12] External Gem and Projects now appear in Editor AssetBrowser (#2227) * External Gem and Projects now appear in Editor AssetBrowser Optimized logic populating the FolderAssetBrowserEntries in the Editor AssetBrowser. Added an "[External]" tag to scan folders which reside outside of the Engine Root Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Fixed conversion of fixed_string to string when normalizing an added AssetBrowser file path. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * RootAssetBrowserEntry.cpp Linux conditional expression fix Because an AZ::IO::PathView is convertible to an AZ::IO::FixedMaxPath and vice-versa, the conversion of the second part of the ternary expression absolutePathView needs to explicitly convert to an AZ::IO::FixedMaxPath Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> --- .../Entries/AssetBrowserEntry.cpp | 4 +- .../AssetBrowser/Entries/AssetBrowserEntry.h | 5 +- .../Entries/FolderAssetBrowserEntry.cpp | 4 +- .../Entries/RootAssetBrowserEntry.cpp | 201 ++++++++---------- .../Entries/RootAssetBrowserEntry.h | 12 +- .../Entries/SourceAssetBrowserEntry.cpp | 4 +- 6 files changed, 105 insertions(+), 125 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Entries/AssetBrowserEntry.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Entries/AssetBrowserEntry.cpp index 17a20a9d19..7eae7621d2 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Entries/AssetBrowserEntry.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Entries/AssetBrowserEntry.cpp @@ -206,12 +206,12 @@ namespace AzToolsFramework const AZStd::string& AssetBrowserEntry::GetRelativePath() const { - return m_relativePath; + return m_relativePath.Native(); } const AZStd::string& AssetBrowserEntry::GetFullPath() const { - return m_fullPath; + return m_fullPath.Native(); } const AssetBrowserEntry* AssetBrowserEntry::GetChild(int index) const diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Entries/AssetBrowserEntry.h b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Entries/AssetBrowserEntry.h index e4a7b6b4cb..24f037a623 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Entries/AssetBrowserEntry.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Entries/AssetBrowserEntry.h @@ -9,6 +9,7 @@ #if !defined(Q_MOC_RUN) #include #include +#include #include #include @@ -130,8 +131,8 @@ namespace AzToolsFramework protected: AZStd::string m_name; QString m_displayName; - AZStd::string m_relativePath; - AZStd::string m_fullPath; + AZ::IO::Path m_relativePath; + AZ::IO::Path m_fullPath; AZStd::vector m_children; AssetBrowserEntry* m_parentAssetEntry = nullptr; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Entries/FolderAssetBrowserEntry.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Entries/FolderAssetBrowserEntry.cpp index 3c5afab0d0..febd406f23 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Entries/FolderAssetBrowserEntry.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Entries/FolderAssetBrowserEntry.cpp @@ -37,8 +37,8 @@ namespace AzToolsFramework void FolderAssetBrowserEntry::UpdateChildPaths(AssetBrowserEntry* child) const { - child->m_relativePath = m_relativePath + AZ_CORRECT_DATABASE_SEPARATOR + child->m_name; - child->m_fullPath = m_fullPath + AZ_CORRECT_DATABASE_SEPARATOR + child->m_name; + child->m_relativePath = m_relativePath / child->m_name; + child->m_fullPath = m_fullPath / child->m_name; AssetBrowserEntry::UpdateChildPaths(child); } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Entries/RootAssetBrowserEntry.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Entries/RootAssetBrowserEntry.cpp index 090ad0d6ca..0e132d2581 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Entries/RootAssetBrowserEntry.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Entries/RootAssetBrowserEntry.cpp @@ -10,6 +10,7 @@ #include #include +#include #include #include @@ -24,8 +25,6 @@ namespace AzToolsFramework { namespace AssetBrowser { - const char* GEMS_FOLDER_NAME = "Gems"; - RootAssetBrowserEntry::RootAssetBrowserEntry() : AssetBrowserEntry() { @@ -53,13 +52,7 @@ namespace AzToolsFramework EntryCache::GetInstance()->Clear(); m_enginePath = enginePath; - - // there is no "Gems" scan folder registered in db, create one manually - auto gemFolder = aznew FolderAssetBrowserEntry(); - gemFolder->m_name = m_enginePath + AZ_CORRECT_DATABASE_SEPARATOR + GEMS_FOLDER_NAME; - gemFolder->m_displayName = GEMS_FOLDER_NAME; - gemFolder->m_isGemsFolder = true; - AddChild(gemFolder); + m_fullPath = enginePath; } bool RootAssetBrowserEntry::IsInitialUpdate() const @@ -80,8 +73,17 @@ namespace AzToolsFramework if (AZ::IO::FileIOBase::GetInstance()->IsDirectory(scanFolderDatabaseEntry.m_scanFolder.c_str())) { - const auto scanFolder = CreateFolders(scanFolderDatabaseEntry.m_scanFolder.c_str(), this); - scanFolder->m_displayName = QString::fromUtf8(scanFolderDatabaseEntry.m_displayName.c_str()); + const auto scanFolder = CreateFolders(scanFolderDatabaseEntry.m_scanFolder, this); + // Append an "[External]" to the display if the Scan Folder is NOT relative to the Engine Root path + if (!AZ::IO::PathView(scanFolderDatabaseEntry.m_scanFolder).IsRelativeTo(m_enginePath)) + { + scanFolder->m_displayName += " [External]"; + } + else + { + scanFolder->m_displayName = QString::fromUtf8(scanFolderDatabaseEntry.m_displayName.c_str()); + } + EntryCache::GetInstance()->m_scanFolderIdMap[scanFolderDatabaseEntry.m_scanFolderID] = scanFolder; } } @@ -121,38 +123,34 @@ namespace AzToolsFramework return; } - const char* filePath = fileDatabaseEntry.m_fileName.c_str(); + AZ::IO::FixedMaxPath absoluteFilePath = AZ::IO::FixedMaxPath(AZStd::string_view{ scanFolder->GetFullPath() }) + / fileDatabaseEntry.m_fileName.c_str(); AssetBrowserEntry* file; // file can be either folder or actual file if (fileDatabaseEntry.m_isFolder) { - file = CreateFolders(filePath, scanFolder); + file = CreateFolders(absoluteFilePath.Native(), scanFolder); } else { - AZStd::string sourcePath; - AZStd::string sourceName; - AZStd::string sourceExtension; - StringFunc::Path::Split(filePath, nullptr, &sourcePath, &sourceName, &sourceExtension); // if missing create folders leading to file's location and get immediate parent // (we don't need to have fileIds for any folders created yet, they will be added later) - auto parent = CreateFolders(sourcePath.c_str(), scanFolder); + auto parent = CreateFolders(absoluteFilePath.ParentPath().Native(), scanFolder); // for simplicity in AB, files are represented as sources, but they are missing SourceDatabaseEntry-specific information such as SourceUuid auto source = aznew SourceAssetBrowserEntry(); - source->m_name = (sourceName + sourceExtension).c_str(); + source->m_name = absoluteFilePath.Filename().Native(); source->m_fileId = fileDatabaseEntry.m_fileID; source->m_displayName = QString::fromUtf8(source->m_name.c_str()); source->m_scanFolderId = fileDatabaseEntry.m_scanFolderPK; - source->m_extension = sourceExtension.c_str(); + source->m_extension = absoluteFilePath.Extension().Native(); parent->AddChild(source); file = source; } EntryCache::GetInstance()->m_fileIdMap[fileDatabaseEntry.m_fileID] = file; - AZStd::string fullPath = file->m_fullPath; - AzFramework::StringFunc::Path::Normalize(fullPath); - EntryCache::GetInstance()->m_absolutePathToFileId[fullPath] = fileDatabaseEntry.m_fileID; + AZStd::string filePath = AZ::IO::PathView(file->m_fullPath).LexicallyNormal().String(); + EntryCache::GetInstance()->m_absolutePathToFileId[filePath] = fileDatabaseEntry.m_fileID; } bool RootAssetBrowserEntry::RemoveFile(const AZ::s64& fileId) const @@ -305,116 +303,95 @@ namespace AzToolsFramework } } - FolderAssetBrowserEntry* RootAssetBrowserEntry::CreateFolder(const char* folderName, AssetBrowserEntry* parent) + AssetBrowserEntry* RootAssetBrowserEntry::GetNearestAncestor(AZ::IO::PathView absolutePathView, AssetBrowserEntry* parent, + AZStd::unordered_set& visitedSet) + { + auto IsPathRelativeToEntry = [absolutePathView](AssetBrowserEntry* assetBrowserEntry) + { + auto& childPath = assetBrowserEntry->m_fullPath; + return absolutePathView.IsRelativeTo(AZ::IO::PathView(childPath)); + }; + + if (visitedSet.contains(parent)) + { + return {}; + } + + visitedSet.insert(parent); + + AssetBrowserEntry* nearestAncestor{}; + for (AssetBrowserEntry* childBrowserEntry : parent->m_children) + { + if (IsPathRelativeToEntry(childBrowserEntry)) + { + // Walk the AssetBrowserEntry Tree looking for a nearer ancestor to the absolute path + // If one is not found in the recursive call to GetNearestAncestor, then the childBrowserEntry + // is the current best candidate + AssetBrowserEntry* candidateAncestor = GetNearestAncestor(absolutePathView, childBrowserEntry, visitedSet); + candidateAncestor = candidateAncestor != nullptr ? candidateAncestor : childBrowserEntry; + AZ::IO::PathView candidatePathView(candidateAncestor->m_fullPath); + // If the candidate is relative to the current nearest ancestor, then it is even nearer to the path + if (!nearestAncestor || candidatePathView.IsRelativeTo(nearestAncestor->m_fullPath)) + { + nearestAncestor = candidateAncestor; + // If the full path compares equal to the AssetBrowserEntry path, then no need to proceed any further + if (AZ::IO::PathView(nearestAncestor->m_fullPath) == absolutePathView) + { + break; + } + } + } + } + + return nearestAncestor; + } + + FolderAssetBrowserEntry* RootAssetBrowserEntry::CreateFolder(AZStd::string_view folderName, AssetBrowserEntry* parent) { auto it = AZStd::find_if(parent->m_children.begin(), parent->m_children.end(), [folderName](AssetBrowserEntry* entry) - { - if (!azrtti_istypeof(entry)) - { - return false; - } - return AzFramework::StringFunc::Equal(entry->m_name.c_str(), folderName); - }); + { + if (!azrtti_istypeof(entry)) + { + return false; + } + return AZ::IO::PathView(entry->m_name) == AZ::IO::PathView(folderName); + }); if (it != parent->m_children.end()) { return azrtti_cast(*it); } const auto folder = aznew FolderAssetBrowserEntry(); folder->m_name = folderName; - folder->m_displayName = folderName; + folder->m_displayName = QString::fromUtf8(folderName.data(), aznumeric_caster(folderName.size())); parent->AddChild(folder); return folder; } - AssetBrowserEntry* RootAssetBrowserEntry::CreateFolders(const char* relativePath, AssetBrowserEntry* parent) + AssetBrowserEntry* RootAssetBrowserEntry::CreateFolders(AZStd::string_view absolutePath, AssetBrowserEntry* parent) { - auto children(parent->m_children); - int n = 0; + AZ::IO::PathView absolutePathView(absolutePath); + // Find the nearest ancestor path to the absolutePath + AZStd::unordered_set visitedSet; - // check if folder with the same name already exists - // step through every character in relativePath and compare to each child's relative path of suggested parent - // if a character @n in child's rel path mismatches character at n in relativePath, remove that child from further search - while (!children.empty() && relativePath[n]) + if (AssetBrowserEntry* nearestAncestor = GetNearestAncestor(absolutePathView, parent, visitedSet); + nearestAncestor != nullptr) { - AZStd::vector toRemove; - for (auto child : children) - { - auto& childPath = azrtti_istypeof(parent) ? child->m_fullPath : child->m_relativePath; - - // child's path mismatched, remove it from search candidates - if (childPath.length() == n || childPath[n] != relativePath[n]) - { - toRemove.push_back(child); - - // it is possible that child may be a closer parent, substitute it as new potential parent - // e.g. child->m_relativePath = 'Gems', relativePath = 'Gems/Assets', old parent = root, new parent = Gems - if (childPath.length() == n && relativePath[n] == AZ_CORRECT_DATABASE_SEPARATOR) - { - parent = child; - relativePath += n; // advance relative path n characters since the parent has changed - n = 0; // Once the relative path pointer is advanced, reset n - } - } - } - for (auto entry : toRemove) - { - children.erase(AZStd::remove(children.begin(), children.end(), entry), children.end()); - } - n++; + parent = nearestAncestor; } - // filter out the remaining children that don't end with '/' or '\0' - // for example if folderName = "foo", while children may still remain with names like "foo123", - // which is not the same folder - AZStd::vector toRemove; - for (auto child : children) + // If the nearest ancestor is the absolutePath, then it is already crated + if (absolutePathView == AZ::IO::PathView(parent->GetFullPath())) { - auto& childPath = azrtti_istypeof(parent) ? child->m_fullPath : child->m_relativePath; - // check if there are non-null characters remaining @n - if (childPath.length() > n) - { - toRemove.push_back(child); - } - } - for (auto entry : toRemove) - { - children.erase(AZStd::remove(children.begin(), children.end(), entry), children.end()); + return parent; } - // at least one child remains, this means the folder with this name already exists, return it - if (!children.empty()) + // create all missing folders + auto proximateToPath = absolutePathView.IsRelativeTo(parent->m_fullPath) + ? absolutePathView.LexicallyProximate(parent->m_fullPath) + : AZ::IO::FixedMaxPath(absolutePathView); + for (AZ::IO::FixedMaxPath scanFolderSegment : proximateToPath) { - parent = children.front(); - } - // if it's a scanfolder, then do not create folders leading to it - // e.g. instead of 'C:\dev\SampleProject' just create 'SampleProject' - else if (parent->GetEntryType() == AssetEntryType::Root) - { - AZStd::string folderName; - AzFramework::StringFunc::Path::Split(relativePath, nullptr, nullptr, &folderName); - parent = CreateFolder(folderName.c_str(), parent); - parent->m_fullPath = relativePath; - } - // otherwise create all missing folders - else - { - n = 0; - AZStd::string folderName(strlen(relativePath) + 1, '\0'); - // iterate through relativePath until the first '/' - while (relativePath[n] && relativePath[n] != AZ_CORRECT_DATABASE_SEPARATOR) - { - folderName[n] = relativePath[n]; - n++; - } - if (n > 0) - { - parent = CreateFolder(folderName.c_str(), parent); - } - // n+1 also skips the '/' character - if (relativePath[n] && relativePath[n + 1]) - { - parent = CreateFolders(relativePath + n + 1, parent); - } + parent = CreateFolder(scanFolderSegment.c_str(), parent); } return parent; } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Entries/RootAssetBrowserEntry.h b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Entries/RootAssetBrowserEntry.h index 883f9dec01..62fbc7a39d 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Entries/RootAssetBrowserEntry.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Entries/RootAssetBrowserEntry.h @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -77,12 +78,15 @@ namespace AzToolsFramework private: AZ_DISABLE_COPY_MOVE(RootAssetBrowserEntry); - AZStd::string m_enginePath; + AZ::IO::Path m_enginePath; //! Create folder entry child - FolderAssetBrowserEntry* CreateFolder(const char* folderName, AssetBrowserEntry* parent); - //! Recursively create folder structure leading to relative path from parent - AssetBrowserEntry* CreateFolders(const char* relativePath, AssetBrowserEntry* parent); + FolderAssetBrowserEntry* CreateFolder(AZStd::string_view folderName, AssetBrowserEntry* parent); + //! Recursively create folder structure leading to path from parent + AssetBrowserEntry* CreateFolders(AZStd::string_view absolutePath, AssetBrowserEntry* parent); + // Retrieves the nearest ancestor AssetBrowserEntry from the absolutePath + static AssetBrowserEntry* GetNearestAncestor(AZ::IO::PathView absolutePath, AssetBrowserEntry* parent, + AZStd::unordered_set& visitedSet); bool m_isInitialUpdate = false; }; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Entries/SourceAssetBrowserEntry.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Entries/SourceAssetBrowserEntry.cpp index e45c234c92..1eea909f7c 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Entries/SourceAssetBrowserEntry.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Entries/SourceAssetBrowserEntry.cpp @@ -26,9 +26,7 @@ namespace AzToolsFramework if (EntryCache* cache = EntryCache::GetInstance()) { cache->m_fileIdMap.erase(m_fileId); - AZStd::string fullPath = m_fullPath; - AzFramework::StringFunc::Path::Normalize(fullPath); - cache->m_absolutePathToFileId.erase(fullPath); + cache->m_absolutePathToFileId.erase(m_fullPath.LexicallyNormal().Native()); if (m_sourceId != -1) { From 173126f5a5f1b3a1efc65e5a902c48d63b2a5ad9 Mon Sep 17 00:00:00 2001 From: Brian Herrera Date: Mon, 19 Jul 2021 16:09:47 -0700 Subject: [PATCH 03/12] Add script for license scanner (#2267) * Add script for license scanner This script will scan the source tree for license files and generate a file with the contents of all the licenses. Signed-off-by: brianherrera --- scripts/license_scanner/license_scanner.py | 129 ++++++++++++++++++++ scripts/license_scanner/scanner_config.json | 12 ++ 2 files changed, 141 insertions(+) create mode 100644 scripts/license_scanner/license_scanner.py create mode 100644 scripts/license_scanner/scanner_config.json diff --git a/scripts/license_scanner/license_scanner.py b/scripts/license_scanner/license_scanner.py new file mode 100644 index 0000000000..c0e3c1f1ba --- /dev/null +++ b/scripts/license_scanner/license_scanner.py @@ -0,0 +1,129 @@ +# +# Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. +# +# SPDX-License-Identifier: Apache-2.0 OR MIT +# +# + +import argparse +import fnmatch +import json +import os +import pathlib +import re +import sys + + +class LicenseScanner: + """Class to contain license scanner. + + Scans source tree for license files using provided filename patterns and generates a file + with the contents of all the licenses. + + :param config_file: Config file with license patterns and scanner settings + """ + + DEFAULT_CONFIG_FILE = 'scanner_config.json' + + def __init__(self, config_file=None): + self.config_file = config_file + self.config_data = self._load_config() + self.license_regex = self._load_license_regex() + + def _load_config(self): + """Load config from the provided file. Sets default file if one is not provided.""" + if self.config_file is None: + script_directory = os.path.dirname(os.path.abspath(__file__)) # Default file expected in same dir as script + self.config_file = os.path.join(script_directory, self.DEFAULT_CONFIG_FILE) + + try: + with open(self.config_file) as f: + return json.load(f) + except FileNotFoundError: + print('Config file cannot be found') + raise + + def _load_license_regex(self): + """Returns regex object with case-insensitive matching from the list of filename patterns.""" + regex_patterns = [] + for pattern in self.config_data['license_patterns']: + regex_patterns.append(fnmatch.translate(pattern)) + return re.compile('|'.join(regex_patterns), re.IGNORECASE) + + def scan(self, path=os.curdir): + """Scan directory tree for filenames matching license_regex. + + :param path: Path of the directory to run scanner + :return: Package paths and their corresponding license file contents + :rtype: dict + """ + licenses = 0 + license_files = {} + + for dirpath, dirnames, filenames in os.walk(path): + for file in filenames: + if self.license_regex.match(file): + license_file_content = self._get_license_file_contents(os.path.join(dirpath, file)) + rel_dirpath = os.path.relpath(dirpath, path) # Limit path inside scanned directory + license_files[rel_dirpath] = license_file_content + licenses += 1 + print(f'License file: {os.path.join(dirpath, file)}') + + # Remove directories that should not be scanned + for dir in self.config_data['excluded_directories']: + if dir in dirnames: + dirnames.remove(dir) + print(f'{licenses} license files found.') + return license_files + + def _get_license_file_contents(self, filepath): + try: + with open(filepath, encoding='utf8') as f: + return f.read() + except UnicodeDecodeError: + print(f'Unable to read license file: {filepath}') + pass + + def create_license_file(self, licenses, filepath='NOTICES.txt'): + """Creates file with all the provided license file contents. + + :param licenses: Dict with package paths and their corresponding license file contents + :param filepath: Path to write the file + """ + package_separator = '------------------------------------' + with open(filepath, 'w', encoding='utf8') as f: + for directory, license in licenses.items(): + license_output = '\n\n'.join([ + f'{package_separator}', + f'Package path: {directory}', + 'License:', + f'{license}\n' + ]) + f.write(license_output) + return None + + +def parse_args(): + parser = argparse.ArgumentParser( + description='Script to run LicenseScanner and generate license file') + parser.add_argument('--config-file', '-c', type=pathlib.Path, help='Config file for LicenseScanner') + parser.add_argument('--license-file-path', '-l', type=pathlib.Path, help='Create license file in the provided path') + parser.add_argument('--scan-path', '-s', default=os.curdir, type=pathlib.Path, help='Path to scan') + return parser.parse_args() + + +def main(): + try: + args = parse_args() + ls = LicenseScanner(args.config_file) + licenses = ls.scan(args.scan_path) + + if args.license_file_path: + ls.create_license_file(licenses, args.license_file_path) + except FileNotFoundError as e: + print(f'Type: {type(e).__name__}, Error: {e}') + return 1 + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/scripts/license_scanner/scanner_config.json b/scripts/license_scanner/scanner_config.json new file mode 100644 index 0000000000..b5863a7d31 --- /dev/null +++ b/scripts/license_scanner/scanner_config.json @@ -0,0 +1,12 @@ +{ + "excluded_directories": [ + ".git", + ".venv", + "build", + "license_scanner" + ], + "license_patterns": [ + "LICENSE*", + "COPYING*" + ] +} From afb57c9cf679592a209dbccdd5f38126e03d6b59 Mon Sep 17 00:00:00 2001 From: Scott Romero <24445312+AMZN-ScottR@users.noreply.github.com> Date: Mon, 19 Jul 2021 18:17:55 -0700 Subject: [PATCH 04/12] [stabliziation/2106] update 3rd party license file name to be pulled into the installer package (#2281) License file name was changed in #2267 Signed-off-by: AMZN-ScottR 24445312+AMZN-ScottR@users.noreply.github.com --- cmake/Packaging.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/Packaging.cmake b/cmake/Packaging.cmake index a07e1ec1d3..2240ff472c 100644 --- a/cmake/Packaging.cmake +++ b/cmake/Packaging.cmake @@ -128,7 +128,7 @@ install(FILES ${_cmake_package_dest} # the version string and git tags are intended to be synchronized so it should be safe to use that instead # of directly calling into git which could get messy in certain scenarios if(${CPACK_PACKAGE_VERSION} VERSION_GREATER "0.0.0.0") - set(_3rd_party_license_filename SPDX-Licenses.txt) + set(_3rd_party_license_filename NOTICES.txt) set(_3rd_party_license_url "https://raw.githubusercontent.com/o3de/3p-package-source/${CPACK_PACKAGE_VERSION}/${_3rd_party_license_filename}") set(_3rd_party_license_dest ${CPACK_BINARY_DIR}/${_3rd_party_license_filename}) From abce54b3cd0a574fff1a8612be838779ab597a73 Mon Sep 17 00:00:00 2001 From: Axel Nana Date: Tue, 20 Jul 2021 01:05:09 +0100 Subject: [PATCH 05/12] Add missing `*.hxx` pattern Signed-off-by: Axel Nana --- cmake/Platform/Common/Install_common.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/Platform/Common/Install_common.cmake b/cmake/Platform/Common/Install_common.cmake index 5b476667e2..0a84d3ceb2 100644 --- a/cmake/Platform/Common/Install_common.cmake +++ b/cmake/Platform/Common/Install_common.cmake @@ -64,6 +64,7 @@ function(ly_setup_target OUTPUT_CONFIGURED_TARGET ALIAS_TARGET_NAME absolute_tar PATTERN *.h PATTERN *.hpp PATTERN *.inl + PATTERN *.hxx ) endif() endforeach() From b58286d9b1022c3e3051c3225b7000935066fd4c Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Tue, 20 Jul 2021 20:40:04 -0500 Subject: [PATCH 06/12] Fixed RootAssetBrowserEntry setting of child AssetBrowserEntries The issue is due to RootAssetBrowserEntry::UpdateChildPaths not taking the RootAssetBrowserEntry fullpath into account when appending the child path entry Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> --- .../AssetBrowser/Entries/RootAssetBrowserEntry.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Entries/RootAssetBrowserEntry.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Entries/RootAssetBrowserEntry.cpp index 0e132d2581..eec9970ca3 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Entries/RootAssetBrowserEntry.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Entries/RootAssetBrowserEntry.cpp @@ -399,7 +399,7 @@ namespace AzToolsFramework void RootAssetBrowserEntry::UpdateChildPaths(AssetBrowserEntry* child) const { child->m_relativePath = child->m_name; - child->m_fullPath = child->m_name; + child->m_fullPath = m_fullPath / child->m_name; AssetBrowserEntry::UpdateChildPaths(child); } From 3050a4db479fb2dacf59942f7b0b42d7d82fcdcd Mon Sep 17 00:00:00 2001 From: jckand-amzn Date: Wed, 21 Jul 2021 10:18:18 -0500 Subject: [PATCH 07/12] Removing obsolete Vegetation Debugger test Signed-off-by: jckand-amzn --- .../EditorScripts/Debugger_DebugCVarsWorks.py | 55 ------------------ .../largeworlds/dyn_veg/test_Debugger.py | 56 ------------------- 2 files changed, 111 deletions(-) delete mode 100755 AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/Debugger_DebugCVarsWorks.py delete mode 100755 AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_Debugger.py diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/Debugger_DebugCVarsWorks.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/Debugger_DebugCVarsWorks.py deleted file mode 100755 index 40fd67d957..0000000000 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/Debugger_DebugCVarsWorks.py +++ /dev/null @@ -1,55 +0,0 @@ -""" -Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - -SPDX-License-Identifier: Apache-2.0 OR MIT -""" - -import os -import sys - -import azlmbr.legacy.general as general -import azlmbr.paths - -sys.path.append(os.path.join(azlmbr.paths.devroot, "AutomatedTesting", "Gem", "PythonTests")) -import editor_python_test_tools.hydra_editor_utils as hydra -from editor_python_test_tools.editor_test_helper import EditorTestHelper - - -class TestDebuggerDebugCVarsWorks(EditorTestHelper): - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="Debugger_DebugCVarsWorks", args=["level"]) - - def run_test(self): - """ - Summary: - C2789148 Vegetation Debug CVars are enabled when the Debugger component is present - - Expected Result: - The following commands are available in the Editor only when the Vegetation Debugger Level component is present: - veg_debugDumpReport (Command) - veg_debugRefreshAllAreas (Command) - - :return: None - """ - - # Create empty level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=1024, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=4096, - use_terrain=False, - ) - - # Initially run the command in console without Debugger component - general.run_console("veg_debugDumpReport") - - # Add the Vegetation Debugger component to the Level Inspector - hydra.add_level_component("Vegetation Debugger") - - # Run a command again after adding the Vegetation debugger - general.run_console("veg_debugRefreshAllAreas") - - -test = TestDebuggerDebugCVarsWorks() -test.run() diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_Debugger.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_Debugger.py deleted file mode 100755 index ed979136e0..0000000000 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_Debugger.py +++ /dev/null @@ -1,56 +0,0 @@ -""" -Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - -SPDX-License-Identifier: Apache-2.0 OR MIT -""" - -import os -import pytest -import logging - -# Bail on the test if ly_test_tools doesn't exist. -pytest.importorskip("ly_test_tools") -import ly_test_tools.environment.file_system as file_system -import editor_python_test_tools.hydra_test_utils as hydra - -logger = logging.getLogger(__name__) -test_directory = os.path.join(os.path.dirname(__file__), "EditorScripts") - - -@pytest.mark.parametrize("project", ["AutomatedTesting"]) -@pytest.mark.parametrize("level", ["tmp_level"]) -@pytest.mark.usefixtures("automatic_process_killer") -@pytest.mark.parametrize("launcher_platform", ['windows_editor']) -class TestDebugger(object): - @pytest.fixture(autouse=True) - def setup_teardown(self, request, workspace, project, level): - # Cleanup our temp level - file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True) - - def teardown(): - # Cleanup our temp level - file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True) - - request.addfinalizer(teardown) - - @pytest.mark.test_case_id("C2789148") - @pytest.mark.SUITE_periodic - @pytest.mark.dynveg_misc - def test_Debugger_DebugCVarsWork(self, request, editor, level, workspace, launcher_platform): - cfg_args = [level] - - expected_lines = [ - "Debugger_DebugCVarsWorks: test started", - "[Warning] Unknown command: veg_debugDumpReport", - "[CONSOLE] Executing console command 'veg_debugRefreshAllAreas'", - "Debugger_DebugCVarsWorks: result=SUCCESS", - ] - - hydra.launch_and_validate_results( - request, - test_directory, - editor, - "Debugger_DebugCVarsWorks.py", - expected_lines=expected_lines, - cfg_args=cfg_args - ) From 7ebdde0be01477ba036bad7f5a1e36ae50e2d879 Mon Sep 17 00:00:00 2001 From: jckand-amzn Date: Wed, 21 Jul 2021 10:25:48 -0500 Subject: [PATCH 08/12] Adding xfail mark to test_LandscapeCanvas_GraphClosed_OnEntityDelete Signed-off-by: jckand-amzn --- .../landscape_canvas/test_GeneralGraphFunctionality.py | 1 + 1 file changed, 1 insertion(+) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/test_GeneralGraphFunctionality.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/test_GeneralGraphFunctionality.py index bbca71461c..e2aa222c3f 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/test_GeneralGraphFunctionality.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/test_GeneralGraphFunctionality.py @@ -104,6 +104,7 @@ class TestGeneralGraphFunctionality(object): @pytest.mark.test_case_id("C17488412") @pytest.mark.SUITE_periodic + @pytest.mark.xfail(reason="https://github.com/o3de/o3de/issues/2201") def test_LandscapeCanvas_GraphClosed_OnEntityDelete(self, request, editor, level, launcher_platform): cfg_args = [level] From fc1ccb9e8574a1d997bbc791fb46a6a1325ee3a2 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Wed, 21 Jul 2021 17:17:09 -0700 Subject: [PATCH 09/12] Issues/2126 PhysX Gem can't be used as build dependency in engine SDK Part (#2337) * Applying GENEX_EVAL to 2 cases where the genex can produce another genex Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> * Missing case when the folder is an external one to the engine/project (e.g. external gems) Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- Code/LauncherUnified/launcher_generator.cmake | 4 ++-- cmake/LYWrappers.cmake | 15 ++++++++++----- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/Code/LauncherUnified/launcher_generator.cmake b/Code/LauncherUnified/launcher_generator.cmake index 628b5fffac..28fddad1eb 100644 --- a/Code/LauncherUnified/launcher_generator.cmake +++ b/Code/LauncherUnified/launcher_generator.cmake @@ -40,9 +40,9 @@ foreach(project_name project_path IN ZIP_LISTS LY_PROJECTS_TARGET_NAME LY_PROJEC add_custom_target(${project_name}.Assets COMMENT "Processing ${project_name} assets..." COMMAND "${CMAKE_COMMAND}" - -DLY_LOCK_FILE=$/project_assets.lock + -DLY_LOCK_FILE=$>/project_assets.lock -P ${LY_ROOT_FOLDER}/cmake/CommandExecution.cmake - EXEC_COMMAND $ + EXEC_COMMAND $> --zeroAnalysisMode --project-path=${project_real_path} --platforms=${LY_ASSET_DEPLOY_ASSET_TYPE} diff --git a/cmake/LYWrappers.cmake b/cmake/LYWrappers.cmake index 40bf6ef541..cfe6df5c81 100644 --- a/cmake/LYWrappers.cmake +++ b/cmake/LYWrappers.cmake @@ -391,10 +391,10 @@ function(ly_delayed_target_link_libraries) endif() if(item_type STREQUAL MODULE_LIBRARY) - target_include_directories(${target} ${visibility} $) - target_link_libraries(${target} ${visibility} $) - target_compile_definitions(${target} ${visibility} $) - target_compile_options(${target} ${visibility} $) + target_include_directories(${target} ${visibility} $>) + target_link_libraries(${target} ${visibility} $>) + target_compile_definitions(${target} ${visibility} $>) + target_compile_options(${target} ${visibility} $>) else() ly_parse_third_party_dependencies(${item}) target_link_libraries(${target} ${visibility} ${item}) @@ -659,7 +659,12 @@ function(ly_get_vs_folder_directory absolute_target_source_dir output_source_dir if(is_target_prefix_of_engine_root) cmake_path(RELATIVE_PATH absolute_target_source_dir BASE_DIRECTORY ${LY_ROOT_FOLDER} OUTPUT_VARIABLE relative_target_source_dir) else() - cmake_path(GET absolute_target_source_dir RELATIVE_PART relative_target_source_dir) + cmake_path(IS_PREFIX CMAKE_SOURCE_DIR ${absolute_target_source_dir} is_target_prefix_of_source_dir) + if(is_target_prefix_of_source_dir) + cmake_path(RELATIVE_PATH absolute_target_source_dir BASE_DIRECTORY ${CMAKE_SOURCE_DIR} OUTPUT_VARIABLE relative_target_source_dir) + else() + cmake_path(GET absolute_target_source_dir RELATIVE_PART relative_target_source_dir) + endif() endif() set(${output_source_dir} ${relative_target_source_dir} PARENT_SCOPE) From 26c9853ff9916b7216a5e01eef6b9f7be8bb4df1 Mon Sep 17 00:00:00 2001 From: moraaar Date: Tue, 27 Jul 2021 09:11:28 +0100 Subject: [PATCH 10/12] Fixed cloth tangent generation (#2440) - The output vectors were not properly filled with zeros when they already had the expected size. - The tolerance was too large and was causing patches while computing tangents and bitangents. - The handedness was inverted to what is expected in the shader (which always inverts tangent's w). Signed-off-by: moraaar --- .../ClothComponentMesh/ClothComponentMesh.cpp | 2 +- .../Code/Source/System/TangentSpaceHelper.cpp | 20 ++++++++++++------- .../ClothConstraintsTest.cpp | 12 ++++++++--- 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/Gems/NvCloth/Code/Source/Components/ClothComponentMesh/ClothComponentMesh.cpp b/Gems/NvCloth/Code/Source/Components/ClothComponentMesh/ClothComponentMesh.cpp index b791e8a543..7e0ac2f230 100644 --- a/Gems/NvCloth/Code/Source/Components/ClothComponentMesh/ClothComponentMesh.cpp +++ b/Gems/NvCloth/Code/Source/Components/ClothComponentMesh/ClothComponentMesh.cpp @@ -577,7 +577,7 @@ namespace NvCloth const AZ::Vector3& renderTangent = renderTangents[renderVertexIndex]; destTangentsBuffer[index].Set( renderTangent, - 1.0f); + -1.0f); // Shader function ConstructTBN inverts w to change bitangent sign, but the bitangents passed are already corrected, so passing -1.0 to counteract. } if (destBitangentsBuffer) diff --git a/Gems/NvCloth/Code/Source/System/TangentSpaceHelper.cpp b/Gems/NvCloth/Code/Source/System/TangentSpaceHelper.cpp index b43ad1923b..e388643c00 100644 --- a/Gems/NvCloth/Code/Source/System/TangentSpaceHelper.cpp +++ b/Gems/NvCloth/Code/Source/System/TangentSpaceHelper.cpp @@ -11,7 +11,7 @@ namespace NvCloth { namespace { - const float Tolerance = 0.0001f; + const float Tolerance = 1e-7f; } bool TangentSpaceHelper::CalculateNormals( @@ -33,7 +33,8 @@ namespace NvCloth const size_t vertexCount = vertices.size(); // Reset results - outNormals.resize(vertexCount, AZ::Vector3::CreateZero()); + outNormals.resize(vertexCount); + AZStd::fill(outNormals.begin(), outNormals.end(), AZ::Vector3::CreateZero()); // calculate the normals per triangle for (size_t i = 0; i < triangleCount; ++i) @@ -114,8 +115,10 @@ namespace NvCloth const size_t vertexCount = vertices.size(); // Reset results - outTangents.resize(vertexCount, AZ::Vector3::CreateZero()); - outBitangents.resize(vertexCount, AZ::Vector3::CreateZero()); + outTangents.resize(vertexCount); + outBitangents.resize(vertexCount); + AZStd::fill(outTangents.begin(), outTangents.end(), AZ::Vector3::CreateZero()); + AZStd::fill(outBitangents.begin(), outBitangents.end(), AZ::Vector3::CreateZero()); // calculate the base vectors per triangle for (size_t i = 0; i < triangleCount; ++i) @@ -192,9 +195,12 @@ namespace NvCloth const size_t vertexCount = vertices.size(); // Reset results - outTangents.resize(vertexCount, AZ::Vector3::CreateZero()); - outBitangents.resize(vertexCount, AZ::Vector3::CreateZero()); - outNormals.resize(vertexCount, AZ::Vector3::CreateZero()); + outTangents.resize(vertexCount); + outBitangents.resize(vertexCount); + outNormals.resize(vertexCount); + AZStd::fill(outTangents.begin(), outTangents.end(), AZ::Vector3::CreateZero()); + AZStd::fill(outBitangents.begin(), outBitangents.end(), AZ::Vector3::CreateZero()); + AZStd::fill(outNormals.begin(), outNormals.end(), AZ::Vector3::CreateZero()); // calculate the base vectors per triangle for (size_t i = 0; i < triangleCount; ++i) diff --git a/Gems/NvCloth/Code/Tests/Components/ClothComponentMesh/ClothConstraintsTest.cpp b/Gems/NvCloth/Code/Tests/Components/ClothComponentMesh/ClothConstraintsTest.cpp index 5f390ed45d..50ca5c17cd 100644 --- a/Gems/NvCloth/Code/Tests/Components/ClothComponentMesh/ClothConstraintsTest.cpp +++ b/Gems/NvCloth/Code/Tests/Components/ClothComponentMesh/ClothConstraintsTest.cpp @@ -124,6 +124,9 @@ namespace UnitTest const AZStd::vector& motionConstraints = clothConstraints->GetMotionConstraints(); EXPECT_TRUE(motionConstraints.size() == SimulationParticles.size()); + EXPECT_THAT(motionConstraints[0].GetAsVector3(), IsCloseTolerance(SimulationParticles[0].GetAsVector3(), Tolerance)); + EXPECT_THAT(motionConstraints[1].GetAsVector3(), IsCloseTolerance(SimulationParticles[1].GetAsVector3(), Tolerance)); + EXPECT_THAT(motionConstraints[2].GetAsVector3(), IsCloseTolerance(SimulationParticles[2].GetAsVector3(), Tolerance)); EXPECT_NEAR(motionConstraints[0].GetW(), 6.0f, Tolerance); EXPECT_NEAR(motionConstraints[1].GetW(), 0.0f, Tolerance); EXPECT_NEAR(motionConstraints[2].GetW(), 0.0f, Tolerance); @@ -277,6 +280,9 @@ namespace UnitTest const AZStd::vector& separationConstraints = clothConstraints->GetSeparationConstraints(); EXPECT_TRUE(motionConstraints.size() == newParticles.size()); + EXPECT_THAT(motionConstraints[0].GetAsVector3(), IsCloseTolerance(newParticles[0].GetAsVector3(), Tolerance)); + EXPECT_THAT(motionConstraints[1].GetAsVector3(), IsCloseTolerance(newParticles[1].GetAsVector3(), Tolerance)); + EXPECT_THAT(motionConstraints[2].GetAsVector3(), IsCloseTolerance(newParticles[2].GetAsVector3(), Tolerance)); EXPECT_NEAR(motionConstraints[0].GetW(), 3.0f, Tolerance); EXPECT_NEAR(motionConstraints[1].GetW(), 1.5f, Tolerance); EXPECT_NEAR(motionConstraints[2].GetW(), 0.0f, Tolerance); @@ -285,8 +291,8 @@ namespace UnitTest EXPECT_NEAR(separationConstraints[0].GetW(), 3.0f, Tolerance); EXPECT_NEAR(separationConstraints[1].GetW(), 1.5f, Tolerance); EXPECT_NEAR(separationConstraints[2].GetW(), 0.3f, Tolerance); - EXPECT_THAT(separationConstraints[0].GetAsVector3(), IsCloseTolerance(AZ::Vector3(-3.03902f, 2.80752f, 3.80752f), Tolerance)); - EXPECT_THAT(separationConstraints[1].GetAsVector3(), IsCloseTolerance(AZ::Vector3(-1.41659f, 0.651243f, -0.348757f), Tolerance)); - EXPECT_THAT(separationConstraints[2].GetAsVector3(), IsCloseTolerance(AZ::Vector3(6.15313f, -0.876132f, 0.123868f), Tolerance)); + EXPECT_THAT(separationConstraints[0].GetAsVector3(), IsCloseTolerance(AZ::Vector3(0.0f, 3.53553f, 4.53553f), Tolerance)); + EXPECT_THAT(separationConstraints[1].GetAsVector3(), IsCloseTolerance(AZ::Vector3(0.0f, 2.06066f, 1.06066f), Tolerance)); + EXPECT_THAT(separationConstraints[2].GetAsVector3(), IsCloseTolerance(AZ::Vector3(1.0f, -3.74767f, -2.74767f), Tolerance)); } } // namespace UnitTest From 902bdeb6d6092d0b88066fbb873eaa043c3b788a Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Thu, 29 Jul 2021 16:50:50 -0700 Subject: [PATCH 11/12] Create RUN target as helpers for the project-centric workflow (#2520) (#2635) * Create RUN target as helpers for the project-centric workflow Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> * typo fix Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> * rename target as ".Imported" and create "" as the metatarget that is used for debugging and building in o3de Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- Code/Editor/CMakeLists.txt | 2 + cmake/Platform/Common/Install_common.cmake | 43 ++++++++++++++++++---- cmake/SettingsRegistry.cmake | 7 +--- cmake/install/InstalledTarget.in | 2 + 4 files changed, 42 insertions(+), 12 deletions(-) diff --git a/Code/Editor/CMakeLists.txt b/Code/Editor/CMakeLists.txt index 5a846a267a..db6b8e958e 100644 --- a/Code/Editor/CMakeLists.txt +++ b/Code/Editor/CMakeLists.txt @@ -163,6 +163,8 @@ ly_add_target( editor_files.cmake PLATFORM_INCLUDE_FILES Platform/${PAL_PLATFORM_NAME}/editor_${PAL_PLATFORM_NAME_LOWERCASE}.cmake + TARGET_PROPERTIES + LY_INSTALL_GENERATE_RUN_TARGET TRUE BUILD_DEPENDENCIES PRIVATE 3rdParty::Qt::Core diff --git a/cmake/Platform/Common/Install_common.cmake b/cmake/Platform/Common/Install_common.cmake index 1ac59ee83f..8058fb5908 100644 --- a/cmake/Platform/Common/Install_common.cmake +++ b/cmake/Platform/Common/Install_common.cmake @@ -9,6 +9,15 @@ include(cmake/FileUtil.cmake) set(CMAKE_INSTALL_MESSAGE NEVER) # Simplify messages to reduce output noise +define_property(TARGET PROPERTY LY_INSTALL_GENERATE_RUN_TARGET + BRIEF_DOCS "Defines if a \"RUN\" targets should be created when installing this target Gem" + FULL_DOCS [[ + Property which is set on targets that should generate a "RUN" + target when installed. This \"RUN\" target helps to run the + binary from the installed location directly from the IDE. + ]] +) + ly_set(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME Core) cmake_path(RELATIVE_PATH CMAKE_RUNTIME_OUTPUT_DIRECTORY BASE_DIRECTORY ${CMAKE_BINARY_DIR} OUTPUT_VARIABLE runtime_output_directory) @@ -105,15 +114,19 @@ function(ly_setup_target OUTPUT_CONFIGURED_TARGET ALIAS_TARGET_NAME absolute_tar set(NAMESPACE_PLACEHOLDER "") set(NAME_PLACEHOLDER ${TARGET_NAME}) endif() + get_target_property(should_create_helper ${TARGET_NAME} LY_INSTALL_GENERATE_RUN_TARGET) + if(should_create_helper) + set(NAME_PLACEHOLDER ${NAME_PLACEHOLDER}.Imported) + endif() set(TARGET_TYPE_PLACEHOLDER "") - get_target_property(target_type ${NAME_PLACEHOLDER} TYPE) + get_target_property(target_type ${TARGET_NAME} TYPE) # Remove the _LIBRARY since we dont need to pass that to ly_add_targets string(REPLACE "_LIBRARY" "" TARGET_TYPE_PLACEHOLDER ${target_type}) # For HEADER_ONLY libs we end up generating "INTERFACE" libraries, need to specify HEADERONLY instead string(REPLACE "INTERFACE" "HEADERONLY" TARGET_TYPE_PLACEHOLDER ${TARGET_TYPE_PLACEHOLDER}) if(TARGET_TYPE_PLACEHOLDER STREQUAL "MODULE") - get_target_property(gem_module ${NAME_PLACEHOLDER} GEM_MODULE) + get_target_property(gem_module ${TARGET_NAME} GEM_MODULE) if(gem_module) set(TARGET_TYPE_PLACEHOLDER "GEM_MODULE") endif() @@ -146,7 +159,6 @@ function(ly_setup_target OUTPUT_CONFIGURED_TARGET ALIAS_TARGET_NAME absolute_tar unset(RUNTIME_DEPENDENCIES_PLACEHOLDER) endif() - get_target_property(inteface_build_dependencies_props ${TARGET_NAME} INTERFACE_LINK_LIBRARIES) unset(INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER) if(inteface_build_dependencies_props) @@ -170,6 +182,23 @@ function(ly_setup_target OUTPUT_CONFIGURED_TARGET ALIAS_TARGET_NAME absolute_tar list(REMOVE_DUPLICATES INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER) string(REPLACE ";" "\n" INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER "${INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER}") + # If the target is an executable/application, add a custom target so we can debug the target in project-centric workflow + if(should_create_helper) + string(REPLACE ".Imported" "" RUN_TARGET_NAME ${NAME_PLACEHOLDER}) + set(target_types_with_debugging_helper EXECUTABLE APPLICATION) + if(NOT target_type IN_LIST target_types_with_debugging_helper) + message(FATAL_ERROR "Cannot generate a RUN target for ${TARGET_NAME}, type is ${target_type}") + endif() + set(TARGET_RUN_HELPER +"add_custom_target(${RUN_TARGET_NAME}) +set_target_properties(${RUN_TARGET_NAME} PROPERTIES + FOLDER \"CMakePredefinedTargets/SDK\" + VS_DEBUGGER_COMMAND \$> + VS_DEBUGGER_COMMAND_ARGUMENTS \"--project-path=\${LY_DEFAULT_PROJECT_PATH}\" +)" +) + endif() + # Config file set(target_file_contents "# Generated by O3DE install\n\n") if(NOT target_type STREQUAL INTERFACE_LIBRARY) @@ -182,13 +211,13 @@ function(ly_setup_target OUTPUT_CONFIGURED_TARGET ALIAS_TARGET_NAME absolute_tar set(target_location "\${LY_ROOT_FOLDER}/${library_output_directory}/${PAL_PLATFORM_NAME}/$/${target_library_output_subdirectory}/$") elseif(target_type STREQUAL SHARED_LIBRARY) string(APPEND target_file_contents -"set_property(TARGET ${TARGET_NAME} +"set_property(TARGET ${NAME_PLACEHOLDER} APPEND_STRING PROPERTY IMPORTED_IMPLIB $<$$:\"\${LY_ROOT_FOLDER}/${archive_output_directory}/${PAL_PLATFORM_NAME}/$/$\"$ ) ") string(APPEND target_file_contents -"set_property(TARGET ${TARGET_NAME} +"set_property(TARGET ${NAME_PLACEHOLDER} PROPERTY IMPORTED_IMPLIB_$> \"\${LY_ROOT_FOLDER}/${archive_output_directory}/${PAL_PLATFORM_NAME}/$/$\" ) @@ -200,11 +229,11 @@ function(ly_setup_target OUTPUT_CONFIGURED_TARGET ALIAS_TARGET_NAME absolute_tar if(target_location) string(APPEND target_file_contents -"set_property(TARGET ${TARGET_NAME} +"set_property(TARGET ${NAME_PLACEHOLDER} APPEND_STRING PROPERTY IMPORTED_LOCATION $<$$:${target_location}$ ) -set_property(TARGET ${TARGET_NAME} +set_property(TARGET ${NAME_PLACEHOLDER} PROPERTY IMPORTED_LOCATION_$> ${target_location} ) diff --git a/cmake/SettingsRegistry.cmake b/cmake/SettingsRegistry.cmake index 934bae4e30..a1e6de73f8 100644 --- a/cmake/SettingsRegistry.cmake +++ b/cmake/SettingsRegistry.cmake @@ -158,10 +158,6 @@ function(ly_delayed_generate_settings_registry) message(FATAL_ERROR "Dependency ${gem_target} from ${target} does not exist") endif() - get_property(has_manually_added_dependencies TARGET ${gem_target} PROPERTY MANUALLY_ADDED_DEPENDENCIES SET) - get_target_property(target_type ${gem_target} TYPE) - - ly_get_gem_module_root(gem_module_root ${gem_target}) file(RELATIVE_PATH gem_module_root_relative_to_engine_root ${LY_ROOT_FOLDER} ${gem_module_root}) @@ -179,7 +175,8 @@ function(ly_delayed_generate_settings_registry) list(JOIN target_gem_dependencies_names ",\n" target_gem_dependencies_names) string(CONFIGURE ${gems_json_template} gem_json @ONLY) get_target_property(is_imported ${target} IMPORTED) - if(is_imported) + get_target_property(target_type ${target} TYPE) + if(is_imported OR target_type STREQUAL UTILITY) unset(target_dir) foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES) string(TOUPPER ${conf} UCONF) diff --git a/cmake/install/InstalledTarget.in b/cmake/install/InstalledTarget.in index 0503fd5f2b..a4f4fa4763 100644 --- a/cmake/install/InstalledTarget.in +++ b/cmake/install/InstalledTarget.in @@ -17,6 +17,8 @@ ly_add_target( @RUNTIME_DEPENDENCIES_PLACEHOLDER@ ) +@TARGET_RUN_HELPER@ + set(configs @CMAKE_CONFIGURATION_TYPES@) foreach(config ${configs}) include("@NAME_PLACEHOLDER@_${config}.cmake" OPTIONAL) From 4b817a6483560691a5f95a34355c87c8972b05ab Mon Sep 17 00:00:00 2001 From: Shirang Jia Date: Wed, 4 Aug 2021 17:57:47 -0700 Subject: [PATCH 12/12] Include build failure root cause in email notification (#2491) Signed-off-by: shiranj --- scripts/build/Jenkins/Jenkinsfile | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/scripts/build/Jenkins/Jenkinsfile b/scripts/build/Jenkins/Jenkinsfile index 70618fea78..e693168af0 100644 --- a/scripts/build/Jenkins/Jenkinsfile +++ b/scripts/build/Jenkins/Jenkinsfile @@ -577,13 +577,19 @@ finally { ) } node('controller') { - step([ - $class: 'Mailer', - notifyEveryUnstableBuild: true, - recipients: emailextrecipients([ + if("${currentBuild.currentResult}" == "SUCCESS") { + emailBody = "${BUILD_URL}\nSuccess!" + } else { + buildFailure = tm('${BUILD_FAILURE_ANALYZER}') + emailBody = "${BUILD_URL}\n${buildFailure}!" + } + emailext ( + body: "${emailBody}", + subject: "${currentBuild.currentResult}: ${JOB_NAME} - Build # ${BUILD_NUMBER}", + recipientProviders: [ [$class: 'RequesterRecipientProvider'] - ]) - ]) + ] + ) } } catch(Exception e) { }