Integrating latest from github/staging
Integrating up through commit 5e1bdae
This commit is contained in:
@@ -11,65 +11,29 @@
|
||||
*/
|
||||
|
||||
#include <AzFramework/ProjectManager/ProjectManager.h>
|
||||
#include <AzFramework/Engine/Engine.h>
|
||||
|
||||
#include <AzCore/Platform.h>
|
||||
#include <AzCore/Settings/CommandLine.h>
|
||||
#include <AzCore/IO/SystemFile.h>
|
||||
#include <AzCore/Settings/SettingsRegistry.h>
|
||||
#include <AzCore/Settings/SettingsRegistryImpl.h>
|
||||
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
|
||||
#include <AzCore/Utils/Utils.h>
|
||||
|
||||
#include <AzFramework/AzFramework_Traits_Platform.h>
|
||||
#include <AzFramework/Process/ProcessWatcher.h>
|
||||
#include <AzFramework/Engine/Engine.h>
|
||||
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
namespace ProjectManager
|
||||
{
|
||||
// Check if any project path appears to have been provided on the command line
|
||||
bool HasCommandLineProjectName(const int argc, char* argv[])
|
||||
{
|
||||
constexpr int numOptionPrefixes = 3;
|
||||
static const char* optionPrefixes[numOptionPrefixes] = { "/", "--", "-" };
|
||||
constexpr int numOptionNames = 2;
|
||||
static const char* optionNames[numOptionNames] = { "projectpath", R"(regset="/Amazon/AzCore/Bootstrap/sys_game_folder)" };
|
||||
for (int i = 1; i < argc; ++i)
|
||||
{
|
||||
int thisPrefix = 0;
|
||||
for (; thisPrefix < numOptionPrefixes; ++thisPrefix)
|
||||
{
|
||||
if (strncmp(argv[i], optionPrefixes[thisPrefix], strlen(optionPrefixes[thisPrefix])) == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
// If the argument doesn't start with any of our switch start parameters, this isn't an argument giving us a project
|
||||
if (thisPrefix == numOptionPrefixes)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// We compare the portion of the string after our prefix
|
||||
int startIndex = strlen(optionPrefixes[thisPrefix]);
|
||||
// If the whole argument was just one of the prefixes, this also isn't what we were looking for
|
||||
if (startIndex == strlen(argv[i]))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
int switchNum = 0;
|
||||
for (; switchNum < numOptionNames; ++switchNum)
|
||||
{
|
||||
// Start the string comparison at startIndex for each string - after the option indicator
|
||||
if (azstrnicmp(&argv[i][startIndex], optionNames[switchNum], strlen(optionNames[switchNum])) == 0)
|
||||
{
|
||||
int expectedOptionLength = strlen(optionNames[switchNum]) + startIndex;
|
||||
// The option is what we're looking for if it had a space after it (it was the whole argument) or it has an equals next
|
||||
if (strlen(argv[i]) == (expectedOptionLength) || ((strlen(argv[i]) > expectedOptionLength ) && argv[i][expectedOptionLength] == '='))
|
||||
{
|
||||
// We found one of the acceptable arguments
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// Check for a project name, if not found, attempt to launch project manager and shut down
|
||||
ProjectPathCheckResult CheckProjectPathProvided(const int argc, char* argv[])
|
||||
{
|
||||
// If we were able to locate a path to a project, we're done
|
||||
if (HasProjectName(argc, argv))
|
||||
if (HasProjectPath(argc, argv))
|
||||
{
|
||||
return ProjectPathCheckResult::ProjectPathFound;
|
||||
}
|
||||
@@ -83,142 +47,88 @@ namespace AzFramework
|
||||
return ProjectPathCheckResult::ProjectManagerLaunchFailed;
|
||||
}
|
||||
|
||||
bool HasProjectPath(const int argc, char* argv[])
|
||||
{
|
||||
bool hasProjectPath = false;
|
||||
bool ownsAllocator = false;
|
||||
if (!AZ::AllocatorInstance<AZ::SystemAllocator>::IsReady())
|
||||
{
|
||||
AZ::AllocatorInstance<AZ::SystemAllocator>::Create();
|
||||
ownsAllocator = true;
|
||||
}
|
||||
{
|
||||
AZ::CommandLine commandLine;
|
||||
commandLine.Parse(argc, argv);
|
||||
AZ::SettingsRegistryImpl settingsRegistry;
|
||||
AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_Bootstrap(settingsRegistry);
|
||||
AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(settingsRegistry, commandLine, false);
|
||||
auto sysGameFolderKey = AZ::SettingsRegistryInterface::FixedValueString(
|
||||
AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey) + "/project_path";
|
||||
AZ::IO::FixedMaxPath registryPath;
|
||||
hasProjectPath = settingsRegistry.Get(registryPath.Native(), sysGameFolderKey);
|
||||
}
|
||||
if (ownsAllocator)
|
||||
{
|
||||
AZ::AllocatorInstance<AZ::SystemAllocator>::Destroy();
|
||||
}
|
||||
return hasProjectPath;
|
||||
}
|
||||
|
||||
bool LaunchProjectManager()
|
||||
{
|
||||
bool launchSuccess = false;
|
||||
#if (AZ_TRAIT_AZFRAMEWORK_USE_PROJECT_MANAGER)
|
||||
bool ownsSystemAllocator = false;
|
||||
if (!AZ::AllocatorInstance<AZ::SystemAllocator>::IsReady())
|
||||
{
|
||||
ownsSystemAllocator = true;
|
||||
AZ::AllocatorInstance<AZ::SystemAllocator>::Create();
|
||||
}
|
||||
{
|
||||
const char projectsScript[] = "projects.py";
|
||||
|
||||
AZ_Warning("ProjectManager", false, "No project provided - launching project selector.");
|
||||
|
||||
AZ::IO::FixedMaxPath enginePath = Engine::FindEngineRoot();
|
||||
if (enginePath.empty())
|
||||
{
|
||||
AZ_Error("ProjectManager", false, "Couldn't find engine root");
|
||||
return false;
|
||||
}
|
||||
auto projectManagerPath = enginePath / "scripts" / "project_manager";
|
||||
|
||||
if (!AZ::IO::SystemFile::Exists((projectManagerPath / projectsScript).c_str()))
|
||||
{
|
||||
AZ_Error("ProjectManager", false, "%s not found at %s!", projectsScript, projectManagerPath.c_str());
|
||||
return false;
|
||||
}
|
||||
char executablePath[AZ_MAX_PATH_LEN];
|
||||
AZ::Utils::GetExecutablePathReturnType result = AZ::Utils::GetExecutablePath(executablePath, AZ_MAX_PATH_LEN);
|
||||
auto exeFolder = AZ::IO::PathView(executablePath).ParentPath().Filename().Native();
|
||||
AZStd::fixed_string<8> debugOption;
|
||||
if (exeFolder == "debug")
|
||||
{
|
||||
// We need to use the debug version of the python interpreter to load up our debug version of our libraries which work with the debug version of QT living in this folder
|
||||
debugOption = "debug ";
|
||||
}
|
||||
AZ::IO::FixedMaxPath pythonPath = enginePath / "python";
|
||||
pythonPath /= AZ_TRAIT_AZFRAMEWORK_PYTHON_SHELL;
|
||||
auto cmdPath = AZ::IO::FixedMaxPathString::format("%s %s%s --executable_path=%s --parent_pid=%" PRId64, pythonPath.Native().c_str(),
|
||||
debugOption.c_str(), (projectManagerPath / projectsScript).c_str(), executablePath, AZ::Platform::GetCurrentProcessId());
|
||||
|
||||
AzFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo;
|
||||
|
||||
processLaunchInfo.m_commandlineParameters = cmdPath;
|
||||
processLaunchInfo.m_showWindow = false;
|
||||
launchSuccess = AzFramework::ProcessLauncher::LaunchUnwatchedProcess(processLaunchInfo);
|
||||
}
|
||||
if(ownsSystemAllocator)
|
||||
{
|
||||
AZ::AllocatorInstance<AZ::SystemAllocator>::Destroy();
|
||||
}
|
||||
#endif // #if defined(AZ_FRAMEWORK_USE_PROJECT_MANAGER)
|
||||
return launchSuccess;
|
||||
}
|
||||
} // ProjectManager
|
||||
|
||||
bool ProjectManager::HasProjectName(const int argc, char* argv[])
|
||||
{
|
||||
return HasCommandLineProjectName(argc, argv) || HasBootstrapProjectName();
|
||||
}
|
||||
|
||||
// This is a transition method until all projects/tests/etc have been converted to expect and use the projectpath parameter
|
||||
// If bootstrap.cfg exists and has a valid project name we should assume we're launching using it
|
||||
// After that time it can be removed
|
||||
bool ProjectManager::HasBootstrapProjectName(AZStd::string_view projectFolder)
|
||||
{
|
||||
AZ::IO::FixedMaxPath enginePath = Engine::FindEngineRoot(projectFolder);
|
||||
if (enginePath.empty())
|
||||
{
|
||||
AZ_Warning("ProjectManager", false, "Couldn't find engine root");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto bootstrapPath = enginePath / "bootstrap.cfg";
|
||||
|
||||
if (!AZ::IO::SystemFile::Exists(bootstrapPath.c_str()))
|
||||
{
|
||||
AZ_Warning("ProjectManager", false, "No bootstrap file found at %s", bootstrapPath.c_str());
|
||||
return false;
|
||||
}
|
||||
AZStd::fixed_string< MaxBootstrapFileSize> bootstrapString;
|
||||
auto fileSize = AZ::IO::SystemFile::Length(bootstrapPath.c_str());
|
||||
if (fileSize >= MaxBootstrapFileSize)
|
||||
{
|
||||
AZ_Warning("ProjectManager", false, "Bootstrap read size at %s is %zu", bootstrapPath.c_str(), fileSize);
|
||||
bootstrapString.resize_no_construct(MaxBootstrapFileSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
bootstrapString.resize_no_construct(fileSize);
|
||||
}
|
||||
AZ::IO::SystemFile::SizeType bytesRead = AZ::IO::SystemFile::Read(bootstrapPath.c_str(), bootstrapString.data(), MaxBootstrapFileSize - 1);
|
||||
if (bytesRead == (MaxBootstrapFileSize - 1))
|
||||
{
|
||||
AZ_Warning("ProjectManager", false, "Bootstrap read size at %s was %zu", bootstrapPath.c_str(), bytesRead);
|
||||
}
|
||||
if (!ContentHasProjectName(bootstrapString))
|
||||
{
|
||||
AZ_TracePrintf("ProjectManager", "Bootstrap at %s did not contain project name", bootstrapPath.c_str());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// This is a transition method until all projects/tests/etc have been converted to expect and use the projectpath parameter
|
||||
// If bootstrap.cfg exists and has a valid project name we should assume we're launching using it
|
||||
// After that time it can be removed
|
||||
bool ProjectManager::ContentHasProjectName(AZStd::fixed_string< MaxBootstrapFileSize>& bootstrapString)
|
||||
{
|
||||
static const char* const projectKey = "sys_game_folder";
|
||||
size_t searchStart = bootstrapString.find(projectKey);
|
||||
while (searchStart != bootstrapString.npos)
|
||||
{
|
||||
// Once we've found the key we need to search the line forward and backwards. Commented out lines shouldn't count
|
||||
// and if there's no value after the equals then it's also not set
|
||||
auto checkPos = searchStart;
|
||||
// We're at the start already if this is position 0
|
||||
bool foundLineStart = checkPos == 0;
|
||||
if (checkPos)
|
||||
{
|
||||
--checkPos;
|
||||
}
|
||||
while (checkPos > 0 && bootstrapString[checkPos] != '-')
|
||||
{
|
||||
if (bootstrapString[checkPos] == '\n')
|
||||
{
|
||||
// Looks like a valid key
|
||||
foundLineStart = true;
|
||||
break;
|
||||
}
|
||||
if (!std::isspace(bootstrapString[checkPos]))
|
||||
{
|
||||
// This appears to be some other character appearing before our key, this isn't valid
|
||||
break;
|
||||
}
|
||||
--checkPos;
|
||||
}
|
||||
if (!foundLineStart)
|
||||
{
|
||||
// Commented line or other content preceding our key, keep searching
|
||||
searchStart = bootstrapString.find(projectKey, searchStart + 1);
|
||||
continue;
|
||||
}
|
||||
checkPos = searchStart + strlen(projectKey);
|
||||
bool foundEquals = false;
|
||||
while (checkPos < bootstrapString.length())
|
||||
{
|
||||
if (bootstrapString[checkPos] == '\n')
|
||||
{
|
||||
// We've reached the end of the line and didn't find anything that seems to be a value for our key
|
||||
break;
|
||||
}
|
||||
if (std::isspace(bootstrapString[checkPos]))
|
||||
{
|
||||
// Whitespace - keep searching back
|
||||
++checkPos;
|
||||
continue;
|
||||
}
|
||||
if (bootstrapString[checkPos] == '=')
|
||||
{
|
||||
foundEquals = true;
|
||||
++checkPos;
|
||||
continue;
|
||||
}
|
||||
if (foundEquals)
|
||||
{
|
||||
auto nameEnd = bootstrapString.find_first_of(" \n", checkPos);
|
||||
if (nameEnd == bootstrapString.npos)
|
||||
{
|
||||
// End of content, this is valid
|
||||
nameEnd = bootstrapString.length();
|
||||
}
|
||||
constexpr size_t nameMax = 100;
|
||||
if (nameEnd - checkPos > nameMax)
|
||||
{
|
||||
AZ_Warning("ProjectManager", false, "Project name exceeded %zu characters (%zu)", nameMax, nameEnd - checkPos);
|
||||
return false;
|
||||
}
|
||||
AZStd::fixed_string<nameMax + 1> projectName(&bootstrapString[checkPos], nameEnd - checkPos);
|
||||
AZ_TracePrintf("ProjectManager", "Found project name of %s", projectName.c_str());
|
||||
// This is not a space, we've found our key, and we've found some sort of non space entry, we count this as "it looks like we have a value entered"
|
||||
return true;
|
||||
}
|
||||
// there was some other content on this line after our key before the equals that was not a space, this isn't our key
|
||||
searchStart = bootstrapString.find(projectKey, searchStart + 1);
|
||||
break;
|
||||
}
|
||||
searchStart = bootstrapString.find(projectKey, searchStart + 1);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} // AzFramework
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace AzFramework
|
||||
constexpr AZ::IO::SystemFile::SizeType MaxBootstrapFileSize = 1024 * 10;
|
||||
|
||||
// Check if any project name can be found anywhere
|
||||
bool HasProjectName(const int argc, char* argv[]);
|
||||
bool HasProjectPath(const int argc, char* argv[]);
|
||||
// Check if any project name can be found on the command line
|
||||
bool HasCommandLineProjectName(const int argc, char* argv[]);
|
||||
// Check if a relative project is being used through bootstrap
|
||||
|
||||
Reference in New Issue
Block a user