File indexing completed on 2024-05-05 16:46:01

0001 /*
0002     SPDX-FileCopyrightText: 2017 Aleix Pol Gonzalez <aleixpol@kde.org>
0003     SPDX-FileCopyrightText: 2018 Daniel Mensinger <daniel@mensinger-ka.de>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 #include "mesonconfig.h"
0009 
0010 #include "mesonmanager.h"
0011 #include <debug.h>
0012 
0013 #include <interfaces/iproject.h>
0014 #include <project/interfaces/ibuildsystemmanager.h>
0015 #include <project/projectmodel.h>
0016 
0017 #include <KLocalizedString>
0018 
0019 #include <QFileDialog>
0020 
0021 using namespace KDevelop;
0022 using namespace Meson;
0023 
0024 static const QString ROOT_CONFIG = QStringLiteral("MesonManager");
0025 static const QString NUM_BUILD_DIRS = QStringLiteral("Number of Build Directories");
0026 static const QString CURRENT_INDEX = QStringLiteral("Current Build Directory Index");
0027 
0028 static const QString BUILD_DIR_SEC = QStringLiteral("BuildDir %1");
0029 static const QString BUILD_DIR_PATH = QStringLiteral("Build Directory Path");
0030 static const QString MESON_EXE = QStringLiteral("Meson executable");
0031 static const QString EXTRA_ARGS = QStringLiteral("Additional meson arguments");
0032 static const QString BACKEND = QStringLiteral("Meson Generator Backend");
0033 
0034 int MesonConfig::addBuildDir(BuildDir dir)
0035 {
0036     int newIndex = buildDirs.size();
0037     dir.canonicalizePaths();
0038     qCDebug(KDEV_Meson) << "BuildDirectories::addBuildDir()=" << dir.buildDir;
0039     buildDirs.push_back(dir);
0040 
0041     // Make sure m_currentIndex is valid
0042     if (currentIndex < 0) {
0043         currentIndex = newIndex;
0044     }
0045 
0046     return newIndex;
0047 }
0048 
0049 bool MesonConfig::removeBuildDir(int index)
0050 {
0051     if (index > buildDirs.size() || index < 0) {
0052         return false;
0053     }
0054 
0055     buildDirs.removeAt(index);
0056 
0057     if (currentIndex >= buildDirs.size()) {
0058         currentIndex = buildDirs.size() - 1;
0059     }
0060 
0061     return true;
0062 }
0063 
0064 KConfigGroup Meson::rootGroup(IProject* project)
0065 {
0066     if (!project) {
0067         qCWarning(KDEV_Meson) << "Meson::rootGroup: IProject pointer is nullptr";
0068         return KConfigGroup();
0069     }
0070 
0071     return project->projectConfiguration()->group(ROOT_CONFIG);
0072 }
0073 
0074 MesonConfig Meson::getMesonConfig(IProject* project)
0075 {
0076     KConfigGroup root = rootGroup(project);
0077     MesonConfig result;
0078 
0079     int numDirs = root.readEntry(NUM_BUILD_DIRS, 0);
0080     result.currentIndex = root.readEntry(CURRENT_INDEX, -1);
0081 
0082     for (int i = 0; i < numDirs; ++i) {
0083         QString section = BUILD_DIR_SEC.arg(i);
0084         if (!root.hasGroup(section)) {
0085             continue;
0086         }
0087 
0088         KConfigGroup current = root.group(section);
0089         BuildDir currBD;
0090         currBD.buildDir = Path(current.readEntry(BUILD_DIR_PATH, QString()));
0091         currBD.mesonExecutable = Path(current.readEntry(MESON_EXE, QString()));
0092         currBD.mesonBackend = current.readEntry(BACKEND, QString());
0093         currBD.mesonArgs = current.readEntry(EXTRA_ARGS, QString());
0094 
0095         currBD.canonicalizePaths();
0096 
0097         // Try to find meson if the config is bad
0098         if (currBD.mesonExecutable.isEmpty()) {
0099             Q_ASSERT(project);
0100             IBuildSystemManager* ibsm = project->buildSystemManager();
0101             auto* bsm = dynamic_cast<MesonManager*>(ibsm);
0102             if (bsm) {
0103                 currBD.mesonExecutable = bsm->findMeson();
0104             }
0105         }
0106 
0107         result.buildDirs.push_back(currBD);
0108     }
0109 
0110     if (result.buildDirs.isEmpty()) {
0111         result.currentIndex = -1;
0112     } else if (result.currentIndex < 0 || result.currentIndex >= result.buildDirs.size()) {
0113         result.currentIndex = 0;
0114     }
0115 
0116     return result;
0117 }
0118 
0119 void Meson::writeMesonConfig(IProject* project, const MesonConfig& cfg)
0120 {
0121     KConfigGroup root = rootGroup(project);
0122 
0123     // Make sure that the config we write is valid
0124     int currentIndex = cfg.currentIndex;
0125     if (cfg.buildDirs.isEmpty()) {
0126         currentIndex = -1;
0127     } else if (currentIndex < 0 || currentIndex >= cfg.buildDirs.size()) {
0128         currentIndex = 0;
0129     }
0130 
0131     root.writeEntry(NUM_BUILD_DIRS, cfg.buildDirs.size());
0132     root.writeEntry(CURRENT_INDEX, currentIndex);
0133 
0134     int counter = 0;
0135     for (const auto& i : cfg.buildDirs) {
0136         KConfigGroup current = root.group(BUILD_DIR_SEC.arg(counter++));
0137 
0138         current.writeEntry(BUILD_DIR_PATH, i.buildDir.path());
0139         current.writeEntry(MESON_EXE, i.mesonExecutable.path());
0140         current.writeEntry(BACKEND, i.mesonBackend);
0141         current.writeEntry(EXTRA_ARGS, i.mesonArgs);
0142     }
0143 }
0144 
0145 BuildDir Meson::currentBuildDir(IProject* project)
0146 {
0147     Q_ASSERT(project);
0148     MesonConfig cfg = getMesonConfig(project);
0149     if (cfg.currentIndex < 0 || cfg.currentIndex >= cfg.buildDirs.size()) {
0150         cfg.currentIndex = 0; // Default to the first build dir
0151 
0152         // Return an invalid build dir
0153         if (cfg.buildDirs.isEmpty()) {
0154             return BuildDir();
0155         }
0156     }
0157 
0158     return cfg.buildDirs[cfg.currentIndex];
0159 }
0160 
0161 bool Meson::BuildDir::isValid() const
0162 {
0163     return !(buildDir.isEmpty() || mesonExecutable.isEmpty());
0164 }
0165 
0166 void Meson::BuildDir::canonicalizePaths()
0167 {
0168     for (auto* i : { &buildDir }) {
0169         // canonicalFilePath checks if the file / directory exists and returns "" if it doesn't.
0170         QString tmp = QFileInfo(i->toLocalFile()).canonicalFilePath();
0171         if (!tmp.isEmpty()) {
0172             *i = Path(tmp);
0173         }
0174     }
0175 }