src: switch from Qt to boost implementation of executeProcess (#1145)
* changed implementation of executeProcess * unified all different implementations of executeProcess * separated arg list from command for all calls of executeProcess (this also required to remove quotes that were added to path args because otherwise the Python indexer would mistake absolute paths for relative paths.) * update expected output for custom command tests
This commit is contained in:
@@ -1,6 +1,12 @@
|
||||
SourceFilePath: "src/a.txt"
|
||||
IndexerCommandCustom
|
||||
SourceFilePath: "src/a.txt"
|
||||
Custom Command: "echo "Hello World""
|
||||
SourceFilePath: "src/b.txt"
|
||||
Arguments:
|
||||
IndexerCommandCustom
|
||||
SourceFilePath: "src/b.txt"
|
||||
Custom Command: "echo "Hello World""
|
||||
SourceFilePath: "src/included/a.txt"
|
||||
Arguments:
|
||||
IndexerCommandCustom
|
||||
SourceFilePath: "src/included/a.txt"
|
||||
Custom Command: "echo "Hello World""
|
||||
Arguments:
|
||||
|
||||
+9
-3
@@ -1,6 +1,12 @@
|
||||
SourceFilePath: "src/a.txt"
|
||||
IndexerCommandCustom
|
||||
SourceFilePath: "src/a.txt"
|
||||
Custom Command: "echo "Hello World""
|
||||
SourceFilePath: "src/b.txt"
|
||||
Arguments:
|
||||
IndexerCommandCustom
|
||||
SourceFilePath: "src/b.txt"
|
||||
Custom Command: "echo "Hello World""
|
||||
SourceFilePath: "src/included/a.txt"
|
||||
Arguments:
|
||||
IndexerCommandCustom
|
||||
SourceFilePath: "src/included/a.txt"
|
||||
Custom Command: "echo "Hello World""
|
||||
Arguments:
|
||||
|
||||
@@ -94,6 +94,7 @@ fi
|
||||
echo -e $INFO "clearing $TARGET_PATH"
|
||||
rm -rf $TARGET_PATH
|
||||
mkdir -p $TARGET_PATH
|
||||
echo -e $INFO "copying downloaded data to $TARGET_PATH"
|
||||
cp -r $TEMP_PATH/$PACKAGE_NAME/* $TARGET_PATH
|
||||
|
||||
|
||||
|
||||
@@ -93,6 +93,11 @@ void addLanguagePackages()
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
// auto p = utility::executeProcessBoost(utility::searchPath(L"mvn") + L" --version", FilePath("/Users/ebsi/Documents/boost_1_67_0"), 3000);
|
||||
// std::wcout << p.first << " " << p.second << std::endl;
|
||||
// return 0;
|
||||
|
||||
|
||||
QCoreApplication::addLibraryPath(QStringLiteral("."));
|
||||
|
||||
#pragma warning(push)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "ResourcePaths.h"
|
||||
|
||||
#include "AppPath.h"
|
||||
#include "utilityApp.h"
|
||||
|
||||
FilePath ResourcePaths::getColorSchemesPath()
|
||||
{
|
||||
@@ -37,7 +38,7 @@ FilePath ResourcePaths::getJavaPath()
|
||||
return AppPath::getSharedDataPath().concatenate(L"data/java/");
|
||||
}
|
||||
|
||||
FilePath ResourcePaths::getPythonPath()
|
||||
FilePath ResourcePaths::getPythonDirectoryPath()
|
||||
{
|
||||
return AppPath::getSharedDataPath().concatenate(L"data/python/");
|
||||
}
|
||||
@@ -46,3 +47,12 @@ FilePath ResourcePaths::getCxxCompilerHeaderPath()
|
||||
{
|
||||
return AppPath::getSharedDataPath().concatenate(L"data/cxx/include/").getCanonical();
|
||||
}
|
||||
|
||||
FilePath ResourcePaths::getPythonIndexerFilePath()
|
||||
{
|
||||
if (utility::getOsType() == OS_WINDOWS)
|
||||
{
|
||||
return getPythonDirectoryPath().concatenate(L"SourcetrailPythonIndexer.exe");
|
||||
}
|
||||
return getPythonDirectoryPath().concatenate(L"SourcetrailPythonIndexer");
|
||||
}
|
||||
|
||||
@@ -15,8 +15,9 @@ public:
|
||||
static FilePath getGuiPath();
|
||||
static FilePath getLicensePath();
|
||||
static FilePath getJavaPath();
|
||||
static FilePath getPythonPath();
|
||||
static FilePath getPythonDirectoryPath();
|
||||
static FilePath getCxxCompilerHeaderPath();
|
||||
static FilePath getPythonIndexerFilePath();
|
||||
};
|
||||
|
||||
#endif // RESOURCE_PATHS_H
|
||||
|
||||
@@ -11,7 +11,8 @@ IndexerCommandType IndexerCommandCustom::getStaticIndexerCommandType()
|
||||
}
|
||||
|
||||
IndexerCommandCustom::IndexerCommandCustom(
|
||||
const std::wstring& customCommand,
|
||||
const std::wstring& command,
|
||||
const std::vector<std::wstring>& arguments,
|
||||
const FilePath& projectFilePath,
|
||||
const FilePath& databaseFilePath,
|
||||
const std::wstring& databaseVersion,
|
||||
@@ -19,7 +20,8 @@ IndexerCommandCustom::IndexerCommandCustom(
|
||||
bool runInParallel)
|
||||
: IndexerCommand(sourceFilePath)
|
||||
, m_type(getStaticIndexerCommandType())
|
||||
, m_customCommand(customCommand)
|
||||
, m_command(command)
|
||||
, m_arguments(arguments)
|
||||
, m_projectFilePath(projectFilePath)
|
||||
, m_databaseFilePath(databaseFilePath)
|
||||
, m_databaseVersion(databaseVersion)
|
||||
@@ -29,7 +31,8 @@ IndexerCommandCustom::IndexerCommandCustom(
|
||||
|
||||
IndexerCommandCustom::IndexerCommandCustom(
|
||||
IndexerCommandType type,
|
||||
const std::wstring& customCommand,
|
||||
const std::wstring& command,
|
||||
const std::vector<std::wstring>& arguments,
|
||||
const FilePath& projectFilePath,
|
||||
const FilePath& databaseFilePath,
|
||||
const std::wstring& databaseVersion,
|
||||
@@ -37,7 +40,8 @@ IndexerCommandCustom::IndexerCommandCustom(
|
||||
bool runInParallel)
|
||||
: IndexerCommand(sourceFilePath)
|
||||
, m_type(type)
|
||||
, m_customCommand(customCommand)
|
||||
, m_command(command)
|
||||
, m_arguments(arguments)
|
||||
, m_projectFilePath(projectFilePath)
|
||||
, m_databaseFilePath(databaseFilePath)
|
||||
, m_databaseVersion(databaseVersion)
|
||||
@@ -67,19 +71,19 @@ void IndexerCommandCustom::setDatabaseFilePath(const FilePath& databaseFilePath)
|
||||
m_databaseFilePath = databaseFilePath;
|
||||
}
|
||||
|
||||
std::wstring IndexerCommandCustom::getCustomCommand() const
|
||||
std::wstring IndexerCommandCustom::getCommand() const
|
||||
{
|
||||
std::wstring command = m_customCommand;
|
||||
return replaceVariables(m_command);
|
||||
}
|
||||
|
||||
command = utility::replace(
|
||||
command, L"%{PROJECT_FILE_PATH}", L'\"' + m_projectFilePath.wstr() + L'\"');
|
||||
command = utility::replace(
|
||||
command, L"%{DATABASE_FILE_PATH}", L'\"' + m_databaseFilePath.wstr() + L'\"');
|
||||
command = utility::replace(command, L"%{DATABASE_VERSION}", L'\"' + m_databaseVersion + L'\"');
|
||||
command = utility::replace(
|
||||
command, L"%{SOURCE_FILE_PATH}", L'\"' + getSourceFilePath().wstr() + L'\"');
|
||||
|
||||
return command;
|
||||
std::vector<std::wstring> IndexerCommandCustom::getArguments() const
|
||||
{
|
||||
std::vector<std::wstring> args;
|
||||
for (const std::wstring& argument: m_arguments)
|
||||
{
|
||||
args.push_back(replaceVariables(argument));
|
||||
}
|
||||
return args;
|
||||
}
|
||||
|
||||
bool IndexerCommandCustom::getRunInParallel() const
|
||||
@@ -92,7 +96,15 @@ QJsonObject IndexerCommandCustom::doSerialize() const
|
||||
QJsonObject jsonObject = IndexerCommand::doSerialize();
|
||||
|
||||
{
|
||||
jsonObject["custom_command"] = QString::fromStdWString(m_customCommand);
|
||||
jsonObject["command"] = QString::fromStdWString(m_command);
|
||||
}
|
||||
{
|
||||
QJsonArray argumentsArray;
|
||||
for (const std::wstring& argument: m_arguments)
|
||||
{
|
||||
argumentsArray.append(QString::fromStdWString(argument));
|
||||
}
|
||||
jsonObject["arguments"] = argumentsArray;
|
||||
}
|
||||
{
|
||||
jsonObject["run_in_parallel"] = m_runInParallel;
|
||||
@@ -100,3 +112,12 @@ QJsonObject IndexerCommandCustom::doSerialize() const
|
||||
|
||||
return jsonObject;
|
||||
}
|
||||
|
||||
std::wstring IndexerCommandCustom::replaceVariables(std::wstring s) const
|
||||
{
|
||||
s = utility::replace(s, L"%{PROJECT_FILE_PATH}", m_projectFilePath.wstr());
|
||||
s = utility::replace(s, L"%{DATABASE_FILE_PATH}", m_databaseFilePath.wstr());
|
||||
s = utility::replace(s, L"%{DATABASE_VERSION}", m_databaseVersion);
|
||||
s = utility::replace(s, L"%{SOURCE_FILE_PATH}", getSourceFilePath().wstr());
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,8 @@ public:
|
||||
static IndexerCommandType getStaticIndexerCommandType();
|
||||
|
||||
IndexerCommandCustom(
|
||||
const std::wstring& customCommand,
|
||||
const std::wstring& command,
|
||||
const std::vector<std::wstring>& arguments,
|
||||
const FilePath& projectFilePath,
|
||||
const FilePath& databaseFilePath,
|
||||
const std::wstring& databaseVersion,
|
||||
@@ -21,7 +22,8 @@ public:
|
||||
|
||||
IndexerCommandCustom(
|
||||
IndexerCommandType type,
|
||||
const std::wstring& customCommand,
|
||||
const std::wstring& command,
|
||||
const std::vector<std::wstring>& arguments,
|
||||
const FilePath& projectFilePath,
|
||||
const FilePath& databaseFilePath,
|
||||
const std::wstring& databaseVersion,
|
||||
@@ -34,15 +36,19 @@ public:
|
||||
FilePath getDatabaseFilePath() const;
|
||||
void setDatabaseFilePath(const FilePath& databaseFilePath);
|
||||
|
||||
std::wstring getCustomCommand() const;
|
||||
std::wstring getCommand() const;
|
||||
std::vector<std::wstring> getArguments() const;
|
||||
bool getRunInParallel() const;
|
||||
|
||||
protected:
|
||||
QJsonObject doSerialize() const override;
|
||||
|
||||
private:
|
||||
std::wstring replaceVariables(std::wstring s) const;
|
||||
|
||||
IndexerCommandType m_type;
|
||||
std::wstring m_customCommand;
|
||||
std::wstring m_command;
|
||||
std::vector<std::wstring> m_arguments;
|
||||
FilePath m_projectFilePath;
|
||||
FilePath m_databaseFilePath;
|
||||
std::wstring m_databaseVersion;
|
||||
|
||||
@@ -188,22 +188,23 @@ void TaskBuildIndex::runIndexerProcess(int processId, const std::wstring& logFil
|
||||
return;
|
||||
}
|
||||
|
||||
const std::wstring commandPath = L"\"" + indexerProcessPath.wstr() + L"\"";
|
||||
std::vector<std::wstring> commandArguments;
|
||||
commandArguments.push_back(std::to_wstring(processId));
|
||||
commandArguments.push_back(utility::decodeFromUtf8(m_appUUID));
|
||||
commandArguments.push_back(L"\"" + AppPath::getSharedDataPath().getAbsolute().wstr() + L"\"");
|
||||
commandArguments.push_back(L"\"" + UserPaths::getUserDataPath().getAbsolute().wstr() + L"\"");
|
||||
commandArguments.push_back(AppPath::getSharedDataPath().getAbsolute().wstr());
|
||||
commandArguments.push_back(UserPaths::getUserDataPath().getAbsolute().wstr());
|
||||
|
||||
if (!logFilePath.empty())
|
||||
{
|
||||
commandArguments.push_back(L"\"" + logFilePath + L"\"");
|
||||
commandArguments.push_back(logFilePath);
|
||||
}
|
||||
|
||||
int result = 1;
|
||||
while ((!m_indexerCommandQueueStopped || result != 0) && !m_interrupted)
|
||||
{
|
||||
result = utility::executeProcessAndGetExitCode(commandPath, commandArguments, FilePath(), -1);
|
||||
result = utility::executeProcess(
|
||||
indexerProcessPath.wstr(), commandArguments, FilePath(), false, -1)
|
||||
.exitCode;
|
||||
|
||||
LOG_INFO_STREAM(<< "Indexer process " << processId << " returned with " + std::to_string(result));
|
||||
}
|
||||
|
||||
@@ -465,17 +465,19 @@ void TaskExecuteCustomCommands::runIndexerCommand(
|
||||
indexedSourceFileCount + 1, indexedSourceFileCount, m_indexerCommandCount, {sourcePath});
|
||||
MessageIndexingStatus(true, indexedSourceFileCount * 100 / m_indexerCommandCount).dispatch();
|
||||
|
||||
const std::wstring command = indexerCommand->getCustomCommand();
|
||||
const std::wstring command = indexerCommand->getCommand();
|
||||
const std::vector<std::wstring> arguments = indexerCommand->getArguments();
|
||||
|
||||
LOG_INFO("Start processing command \"" + utility::encodeToUtf8(command) + "\"");
|
||||
LOG_INFO(
|
||||
"Start processing command \"" +
|
||||
utility::encodeToUtf8(command + L" " + utility::join(arguments, L" ")) + "\"");
|
||||
|
||||
const ErrorCountInfo previousErrorCount = storage ? storage->getErrorCount()
|
||||
: ErrorCountInfo();
|
||||
|
||||
LOG_INFO("Starting to index");
|
||||
std::wstring errorMessage;
|
||||
const int result = utility::executeProcessAndGetExitCode(
|
||||
command, {}, m_projectDirectory, -1, true, &errorMessage);
|
||||
const utility::ProcessOutput out = utility::executeProcess(
|
||||
command, arguments, m_projectDirectory, false, -1, true);
|
||||
LOG_INFO("Finished indexing");
|
||||
|
||||
if (storage)
|
||||
@@ -501,22 +503,22 @@ void TaskExecuteCustomCommands::runIndexerCommand(
|
||||
}
|
||||
}
|
||||
|
||||
if (result == 0 && errorMessage.empty())
|
||||
if (out.exitCode == 0 && out.error.empty())
|
||||
{
|
||||
std::wstring message = L"Process returned successfully.\n";
|
||||
LOG_INFO(message);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::wstring statusText = L"command \"" + indexerCommand->getCustomCommand() +
|
||||
L"\" returned";
|
||||
if (result != 0)
|
||||
std::wstring statusText = L"command \"" + indexerCommand->getCommand() + L" " +
|
||||
utility::join(arguments, L" ") + L"\" returned";
|
||||
if (out.exitCode != 0)
|
||||
{
|
||||
statusText += L" code \"" + std::to_wstring(result) + L"\"";
|
||||
statusText += L" code \"" + std::to_wstring(out.exitCode) + L"\"";
|
||||
}
|
||||
if (!errorMessage.empty())
|
||||
if (!out.error.empty())
|
||||
{
|
||||
statusText += L" with message \"" + errorMessage + L"\"";
|
||||
statusText += L" with message \"" + out.error + L"\"";
|
||||
}
|
||||
statusText += L".";
|
||||
|
||||
|
||||
@@ -42,7 +42,6 @@ std::set<FilePath> SourceGroupCustomCommand::getAllSourceFilePaths() const
|
||||
std::vector<std::shared_ptr<IndexerCommand>> SourceGroupCustomCommand::getIndexerCommands(
|
||||
const RefreshInfo& info) const
|
||||
{
|
||||
const std::wstring customCommand = m_settings->getCustomCommand();
|
||||
const bool runInParallel = m_settings->getRunInParallel();
|
||||
|
||||
std::vector<std::shared_ptr<IndexerCommand>> indexerCommands;
|
||||
@@ -51,7 +50,8 @@ std::vector<std::shared_ptr<IndexerCommand>> SourceGroupCustomCommand::getIndexe
|
||||
if (info.filesToIndex.find(sourcePath) != info.filesToIndex.end())
|
||||
{
|
||||
indexerCommands.push_back(std::make_shared<IndexerCommandCustom>(
|
||||
customCommand,
|
||||
m_settings->getCustomCommand(),
|
||||
std::vector<std::wstring> {},
|
||||
m_settings->getProjectSettings()->getProjectFilePath(),
|
||||
m_settings->getProjectSettings()->getTempDBFilePath(),
|
||||
std::to_wstring(SqliteIndexStorage::getStorageVersion()),
|
||||
|
||||
@@ -24,20 +24,19 @@ void QtProjectWizardContentSelect::populate(QGridLayout* layout, int& row)
|
||||
{
|
||||
std::string pythonIndexerVersion = " ";
|
||||
{
|
||||
std::string str =
|
||||
utility::executeProcess(
|
||||
ResourcePaths::getPythonPath().wstr().append(L"SourcetrailPythonIndexer"),
|
||||
std::vector<std::wstring> {L"--version"},
|
||||
FilePath(),
|
||||
5000)
|
||||
.second;
|
||||
std::regex regex(
|
||||
"v\\d*\\.db\\d*\\.p\\d*"); // "\\d" matches any digit; "\\." matches the "." character
|
||||
std::smatch matches;
|
||||
std::regex_search(str, matches, regex);
|
||||
if (!matches.empty())
|
||||
utility::ProcessOutput output = utility::executeProcess(
|
||||
ResourcePaths::getPythonIndexerFilePath().wstr(), {L"--version"}, FilePath(), false, 5000);
|
||||
if (output.exitCode == 0)
|
||||
{
|
||||
pythonIndexerVersion = matches.str(0) + " ";
|
||||
std::string str = utility::encodeToUtf8(output.output);
|
||||
std::regex regex("v\\d*\\.db\\d*\\.p\\d*"); // "\\d" matches any digit; "\\." matches
|
||||
// the "." character
|
||||
std::smatch matches;
|
||||
std::regex_search(str, matches, regex);
|
||||
if (!matches.empty())
|
||||
{
|
||||
pythonIndexerVersion = matches.str(0) + " ";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+10
-10
@@ -62,20 +62,20 @@ void QtProjectWizardContentPathPythonEnvironment::onTextChanged(const QString& t
|
||||
{
|
||||
m_resultLabel->setText("Checking validity of Python environment...");
|
||||
std::thread([=]() {
|
||||
std::pair<int, std::string> out = utility::executeProcess(
|
||||
ResourcePaths::getPythonPath().wstr().append(L"SourcetrailPythonIndexer"),
|
||||
std::vector<std::wstring>{
|
||||
L"check-environment",
|
||||
L"--environment-path " + utility::getExpandedAndAbsolutePath(
|
||||
FilePath(text.toStdWString()), m_settings->getProjectDirectoryPath())
|
||||
.wstr()
|
||||
},
|
||||
const utility::ProcessOutput out = utility::executeProcess(
|
||||
ResourcePaths::getPythonIndexerFilePath().wstr(),
|
||||
{L"check-environment",
|
||||
L"--environment-path",
|
||||
utility::getExpandedAndAbsolutePath(
|
||||
FilePath(text.toStdWString()), m_settings->getProjectDirectoryPath())
|
||||
.wstr()},
|
||||
FilePath(),
|
||||
false,
|
||||
5000);
|
||||
m_onQtThread([=]() {
|
||||
if (out.first == 0)
|
||||
if (out.exitCode == 0)
|
||||
{
|
||||
m_resultLabel->setText(QString::fromStdString(out.second));
|
||||
m_resultLabel->setText(QString::fromStdWString(out.output));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -11,14 +11,14 @@ CxxFrameworkPathDetector::CxxFrameworkPathDetector(const std::string& compilerNa
|
||||
|
||||
std::vector<FilePath> CxxFrameworkPathDetector::doGetPaths() const
|
||||
{
|
||||
std::vector<std::string> paths = utility::getCxxHeaderPaths(m_compilerName);
|
||||
std::vector<std::wstring> paths = utility::getCxxHeaderPaths(m_compilerName);
|
||||
std::vector<FilePath> frameworkPaths;
|
||||
for (const std::string& path: paths)
|
||||
for (const std::wstring& path: paths)
|
||||
{
|
||||
if (utility::isPostfix<std::string>(" (framework directory)", path))
|
||||
if (utility::isPostfix<std::wstring>(L" (framework directory)", path))
|
||||
{
|
||||
FilePath p =
|
||||
FilePath(utility::replace(path, " (framework directory)", "")).makeCanonical();
|
||||
FilePath(utility::replace(path, L" (framework directory)", L"")).makeCanonical();
|
||||
if (p.exists())
|
||||
{
|
||||
frameworkPaths.push_back(p);
|
||||
|
||||
@@ -11,12 +11,12 @@ CxxHeaderPathDetector::CxxHeaderPathDetector(const std::string& compilerName)
|
||||
|
||||
std::vector<FilePath> CxxHeaderPathDetector::doGetPaths() const
|
||||
{
|
||||
std::vector<std::string> paths = utility::getCxxHeaderPaths(m_compilerName);
|
||||
std::vector<std::wstring> paths = utility::getCxxHeaderPaths(m_compilerName);
|
||||
std::vector<FilePath> headerSearchPaths;
|
||||
|
||||
for (const std::string& path: paths)
|
||||
for (const std::wstring& path: paths)
|
||||
{
|
||||
if (!utility::isPostfix<std::string>(" (framework directory)", path) &&
|
||||
if (!utility::isPostfix<std::wstring>(L" (framework directory)", path) &&
|
||||
FilePath(path).getCanonical().exists() &&
|
||||
!FilePath(path).getCanonical().getConcatenated(L"/stdarg.h").exists())
|
||||
{
|
||||
|
||||
@@ -20,27 +20,32 @@ std::vector<FilePath> CxxVs15HeaderPathDetector::doGetPaths() const
|
||||
.expandEnvironmentVariables();
|
||||
if (!expandedPaths.empty())
|
||||
{
|
||||
const std::string output =
|
||||
utility::executeProcess(
|
||||
expandedPaths[0].wstr(), std::vector<std::wstring> {L"-latest", L"-property installationPath"}, FilePath(), 10000)
|
||||
.second;
|
||||
|
||||
const FilePath vsInstallPath(output);
|
||||
if (vsInstallPath.exists())
|
||||
const utility::ProcessOutput out = utility::executeProcess(
|
||||
expandedPaths.front().wstr(),
|
||||
{L"-latest", L"-property", L"installationPath"},
|
||||
FilePath(),
|
||||
false,
|
||||
10000);
|
||||
if (out.exitCode == 0)
|
||||
{
|
||||
for (const FilePath& versionPath: FileSystem::getDirectSubDirectories(
|
||||
vsInstallPath.getConcatenated(L"VC/Tools/MSVC")))
|
||||
const FilePath vsInstallPath(out.output);
|
||||
if (vsInstallPath.exists())
|
||||
{
|
||||
if (versionPath.exists())
|
||||
for (const FilePath& versionPath: FileSystem::getDirectSubDirectories(
|
||||
vsInstallPath.getConcatenated(L"VC/Tools/MSVC")))
|
||||
{
|
||||
headerSearchPaths.push_back(versionPath.getConcatenated(L"include"));
|
||||
headerSearchPaths.push_back(versionPath.getConcatenated(L"atlmfc/include"));
|
||||
if (versionPath.exists())
|
||||
{
|
||||
headerSearchPaths.push_back(versionPath.getConcatenated(L"include"));
|
||||
headerSearchPaths.push_back(
|
||||
versionPath.getConcatenated(L"atlmfc/include"));
|
||||
}
|
||||
}
|
||||
headerSearchPaths.push_back(
|
||||
vsInstallPath.getConcatenated(L"VC/Auxiliary/VS/include"));
|
||||
headerSearchPaths.push_back(
|
||||
vsInstallPath.getConcatenated(L"VC/Auxiliary/VS/UnitTest/include"));
|
||||
}
|
||||
headerSearchPaths.push_back(
|
||||
vsInstallPath.getConcatenated(L"VC/Auxiliary/VS/include"));
|
||||
headerSearchPaths.push_back(
|
||||
vsInstallPath.getConcatenated(L"VC/Auxiliary/VS/UnitTest/include"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,22 +9,23 @@
|
||||
|
||||
namespace utility
|
||||
{
|
||||
std::vector<std::string> getCxxHeaderPaths(const std::string& compilerName)
|
||||
std::vector<std::wstring> getCxxHeaderPaths(const std::string& compilerName)
|
||||
{
|
||||
std::string command = compilerName + " -x c++ -v -E /dev/null";
|
||||
std::string clangOutput = utility::executeProcess(
|
||||
utility::decodeFromUtf8(compilerName),
|
||||
std::vector<std::wstring> {L"-x c++", L"-v", L"-E /dev/null"})
|
||||
.second;
|
||||
std::string standardHeaders = utility::substrBetween<std::string>(
|
||||
clangOutput, "#include <...> search starts here:\n", "\nEnd of search list");
|
||||
std::vector<std::string> paths;
|
||||
std::vector<std::wstring> paths;
|
||||
|
||||
if (!standardHeaders.empty())
|
||||
const utility::ProcessOutput out = utility::executeProcess(
|
||||
utility::decodeFromUtf8(compilerName), {L"-x", L"c++", L"-v", L"-E", L"/dev/null"});
|
||||
if (out.exitCode == 0)
|
||||
{
|
||||
for (const std::string& s: utility::splitToVector(standardHeaders, '\n'))
|
||||
std::wstring standardHeaders = utility::substrBetween<std::wstring>(
|
||||
out.output, L"#include <...> search starts here:\n", L"\nEnd of search list");
|
||||
|
||||
if (!standardHeaders.empty())
|
||||
{
|
||||
paths.push_back(utility::trim(s));
|
||||
for (const std::wstring& s: utility::splitToVector(standardHeaders, L'\n'))
|
||||
{
|
||||
paths.push_back(utility::trim(s));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
namespace utility
|
||||
{
|
||||
std::vector<std::string> getCxxHeaderPaths(const std::string& compilerName);
|
||||
std::vector<std::wstring> getCxxHeaderPaths(const std::string& compilerName);
|
||||
|
||||
std::vector<FilePath> getWindowsSdkHeaderSearchPaths(ApplicationArchitectureType architectureType);
|
||||
FilePath getWindowsSdkRootPathUsingRegistry(
|
||||
|
||||
@@ -54,28 +54,28 @@ std::vector<FilePath> JavaPathDetectorLinux::doGetPaths() const
|
||||
|
||||
FilePath JavaPathDetectorLinux::getJavaInPath() const
|
||||
{
|
||||
std::string output = utility::executeProcess(L"which", std::vector<std::wstring>{L"java"}).second;
|
||||
|
||||
if (!output.empty())
|
||||
bool ok;
|
||||
FilePath javaPath(utility::searchPath(L"java", ok));
|
||||
if (ok && !javaPath.empty() && javaPath.exists())
|
||||
{
|
||||
output = utility::trim(output);
|
||||
|
||||
FilePath javaPath(output);
|
||||
if (!javaPath.empty() && javaPath.exists())
|
||||
{
|
||||
return javaPath;
|
||||
}
|
||||
return javaPath;
|
||||
}
|
||||
|
||||
return FilePath();
|
||||
}
|
||||
|
||||
FilePath JavaPathDetectorLinux::readLink(const FilePath& path) const
|
||||
{
|
||||
FilePath javaPath(utility::executeProcess(L"readlink", std::vector<std::wstring>{L"-f", path.wstr()}).second);
|
||||
if (!javaPath.empty())
|
||||
const utility::ProcessOutput out = utility::executeProcess(
|
||||
L"readlink", std::vector<std::wstring> {L"-f", path.wstr()});
|
||||
|
||||
if (out.exitCode == 0 && !out.output.empty())
|
||||
{
|
||||
return javaPath;
|
||||
FilePath javaPath(utility::trim(out.output));
|
||||
|
||||
if (!javaPath.empty())
|
||||
{
|
||||
return javaPath;
|
||||
}
|
||||
}
|
||||
return FilePath();
|
||||
}
|
||||
@@ -113,7 +113,9 @@ FilePath JavaPathDetectorLinux::getJavaInJavaHome() const
|
||||
|
||||
bool JavaPathDetectorLinux::checkVersion(const FilePath& path) const
|
||||
{
|
||||
std::string output = utility::executeProcess(path.wstr(), std::vector<std::wstring>{L"-version"}).second;
|
||||
const utility::ProcessOutput out = utility::executeProcess(path.wstr(), {L"-version"});
|
||||
|
||||
return output.find(m_javaVersion) != std::string::npos;
|
||||
return (
|
||||
(out.exitCode == 0) &&
|
||||
(out.output.find(utility::decodeFromUtf8(m_javaVersion)) != std::string::npos));
|
||||
}
|
||||
|
||||
@@ -14,21 +14,22 @@ std::vector<FilePath> JavaPathDetectorMac::doGetPaths() const
|
||||
std::vector<FilePath> paths;
|
||||
FilePath javaPath;
|
||||
|
||||
std::string output = utility::executeProcess(L"/usr/libexec/java_home", std::vector<std::wstring>{}).second;
|
||||
const utility::ProcessOutput out = utility::executeProcess(L"/usr/libexec/java_home", {});
|
||||
|
||||
const std::wstring output = out.exitCode == 0 ? utility::trim(out.output) : L"";
|
||||
if (!output.empty())
|
||||
{
|
||||
javaPath = FilePath(utility::trim(output) + "/../MacOS/libjli.dylib").makeCanonical();
|
||||
javaPath = FilePath(output + L"/../MacOS/libjli.dylib").makeCanonical();
|
||||
}
|
||||
|
||||
if (!javaPath.exists() && output.size())
|
||||
if (!javaPath.exists() && !output.empty())
|
||||
{
|
||||
javaPath = FilePath(utility::trim(output) + "/lib/libjli.dylib");
|
||||
javaPath = FilePath(output + L"/lib/libjli.dylib");
|
||||
}
|
||||
|
||||
if (!javaPath.exists() && output.size())
|
||||
if (!javaPath.exists() && !output.empty())
|
||||
{
|
||||
javaPath = FilePath(utility::trim(output) + "/jre/lib/jli/libjli.dylib");
|
||||
javaPath = FilePath(output + L"/jre/lib/jli/libjli.dylib");
|
||||
}
|
||||
|
||||
if (!javaPath.exists())
|
||||
@@ -36,9 +37,9 @@ std::vector<FilePath> JavaPathDetectorMac::doGetPaths() const
|
||||
javaPath = FilePath(L"/usr/lib/libjli.dylib");
|
||||
}
|
||||
|
||||
if (!javaPath.exists() && output.size())
|
||||
if (!javaPath.exists() && !output.empty())
|
||||
{
|
||||
javaPath = FilePath(utility::trim(output) + "/jre/lib/server/libjvm.dylib");
|
||||
javaPath = FilePath(output + L"/jre/lib/server/libjvm.dylib");
|
||||
}
|
||||
|
||||
if (!javaPath.exists())
|
||||
|
||||
@@ -7,12 +7,17 @@ MavenPathDetectorUnix::MavenPathDetectorUnix(): PathDetector("Maven for Unix") {
|
||||
|
||||
std::vector<FilePath> MavenPathDetectorUnix::doGetPaths() const
|
||||
{
|
||||
FilePath mavenPath(utility::executeProcess(L"which", std::vector<std::wstring>{L"mvn"}).second);
|
||||
|
||||
std::vector<FilePath> paths;
|
||||
if (mavenPath.exists())
|
||||
|
||||
const utility::ProcessOutput out = utility::executeProcess(L"which", {L"mvn"});
|
||||
|
||||
if (out.exitCode == 0)
|
||||
{
|
||||
paths.push_back(mavenPath);
|
||||
FilePath mavenPath(out.output);
|
||||
if (mavenPath.exists())
|
||||
{
|
||||
paths.push_back(mavenPath);
|
||||
}
|
||||
}
|
||||
return paths;
|
||||
}
|
||||
|
||||
@@ -7,10 +7,11 @@ MavenPathDetectorWindows::MavenPathDetectorWindows(): PathDetector("Maven for Wi
|
||||
|
||||
std::vector<FilePath> MavenPathDetectorWindows::doGetPaths() const
|
||||
{
|
||||
FilePath mavenPath(utility::executeProcess(L"cmd", std::vector<std::wstring>{L"/c where mvn.cmd && exit"}).second);
|
||||
|
||||
std::vector<FilePath> paths;
|
||||
if (mavenPath.exists())
|
||||
|
||||
bool ok;
|
||||
FilePath mavenPath(utility::searchPath(L"mvn.cmd", ok));
|
||||
if (ok && !mavenPath.empty() && mavenPath.exists())
|
||||
{
|
||||
paths.push_back(mavenPath);
|
||||
}
|
||||
|
||||
+155
-224
@@ -1,284 +1,215 @@
|
||||
#include "utilityApp.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <mutex>
|
||||
#include <set>
|
||||
|
||||
#include <QProcess>
|
||||
#include <QRegularExpression>
|
||||
#include <QSysInfo>
|
||||
#include <QThread>
|
||||
#include <qprocessordetection.h>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <boost/asio/io_service.hpp>
|
||||
#include <boost/asio/read.hpp>
|
||||
#include <boost/process.hpp>
|
||||
#include <boost/process/async_pipe.hpp>
|
||||
#include <boost/process/child.hpp>
|
||||
#include <boost/process/io.hpp>
|
||||
#include <boost/process/search_path.hpp>
|
||||
#include <boost/process/start_dir.hpp>
|
||||
|
||||
#include "AppPath.h"
|
||||
#include "ApplicationSettings.h"
|
||||
#include "UserPaths.h"
|
||||
#include <QThread>
|
||||
|
||||
#include "ScopedFunctor.h"
|
||||
#include "logging.h"
|
||||
#include "utilityString.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
void logProcessStreams(QProcess& process, std::wstring& outputBuffer, std::wstring& errorBuffer)
|
||||
{
|
||||
{
|
||||
outputBuffer += QString(process.readAllStandardOutput()).toStdWString();
|
||||
std::vector<std::wstring> outputLines = utility::split<std::vector<std::wstring>>(
|
||||
outputBuffer, L"\n");
|
||||
for (size_t i = 0; i < outputLines.size() - 1; i++)
|
||||
{
|
||||
if (outputLines[i].back() == L'\r')
|
||||
{
|
||||
outputLines[i].pop_back();
|
||||
}
|
||||
LOG_INFO_BARE(L"Process output: " + outputLines[i]);
|
||||
}
|
||||
outputBuffer = outputLines.back();
|
||||
}
|
||||
{
|
||||
errorBuffer += QString(process.readAllStandardError()).toStdWString();
|
||||
std::vector<std::wstring> errorLines = utility::split<std::vector<std::wstring>>(
|
||||
errorBuffer, L"\n");
|
||||
for (size_t i = 0; i < errorLines.size() - 1; i++)
|
||||
{
|
||||
if (errorLines[i].back() == L'\r')
|
||||
{
|
||||
errorLines[i].pop_back();
|
||||
}
|
||||
LOG_ERROR_BARE(L"Process error: " + errorLines[i]);
|
||||
}
|
||||
errorBuffer = errorLines.back();
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace utility
|
||||
{
|
||||
std::mutex s_runningProcessesMutex;
|
||||
std::set<QProcess*> s_runningProcesses;
|
||||
std::set<std::shared_ptr<boost::process::child>> s_runningProcesses;
|
||||
} // namespace utility
|
||||
|
||||
std::pair<int, std::string> utility::executeProcess(
|
||||
const std::wstring& commandPath,
|
||||
const std::vector<std::wstring>& commandArguments,
|
||||
const FilePath& workingDirectory,
|
||||
const int timeout)
|
||||
std::wstring utility::searchPath(const std::wstring& bin, bool& ok)
|
||||
{
|
||||
QProcess process;
|
||||
process.setProcessChannelMode(QProcess::MergedChannels);
|
||||
|
||||
if (!workingDirectory.empty())
|
||||
ok = false;
|
||||
std::wstring r = boost::process::search_path(bin).generic_wstring();
|
||||
if (!r.empty())
|
||||
{
|
||||
process.setWorkingDirectory(QString::fromStdWString(workingDirectory.wstr()));
|
||||
ok = true;
|
||||
return r;
|
||||
}
|
||||
|
||||
QString command = QString::fromStdWString(commandPath);
|
||||
for (const std::wstring& commandArgument: commandArguments)
|
||||
{
|
||||
command += QString::fromStdWString(L" " + commandArgument);
|
||||
}
|
||||
|
||||
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
||||
QStringList envlist = env.toStringList();
|
||||
envlist.replaceInStrings(
|
||||
QRegularExpression(QStringLiteral("^(?i)PATH=(.*)")),
|
||||
QStringLiteral("PATH=/opt/local/bin:/usr/local/bin:$HOME/bin:\\1"));
|
||||
process.setEnvironment(envlist);
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(s_runningProcessesMutex);
|
||||
process.start(command);
|
||||
s_runningProcesses.insert(&process);
|
||||
}
|
||||
|
||||
process.waitForFinished(timeout);
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(s_runningProcessesMutex);
|
||||
s_runningProcesses.erase(&process);
|
||||
}
|
||||
|
||||
// QProcess::ProcessError error = process.error();
|
||||
|
||||
const std::string processoutput = process.readAll().toStdString();
|
||||
const int exitCode = process.exitCode();
|
||||
process.close();
|
||||
|
||||
return std::make_pair(exitCode, utility::trim(processoutput));
|
||||
return bin;
|
||||
}
|
||||
|
||||
std::string utility::executeProcessUntilNoOutput(
|
||||
const std::wstring& commandPath,
|
||||
const std::vector<std::wstring>& commandArguments,
|
||||
const FilePath& workingDirectory,
|
||||
const int waitTime)
|
||||
std::wstring utility::searchPath(const std::wstring& bin)
|
||||
{
|
||||
QProcess process;
|
||||
process.setProcessChannelMode(QProcess::MergedChannels);
|
||||
bool ok;
|
||||
return searchPath(bin, ok);
|
||||
}
|
||||
|
||||
if (!workingDirectory.empty())
|
||||
utility::ProcessOutput utility::executeProcess(
|
||||
const std::wstring& command,
|
||||
const std::vector<std::wstring>& arguments,
|
||||
const FilePath& workingDirectory,
|
||||
const bool waitUntilNoOutput,
|
||||
const int timeout,
|
||||
bool logProcessOutput)
|
||||
{
|
||||
std::string output = "";
|
||||
int exitCode = 255;
|
||||
try
|
||||
{
|
||||
process.setWorkingDirectory(QString::fromStdWString(workingDirectory.wstr()));
|
||||
}
|
||||
boost::asio::io_service ios;
|
||||
boost::process::async_pipe ap(ios);
|
||||
|
||||
QString command = QString::fromStdWString(commandPath);
|
||||
for (const std::wstring& commandArgument: commandArguments)
|
||||
{
|
||||
command += QString::fromStdWString(L" " + commandArgument);
|
||||
}
|
||||
std::shared_ptr<boost::process::child> process;
|
||||
|
||||
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
||||
QStringList envlist = env.toStringList();
|
||||
envlist.replaceInStrings(
|
||||
QRegularExpression(QStringLiteral("^(?i)PATH=(.*)")),
|
||||
QStringLiteral("PATH=/opt/local/bin:/usr/local/bin:$HOME/bin:\\1"));
|
||||
process.setEnvironment(envlist);
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(s_runningProcessesMutex);
|
||||
process.start(command);
|
||||
s_runningProcesses.insert(&process);
|
||||
}
|
||||
|
||||
std::string processoutput = "";
|
||||
while (!process.waitForFinished(waitTime))
|
||||
{
|
||||
const std::string currentOutput = process.readAll().toStdString();
|
||||
if (currentOutput.empty())
|
||||
boost::process::environment env = boost::this_process::environment();
|
||||
std::vector<std::string> previousPath = env["PATH"].to_vector();
|
||||
env["PATH"] = {"/opt/local/bin", "/usr/local/bin", "$HOME/bin"};
|
||||
for (const std::string& entry: previousPath)
|
||||
{
|
||||
LOG_WARNING(
|
||||
"Canceling process because it did not generate any output during the last " +
|
||||
std::to_string(waitTime / 1000) + " seconds.");
|
||||
break;
|
||||
env["PATH"].append(entry);
|
||||
}
|
||||
|
||||
if (workingDirectory.empty())
|
||||
{
|
||||
process = std::make_shared<boost::process::child>(
|
||||
searchPath(command),
|
||||
boost::process::args(arguments),
|
||||
env,
|
||||
boost::process::std_in.close(),
|
||||
(boost::process::std_out & boost::process::std_err) > ap);
|
||||
}
|
||||
else
|
||||
{
|
||||
processoutput += currentOutput;
|
||||
process = std::make_shared<boost::process::child>(
|
||||
searchPath(command),
|
||||
boost::process::args(arguments),
|
||||
boost::process::start_dir(workingDirectory.wstr()),
|
||||
env,
|
||||
boost::process::std_in.close(),
|
||||
(boost::process::std_out & boost::process::std_err) > ap);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(s_runningProcessesMutex);
|
||||
s_runningProcesses.erase(&process);
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(s_runningProcessesMutex);
|
||||
s_runningProcesses.insert(process);
|
||||
}
|
||||
|
||||
processoutput += process.readAll().toStdString();
|
||||
process.close();
|
||||
processoutput = utility::trim(processoutput);
|
||||
|
||||
return processoutput;
|
||||
}
|
||||
|
||||
int utility::executeProcessAndGetExitCode(
|
||||
const std::wstring& commandPath,
|
||||
const std::vector<std::wstring>& commandArguments,
|
||||
const FilePath& workingDirectory,
|
||||
const int timeout,
|
||||
bool logProcessOutput,
|
||||
std::wstring* errorMessage)
|
||||
{
|
||||
bool finished = false;
|
||||
|
||||
QProcess process;
|
||||
|
||||
QObject::connect(
|
||||
&process, &QProcess::errorOccurred, [&finished, errorMessage](QProcess::ProcessError error) {
|
||||
finished = true;
|
||||
if (errorMessage != nullptr)
|
||||
{
|
||||
switch (error)
|
||||
{
|
||||
case QProcess::FailedToStart:
|
||||
*errorMessage = L"File not found or resource error occurred.";
|
||||
break;
|
||||
case QProcess::Crashed:
|
||||
*errorMessage = L"Process crashed.";
|
||||
break;
|
||||
case QProcess::Timedout:
|
||||
*errorMessage = L"Process timed out.";
|
||||
break;
|
||||
case QProcess::ReadError:
|
||||
*errorMessage = L"A read error occurred while executing process.";
|
||||
break;
|
||||
case QProcess::WriteError:
|
||||
*errorMessage = L"A write error occurred while executing process.";
|
||||
break;
|
||||
case QProcess::UnknownError:
|
||||
*errorMessage = L"An unknown error occurred while executing process.";
|
||||
break;
|
||||
}
|
||||
};
|
||||
ScopedFunctor remover([process]() {
|
||||
std::lock_guard<std::mutex> lock(s_runningProcessesMutex);
|
||||
s_runningProcesses.erase(process);
|
||||
});
|
||||
|
||||
QObject::connect(
|
||||
&process,
|
||||
static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished),
|
||||
[&finished](int exitCode, QProcess::ExitStatus exitStatus) { finished = true; });
|
||||
bool outputReceived = false;
|
||||
std::vector<char> buf(128);
|
||||
auto stdOutBuffer = boost::asio::buffer(buf);
|
||||
std::string logBuffer;
|
||||
|
||||
std::function<void(const boost::system::error_code& ec, std::size_t n)> onStdOut =
|
||||
[&output, &buf, &stdOutBuffer, &ap, &onStdOut, &outputReceived, &logBuffer, logProcessOutput](
|
||||
const boost::system::error_code& ec, std::size_t size) {
|
||||
std::string text;
|
||||
text.reserve(size);
|
||||
text.insert(text.end(), buf.begin(), buf.begin() + size);
|
||||
|
||||
if (!workingDirectory.empty())
|
||||
{
|
||||
process.setWorkingDirectory(QString::fromStdWString(workingDirectory.wstr()));
|
||||
}
|
||||
if (!text.empty())
|
||||
{
|
||||
outputReceived = true;
|
||||
}
|
||||
|
||||
QString command = QString::fromStdWString(commandPath);
|
||||
for (const std::wstring& commandArgument: commandArguments)
|
||||
{
|
||||
command += QString::fromStdWString(L" " + commandArgument);
|
||||
}
|
||||
|
||||
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
||||
QStringList envlist = env.toStringList();
|
||||
envlist.replaceInStrings(
|
||||
QRegularExpression(QStringLiteral("^(?i)PATH=(.*)")),
|
||||
QStringLiteral("PATH=/opt/local/bin:/usr/local/bin:$HOME/bin:\\1"));
|
||||
process.setEnvironment(envlist);
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(s_runningProcessesMutex);
|
||||
process.start(command);
|
||||
s_runningProcesses.insert(&process);
|
||||
}
|
||||
|
||||
{
|
||||
std::wstring outputBuffer;
|
||||
std::wstring errorBuffer;
|
||||
if (timeout == -1)
|
||||
{
|
||||
while (!finished && !process.waitForFinished(1000))
|
||||
{
|
||||
output += text;
|
||||
if (logProcessOutput)
|
||||
{
|
||||
logProcessStreams(process, outputBuffer, errorBuffer);
|
||||
logBuffer += text;
|
||||
const bool isEndOfLine = (logBuffer.back() == '\n');
|
||||
const std::vector<std::string> lines = utility::splitToVector(logBuffer, "\n");
|
||||
for (size_t i = 0; i < lines.size() - (isEndOfLine ? 0 : 1); i++)
|
||||
{
|
||||
LOG_INFO_BARE("Process output: " + lines[i]);
|
||||
}
|
||||
if (isEndOfLine)
|
||||
{
|
||||
logBuffer.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
logBuffer = lines.back();
|
||||
}
|
||||
}
|
||||
if (!ec)
|
||||
{
|
||||
boost::asio::async_read(ap, stdOutBuffer, onStdOut);
|
||||
}
|
||||
};
|
||||
|
||||
boost::asio::async_read(ap, stdOutBuffer, onStdOut);
|
||||
ios.run();
|
||||
|
||||
if (timeout > 0)
|
||||
{
|
||||
if (waitUntilNoOutput)
|
||||
{
|
||||
while (!process->wait_for(std::chrono::milliseconds(timeout)))
|
||||
{
|
||||
if (!outputReceived)
|
||||
{
|
||||
LOG_WARNING(
|
||||
"Canceling process because it did not generate any output during the "
|
||||
"last " +
|
||||
std::to_string(timeout / 1000) + " seconds.");
|
||||
process->terminate();
|
||||
break;
|
||||
}
|
||||
outputReceived = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!process->wait_for(std::chrono::milliseconds(timeout)))
|
||||
{
|
||||
LOG_WARNING(
|
||||
"Canceling process because it timed out after " +
|
||||
std::to_string(timeout / 1000) + " seconds.");
|
||||
process->terminate();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!finished)
|
||||
{
|
||||
process.waitForFinished(timeout);
|
||||
}
|
||||
process->wait();
|
||||
}
|
||||
|
||||
if (logProcessOutput)
|
||||
{
|
||||
logProcessStreams(process, outputBuffer, errorBuffer);
|
||||
for (const std::string& line: utility::splitToVector(logBuffer, "\n"))
|
||||
{
|
||||
LOG_INFO_BARE("Process output: " + line);
|
||||
}
|
||||
}
|
||||
|
||||
exitCode = process->exit_code();
|
||||
}
|
||||
catch (const boost::process::process_error& e)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(s_runningProcessesMutex);
|
||||
s_runningProcesses.erase(&process);
|
||||
ProcessOutput ret;
|
||||
ret.error = utility::decodeFromUtf8(e.code().message());
|
||||
ret.exitCode = e.code().value();
|
||||
LOG_ERROR_BARE(L"Process error: " + ret.error);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
const int exitCode = process.exitCode();
|
||||
process.close();
|
||||
return exitCode;
|
||||
ProcessOutput ret;
|
||||
ret.output = utility::trim(utility::decodeFromUtf8(output));
|
||||
ret.exitCode = exitCode;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void utility::killRunningProcesses()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(s_runningProcessesMutex);
|
||||
for (QProcess* process: s_runningProcesses)
|
||||
for (std::shared_ptr<boost::process::child> process: s_runningProcesses)
|
||||
{
|
||||
process->kill();
|
||||
process->terminate();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -307,4 +238,4 @@ std::string utility::getOsTypeString()
|
||||
break;
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,25 +9,27 @@
|
||||
|
||||
namespace utility
|
||||
{
|
||||
std::pair<int, std::string> executeProcess(
|
||||
const std::wstring& commandPath,
|
||||
const std::vector<std::wstring>& commandArguments,
|
||||
const FilePath& workingDirectory = FilePath(),
|
||||
const int timeout = 30000);
|
||||
std::string executeProcessUntilNoOutput(
|
||||
const std::wstring& commandPath,
|
||||
const std::vector<std::wstring>& commandArguments,
|
||||
const FilePath& workingDirectory,
|
||||
int waitTime = 10000);
|
||||
int executeProcessAndGetExitCode(
|
||||
const std::wstring& commandPath,
|
||||
const std::vector<std::wstring>& commandArguments,
|
||||
struct ProcessOutput
|
||||
{
|
||||
std::wstring output;
|
||||
std::wstring error;
|
||||
int exitCode;
|
||||
};
|
||||
|
||||
std::wstring searchPath(const std::wstring& bin, bool& ok);
|
||||
|
||||
std::wstring searchPath(const std::wstring& bin);
|
||||
|
||||
ProcessOutput executeProcess(
|
||||
const std::wstring& command,
|
||||
const std::vector<std::wstring>& arguments,
|
||||
const FilePath& workingDirectory = FilePath(),
|
||||
const bool waitUntilNoOutput = false,
|
||||
const int timeout = 30000,
|
||||
bool logProcessOutput = false,
|
||||
std::wstring* errorMessage = nullptr);
|
||||
bool logProcessOutput = false);
|
||||
|
||||
void killRunningProcesses();
|
||||
|
||||
int getIdealThreadCount();
|
||||
|
||||
constexpr OsType getOsType()
|
||||
|
||||
@@ -104,12 +104,8 @@ std::wstring mavenGenerateSources(
|
||||
auto args = getMavenArgs(settingsFilePath);
|
||||
args.push_back(L"generate-sources");
|
||||
|
||||
std::shared_ptr<TextAccess> outputAccess = TextAccess::createFromString(
|
||||
utility::executeProcessUntilNoOutput(
|
||||
mavenPath.wstr(),
|
||||
args,
|
||||
projectDirectoryPath,
|
||||
60000));
|
||||
std::shared_ptr<TextAccess> outputAccess = TextAccess::createFromString(utility::encodeToUtf8(
|
||||
utility::executeProcess(mavenPath.wstr(), args, projectDirectoryPath, true, 60000).output));
|
||||
|
||||
if (outputAccess->isEmpty())
|
||||
{
|
||||
@@ -132,12 +128,8 @@ bool mavenCopyDependencies(
|
||||
args.push_back(L"dependency:copy-dependencies");
|
||||
args.push_back(L"-DoutputDirectory=" + outputDirectoryPath.wstr());
|
||||
|
||||
std::shared_ptr<TextAccess> outputAccess = TextAccess::createFromString(
|
||||
utility::executeProcessUntilNoOutput(
|
||||
mavenPath.wstr(),
|
||||
args,
|
||||
projectDirectoryPath,
|
||||
60000));
|
||||
std::shared_ptr<TextAccess> outputAccess = TextAccess::createFromString(utility::encodeToUtf8(
|
||||
utility::executeProcess(mavenPath.wstr(), args, projectDirectoryPath, true, 60000).output));
|
||||
|
||||
const std::wstring errorMessage = getErrorMessageFromMavenOutput(outputAccess);
|
||||
if (!errorMessage.empty())
|
||||
@@ -165,12 +157,8 @@ std::vector<FilePath> mavenGetAllDirectoriesFromEffectivePom(
|
||||
args.push_back(L"help:effective-pom");
|
||||
args.push_back(L"-Doutput=" + outputPath.wstr());
|
||||
|
||||
std::shared_ptr<TextAccess> outputAccess = TextAccess::createFromString(
|
||||
utility::executeProcessUntilNoOutput(
|
||||
mavenPath.wstr(),
|
||||
args,
|
||||
projectDirectoryPath,
|
||||
60000));
|
||||
std::shared_ptr<TextAccess> outputAccess = TextAccess::createFromString(utility::encodeToUtf8(
|
||||
utility::executeProcess(mavenPath.wstr(), args, projectDirectoryPath, true, 60000).output));
|
||||
|
||||
const std::wstring errorMessage = getErrorMessageFromMavenOutput(outputAccess);
|
||||
if (!errorMessage.empty())
|
||||
|
||||
@@ -49,25 +49,28 @@ std::set<FilePath> SourceGroupPythonEmpty::getAllSourceFilePaths() const
|
||||
std::vector<std::shared_ptr<IndexerCommand>> SourceGroupPythonEmpty::getIndexerCommands(
|
||||
const RefreshInfo& info) const
|
||||
{
|
||||
std::wstring args = L"";
|
||||
std::vector<std::wstring> args;
|
||||
args.push_back(L"index");
|
||||
|
||||
args += L" --source-file-path=%{SOURCE_FILE_PATH}";
|
||||
args += L" --database-file-path=%{DATABASE_FILE_PATH}";
|
||||
args.push_back(L"--source-file-path");
|
||||
args.push_back(L"%{SOURCE_FILE_PATH}");
|
||||
args.push_back(L"--database-file-path");
|
||||
args.push_back(L"%{DATABASE_FILE_PATH}");
|
||||
|
||||
if (!m_settings->getEnvironmentPath().empty())
|
||||
{
|
||||
args += L" --environment-path=\"" +
|
||||
m_settings->getEnvironmentPathExpandedAndAbsolute().wstr() + L"\"";
|
||||
args.push_back(L"--environment-path");
|
||||
args.push_back(m_settings->getEnvironmentPathExpandedAndAbsolute().wstr());
|
||||
}
|
||||
|
||||
if (ApplicationSettings::getInstance()->getVerboseIndexerLoggingEnabled())
|
||||
{
|
||||
args += L" --verbose";
|
||||
args.push_back(L"--verbose");
|
||||
}
|
||||
|
||||
if (info.shallow)
|
||||
{
|
||||
args += L" --shallow";
|
||||
args.push_back(L"--shallow");
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<IndexerCommand>> indexerCommands;
|
||||
@@ -77,8 +80,8 @@ std::vector<std::shared_ptr<IndexerCommand>> SourceGroupPythonEmpty::getIndexerC
|
||||
{
|
||||
indexerCommands.push_back(std::make_shared<IndexerCommandCustom>(
|
||||
INDEXER_COMMAND_PYTHON,
|
||||
L"\"" + ResourcePaths::getPythonPath().wstr() +
|
||||
L"SourcetrailPythonIndexer\" index" + args,
|
||||
ResourcePaths::getPythonIndexerFilePath().wstr(),
|
||||
args,
|
||||
m_settings->getProjectSettings()->getProjectFilePath(),
|
||||
m_settings->getProjectSettings()->getTempDBFilePath(),
|
||||
std::to_wstring(SqliteIndexStorage::getStorageVersion()),
|
||||
|
||||
@@ -56,28 +56,38 @@ std::shared_ptr<TestStorage> parseCode(std::string code)
|
||||
const std::set<FilePathFilter> includeFilters;
|
||||
const FilePath workingDirectory(L".");
|
||||
|
||||
std::wstring args = L"";
|
||||
args += L" --source-file-path=%{SOURCE_FILE_PATH}";
|
||||
args += L" --database-file-path=%{DATABASE_FILE_PATH}";
|
||||
args += L" --shallow";
|
||||
std::vector<std::wstring> args;
|
||||
args.push_back(L"index");
|
||||
args.push_back(L"--source-file-path");
|
||||
args.push_back(L"%{SOURCE_FILE_PATH}");
|
||||
args.push_back(L"--database-file-path");
|
||||
args.push_back(L"%{DATABASE_FILE_PATH}");
|
||||
args.push_back(L"--shallow");
|
||||
|
||||
std::shared_ptr<IndexerCommandCustom> indexerCommand = std::make_shared<IndexerCommandCustom>(
|
||||
INDEXER_COMMAND_PYTHON,
|
||||
L"\"" +
|
||||
FilePath("../app").getConcatenated(ResourcePaths::getPythonPath()).makeAbsolute().wstr() +
|
||||
L"SourcetrailPythonIndexer\" index" + args,
|
||||
FilePath("../app")
|
||||
.getConcatenated(ResourcePaths::getPythonIndexerFilePath())
|
||||
.makeAbsolute()
|
||||
.makeCanonical()
|
||||
.wstr(),
|
||||
args,
|
||||
rootPath,
|
||||
tempDbPath,
|
||||
std::to_wstring(SqliteIndexStorage::getStorageVersion()),
|
||||
sourceFilePath,
|
||||
true);
|
||||
|
||||
std::wstring errorMessage;
|
||||
const int result = utility::executeProcessAndGetExitCode(
|
||||
indexerCommand->getCustomCommand(), {}, rootPath, -1, true, &errorMessage);
|
||||
const utility::ProcessOutput out = utility::executeProcess(
|
||||
indexerCommand->getCommand(), indexerCommand->getArguments(), rootPath, false, -1, true);
|
||||
|
||||
REQUIRE(result == 0);
|
||||
REQUIRE(errorMessage.empty());
|
||||
if (!out.error.empty())
|
||||
{
|
||||
FAIL(
|
||||
"Error occurred while running the indexer: \"" + utility::encodeToUtf8(out.error) +
|
||||
"\". Process output was: \"" + utility::encodeToUtf8(out.output) + "\"");
|
||||
}
|
||||
REQUIRE(out.exitCode == 0);
|
||||
}
|
||||
|
||||
std::shared_ptr<TestStorage> testStorage;
|
||||
|
||||
@@ -148,9 +148,15 @@ std::wstring indexerCommandCustomToString(
|
||||
std::shared_ptr<const IndexerCommandCustom> indexerCommand, const FilePath& baseDirectory)
|
||||
{
|
||||
std::wstring result;
|
||||
result += L"SourceFilePath: \"" +
|
||||
result += L"IndexerCommandCustom\n";
|
||||
result += L"\tSourceFilePath: \"" +
|
||||
indexerCommand->getSourceFilePath().getRelativeTo(baseDirectory).wstr() + L"\"\n";
|
||||
result += L"\tCustom Command: \"" + indexerCommand->getCustomCommand() + L"\"\n";
|
||||
result += L"\tCustom Command: \"" + indexerCommand->getCommand() + L"\"\n";
|
||||
result += L"\tArguments:\n";
|
||||
for (const std::wstring& argument: indexerCommand->getArguments())
|
||||
{
|
||||
result += L"\t\t\"" + argument + L"\"\n";
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user