From 3c1638da2544ecfdfac22dde665d146cd9e44619 Mon Sep 17 00:00:00 2001 From: Malte Langkabel Date: Mon, 22 Feb 2021 16:00:32 +0100 Subject: [PATCH] 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 --- .../expected_output/output_unix.txt | 12 +- .../expected_output/output_windows.txt | 12 +- script/download_python_indexer.sh | 1 + src/app/main.cpp | 5 + src/lib/app/paths/ResourcePaths.cpp | 12 +- src/lib/app/paths/ResourcePaths.h | 3 +- src/lib/data/indexer/IndexerCommandCustom.cpp | 53 ++- src/lib/data/indexer/IndexerCommandCustom.h | 14 +- src/lib/data/indexer/TaskBuildIndex.cpp | 11 +- .../indexer/TaskExecuteCustomCommands.cpp | 26 +- src/lib/project/SourceGroupCustomCommand.cpp | 4 +- .../content/QtProjectWizardContentSelect.cpp | 25 +- ...jectWizardContentPathPythonEnvironment.cpp | 20 +- .../cxx_header/CxxFrameworkPathDetector.cpp | 8 +- .../cxx_header/CxxHeaderPathDetector.cpp | 6 +- .../cxx_header/CxxVs15HeaderPathDetector.cpp | 37 +- .../cxx_header/utilityCxxHeaderDetection.cpp | 25 +- .../cxx_header/utilityCxxHeaderDetection.h | 2 +- .../java_runtime/JavaPathDetectorLinux.cpp | 34 +- .../java_runtime/JavaPathDetectorMac.cpp | 17 +- .../MavenPathDetectorUnix.cpp | 13 +- .../MavenPathDetectorWindows.cpp | 7 +- src/lib_gui/utility/utilityApp.cpp | 379 +++++++----------- src/lib_gui/utility/utilityApp.h | 32 +- src/lib_java/utility/utilityMaven.cpp | 24 +- .../project/SourceGroupPythonEmpty.cpp | 21 +- src/test/PythonIndexerTestSuite.cpp | 34 +- src/test/SourceGroupTestSuite.cpp | 10 +- 28 files changed, 430 insertions(+), 417 deletions(-) diff --git a/bin/test/data/SourceGroupTestSuite/custom_command/expected_output/output_unix.txt b/bin/test/data/SourceGroupTestSuite/custom_command/expected_output/output_unix.txt index 552d7d1e..d2a054e3 100644 --- a/bin/test/data/SourceGroupTestSuite/custom_command/expected_output/output_unix.txt +++ b/bin/test/data/SourceGroupTestSuite/custom_command/expected_output/output_unix.txt @@ -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: diff --git a/bin/test/data/SourceGroupTestSuite/custom_command/expected_output/output_windows.txt b/bin/test/data/SourceGroupTestSuite/custom_command/expected_output/output_windows.txt index 552d7d1e..d2a054e3 100644 --- a/bin/test/data/SourceGroupTestSuite/custom_command/expected_output/output_windows.txt +++ b/bin/test/data/SourceGroupTestSuite/custom_command/expected_output/output_windows.txt @@ -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: diff --git a/script/download_python_indexer.sh b/script/download_python_indexer.sh index d637494f..16e3be56 100755 --- a/script/download_python_indexer.sh +++ b/script/download_python_indexer.sh @@ -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 diff --git a/src/app/main.cpp b/src/app/main.cpp index 9705bcdc..4ae66d6c 100644 --- a/src/app/main.cpp +++ b/src/app/main.cpp @@ -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) diff --git a/src/lib/app/paths/ResourcePaths.cpp b/src/lib/app/paths/ResourcePaths.cpp index 593a8f75..acb8489c 100644 --- a/src/lib/app/paths/ResourcePaths.cpp +++ b/src/lib/app/paths/ResourcePaths.cpp @@ -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"); +} diff --git a/src/lib/app/paths/ResourcePaths.h b/src/lib/app/paths/ResourcePaths.h index a7fa351d..79b1617f 100644 --- a/src/lib/app/paths/ResourcePaths.h +++ b/src/lib/app/paths/ResourcePaths.h @@ -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 diff --git a/src/lib/data/indexer/IndexerCommandCustom.cpp b/src/lib/data/indexer/IndexerCommandCustom.cpp index bf9759a1..fc131439 100644 --- a/src/lib/data/indexer/IndexerCommandCustom.cpp +++ b/src/lib/data/indexer/IndexerCommandCustom.cpp @@ -11,7 +11,8 @@ IndexerCommandType IndexerCommandCustom::getStaticIndexerCommandType() } IndexerCommandCustom::IndexerCommandCustom( - const std::wstring& customCommand, + const std::wstring& command, + const std::vector& 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& 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 IndexerCommandCustom::getArguments() const +{ + std::vector 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; +} diff --git a/src/lib/data/indexer/IndexerCommandCustom.h b/src/lib/data/indexer/IndexerCommandCustom.h index c0a007be..6b8c4032 100644 --- a/src/lib/data/indexer/IndexerCommandCustom.h +++ b/src/lib/data/indexer/IndexerCommandCustom.h @@ -12,7 +12,8 @@ public: static IndexerCommandType getStaticIndexerCommandType(); IndexerCommandCustom( - const std::wstring& customCommand, + const std::wstring& command, + const std::vector& 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& 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 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 m_arguments; FilePath m_projectFilePath; FilePath m_databaseFilePath; std::wstring m_databaseVersion; diff --git a/src/lib/data/indexer/TaskBuildIndex.cpp b/src/lib/data/indexer/TaskBuildIndex.cpp index 55f597c0..15026ced 100644 --- a/src/lib/data/indexer/TaskBuildIndex.cpp +++ b/src/lib/data/indexer/TaskBuildIndex.cpp @@ -188,22 +188,23 @@ void TaskBuildIndex::runIndexerProcess(int processId, const std::wstring& logFil return; } - const std::wstring commandPath = L"\"" + indexerProcessPath.wstr() + L"\""; std::vector 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)); } diff --git a/src/lib/data/indexer/TaskExecuteCustomCommands.cpp b/src/lib/data/indexer/TaskExecuteCustomCommands.cpp index 0ad359e4..7ca9356e 100644 --- a/src/lib/data/indexer/TaskExecuteCustomCommands.cpp +++ b/src/lib/data/indexer/TaskExecuteCustomCommands.cpp @@ -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 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"."; diff --git a/src/lib/project/SourceGroupCustomCommand.cpp b/src/lib/project/SourceGroupCustomCommand.cpp index 27abf4b8..2dc3bc15 100644 --- a/src/lib/project/SourceGroupCustomCommand.cpp +++ b/src/lib/project/SourceGroupCustomCommand.cpp @@ -42,7 +42,6 @@ std::set SourceGroupCustomCommand::getAllSourceFilePaths() const std::vector> SourceGroupCustomCommand::getIndexerCommands( const RefreshInfo& info) const { - const std::wstring customCommand = m_settings->getCustomCommand(); const bool runInParallel = m_settings->getRunInParallel(); std::vector> indexerCommands; @@ -51,7 +50,8 @@ std::vector> SourceGroupCustomCommand::getIndexe if (info.filesToIndex.find(sourcePath) != info.filesToIndex.end()) { indexerCommands.push_back(std::make_shared( - customCommand, + m_settings->getCustomCommand(), + std::vector {}, m_settings->getProjectSettings()->getProjectFilePath(), m_settings->getProjectSettings()->getTempDBFilePath(), std::to_wstring(SqliteIndexStorage::getStorageVersion()), diff --git a/src/lib_gui/qt/project_wizard/content/QtProjectWizardContentSelect.cpp b/src/lib_gui/qt/project_wizard/content/QtProjectWizardContentSelect.cpp index 7b119896..2f93091a 100644 --- a/src/lib_gui/qt/project_wizard/content/QtProjectWizardContentSelect.cpp +++ b/src/lib_gui/qt/project_wizard/content/QtProjectWizardContentSelect.cpp @@ -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 {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) + " "; + } } } diff --git a/src/lib_gui/qt/project_wizard/content/path/QtProjectWizardContentPathPythonEnvironment.cpp b/src/lib_gui/qt/project_wizard/content/path/QtProjectWizardContentPathPythonEnvironment.cpp index deed2011..0a67eda8 100644 --- a/src/lib_gui/qt/project_wizard/content/path/QtProjectWizardContentPathPythonEnvironment.cpp +++ b/src/lib_gui/qt/project_wizard/content/path/QtProjectWizardContentPathPythonEnvironment.cpp @@ -62,20 +62,20 @@ void QtProjectWizardContentPathPythonEnvironment::onTextChanged(const QString& t { m_resultLabel->setText("Checking validity of Python environment..."); std::thread([=]() { - std::pair out = utility::executeProcess( - ResourcePaths::getPythonPath().wstr().append(L"SourcetrailPythonIndexer"), - std::vector{ - 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 { diff --git a/src/lib_gui/utility/path_detector/cxx_header/CxxFrameworkPathDetector.cpp b/src/lib_gui/utility/path_detector/cxx_header/CxxFrameworkPathDetector.cpp index db7a7b9d..778527b1 100644 --- a/src/lib_gui/utility/path_detector/cxx_header/CxxFrameworkPathDetector.cpp +++ b/src/lib_gui/utility/path_detector/cxx_header/CxxFrameworkPathDetector.cpp @@ -11,14 +11,14 @@ CxxFrameworkPathDetector::CxxFrameworkPathDetector(const std::string& compilerNa std::vector CxxFrameworkPathDetector::doGetPaths() const { - std::vector paths = utility::getCxxHeaderPaths(m_compilerName); + std::vector paths = utility::getCxxHeaderPaths(m_compilerName); std::vector frameworkPaths; - for (const std::string& path: paths) + for (const std::wstring& path: paths) { - if (utility::isPostfix(" (framework directory)", path)) + if (utility::isPostfix(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); diff --git a/src/lib_gui/utility/path_detector/cxx_header/CxxHeaderPathDetector.cpp b/src/lib_gui/utility/path_detector/cxx_header/CxxHeaderPathDetector.cpp index dfb0a56c..71a8f8d5 100644 --- a/src/lib_gui/utility/path_detector/cxx_header/CxxHeaderPathDetector.cpp +++ b/src/lib_gui/utility/path_detector/cxx_header/CxxHeaderPathDetector.cpp @@ -11,12 +11,12 @@ CxxHeaderPathDetector::CxxHeaderPathDetector(const std::string& compilerName) std::vector CxxHeaderPathDetector::doGetPaths() const { - std::vector paths = utility::getCxxHeaderPaths(m_compilerName); + std::vector paths = utility::getCxxHeaderPaths(m_compilerName); std::vector headerSearchPaths; - for (const std::string& path: paths) + for (const std::wstring& path: paths) { - if (!utility::isPostfix(" (framework directory)", path) && + if (!utility::isPostfix(L" (framework directory)", path) && FilePath(path).getCanonical().exists() && !FilePath(path).getCanonical().getConcatenated(L"/stdarg.h").exists()) { diff --git a/src/lib_gui/utility/path_detector/cxx_header/CxxVs15HeaderPathDetector.cpp b/src/lib_gui/utility/path_detector/cxx_header/CxxVs15HeaderPathDetector.cpp index 89459917..b08c60c1 100644 --- a/src/lib_gui/utility/path_detector/cxx_header/CxxVs15HeaderPathDetector.cpp +++ b/src/lib_gui/utility/path_detector/cxx_header/CxxVs15HeaderPathDetector.cpp @@ -20,27 +20,32 @@ std::vector CxxVs15HeaderPathDetector::doGetPaths() const .expandEnvironmentVariables(); if (!expandedPaths.empty()) { - const std::string output = - utility::executeProcess( - expandedPaths[0].wstr(), std::vector {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")); } } } diff --git a/src/lib_gui/utility/path_detector/cxx_header/utilityCxxHeaderDetection.cpp b/src/lib_gui/utility/path_detector/cxx_header/utilityCxxHeaderDetection.cpp index 7f1d36c1..b0a1d810 100644 --- a/src/lib_gui/utility/path_detector/cxx_header/utilityCxxHeaderDetection.cpp +++ b/src/lib_gui/utility/path_detector/cxx_header/utilityCxxHeaderDetection.cpp @@ -9,22 +9,23 @@ namespace utility { -std::vector getCxxHeaderPaths(const std::string& compilerName) +std::vector 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 {L"-x c++", L"-v", L"-E /dev/null"}) - .second; - std::string standardHeaders = utility::substrBetween( - clangOutput, "#include <...> search starts here:\n", "\nEnd of search list"); - std::vector paths; + std::vector 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( + 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)); + } } } diff --git a/src/lib_gui/utility/path_detector/cxx_header/utilityCxxHeaderDetection.h b/src/lib_gui/utility/path_detector/cxx_header/utilityCxxHeaderDetection.h index e958864f..921c322d 100644 --- a/src/lib_gui/utility/path_detector/cxx_header/utilityCxxHeaderDetection.h +++ b/src/lib_gui/utility/path_detector/cxx_header/utilityCxxHeaderDetection.h @@ -9,7 +9,7 @@ namespace utility { -std::vector getCxxHeaderPaths(const std::string& compilerName); +std::vector getCxxHeaderPaths(const std::string& compilerName); std::vector getWindowsSdkHeaderSearchPaths(ApplicationArchitectureType architectureType); FilePath getWindowsSdkRootPathUsingRegistry( diff --git a/src/lib_gui/utility/path_detector/java_runtime/JavaPathDetectorLinux.cpp b/src/lib_gui/utility/path_detector/java_runtime/JavaPathDetectorLinux.cpp index a2491574..b945a52a 100644 --- a/src/lib_gui/utility/path_detector/java_runtime/JavaPathDetectorLinux.cpp +++ b/src/lib_gui/utility/path_detector/java_runtime/JavaPathDetectorLinux.cpp @@ -54,28 +54,28 @@ std::vector JavaPathDetectorLinux::doGetPaths() const FilePath JavaPathDetectorLinux::getJavaInPath() const { - std::string output = utility::executeProcess(L"which", std::vector{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{L"-f", path.wstr()}).second); - if (!javaPath.empty()) + const utility::ProcessOutput out = utility::executeProcess( + L"readlink", std::vector {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{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)); } diff --git a/src/lib_gui/utility/path_detector/java_runtime/JavaPathDetectorMac.cpp b/src/lib_gui/utility/path_detector/java_runtime/JavaPathDetectorMac.cpp index 33c19d40..3f9bb54b 100644 --- a/src/lib_gui/utility/path_detector/java_runtime/JavaPathDetectorMac.cpp +++ b/src/lib_gui/utility/path_detector/java_runtime/JavaPathDetectorMac.cpp @@ -14,21 +14,22 @@ std::vector JavaPathDetectorMac::doGetPaths() const std::vector paths; FilePath javaPath; - std::string output = utility::executeProcess(L"/usr/libexec/java_home", std::vector{}).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 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()) diff --git a/src/lib_gui/utility/path_detector/maven_executable/MavenPathDetectorUnix.cpp b/src/lib_gui/utility/path_detector/maven_executable/MavenPathDetectorUnix.cpp index ca8af480..2460d6cf 100644 --- a/src/lib_gui/utility/path_detector/maven_executable/MavenPathDetectorUnix.cpp +++ b/src/lib_gui/utility/path_detector/maven_executable/MavenPathDetectorUnix.cpp @@ -7,12 +7,17 @@ MavenPathDetectorUnix::MavenPathDetectorUnix(): PathDetector("Maven for Unix") { std::vector MavenPathDetectorUnix::doGetPaths() const { - FilePath mavenPath(utility::executeProcess(L"which", std::vector{L"mvn"}).second); - std::vector 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; } diff --git a/src/lib_gui/utility/path_detector/maven_executable/MavenPathDetectorWindows.cpp b/src/lib_gui/utility/path_detector/maven_executable/MavenPathDetectorWindows.cpp index ac8bf996..c43b21be 100644 --- a/src/lib_gui/utility/path_detector/maven_executable/MavenPathDetectorWindows.cpp +++ b/src/lib_gui/utility/path_detector/maven_executable/MavenPathDetectorWindows.cpp @@ -7,10 +7,11 @@ MavenPathDetectorWindows::MavenPathDetectorWindows(): PathDetector("Maven for Wi std::vector MavenPathDetectorWindows::doGetPaths() const { - FilePath mavenPath(utility::executeProcess(L"cmd", std::vector{L"/c where mvn.cmd && exit"}).second); - std::vector paths; - if (mavenPath.exists()) + + bool ok; + FilePath mavenPath(utility::searchPath(L"mvn.cmd", ok)); + if (ok && !mavenPath.empty() && mavenPath.exists()) { paths.push_back(mavenPath); } diff --git a/src/lib_gui/utility/utilityApp.cpp b/src/lib_gui/utility/utilityApp.cpp index e6c2a2e4..175e67a0 100644 --- a/src/lib_gui/utility/utilityApp.cpp +++ b/src/lib_gui/utility/utilityApp.cpp @@ -1,284 +1,215 @@ #include "utilityApp.h" +#include #include #include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include -#include "AppPath.h" -#include "ApplicationSettings.h" -#include "UserPaths.h" +#include + +#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 outputLines = utility::split>( - 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 errorLines = utility::split>( - 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 s_runningProcesses; +std::set> s_runningProcesses; } // namespace utility -std::pair utility::executeProcess( - const std::wstring& commandPath, - const std::vector& 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 lock(s_runningProcessesMutex); - process.start(command); - s_runningProcesses.insert(&process); - } - - process.waitForFinished(timeout); - { - std::lock_guard 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& 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& 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 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 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 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( + 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( + 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 lock(s_runningProcessesMutex); - s_runningProcesses.erase(&process); - } + { + std::lock_guard 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& 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 lock(s_runningProcessesMutex); + s_runningProcesses.erase(process); }); - QObject::connect( - &process, - static_cast(&QProcess::finished), - [&finished](int exitCode, QProcess::ExitStatus exitStatus) { finished = true; }); + bool outputReceived = false; + std::vector buf(128); + auto stdOutBuffer = boost::asio::buffer(buf); + std::string logBuffer; + std::function 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 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 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 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 lock(s_runningProcessesMutex); - for (QProcess* process: s_runningProcesses) + for (std::shared_ptr process: s_runningProcesses) { - process->kill(); + process->terminate(); } } @@ -307,4 +238,4 @@ std::string utility::getOsTypeString() break; } return "unknown"; -} \ No newline at end of file +} diff --git a/src/lib_gui/utility/utilityApp.h b/src/lib_gui/utility/utilityApp.h index 9835b814..d46bbf48 100644 --- a/src/lib_gui/utility/utilityApp.h +++ b/src/lib_gui/utility/utilityApp.h @@ -9,25 +9,27 @@ namespace utility { -std::pair executeProcess( - const std::wstring& commandPath, - const std::vector& commandArguments, - const FilePath& workingDirectory = FilePath(), - const int timeout = 30000); -std::string executeProcessUntilNoOutput( - const std::wstring& commandPath, - const std::vector& commandArguments, - const FilePath& workingDirectory, - int waitTime = 10000); -int executeProcessAndGetExitCode( - const std::wstring& commandPath, - const std::vector& 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& 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() diff --git a/src/lib_java/utility/utilityMaven.cpp b/src/lib_java/utility/utilityMaven.cpp index 0403db80..acd8b16f 100644 --- a/src/lib_java/utility/utilityMaven.cpp +++ b/src/lib_java/utility/utilityMaven.cpp @@ -104,12 +104,8 @@ std::wstring mavenGenerateSources( auto args = getMavenArgs(settingsFilePath); args.push_back(L"generate-sources"); - std::shared_ptr outputAccess = TextAccess::createFromString( - utility::executeProcessUntilNoOutput( - mavenPath.wstr(), - args, - projectDirectoryPath, - 60000)); + std::shared_ptr 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 outputAccess = TextAccess::createFromString( - utility::executeProcessUntilNoOutput( - mavenPath.wstr(), - args, - projectDirectoryPath, - 60000)); + std::shared_ptr 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 mavenGetAllDirectoriesFromEffectivePom( args.push_back(L"help:effective-pom"); args.push_back(L"-Doutput=" + outputPath.wstr()); - std::shared_ptr outputAccess = TextAccess::createFromString( - utility::executeProcessUntilNoOutput( - mavenPath.wstr(), - args, - projectDirectoryPath, - 60000)); + std::shared_ptr outputAccess = TextAccess::createFromString(utility::encodeToUtf8( + utility::executeProcess(mavenPath.wstr(), args, projectDirectoryPath, true, 60000).output)); const std::wstring errorMessage = getErrorMessageFromMavenOutput(outputAccess); if (!errorMessage.empty()) diff --git a/src/lib_python/project/SourceGroupPythonEmpty.cpp b/src/lib_python/project/SourceGroupPythonEmpty.cpp index dfe7a498..42156a16 100644 --- a/src/lib_python/project/SourceGroupPythonEmpty.cpp +++ b/src/lib_python/project/SourceGroupPythonEmpty.cpp @@ -49,25 +49,28 @@ std::set SourceGroupPythonEmpty::getAllSourceFilePaths() const std::vector> SourceGroupPythonEmpty::getIndexerCommands( const RefreshInfo& info) const { - std::wstring args = L""; + std::vector 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> indexerCommands; @@ -77,8 +80,8 @@ std::vector> SourceGroupPythonEmpty::getIndexerC { indexerCommands.push_back(std::make_shared( 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()), diff --git a/src/test/PythonIndexerTestSuite.cpp b/src/test/PythonIndexerTestSuite.cpp index c97d387b..7666e38c 100644 --- a/src/test/PythonIndexerTestSuite.cpp +++ b/src/test/PythonIndexerTestSuite.cpp @@ -56,28 +56,38 @@ std::shared_ptr parseCode(std::string code) const std::set 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 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 indexerCommand = std::make_shared( 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; diff --git a/src/test/SourceGroupTestSuite.cpp b/src/test/SourceGroupTestSuite.cpp index b5c5562a..6c64c25e 100644 --- a/src/test/SourceGroupTestSuite.cpp +++ b/src/test/SourceGroupTestSuite.cpp @@ -148,9 +148,15 @@ std::wstring indexerCommandCustomToString( std::shared_ptr 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; }