2019-09-16 22:43:27 +02:00
|
|
|
/****************************************************************************
|
|
|
|
|
**
|
|
|
|
|
** Copyright (C) Filippo Cucchetto <filippocucchetto@gmail.com>
|
|
|
|
|
** Contact: http://www.qt.io/licensing
|
|
|
|
|
**
|
|
|
|
|
** This file is part of Qt Creator.
|
|
|
|
|
**
|
|
|
|
|
** Commercial License Usage
|
|
|
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
|
|
|
** accordance with the commercial license agreement provided with the
|
|
|
|
|
** Software or, alternatively, in accordance with the terms contained in
|
|
|
|
|
** a written agreement between you and The Qt Company. For licensing terms
|
|
|
|
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
|
|
|
|
** information use the contact form at https://www.qt.io/contact-us.
|
|
|
|
|
**
|
|
|
|
|
** GNU General Public License Usage
|
|
|
|
|
** Alternatively, this file may be used under the terms of the GNU
|
|
|
|
|
** General Public License version 3 as published by the Free Software
|
|
|
|
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
|
|
|
|
** included in the packaging of this file. Please review the following
|
|
|
|
|
** information to ensure the GNU General Public License requirements will
|
|
|
|
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
|
|
|
|
**
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
|
|
#include "nimblebuildsystem.h"
|
|
|
|
|
#include "nimbleproject.h"
|
2019-11-22 12:41:15 +01:00
|
|
|
#include "nimproject.h"
|
2019-09-16 22:43:27 +02:00
|
|
|
|
2019-10-25 09:55:32 +02:00
|
|
|
#include <projectexplorer/target.h>
|
|
|
|
|
|
2019-09-16 22:43:27 +02:00
|
|
|
#include <utils/algorithm.h>
|
|
|
|
|
#include <utils/qtcassert.h>
|
|
|
|
|
|
|
|
|
|
#include <QProcess>
|
|
|
|
|
#include <QStandardPaths>
|
|
|
|
|
|
|
|
|
|
using namespace ProjectExplorer;
|
|
|
|
|
using namespace Utils;
|
|
|
|
|
|
2019-11-22 12:41:15 +01:00
|
|
|
namespace Nim {
|
2019-09-16 22:43:27 +02:00
|
|
|
|
2019-10-25 09:55:32 +02:00
|
|
|
const char C_NIMBLEPROJECT_TASKS[] = "Nim.NimbleProject.Tasks";
|
|
|
|
|
const char C_NIMBLEPROJECT_METADATA[] = "Nim.NimbleProject.Metadata";
|
|
|
|
|
|
2019-11-22 12:41:15 +01:00
|
|
|
static std::vector<NimbleTask> parseTasks(const QString &nimblePath, const QString &workingDirectory)
|
2019-09-16 22:43:27 +02:00
|
|
|
{
|
|
|
|
|
QProcess process;
|
|
|
|
|
process.setWorkingDirectory(workingDirectory);
|
|
|
|
|
process.start(QStandardPaths::findExecutable(nimblePath), {"tasks"});
|
|
|
|
|
process.waitForFinished();
|
|
|
|
|
|
|
|
|
|
std::vector<NimbleTask> result;
|
|
|
|
|
|
|
|
|
|
QList<QByteArray> lines = process.readAllStandardOutput().split('\n');
|
|
|
|
|
lines = Utils::transform(lines, [](const QByteArray &line){ return line.trimmed(); });
|
|
|
|
|
Utils::erase(lines, [](const QByteArray &line) { return line.isEmpty(); });
|
|
|
|
|
|
|
|
|
|
for (const QByteArray &line : lines) {
|
|
|
|
|
QList<QByteArray> tokens = line.trimmed().split(' ');
|
|
|
|
|
QTC_ASSERT(!tokens.empty(), continue);
|
|
|
|
|
QString taskName = QString::fromUtf8(tokens.takeFirst());
|
|
|
|
|
QString taskDesc = QString::fromUtf8(tokens.join(' '));
|
|
|
|
|
result.push_back({std::move(taskName), std::move(taskDesc)});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-22 12:41:15 +01:00
|
|
|
static NimbleMetadata parseMetadata(const QString &nimblePath, const QString &workingDirectory)
|
|
|
|
|
{
|
2019-09-16 22:43:27 +02:00
|
|
|
QProcess process;
|
|
|
|
|
process.setWorkingDirectory(workingDirectory);
|
|
|
|
|
process.start(QStandardPaths::findExecutable(nimblePath), {"dump"});
|
|
|
|
|
process.waitForFinished();
|
|
|
|
|
|
|
|
|
|
NimbleMetadata result = {};
|
|
|
|
|
|
|
|
|
|
QList<QByteArray> lines = process.readAllStandardOutput().split('\n');
|
|
|
|
|
lines = Utils::transform(lines, [](const QByteArray &line){ return line.trimmed(); });
|
|
|
|
|
Utils::erase(lines, [](const QByteArray &line) { return line.isEmpty(); });
|
|
|
|
|
|
|
|
|
|
for (const QByteArray &line : lines) {
|
|
|
|
|
QList<QByteArray> tokens = line.trimmed().split(':');
|
|
|
|
|
QTC_ASSERT(tokens.size() == 2, continue);
|
|
|
|
|
QString name = QString::fromUtf8(tokens.takeFirst()).trimmed();
|
|
|
|
|
QString value = QString::fromUtf8(tokens.takeFirst()).trimmed();
|
|
|
|
|
QTC_ASSERT(value.size() >= 2, continue);
|
|
|
|
|
QTC_ASSERT(value.front() == QChar('"'), continue);
|
|
|
|
|
QTC_ASSERT(value.back() == QChar('"'), continue);
|
|
|
|
|
value.remove(0, 1);
|
|
|
|
|
value.remove(value.size() - 1, 1);
|
|
|
|
|
|
|
|
|
|
if (name == "binDir")
|
|
|
|
|
result.binDir = value;
|
|
|
|
|
else if (name == "srcDir")
|
|
|
|
|
result.srcDir = value;
|
|
|
|
|
else if (name == "bin") {
|
|
|
|
|
QStringList bin = value.split(',');
|
|
|
|
|
bin = Utils::transform(bin, [](const QString &x){ return x.trimmed(); });
|
|
|
|
|
Utils::erase(bin, [](const QString &x) { return x.isEmpty(); });
|
|
|
|
|
result.bin = std::move(bin);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-25 09:55:32 +02:00
|
|
|
NimbleBuildSystem::NimbleBuildSystem(Target *target)
|
2019-11-22 12:41:15 +01:00
|
|
|
: BuildSystem(target), m_projectScanner(target->project())
|
2019-09-16 22:43:27 +02:00
|
|
|
{
|
2019-11-22 12:41:15 +01:00
|
|
|
m_projectScanner.watchProjectFilePath();
|
2019-10-25 09:55:32 +02:00
|
|
|
|
2019-11-22 12:41:15 +01:00
|
|
|
connect(&m_projectScanner, &NimProjectScanner::fileChanged, this, [this](const QString &path) {
|
|
|
|
|
if (path == projectFilePath().toString())
|
|
|
|
|
requestDelayedParse();
|
2019-11-05 07:19:45 +01:00
|
|
|
});
|
2019-10-25 09:55:32 +02:00
|
|
|
|
2019-11-22 12:41:15 +01:00
|
|
|
connect(&m_projectScanner, &NimProjectScanner::requestReparse,
|
|
|
|
|
this, &NimbleBuildSystem::requestDelayedParse);
|
2019-09-16 22:43:27 +02:00
|
|
|
|
2019-11-22 12:41:15 +01:00
|
|
|
connect(&m_projectScanner, &NimProjectScanner::finished, this, &NimbleBuildSystem::updateProject);
|
2019-09-16 22:43:27 +02:00
|
|
|
|
2020-02-17 00:18:40 +01:00
|
|
|
connect(&m_projectScanner, &NimProjectScanner::directoryChanged, this, [this] (const QString &directory){
|
|
|
|
|
// Workaround for nimble creating temporary files in project root directory
|
|
|
|
|
// when querying the list of tasks.
|
|
|
|
|
// See https://github.com/nim-lang/nimble/issues/720
|
|
|
|
|
if (directory != projectDirectory().toString())
|
2019-11-22 12:41:15 +01:00
|
|
|
requestDelayedParse();
|
|
|
|
|
});
|
2019-09-16 22:43:27 +02:00
|
|
|
|
2019-11-22 12:41:15 +01:00
|
|
|
requestDelayedParse();
|
2019-09-16 22:43:27 +02:00
|
|
|
}
|
|
|
|
|
|
2019-11-22 12:41:15 +01:00
|
|
|
void NimbleBuildSystem::triggerParsing()
|
2019-09-16 22:43:27 +02:00
|
|
|
{
|
2019-11-22 12:41:15 +01:00
|
|
|
m_guard = guardParsingRun();
|
|
|
|
|
m_projectScanner.startScan();
|
2019-10-25 09:55:32 +02:00
|
|
|
}
|
|
|
|
|
|
2019-11-22 12:41:15 +01:00
|
|
|
void NimbleBuildSystem::updateProject()
|
2019-10-25 09:55:32 +02:00
|
|
|
{
|
2019-11-22 12:41:15 +01:00
|
|
|
const FilePath projectDir = projectDirectory();
|
|
|
|
|
|
|
|
|
|
m_metadata = parseMetadata(QStandardPaths::findExecutable("nimble"), projectDir.toString());
|
|
|
|
|
const FilePath binDir = projectDir.pathAppended(m_metadata.binDir);
|
2019-10-25 09:55:32 +02:00
|
|
|
const FilePath srcDir = projectDir.pathAppended("src");
|
|
|
|
|
|
2019-11-22 12:41:15 +01:00
|
|
|
QList<BuildTargetInfo> targets = Utils::transform(m_metadata.bin, [&](const QString &bin){
|
2019-10-25 09:55:32 +02:00
|
|
|
BuildTargetInfo info = {};
|
|
|
|
|
info.displayName = bin;
|
|
|
|
|
info.targetFilePath = binDir.pathAppended(HostOsInfo::withExecutableSuffix(bin));
|
|
|
|
|
info.projectFilePath = srcDir.pathAppended(bin).stringAppended(".nim");
|
|
|
|
|
info.workingDirectory = binDir;
|
|
|
|
|
info.buildKey = bin;
|
|
|
|
|
return info;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
setApplicationTargets(std::move(targets));
|
2019-11-22 12:41:15 +01:00
|
|
|
|
|
|
|
|
std::vector<NimbleTask> tasks = parseTasks(QStandardPaths::findExecutable("nimble"), projectDir.toString());
|
|
|
|
|
if (tasks != m_tasks) {
|
|
|
|
|
m_tasks = std::move(tasks);
|
|
|
|
|
emit tasksChanged();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Complete scan
|
|
|
|
|
m_guard.markAsSuccess();
|
|
|
|
|
m_guard = {};
|
|
|
|
|
|
|
|
|
|
emitBuildSystemUpdated();
|
2019-10-25 09:55:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::vector<NimbleTask> NimbleBuildSystem::tasks() const
|
|
|
|
|
{
|
|
|
|
|
return m_tasks;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NimbleMetadata NimbleBuildSystem::metadata() const
|
|
|
|
|
{
|
|
|
|
|
return m_metadata;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void NimbleBuildSystem::saveSettings()
|
|
|
|
|
{
|
|
|
|
|
QStringList result;
|
|
|
|
|
for (const NimbleTask &task : m_tasks) {
|
|
|
|
|
result.push_back(task.name);
|
|
|
|
|
result.push_back(task.description);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
project()->setNamedSettings(C_NIMBLEPROJECT_TASKS, result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void NimbleBuildSystem::loadSettings()
|
|
|
|
|
{
|
|
|
|
|
QStringList list = project()->namedSettings(C_NIMBLEPROJECT_TASKS).toStringList();
|
|
|
|
|
|
|
|
|
|
m_tasks.clear();
|
|
|
|
|
if (list.size() % 2 != 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
std::vector<NimbleTask> result;
|
|
|
|
|
for (int i = 0; i < list.size(); i += 2)
|
|
|
|
|
result.push_back({list[i], list[i + 1]});
|
2019-11-22 12:41:15 +01:00
|
|
|
|
|
|
|
|
requestParse();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool NimbleBuildSystem::supportsAction(Node *context, ProjectAction action, const Node *node) const
|
|
|
|
|
{
|
|
|
|
|
if (node->asFileNode()) {
|
|
|
|
|
return action == ProjectAction::Rename
|
|
|
|
|
|| action == ProjectAction::RemoveFile;
|
|
|
|
|
}
|
|
|
|
|
if (node->isFolderNodeType() || node->isProjectNodeType()) {
|
|
|
|
|
return action == ProjectAction::AddNewFile
|
|
|
|
|
|| action == ProjectAction::RemoveFile
|
|
|
|
|
|| action == ProjectAction::AddExistingFile;
|
|
|
|
|
}
|
|
|
|
|
return BuildSystem::supportsAction(context, action, node);
|
2019-09-16 22:43:27 +02:00
|
|
|
}
|
2019-11-22 12:41:15 +01:00
|
|
|
|
|
|
|
|
bool NimbleBuildSystem::addFiles(Node *, const QStringList &filePaths, QStringList *)
|
|
|
|
|
{
|
|
|
|
|
return m_projectScanner.addFiles(filePaths);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RemovedFilesFromProject NimbleBuildSystem::removeFiles(Node *,
|
|
|
|
|
const QStringList &filePaths,
|
|
|
|
|
QStringList *)
|
|
|
|
|
{
|
|
|
|
|
return m_projectScanner.removeFiles(filePaths);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool NimbleBuildSystem::deleteFiles(Node *, const QStringList &)
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool NimbleBuildSystem::renameFile(Node *, const QString &filePath, const QString &newFilePath)
|
|
|
|
|
{
|
|
|
|
|
return m_projectScanner.renameFile(filePath, newFilePath);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // Nim
|