1// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
2//
3// SPDX-License-Identifier: GPL-3.0-or-later
4
5#include "builder.h"
6#include "util/custompaths.h"
7#include "dialog/contextdialog.h"
8
9#include <QStringList>
10#include <QJsonDocument>
11#include <QJsonObject>
12#include <QJsonArray>
13#include <QList>
14#include <QDir>
15#include <QFile>
16#include <QDebug>
17#include <QtConcurrent>
18
19#define NO_ERROR 0
20#define GLOBAL_ERROR 1
21#define USER_ERROR 2
22namespace support_file {
23namespace documents {
24inline static QJsonDocument builderGlobal;
25inline static QJsonDocument builderUser;
26
27static bool builderIsLoaded();
28
29static int loadDocument(QJsonDocument &globalDoc, const QString &globalFilePath,
30 QJsonDocument &userDoc, const QString &userFilePath,
31 QString * errorString = nullptr);
32
33static BuildFileInfo getBuildFileInfo(const QJsonDocument &doc,
34 const QFileInfo &info);
35}
36
37QString Builder::globalPath()
38{
39 auto result = CustomPaths::endSeparator(CustomPaths::global(CustomPaths::Configures));
40 return result + "builder.support";
41}
42
43QString Builder::userPath()
44{
45 auto result = CustomPaths::endSeparator(CustomPaths::user(CustomPaths::Configures));
46 return result + "builder.support";
47}
48
49void Builder::initialize()
50{
51 if (!documents::builderIsLoaded()) {
52 QString error;
53 if (0 != documents::loadDocument(documents::builderGlobal,
54 support_file::Builder::globalPath(),
55 documents::builderUser,
56 support_file::Builder::userPath(),
57 &error)) {
58 ContextDialog::ok(error);
59 }
60 }
61}
62
63QString Builder::buildSystem(const QString &filePath)
64{
65 support_file::Builder::initialize();
66
67 QFileInfo fileInfo(filePath);
68 if (!fileInfo.exists())
69 return "";
70
71 QJsonObject globalJsonObj = documents::builderGlobal.object();
72 QStringList globalJsonObjKeys = globalJsonObj.keys();
73 foreach (auto val, globalJsonObjKeys) {
74 if (globalJsonObj.value(val).toObject().value("suffix").toArray().contains(fileInfo.suffix()))
75 return val;
76 if (globalJsonObj.value(val).toObject().value("base").toArray().contains(fileInfo.fileName()))
77 return val;
78 }
79
80 QJsonObject cacheJsonObj = documents::builderUser.object();
81 QStringList cacheJsonObjKeys = cacheJsonObj.keys();
82 foreach (auto val, cacheJsonObjKeys) {
83 if (cacheJsonObj.value(val).toObject().value("suffix").toArray().contains(fileInfo.suffix()))
84 return val;
85 if (cacheJsonObj.value(val).toObject().value("base").toArray().contains(fileInfo.fileName()))
86 return val;
87 }
88
89 return "";
90}
91
92BuildFileInfo Builder::buildInfo(const QString &filePath)
93{
94 QFileInfo info(filePath);
95 if (!info.exists())
96 return {};
97
98 support_file::BuildFileInfo result = documents::getBuildFileInfo(documents::builderUser, info);
99 if (result.isEmpty())
100 result = documents::getBuildFileInfo(documents::builderGlobal, info);
101 return result;
102}
103
104QList<BuildFileInfo> Builder::buildInfos(const QString &dirPath)
105{
106 support_file::Builder::initialize();
107
108 if (documents::builderIsLoaded()) {
109 QSet<BuildFileInfo> result;
110 QDir dir(dirPath);
111 QFileInfoList infos = dir.entryInfoList(QDir::Filter::NoDot|QDir::Filter::NoDotDot|QDir::Filter::Files);
112 QJsonObject globalObject = documents::builderGlobal.object();
113 QJsonObject userObject = documents::builderUser.object();
114
115 auto mappedFunc = [=, &result](const QFileInfo &info)
116 {
117 if (!info.exists())
118 return;
119
120 auto tempBuildInfo = documents::getBuildFileInfo(documents::builderGlobal, info);
121 if (!tempBuildInfo.isEmpty())
122 result += tempBuildInfo;
123
124 tempBuildInfo = documents::getBuildFileInfo(documents::builderUser, info);
125 if (!tempBuildInfo.isEmpty())
126 result += tempBuildInfo;
127 };
128
129 QtConcurrent::blockingMap(infos, mappedFunc);
130
131 return result.values();
132 }
133
134 return {};
135}
136
137
138
139bool support_file::documents::builderIsLoaded()
140{
141 return !builderGlobal.isEmpty() && !builderUser.isEmpty();
142}
143
144int support_file::documents::loadDocument(QJsonDocument &globalDoc,
145 const QString &globalFilePath,
146 QJsonDocument &userDoc,
147 const QString &userFilePath,
148 QString *errorString)
149{
150 QFile file(globalFilePath);
151 if (!file.exists()) {
152 if (errorString)
153 *errorString = QString("Failed, not found global configure file: %0").arg(globalFilePath);
154 return GLOBAL_ERROR;
155 }
156
157 if (!file.open(QFile::ReadOnly)) {
158 if (errorString)
159 *errorString = QString("Failed, can't open global configure file: %0").arg(globalFilePath);
160 return GLOBAL_ERROR;
161 }
162
163 globalDoc = QJsonDocument::fromJson(file.readAll());
164 file.close();
165
166 CustomPaths::checkDir(CustomPaths::user(CustomPaths::Configures));
167
168 QFileInfo fileInfo(userFilePath);
169 if (!fileInfo.exists()) {
170 QFile::copy(globalFilePath, fileInfo.filePath());
171 }
172
173 QFile userfile(userFilePath);
174 if (!userfile.permissions().testFlag(QFile::WriteUser)) {
175 userfile.setPermissions(userfile.permissions() | QFile::WriteUser);
176 }
177
178 if (!userfile.open(QFile::OpenModeFlag::ReadOnly)) {
179 if (errorString) {
180 *errorString += "Failed, can't open user configure file: ";
181 *errorString += userFilePath;
182 return USER_ERROR;
183 }
184 }
185
186 userDoc = QJsonDocument::fromJson(userfile.readAll());
187 userfile.close();
188 return NO_ERROR;
189}
190
191BuildFileInfo documents::getBuildFileInfo(const QJsonDocument &doc, const QFileInfo &info)
192{
193 support_file::BuildFileInfo result;
194 auto docObject = doc.object();
195 auto keys = docObject.keys();
196 for (auto key : keys) {
197 QJsonObject keyObject = docObject.value(key).toObject();
198 QJsonArray suffixs = keyObject.value("suffix").toArray();
199 QJsonArray bases = keyObject.value("base").toArray();
200 foreach (auto suffix, suffixs) {
201 if (suffix == info.suffix()) {
202 return support_file::BuildFileInfo { key, info.filePath() };
203 }
204 }
205
206 foreach (auto base, bases) {
207 if (base == info.fileName()) {
208 return support_file::BuildFileInfo { key, info.filePath() };
209 }
210 }
211 }
212 return result;
213}
214
215bool BuildFileInfo::operator==(const support_file::BuildFileInfo &info) const
216{
217 return buildSystem == info.buildSystem
218 && projectPath == info.projectPath;
219}
220
221bool BuildFileInfo::isEmpty()
222{
223 return buildSystem.isEmpty() || projectPath.isEmpty();
224}
225
226uint qHash(const support_file::BuildFileInfo &info, uint seed)
227{
228 return qHash(info.buildSystem + " " + info.projectPath, seed);
229}
230
231} // namespace support_file
232
233
234