diff options
| -rw-r--r-- | src/libs/utils/datafromprocess.h | 4 | ||||
| -rw-r--r-- | src/plugins/cmakeprojectmanager/cmaketool.cpp | 139 | ||||
| -rw-r--r-- | src/plugins/cmakeprojectmanager/cmaketool.h | 6 | ||||
| -rw-r--r-- | src/plugins/python/pyside.cpp | 2 | ||||
| -rw-r--r-- | src/plugins/python/pythonlanguageclient.cpp | 4 | ||||
| -rw-r--r-- | src/plugins/python/pythonsettings.cpp | 8 | ||||
| -rw-r--r-- | src/plugins/python/pythonutils.cpp | 47 | ||||
| -rw-r--r-- | src/plugins/python/pythonutils.h | 1 | ||||
| -rw-r--r-- | src/plugins/qtsupport/qtoptionspage.cpp | 3 |
9 files changed, 127 insertions, 87 deletions
diff --git a/src/libs/utils/datafromprocess.h b/src/libs/utils/datafromprocess.h index b87b7f7d133..00a105e8acf 100644 --- a/src/libs/utils/datafromprocess.h +++ b/src/libs/utils/datafromprocess.h @@ -53,6 +53,7 @@ public: Callback cachedValueChangedCallback; bool persistValue = true; QList<ProcessResult> allowedResults{ProcessResult::FinishedWithSuccess}; + bool disableUnixTerminal = false; }; // Use the first variant whenever possible. @@ -109,6 +110,9 @@ inline std::optional<Data> DataFromProcess<Data>::getOrProvideData(const Paramet const auto outputRetriever = std::make_shared<Process>(); outputRetriever->setCommand(params.commandLine); + outputRetriever->setEnvironment(params.environment); + if (params.disableUnixTerminal) + outputRetriever->setDisableUnixTerminal(); if (params.persistValue && !params.callback) { const QChar separator = params.commandLine.executable().pathListSeparator(); diff --git a/src/plugins/cmakeprojectmanager/cmaketool.cpp b/src/plugins/cmakeprojectmanager/cmaketool.cpp index 1f53f797213..66fda223b3b 100644 --- a/src/plugins/cmakeprojectmanager/cmaketool.cpp +++ b/src/plugins/cmakeprojectmanager/cmaketool.cpp @@ -9,6 +9,7 @@ #include <coreplugin/icore.h> #include <projectexplorer/devicesupport/devicemanager.h> #include <utils/algorithm.h> +#include <utils/datafromprocess.h> #include <utils/environment.h> #include <utils/qtcassert.h> #include <utils/qtcprocess.h> @@ -40,11 +41,35 @@ const char CMAKE_INFORMATION_AUTO_CREATE_BUILD_DIRECTORY[] = "AutoCreateBuildDir const char CMAKE_INFORMATION_AUTODETECTED[] = "AutoDetected"; const char CMAKE_INFORMATION_DETECTIONSOURCE[] = "DetectionSource"; +bool operator==(const CMakeTool::Version &v1, const CMakeTool::Version &v2) +{ + return v1.major == v2.major && v1.minor == v2.minor && v1.patch == v2.patch + && v1.fullVersion == v2.fullVersion; +} + +bool operator!=(const CMakeTool::Version &v1, const CMakeTool::Version &v2) +{ + return !(v1 == v2); +} + bool CMakeTool::Generator::matches(const QString &n) const { return n == name; } +bool operator==(const CMakeTool::Generator &g1, const CMakeTool::Generator &g2) +{ + return g1.name == g2.name + && g1.extraGenerators == g2.extraGenerators + && g1.supportsPlatform == g2.supportsPlatform + && g1.supportsToolset == g2.supportsToolset; +} + +bool operator!=(const CMakeTool::Generator &g1, const CMakeTool::Generator &g2) +{ + return !(g1 == g2); +} + namespace Internal { // -------------------------------------------------------------------- @@ -57,6 +82,37 @@ public: std::pair<int, int> version; }; +bool operator==(const FileApi &f1, const FileApi &f2) +{ + return f1.kind == f2.kind && f1.version == f2.version; +} + +bool operator!=(const FileApi &f1, const FileApi &f2) +{ + return !(f1 == f2); +} + +class Capabilities { +public: + static Capabilities fromJson(const QString &input); + + QList<CMakeTool::Generator> generators; + QList<FileApi> fileApis; + CMakeTool::Version version; +}; + +bool operator==(const Capabilities &c1, const Capabilities &c2) +{ + return c1.generators == c2.generators + && c1.fileApis == c2.fileApis + && c1.version == c2.version; +} + +bool operator!=(const Capabilities &c1, const Capabilities &c2) +{ + return !(c1 == c2); +} + class IntrospectionData { public: @@ -64,13 +120,9 @@ public: bool m_haveCapabilitites = true; bool m_haveKeywords = false; - QList<CMakeTool::Generator> m_generators; + Capabilities m_capabilities; CMakeKeywords m_keywords; QMutex m_keywordsMutex; - QList<FileApi> m_fileApis; - CMakeTool::Version m_version; - - void parseFromCapabilities(const QString &input); }; } // namespace Internal @@ -145,7 +197,8 @@ bool CMakeTool::isValid() const if (!m_introspection->m_didAttemptToRun) readInformation(); - return m_introspection->m_haveCapabilitites && !m_introspection->m_fileApis.isEmpty(); + return m_introspection->m_haveCapabilitites + && !m_introspection->m_capabilities.fileApis.isEmpty(); } void CMakeTool::runCMake(Process &cmake, const QStringList &args, int timeoutS) const @@ -214,7 +267,7 @@ FilePath CMakeTool::cmakeExecutable(const FilePath &path) QList<CMakeTool::Generator> CMakeTool::supportedGenerators() const { - return isValid() ? m_introspection->m_generators : QList<CMakeTool::Generator>(); + return isValid() ? m_introspection->m_capabilities.generators : QList<CMakeTool::Generator>(); } CMakeKeywords CMakeTool::keywords() @@ -233,14 +286,18 @@ CMakeKeywords CMakeTool::keywords() / "find-root.cmake"; findCMakeRoot.writeFileContents("message(${CMAKE_ROOT})"); - FilePath cmakeRoot; - runCMake(proc, {"-P", findCMakeRoot.nativePath()}); - if (proc.result() == ProcessResult::FinishedWithSuccess) { - QStringList output = filtered(proc.allOutput().split('\n'), - std::not_fn(&QString::isEmpty)); + CommandLine command(cmakeExecutable(), {"-P", findCMakeRoot.nativePath()}); + auto outputParser = [](const QString &stdOut, const QString &) -> std::optional<FilePath> { + QStringList output = filtered(stdOut.split('\n'), std::not_fn(&QString::isEmpty)); if (output.size() > 0) - cmakeRoot = FilePath::fromString(output[0]); - } + return FilePath::fromString(output[0]); + return {}; + }; + DataFromProcess<FilePath>::Parameters params(command, outputParser); + params.environment = command.executable().deviceEnvironment(); + params.environment.setupEnglishOutput(); + params.disableUnixTerminal = true; + const FilePath cmakeRoot = DataFromProcess<FilePath>::getData(params).value_or(FilePath()); const struct { @@ -299,12 +356,12 @@ CMakeKeywords CMakeTool::keywords() bool CMakeTool::hasFileApi() const { - return isValid() ? !m_introspection->m_fileApis.isEmpty() : false; + return isValid() ? !m_introspection->m_capabilities.fileApis.isEmpty() : false; } CMakeTool::Version CMakeTool::version() const { - return isValid() ? m_introspection->m_version : CMakeTool::Version(); + return isValid() ? m_introspection->m_capabilities.version : CMakeTool::Version(); } QString CMakeTool::versionDisplay() const @@ -315,7 +372,7 @@ QString CMakeTool::versionDisplay() const if (!isValid()) return Tr::tr("Version not parseable"); - const Version &version = m_introspection->m_version; + const Version &version = m_introspection->m_capabilities.version; if (version.fullVersion.isEmpty()) return QString::fromUtf8(version.fullVersion); @@ -450,15 +507,25 @@ void CMakeTool::fetchFromCapabilities() const if (device && (device->deviceState() == IDevice::DeviceReadyToUse || device->deviceState() == IDevice::DeviceConnected)) { - Process cmake; - runCMake(cmake, {"-E", "capabilities"}); - if (cmake.result() == ProcessResult::FinishedWithSuccess) { + CommandLine command(cmakeExecutable(), {"-E", "capabilities"}); + auto outputParser = [](const QString &stdOut, const QString &) { + return Internal::Capabilities::fromJson(stdOut); + }; + DataFromProcess<Internal::Capabilities>::Parameters params(command, outputParser); + params.environment = command.executable().deviceEnvironment(); + params.environment.setupEnglishOutput(); + params.disableUnixTerminal = true; + params.errorHandler = [](const Process &p) { + qCCritical(cmakeToolLog) << "Fetching capabilities failed: " << p.verboseExitMessage(); + }; + const auto capabilities = DataFromProcess<Internal::Capabilities>::getData(params); + + if (const auto capabilities = DataFromProcess<Internal::Capabilities>::getData(params)) { m_introspection->m_haveCapabilitites = true; - m_introspection->parseFromCapabilities(cmake.cleanedStdOut()); + m_introspection->m_capabilities = *capabilities; return; } - qCCritical(cmakeToolLog) << "Fetching capabilities failed: " << cmake.verboseExitMessage(); } else { qCDebug(cmakeToolLog) << "Device for" << cmakeExecutable().toUserOutput() << "is not connected"; @@ -479,22 +546,22 @@ static int getVersion(const QVariantMap &obj, const QString &value) return result; } -void Internal::IntrospectionData::parseFromCapabilities(const QString &input) +Internal::Capabilities Internal::Capabilities::fromJson(const QString &input) { + Capabilities result; auto doc = QJsonDocument::fromJson(input.toUtf8()); if (!doc.isObject()) - return; + return result; const QVariantMap data = doc.object().toVariantMap(); const QVariantList generatorList = data.value("generators").toList(); for (const QVariant &v : generatorList) { const QVariantMap gen = v.toMap(); - m_generators.append( - CMakeTool::Generator( - gen.value("name").toString(), - gen.value("extraGenerators").toStringList(), - gen.value("platformSupport").toBool(), - gen.value("toolsetSupport").toBool())); + result.generators.append(CMakeTool::Generator( + gen.value("name").toString(), + gen.value("extraGenerators").toStringList(), + gen.value("platformSupport").toBool(), + gen.value("toolsetSupport").toBool())); } const QVariantMap fileApis = data.value("fileApi").toMap(); @@ -513,14 +580,16 @@ void Internal::IntrospectionData::parseFromCapabilities(const QString &input) highestVersion = version; } if (!kind.isNull() && highestVersion.first != -1 && highestVersion.second != -1) - m_fileApis.append({kind, highestVersion}); + result.fileApis.append({kind, highestVersion}); } const QVariantMap versionInfo = data.value("version").toMap(); - m_version.major = versionInfo.value("major").toInt(); - m_version.minor = versionInfo.value("minor").toInt(); - m_version.patch = versionInfo.value("patch").toInt(); - m_version.fullVersion = versionInfo.value("string").toByteArray(); + result.version.major = versionInfo.value("major").toInt(); + result.version.minor = versionInfo.value("minor").toInt(); + result.version.patch = versionInfo.value("patch").toInt(); + result.version.fullVersion = versionInfo.value("string").toByteArray(); + + return result; } void CMakeTool::setDetectionSource(const DetectionSource &source) diff --git a/src/plugins/cmakeprojectmanager/cmaketool.h b/src/plugins/cmakeprojectmanager/cmaketool.h index 4dfeb265926..7b071d19790 100644 --- a/src/plugins/cmakeprojectmanager/cmaketool.h +++ b/src/plugins/cmakeprojectmanager/cmaketool.h @@ -46,6 +46,9 @@ public: int minor = 0; int patch = 0; QByteArray fullVersion; + + friend bool operator==(const Version &v1, const Version &v2); + friend bool operator!=(const Version &v1, const Version &v2); }; class Generator @@ -61,6 +64,9 @@ public: bool supportsToolset = true; bool matches(const QString &n) const; + + friend bool operator==(const CMakeTool::Generator &g1, const CMakeTool::Generator &g2); + friend bool operator!=(const CMakeTool::Generator &g1, const CMakeTool::Generator &g2); }; explicit CMakeTool(const Utils::Store &map, bool fromSdk); diff --git a/src/plugins/python/pyside.cpp b/src/plugins/python/pyside.cpp index 79cb6949ee2..8e74e71b1f6 100644 --- a/src/plugins/python/pyside.cpp +++ b/src/plugins/python/pyside.cpp @@ -211,7 +211,7 @@ void PySideInstaller::handlePySideMissing(const FilePath &python, if (!document || !document->infoBar()->canInfoBeAdded(installPySideInfoBarId)) return; const QString message = Tr::tr("%1 installation missing for %2 (%3)") - .arg(pySide, pythonName(python), python.toUserOutput()); + .arg(pySide, pythonVersion(python), python.toUserOutput()); InfoBarEntry info(installPySideInfoBarId, message, InfoBarEntry::GlobalSuppression::Enabled); auto installCallback = [this, python, pySide] { installPySide(python, pySide, true); }; const QString installTooltip = Tr::tr("Install %1 for %2 using pip package installer.") diff --git a/src/plugins/python/pythonlanguageclient.cpp b/src/plugins/python/pythonlanguageclient.cpp index 052ebe1d388..4a2ed9ec23b 100644 --- a/src/plugins/python/pythonlanguageclient.cpp +++ b/src/plugins/python/pythonlanguageclient.cpp @@ -390,7 +390,7 @@ void PyLSConfigureAssistant::handlePyLSState(const FilePath &python, && infoBar->canInfoBeAdded(installPylsInfoBarId)) { auto message = Tr::tr("Install Python language server (PyLS) for %1 (%2). " "The language server provides Python specific completion and annotation.") - .arg(pythonName(python), python.toUserOutput()); + .arg(pythonVersion(python), python.toUserOutput()); InfoBarEntry info(installPylsInfoBarId, message, InfoBarEntry::GlobalSuppression::Enabled); info.addCustomButton(Tr::tr("Install"), [this, python, document, state] { installPythonLanguageServer(python, document, state.pylsModulePath, false, false); @@ -400,7 +400,7 @@ void PyLSConfigureAssistant::handlePyLSState(const FilePath &python, } else if (state.state == PythonLanguageServerState::Updatable) { if (infoBar->canInfoBeAdded(updatePylsInfoBarId)) { auto message = Tr::tr("Update Python language server (PyLS) for %1 (%2).") - .arg(pythonName(python), python.toUserOutput()); + .arg(pythonVersion(python), python.toUserOutput()); InfoBarEntry info(updatePylsInfoBarId, message); info.addCustomButton( Tr::tr("Always Update"), diff --git a/src/plugins/python/pythonsettings.cpp b/src/plugins/python/pythonsettings.cpp index 6c257aa2c90..fde31e692f1 100644 --- a/src/plugins/python/pythonsettings.cpp +++ b/src/plugins/python/pythonsettings.cpp @@ -129,13 +129,7 @@ Interpreter PythonSettings::createInterpreter( result.command = python; result.detectionSource = detectionSource; - Process pythonProcess; - pythonProcess.setProcessChannelMode(QProcess::MergedChannels); - pythonProcess.setCommand({python, {"--version"}}); - using namespace std::chrono_literals; - pythonProcess.runBlocking(1s); - if (pythonProcess.result() == ProcessResult::FinishedWithSuccess) - result.name = pythonProcess.cleanedStdOut().trimmed(); + result.name = pythonVersion(python); if (result.name.isEmpty()) result.name = defaultName; QDir pythonDir(python.parentDir().toUrlishString()); diff --git a/src/plugins/python/pythonutils.cpp b/src/plugins/python/pythonutils.cpp index 2936d4f4c5d..178f66108e1 100644 --- a/src/plugins/python/pythonutils.cpp +++ b/src/plugins/python/pythonutils.cpp @@ -18,6 +18,7 @@ #include <projectexplorer/target.h> #include <utils/algorithm.h> +#include <utils/datafromprocess.h> #include <utils/mimeutils.h> #include <utils/qtcprocess.h> #include <utils/synchronizedvalue.h> @@ -137,25 +138,6 @@ void openPythonRepl(QObject *parent, const FilePath &file, ReplType type) } } -QString pythonName(const FilePath &pythonPath) -{ - static QHash<FilePath, QString> nameForPython; - if (!pythonPath.exists()) - return {}; - QString name = nameForPython.value(pythonPath); - if (name.isEmpty()) { - Process pythonProcess; - pythonProcess.setCommand({pythonPath, {"--version"}}); - using namespace std::chrono_literals; - pythonProcess.runBlocking(2s); - if (pythonProcess.result() != ProcessResult::FinishedWithSuccess) - return {}; - name = pythonProcess.allOutput().trimmed(); - nameForPython[pythonPath] = name; - } - return name; -} - PythonProject *pythonProjectForFile(const FilePath &file) { for (Project *project : ProjectManager::projects()) { @@ -207,26 +189,13 @@ bool pipIsUsable(const FilePath &python) QString pythonVersion(const FilePath &python) { - static QReadWriteLock lock; - static QMap<FilePath, QString> versionCache; - - { - QReadLocker locker(&lock); - auto it = versionCache.constFind(python); - if (it != versionCache.constEnd()) - return *it; - } - - Process p; - p.setCommand({python, {"--version"}}); - p.runBlocking(); - if (p.result() == ProcessResult::FinishedWithSuccess) { - const QString version = p.readAllStandardOutput().trimmed(); - QWriteLocker locker(&lock); - versionCache.insert(python, version); - return version; - } - return QString(); + DataFromProcess<QString>::Parameters + params({python, {"--version"}}, [](const QString &stdOut, const QString &) { + return stdOut.trimmed(); + }); + if (const std::optional<QString> version = DataFromProcess<QString>::getData(params)) + return *version; + return {}; } } // namespace Python::Internal diff --git a/src/plugins/python/pythonutils.h b/src/plugins/python/pythonutils.h index 7aa5a575f56..4d4b0bd8cc1 100644 --- a/src/plugins/python/pythonutils.h +++ b/src/plugins/python/pythonutils.h @@ -11,7 +11,6 @@ enum class ReplType { Unmodified, Import, ImportToplevel }; void openPythonRepl(QObject *parent, const Utils::FilePath &file, ReplType type); Utils::FilePath detectPython(const Utils::FilePath &documentPath); void definePythonForDocument(const Utils::FilePath &documentPath, const Utils::FilePath &python); -QString pythonName(const Utils::FilePath &pythonPath); class PythonProject; PythonProject *pythonProjectForFile(const Utils::FilePath &pythonFile); diff --git a/src/plugins/qtsupport/qtoptionspage.cpp b/src/plugins/qtsupport/qtoptionspage.cpp index 06403105f04..44477828eb8 100644 --- a/src/plugins/qtsupport/qtoptionspage.cpp +++ b/src/plugins/qtsupport/qtoptionspage.cpp @@ -801,8 +801,7 @@ void QtSettingsPageWidget::redetect() if (!QTC_GUARD(dev)) return; - const FilePaths qMakes - = BuildableHelperLibrary::findQtsInEnvironment(dev->systemEnvironment(), dev->rootPath()); + const FilePaths qMakes = BuildableHelperLibrary::findQtsInPaths(dev->toolSearchPaths()); for (const FilePath &qmakePath : qMakes) { if (BuildableHelperLibrary::isQtChooser(qmakePath)) continue; |
