File indexing completed on 2024-05-05 04:39:01
0001 /* 0002 SPDX-FileCopyrightText: 2013-2014 Maciej Poleski 0003 0004 SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0005 */ 0006 0007 #include "bazaarutils.h" 0008 0009 #include <QDateTime> 0010 #include <QDebug> 0011 0012 #include <vcs/vcsrevision.h> 0013 #include <vcs/vcsstatusinfo.h> 0014 #include <vcs/vcsevent.h> 0015 0016 QDir BazaarUtils::toQDir(const QUrl& url) 0017 { 0018 return QDir(url.toLocalFile()); 0019 } 0020 0021 QDir BazaarUtils::workingCopy(const QUrl& path) 0022 { 0023 QDir dir = BazaarUtils::toQDir(path); 0024 while (!dir.exists(QStringLiteral(".bzr")) && dir.cdUp()); 0025 0026 return dir; 0027 } 0028 0029 QString BazaarUtils::getRevisionSpec(const KDevelop::VcsRevision& revision) 0030 { 0031 if (revision.revisionType() == KDevelop::VcsRevision::Special) { 0032 if (revision.specialType() == KDevelop::VcsRevision::Head) 0033 return QStringLiteral("-rlast:1"); 0034 else if (revision.specialType() == KDevelop::VcsRevision::Base) 0035 return QString(); // Workaround strange KDevelop behaviour 0036 else if (revision.specialType() == KDevelop::VcsRevision::Working) 0037 return QString(); 0038 else if (revision.specialType() == KDevelop::VcsRevision::Start) 0039 return QStringLiteral("-r1"); 0040 else 0041 return QString(); // Don't know how to handle this situation 0042 } else if (revision.revisionType() == KDevelop::VcsRevision::GlobalNumber) 0043 return QLatin1String("-r") + QString::number(revision.revisionValue().toLongLong()); 0044 else 0045 return QString(); // Don't know how to handle this situation 0046 } 0047 0048 QString BazaarUtils::getRevisionSpecRange(const KDevelop::VcsRevision& end) 0049 { 0050 if (end.revisionType() == KDevelop::VcsRevision::Special) { 0051 if (end.specialType() == KDevelop::VcsRevision::Head) { 0052 return QStringLiteral("-r..last:1"); 0053 } else if (end.specialType() == KDevelop::VcsRevision::Base) { 0054 return QStringLiteral("-r..last:1"); // Workaround strange KDevelop behaviour 0055 } else if (end.specialType() == KDevelop::VcsRevision::Working) { 0056 return QString(); 0057 } else if (end.specialType() == KDevelop::VcsRevision::Start) { 0058 return QStringLiteral("-..r1"); 0059 } else { 0060 return QString(); // Don't know how to handle this situation 0061 } 0062 } else if (end.revisionType() == KDevelop::VcsRevision::GlobalNumber) { 0063 return QStringLiteral("-r") + QString::number(end.revisionValue().toLongLong()); 0064 } 0065 0066 return QString(); // Don't know how to handle this situation 0067 } 0068 0069 QString BazaarUtils::getRevisionSpecRange(const KDevelop::VcsRevision& begin, 0070 const KDevelop::VcsRevision& end) 0071 { 0072 if (begin.revisionType() == KDevelop::VcsRevision::Special) { 0073 if (begin.specialType() == KDevelop::VcsRevision::Previous) { 0074 if (end.revisionType() == KDevelop::VcsRevision::Special) { 0075 if (end.specialType() == KDevelop::VcsRevision::Base || 0076 end.specialType() == KDevelop::VcsRevision::Head) 0077 return QStringLiteral("-rlast:2..last:1"); 0078 else if (end.specialType() == KDevelop::VcsRevision::Working) 0079 return QString(); 0080 else if (end.specialType() == KDevelop::VcsRevision::Start) 0081 return QStringLiteral("-r0..1"); // That's wrong revision range 0082 } else if (end.revisionType() == KDevelop::VcsRevision::GlobalNumber) 0083 return QStringLiteral("-r") + 0084 QString::number(end.revisionValue().toLongLong() - 1) 0085 + QLatin1String("..") + QString::number(end.revisionValue().toLongLong()); 0086 else 0087 return QString(); // Don't know how to handle this situation 0088 } else if (begin.specialType() == KDevelop::VcsRevision::Base || 0089 begin.specialType() == KDevelop::VcsRevision::Head) { 0090 // Only one possibility: comparing working copy to last commit 0091 return QString(); 0092 } 0093 } else if (begin.revisionType() == KDevelop::VcsRevision::GlobalNumber) { 0094 if (end.revisionType() == KDevelop::VcsRevision::Special) { 0095 // Assuming working copy 0096 return QLatin1String("-r") + QString::number(begin.revisionValue().toLongLong()); 0097 } else { 0098 return QLatin1String("-r") + QString::number(begin.revisionValue().toLongLong()) 0099 + QLatin1String("..") + QString::number(end.revisionValue().toLongLong()); 0100 } 0101 } 0102 return QString(); // Don't know how to handle this situation 0103 } 0104 0105 bool BazaarUtils::isValidDirectory(const QUrl& dirPath) 0106 { 0107 QDir dir = BazaarUtils::workingCopy(dirPath); 0108 0109 return dir.cd(QStringLiteral(".bzr")) && dir.exists(QStringLiteral("branch")); 0110 } 0111 0112 KDevelop::VcsStatusInfo BazaarUtils::parseVcsStatusInfoLine(const QString& line) 0113 { 0114 const auto tokens = line.splitRef(QLatin1Char(' '), Qt::SkipEmptyParts); 0115 KDevelop::VcsStatusInfo result; 0116 if (tokens.size() < 2) // Don't know how to handle this situation (it is an error) 0117 return result; 0118 result.setUrl(QUrl::fromLocalFile(tokens.back().toString())); 0119 if (tokens[0] == QLatin1String("M")) { 0120 result.setState(KDevelop::VcsStatusInfo::ItemModified); 0121 } else if (tokens[0] == QLatin1String("C")) { 0122 result.setState(KDevelop::VcsStatusInfo::ItemHasConflicts); 0123 } else if (tokens[0] == QLatin1String("+N")) { 0124 result.setState(KDevelop::VcsStatusInfo::ItemAdded); 0125 } else if (tokens[0] == QLatin1String("?")) { 0126 result.setState(KDevelop::VcsStatusInfo::ItemUnknown); 0127 } else if (tokens[0] == QLatin1String("D")) { 0128 result.setState(KDevelop::VcsStatusInfo::ItemDeleted); 0129 } else { 0130 result.setState(KDevelop::VcsStatusInfo::ItemUserState); 0131 qWarning() << "Unsupported status: " << tokens[0]; 0132 } 0133 return result; 0134 } 0135 0136 QString BazaarUtils::concatenatePath(const QDir& workingCopy, const QUrl& pathInWorkingCopy) 0137 { 0138 return QFileInfo(workingCopy.absolutePath() + QDir::separator() 0139 + pathInWorkingCopy.toLocalFile()).absoluteFilePath(); 0140 } 0141 0142 KDevelop::VcsEvent BazaarUtils::parseBzrLogPart(const QString& output) 0143 { 0144 const QStringList outputLines = output.split(QLatin1Char('\n')); 0145 KDevelop::VcsEvent commitInfo; 0146 bool atMessage = false; 0147 QString message; 0148 bool afterMessage = false; 0149 QHash<QString, KDevelop::VcsItemEvent::Actions> fileToActionsMapping; 0150 KDevelop::VcsItemEvent::Action currentAction; 0151 for (const QString &line : outputLines) { 0152 if (!atMessage) { 0153 if (line.startsWith(QLatin1String("revno"))) { 0154 QString revno = line.mid(QStringLiteral("revno: ").length()); 0155 revno = revno.left(revno.indexOf(QLatin1Char(' '))); 0156 KDevelop::VcsRevision revision; 0157 revision.setRevisionValue(revno.toLongLong(), KDevelop::VcsRevision::GlobalNumber); 0158 commitInfo.setRevision(revision); 0159 } else if (line.startsWith(QLatin1String("committer: "))) { 0160 QString commiter = line.mid(QStringLiteral("committer: ").length()); 0161 commitInfo.setAuthor(commiter); // Author goes after committer, but only if is different 0162 } else if (line.startsWith(QLatin1String("author"))) { 0163 QString author = line.mid(QStringLiteral("author: ").length()); 0164 commitInfo.setAuthor(author); // It may override committer (In fact committer is not supported by VcsEvent) 0165 } else if (line.startsWith(QLatin1String("timestamp"))) { 0166 const QString formatString = QStringLiteral("yyyy-MM-dd hh:mm:ss"); 0167 QString timestamp = line.mid(QStringLiteral("timestamp: ddd ").length(), formatString.length()); 0168 commitInfo.setDate(QDateTime::fromString(timestamp, formatString)); 0169 } else if (line.startsWith(QLatin1String("message"))) { 0170 atMessage = true; 0171 } 0172 } else if (atMessage && !afterMessage) { 0173 if (!line.isEmpty() && line[0].isSpace()) { 0174 message += line.trimmed() + QLatin1Char('\n'); 0175 } else if (!line.isEmpty()) { 0176 afterMessage = true; 0177 // leave atMessage = true 0178 currentAction = BazaarUtils::parseActionDescription(line); 0179 } // if line is empty - ignore and get next 0180 } else if (afterMessage) { 0181 if (!line.isEmpty() && !line[0].isSpace()) { 0182 currentAction = BazaarUtils::parseActionDescription(line); 0183 } else if (!line.isEmpty()) { 0184 fileToActionsMapping[line.trimmed()] |= currentAction; 0185 } // if line is empty - ignore and get next 0186 } 0187 } 0188 if (atMessage) 0189 commitInfo.setMessage(message.trimmed()); 0190 for (auto i = fileToActionsMapping.begin(); i != fileToActionsMapping.end(); ++i) { 0191 KDevelop::VcsItemEvent itemEvent; 0192 itemEvent.setRepositoryLocation(i.key()); 0193 itemEvent.setActions(i.value()); 0194 commitInfo.addItem(itemEvent); 0195 } 0196 return commitInfo; 0197 } 0198 0199 KDevelop::VcsItemEvent::Action BazaarUtils::parseActionDescription(const QString& action) 0200 { 0201 if (action == QLatin1String("added:")) { 0202 return KDevelop::VcsItemEvent::Added; 0203 } else if (action == QLatin1String("modified:")) { 0204 return KDevelop::VcsItemEvent::Modified; 0205 } else if (action == QLatin1String("removed:")) { 0206 return KDevelop::VcsItemEvent::Deleted; 0207 } else if (action == QLatin1String("kind changed:")) { 0208 return KDevelop::VcsItemEvent::Replaced; // Best approximation 0209 } else if (action.startsWith(QLatin1String("renamed"))) { 0210 return KDevelop::VcsItemEvent::Modified; // Best approximation 0211 } else { 0212 qCritical("Unsupported action: %s", action.toLocal8Bit().constData()); 0213 return KDevelop::VcsItemEvent::Action(); 0214 } 0215 } 0216 0217 QList<QUrl> BazaarUtils::handleRecursion(const QList<QUrl>& listOfUrls, KDevelop::IBasicVersionControl::RecursionMode recursion) 0218 { 0219 if (recursion == KDevelop::IBasicVersionControl::Recursive) { 0220 return listOfUrls; // Nothing to do 0221 } else { 0222 QList<QUrl> result; 0223 for (const auto& url : listOfUrls) { 0224 if (url.isLocalFile() && QFileInfo(url.toLocalFile()).isFile()) { 0225 result.push_back(url); 0226 } 0227 } 0228 return result; 0229 } 0230 }