QbsProjectManager: Do renamings in bulk for qbs >= 2.5

Bulk renamings don't work reliably if we split them up on the client
side.

Change-Id: I5a1e58c80c1bac806dc92f535f4119d8f5374192
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
Christian Kandeler
2024-09-13 15:38:33 +02:00
parent 05430afdcf
commit 92b7df11c0
4 changed files with 104 additions and 8 deletions

View File

@@ -272,6 +272,12 @@ bool QbsBuildSystem::renameFiles(Node *context, const FilePairs &filesToRename,
if (auto *n = dynamic_cast<QbsGroupNode *>(context)) {
const QbsProductNode * const prdNode = parentQbsProductNode(n);
QTC_ASSERT(prdNode, return false);
if (session()->apiLevel() >= 6) {
return renameFilesInProduct(
filesToRename, prdNode->productData(), n->groupData(), notRenamed);
}
bool success = true;
for (const auto &[oldFilePath, newFilePath] : filesToRename) {
if (!renameFileInProduct(
@@ -288,6 +294,9 @@ bool QbsBuildSystem::renameFiles(Node *context, const FilePairs &filesToRename,
}
if (auto *n = dynamic_cast<QbsProductNode *>(context)) {
if (session()->apiLevel() >= 6)
return renameFilesInProduct(filesToRename, n->productData(), n->mainGroup(), notRenamed);
bool success = true;
for (const auto &[oldFilePath, newFilePath] : filesToRename) {
if (!renameFileInProduct(
@@ -433,6 +442,40 @@ bool QbsBuildSystem::renameFileInProduct(
return addFilesToProduct({FilePath::fromString(newPath)}, product, group, &dummy);
}
bool QbsBuildSystem::renameFilesInProduct(
const Utils::FilePairs &files,
const QJsonObject &product,
const QJsonObject &group,
Utils::FilePaths *notRenamed)
{
const auto allWildcardsInGroup = transform<QStringList>(
group.value("source-artifacts-from-wildcards").toArray(),
[](const QJsonValue &v) { return v.toObject().value("file-path").toString(); });
using FileStringPair = std::pair<QString, QString>;
using FileStringPairs = QList<FileStringPair>;
const FileStringPairs filesAsStrings = Utils::transform(files, [](const FilePair &fp) {
return std::make_pair(fp.first.path(), fp.second.path());
});
FileStringPairs nonWildcardFiles;
for (const FileStringPair &file : filesAsStrings) {
if (!allWildcardsInGroup.contains(file.first))
nonWildcardFiles << file;
}
const QString groupFilePath = group.value("location")
.toObject().value("file-path").toString();
ensureWriteableQbsFile(groupFilePath);
const FileChangeResult result = session()->renameFiles(
nonWildcardFiles,
product.value("name").toString(),
group.value("name").toString());
*notRenamed = FileUtils::toFilePathList(result.failedFiles());
if (result.error().hasError())
MessageManager::writeDisrupting(result.error().toString());
return notRenamed->isEmpty();
}
QString QbsBuildSystem::profile() const
{
return QbsProfileManager::ensureProfileForKit(target()->kit());

View File

@@ -87,6 +87,11 @@ public:
bool renameFileInProduct(const QString &oldPath,
const QString &newPath, const QJsonObject &product,
const QJsonObject &group);
bool renameFilesInProduct(
const Utils::FilePairs &files,
const QJsonObject &product,
const QJsonObject &group,
Utils::FilePaths *notRenamed);
static ProjectExplorer::FileType fileTypeFor(const QSet<QString> &tags);

View File

@@ -142,6 +142,7 @@ public:
QHash<QString, QStringList> generatedFilesForSources;
std::optional<Error> lastError;
State state = State::Inactive;
int apiLevel = 0;
bool fileUpdatePossible = true;
};
@@ -259,6 +260,11 @@ QJsonObject QbsSession::projectData() const
return d->projectData;
}
int QbsSession::apiLevel() const
{
return d->apiLevel;
}
void QbsSession::sendRequest(const QJsonObject &request)
{
QTC_ASSERT(d->currentRequest.isEmpty(),
@@ -317,6 +323,12 @@ FileChangeResult QbsSession::removeFiles(const QStringList &files, const QString
return updateFileList("remove-files", files, product, group);
}
FileChangeResult QbsSession::renameFiles(
const QList<std::pair<QString, QString>> &files, const QString &product, const QString &group)
{
return updateFileList("rename-files", files, product, group);
}
RunEnvironmentResult QbsSession::getRunEnvironment(
const QString &product,
const QProcessEnvironment &baseEnv,
@@ -456,7 +468,8 @@ void QbsSession::handlePacket(const QJsonObject &packet)
setError(Error::VersionMismatch);
return;
}
if (parent() && packet.value("api-level").toInt() > 4) {
d->apiLevel = packet.value("api-level").toInt();
if (parent() && d->apiLevel > 4) {
const QString lspSocket = packet.value("lsp-socket").toString();
if (!lspSocket.isEmpty())
d->languageClient = new QbsLanguageClient(lspSocket,
@@ -585,14 +598,38 @@ void QbsSession::setInactive()
d->languageClient = nullptr; // Owned by LanguageClientManager
}
FileChangeResult QbsSession::updateFileList(const char *action, const QStringList &files,
const QString &product, const QString &group)
FileChangeResult QbsSession::updateFileList(
const char *action,
const std::variant<QStringList, QList<std::pair<QString, QString>>> &files,
const QString &product,
const QString &group)
{
if (d->state != State::Active)
return FileChangeResult(files, Tr::tr("The qbs session is not in a valid state."));
const bool filesAreStrings = std::holds_alternative<QStringList>(files);
if (d->state != State::Active) {
QStringList failedFiles;
if (filesAreStrings) {
failedFiles = std::get<QStringList>(files);
} else {
failedFiles = Utils::transform(
std::get<QList<std::pair<QString, QString>>>(files),
[](const std::pair<QString, QString> &p) { return p.first; });
}
return FileChangeResult(failedFiles, Tr::tr("The qbs session is not in a valid state."));
}
QJsonArray filesAsJson;
if (filesAreStrings) {
filesAsJson = QJsonArray::fromStringList(std::get<QStringList>(files));
} else {
for (const auto &[source, target] : std::get<QList<std::pair<QString, QString>>>(files)) {
const QJsonObject file(
{std::make_pair(QLatin1String("source-path"), source),
std::make_pair(QLatin1String("target-path"), target)});
filesAsJson << file;
}
}
const QJsonObject fileUpdateRequest{
{"type", QLatin1String(action)},
{"files", QJsonArray::fromStringList(files)},
{"files", filesAsJson},
{"product", product},
{"group", group}};
if (d->fileUpdatePossible)

View File

@@ -14,6 +14,8 @@
#include <functional>
#include <optional>
#include <utility>
#include <variant>
namespace ProjectExplorer { class Target; }
@@ -114,6 +116,8 @@ public:
static QString errorString(Error error);
QJsonObject projectData() const;
int apiLevel() const;
void sendRequest(const QJsonObject &request);
void cancelCurrentJob();
void requestFilesGeneratedFrom(const QHash<QString, QStringList> &sourceFilesPerProduct);
@@ -122,6 +126,10 @@ public:
const QString &group);
FileChangeResult removeFiles(const QStringList &files, const QString &product,
const QString &group);
FileChangeResult renameFiles(
const QList<std::pair<QString, QString>> &files,
const QString &product,
const QString &group);
RunEnvironmentResult getRunEnvironment(const QString &product,
const QProcessEnvironment &baseEnv,
const QStringList &config);
@@ -170,8 +178,11 @@ private:
void setProjectDataFromReply(const QJsonObject &packet, bool withBuildSystemFiles);
void setError(Error error);
void setInactive();
FileChangeResult updateFileList(const char *action, const QStringList &files,
const QString &product, const QString &group);
FileChangeResult updateFileList(
const char *action,
const std::variant<QStringList, QList<std::pair<QString, QString>>> &files,
const QString &product,
const QString &group);
void handleFileListUpdated(const QJsonObject &reply);
void sendNextPendingFileUpdateRequest();
void sendFileUpdateRequest(const QJsonObject &request);