diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -130,6 +130,7 @@ add_subdirectory(standardoutputview) add_subdirectory(switchtobuddy) add_subdirectory(testview) +add_subdirectory(meson) ecm_optional_add_subdirectory(classbrowser) ecm_optional_add_subdirectory(executeplasmoid) ecm_optional_add_subdirectory(ghprovider) diff --git a/plugins/meson/CMakeLists.txt b/plugins/meson/CMakeLists.txt new file mode 100644 --- /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 --- /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 0000000000000000000000000000000000000000..f09f8fd3c405de223ab89fa1e63ce347ccbb9387 GIT binary patch literal 3942 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 A!~g&Q literal 0 Hc$@1T7<^v=?dB zs$HwlNKF?ZD zxD{v;-G&fM#prZ-F0K^ilG3X46>wx^ywCB-I|$L83K-L4S9D;qq9I$SClQ>hku_Z2 z^!gv7C(BEQYre1}NjOz4Bu2~Whri&_`?9LhnuYC2Ps5Y5Q0pM=F`;6ioz|$AGw;DG?K2r QRsaA107*qoM6N<$g6FOXbN~PV literal 0 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 T59!en@LyAwSCgxjF$w-3i0ekk literal 0 Hc$@XG$=`)o0kbIcYNk2`}zB74%^3YH!qWL3T&ak5-ypE9x{;u zw2$F7W_cN*AEh;*o>O?~+cclpoOON35tKooIiNbPFqB{6^_c-y%M~W*LqWu zX#;?i#u3Dg$Jt*6K$U~_yx$n544^dDW2?eb6#(`Q(?zXk`O z;Lwe~Hnwa&uCM?cssI3oQXXdz5~@5C#0R_vYz3aRB{05;M}X0_pamYX)kJ|)lWBSY zx;)x}2g`I#3MWzPAx}-Ec?F>J7`sGBS)OtV7&S$24_ni0c(ZJJBKrMsx@`7ANM@4& zrelN_;NEH<%r7+X)dpD%-$#$n&+FrcCB}iQW!vukW5i6%C%H!IDukcU9$;l-o@XvH zfEd56k53Y5#s2F zKuT1kbg~-x|26pI0W%>SyVFQW4bM9KXj%U3s&8EQqG~NxnUONEI}O6E7S)xXdaBc% zHM|8SVp^#E%ZkH$!R6JZQ2y+YE{{yHU{nB@N^?V4oclcPR;AS!no%4PE}>+m&N0m( zzO`BL$Xm#skxq}x0!=}KTQ=j2AE0n8`o29w#N#eGO9z%QBIIpG7Z2nCxX(;2weF!1)?xbH?yoXq#5x zFdAB}wdi{s!(&suybyj>gP2q+O?gwQ53aI&wvP))NDERX-J>+;ax{z5sKSCcXv;i* go;*U1|0N**02VnET$4!bbpQYW07*qoM6N<$f;F4#>;M1& literal 0 Hc$@-}jEz94F`~54R&INH&a*%6mHxUv z&U<>!Lb5(d|LD2reV_OFp67j@@AJIpz^u&5tjx;)u}IK?^+^`Tlxx)CGV!SPgmcDY z2w~857^?gay`8O$g|W!>zu_v+;cA6tqEsW)2#hEU3-sc0d}$3Q_BY{13P3!`MuF|X zW?+7a+tVn|itt!hf+Il;Z%lHR!ViFzK5jpY@Pc^k?P}%^p#rdG4@=52{1V~L0CuDm zzTTZ+k0scT3p^aqX`b>7Ej`=#V8#H{Ct2(Wuc0iTffuVPP2J7>-ly^37Wl~wcTP{m zhkU;Cn+z4Z$rN8U;=nUAG#)@icw)^SmiXE40zV2NbgUbx4m!_{=`$15FW8uSJC;CD%rw zQsJv>enpvY0NfFpfVq*_UjzUZ7DmK)uP86$Hs1iKur)IB?G*+9kMgM0s^kyA(*TJ7 znp$8(WcC;F00bw(x@XI(cB)DOAP!&3#;VAwuSG?En;#(nRaIltsl3UviZ4c7el9NJ zri-G~t-?J;0oc5YIZ?WQE+Xfp)$zU5pwVQ33FvRi*_a=I{%URpDkJVe)U8iaKkaIU z1msUuA);SBFptj_1VDvN0jC}Wdi^H?en{)M?uK@*7kJd?a2MsT2&V&j;2i}45V$#j zTm7^G7Nru@snYCo)W(K74m2dWqan#RaOngV_%YrHx2Bp|o!Um73g61wWJitj_5(H~ zsYt^BOx`0U|@%~g|GDD3gc}d7matb*?tel0f-$(x>4@e7Z zER9#=^3X)%b9_D-VE}E*6UCpf_1Vnmc+GJU0QG3JoaohqJ9&HR#RWsWl#2!$%AaI0O9i+%a7zxW^{2;C6?(A%|>vw8KwZ!KMEvIlJ5#T_kT0?I!v5X}P6cb=tS(TUL#dvW}U{q27d0H-`08=co? zw{scSSk}~U``lv(L-haGeR7jy7PHo@YNyH=wFbb~({Np02r&a3@Z|t@08o)(xlua+ z)J^+~@IB2O0^SIN0rs5qH;;;4`gI)E8t@N*!ns2&WPI*Nb%hpSct+Vz_&%-vGD?}l zJC<~QwE;e1v6%O56uh~e!G8PHuAV z3LVJ(MJ=QFJk?T|V+3LrlV6r2PM4-Af`vT-uCXFPV2-B4d3hlUS=Y`2>^jS1#+I`$ za3gMA&%^<=@S#fqk8uq;y~|QeE(q%`RRD}- zHnef4z|T;sqgtK=2Tdl;o8Ys+30%?eV1ShNK*ZtWy@Mxt%N%OqeZ{Jy8o++83NR+x zcLkK+(TZoXZ6O{en&YgGIJX2qZ74$XGa~!~a$VuBog4@5%M}t)ctCFe)J{kE^ml#q z4a3E=!Bm3hFx&-pC8$pTo)0i)e?-Q2RGi|w7un;)-%{In(eYRfyb_|yV@^4b+YVY< z#ghns3~?QA0e7boe0k!hJO%e=d^a~3*y0JF6}Sm33k~R3=upG={Cv5QPd4vjPX9a} z1zNzm7x8ZHys*=AInc8sf6Lr=a9YtpdF2qbMz~UPxmg_M;Z3f;Js1#&)0qn#_uW4% zAzM3e`p&b|by#AQk0H|=9%>j;NIMzMD7=&JD1BCDWmaZoR;I{*0S-?o>~_ncl>h($ M07*qoM6N<$f*Gr+y8r+H literal 0 Hc$@ + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/plugins/meson/kdevmesonmanager.json b/plugins/meson/kdevmesonmanager.json new file mode 100644 --- /dev/null +++ b/plugins/meson/kdevmesonmanager.json @@ -0,0 +1,68 @@ +{ + "KPlugin": { + "Category": "Project Management", + "Description": "Imports and edits Meson projects", + "Description[ca@valencia]": "Importa i edita projectes del Meson", + "Description[ca]": "Importa i edita projectes del Meson", + "Description[cs]": "Importuje a upravuje vlastní projekty Meson", + "Description[de]": "Import und Bearbeitung von benutzerdefinierten Meson-Projekten", + "Description[es]": "Importa y edita proyectos Meson", + "Description[et]": "Meson'i projektide import ja muutmine", + "Description[fi]": "Tuo ja muokkaa Meson-projekteja", + "Description[fr]": "Importe et édite des projet Meson", + "Description[gl]": "Importa e edita proxectos Meson.", + "Description[it]": "Importa e modifica i progetti Meson", + "Description[nl]": "Importeert en bewerkt Meson-projecten", + "Description[pl]": "Importuje i edytuje projekty Meson", + "Description[pt]": "Importa e edita os projectos do Meson", + "Description[pt_BR]": "Importa e edita os projetos do Meson", + "Description[sk]": "Importuje a upravuje projekty Meson", + "Description[sl]": "Uvozi in ureja projekte po meri temelječe na Meson", + "Description[sv]": "Importerar och redigerar Meson-projekt", + "Description[tr]": "Meson projelerini içeriye aktarır ve düzenler", + "Description[uk]": "Імпортує і дає змогу редагувати проекти Meson", + "Description[x-test]": "xxImports and edits Meson projectsxx", + "Description[zh_CN]": "导入并编辑 Meson 工程", + "Icon": "qtlogo", + "Id": "KDevMesonManager", + "Name": "Meson Project Manager", + "Name[ca@valencia]": "Gestor de projectes Meson", + "Name[ca]": "Gestor de projectes Meson", + "Name[cs]": "Správce projektů Meson", + "Name[de]": "Meson-Projektverwaltung", + "Name[es]": "Gestor de proyectos Meson", + "Name[et]": "Meson'i projektihaldur", + "Name[fi]": "Meson-projektinhallinta", + "Name[fr]": "Gestionnaire de projet Meson", + "Name[gl]": "Xestor de proxectos Meson", + "Name[it]": "Gestore progetto Meson", + "Name[nl]": "Meson-projectbeheerder", + "Name[pl]": "Zarządzanie projektem Meson", + "Name[pt]": "Gestor de Projectos Meson", + "Name[pt_BR]": "Gerenciador de projetos do Meson", + "Name[sk]": "Správca projektov Meson", + "Name[sl]": "Upravljalnik projektov Meson", + "Name[sv]": "Meson-projekthantering", + "Name[tr]": "Meson Proje Yöneticisi", + "Name[uk]": "Керування проектами Meson", + "Name[x-test]": "xxMeson Project Managerxx", + "Name[zh_CN]": "Meson 工程管理器", + "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.h b/plugins/meson/mesonbuilder.h new file mode 100644 --- /dev/null +++ b/plugins/meson/mesonbuilder.h @@ -0,0 +1,74 @@ +/* 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, + 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); + + 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; + + KJob* configureIfRequired(KDevelop::IProject* project, KJob *realJob); +}; diff --git a/plugins/meson/mesonbuilder.cpp b/plugins/meson/mesonbuilder.cpp new file mode 100644 --- /dev/null +++ b/plugins/meson/mesonbuilder.cpp @@ -0,0 +1,237 @@ +/* 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) + { + } + + void start() override + { + auto* output = new OutputModel(this); + setModel(output); + startOutput(); + + output->appendLine(i18n(" *** MESON ERROR ***")); + output->appendLine(QStringLiteral("")); + QStringList lines = m_error.split(QChar((int)'\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*))); + } + } +} + +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; + } + + QStringList requiredPaths = { QStringLiteral("meson-logs"), QStringLiteral("meson-private") }; + if (backend == QStringLiteral("ninja")) { + requiredPaths += QStringLiteral("build.ninja"); + } + + // Check if this is a meson directory + QStringList entries = dir.entryList(); + for (auto const& i : requiredPaths) { + if (!entries.contains(i)) { + return DIR_NOT_EMPTY; + } + } + + 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: + 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 seam to be an already configured build directory", + buildDir.buildDir.toLocalFile())); + case INVALID_BUILD_DIR: + return new ErrorJob( + this, + i18n("The directory '%1' can not 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; + } else { + QList jobs = { + configure(project, buildDir, status), // First configure the build directory + realJob // If this succeeds execute the real job + }; + + return new ExecuteCompositeJob(this, jobs); + } + + 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::build(KDevelop::ProjectBaseItem* item) +{ + Q_ASSERT(item); + return configureIfRequired(item->project(), m_ninjaBuilder->build(item)); +} + +KJob* MesonBuilder::clean(KDevelop::ProjectBaseItem* item) +{ + Q_ASSERT(item); + return configureIfRequired(item->project(), m_ninjaBuilder->clean(item)); +} + +KJob* MesonBuilder::install(KDevelop::ProjectBaseItem* item, const QUrl& installPath) +{ + Q_ASSERT(item); + 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 }; +} + +#include "mesonbuilder.moc" diff --git a/plugins/meson/mesonconfig.h b/plugins/meson/mesonconfig.h new file mode 100644 --- /dev/null +++ b/plugins/meson/mesonconfig.h @@ -0,0 +1,59 @@ +/* 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; +}; + +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/mesonconfig.cpp b/plugins/meson/mesonconfig.cpp new file mode 100644 --- /dev/null +++ b/plugins/meson/mesonconfig.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 "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(); + 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()); + + // 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 +{ + if (buildDir.isEmpty() || mesonExecutable.isEmpty() || buildType.isEmpty()) { + return false; + } + + return true; +} diff --git a/plugins/meson/mesonimportjob.h b/plugins/meson/mesonimportjob.h new file mode 100644 --- /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/mesonimportjob.cpp b/plugins/meson/mesonimportjob.cpp new file mode 100644 --- /dev/null +++ b/plugins/meson/mesonimportjob.cpp @@ -0,0 +1,97 @@ +/* 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(const Path& commandsFile, const Path& sourcePath, const Path& builddir) +{ + QFile f(commandsFile.toLocalFile()); + if (!f.open(QFile::ReadOnly)) { + qCWarning(KDEV_Meson) << "Failed to open " << commandsFile; + return {}; + } + + QJsonParseError error; + QJsonDocument doc = QJsonDocument::fromJson(f.readAll(), &error); + if (error.error) { + qCWarning(KDEV_Meson) << "error parsing" << commandsFile << error.errorString(); + return {}; + } + return doc.object(); +} + +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; + } + + const Path commandsFile(buildDir.buildDir, QLatin1String("compile_commands.json")); + const auto sourceDir = m_project->path(); + + auto rt = ICore::self()->runtimeController()->currentRuntime(); + auto future = QtConcurrent::run(import, commandsFile, sourceDir, rt->pathInRuntime(buildDir.buildDir)); + 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/mesonjob.h b/plugins/meson/mesonjob.h new file mode 100644 --- /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/mesonjob.cpp b/plugins/meson/mesonjob.cpp new file mode 100644 --- /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/mesonjobprune.h b/plugins/meson/mesonjobprune.h new file mode 100644 --- /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/mesonjobprune.cpp b/plugins/meson/mesonjobprune.cpp new file mode 100644 --- /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/mesonmanager.h b/plugins/meson/mesonmanager.h new file mode 100644 --- /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/mesonmanager.cpp b/plugins/meson/mesonmanager.cpp new file mode 100644 --- /dev/null +++ b/plugins/meson/mesonmanager.cpp @@ -0,0 +1,185 @@ +/* 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)) +{ +} + +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); + 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/settings/mesonadvancedsettings.h b/plugins/meson/settings/mesonadvancedsettings.h new file mode 100644 --- /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.cpp b/plugins/meson/settings/mesonadvancedsettings.cpp new file mode 100644 --- /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.ui b/plugins/meson/settings/mesonadvancedsettings.ui new file mode 100644 --- /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 +
klineedit.h
+
+ + KComboBox + QComboBox +
kcombobox.h
+
+ + KUrlRequester + QWidget +
kurlrequester.h
+
+
+ + + + 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.h b/plugins/meson/settings/mesonconfigpage.h new file mode 100644 --- /dev/null +++ b/plugins/meson/settings/mesonconfigpage.h @@ -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. +*/ + +#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; +}; diff --git a/plugins/meson/settings/mesonconfigpage.cpp b/plugins/meson/settings/mesonconfigpage.cpp new file mode 100644 --- /dev/null +++ b/plugins/meson/settings/mesonconfigpage.cpp @@ -0,0 +1,256 @@ +/* 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 + +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) { + QStringList args; + QList joblist = { + new MesonJob(m_current, m_project, MesonJob::SET_CONFIG, args, nullptr), + new MesonJob(m_current, m_project, MesonJob::RE_CONFIGURE, args, nullptr), + }; + KJob* job = new ExecuteCompositeJob(nullptr, joblist); + 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); +} + +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() +{ + 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.ui b/plugins/meson/settings/mesonconfigpage.ui new file mode 100644 --- /dev/null +++ b/plugins/meson/settings/mesonconfigpage.ui @@ -0,0 +1,296 @@ + + + MesonConfigPage + + + + 0 + 0 + 587 + 499 + + + + + + + + + + 0 + 0 + + + + + + + + ... + + + + .. + + + + + + + ... + + + + .. + + + + + + + + + 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 + 267 + + + + + + + false + + + TODO -- Implement in seperate UI file + + + Qt::AlignCenter + + + + + + + Qt::Vertical + + + + 0 + 0 + + + + + + + + + + + + + + + + + + + KComboBox + QComboBox +
kcombobox.h
+
+ + KUrlRequester + QWidget +
kurlrequester.h
+
+ + 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.h b/plugins/meson/settings/mesonnewbuilddir.h new file mode 100644 --- /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.cpp b/plugins/meson/settings/mesonnewbuilddir.cpp new file mode 100644 --- /dev/null +++ b/plugins/meson/settings/mesonnewbuilddir.cpp @@ -0,0 +1,206 @@ +/* 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; + } + + m_ui->l_statusMessage->setText( + QStringLiteral("%2").arg(scheme.foreground(role).color().name(), 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 already configured build directory"), true); + break; + case MesonBuilder::INVALID_BUILD_DIR: + setStatus(i18n("Can not 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) << "Can not 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.ui b/plugins/meson/settings/mesonnewbuilddir.ui new file mode 100644 --- /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 +
kcombobox.h
+
+ + KUrlRequester + QWidget +
kurlrequester.h
+
+ + 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() + +