forked from qt-creator/qt-creator
Gerrit: Refactor actual output parsing from its setup
Change-Id: I5cf4c75dfbe1620a59cebc756e4e138957cf635e Reviewed-by: Tobias Hunger <tobias.hunger@qt.io>
This commit is contained in:
committed by
Orgad Shaneh
parent
d64e17ad55
commit
1e89c617f4
@@ -547,13 +547,8 @@ void GerritModel::setState(GerritModel::QueryState s)
|
|||||||
\endcode
|
\endcode
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static bool parseOutput(const QSharedPointer<GerritParameters> ¶meters,
|
static GerritChangePtr parseSshOutput(const QJsonObject &object)
|
||||||
const GerritServer &server,
|
|
||||||
const QByteArray &output,
|
|
||||||
QList<GerritChangePtr> &result)
|
|
||||||
{
|
{
|
||||||
// The output consists of separate lines containing a document each
|
|
||||||
const QString typeKey = "type";
|
|
||||||
const QString dependsOnKey = "dependsOn";
|
const QString dependsOnKey = "dependsOn";
|
||||||
const QString neededByKey = "neededBy";
|
const QString neededByKey = "neededBy";
|
||||||
const QString branchKey = "branch";
|
const QString branchKey = "branch";
|
||||||
@@ -572,96 +567,110 @@ static bool parseOutput(const QSharedPointer<GerritParameters> ¶meters,
|
|||||||
const QString approvalsValueKey = "value";
|
const QString approvalsValueKey = "value";
|
||||||
const QString approvalsByKey = "by";
|
const QString approvalsByKey = "by";
|
||||||
const QString lastUpdatedKey = "lastUpdated";
|
const QString lastUpdatedKey = "lastUpdated";
|
||||||
const QList<QByteArray> lines = output.split('\n');
|
|
||||||
const QString approvalsTypeKey = "type";
|
const QString approvalsTypeKey = "type";
|
||||||
const QString approvalsDescriptionKey = "description";
|
const QString approvalsDescriptionKey = "description";
|
||||||
|
|
||||||
bool res = true;
|
GerritChangePtr change(new GerritChange);
|
||||||
result.clear();
|
// Read current patch set.
|
||||||
result.reserve(lines.size());
|
const QJsonObject patchSet = object.value(patchSetKey).toObject();
|
||||||
|
change->currentPatchSet.patchSetNumber = qMax(1, patchSet.value(numberKey).toString().toInt());
|
||||||
|
change->currentPatchSet.ref = patchSet.value(refKey).toString();
|
||||||
|
const QJsonArray approvalsJ = patchSet.value(approvalsKey).toArray();
|
||||||
|
const int ac = approvalsJ.size();
|
||||||
|
for (int a = 0; a < ac; ++a) {
|
||||||
|
const QJsonObject ao = approvalsJ.at(a).toObject();
|
||||||
|
GerritApproval approval;
|
||||||
|
const QJsonObject approverO = ao.value(approvalsByKey).toObject();
|
||||||
|
approval.reviewer = approverO.value(ownerUserKey).toString();
|
||||||
|
approval.email = approverO.value(ownerEmailKey).toString();
|
||||||
|
approval.approval = ao.value(approvalsValueKey).toString().toInt();
|
||||||
|
approval.type = ao.value(approvalsTypeKey).toString();
|
||||||
|
approval.description = ao.value(approvalsDescriptionKey).toString();
|
||||||
|
change->currentPatchSet.approvals.push_back(approval);
|
||||||
|
}
|
||||||
|
std::stable_sort(change->currentPatchSet.approvals.begin(),
|
||||||
|
change->currentPatchSet.approvals.end(),
|
||||||
|
gerritApprovalLessThan);
|
||||||
|
// Remaining
|
||||||
|
change->number = object.value(numberKey).toString().toInt();
|
||||||
|
change->url = object.value(urlKey).toString();
|
||||||
|
change->title = object.value(titleKey).toString();
|
||||||
|
const QJsonObject ownerJ = object.value(ownerKey).toObject();
|
||||||
|
change->owner = ownerJ.value(ownerNameKey).toString();
|
||||||
|
change->user = ownerJ.value(ownerUserKey).toString();
|
||||||
|
change->email = ownerJ.value(ownerEmailKey).toString();
|
||||||
|
change->project = object.value(projectKey).toString();
|
||||||
|
change->branch = object.value(branchKey).toString();
|
||||||
|
change->status = object.value(statusKey).toString();
|
||||||
|
if (const int timeT = qRound(object.value(lastUpdatedKey).toDouble()))
|
||||||
|
change->lastUpdated = QDateTime::fromTime_t(timeT);
|
||||||
|
// Read out dependencies
|
||||||
|
const QJsonValue dependsOnValue = object.value(dependsOnKey);
|
||||||
|
if (dependsOnValue.isArray()) {
|
||||||
|
const QJsonArray dependsOnArray = dependsOnValue.toArray();
|
||||||
|
if (!dependsOnArray.isEmpty()) {
|
||||||
|
const QJsonValue first = dependsOnArray.at(0);
|
||||||
|
if (first.isObject())
|
||||||
|
change->dependsOnNumber = first.toObject()[numberKey].toString().toInt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Read out needed by
|
||||||
|
const QJsonValue neededByValue = object.value(neededByKey);
|
||||||
|
if (neededByValue.isArray()) {
|
||||||
|
const QJsonArray neededByArray = neededByValue.toArray();
|
||||||
|
if (!neededByArray.isEmpty()) {
|
||||||
|
const QJsonValue first = neededByArray.at(0);
|
||||||
|
if (first.isObject())
|
||||||
|
change->neededByNumber = first.toObject()[numberKey].toString().toInt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return change;
|
||||||
|
}
|
||||||
|
|
||||||
for (const QByteArray &line : lines) {
|
static bool parseOutput(const QSharedPointer<GerritParameters> ¶meters,
|
||||||
if (line.isEmpty())
|
const GerritServer &server,
|
||||||
continue;
|
const QByteArray &output,
|
||||||
QJsonParseError error;
|
QList<GerritChangePtr> &result)
|
||||||
const QJsonDocument doc = QJsonDocument::fromJson(line, &error);
|
{
|
||||||
if (doc.isNull()) {
|
// The output consists of separate lines containing a document each
|
||||||
QString errorMessage = GerritModel::tr("Parse error: \"%1\" -> %2")
|
// Add a comma after each line (except the last), and enclose it as an array
|
||||||
.arg(QString::fromLocal8Bit(line))
|
QByteArray adaptedOutput = '[' + output + ']';
|
||||||
.arg(error.errorString());
|
adaptedOutput.replace('\n', ',');
|
||||||
qWarning() << errorMessage;
|
const int lastComma = adaptedOutput.lastIndexOf(',');
|
||||||
VcsOutputWindow::appendError(errorMessage);
|
if (lastComma >= 0)
|
||||||
res = false;
|
adaptedOutput[lastComma] = '\n';
|
||||||
continue;
|
bool res = true;
|
||||||
}
|
|
||||||
GerritChangePtr change(new GerritChange);
|
QJsonParseError error;
|
||||||
const QJsonObject object = doc.object();
|
const QJsonDocument doc = QJsonDocument::fromJson(adaptedOutput, &error);
|
||||||
|
if (doc.isNull()) {
|
||||||
|
QString errorMessage = GerritModel::tr("Parse error: \"%1\" -> %2")
|
||||||
|
.arg(QString::fromUtf8(output))
|
||||||
|
.arg(error.errorString());
|
||||||
|
qWarning() << errorMessage;
|
||||||
|
VcsOutputWindow::appendError(errorMessage);
|
||||||
|
res = false;
|
||||||
|
}
|
||||||
|
const QJsonArray rootArray = doc.array();
|
||||||
|
result.clear();
|
||||||
|
result.reserve(rootArray.count());
|
||||||
|
for (const QJsonValue &value : rootArray) {
|
||||||
|
const QJsonObject object = value.toObject();
|
||||||
// Skip stats line: {"type":"stats","rowCount":9,"runTimeMilliseconds":13}
|
// Skip stats line: {"type":"stats","rowCount":9,"runTimeMilliseconds":13}
|
||||||
if (!object.value(typeKey).toString().isEmpty())
|
if (object.contains("type"))
|
||||||
continue;
|
continue;
|
||||||
// Read current patch set.
|
GerritChangePtr change = parseSshOutput(object);
|
||||||
const QJsonObject patchSet = object.value(patchSetKey).toObject();
|
|
||||||
change->currentPatchSet.patchSetNumber = qMax(1, patchSet.value(numberKey).toString().toInt());
|
|
||||||
change->currentPatchSet.ref = patchSet.value(refKey).toString();
|
|
||||||
const QJsonArray approvalsJ = patchSet.value(approvalsKey).toArray();
|
|
||||||
const int ac = approvalsJ.size();
|
|
||||||
for (int a = 0; a < ac; ++a) {
|
|
||||||
const QJsonObject ao = approvalsJ.at(a).toObject();
|
|
||||||
GerritApproval approval;
|
|
||||||
const QJsonObject approverO = ao.value(approvalsByKey).toObject();
|
|
||||||
approval.reviewer = approverO.value(ownerUserKey).toString();
|
|
||||||
approval.email = approverO.value(ownerEmailKey).toString();
|
|
||||||
approval.approval = ao.value(approvalsValueKey).toString().toInt();
|
|
||||||
approval.type = ao.value(approvalsTypeKey).toString();
|
|
||||||
approval.description = ao.value(approvalsDescriptionKey).toString();
|
|
||||||
change->currentPatchSet.approvals.push_back(approval);
|
|
||||||
}
|
|
||||||
std::stable_sort(change->currentPatchSet.approvals.begin(),
|
|
||||||
change->currentPatchSet.approvals.end(),
|
|
||||||
gerritApprovalLessThan);
|
|
||||||
// Remaining
|
|
||||||
change->number = object.value(numberKey).toString().toInt();
|
|
||||||
change->url = object.value(urlKey).toString();
|
|
||||||
if (change->url.isEmpty()) // No "canonicalWebUrl" is in gerrit.config.
|
|
||||||
change->url = defaultUrl(parameters, server, change->number);
|
|
||||||
change->title = object.value(titleKey).toString();
|
|
||||||
const QJsonObject ownerJ = object.value(ownerKey).toObject();
|
|
||||||
change->owner = ownerJ.value(ownerNameKey).toString();
|
|
||||||
change->user = ownerJ.value(ownerUserKey).toString();
|
|
||||||
change->email = ownerJ.value(ownerEmailKey).toString();
|
|
||||||
change->project = object.value(projectKey).toString();
|
|
||||||
change->branch = object.value(branchKey).toString();
|
|
||||||
change->status = object.value(statusKey).toString();
|
|
||||||
if (const int timeT = qRound(object.value(lastUpdatedKey).toDouble()))
|
|
||||||
change->lastUpdated = QDateTime::fromTime_t(timeT);
|
|
||||||
if (change->isValid()) {
|
if (change->isValid()) {
|
||||||
|
if (change->url.isEmpty()) // No "canonicalWebUrl" is in gerrit.config.
|
||||||
|
change->url = defaultUrl(parameters, server, change->number);
|
||||||
result.push_back(change);
|
result.push_back(change);
|
||||||
} else {
|
} else {
|
||||||
qWarning("%s: Parse error: '%s'.", Q_FUNC_INFO, line.constData());
|
const QByteArray jsonObject = QJsonDocument(object).toJson();
|
||||||
|
qWarning("%s: Parse error: '%s'.", Q_FUNC_INFO, jsonObject.constData());
|
||||||
VcsOutputWindow::appendError(GerritModel::tr("Parse error: \"%1\"")
|
VcsOutputWindow::appendError(GerritModel::tr("Parse error: \"%1\"")
|
||||||
.arg(QString::fromLocal8Bit(line)));
|
.arg(QString::fromUtf8(jsonObject)));
|
||||||
res = false;
|
res = false;
|
||||||
}
|
}
|
||||||
// Read out dependencies
|
|
||||||
const QJsonValue dependsOnValue = object.value(dependsOnKey);
|
|
||||||
if (dependsOnValue.isArray()) {
|
|
||||||
const QJsonArray dependsOnArray = dependsOnValue.toArray();
|
|
||||||
if (!dependsOnArray.isEmpty()) {
|
|
||||||
const QJsonValue first = dependsOnArray.at(0);
|
|
||||||
if (first.isObject())
|
|
||||||
change->dependsOnNumber = first.toObject()[numberKey].toString().toInt();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Read out needed by
|
|
||||||
const QJsonValue neededByValue = object.value(neededByKey);
|
|
||||||
if (neededByValue.isArray()) {
|
|
||||||
const QJsonArray neededByArray = neededByValue.toArray();
|
|
||||||
if (!neededByArray.isEmpty()) {
|
|
||||||
const QJsonValue first = neededByArray.at(0);
|
|
||||||
if (first.isObject())
|
|
||||||
change->neededByNumber = first.toObject()[numberKey].toString().toInt();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user