File indexing completed on 2024-05-19 04:41:21
0001 /* 0002 SPDX-FileCopyrightText: 2018 Daniel Mensinger <daniel@mensinger-ka.de> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "mesonnewbuilddir.h" 0008 0009 #include "mesonbuilder.h" 0010 #include "mesonmanager.h" 0011 #include "ui_mesonnewbuilddir.h" 0012 #include <debug.h> 0013 0014 #include <interfaces/icore.h> 0015 #include <interfaces/iproject.h> 0016 #include <interfaces/iruncontroller.h> 0017 #include <interfaces/iruntime.h> 0018 #include <interfaces/iruntimecontroller.h> 0019 #include <project/helper.h> 0020 0021 #include <KColorScheme> 0022 0023 #include <QDialogButtonBox> 0024 #include <QFileInfo> 0025 0026 #include <algorithm> 0027 0028 using namespace KDevelop; 0029 0030 MesonNewBuildDir::MesonNewBuildDir(IProject* project, QWidget* parent) 0031 : QDialog(parent) 0032 , m_project(project) 0033 { 0034 Q_ASSERT(project); // Just in case 0035 auto* mgr = dynamic_cast<MesonManager*>(m_project->buildSystemManager()); 0036 Q_ASSERT(mgr); // This dialog only works with the MesonManager 0037 0038 setWindowTitle( 0039 i18nc("@title:window", "Configure a Build Directory - %1", ICore::self()->runtimeController()->currentRuntime()->name())); 0040 0041 m_ui = new Ui::MesonNewBuildDir; 0042 m_ui->setupUi(this); 0043 0044 m_ui->advanced->setSupportedBackends(mgr->supportedMesonBackends()); 0045 0046 connect(m_ui->b_buttonBox, &QDialogButtonBox::clicked, this, [this](QAbstractButton* b) { 0047 if (m_ui->b_buttonBox->buttonRole(b) == QDialogButtonBox::ResetRole) { 0048 resetFields(); 0049 } 0050 }); 0051 0052 m_ui->i_buildDir->setAcceptMode(QFileDialog::AcceptSave); 0053 0054 resetFields(); 0055 } 0056 0057 MesonNewBuildDir::~MesonNewBuildDir() 0058 { 0059 delete m_ui; 0060 } 0061 0062 void MesonNewBuildDir::resetFields() 0063 { 0064 Meson::MesonConfig cfg = Meson::getMesonConfig(m_project); 0065 Path projectPath = m_project->path(); 0066 auto* mgr = dynamic_cast<MesonManager*>(m_project->buildSystemManager()); 0067 Q_ASSERT(mgr); // This dialog only works with the MesonManager 0068 0069 auto aConf = m_ui->advanced->getConfig(); 0070 0071 // Find a build dir that is not already configured 0072 Path buildDirPath = projectPath; 0073 buildDirPath.addPath(QStringLiteral("build")); 0074 0075 auto checkInCfg = [](const Meson::MesonConfig& cfg, const Path& p) -> bool { 0076 for (const auto& i : cfg.buildDirs) { 0077 if (i.buildDir == p) { 0078 return true; 0079 } 0080 } 0081 return false; 0082 }; 0083 0084 for (int i = 2; checkInCfg(cfg, buildDirPath); ++i) { 0085 buildDirPath = projectPath; 0086 buildDirPath.addPath(QStringLiteral("build%1").arg(i)); 0087 } 0088 0089 m_ui->i_buildDir->setUrl(buildDirPath.toUrl()); 0090 0091 // Extra args 0092 aConf.args.clear(); 0093 0094 // Backend 0095 aConf.backend = mgr->defaultMesonBackend(); 0096 0097 // Meson exe 0098 aConf.meson = mgr->findMeson(); 0099 0100 m_ui->advanced->setConfig(aConf); 0101 updated(); 0102 } 0103 0104 void MesonNewBuildDir::setStatus(const QString& str, bool validConfig) 0105 { 0106 m_configIsValid = validConfig; 0107 0108 KColorScheme scheme(QPalette::Normal); 0109 KColorScheme::ForegroundRole role; 0110 if (validConfig) { 0111 role = KColorScheme::PositiveText; 0112 } else { 0113 role = KColorScheme::NegativeText; 0114 } 0115 0116 QPalette pal = m_ui->l_statusMessage->palette(); 0117 pal.setColor(QPalette::WindowText, scheme.foreground(role).color()); 0118 m_ui->l_statusMessage->setPalette(pal); 0119 m_ui->l_statusMessage->setText(str); 0120 0121 auto okButton = m_ui->b_buttonBox->button(QDialogButtonBox::Ok); 0122 okButton->setEnabled(m_configIsValid); 0123 if (m_configIsValid) { 0124 auto cancelButton = m_ui->b_buttonBox->button(QDialogButtonBox::Cancel); 0125 cancelButton->clearFocus(); 0126 } 0127 } 0128 0129 void MesonNewBuildDir::updated() 0130 { 0131 auto advanced = m_ui->advanced->getConfig(); 0132 Path buildDir = Path(m_ui->i_buildDir->url()); 0133 QFileInfo mesonExe(advanced.meson.toLocalFile()); 0134 0135 if (!mesonExe.exists() || !mesonExe.isExecutable() || !mesonExe.isFile() 0136 || !mesonExe.permission(QFileDevice::ReadUser | QFileDevice::ExeUser)) { 0137 setStatus(i18n("Specified meson executable does not exist"), false); 0138 return; 0139 } 0140 0141 MesonBuilder::DirectoryStatus status = MesonBuilder::evaluateBuildDirectory(buildDir, advanced.backend); 0142 switch (status) { 0143 case MesonBuilder::CLEAN: 0144 case MesonBuilder::DOES_NOT_EXIST: 0145 setStatus(i18n("Creating new build directory"), true); 0146 break; 0147 case MesonBuilder::MESON_CONFIGURED: 0148 setStatus(i18n("Using an already configured build directory"), true); 0149 break; 0150 case MesonBuilder::MESON_FAILED_CONFIGURATION: 0151 setStatus(i18n("Using a broken meson build directory (this should be fine)"), true); 0152 break; 0153 case MesonBuilder::INVALID_BUILD_DIR: 0154 setStatus(i18n("Cannot use specified directory"), false); 0155 break; 0156 case MesonBuilder::DIR_NOT_EMPTY: 0157 setStatus(i18n("There are already files in the build directory"), false); 0158 break; 0159 case MesonBuilder::EMPTY_STRING: 0160 setStatus(i18n("The build directory field must not be empty"), false); 0161 break; 0162 case MesonBuilder::___UNDEFINED___: 0163 setStatus(i18n("You have reached unreachable code. This is a bug"), false); 0164 break; 0165 } 0166 0167 bool buildDirChanged = false; 0168 if (m_oldBuildDir != buildDir.toLocalFile()) { 0169 m_oldBuildDir = buildDir.toLocalFile(); 0170 buildDirChanged = true; 0171 } 0172 0173 bool mesonHasChanged = m_ui->advanced->hasMesonChanged(); // Outside if to prevent lazy evaluation 0174 if (!m_ui->options->options() || mesonHasChanged || buildDirChanged) { 0175 if (status == MesonBuilder::MESON_CONFIGURED) { 0176 m_ui->options->repopulateFromBuildDir(m_project, currentConfig())->start(); 0177 } else { 0178 m_ui->options->repopulateFromMesonFile(m_project, advanced.meson)->start(); 0179 } 0180 } 0181 } 0182 0183 Meson::BuildDir MesonNewBuildDir::currentConfig() const 0184 { 0185 Meson::BuildDir buildDir; 0186 if (!m_configIsValid) { 0187 qCDebug(KDEV_Meson) << "Cannot generate build dir config from invalid config"; 0188 return buildDir; 0189 } 0190 0191 auto advanced = m_ui->advanced->getConfig(); 0192 0193 buildDir.buildDir = Path(m_ui->i_buildDir->url()); 0194 buildDir.mesonArgs = advanced.args; 0195 buildDir.mesonBackend = advanced.backend; 0196 buildDir.mesonExecutable = advanced.meson; 0197 0198 return buildDir; 0199 } 0200 0201 QStringList MesonNewBuildDir::mesonArgs() const 0202 { 0203 auto options = m_ui->options->options(); 0204 if (!options) { 0205 return {}; 0206 } 0207 0208 return options->getMesonArgs(); 0209 } 0210 0211 bool MesonNewBuildDir::isConfigValid() const 0212 { 0213 return m_configIsValid; 0214 } 0215 0216 #include "moc_mesonnewbuilddir.cpp"