Changeset View
Standalone View
projectmanagers/cmake/cmakemanager.cpp
Show All 27 Lines | |||||
28 | #include "debug.h" | 28 | #include "debug.h" | ||
29 | #include "settings/cmakepreferences.h" | 29 | #include "settings/cmakepreferences.h" | ||
30 | #include <projectmanagers/custommake/makefileresolver/makefileresolver.h> | 30 | #include <projectmanagers/custommake/makefileresolver/makefileresolver.h> | ||
31 | #include "cmakecodecompletionmodel.h" | 31 | #include "cmakecodecompletionmodel.h" | ||
32 | #include "cmakenavigationwidget.h" | 32 | #include "cmakenavigationwidget.h" | ||
33 | #include "icmakedocumentation.h" | 33 | #include "icmakedocumentation.h" | ||
34 | #include "cmakemodelitems.h" | 34 | #include "cmakemodelitems.h" | ||
35 | #include "testing/ctestutils.h" | 35 | #include "testing/ctestutils.h" | ||
36 | #include "cmakeserverimportjob.h" | ||||
37 | #include "cmakeserver.h" | ||||
36 | 38 | | |||
37 | #include <QDir> | 39 | #include <QDir> | ||
38 | #include <QReadWriteLock> | 40 | #include <QReadWriteLock> | ||
39 | #include <QThread> | 41 | #include <QThread> | ||
40 | #include <QFileSystemWatcher> | 42 | #include <QFileSystemWatcher> | ||
41 | #include <QTimer> | 43 | #include <QTimer> | ||
42 | #include <qjsondocument.h> | 44 | #include <qjsondocument.h> | ||
43 | 45 | | |||
▲ Show 20 Lines • Show All 63 Lines • ▼ Show 20 Line(s) | |||||
107 | { | 109 | { | ||
108 | parseLock()->lockForWrite(); | 110 | parseLock()->lockForWrite(); | ||
109 | // By locking the parse-mutexes, we make sure that parse jobs get a chance to finish in a good state | 111 | // By locking the parse-mutexes, we make sure that parse jobs get a chance to finish in a good state | ||
110 | parseLock()->unlock(); | 112 | parseLock()->unlock(); | ||
111 | } | 113 | } | ||
112 | 114 | | |||
113 | bool CMakeManager::hasBuildInfo(ProjectBaseItem* item) const | 115 | bool CMakeManager::hasBuildInfo(ProjectBaseItem* item) const | ||
114 | { | 116 | { | ||
115 | return m_projects[item->project()].jsonData.files.contains(item->path()); | 117 | return m_projects[item->project()].compilationData.files.contains(item->path()); | ||
116 | } | 118 | } | ||
117 | 119 | | |||
118 | Path CMakeManager::buildDirectory(KDevelop::ProjectBaseItem *item) const | 120 | Path CMakeManager::buildDirectory(KDevelop::ProjectBaseItem *item) const | ||
119 | { | 121 | { | ||
120 | // CMakeFolderItem *fi=dynamic_cast<CMakeFolderItem*>(item); | 122 | // CMakeFolderItem *fi=dynamic_cast<CMakeFolderItem*>(item); | ||
121 | // Path ret; | 123 | // Path ret; | ||
122 | // ProjectBaseItem* parent = fi ? fi->formerParent() : item->parent(); | 124 | // ProjectBaseItem* parent = fi ? fi->formerParent() : item->parent(); | ||
123 | // if (parent) | 125 | // if (parent) | ||
Show All 9 Lines | |||||
133 | 135 | | |||
134 | KDevelop::ProjectFolderItem* CMakeManager::import( KDevelop::IProject *project ) | 136 | KDevelop::ProjectFolderItem* CMakeManager::import( KDevelop::IProject *project ) | ||
135 | { | 137 | { | ||
136 | CMake::checkForNeedingConfigure(project); | 138 | CMake::checkForNeedingConfigure(project); | ||
137 | 139 | | |||
138 | return AbstractFileManagerPlugin::import(project); | 140 | return AbstractFileManagerPlugin::import(project); | ||
139 | } | 141 | } | ||
140 | 142 | | |||
143 | static bool serverSupported() | ||||
mwolff: for PODs, you don't need Q_GLOBAL_STATIC. simply make this a
namespace {
static bool… | |||||
mwolff: this is not used anywhere now? | |||||
144 | { | ||||
145 | static int supported = 2; | ||||
146 | if (supported == 2) { | ||||
147 | QProcess p; | ||||
148 | p.start(CMake::findExecutable(), {"--version"}); | ||||
149 | p.waitForReadyRead(); | ||||
150 | const QByteArray line = p.readLine(); | ||||
151 | | ||||
152 | QRegularExpression rx("cmake version (\\d+)\\.(\\d+)\\.(\\d+)"); | ||||
153 | auto match = rx.match(line); | ||||
154 | if (match.isValid()) { | ||||
155 | match.capturedTexts(); | ||||
156 | } | ||||
157 | } | ||||
158 | return supported == 1; | ||||
159 | } | ||||
160 | | ||||
141 | KJob* CMakeManager::createImportJob(ProjectFolderItem* item) | 161 | KJob* CMakeManager::createImportJob(ProjectFolderItem* item) | ||
142 | { | 162 | { | ||
143 | auto project = item->project(); | 163 | auto project = item->project(); | ||
144 | 164 | | |||
145 | QList<KJob*> jobs; | 165 | QList<KJob*> jobs; | ||
146 | 166 | | |||
167 | CMakeServer* server = new CMakeServer(this); | ||||
Who will delete the server when it is available? this looks like you are piling up servers until the CMakeManager is deleted at shutdown. You probably want to use a unique_ptr here and transfer ownership into the import job when the server is available mwolff: Who will delete the server when it is available? this looks like you are piling up servers… | |||||
168 | server->waitForConnected(); | ||||
Somewhy is not working:
zhigalin: Somewhy is not working:
> kdevelop.projectmanagers.cmake: cmake server socket error… | |||||
169 | | ||||
170 | if (server->isServerAvailable()) { | ||||
171 | auto job = new CMakeServerImportJob(project, server, this); | ||||
make this a warning? also, do we want to show the user that? this can be serious and render the whole cmake support useless after all, right? mwolff: make this a warning? also, do we want to show the user that? this can be serious and render the… | |||||
172 | connect(job, &CMakeServerImportJob::result, this, [this, job](){ | ||||
173 | if (job->error() != 0) { | ||||
174 | qCWarning(CMAKE) << "couldn't load server successfully" << job->project()->name(); | ||||
175 | m_projects.remove(job->project()); | ||||
176 | } else { | ||||
177 | integrateData(job->projectData(), job->project()); | ||||
178 | } | ||||
179 | }); | ||||
180 | jobs << job; | ||||
181 | } else { | ||||
182 | delete server; | ||||
183 | // parse the JSON file | ||||
184 | CMakeImportJsonJob* job = new CMakeImportJsonJob(project, this); | ||||
185 | | ||||
arrowd: Why comment this? | |||||
147 | // create the JSON file if it doesn't exist | 186 | // create the JSON file if it doesn't exist | ||
148 | auto commandsFile = CMake::commandsFile(project); | 187 | auto commandsFile = CMake::commandsFile(project); | ||
149 | if (!QFileInfo::exists(commandsFile.toLocalFile())) { | 188 | if (!QFileInfo::exists(commandsFile.toLocalFile())) { | ||
150 | qCDebug(CMAKE) << "couldn't find commands file:" << commandsFile << "- now trying to reconfigure"; | 189 | qCDebug(CMAKE) << "couldn't find commands file:" << commandsFile << "- now trying to reconfigure"; | ||
151 | jobs << builder()->configure(project); | 190 | jobs << builder()->configure(project); | ||
152 | } | 191 | } | ||
153 | 192 | | |||
154 | // parse the JSON file | 193 | connect(job, &CMakeImportJsonJob::result, this, [this, job](){ | ||
155 | CMakeImportJob* job = new CMakeImportJob(project, this); | 194 | if (job->error() != 0) { | ||
156 | connect(job, &CMakeImportJob::result, this, &CMakeManager::importFinished); | 195 | qCWarning(CMAKE) << "couldn't load json successfully" << job->project()->name(); | ||
warning, and see above? actually the whole code is duplicated - move this into a proper slot? or at least share the lambda body? mwolff: warning, and see above? actually the whole code is duplicated - move this into a proper slot? | |||||
As is we can't, they should inherit from the same class. I don't think it's a big deal at the moment... apol: As is we can't, they should inherit from the same class. I don't think it's a big deal at the… | |||||
196 | m_projects.remove(job->project()); | ||||
197 | } else { | ||||
198 | integrateData(job->projectData(), job->project()); | ||||
199 | } | ||||
200 | }); | ||||
157 | jobs << job; | 201 | jobs << job; | ||
202 | } | ||||
158 | 203 | | |||
159 | // generate the file system listing | 204 | // generate the file system listing | ||
160 | jobs << KDevelop::AbstractFileManagerPlugin::createImportJob(item); | 205 | jobs << KDevelop::AbstractFileManagerPlugin::createImportJob(item); | ||
161 | 206 | | |||
162 | Q_ASSERT(!jobs.contains(nullptr)); | 207 | Q_ASSERT(!jobs.contains(nullptr)); | ||
163 | ExecuteCompositeJob* composite = new ExecuteCompositeJob(this, jobs); | 208 | ExecuteCompositeJob* composite = new ExecuteCompositeJob(this, jobs); | ||
164 | // even if the cmake call failed, we want to load the project so that the project can be worked on | 209 | // even if the cmake call failed, we want to load the project so that the project can be worked on | ||
165 | composite->setAbortOnError(false); | 210 | composite->setAbortOnError(false); | ||
166 | return composite; | 211 | return composite; | ||
167 | } | 212 | } | ||
168 | 213 | | |||
169 | // QList<ProjectFolderItem*> CMakeManager::parse(ProjectFolderItem*) | 214 | // QList<ProjectFolderItem*> CMakeManager::parse(ProjectFolderItem*) | ||
170 | // { return QList< ProjectFolderItem* >(); } | 215 | // { return QList< ProjectFolderItem* >(); } | ||
171 | // | 216 | // | ||
172 | // | 217 | // | ||
173 | 218 | | |||
174 | QList<KDevelop::ProjectTargetItem*> CMakeManager::targets() const | 219 | QList<KDevelop::ProjectTargetItem*> CMakeManager::targets() const | ||
175 | { | 220 | { | ||
176 | QList<KDevelop::ProjectTargetItem*> ret; | 221 | QList<KDevelop::ProjectTargetItem*> ret; | ||
177 | foreach(IProject* p, m_projects.keys()) | 222 | foreach(IProject* p, m_projects.keys()) | ||
178 | { | 223 | { | ||
179 | ret+=p->projectItem()->targetList(); | 224 | ret+=p->projectItem()->targetList(); | ||
180 | } | 225 | } | ||
mwolff: these shouldn't be QPointer, or? | |||||
181 | return ret; | 226 | return ret; | ||
182 | } | 227 | } | ||
183 | 228 | | |||
184 | CMakeFile CMakeManager::fileInformation(KDevelop::ProjectBaseItem* item) const | 229 | CMakeFile CMakeManager::fileInformation(KDevelop::ProjectBaseItem* item) const | ||
185 | { | 230 | { | ||
186 | const CMakeJsonData & data = m_projects[item->project()].jsonData; | 231 | const auto & data = m_projects[item->project()].compilationData; | ||
187 | QHash<KDevelop::Path, CMakeFile>::const_iterator it = data.files.constFind(item->path()); | 232 | QHash<KDevelop::Path, CMakeFile>::const_iterator it = data.files.constFind(item->path()); | ||
188 | 233 | | |||
189 | if (it == data.files.constEnd()) { | 234 | if (it == data.files.constEnd()) { | ||
190 | // if the item path contains a symlink, then we will not find it in the lookup table | 235 | // if the item path contains a symlink, then we will not find it in the lookup table | ||
191 | // as that only only stores canonicalized paths. Thus, we fallback to | 236 | // as that only only stores canonicalized paths. Thus, we fallback to | ||
192 | // to the canonicalized path and see if that brings up any matches | 237 | // to the canonicalized path and see if that brings up any matches | ||
193 | const auto canonicalized = Path(QFileInfo(item->path().toLocalFile()).canonicalFilePath()); | 238 | const auto canonicalized = Path(QFileInfo(item->path().toLocalFile()).canonicalFilePath()); | ||
194 | it = data.files.constFind(canonicalized); | 239 | it = data.files.constFind(canonicalized); | ||
▲ Show 20 Lines • Show All 86 Lines • ▼ Show 20 Line(s) | 325 | ) | |||
281 | new CMakeTargetItem(folder, name); | 326 | new CMakeTargetItem(folder, name); | ||
282 | } | 327 | } | ||
283 | 328 | | |||
284 | foreach (ProjectFolderItem* children, folder->folderList()) { | 329 | foreach (ProjectFolderItem* children, folder->folderList()) { | ||
285 | populateTargets(children, targets); | 330 | populateTargets(children, targets); | ||
286 | } | 331 | } | ||
287 | } | 332 | } | ||
288 | 333 | | |||
289 | void CMakeManager::importFinished(KJob* j) | 334 | void CMakeManager::integrateData(const CMakeProjectData &data, KDevelop::IProject* project) | ||
290 | { | 335 | { | ||
291 | CMakeImportJob* job = qobject_cast<CMakeImportJob*>(j); | | |||
292 | Q_ASSERT(job); | | |||
293 | | ||||
294 | auto project = job->project(); | | |||
295 | if (job->error() != 0) { | | |||
296 | qCDebug(CMAKE) << "Import failed for project" << project->name() << job->errorText(); | | |||
297 | m_projects.remove(project); | | |||
298 | } | | |||
299 | | ||||
300 | qCDebug(CMAKE) << "Successfully imported project" << project->name(); | | |||
301 | | ||||
302 | CMakeProjectData data; | | |||
303 | data.watcher->addPath(CMake::commandsFile(project).toLocalFile()); | | |||
304 | data.watcher->addPath(CMake::targetDirectoriesFile(project).toLocalFile()); | | |||
305 | data.jsonData = job->jsonData(); | | |||
306 | data.targets = job->targets(); | | |||
307 | connect(data.watcher.data(), &QFileSystemWatcher::fileChanged, this, &CMakeManager::dirtyFile); | 336 | connect(data.watcher.data(), &QFileSystemWatcher::fileChanged, this, &CMakeManager::dirtyFile); | ||
308 | connect(data.watcher.data(), &QFileSystemWatcher::directoryChanged, this, &CMakeManager::dirtyFile); | 337 | connect(data.watcher.data(), &QFileSystemWatcher::directoryChanged, this, &CMakeManager::dirtyFile); | ||
309 | m_projects[job->project()] = data; | 338 | m_projects[project] = data; | ||
310 | | ||||
311 | populateTargets(job->project()->projectItem(), job->targets()); | | |||
312 | 339 | | |||
313 | CTestUtils::createTestSuites(job->testSuites(), project); | 340 | populateTargets(project->projectItem(), data.targets); | ||
341 | CTestUtils::createTestSuites(data.m_testSuites, project); | ||||
314 | } | 342 | } | ||
315 | 343 | | |||
316 | // void CMakeManager::deletedWatchedDirectory(IProject* p, const QUrl &dir) | 344 | // void CMakeManager::deletedWatchedDirectory(IProject* p, const QUrl &dir) | ||
317 | // { | 345 | // { | ||
318 | // if(p->folder().equals(dir, QUrl::CompareWithoutTrailingSlash)) { | 346 | // if(p->folder().equals(dir, QUrl::CompareWithoutTrailingSlash)) { | ||
319 | // ICore::self()->projectController()->closeProject(p); | 347 | // ICore::self()->projectController()->closeProject(p); | ||
320 | // } else { | 348 | // } else { | ||
321 | // if(dir.fileName()=="CMakeLists.txt") { | 349 | // if(dir.fileName()=="CMakeLists.txt") { | ||
▲ Show 20 Lines • Show All 561 Lines • Show Last 20 Lines |
for PODs, you don't need Q_GLOBAL_STATIC. simply make this a
namespace {
static bool s_serverSupported = false;
}
on a conceptual level - this depends on the cmake binary that can be selected for every project, no? So this should not be a static at all, but rather a per-project property?