diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt
index 535c739674..3ea4b29bb6 100644
--- a/plugins/CMakeLists.txt
+++ b/plugins/CMakeLists.txt
@@ -1,159 +1,160 @@
# BEGIN: Analyzers
add_subdirectory(clangtidy)
add_subdirectory(clazy)
add_subdirectory(cppcheck)
if(UNIX AND NOT (APPLE OR CYGWIN))
add_subdirectory(heaptrack)
endif()
# END: Analyzers
# BEGIN: Debuggers
add_subdirectory(debuggercommon)
add_subdirectory(lldb)
add_subdirectory(gdb)
# END: Debuggers
# BEGIN: Documentation
find_package(Qt5Help CONFIG)
set_package_properties(Qt5Help PROPERTIES
PURPOSE "The Help module for the Qt toolkit, needed for the qthelp plugin"
URL "https://www.qt.io/"
TYPE OPTIONAL)
if(Qt5Help_FOUND)
ecm_optional_add_subdirectory(qthelp)
endif()
ecm_optional_add_subdirectory(manpage)
# END: Documentation
# BEGIN: Formatters
add_subdirectory(astyle)
add_subdirectory(customscript)
# END: Formatters
# BEGIN: Languages
ecm_optional_add_subdirectory(custom-definesandincludes)
# 3rdparty/qtcreator-libs uses QT_CONFIG which was added for 5.8
if(NOT Qt5_VERSION VERSION_LESS "5.8.0")
ecm_optional_add_subdirectory(qmljs)
else()
message(WARNING "Will not build QML/JS plugin, needs Qt >= 5.8.0")
endif()
find_package(Clang 3.8)
set(clangSearchHint "")
if (NOT CLANG_FOUND)
set(clangSearchHint "Please install a package providing libclang. Either pass -DLLVM_ROOT=/path/to/llvm-prefix or install the 'llvm-config' command-line utility for auto-detection.")
endif()
set_package_properties(Clang PROPERTIES
DESCRIPTION "Clang libraries from the LLVM project. ${clangSearchHint}"
PURPOSE "Used for KDevelop's C++/C support plugin."
TYPE REQUIRED
)
if (CLANG_FOUND)
if (NOT CLANG_CLANG_LIB)
message(FATAL_ERROR "Could not find the Clang C library: libclang")
endif()
add_library(Clang::clang UNKNOWN IMPORTED)
set_property(TARGET Clang::clang PROPERTY IMPORTED_LOCATION ${CLANG_CLANG_LIB})
ecm_optional_add_subdirectory(clang)
endif()
# END: Languages
# BEGIN: Project builders
add_subdirectory(makebuilder)
add_subdirectory(ninjabuilder)
ecm_optional_add_subdirectory(cmakebuilder)
if (KDevelop-PG-Qt_FOUND)
ecm_optional_add_subdirectory(qmakebuilder)
endif()
# END: Project builders
# BEGIN: Project managers
ecm_optional_add_subdirectory(cmake)
ecm_optional_add_subdirectory(custommake)
ecm_optional_add_subdirectory(custom-buildsystem)
if (KDevelop-PG-Qt_FOUND)
ecm_optional_add_subdirectory(qmakemanager)
endif()
ecm_optional_add_subdirectory(genericprojectmanager)
# END: Project managers
# BEGIN: Runtimes
add_subdirectory(android)
if (UNIX)
add_subdirectory(docker)
add_subdirectory(flatpak)
endif()
# END: Runtimes
# BEGIN: VCS
ecm_optional_add_subdirectory(bazaar)
ecm_optional_add_subdirectory(git)
ecm_optional_add_subdirectory(perforce)
find_package(SubversionLibrary)
set_package_properties(SubversionLibrary PROPERTIES
PURPOSE "Support for Subversion integration"
URL "http://subversion.tigris.org"
TYPE OPTIONAL)
if(SubversionLibrary_FOUND)
ecm_optional_add_subdirectory(subversion)
endif()
add_subdirectory(vcschangesview)
# END: VCS
# BEGIN: Others
add_subdirectory(appwizard)
add_subdirectory(codeutils)
add_subdirectory(contextbrowser)
add_subdirectory(documentswitcher)
add_subdirectory(documentview)
add_subdirectory(execute)
add_subdirectory(executescript)
add_subdirectory(externalscript)
add_subdirectory(filemanager)
add_subdirectory(filetemplates)
add_subdirectory(grepview)
add_subdirectory(openwith)
add_subdirectory(outlineview)
add_subdirectory(patchreview)
add_subdirectory(problemreporter)
add_subdirectory(projectfilter)
add_subdirectory(projectmanagerview)
add_subdirectory(quickopen)
add_subdirectory(sourceformatter)
add_subdirectory(standardoutputview)
add_subdirectory(switchtobuddy)
add_subdirectory(testview)
add_subdirectory(scratchpad)
+add_subdirectory(meson)
ecm_optional_add_subdirectory(classbrowser)
ecm_optional_add_subdirectory(executeplasmoid)
ecm_optional_add_subdirectory(ghprovider)
ecm_optional_add_subdirectory(kdeprovider)
ecm_optional_add_subdirectory(konsole)
if (Qt5QuickWidgets_FOUND)
add_subdirectory(welcomepage)
endif()
find_package(OktetaKastenControllers 0.3.1 CONFIG)
set_package_properties(OktetaKastenControllers PROPERTIES
PURPOSE "Required for building Okteta KDevelop plugin."
URL "http://kde.org/"
TYPE OPTIONAL)
if (OktetaKastenControllers_FOUND)
find_package(KastenControllers CONFIG)
set_package_properties(KastenControllers PROPERTIES
PURPOSE "Required for building Okteta KDevelop plugin."
URL "http://kde.org/"
TYPE OPTIONAL)
endif()
if (OktetaKastenControllers_FOUND AND KastenControllers_FOUND)
add_subdirectory(okteta)
endif()
# END: Others
diff --git a/plugins/meson/CMakeLists.txt b/plugins/meson/CMakeLists.txt
new file mode 100644
index 0000000000..3e1a0497cd
--- /dev/null
+++ b/plugins/meson/CMakeLists.txt
@@ -0,0 +1,37 @@
+add_definitions(-DTRANSLATION_DOMAIN=\"kdevmesonmanager\")
+
+set(mesonbuilder_SRCS
+ mesonbuilder.cpp
+ mesonconfig.cpp
+ mesonimportjob.cpp
+ mesonjob.cpp
+ mesonjobprune.cpp
+ mesonmanager.cpp
+
+ settings/mesonadvancedsettings.cpp
+ settings/mesonconfigpage.cpp
+ settings/mesonnewbuilddir.cpp
+)
+
+include_directories(${CMAKE_CURRENT_SOURCE_DIR})
+
+ki18n_wrap_ui(mesonbuilder_SRCS settings/mesonadvancedsettings.ui settings/mesonconfigpage.ui settings/mesonnewbuilddir.ui)
+ecm_qt_declare_logging_category(mesonbuilder_SRCS
+ HEADER debug.h
+ IDENTIFIER KDEV_Meson
+ CATEGORY_NAME "kdevelop.plugins.meson"
+)
+
+kdevplatform_add_plugin(kdevmesonmanager
+ JSON kdevmesonmanager.json
+ SOURCES ${mesonbuilder_SRCS})
+
+add_subdirectory(icons)
+
+target_link_libraries(kdevmesonmanager
+ Qt5::Concurrent
+ KDev::Interfaces
+ KDev::Project
+ KDev::Util
+ KDev::OutputView
+)
diff --git a/plugins/meson/Messages.sh b/plugins/meson/Messages.sh
new file mode 100644
index 0000000000..0a9213a91a
--- /dev/null
+++ b/plugins/meson/Messages.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+$EXTRACTRC `find . -name \*.rc -o -name \*.ui | grep -v '/tests/'` >>rc.cpp
+$XGETTEXT `find . -name \*.cc -o -name \*.cpp -o -name \*.h | grep -v '/tests/'` -o $podir/kdevmesonmanager.pot
+rm -f rc.cpp
diff --git a/plugins/meson/icons/128-apps-meson.png b/plugins/meson/icons/128-apps-meson.png
new file mode 100644
index 0000000000..f09f8fd3c4
Binary files /dev/null and b/plugins/meson/icons/128-apps-meson.png differ
diff --git a/plugins/meson/icons/16-apps-meson.png b/plugins/meson/icons/16-apps-meson.png
new file mode 100644
index 0000000000..00f73111ce
Binary files /dev/null and b/plugins/meson/icons/16-apps-meson.png differ
diff --git a/plugins/meson/icons/256-apps-meson.png b/plugins/meson/icons/256-apps-meson.png
new file mode 100644
index 0000000000..03868d680e
Binary files /dev/null and b/plugins/meson/icons/256-apps-meson.png differ
diff --git a/plugins/meson/icons/32-apps-meson.png b/plugins/meson/icons/32-apps-meson.png
new file mode 100644
index 0000000000..9e188071c9
Binary files /dev/null and b/plugins/meson/icons/32-apps-meson.png differ
diff --git a/plugins/meson/icons/64-apps-meson.png b/plugins/meson/icons/64-apps-meson.png
new file mode 100644
index 0000000000..a80d901deb
Binary files /dev/null and b/plugins/meson/icons/64-apps-meson.png differ
diff --git a/plugins/meson/icons/CMakeLists.txt b/plugins/meson/icons/CMakeLists.txt
new file mode 100644
index 0000000000..4dd530f40a
--- /dev/null
+++ b/plugins/meson/icons/CMakeLists.txt
@@ -0,0 +1,8 @@
+ecm_install_icons(ICONS
+ 256-apps-meson.png
+ 128-apps-meson.png
+ 64-apps-meson.png
+ 32-apps-meson.png
+ 16-apps-meson.png
+ DESTINATION ${KDE_INSTALL_ICONDIR})
+
diff --git a/plugins/meson/icons/meson_logo.svg b/plugins/meson/icons/meson_logo.svg
new file mode 100644
index 0000000000..b8dd59371b
--- /dev/null
+++ b/plugins/meson/icons/meson_logo.svg
@@ -0,0 +1,96 @@
+
+
+
+
diff --git a/plugins/meson/kdevmesonmanager.json b/plugins/meson/kdevmesonmanager.json
new file mode 100644
index 0000000000..06c3aba6d0
--- /dev/null
+++ b/plugins/meson/kdevmesonmanager.json
@@ -0,0 +1,26 @@
+{
+ "KPlugin": {
+ "Category": "Project Management",
+ "Description": "Imports and edits Meson projects",
+ "Icon": "meson",
+ "Id": "KDevMesonManager",
+ "Name": "Meson Project Manager",
+ "ServiceTypes": [
+ "KDevelop/Plugin"
+ ]
+ },
+ "X-KDevelop-Category": "Project",
+ "X-KDevelop-FileManager": "Meson",
+ "X-KDevelop-IRequired": [
+ "org.kdevelop.IProjectBuilder"
+ ],
+ "X-KDevelop-Interfaces": [
+ "org.kdevelop.IBuildSystemManager",
+ "org.kdevelop.IProjectFileManager"
+ ],
+ "X-KDevelop-Mode": "NoGUI",
+ "X-KDevelop-ProjectFilesFilter": [
+ "meson.build"
+ ],
+ "X-KDevelop-ProjectFilesFilterDescription": "Meson Project Files"
+}
diff --git a/plugins/meson/mesonbuilder.cpp b/plugins/meson/mesonbuilder.cpp
new file mode 100644
index 0000000000..bb3e3ebfe7
--- /dev/null
+++ b/plugins/meson/mesonbuilder.cpp
@@ -0,0 +1,265 @@
+/* This file is part of KDevelop
+ Copyright 2017 Aleix Pol Gonzalez
+ Copyright 2018 Daniel Mensinger
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "mesonbuilder.h"
+#include "mesonconfig.h"
+#include "mesonjob.h"
+#include "mesonjobprune.h"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+using namespace KDevelop;
+
+class ErrorJob : public OutputJob
+{
+ Q_OBJECT
+public:
+ ErrorJob(QObject* parent, const QString& error)
+ : OutputJob(parent)
+ , m_error(error)
+ {
+ setStandardToolView(IOutputView::BuildView);
+ }
+
+ void start() override
+ {
+ auto* output = new OutputModel(this);
+ setModel(output);
+ startOutput();
+
+ output->appendLine(i18n(" *** MESON ERROR ***\n"));
+ QStringList lines = m_error.split(QChar::fromLatin1('\n'));
+ output->appendLines(lines);
+
+ setError(!m_error.isEmpty());
+ setErrorText(m_error);
+ emitResult();
+ }
+
+private:
+ QString m_error;
+};
+
+MesonBuilder::MesonBuilder(QObject* parent)
+ : QObject(parent)
+{
+ auto p = KDevelop::ICore::self()->pluginController()->pluginForExtension(
+ QStringLiteral("org.kdevelop.IProjectBuilder"), QStringLiteral("KDevNinjaBuilder"));
+ if (p) {
+ m_ninjaBuilder = p->extension();
+ if (m_ninjaBuilder) {
+ connect(p, SIGNAL(built(KDevelop::ProjectBaseItem*)), this, SIGNAL(built(KDevelop::ProjectBaseItem*)));
+ connect(p, SIGNAL(installed(KDevelop::ProjectBaseItem*)), this,
+ SIGNAL(installed(KDevelop::ProjectBaseItem*)));
+ connect(p, SIGNAL(cleaned(KDevelop::ProjectBaseItem*)), this, SIGNAL(cleaned(KDevelop::ProjectBaseItem*)));
+ connect(p, SIGNAL(failed(KDevelop::ProjectBaseItem*)), this, SIGNAL(failed(KDevelop::ProjectBaseItem*)));
+ } else {
+ m_errorString = i18n("Failed to set the internally used Ninja builder");
+ }
+ } else {
+ m_errorString = i18n("Failed to acquire the Ninja builder plugin");
+ }
+}
+
+MesonBuilder::DirectoryStatus MesonBuilder::evaluateBuildDirectory(const Path& path, QString const& backend)
+{
+ QString pathSTR = path.toLocalFile();
+ if (pathSTR.isEmpty()) {
+ return EMPTY_STRING;
+ }
+
+ QFileInfo info(pathSTR);
+ if (!info.exists()) {
+ return DOES_NOT_EXIST;
+ }
+
+ if (!info.isDir() || !info.isReadable() || !info.isWritable()) {
+ return INVALID_BUILD_DIR;
+ }
+
+ QDir dir(path.toLocalFile());
+ if (dir.isEmpty(QDir::NoDotAndDotDot | QDir::Hidden | QDir::AllEntries)) {
+ return CLEAN;
+ }
+
+ // Check if the directory is a meson directory
+ const static QStringList mesonPaths = { QStringLiteral("meson-logs"), QStringLiteral("meson-private") };
+ for (auto const& i : mesonPaths) {
+ Path curr = path;
+ curr.addPath(i);
+ QFileInfo currFI(curr.toLocalFile());
+ if (!currFI.exists()) {
+ return DIR_NOT_EMPTY;
+ }
+ }
+
+ // Also check if the meson configuration succeeded. This should be the case if the backend file exists.
+ // Meson actually checks for meson-private/coredata.dat, this might change in the future.
+ // see: https://github.com/mesonbuild/meson/blob/master/mesonbuild/msetup.py#L117
+ QStringList configured = {};
+ if (backend == QStringLiteral("ninja")) {
+ configured << QStringLiteral("build.ninja");
+ }
+
+ // Check if this is a CONFIGURED meson directory
+ for (auto const& i : configured) {
+ Path curr = path;
+ curr.addPath(i);
+ QFileInfo currFI(curr.toLocalFile());
+ if (!currFI.exists()) {
+ return MESON_FAILED_CONFIGURATION;
+ }
+ }
+
+ return MESON_CONFIGURED;
+}
+
+KJob* MesonBuilder::configure(IProject* project, const Meson::BuildDir& buildDir, DirectoryStatus status)
+{
+ Q_ASSERT(project);
+
+ if (!buildDir.isValid()) {
+ return new ErrorJob(this, i18n("The current build directory for %1 is invalid", project->name()));
+ }
+
+ if (status == ___UNDEFINED___) {
+ status = evaluateBuildDirectory(buildDir.buildDir, buildDir.mesonBackend);
+ }
+
+ KJob* job = nullptr;
+
+ switch (status) {
+ case DOES_NOT_EXIST:
+ case CLEAN:
+ case MESON_FAILED_CONFIGURATION:
+ job = new MesonJob(buildDir, project, MesonJob::CONFIGURE, {}, this);
+ connect(job, &KJob::result, this, [this, project]() { emit configured(project); });
+ return job;
+ case MESON_CONFIGURED:
+ job = new MesonJob(buildDir, project, MesonJob::RE_CONFIGURE, {}, this);
+ connect(job, &KJob::result, this, [this, project]() { emit configured(project); });
+ return job;
+ case DIR_NOT_EMPTY:
+ return new ErrorJob(
+ this,
+ i18n("The directory '%1' is not empty and does not seem to be an already configured build directory",
+ buildDir.buildDir.toLocalFile()));
+ case INVALID_BUILD_DIR:
+ return new ErrorJob(
+ this,
+ i18n("The directory '%1' cannot be used as a meson build directory", buildDir.buildDir.toLocalFile()));
+ case EMPTY_STRING:
+ return new ErrorJob(
+ this, i18n("The current build configuration is broken, because the build directory is not specified"));
+ default:
+ // This code should NEVER be reached
+ return new ErrorJob(this,
+ i18n("Congratulations: You have reached unreachable code!\n"
+ "Please report a bug at https://bugs.kde.org/\n"
+ "FILE: %1:%2",
+ QStringLiteral(__FILE__), __LINE__));
+ }
+}
+
+KJob* MesonBuilder::configure(KDevelop::IProject* project)
+{
+ Q_ASSERT(project);
+ auto buildDir = Meson::currentBuildDir(project);
+ return configure(project, buildDir);
+}
+
+KJob* MesonBuilder::configureIfRequired(KDevelop::IProject* project, KJob* realJob)
+{
+ Q_ASSERT(project);
+ Meson::BuildDir buildDir = Meson::currentBuildDir(project);
+ DirectoryStatus status = evaluateBuildDirectory(buildDir.buildDir, buildDir.mesonBackend);
+
+ if (status == MESON_CONFIGURED) {
+ return realJob;
+ }
+
+ QList jobs = {
+ configure(project, buildDir, status), // First configure the build directory
+ realJob // If this succeeds execute the real job
+ };
+
+ return new ExecuteCompositeJob(this, jobs);
+}
+
+KJob* MesonBuilder::build(KDevelop::ProjectBaseItem* item)
+{
+ Q_ASSERT(item);
+ Q_ASSERT(m_ninjaBuilder);
+ return configureIfRequired(item->project(), m_ninjaBuilder->build(item));
+}
+
+KJob* MesonBuilder::clean(KDevelop::ProjectBaseItem* item)
+{
+ Q_ASSERT(item);
+ Q_ASSERT(m_ninjaBuilder);
+ return configureIfRequired(item->project(), m_ninjaBuilder->clean(item));
+}
+
+KJob* MesonBuilder::install(KDevelop::ProjectBaseItem* item, const QUrl& installPath)
+{
+ Q_ASSERT(item);
+ Q_ASSERT(m_ninjaBuilder);
+ return configureIfRequired(item->project(), m_ninjaBuilder->install(item, installPath));
+}
+
+KJob* MesonBuilder::prune(KDevelop::IProject* project)
+{
+ Q_ASSERT(project);
+ Meson::BuildDir buildDir = Meson::currentBuildDir(project);
+ if (!buildDir.isValid()) {
+ qCWarning(KDEV_Meson) << "The current build directory is invalid";
+ return new ErrorJob(this, i18n("The current build directory for %1 is invalid", project->name()));
+ }
+
+ KJob* job = new MesonJobPrune(buildDir, this);
+ connect(job, &KJob::result, this, [this, project]() { emit pruned(project); });
+ return job;
+}
+
+QList MesonBuilder::additionalBuilderPlugins(IProject*) const
+{
+ return { m_ninjaBuilder };
+}
+
+bool MesonBuilder::hasError() const
+{
+ return m_errorString.size() > 0;
+}
+
+QString MesonBuilder::errorDescription() const
+{
+ return m_errorString;
+}
+
+#include "mesonbuilder.moc"
diff --git a/plugins/meson/mesonbuilder.h b/plugins/meson/mesonbuilder.h
new file mode 100644
index 0000000000..ad94218ddc
--- /dev/null
+++ b/plugins/meson/mesonbuilder.h
@@ -0,0 +1,79 @@
+/* This file is part of KDevelop
+ Copyright 2017 Aleix Pol Gonzalez
+ Copyright 2018 Daniel Mensinger
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#pragma once
+
+#include
+#include
+
+namespace Meson
+{
+struct BuildDir;
+}
+
+class MesonBuilder : public QObject, public KDevelop::IProjectBuilder
+{
+ Q_OBJECT
+ Q_INTERFACES(KDevelop::IProjectBuilder)
+public:
+ enum DirectoryStatus {
+ DOES_NOT_EXIST = 0,
+ CLEAN,
+ MESON_CONFIGURED,
+ MESON_FAILED_CONFIGURATION,
+ INVALID_BUILD_DIR,
+ DIR_NOT_EMPTY,
+ EMPTY_STRING,
+ ___UNDEFINED___
+ };
+
+ explicit MesonBuilder(QObject* parent);
+
+ KJob* build(KDevelop::ProjectBaseItem* item) override;
+ KJob* clean(KDevelop::ProjectBaseItem* item) override;
+ KJob* install(KDevelop::ProjectBaseItem* dom, const QUrl& installPath) override;
+ KJob* prune(KDevelop::IProject* project) override;
+
+ KJob* configure(KDevelop::IProject* project) override;
+ KJob* configure(KDevelop::IProject* project, Meson::BuildDir const& buildDir,
+ DirectoryStatus status = ___UNDEFINED___);
+
+ /// Evaluate a directory for the use with meson
+ static DirectoryStatus evaluateBuildDirectory(KDevelop::Path const& path, QString const& backend);
+
+ bool hasError() const;
+ QString errorDescription() const;
+
+ QList additionalBuilderPlugins(KDevelop::IProject * project) const override;
+
+Q_SIGNALS:
+ void built(KDevelop::ProjectBaseItem*);
+ void installed(KDevelop::ProjectBaseItem*);
+ void cleaned(KDevelop::ProjectBaseItem*);
+ void failed(KDevelop::ProjectBaseItem*);
+ void configured(KDevelop::IProject*);
+ void pruned(KDevelop::IProject*);
+
+private:
+ KDevelop::IProjectBuilder* m_ninjaBuilder = nullptr;
+ QString m_errorString = QStringLiteral("");
+
+ KJob* configureIfRequired(KDevelop::IProject* project, KJob *realJob);
+};
diff --git a/plugins/meson/mesonconfig.cpp b/plugins/meson/mesonconfig.cpp
new file mode 100644
index 0000000000..4e6a21c447
--- /dev/null
+++ b/plugins/meson/mesonconfig.cpp
@@ -0,0 +1,195 @@
+/* This file is part of KDevelop
+ Copyright 2017 Aleix Pol Gonzalez
+ Copyright 2018 Daniel Mensinger
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "mesonconfig.h"
+#include "mesonmanager.h"
+#include
+#include
+#include
+#include
+#include
+#include
+
+using namespace KDevelop;
+using namespace Meson;
+
+static const QString ROOT_CONFIG = QStringLiteral("MesonManager");
+static const QString NUM_BUILD_DIRS = QStringLiteral("Number of Build Directories");
+static const QString CURRENT_INDEX = QStringLiteral("Current Build Directory Index");
+
+static const QString BUILD_DIR_SEC = QStringLiteral("BuildDir %1");
+static const QString BUILD_DIR_PATH = QStringLiteral("Build Directory Path");
+static const QString INSTALL_PREFIX = QStringLiteral("Installation prefix");
+static const QString MESON_EXE = QStringLiteral("Meson executable");
+static const QString EXTRA_ARGS = QStringLiteral("Additional meson arguments");
+static const QString BUILD_TYPE = QStringLiteral("Build type");
+static const QString BACKEND = QStringLiteral("Meson Generator Backend");
+
+int MesonConfig::addBuildDir(BuildDir dir)
+{
+ int newIndex = buildDirs.size();
+ dir.canonicalizePaths();
+ qCDebug(KDEV_Meson) << "BuildDirectories::addBuildDir()=" << dir.buildDir;
+ buildDirs.push_back(dir);
+
+ // Make sure m_currentIndex is valid
+ if (currentIndex < 0) {
+ currentIndex = newIndex;
+ }
+
+ return newIndex;
+}
+
+bool MesonConfig::removeBuildDir(int index)
+{
+ if (index > buildDirs.size() || index < 0) {
+ return false;
+ }
+
+ buildDirs.removeAt(index);
+
+ if (currentIndex >= buildDirs.size()) {
+ currentIndex = buildDirs.size() - 1;
+ }
+
+ return true;
+}
+
+KConfigGroup Meson::rootGroup(IProject* project)
+{
+ if (!project) {
+ qCWarning(KDEV_Meson) << "Meson::rootGroup: IProject pointer is nullptr";
+ return KConfigGroup();
+ }
+
+ return project->projectConfiguration()->group(ROOT_CONFIG);
+}
+
+MesonConfig Meson::getMesonConfig(IProject* project)
+{
+ KConfigGroup root = rootGroup(project);
+ MesonConfig result;
+
+ int numDirs = root.readEntry(NUM_BUILD_DIRS, 0);
+ result.currentIndex = root.readEntry(CURRENT_INDEX, -1);
+
+ for (int i = 0; i < numDirs; ++i) {
+ QString section = BUILD_DIR_SEC.arg(i);
+ if (!root.hasGroup(section)) {
+ continue;
+ }
+
+ KConfigGroup current = root.group(section);
+ BuildDir currBD;
+ currBD.buildDir = Path(current.readEntry(BUILD_DIR_PATH, QString()));
+ currBD.installPrefix = Path(current.readEntry(INSTALL_PREFIX, QString()));
+ currBD.mesonExecutable = Path(current.readEntry(MESON_EXE, QString()));
+ currBD.buildType = current.readEntry(BUILD_TYPE, QStringLiteral("debug"));
+ currBD.mesonBackend = current.readEntry(BACKEND, QString());
+ currBD.mesonArgs = current.readEntry(EXTRA_ARGS, QString());
+
+ currBD.canonicalizePaths();
+
+ // Try to find meson if the config is bad
+ if (currBD.mesonExecutable.isEmpty()) {
+ Q_ASSERT(project);
+ IBuildSystemManager* ibsm = project->buildSystemManager();
+ MesonManager* bsm = dynamic_cast(ibsm);
+ if (bsm) {
+ currBD.mesonExecutable = bsm->findMeson();
+ }
+ }
+
+ result.buildDirs.push_back(currBD);
+ }
+
+ if (result.buildDirs.isEmpty()) {
+ result.currentIndex = -1;
+ } else if (result.currentIndex < 0 || result.currentIndex >= result.buildDirs.size()) {
+ result.currentIndex = 0;
+ }
+
+ return result;
+}
+
+void Meson::writeMesonConfig(IProject* project, const MesonConfig& cfg)
+{
+ KConfigGroup root = rootGroup(project);
+
+ // Make sure that the config we write is valid
+ int currentIndex = cfg.currentIndex;
+ if (cfg.buildDirs.isEmpty()) {
+ currentIndex = -1;
+ } else if (currentIndex < 0 || currentIndex >= cfg.buildDirs.size()) {
+ currentIndex = 0;
+ }
+
+ root.writeEntry(NUM_BUILD_DIRS, cfg.buildDirs.size());
+ root.writeEntry(CURRENT_INDEX, currentIndex);
+
+ int counter = 0;
+ for (auto const& i : cfg.buildDirs) {
+ KConfigGroup current = root.group(BUILD_DIR_SEC.arg(counter++));
+
+ current.writeEntry(BUILD_DIR_PATH, i.buildDir.path());
+ current.writeEntry(INSTALL_PREFIX, i.installPrefix.path());
+ current.writeEntry(MESON_EXE, i.mesonExecutable.path());
+ current.writeEntry(BUILD_TYPE, i.buildType);
+ current.writeEntry(BACKEND, i.mesonBackend);
+ current.writeEntry(EXTRA_ARGS, i.mesonArgs);
+ }
+}
+
+BuildDir Meson::currentBuildDir(IProject* project)
+{
+ Q_ASSERT(project);
+ MesonConfig cfg = getMesonConfig(project);
+ if (cfg.currentIndex < 0 || cfg.currentIndex >= cfg.buildDirs.size()) {
+ cfg.currentIndex = 0; // Default to the first build dir
+
+ // Request a new build directory if neccessary
+ if (cfg.buildDirs.isEmpty()) {
+ IBuildSystemManager* ibsm = project->buildSystemManager();
+ MesonManager* bsm = dynamic_cast(ibsm);
+ if (!bsm) {
+ qCCritical(KDEV_Meson) << "Invalid build system manager for mesonconfig";
+ qCCritical(KDEV_Meson) << "Project " << project->name() << "is probably broken";
+ return BuildDir();
+ }
+
+ // newBuildDirectory() will add the build dir to the config and set cfg.currentIndex
+ return bsm->newBuildDirectory(project);
+ }
+ }
+
+ return cfg.buildDirs[cfg.currentIndex];
+}
+
+bool Meson::BuildDir::isValid() const
+{
+ return !(buildDir.isEmpty() || mesonExecutable.isEmpty() || buildType.isEmpty());
+}
+
+void Meson::BuildDir::canonicalizePaths()
+{
+ for (auto* i : { &buildDir, &installPrefix, &mesonExecutable }) {
+ *i = Path(QFileInfo(i->toLocalFile()).canonicalFilePath());
+ }
+}
diff --git a/plugins/meson/mesonconfig.h b/plugins/meson/mesonconfig.h
new file mode 100644
index 0000000000..12217d37e0
--- /dev/null
+++ b/plugins/meson/mesonconfig.h
@@ -0,0 +1,60 @@
+/* This file is part of KDevelop
+ Copyright 2017 Aleix Pol Gonzalez
+ Copyright 2018 Daniel Mensinger
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#pragma once
+
+#include
+#include
+
+namespace KDevelop
+{
+class IProject;
+}
+
+namespace Meson
+{
+
+struct BuildDir {
+ KDevelop::Path buildDir;
+ KDevelop::Path installPrefix;
+ KDevelop::Path mesonExecutable;
+ QString buildType;
+ QString mesonBackend;
+ QString mesonArgs;
+
+ bool isValid() const;
+ void canonicalizePaths();
+};
+
+struct MesonConfig
+{
+ int currentIndex = -1;
+ QVector buildDirs;
+
+ int addBuildDir(BuildDir dir);
+ bool removeBuildDir(int index);
+};
+
+KConfigGroup rootGroup(KDevelop::IProject* project);
+BuildDir currentBuildDir(KDevelop::IProject* project);
+MesonConfig getMesonConfig(KDevelop::IProject* project);
+void writeMesonConfig(KDevelop::IProject* project, MesonConfig const& cfg);
+
+}
diff --git a/plugins/meson/mesonimportjob.cpp b/plugins/meson/mesonimportjob.cpp
new file mode 100644
index 0000000000..264d478778
--- /dev/null
+++ b/plugins/meson/mesonimportjob.cpp
@@ -0,0 +1,82 @@
+/* This file is part of KDevelop
+ Copyright 2017 Aleix Pol Gonzalez
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "mesonimportjob.h"
+#include "mesonconfig.h"
+#include "mesonmanager.h"
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+using namespace KDevelop;
+
+MesonImportJob::MesonImportJob(MesonManager* manager, KDevelop::IProject* project, QObject* parent)
+ : KJob(parent)
+ , m_project(project)
+ , m_manager(manager)
+{
+ connect(&m_futureWatcher, &QFutureWatcher::finished, this, &MesonImportJob::importFinished);
+}
+
+// TODO: probably want to process the object in this function (e.g. see CMakeImportJsonJob)
+QJsonObject import()
+{
+ qCDebug(KDEV_Meson) << "import(): This is a stub.";
+ return QJsonObject();
+}
+
+void MesonImportJob::start()
+{
+ Meson::BuildDir buildDir = Meson::currentBuildDir(m_project);
+ if (!buildDir.isValid()) {
+ qCWarning(KDEV_Meson) << "The current build directory is invalid";
+ setError(true);
+ setErrorText(i18n("The current build directory for %1 is invalid").arg(m_project->name()));
+ emitResult();
+ return;
+ }
+
+ auto future = QtConcurrent::run(import);
+ m_futureWatcher.setFuture(future);
+}
+
+void MesonImportJob::importFinished()
+{
+ auto future = m_futureWatcher.future();
+ auto data = future.result();
+ m_manager->setProjectData(m_project, data);
+ emitResult();
+}
+
+bool MesonImportJob::doKill()
+{
+ if (m_futureWatcher.isRunning()) {
+ m_futureWatcher.cancel();
+ }
+ return true;
+}
diff --git a/plugins/meson/mesonimportjob.h b/plugins/meson/mesonimportjob.h
new file mode 100644
index 0000000000..7000681cc9
--- /dev/null
+++ b/plugins/meson/mesonimportjob.h
@@ -0,0 +1,48 @@
+/* This file is part of KDevelop
+ Copyright 2017 Aleix Pol Gonzalez
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef MESONIMPORTJOB_H
+#define MESONIMPORTJOB_H
+
+#include
+#include
+#include
+#include
+
+class MesonManager;
+
+class MesonImportJob : public KJob
+{
+ Q_OBJECT
+
+public:
+ MesonImportJob(MesonManager* manager, KDevelop::IProject* project, QObject* parent);
+
+ void start() override;
+ bool doKill() override;
+
+private:
+ void importFinished();
+
+ KDevelop::IProject* m_project;
+ QFutureWatcher m_futureWatcher;
+ MesonManager* m_manager;
+};
+
+#endif // MESONIMPORTJOB_H
diff --git a/plugins/meson/mesonjob.cpp b/plugins/meson/mesonjob.cpp
new file mode 100644
index 0000000000..a2502c5a78
--- /dev/null
+++ b/plugins/meson/mesonjob.cpp
@@ -0,0 +1,77 @@
+/* This file is part of KDevelop
+ Copyright 2018 Daniel Mensinger
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "mesonjob.h"
+#include "mesonconfig.h"
+#include
+#include
+#include
+
+using namespace KDevelop;
+
+MesonJob::MesonJob(Meson::BuildDir const& buildDir, IProject* project, MesonJob::CommandType commandType,
+ const QStringList& arguments, QObject* parent)
+ : OutputExecuteJob(parent)
+ , m_project(project)
+ , m_commandType(commandType)
+ , m_arguments(arguments)
+{
+ Q_ASSERT(m_project);
+
+ setToolTitle(i18n("Meson"));
+ setCapabilities(Killable);
+ setStandardToolView(KDevelop::IOutputView::BuildView);
+ setBehaviours(KDevelop::IOutputView::AllowUserClose | KDevelop::IOutputView::AutoScroll);
+ setProperties(NeedWorkingDirectory | PortableMessages | DisplayStdout | DisplayStderr);
+
+ *this << buildDir.mesonExecutable.toLocalFile();
+
+ switch (m_commandType) {
+ case CONFIGURE:
+ if (!buildDir.installPrefix.isEmpty()) {
+ *this << QStringLiteral("--prefix") << buildDir.installPrefix.toLocalFile();
+ }
+
+ *this << QStringLiteral("--backend") << buildDir.mesonBackend;
+ *this << QStringLiteral("--buildtype") << buildDir.buildType;
+
+ for (auto const& i : buildDir.mesonArgs) {
+ *this << i;
+ }
+
+ break;
+ case RE_CONFIGURE:
+ *this << QStringLiteral("--reconfigure");
+ break;
+ case SET_CONFIG:
+ *this << QStringLiteral("configure");
+ if (!buildDir.installPrefix.isEmpty()) {
+ *this << QStringLiteral("-Dprefix=") + buildDir.installPrefix.toLocalFile();
+ }
+ *this << QStringLiteral("-Dbuildtype=") + buildDir.buildType;
+ }
+
+ *this << m_arguments;
+ *this << buildDir.buildDir.toLocalFile();
+}
+
+QUrl MesonJob::workingDirectory() const
+{
+ return m_project->path().toUrl();
+}
diff --git a/plugins/meson/mesonjob.h b/plugins/meson/mesonjob.h
new file mode 100644
index 0000000000..1d3fb3affa
--- /dev/null
+++ b/plugins/meson/mesonjob.h
@@ -0,0 +1,50 @@
+/* This file is part of KDevelop
+ Copyright 2018 Daniel Mensinger
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#pragma once
+
+#include
+
+namespace Meson
+{
+struct BuildDir;
+}
+
+namespace KDevelop
+{
+class IProject;
+}
+
+class MesonJob : public KDevelop::OutputExecuteJob
+{
+ Q_OBJECT
+public:
+ enum CommandType { CONFIGURE, RE_CONFIGURE, SET_CONFIG };
+
+public:
+ MesonJob(Meson::BuildDir const& buildDir, KDevelop::IProject* project, CommandType commandType,
+ QStringList const& arguments, QObject* parent);
+
+ QUrl workingDirectory() const override;
+
+private:
+ KDevelop::IProject* m_project = nullptr;
+ CommandType m_commandType;
+ QStringList m_arguments;
+};
diff --git a/plugins/meson/mesonjobprune.cpp b/plugins/meson/mesonjobprune.cpp
new file mode 100644
index 0000000000..248cf98078
--- /dev/null
+++ b/plugins/meson/mesonjobprune.cpp
@@ -0,0 +1,97 @@
+/* This file is part of KDevelop
+ Copyright 2018 Daniel Mensinger
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "mesonjobprune.h"
+#include "mesonbuilder.h"
+#include "mesonconfig.h"
+#include
+#include
+#include
+#include
+
+using namespace KDevelop;
+
+MesonJobPrune::MesonJobPrune(Meson::BuildDir const& buildDir, QObject* parent)
+ : OutputJob(parent, Verbose)
+ , m_buildDir(buildDir.buildDir)
+ , m_backend(buildDir.mesonBackend)
+{
+ setCapabilities(Killable);
+ setToolTitle(i18n("Meson"));
+ setStandardToolView(KDevelop::IOutputView::BuildView);
+ setBehaviours(KDevelop::IOutputView::AllowUserClose | KDevelop::IOutputView::AutoScroll);
+}
+
+void MesonJobPrune::start()
+{
+ auto* output = new OutputModel(this);
+ setModel(output);
+ startOutput();
+
+ auto status = MesonBuilder::evaluateBuildDirectory(m_buildDir, m_backend);
+
+ switch (status) {
+ case MesonBuilder::DOES_NOT_EXIST:
+ case MesonBuilder::CLEAN:
+ output->appendLine(i18n("The directory '%1' is already pruned", m_buildDir.toLocalFile()));
+ emitResult();
+ return;
+ case MesonBuilder::DIR_NOT_EMPTY:
+ case MesonBuilder::INVALID_BUILD_DIR:
+ output->appendLine(
+ i18n("The directory '%1' does not appear to be a meson build directory", m_buildDir.toLocalFile()));
+ output->appendLine(i18n("Aborting prune operation"));
+ emitResult();
+ return;
+ case MesonBuilder::EMPTY_STRING:
+ output->appendLine(
+ i18n("The current build configuration is broken, because the build directory is not specified"));
+ emitResult();
+ return;
+ default:
+ break;
+ }
+
+ QDir d(m_buildDir.toLocalFile());
+ QList urls;
+ const auto entries = d.entryList(QDir::NoDotAndDotDot | QDir::Hidden | QDir::AllEntries);
+ urls.reserve(entries.size());
+ for (const auto& entry : entries) {
+ urls << Path(m_buildDir, entry).toUrl();
+ }
+
+ output->appendLine(i18n("Deleting contents of '%1'", m_buildDir.toLocalFile()));
+ m_job = KIO::del(urls);
+ m_job->start();
+
+ connect(m_job, &KJob::finished, this, [this, output](KJob* job) {
+ if (job->error() == 0) {
+ output->appendLine(i18n("** Prune successful **"));
+ } else {
+ output->appendLine(i18n("** Prune failed: %1 **", job->errorString()));
+ }
+ emitResult();
+ m_job = nullptr;
+ });
+}
+
+bool MesonJobPrune::doKill()
+{
+ return m_job->kill();
+}
diff --git a/plugins/meson/mesonjobprune.h b/plugins/meson/mesonjobprune.h
new file mode 100644
index 0000000000..6552f57409
--- /dev/null
+++ b/plugins/meson/mesonjobprune.h
@@ -0,0 +1,43 @@
+/* This file is part of KDevelop
+ Copyright 2018 Daniel Mensinger
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#pragma once
+
+#include
+#include
+
+namespace Meson
+{
+struct BuildDir;
+}
+
+// "Inspired" by the CMake prune job
+class MesonJobPrune : public KDevelop::OutputJob
+{
+ Q_OBJECT
+public:
+ explicit MesonJobPrune(Meson::BuildDir const& buildDir, QObject* parent);
+ void start() override;
+ bool doKill() override;
+
+private:
+ KDevelop::Path m_buildDir;
+ QString m_backend;
+ KJob* m_job = nullptr;
+};
diff --git a/plugins/meson/mesonmanager.cpp b/plugins/meson/mesonmanager.cpp
new file mode 100644
index 0000000000..41644dacd8
--- /dev/null
+++ b/plugins/meson/mesonmanager.cpp
@@ -0,0 +1,189 @@
+/* This file is part of KDevelop
+ Copyright 2017 Aleix Pol Gonzalez
+ Copyright 2018 Daniel Mensinger
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "mesonmanager.h"
+#include "mesonbuilder.h"
+#include "mesonconfig.h"
+#include "mesonimportjob.h"
+#include "settings/mesonconfigpage.h"
+#include "settings/mesonnewbuilddir.h"
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#include "debug.h"
+
+using namespace KDevelop;
+
+static const QString GENERATOR_NINJA = QStringLiteral("ninja");
+
+K_PLUGIN_FACTORY_WITH_JSON(MesonSupportFactory, "kdevmesonmanager.json", registerPlugin();)
+
+MesonManager::MesonManager(QObject* parent, const QVariantList& args)
+ : AbstractFileManagerPlugin(QStringLiteral("KDevMesonManager"), parent, args)
+ , m_builder(new MesonBuilder(this))
+{
+ if (m_builder->hasError()) {
+ setErrorDescription(i18n("Meson builder error: %s", m_builder->errorDescription()));
+ }
+}
+
+MesonManager::~MesonManager()
+{
+ delete m_builder;
+}
+
+// *********************************
+// * AbstractFileManagerPlugin API *
+// *********************************
+
+IProjectFileManager::Features MesonManager::features() const
+{
+ return IProjectFileManager::Files | IProjectFileManager::Folders | IProjectFileManager::Targets;
+}
+
+ProjectFolderItem* MesonManager::createFolderItem(IProject* project, const Path& path, ProjectBaseItem* parent)
+{
+ // TODO: Maybe use meson targets instead
+ if (QFile::exists(path.toLocalFile() + QStringLiteral("/meson.build")))
+ return new ProjectBuildFolderItem(project, path, parent);
+ else
+ return AbstractFileManagerPlugin::createFolderItem(project, path, parent);
+}
+
+// ***************************
+// * IBuildSystemManager API *
+// ***************************
+
+KJob* MesonManager::createImportJob(ProjectFolderItem* item)
+{
+ auto project = item->project();
+ auto job = new MesonImportJob(this, project, this);
+
+ connect(job, &KJob::result, this, [this, job, project]() {
+ if (job->error() != 0) {
+ qCWarning(KDEV_Meson) << "couldn't load project successfully" << project->name();
+ m_projects.remove(project);
+ }
+ });
+
+ const QList jobs = {
+ builder()->configure(project), // Make sure the project is configured
+ job, // Import the compile_commands.json file
+ AbstractFileManagerPlugin::createImportJob(item) // generate the file system listing
+ };
+
+ Q_ASSERT(!jobs.contains(nullptr));
+ auto composite = new ExecuteCompositeJob(this, jobs);
+ composite->setAbortOnError(false);
+ return composite;
+}
+
+Path MesonManager::buildDirectory(ProjectBaseItem* item) const
+{
+ Q_ASSERT(item);
+ Meson::BuildDir buildDir = Meson::currentBuildDir(item->project());
+ return buildDir.buildDir;
+}
+
+IProjectBuilder* MesonManager::builder() const
+{
+ return m_builder;
+}
+
+Meson::BuildDir MesonManager::newBuildDirectory(IProject* project)
+{
+ Q_ASSERT(project);
+ MesonNewBuildDir newBD(project);
+
+ if (!newBD.exec() || !newBD.isConfigValid()) {
+ qCWarning(KDEV_Meson) << "Failed to create new build directory for project " << project->name();
+ return Meson::BuildDir();
+ }
+
+ Meson::BuildDir buildDir = newBD.currentConfig();
+ Meson::MesonConfig mesonCfg = Meson::getMesonConfig(project);
+ buildDir.canonicalizePaths();
+ mesonCfg.addBuildDir(buildDir);
+ Meson::writeMesonConfig(project, mesonCfg);
+
+ return buildDir;
+}
+
+QStringList MesonManager::supportedMesonBackends() const
+{
+ // Maybe add support for other generators
+ return { GENERATOR_NINJA };
+}
+
+QString MesonManager::defaultMesonBackend() const
+{
+ return GENERATOR_NINJA;
+}
+
+Path MesonManager::findMeson() const
+{
+ QString mesonPath;
+
+ const static QStringList mesonExecutables = { QStringLiteral("meson"), QStringLiteral("meson.py") };
+ const static QStringList mesonPaths
+ = { QStringLiteral("%1/.local/bin").arg(QStandardPaths::standardLocations(QStandardPaths::HomeLocation)[0]) };
+
+ for (auto const& i : mesonExecutables) {
+ mesonPath = QStandardPaths::findExecutable(i);
+ if (!mesonPath.isEmpty()) {
+ break;
+ }
+
+ mesonPath = QStandardPaths::findExecutable(i, mesonPaths);
+ if (!mesonPath.isEmpty()) {
+ break;
+ }
+ }
+
+ return Path(mesonPath);
+}
+
+void MesonManager::setProjectData(IProject* project, const QJsonObject& data)
+{
+ m_projects[project] = data;
+}
+
+ConfigPage* MesonManager::perProjectConfigPage(int number, const ProjectConfigOptions& options, QWidget* parent)
+{
+ if (number == 0) {
+ return new MesonConfigPage(this, options.project, parent);
+ }
+ return nullptr;
+}
+
+int MesonManager::perProjectConfigPages() const
+{
+ return 1;
+}
+
+#include "mesonmanager.moc"
diff --git a/plugins/meson/mesonmanager.h b/plugins/meson/mesonmanager.h
new file mode 100644
index 0000000000..ce0002e881
--- /dev/null
+++ b/plugins/meson/mesonmanager.h
@@ -0,0 +1,109 @@
+/* This file is part of KDevelop
+ Copyright 2017 Aleix Pol Gonzalez
+ Copyright 2018 Daniel Mensinger
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KDEVPLATFORM_PLUGIN_MESONMANAGER_H
+#define KDEVPLATFORM_PLUGIN_MESONMANAGER_H
+
+#include "mesonconfig.h"
+#include
+#include
+
+class MesonBuilder;
+
+class MesonManager : public KDevelop::AbstractFileManagerPlugin, public KDevelop::IBuildSystemManager
+{
+ Q_OBJECT
+ Q_INTERFACES(KDevelop::IBuildSystemManager)
+
+public:
+ explicit MesonManager(QObject* parent = nullptr, const QVariantList& args = QVariantList());
+ ~MesonManager() override;
+
+ // ********************
+ // * Custom functions *
+ // ********************
+
+ /// Create a new build directory and write it into the config
+ Meson::BuildDir newBuildDirectory(KDevelop::IProject* project);
+
+ /// Returns a list of all supported Meson backends (for now only ninja)
+ QStringList supportedMesonBackends() const;
+ QString defaultMesonBackend() const;
+
+ KDevelop::Path findMeson() const;
+
+ void setProjectData(KDevelop::IProject* project, const QJsonObject& data);
+
+ // *********************************
+ // * AbstractFileManagerPlugin API *
+ // *********************************
+
+ KDevelop::IProjectFileManager::Features features() const override;
+ KDevelop::ProjectFolderItem* createFolderItem(KDevelop::IProject* project, const KDevelop::Path& path,
+ KDevelop::ProjectBaseItem* parent = nullptr) override;
+
+ // ***********
+ // * IPlugin *
+ // ***********
+
+ KDevelop::ConfigPage* perProjectConfigPage(int number, const KDevelop::ProjectConfigOptions& options,
+ QWidget* parent) override;
+ int perProjectConfigPages() const override;
+
+ // ***************************
+ // * IBuildSystemManager API *
+ // ***************************
+
+ KJob* createImportJob(KDevelop::ProjectFolderItem* item) override;
+
+ KDevelop::IProjectBuilder* builder() const override;
+
+ // FIXME now: should use compile_commands.json for these (i.e. m_projects)
+ KDevelop::Path::List includeDirectories(KDevelop::ProjectBaseItem*) const override { return {}; }
+ KDevelop::Path::List frameworkDirectories(KDevelop::ProjectBaseItem*) const override { return {}; }
+ QHash defines(KDevelop::ProjectBaseItem*) const override { return {}; }
+ QString extraArguments(KDevelop::ProjectBaseItem* /*item*/) const override { return {}; }
+ bool hasBuildInfo(KDevelop::ProjectBaseItem* /*item*/) const override { return false; }
+
+ KDevelop::Path buildDirectory(KDevelop::ProjectBaseItem*) const override;
+
+ // fill if&when we have targets
+ QList targets(KDevelop::ProjectFolderItem*) const override { return {}; }
+
+ // you can ignore these for now I guess, but TODO
+ KDevelop::ProjectTargetItem* createTarget(const QString& /*target*/,
+ KDevelop::ProjectFolderItem* /*parent*/) override
+ {
+ return nullptr;
+ }
+ bool removeTarget(KDevelop::ProjectTargetItem* /*target*/) override { return false; }
+ bool addFilesToTarget(const QList& /*files*/,
+ KDevelop::ProjectTargetItem* /*target*/) override
+ {
+ return false;
+ }
+ bool removeFilesFromTargets(const QList& /*files*/) override { return false; }
+
+private:
+ MesonBuilder* m_builder;
+ QHash m_projects;
+};
+
+#endif
diff --git a/plugins/meson/settings/mesonadvancedsettings.cpp b/plugins/meson/settings/mesonadvancedsettings.cpp
new file mode 100644
index 0000000000..db1edc3f39
--- /dev/null
+++ b/plugins/meson/settings/mesonadvancedsettings.cpp
@@ -0,0 +1,66 @@
+/* This file is part of KDevelop
+ Copyright 2018 Daniel Mensinger
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "mesonadvancedsettings.h"
+#include "ui_mesonadvancedsettings.h"
+
+using namespace KDevelop;
+
+MesonAdvancedSettings::MesonAdvancedSettings(QWidget* parent)
+ : QWidget(parent)
+{
+ m_ui = new Ui::MesonAdvancedSettings;
+ m_ui->setupUi(this);
+ m_ui->container->hide();
+}
+
+MesonAdvancedSettings::~MesonAdvancedSettings()
+{
+ delete m_ui;
+}
+
+MesonAdvancedSettings::Data MesonAdvancedSettings::getConfig() const
+{
+ Data res;
+
+ res.args = m_ui->i_mesonArgs->text();
+ res.backend = m_ui->i_backend->currentText();
+ res.meson = Path(m_ui->i_mesonExe->url());
+
+ return res;
+}
+
+void MesonAdvancedSettings::setConfig(const MesonAdvancedSettings::Data& conf)
+{
+ m_ui->i_mesonArgs->setText(conf.args);
+ m_ui->i_mesonExe->setUrl(conf.meson.toUrl());
+ m_ui->i_backend->setCurrentIndex(std::max(0, m_backendList.indexOf(conf.backend)));
+}
+
+void MesonAdvancedSettings::setSupportedBackends(const QStringList& backends)
+{
+ m_backendList = backends;
+ m_ui->i_backend->clear();
+ m_ui->i_backend->addItems(m_backendList);
+}
+
+void MesonAdvancedSettings::updated()
+{
+ emit configChanged();
+}
diff --git a/plugins/meson/settings/mesonadvancedsettings.h b/plugins/meson/settings/mesonadvancedsettings.h
new file mode 100644
index 0000000000..d6c396a60f
--- /dev/null
+++ b/plugins/meson/settings/mesonadvancedsettings.h
@@ -0,0 +1,58 @@
+/* This file is part of KDevelop
+ Copyright 2018 Daniel Mensinger
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#pragma once
+
+#include "util/path.h"
+#include
+
+namespace Ui
+{
+class MesonAdvancedSettings;
+}
+
+class MesonAdvancedSettings : public QWidget
+{
+ Q_OBJECT
+public:
+ struct Data {
+ QString backend;
+ QString args;
+ KDevelop::Path meson;
+ };
+
+public:
+ explicit MesonAdvancedSettings(QWidget* parent = nullptr);
+ ~MesonAdvancedSettings() override;
+
+ Data getConfig() const;
+ void setConfig(Data const& conf);
+
+ void setSupportedBackends(QStringList const& backends);
+
+Q_SIGNALS:
+ void configChanged();
+
+public Q_SLOTS:
+ void updated();
+
+private:
+ Ui::MesonAdvancedSettings* m_ui = nullptr;
+ QStringList m_backendList;
+};
diff --git a/plugins/meson/settings/mesonadvancedsettings.ui b/plugins/meson/settings/mesonadvancedsettings.ui
new file mode 100644
index 0000000000..f9598345b3
--- /dev/null
+++ b/plugins/meson/settings/mesonadvancedsettings.ui
@@ -0,0 +1,247 @@
+
+
+ MesonAdvancedSettings
+
+
+
+ 0
+ 0
+ 500
+ 250
+
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+ -
+
+
+ Show advanced configuration
+
+
+
+ -
+
+
+ Advanced configuration
+
+
+
-
+
+
-
+
+
+ Extra Meson arguments:
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+ Qt::LeftToRight
+
+
+ Meson backend:
+
+
+ false
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+ Meson executable:
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+ Extra meson configuration arguments
+
+
+ true
+
+
+
+ -
+
+
+ -
+
+
+ Path to the meson executable
+
+
+
+
+
+ -
+
+
+ Hide advanced configuration
+
+
+
+
+
+
+
+
+
+
+ KLineEdit
+ QLineEdit
+
+
+
+ KComboBox
+ QComboBox
+
+
+
+ KUrlRequester
+ QWidget
+
+
+
+
+
+
+ b_showAdvanced
+ clicked()
+ container
+ show()
+
+
+ 249
+ 16
+
+
+ 249
+ 144
+
+
+
+
+ b_showAdvanced
+ clicked()
+ b_showAdvanced
+ hide()
+
+
+ 249
+ 16
+
+
+ 249
+ 16
+
+
+
+
+ b_hideAdvanced
+ clicked()
+ container
+ hide()
+
+
+ 249
+ 224
+
+
+ 249
+ 144
+
+
+
+
+ b_hideAdvanced
+ clicked()
+ b_showAdvanced
+ show()
+
+
+ 249
+ 224
+
+
+ 249
+ 16
+
+
+
+
+ i_mesonArgs
+ textChanged(QString)
+ MesonAdvancedSettings
+ updated()
+
+
+ 327
+ 90
+
+
+ 249
+ 124
+
+
+
+
+ i_backend
+ currentIndexChanged(int)
+ MesonAdvancedSettings
+ updated()
+
+
+ 327
+ 128
+
+
+ 249
+ 124
+
+
+
+
+ i_mesonExe
+ textChanged(QString)
+ MesonAdvancedSettings
+ updated()
+
+
+ 327
+ 175
+
+
+ 249
+ 124
+
+
+
+
+
+ configChanged()
+ updated()
+
+
diff --git a/plugins/meson/settings/mesonconfigpage.cpp b/plugins/meson/settings/mesonconfigpage.cpp
new file mode 100644
index 0000000000..9b42ac4c97
--- /dev/null
+++ b/plugins/meson/settings/mesonconfigpage.cpp
@@ -0,0 +1,320 @@
+/* This file is part of KDevelop
+ Copyright 2018 Daniel Mensinger
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "mesonconfigpage.h"
+#include "mesonbuilder.h"
+#include "mesonjob.h"
+#include "mesonmanager.h"
+#include "mesonnewbuilddir.h"
+#include "ui_mesonconfigpage.h"
+#include
+#include
+#include
+#include
+#include
+#include
+
+using namespace KDevelop;
+
+MesonConfigPage::MesonConfigPage(IPlugin* plugin, IProject* project, QWidget* parent)
+ : ConfigPage(plugin, nullptr, parent)
+ , m_project(project)
+{
+ Q_ASSERT(project); // Catch errors early
+ MesonManager* mgr = dynamic_cast(m_project->buildSystemManager());
+ Q_ASSERT(mgr); // This dialog only works with the MesonManager
+
+ m_ui = new Ui::MesonConfigPage;
+ m_ui->setupUi(this);
+ m_ui->advanced->setSupportedBackends(mgr->supportedMesonBackends());
+
+ m_config = Meson::getMesonConfig(m_project);
+ if (m_config.buildDirs.isEmpty()) {
+ m_config.currentIndex = -1;
+ reset();
+ return;
+ } else if (m_config.currentIndex < 0 || m_config.currentIndex >= m_config.buildDirs.size()) {
+ m_config.currentIndex = 0;
+ }
+
+ QStringList buildPathList;
+ for (auto& i : m_config.buildDirs) {
+ buildPathList << i.buildDir.toLocalFile();
+ }
+
+ m_ui->i_buildDirs->blockSignals(true);
+ m_ui->i_buildDirs->clear();
+ m_ui->i_buildDirs->addItems(buildPathList);
+ m_ui->i_buildDirs->setCurrentIndex(m_config.currentIndex);
+ m_ui->i_buildDirs->blockSignals(false);
+
+ reset();
+}
+
+void MesonConfigPage::writeConfig()
+{
+ qCDebug(KDEV_Meson) << "Writing config to file";
+ if (m_config.currentIndex >= 0) {
+ m_config.buildDirs[m_config.currentIndex] = m_current;
+ }
+
+ if (m_config.buildDirs.isEmpty()) {
+ m_config.currentIndex = -1;
+ } else if (m_config.currentIndex < 0 || m_config.currentIndex >= m_config.buildDirs.size()) {
+ m_config.currentIndex = 0;
+ }
+ Meson::writeMesonConfig(m_project, m_config);
+}
+
+void MesonConfigPage::apply()
+{
+ qCDebug(KDEV_Meson) << "Applying meson config for build dir " << m_current.buildDir;
+ readUI();
+ writeConfig();
+
+ if (m_config.currentIndex >= 0 && m_configChanged) {
+ QList joblist;
+
+ // Check if a configuration is required
+ auto status = MesonBuilder::evaluateBuildDirectory(m_current.buildDir, m_current.mesonBackend);
+ if (status != MesonBuilder::MESON_CONFIGURED) {
+ joblist << new MesonJob(m_current, m_project, MesonJob::CONFIGURE, {}, nullptr);
+ }
+
+ joblist << new MesonJob(m_current, m_project, MesonJob::SET_CONFIG, {}, nullptr);
+ joblist << new MesonJob(m_current, m_project, MesonJob::RE_CONFIGURE, {}, nullptr);
+ KJob* job = new ExecuteCompositeJob(nullptr, joblist);
+ connect(job, &KJob::result, this, [this]() {
+ setDisabled(false);
+ updateUI();
+ });
+ setDisabled(true);
+ m_configChanged = false;
+ job->start();
+ }
+}
+
+void MesonConfigPage::defaults()
+{
+ qCDebug(KDEV_Meson) << "Restoring build dir " << m_current.buildDir << " to it's default values";
+ MesonManager* mgr = dynamic_cast(m_project->buildSystemManager());
+ Q_ASSERT(mgr);
+
+ m_current.mesonArgs.clear();
+ m_current.mesonBackend = mgr->defaultMesonBackend();
+ m_current.mesonExecutable = mgr->findMeson();
+
+ updateUI();
+}
+
+void MesonConfigPage::reset()
+{
+ if (m_config.buildDirs.isEmpty()) {
+ m_config.currentIndex = -1;
+ m_ui->i_buildDirs->clear();
+ setWidgetsDisabled(true);
+ return;
+ } else if (m_config.currentIndex < 0 || m_config.currentIndex >= m_config.buildDirs.size()) {
+ m_config.currentIndex = 0;
+ m_ui->i_buildDirs->blockSignals(true);
+ m_ui->i_buildDirs->setCurrentIndex(m_config.currentIndex);
+ m_ui->i_buildDirs->blockSignals(false);
+ }
+
+ setWidgetsDisabled(false);
+ qCDebug(KDEV_Meson) << "Resetting changes for build dir " << m_current.buildDir;
+
+ m_current = m_config.buildDirs[m_config.currentIndex];
+ updateUI();
+}
+
+void MesonConfigPage::updateUI()
+{
+ m_ui->i_buildType->setCurrentIndex(1);
+
+ QStringList buildTypes = { QStringLiteral("plain"), QStringLiteral("debug"), QStringLiteral("debugoptimized"),
+ QStringLiteral("release"), QStringLiteral("minsize"), QStringLiteral("custom") };
+
+ m_ui->i_buildType->clear();
+ m_ui->i_buildType->addItems(buildTypes);
+ m_ui->i_buildType->setCurrentIndex(std::max(0, buildTypes.indexOf(m_current.buildType)));
+
+ m_ui->i_installPrefix->setUrl(m_current.installPrefix.toUrl());
+
+ auto aConf = m_ui->advanced->getConfig();
+ aConf.args = m_current.mesonArgs;
+ aConf.backend = m_current.mesonBackend;
+ aConf.meson = m_current.mesonExecutable;
+ m_ui->advanced->setConfig(aConf);
+
+ // Get the config build dir status
+ auto status = MesonBuilder::evaluateBuildDirectory(m_current.buildDir, m_current.mesonBackend);
+ auto setStatus = [this](QString const& msg, int color) -> void {
+ KColorScheme scheme(QPalette::Normal);
+ KColorScheme::ForegroundRole role;
+ switch (color) {
+ case 0:
+ role = KColorScheme::PositiveText;
+ break;
+ case 1:
+ role = KColorScheme::NeutralText;
+ break;
+ case 2:
+ default:
+ role = KColorScheme::NegativeText;
+ break;
+ }
+
+ QPalette pal = m_ui->l_status->palette();
+ pal.setColor(QPalette::Foreground, scheme.foreground(role).color());
+ m_ui->l_status->setPalette(pal);
+ m_ui->l_status->setText(i18n("Status: %1", msg));
+ };
+
+ switch (status) {
+ case MesonBuilder::DOES_NOT_EXIST:
+ setStatus(i18n("The current build direcory does not exist"), 1);
+ break;
+ case MesonBuilder::CLEAN:
+ setStatus(i18n("The current build direcory is empty"), 1);
+ break;
+ case MesonBuilder::MESON_CONFIGURED:
+ setStatus(i18n("Build direcory configured"), 0);
+ break;
+ case MesonBuilder::MESON_FAILED_CONFIGURATION:
+ setStatus(i18n("This meson build direcory is not fully configured"), 1);
+ break;
+ case MesonBuilder::INVALID_BUILD_DIR:
+ setStatus(i18n("The current build directory is invalid"), 2);
+ break;
+ case MesonBuilder::DIR_NOT_EMPTY:
+ setStatus(i18n("This directory does not seem to be a meson build direcory"), 2);
+ break;
+ case MesonBuilder::EMPTY_STRING:
+ setStatus(i18n("Invalid build directory configuration (empty build direcory string)"), 2);
+ break;
+ case MesonBuilder::___UNDEFINED___:
+ setStatus(i18n("Something went verry wrong. This is a bug"), 2);
+ break;
+ }
+}
+
+void MesonConfigPage::readUI()
+{
+ qCDebug(KDEV_Meson) << "Reading current build configuration from the UI " << m_current.buildDir.toLocalFile();
+ m_current.installPrefix = Path(m_ui->i_installPrefix->url());
+ m_current.buildType = m_ui->i_buildType->currentText();
+
+ auto aConf = m_ui->advanced->getConfig();
+ m_current.mesonArgs = aConf.args;
+ m_current.mesonBackend = aConf.backend;
+ m_current.mesonExecutable = aConf.meson;
+}
+
+void MesonConfigPage::setWidgetsDisabled(bool disabled)
+{
+ m_ui->advanced->setDisabled(disabled);
+ m_ui->c_01_basic->setDisabled(disabled);
+ m_ui->c_02_buildConfig->setDisabled(disabled);
+ m_ui->b_rmDir->setDisabled(disabled);
+}
+
+void MesonConfigPage::addBuildDir()
+{
+ qCDebug(KDEV_Meson) << "Adding build directory";
+ MesonManager* mgr = dynamic_cast(m_project->buildSystemManager());
+ MesonBuilder* bld = dynamic_cast(mgr->builder());
+ Q_ASSERT(mgr);
+ Q_ASSERT(bld);
+ MesonNewBuildDir newBD(m_project);
+
+ if (!newBD.exec() || !newBD.isConfigValid()) {
+ qCDebug(KDEV_Meson) << "Failed to create a new build directory";
+ return;
+ }
+
+ m_current = newBD.currentConfig();
+ m_config.currentIndex = m_config.addBuildDir(m_current);
+ m_ui->i_buildDirs->blockSignals(true);
+ m_ui->i_buildDirs->addItem(m_current.buildDir.toLocalFile());
+ m_ui->i_buildDirs->setCurrentIndex(m_config.currentIndex);
+ m_ui->i_buildDirs->blockSignals(false);
+
+ setWidgetsDisabled(true);
+ writeConfig();
+ KJob* job = bld->configure(m_project);
+ connect(job, &KJob::result, this, [this]() { reset(); });
+ job->start();
+}
+
+void MesonConfigPage::removeBuildDir()
+{
+ qCDebug(KDEV_Meson) << "Removing current build directory";
+ m_ui->i_buildDirs->blockSignals(true);
+ m_ui->i_buildDirs->removeItem(m_config.currentIndex);
+ m_config.removeBuildDir(m_config.currentIndex);
+ if (m_config.buildDirs.isEmpty()) {
+ m_config.currentIndex = -1;
+ } else if (m_config.currentIndex < 0 || m_config.currentIndex >= m_config.buildDirs.size()) {
+ m_config.currentIndex = 0;
+ }
+ m_ui->i_buildDirs->setCurrentIndex(m_config.currentIndex);
+ m_ui->i_buildDirs->blockSignals(false);
+ reset();
+ writeConfig();
+}
+
+void MesonConfigPage::changeBuildDirIndex(int index)
+{
+ if (index == m_config.currentIndex || m_config.buildDirs.isEmpty()) {
+ return;
+ }
+
+ if (index < 0 || index >= m_config.buildDirs.size()) {
+ qCWarning(KDEV_Meson) << "Invalid build dir index " << index;
+ return;
+ }
+
+ qCDebug(KDEV_Meson) << "Changing build directory to index " << index;
+
+ m_config.currentIndex = index;
+ reset();
+ writeConfig();
+}
+
+void MesonConfigPage::emitChanged()
+{
+ m_configChanged = true;
+ emit changed();
+}
+
+QString MesonConfigPage::name() const
+{
+ return i18n("Meson");
+}
+
+QString MesonConfigPage::fullName() const
+{
+ return i18n("Meson project configuration");
+}
+
+QIcon MesonConfigPage::icon() const
+{
+ return QIcon::fromTheme(QStringLiteral("meson"));
+}
diff --git a/plugins/meson/settings/mesonconfigpage.h b/plugins/meson/settings/mesonconfigpage.h
new file mode 100644
index 0000000000..9aa35d8fb2
--- /dev/null
+++ b/plugins/meson/settings/mesonconfigpage.h
@@ -0,0 +1,67 @@
+/* This file is part of KDevelop
+ Copyright 2018 Daniel Mensinger
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#pragma once
+
+#include
+#include "mesonconfig.h"
+
+namespace KDevelop
+{
+class IPlugin;
+class IProject;
+}
+
+namespace Ui {
+ class MesonConfigPage;
+}
+
+class MesonConfigPage : public KDevelop::ConfigPage
+{
+ Q_OBJECT
+public:
+ explicit MesonConfigPage(KDevelop::IPlugin* plugin, KDevelop::IProject *project, QWidget* parent = nullptr);
+
+ QString name() const override;
+ QString fullName() const override;
+ QIcon icon() const override;
+
+public Q_SLOTS:
+ void apply() override;
+ void defaults() override;
+ void reset() override;
+
+ void addBuildDir();
+ void removeBuildDir();
+ void changeBuildDirIndex(int index);
+ void emitChanged();
+
+private:
+ void updateUI();
+ void readUI();
+ void writeConfig();
+ void setWidgetsDisabled(bool disabled);
+
+private:
+ KDevelop::IProject *m_project = nullptr;
+ Ui::MesonConfigPage *m_ui = nullptr;
+ Meson::MesonConfig m_config;
+ Meson::BuildDir m_current;
+ bool m_configChanged = false;
+};
diff --git a/plugins/meson/settings/mesonconfigpage.ui b/plugins/meson/settings/mesonconfigpage.ui
new file mode 100644
index 0000000000..7b14f0edcb
--- /dev/null
+++ b/plugins/meson/settings/mesonconfigpage.ui
@@ -0,0 +1,303 @@
+
+
+ MesonConfigPage
+
+
+
+ 0
+ 0
+ 587
+ 499
+
+
+
+ -
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+ -
+
+
+ ...
+
+
+
+ ../../../../../.designer/backup../../../../../.designer/backup
+
+
+
+ -
+
+
+ ...
+
+
+
+ ../../../../../.designer/backup../../../../../.designer/backup
+
+
+
+
+
+ -
+
+
+ Basic configuration
+
+
+
-
+
+
+ Build type:
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+ -
+
+
+ KFile::Directory|KFile::ExistingOnly|KFile::LocalOnly
+
+
+ Full path to the installation prefix
+
+
+
+ -
+
+
+ Installation prefix:
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+
+
+
+ -
+
+
+ true
+
+
+ Build configuration
+
+
+
-
+
+
+ true
+
+
+
+
+ 0
+ 0
+ 555
+ 237
+
+
+
+
-
+
+
+ false
+
+
+ TODO -- Implement in seperate UI file
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+ -
+
+
+ Status message...
+
+
+
+
+
+
+
+ KComboBox
+ QComboBox
+
+
+
+ KUrlRequester
+ QWidget
+
+
+
+ MesonAdvancedSettings
+ QWidget
+ settings/mesonadvancedsettings.h
+ 1
+
+ configChanged()
+
+
+
+
+
+
+ b_addDir
+ clicked()
+ MesonConfigPage
+ addBuildDir()
+
+
+ 529
+ 22
+
+
+ 295
+ 246
+
+
+
+
+ b_rmDir
+ clicked()
+ MesonConfigPage
+ removeBuildDir()
+
+
+ 567
+ 22
+
+
+ 295
+ 246
+
+
+
+
+ i_buildDirs
+ currentIndexChanged(int)
+ MesonConfigPage
+ changeBuildDirIndex(int)
+
+
+ 257
+ 22
+
+
+ 295
+ 246
+
+
+
+
+ i_buildDirs
+ currentIndexChanged(int)
+ MesonConfigPage
+ emitChanged()
+
+
+ 255
+ 22
+
+
+ 293
+ 249
+
+
+
+
+ i_installPrefix
+ textChanged(QString)
+ MesonConfigPage
+ emitChanged()
+
+
+ 351
+ 133
+
+
+ 293
+ 249
+
+
+
+
+ advanced
+ configChanged()
+ MesonConfigPage
+ emitChanged()
+
+
+ 293
+ 487
+
+
+ 293
+ 249
+
+
+
+
+ i_buildType
+ currentIndexChanged(int)
+ MesonConfigPage
+ emitChanged()
+
+
+ 351
+ 95
+
+
+ 293
+ 249
+
+
+
+
+
+ addBuildDir()
+ removeBuildDir()
+ changeBuildDirIndex(int)
+ emitChanged()
+
+
diff --git a/plugins/meson/settings/mesonnewbuilddir.cpp b/plugins/meson/settings/mesonnewbuilddir.cpp
new file mode 100644
index 0000000000..a0300c5bb4
--- /dev/null
+++ b/plugins/meson/settings/mesonnewbuilddir.cpp
@@ -0,0 +1,211 @@
+/* This file is part of KDevelop
+ Copyright 2018 Daniel Mensinger
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "mesonnewbuilddir.h"
+#include "mesonbuilder.h"
+#include "mesonmanager.h"
+#include "ui_mesonnewbuilddir.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+using namespace KDevelop;
+
+MesonNewBuildDir::MesonNewBuildDir(IProject* project, QWidget* parent)
+ : QDialog(parent)
+ , m_project(project)
+{
+ Q_ASSERT(project); // Just in case
+ MesonManager* mgr = dynamic_cast(m_project->buildSystemManager());
+ Q_ASSERT(mgr); // This dialog only works with the MesonManager
+
+ setWindowTitle(
+ i18n("Configure a build directory - %1", ICore::self()->runtimeController()->currentRuntime()->name()));
+
+ m_ui = new Ui::MesonNewBuildDir;
+ m_ui->setupUi(this);
+
+ m_ui->advanced->setSupportedBackends(mgr->supportedMesonBackends());
+
+ connect(m_ui->b_buttonBox, &QDialogButtonBox::clicked, this, [this](QAbstractButton* b) {
+ if (m_ui->b_buttonBox->buttonRole(b) == QDialogButtonBox::ResetRole) {
+ resetFields();
+ }
+ });
+
+ resetFields();
+}
+
+MesonNewBuildDir::~MesonNewBuildDir()
+{
+ delete m_ui;
+}
+
+void MesonNewBuildDir::resetFields()
+{
+ Meson::MesonConfig cfg = Meson::getMesonConfig(m_project);
+ Path projectPath = m_project->path();
+ MesonManager* mgr = dynamic_cast(m_project->buildSystemManager());
+ Q_ASSERT(mgr); // This dialog only works with the MesonManager
+
+ auto aConf = m_ui->advanced->getConfig();
+
+ // Find a build dir that is not already configured
+ Path buildDirPath = projectPath;
+ buildDirPath.addPath(QStringLiteral("build"));
+
+ auto checkInCfg = [](Meson::MesonConfig const& cfg, Path const& p) -> bool {
+ for (auto const& i : cfg.buildDirs) {
+ if (i.buildDir == p) {
+ return true;
+ }
+ }
+ return false;
+ };
+
+ for (int i = 2; checkInCfg(cfg, buildDirPath); ++i) {
+ buildDirPath = projectPath;
+ buildDirPath.addPath(QStringLiteral("build%1").arg(i));
+ }
+
+ m_ui->i_buildDir->setUrl(buildDirPath.toUrl());
+
+ // Init build type
+ // TODO use introspection once https://github.com/mesonbuild/meson/pull/4564 is merged
+ QStringList buildTypes = { QStringLiteral("plain"), QStringLiteral("debug"), QStringLiteral("debugoptimized"),
+ QStringLiteral("release"), QStringLiteral("minsize"), QStringLiteral("custom") };
+
+ m_ui->i_buildType->clear();
+ m_ui->i_buildType->addItems(buildTypes);
+ m_ui->i_buildType->setCurrentIndex(std::max(0, buildTypes.indexOf(QStringLiteral("debug"))));
+
+ // Install prefix
+ m_ui->i_installPrefix->clear();
+
+ // Extra args
+ aConf.args.clear();
+
+ // Backend
+ aConf.backend = mgr->defaultMesonBackend();
+
+ // Meson exe
+ aConf.meson = mgr->findMeson();
+
+ m_ui->advanced->setConfig(aConf);
+ updated();
+}
+
+void MesonNewBuildDir::setStatus(const QString& str, bool validConfig)
+{
+ m_configIsValid = validConfig;
+
+ KColorScheme scheme(QPalette::Normal);
+ KColorScheme::ForegroundRole role;
+ if (validConfig) {
+ role = KColorScheme::PositiveText;
+ } else {
+ role = KColorScheme::NegativeText;
+ }
+
+ QPalette pal = m_ui->l_statusMessage->palette();
+ pal.setColor(QPalette::Foreground, scheme.foreground(role).color());
+ m_ui->l_statusMessage->setPalette(pal);
+ m_ui->l_statusMessage->setText(str);
+
+ auto okButton = m_ui->b_buttonBox->button(QDialogButtonBox::Ok);
+ okButton->setEnabled(m_configIsValid);
+ if (m_configIsValid) {
+ auto cancelButton = m_ui->b_buttonBox->button(QDialogButtonBox::Cancel);
+ cancelButton->clearFocus();
+ }
+}
+
+void MesonNewBuildDir::updated()
+{
+ auto advanced = m_ui->advanced->getConfig();
+ Path buildDir = Path(m_ui->i_buildDir->url());
+ QFileInfo mesonExe(advanced.meson.toLocalFile());
+
+ if (!mesonExe.exists() || !mesonExe.isExecutable()
+ || !mesonExe.permission(QFileDevice::ReadUser | QFileDevice::ExeUser)) {
+ setStatus(i18n("Specified meson executable does not exist"), false);
+ return;
+ }
+
+ MesonBuilder::DirectoryStatus status = MesonBuilder::evaluateBuildDirectory(buildDir, advanced.backend);
+ switch (status) {
+ case MesonBuilder::CLEAN:
+ case MesonBuilder::DOES_NOT_EXIST:
+ setStatus(i18n("Creating new build directory"), true);
+ break;
+ case MesonBuilder::MESON_CONFIGURED:
+ setStatus(i18n("Using an already configured build directory"), true);
+ break;
+ case MesonBuilder::MESON_FAILED_CONFIGURATION:
+ setStatus(i18n("Using a broken meson build directory (this should be fine)"), true);
+ break;
+ case MesonBuilder::INVALID_BUILD_DIR:
+ setStatus(i18n("Cannot use specified directory"), false);
+ break;
+ case MesonBuilder::DIR_NOT_EMPTY:
+ setStatus(i18n("There are already files in the build directory"), false);
+ break;
+ case MesonBuilder::EMPTY_STRING:
+ setStatus(i18n("The build directory field must not be empty"), false);
+ break;
+ case MesonBuilder::___UNDEFINED___:
+ setStatus(i18n("You have reached unreachable code. This is a bug"), false);
+ break;
+ }
+}
+
+Meson::BuildDir MesonNewBuildDir::currentConfig() const
+{
+ Meson::BuildDir buildDir;
+ if (!m_configIsValid) {
+ qCDebug(KDEV_Meson) << "Cannot generate build dir config from invalid config";
+ return buildDir;
+ }
+
+ auto advanced = m_ui->advanced->getConfig();
+
+ buildDir.buildDir = Path(m_ui->i_buildDir->url());
+ buildDir.buildType = m_ui->i_buildType->currentText();
+ buildDir.installPrefix = Path(m_ui->i_installPrefix->url());
+ buildDir.mesonArgs = advanced.args;
+ buildDir.mesonBackend = advanced.backend;
+ buildDir.mesonExecutable = advanced.meson;
+
+ return buildDir;
+}
+
+bool MesonNewBuildDir::isConfigValid() const
+{
+ return m_configIsValid;
+}
diff --git a/plugins/meson/settings/mesonnewbuilddir.h b/plugins/meson/settings/mesonnewbuilddir.h
new file mode 100644
index 0000000000..151f5e6ed2
--- /dev/null
+++ b/plugins/meson/settings/mesonnewbuilddir.h
@@ -0,0 +1,57 @@
+/* This file is part of KDevelop
+ Copyright 2018 Daniel Mensinger
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#pragma once
+
+#include "mesonconfig.h"
+#include
+
+class QDialogButtonBox;
+
+namespace KDevelop {
+ class IProject;
+}
+
+namespace Ui
+{
+class MesonNewBuildDir;
+}
+
+class MesonNewBuildDir : public QDialog
+{
+ Q_OBJECT
+public:
+ explicit MesonNewBuildDir(KDevelop::IProject *project, QWidget* parent = nullptr);
+ ~MesonNewBuildDir() override;
+ MesonNewBuildDir() = delete;
+
+ void setStatus(QString const& str, bool validConfig);
+
+ bool isConfigValid() const;
+ Meson::BuildDir currentConfig() const;
+
+private Q_SLOTS:
+ void resetFields();
+ void updated();
+
+private:
+ bool m_configIsValid = false;
+ KDevelop::IProject* m_project = nullptr;
+ Ui::MesonNewBuildDir* m_ui = nullptr;
+};
diff --git a/plugins/meson/settings/mesonnewbuilddir.ui b/plugins/meson/settings/mesonnewbuilddir.ui
new file mode 100644
index 0000000000..e5293cc419
--- /dev/null
+++ b/plugins/meson/settings/mesonnewbuilddir.ui
@@ -0,0 +1,260 @@
+
+
+ MesonNewBuildDir
+
+
+
+ 0
+ 0
+ 650
+ 625
+
+
+
+
+
+
+ -
+
+
+ Basic configuration
+
+
+
-
+
+
+ Build directory:
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+ Installation prefix:
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+ KFile::Directory|KFile::ExistingOnly|KFile::LocalOnly
+
+
+ QFileDialog::AcceptSave
+
+
+ Full Path to the new build directory
+
+
+
+ -
+
+
+ Build type:
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+ -
+
+
+ KFile::Directory|KFile::ExistingOnly|KFile::LocalOnly
+
+
+ Full path to the installation prefix
+
+
+
+
+
+
+ -
+
+
+ true
+
+
+ Build configuration
+
+
+
-
+
+
+ true
+
+
+
+
+ 0
+ 0
+ 618
+ 353
+
+
+
+
-
+
+
+ false
+
+
+ TODO -- Implement in seperate UI file
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+ -
+
+
-
+
+
+ Status message...
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::Reset
+
+
+
+
+
+
+
+
+
+ KComboBox
+ QComboBox
+
+
+
+ KUrlRequester
+ QWidget
+
+
+
+ MesonAdvancedSettings
+ QWidget
+ settings/mesonadvancedsettings.h
+ 1
+
+ configChanged()
+
+
+
+
+
+
+ b_buttonBox
+ accepted()
+ MesonNewBuildDir
+ accept()
+
+
+ 564
+ 643
+
+
+ 329
+ 333
+
+
+
+
+ b_buttonBox
+ rejected()
+ MesonNewBuildDir
+ reject()
+
+
+ 564
+ 643
+
+
+ 329
+ 333
+
+
+
+
+ i_buildDir
+ textChanged(QString)
+ MesonNewBuildDir
+ updated()
+
+
+ 383
+ 55
+
+
+ 324
+ 312
+
+
+
+
+ advanced
+ configChanged()
+ MesonNewBuildDir
+ updated()
+
+
+ 324
+ 571
+
+
+ 324
+ 312
+
+
+
+
+
+ resetFields()
+ updated()
+
+