diff --git a/src/plugins/mesonprojectmanager/CMakeLists.txt b/src/plugins/mesonprojectmanager/CMakeLists.txt index 389298783c0..4cc66cab91b 100644 --- a/src/plugins/mesonprojectmanager/CMakeLists.txt +++ b/src/plugins/mesonprojectmanager/CMakeLists.txt @@ -59,8 +59,6 @@ add_qtc_plugin(MesonProjectManager toolssettingspage.h tooltreeitem.cpp tooltreeitem.h - toolwrapper.cpp - toolwrapper.h versionhelper.h ) @@ -81,8 +79,7 @@ add_qtc_test(tst_mesonwrapper TEST_RELATIVE_LIBEXEC_PATH="${TEST_RELATIVE_LIBEXEC_PATH}" SOURCES tests/testmesonwrapper.cpp - toolwrapper.h - toolwrapper.cpp + mesontools.cpp mesontools.h ) @@ -99,10 +96,9 @@ add_qtc_test(tst_mesoninfoparser TEST_RELATIVE_LIBEXEC_PATH="${TEST_RELATIVE_LIBEXEC_PATH}" SOURCES tests/testmesoninfoparser.cpp - toolwrapper.h - toolwrapper.cpp - mesontools.h mesoninfoparser.h + mesontools.cpp + mesontools.h ) add_qtc_test(tst_ninjaparser diff --git a/src/plugins/mesonprojectmanager/mesonprojectmanager.qbs b/src/plugins/mesonprojectmanager/mesonprojectmanager.qbs index fed454a6ce5..619d6f26f0f 100644 --- a/src/plugins/mesonprojectmanager/mesonprojectmanager.qbs +++ b/src/plugins/mesonprojectmanager/mesonprojectmanager.qbs @@ -20,8 +20,6 @@ Project { files: [ "mesontools.cpp", "mesontools.h", - "toolwrapper.cpp", - "toolwrapper.h", "kitdata.h", "mesonactionsmanager.cpp", "mesonactionsmanager.h", @@ -91,8 +89,6 @@ Project { cpp.includePaths: "." files: [ - "toolwrapper.h", - "toolwrapper.cpp", "mesontools.h", "tests/testmesonwrapper.cpp", ] @@ -108,8 +104,6 @@ Project { cpp.includePaths: "." files: [ - "toolwrapper.h", - "toolwrapper.cpp", "mesontools.h", "mesoninfoparser.h", "tests/testmesoninfoparser.cpp", diff --git a/src/plugins/mesonprojectmanager/mesonprojectparser.h b/src/plugins/mesonprojectmanager/mesonprojectparser.h index 48da877a95a..991c836e001 100644 --- a/src/plugins/mesonprojectmanager/mesonprojectparser.h +++ b/src/plugins/mesonprojectmanager/mesonprojectparser.h @@ -7,7 +7,7 @@ #include "mesoninfoparser.h" #include "mesonoutputparser.h" #include "mesonprojectnodes.h" -#include "toolwrapper.h" +#include "mesontools.h" #include #include diff --git a/src/plugins/mesonprojectmanager/mesontools.cpp b/src/plugins/mesonprojectmanager/mesontools.cpp index 76a7b319bd8..f2e4929fd60 100644 --- a/src/plugins/mesonprojectmanager/mesontools.cpp +++ b/src/plugins/mesonprojectmanager/mesontools.cpp @@ -3,13 +3,226 @@ #include "mesontools.h" +#include "mesonpluginconstants.h" + #include #include +#include +#include +#include + +#include +#include +#include using namespace Utils; namespace MesonProjectManager::Internal { +static ToolType typeFromId(const QString &id) +{ + if (id == Constants::ToolsSettings::TOOL_TYPE_NINJA) + return ToolType::Ninja; + if (id == Constants::ToolsSettings::TOOL_TYPE_MESON) + return ToolType::Meson; + QTC_CHECK(false); + return ToolType::Meson; +} + +ToolWrapper::ToolWrapper(const Store &data) +{ + m_toolType = typeFromId(data.value(Constants::ToolsSettings::TOOL_TYPE_KEY).toString()); + m_name = data[Constants::ToolsSettings::NAME_KEY].toString(); + m_exe = FilePath::fromSettings(data[Constants::ToolsSettings::EXE_KEY]); + m_id = Id::fromSetting(data[Constants::ToolsSettings::ID_KEY]); + m_autoDetected = data[Constants::ToolsSettings::AUTO_DETECTED_KEY].toBool(); +} + +ToolWrapper::ToolWrapper(ToolType toolType, + const QString &name, + const FilePath &path, + bool autoDetected) + : m_toolType(toolType) + , m_version(read_version(path)) + , m_isValid{path.exists() && m_version.isValid} + , m_autoDetected{autoDetected} + , m_id{Utils::Id::generate()} + , m_exe{path} + , m_name{name} +{} + +ToolWrapper::ToolWrapper(ToolType toolType, + const QString &name, + const FilePath &path, + const Id &id, + bool autoDetected) + : m_toolType(toolType) + , m_version(read_version(path)) + , m_isValid{path.exists() && m_version.isValid} + , m_autoDetected{autoDetected} + , m_id{id} + , m_exe{path} + , m_name{name} +{ + QTC_ASSERT(m_id.isValid(), m_id = Utils::Id::generate()); +} + +ToolWrapper::~ToolWrapper() = default; + +void ToolWrapper::setExe(const Utils::FilePath &newExe) +{ + m_exe = newExe; + m_version = read_version(m_exe); +} + +Version ToolWrapper::read_version(const Utils::FilePath &toolPath) +{ + if (toolPath.toFileInfo().isExecutable()) { + Utils::Process process; + process.setCommand({ toolPath, { "--version" } }); + process.start(); + if (process.waitForFinished()) + return Version::fromString(process.cleanedStdOut()); + } + return {}; +} + +Store ToolWrapper::toVariantMap() const +{ + Utils::Store data; + data.insert(Constants::ToolsSettings::NAME_KEY, m_name); + data.insert(Constants::ToolsSettings::EXE_KEY, m_exe.toSettings()); + data.insert(Constants::ToolsSettings::AUTO_DETECTED_KEY, m_autoDetected); + data.insert(Constants::ToolsSettings::ID_KEY, m_id.toSetting()); + if (m_toolType == ToolType::Meson) + data.insert(Constants::ToolsSettings::TOOL_TYPE_KEY, Constants::ToolsSettings::TOOL_TYPE_MESON); + else + data.insert(Constants::ToolsSettings::TOOL_TYPE_KEY, Constants::ToolsSettings::TOOL_TYPE_NINJA); + ; + return data; +} + +template +void impl_option_cat(QStringList &list, const First &first) +{ + list.append(first); +} + +template +void impl_option_cat(QStringList &list, const First &first, const T &...args) +{ + impl_option_cat(list, first); + impl_option_cat(list, args...); +} + +template +QStringList options_cat(const T &...args) +{ + QStringList result; + impl_option_cat(result, args...); + return result; +} + +Command ToolWrapper::setup(const FilePath &sourceDirectory, + const FilePath &buildDirectory, + const QStringList &options) const +{ + return {{m_exe, options_cat("setup", options, sourceDirectory.path(), buildDirectory.path())}, + sourceDirectory}; +} + +Command ToolWrapper::configure(const FilePath &sourceDirectory, + const FilePath &buildDirectory, + const QStringList &options) const +{ + if (!isSetup(buildDirectory)) + return setup(sourceDirectory, buildDirectory, options); + return {{m_exe, options_cat("configure", options, buildDirectory.path())}, + buildDirectory}; +} + +Command ToolWrapper::regenerate(const FilePath &sourceDirectory, + const FilePath &buildDirectory) const +{ + return {{m_exe, + options_cat("--internal", + "regenerate", + sourceDirectory.path(), + buildDirectory.path(), + "--backend", + "ninja")}, + buildDirectory}; +} + +Command ToolWrapper::introspect(const Utils::FilePath &sourceDirectory) const +{ + return {{m_exe, + {"introspect", "--all", QString("%1/meson.build").arg(sourceDirectory.path())}}, + sourceDirectory}; +} + +template +bool containsFiles(const QString &path, const File_t &file) +{ + return QFileInfo::exists(QString("%1/%2").arg(path).arg(file)); +} + +template +bool containsFiles(const QString &path, const File_t &file, const T &...files) +{ + return containsFiles(path, file) && containsFiles(path, files...); +} + +bool run_meson(const Command &command, QIODevice *output) +{ + Utils::Process process; + process.setWorkingDirectory(command.workDir); + process.setCommand(command.cmdLine); + process.start(); + if (!process.waitForFinished()) + return false; + if (output) { + output->write(process.rawStdOut()); + } + return process.exitCode() == 0; +} + +bool isSetup(const Utils::FilePath &buildPath) +{ + using namespace Utils; + return containsFiles(buildPath.pathAppended(Constants::MESON_INFO_DIR).toString(), + Constants::MESON_INTRO_TESTS, + Constants::MESON_INTRO_TARGETS, + Constants::MESON_INTRO_INSTALLED, + Constants::MESON_INTRO_BENCHMARKS, + Constants::MESON_INTRO_BUIDOPTIONS, + Constants::MESON_INTRO_PROJECTINFO, + Constants::MESON_INTRO_DEPENDENCIES, + Constants::MESON_INTRO_BUILDSYSTEM_FILES); +} + +static std::optional findToolHelper(const QStringList &exeNames) +{ + Environment systemEnvironment = Environment::systemEnvironment(); + for (const auto &exe : exeNames) { + const FilePath exe_path = systemEnvironment.searchInPath(exe); + if (exe_path.exists()) + return exe_path; + } + return std::nullopt; +} + +std::optional findTool(ToolType toolType) +{ + if (toolType == ToolType::Meson) + return findToolHelper({"meson.py", "meson"}); + if (toolType == ToolType::Ninja) + return findToolHelper({"ninja", "ninja-build"}); + QTC_CHECK(false); + return {}; +} + + std::vector s_tools; static MesonTools::Tool_t findTool(const Id &id, ToolType toolType) diff --git a/src/plugins/mesonprojectmanager/mesontools.h b/src/plugins/mesonprojectmanager/mesontools.h index e625c8b59a7..00f91bac164 100644 --- a/src/plugins/mesonprojectmanager/mesontools.h +++ b/src/plugins/mesonprojectmanager/mesontools.h @@ -3,12 +3,86 @@ #pragma once -#include "toolwrapper.h" +#include "versionhelper.h" +#include +#include +#include + +#include #include namespace MesonProjectManager::Internal { +enum class ToolType { Meson, Ninja }; + +class Command +{ +public: + Utils::CommandLine cmdLine; + Utils::FilePath workDir; +}; + +class ToolWrapper final +{ +public: + ToolWrapper() = delete; + explicit ToolWrapper(const Utils::Store &data); + ToolWrapper(ToolType toolType, + const QString &name, + const Utils::FilePath &path, + bool autoDetected = false); + ToolWrapper(ToolType toolType, + const QString &name, + const Utils::FilePath &path, + const Utils::Id &id, + bool autoDetected = false); + + ~ToolWrapper(); + + const Version &version() const noexcept { return m_version; } + bool isValid() const noexcept { return m_isValid; } + bool autoDetected() const noexcept { return m_autoDetected; } + Utils::Id id() const noexcept { return m_id; } + Utils::FilePath exe() const noexcept { return m_exe; } + QString name() const noexcept { return m_name; } + + void setName(const QString &newName) { m_name = newName; } + void setExe(const Utils::FilePath &newExe); + + static Version read_version(const Utils::FilePath &toolPath); + + Utils::Store toVariantMap() const; + + ToolType toolType() const { return m_toolType; } + void setToolType(ToolType newToolType) { m_toolType = newToolType; } + + Command setup(const Utils::FilePath &sourceDirectory, + const Utils::FilePath &buildDirectory, + const QStringList &options = {}) const; + Command configure(const Utils::FilePath &sourceDirectory, + const Utils::FilePath &buildDirectory, + const QStringList &options = {}) const; + Command regenerate(const Utils::FilePath &sourceDirectory, + const Utils::FilePath &buildDirectory) const; + Command introspect(const Utils::FilePath &sourceDirectory) const; + +private: + ToolType m_toolType; + Version m_version; + bool m_isValid; + bool m_autoDetected; + Utils::Id m_id; + Utils::FilePath m_exe; + QString m_name; +}; + +bool run_meson(const Command &command, QIODevice *output = nullptr); + +bool isSetup(const Utils::FilePath &buildPath); + +std::optional findTool(ToolType toolType); + class MesonTools : public QObject { Q_OBJECT diff --git a/src/plugins/mesonprojectmanager/tests/testmesoninfoparser.cpp b/src/plugins/mesonprojectmanager/tests/testmesoninfoparser.cpp index c806a7524c8..cd908f30aa6 100644 --- a/src/plugins/mesonprojectmanager/tests/testmesoninfoparser.cpp +++ b/src/plugins/mesonprojectmanager/tests/testmesoninfoparser.cpp @@ -1,8 +1,8 @@ // Copyright (C) 2020 Alexis Jeandet. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -#include "toolwrapper.h" #include "mesoninfoparser.h" +#include "mesontools.h" #include #include @@ -19,15 +19,15 @@ using namespace MesonProjectManager::Internal; using namespace Utils; -struct projectData +struct ProjectData { const char *name; QString path; QStringList targets; }; -static const QList projectList{ - {"Simple C Project", "simplecproject", {"SimpleCProject"}}}; +static const ProjectData projectList[] = + {{"Simple C Project", "simplecproject", {"SimpleCProject"}}}; #define WITH_UNCONFIGURED_PROJECT(_source_dir, _intro_file, ...) \ diff --git a/src/plugins/mesonprojectmanager/tests/testmesonwrapper.cpp b/src/plugins/mesonprojectmanager/tests/testmesonwrapper.cpp index f9ecf7ae4e4..9064333f637 100644 --- a/src/plugins/mesonprojectmanager/tests/testmesonwrapper.cpp +++ b/src/plugins/mesonprojectmanager/tests/testmesonwrapper.cpp @@ -1,7 +1,7 @@ // Copyright (C) 2020 Alexis Jeandet. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -#include "../toolwrapper.h" +#include "../mesontools.h" #include #include diff --git a/src/plugins/mesonprojectmanager/toolkitaspectwidget.h b/src/plugins/mesonprojectmanager/toolkitaspectwidget.h index a57197aca24..8b29047e86a 100644 --- a/src/plugins/mesonprojectmanager/toolkitaspectwidget.h +++ b/src/plugins/mesonprojectmanager/toolkitaspectwidget.h @@ -3,7 +3,7 @@ #pragma once -#include "toolwrapper.h" +#include "mesontools.h" #include #include