Process launcher updates (#6183)
* Enable process and ap connection tests on linux * Updated 'OpenProjectManager' to use new the ProcessLauncher argument type * Add logic to double-escape escaped double quotes in arguments on windows platforms * Updated argument for LaunchProjectManager to reflect new ProcessLauncher argument type * Fixed unit test arguments for 'arg=value' condition * Fix compile errors for BuilderManager and RHI.Edit\Utils.cpp * PAL'ify the GetCommandLineParametersAsString() to handle windows specific behavior Signed-off-by: Steve Pham <82231385+spham-amzn@users.noreply.github.com> Co-authored-by: byrcolin <byrcolin@amazon.com>
This commit is contained in:
+20
-1
@@ -6,10 +6,10 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/StringFunc/StringFunc.h>
|
||||
#include <AzFramework/Process/ProcessWatcher.h>
|
||||
#include <AzFramework/Process/ProcessCommunicator.h>
|
||||
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
|
||||
@@ -83,4 +83,23 @@ namespace AzFramework
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
AZStd::string ProcessLauncher::ProcessLaunchInfo::GetCommandLineParametersAsString() const
|
||||
{
|
||||
struct CommandLineParametersVisitor
|
||||
{
|
||||
AZStd::string operator()(const AZStd::string& commandLine) const
|
||||
{
|
||||
return commandLine;
|
||||
}
|
||||
|
||||
AZStd::string operator()(const AZStd::vector<AZStd::string>& commandLineArray) const
|
||||
{
|
||||
AZStd::string commandLineResult;
|
||||
AZ::StringFunc::Join(commandLineResult, commandLineArray.begin(), commandLineArray.end(), " ");
|
||||
return commandLineResult;
|
||||
}
|
||||
};
|
||||
return AZStd::visit(CommandLineParametersVisitor{}, m_commandlineParameters);
|
||||
}
|
||||
} //namespace AzFramework
|
||||
|
||||
+64
-30
@@ -10,12 +10,11 @@
|
||||
#include <AzFramework/Process/ProcessWatcher.h>
|
||||
#include <AzFramework/Process/ProcessCommunicator.h>
|
||||
|
||||
#include <AzFramework/StringFunc/StringFunc.h>
|
||||
|
||||
#include <AzCore/base.h>
|
||||
#include <AzCore/IO/SystemFile.h>
|
||||
#include <AzCore/std/parallel/thread.h>
|
||||
#include <AzCore/std/smart_ptr/shared_ptr.h>
|
||||
#include <AzCore/StringFunc/StringFunc.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <errno.h>
|
||||
@@ -220,36 +219,52 @@ namespace AzFramework
|
||||
// this is so that the callers (which could be numerous) do not have to worry about this and sprinkle ifdefs
|
||||
// all over their code.
|
||||
// We'll convert this to UNIX style command line parameters by counting and eliminating quotes:
|
||||
|
||||
AZStd::vector<AZStd::string> commandTokens;
|
||||
|
||||
AZStd::string outputString;
|
||||
bool inQuotes = false;
|
||||
for (const char currentChar : processLaunchInfo.m_commandlineParameters)
|
||||
{
|
||||
if (currentChar == '"')
|
||||
{
|
||||
inQuotes = !inQuotes;
|
||||
}
|
||||
else if ((currentChar == ' ') && (!inQuotes))
|
||||
{
|
||||
// its a space outside of quotes, so it ends the current parameter
|
||||
commandTokens.push_back(outputString);
|
||||
outputString.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Its a normal character, or its a space inside quotes
|
||||
outputString.push_back(currentChar);
|
||||
}
|
||||
}
|
||||
|
||||
if (!outputString.empty())
|
||||
// Struct uses overloaded operator() to quote command line arguments based
|
||||
// on whether a string or a vector<string> was supplied
|
||||
struct EscapeCommandArguments
|
||||
{
|
||||
commandTokens.push_back(outputString);
|
||||
outputString.clear();
|
||||
}
|
||||
|
||||
void operator()(const AZStd::string& commandParameterString)
|
||||
{
|
||||
AZStd::string outputString;
|
||||
bool inQuotes = false;
|
||||
for (size_t pos = 0; pos < commandParameterString.size(); ++pos)
|
||||
{
|
||||
char currentChar = commandParameterString[pos];
|
||||
if (currentChar == '"')
|
||||
{
|
||||
inQuotes = !inQuotes;
|
||||
}
|
||||
else if ((currentChar == ' ') && (!inQuotes))
|
||||
{
|
||||
// its a space outside of quotes, so it ends the current parameter
|
||||
commandArray.push_back(outputString);
|
||||
outputString.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Its a normal character, or its a space inside quotes
|
||||
outputString.push_back(currentChar);
|
||||
}
|
||||
}
|
||||
|
||||
if (!outputString.empty())
|
||||
{
|
||||
commandArray.push_back(outputString);
|
||||
outputString.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void operator()(const AZStd::vector<AZStd::string>& commandParameterArray)
|
||||
{
|
||||
commandArray = commandParameterArray;
|
||||
}
|
||||
AZStd::vector<AZStd::string>& commandArray;
|
||||
};
|
||||
|
||||
AZStd::vector<AZStd::string> commandTokens;
|
||||
AZStd::visit(EscapeCommandArguments{ commandTokens }, processLaunchInfo.m_commandlineParameters);
|
||||
|
||||
if (!processLaunchInfo.m_processExecutableString.empty())
|
||||
{
|
||||
commandTokens.insert(commandTokens.begin(), processLaunchInfo.m_processExecutableString);
|
||||
@@ -452,4 +467,23 @@ namespace AzFramework
|
||||
|
||||
kill(m_pWatcherData->m_childProcessId, SIGKILL);
|
||||
}
|
||||
|
||||
AZStd::string ProcessLauncher::ProcessLaunchInfo::GetCommandLineParametersAsString() const
|
||||
{
|
||||
struct CommandLineParametersVisitor
|
||||
{
|
||||
AZStd::string operator()(const AZStd::string& commandLine) const
|
||||
{
|
||||
return commandLine;
|
||||
}
|
||||
|
||||
AZStd::string operator()(const AZStd::vector<AZStd::string>& commandLineArray) const
|
||||
{
|
||||
AZStd::string commandLineResult;
|
||||
AZ::StringFunc::Join(commandLineResult, commandLineArray.begin(), commandLineArray.end(), " ");
|
||||
return commandLineResult;
|
||||
}
|
||||
};
|
||||
return AZStd::visit(CommandLineParametersVisitor{}, m_commandlineParameters);
|
||||
}
|
||||
} //namespace AzFramework
|
||||
|
||||
+64
-41
@@ -11,13 +11,12 @@
|
||||
#include <AzFramework/Process/ProcessWatcher.h>
|
||||
#include <AzFramework/Process/ProcessCommunicator.h>
|
||||
|
||||
#include <AzFramework/StringFunc/StringFunc.h>
|
||||
|
||||
#include <AzCore/base.h>
|
||||
#include <AzCore/IO/SystemFile.h>
|
||||
#include <AzCore/std/containers/fixed_vector.h>
|
||||
#include <AzCore/std/parallel/thread.h>
|
||||
#include <AzCore/std/smart_ptr/shared_ptr.h>
|
||||
#include <AzCore/StringFunc/StringFunc.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <errno.h>
|
||||
@@ -210,46 +209,51 @@ namespace AzFramework
|
||||
// this is so that the callers (which could be numerous) do not have to worry about this and sprinkle ifdefs
|
||||
// all over their code.
|
||||
// We'll convert this to UNIX style command line parameters by counting and eliminating quotes:
|
||||
|
||||
|
||||
// Struct uses overloaded operator() to quote command line arguments based
|
||||
// on whether a string or a vector<string> was supplied
|
||||
struct EscapeCommandArguments
|
||||
{
|
||||
void operator()(const AZStd::string& commandParameterString)
|
||||
{
|
||||
AZStd::string outputString;
|
||||
bool inQuotes = false;
|
||||
for (size_t pos = 0; pos < commandParameterString.size(); ++pos)
|
||||
{
|
||||
char currentChar = commandParameterString[pos];
|
||||
if (currentChar == '"')
|
||||
{
|
||||
inQuotes = !inQuotes;
|
||||
}
|
||||
else if ((currentChar == ' ') && (!inQuotes))
|
||||
{
|
||||
// its a space outside of quotes, so it ends the current parameter
|
||||
commandArray.push_back(outputString);
|
||||
outputString.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Its a normal character, or its a space inside quotes
|
||||
outputString.push_back(currentChar);
|
||||
}
|
||||
}
|
||||
|
||||
if (!outputString.empty())
|
||||
{
|
||||
commandArray.push_back(outputString);
|
||||
outputString.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void operator()(const AZStd::vector<AZStd::string>& commandParameterArray)
|
||||
{
|
||||
commandArray = commandParameterArray;
|
||||
}
|
||||
AZStd::vector<AZStd::string>& commandArray;
|
||||
};
|
||||
|
||||
AZStd::vector<AZStd::string> commandTokens;
|
||||
|
||||
AZStd::string outputString;
|
||||
bool inQuotes = false;
|
||||
for (size_t pos = 0; pos < processLaunchInfo.m_commandlineParameters.size(); ++pos)
|
||||
{
|
||||
char currentChar = processLaunchInfo.m_commandlineParameters[pos];
|
||||
if (currentChar == '"')
|
||||
{
|
||||
// Allow quote literals to go through as quotes which do NOT alter our "in quotes" bool below
|
||||
// This is to conform with our PC parameter strings which will sometimes include path parameters which
|
||||
// Can have spaces and commas and need to be output as paramname="\"Some pa,ram\"" in order to capture both correctly
|
||||
if (outputString.length() && outputString.back() == '\\')
|
||||
{
|
||||
outputString.back() = currentChar;
|
||||
}
|
||||
else
|
||||
{
|
||||
inQuotes = !inQuotes;
|
||||
}
|
||||
}
|
||||
else if ((currentChar == ' ') && (!inQuotes))
|
||||
{
|
||||
// its a space outside of quotes, so it ends the current parameter
|
||||
commandTokens.push_back(outputString);
|
||||
outputString.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Its a normal character, or its a space inside quotes
|
||||
outputString.push_back(currentChar);
|
||||
}
|
||||
}
|
||||
|
||||
if (!outputString.empty())
|
||||
{
|
||||
commandTokens.push_back(outputString);
|
||||
outputString.clear();
|
||||
}
|
||||
AZStd::visit(EscapeCommandArguments{ commandTokens }, processLaunchInfo.m_commandlineParameters);
|
||||
|
||||
if (!processLaunchInfo.m_processExecutableString.empty())
|
||||
{
|
||||
@@ -417,5 +421,24 @@ namespace AzFramework
|
||||
kill(m_pWatcherData->m_childProcessId, SIGKILL);
|
||||
waitpid(m_pWatcherData->m_childProcessId, NULL, 0);
|
||||
}
|
||||
|
||||
AZStd::string ProcessLauncher::ProcessLaunchInfo::GetCommandLineParametersAsString() const
|
||||
{
|
||||
struct CommandLineParametersVisitor
|
||||
{
|
||||
AZStd::string operator()(const AZStd::string& commandLine) const
|
||||
{
|
||||
return commandLine;
|
||||
}
|
||||
|
||||
AZStd::string operator()(const AZStd::vector<AZStd::string>& commandLineArray) const
|
||||
{
|
||||
AZStd::string commandLineResult;
|
||||
AZ::StringFunc::Join(commandLineResult, commandLineArray.begin(), commandLineArray.end(), " ");
|
||||
return commandLineResult;
|
||||
}
|
||||
};
|
||||
return AZStd::visit(CommandLineParametersVisitor{}, m_commandlineParameters);
|
||||
}
|
||||
} //namespace AzFramework
|
||||
|
||||
|
||||
+39
-1
@@ -10,6 +10,7 @@
|
||||
#include <AzCore/std/string/conversions.h>
|
||||
#include <AzCore/std/parallel/thread.h>
|
||||
#include <AzCore/PlatformIncl.h>
|
||||
#include <AzCore/StringFunc/StringFunc.h>
|
||||
|
||||
#include <AzFramework/Process/ProcessWatcher.h>
|
||||
#include <AzFramework/Process/ProcessCommunicator.h>
|
||||
@@ -99,7 +100,7 @@ namespace AzFramework
|
||||
AZStd::wstring editableCommandLine;
|
||||
AZStd::wstring processExecutableString;
|
||||
AZStd::wstring workingDirectory;
|
||||
AZStd::to_wstring(editableCommandLine, processLaunchInfo.m_commandlineParameters);
|
||||
AZStd::to_wstring(editableCommandLine, processLaunchInfo.GetCommandLineParametersAsString());
|
||||
AZStd::to_wstring(processExecutableString, processLaunchInfo.m_processExecutableString);
|
||||
AZStd::to_wstring(workingDirectory, processLaunchInfo.m_workingDirectory);
|
||||
|
||||
@@ -355,4 +356,41 @@ namespace AzFramework
|
||||
::TerminateProcess(m_pWatcherData->processInformation.hProcess, exitCode);
|
||||
}
|
||||
}
|
||||
|
||||
AZStd::string ProcessLauncher::ProcessLaunchInfo::GetCommandLineParametersAsString() const
|
||||
{
|
||||
struct CommandLineParametersVisitor
|
||||
{
|
||||
AZStd::string operator()(const AZStd::string& commandLine) const
|
||||
{
|
||||
return commandLine;
|
||||
}
|
||||
|
||||
AZStd::string operator()(const AZStd::vector<AZStd::string>& commandLineArray) const
|
||||
{
|
||||
AZStd::string commandLineResult;
|
||||
|
||||
// When re-constructing a command line from an argument list (on windows), if an argument
|
||||
// is double-quoted, then the double-quotes must be escaped properly otherwise
|
||||
// it will be absorbed by the native argument parser and possibly evaluated as
|
||||
// multiple values for arguments
|
||||
AZStd::string_view escapedDoubleQuote = R"("\")";
|
||||
|
||||
AZStd::vector<AZStd::string> preprocessedCommandArray;
|
||||
|
||||
for (const auto& commandArg : commandLineArray)
|
||||
{
|
||||
AZStd::string replacedArg = commandArg;
|
||||
AZ::StringFunc::Replace(replacedArg, R"(")", R"("\")", false, true, true);
|
||||
preprocessedCommandArray.emplace_back(replacedArg);
|
||||
}
|
||||
AZ::StringFunc::Join(commandLineResult, preprocessedCommandArray.begin(), preprocessedCommandArray.end(), " ");
|
||||
|
||||
return commandLineResult;
|
||||
}
|
||||
};
|
||||
|
||||
return AZStd::visit(CommandLineParametersVisitor{}, m_commandlineParameters);
|
||||
}
|
||||
|
||||
} // namespace AzFramework
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/StringFunc/StringFunc.h>
|
||||
#include <AzFramework/Process/ProcessWatcher.h>
|
||||
#include <AzFramework/Process/ProcessCommunicator.h>
|
||||
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
|
||||
@@ -83,4 +83,23 @@ namespace AzFramework
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
AZStd::string ProcessLauncher::ProcessLaunchInfo::GetCommandLineParametersAsString() const
|
||||
{
|
||||
struct CommandLineParametersVisitor
|
||||
{
|
||||
AZStd::string operator()(const AZStd::string& commandLine) const
|
||||
{
|
||||
return commandLine;
|
||||
}
|
||||
|
||||
AZStd::string operator()(const AZStd::vector<AZStd::string>& commandLineArray) const
|
||||
{
|
||||
AZStd::string commandLineResult;
|
||||
Az::StringFunc::Join(commandLineResult, commandLineArray.begin(), commandLineArray.end(), " ");
|
||||
return commandLineResult;
|
||||
}
|
||||
};
|
||||
return AZStd::visit(CommandLineParametersVisitor{}, m_commandlineParameters);
|
||||
}
|
||||
} //namespace AzFramework
|
||||
|
||||
Reference in New Issue
Block a user