kde-extraapps/kdevplatform/plugins/bazaar/bazaarutils.cpp
2015-07-26 14:23:17 +03:00

246 lines
11 KiB
C++

/***************************************************************************
* Copyright 2013-2014 Maciej Poleski *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
* published by the Free Software Foundation; either version 2 of *
* the License or (at your option) version 3 or any later version *
* accepted by the membership of KDE e.V. (or its successor approved *
* by the membership of KDE e.V.), which shall act as a proxy *
* defined in Section 14 of version 3 of the license. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
#include "bazaarutils.h"
#include <QtCore/QDateTime>
#include <KDebug>
#include <KUrl>
#include <vcs/vcsrevision.h>
#include <vcs/vcsstatusinfo.h>
#include <vcs/vcsevent.h>
QDir BazaarUtils::toQDir(const KUrl& url)
{
return QDir(url.toLocalFile());
}
QDir BazaarUtils::workingCopy(const KUrl& path)
{
QDir dir = BazaarUtils::toQDir(path);
while (!dir.exists(".bzr") && dir.cdUp());
return dir;
}
QString BazaarUtils::getRevisionSpec(const KDevelop::VcsRevision& revision)
{
if (revision.revisionType() == KDevelop::VcsRevision::Special) {
if (revision.specialType() == KDevelop::VcsRevision::Head)
return "-rlast:1";
else if (revision.specialType() == KDevelop::VcsRevision::Base)
return QString(); // Workaround strange KDevelop behaviour
else if (revision.specialType() == KDevelop::VcsRevision::Working)
return QString();
else if (revision.specialType() == KDevelop::VcsRevision::Start)
return "-r1";
else
return QString(); // Don't know how to handle this situation
} else if (revision.revisionType() == KDevelop::VcsRevision::GlobalNumber)
return QString("-r") + QString::number(revision.revisionValue().toLongLong());
else
return QString(); // Don't know how to handle this situation
}
QString BazaarUtils::getRevisionSpecRange(const KDevelop::VcsRevision& end)
{
if (end.revisionType() == KDevelop::VcsRevision::Special) {
if (end.specialType() == KDevelop::VcsRevision::Head) {
return "-r..last:1";
} else if (end.specialType() == KDevelop::VcsRevision::Base) {
return "-r..last:1"; // Workaround strange KDevelop behaviour
} else if (end.specialType() == KDevelop::VcsRevision::Working) {
return QString();
} else if (end.specialType() == KDevelop::VcsRevision::Start) {
return "-..r1";
} else {
return QString(); // Don't know how to handle this situation
}
} else if (end.revisionType() == KDevelop::VcsRevision::GlobalNumber) {
return QString("-r") + QString::number(end.revisionValue().toLongLong());
}
return QString(); // Don't know how to handle this situation
}
QString BazaarUtils::getRevisionSpecRange(const KDevelop::VcsRevision& begin,
const KDevelop::VcsRevision& end)
{
if (begin.revisionType() == KDevelop::VcsRevision::Special) {
if (begin.specialType() == KDevelop::VcsRevision::Previous) {
if (end.revisionType() == KDevelop::VcsRevision::Special) {
if (end.specialType() == KDevelop::VcsRevision::Base ||
end.specialType() == KDevelop::VcsRevision::Head)
return "-rlast:2..last:1";
else if (end.specialType() == KDevelop::VcsRevision::Working)
return QString();
else if (end.specialType() == KDevelop::VcsRevision::Start)
return "-r0..1"; // That's wrong revision range
} else if (end.revisionType() == KDevelop::VcsRevision::GlobalNumber)
return QString("-r") +
QString::number(end.revisionValue().toLongLong() - 1)
+ ".." + QString::number(end.revisionValue().toLongLong());
else
return QString(); // Don't know how to handle this situation
} else if (begin.specialType() == KDevelop::VcsRevision::Base ||
begin.specialType() == KDevelop::VcsRevision::Head) {
// Only one possibility: comparing working copy to last commit
return QString();
}
} else if (begin.revisionType() == KDevelop::VcsRevision::GlobalNumber) {
if (end.revisionType() == KDevelop::VcsRevision::Special) {
// Assuming working copy
return QString("-r") + QString::number(begin.revisionValue().toLongLong());
} else {
return QString("-r") + QString::number(begin.revisionValue().toLongLong())
+ ".." + QString::number(end.revisionValue().toLongLong());
}
}
return QString(); // Don't know how to handle this situation
}
bool BazaarUtils::isValidDirectory(const KUrl& dirPath)
{
QDir dir = BazaarUtils::workingCopy(dirPath);
return dir.cd(".bzr") && dir.exists("branch");
}
KDevelop::VcsStatusInfo BazaarUtils::parseVcsStatusInfoLine(const QString& line)
{
QStringList tokens = line.split(' ', QString::SkipEmptyParts);
KDevelop::VcsStatusInfo result;
if (tokens.size() < 2) // Don't know how to handle this situation (it is an error)
return result;
result.setUrl(tokens.back());
if (tokens[0] == "M") {
result.setState(KDevelop::VcsStatusInfo::ItemModified);
} else if (tokens[0] == "C") {
result.setState(KDevelop::VcsStatusInfo::ItemHasConflicts);
} else if (tokens[0] == "+N") {
result.setState(KDevelop::VcsStatusInfo::ItemAdded);
} else if (tokens[0] == "?") {
result.setState(KDevelop::VcsStatusInfo::ItemUnknown);
} else if (tokens[0] == "D") {
result.setState(KDevelop::VcsStatusInfo::ItemDeleted);
} else {
result.setState(KDevelop::VcsStatusInfo::ItemUserState);
kWarning() << "Unsupported status: " << tokens[0];
}
return result;
}
QString BazaarUtils::concatenatePath(const QDir& workingCopy, const KUrl& pathInWorkingCopy)
{
return QFileInfo(workingCopy.absolutePath() + QDir::separator()
+ pathInWorkingCopy.toLocalFile()).absoluteFilePath();
}
KDevelop::VcsEvent BazaarUtils::parseBzrLogPart(const QString& output)
{
const QStringList outputLines = output.split('\n');
KDevelop::VcsEvent commitInfo;
bool atMessage = false;
QString message;
bool afterMessage = false;
QHash<QString, KDevelop::VcsItemEvent::Actions> fileToActionsMapping;
KDevelop::VcsItemEvent::Action currentAction;
for (const QString &line : outputLines) {
if (!atMessage) {
if (line.startsWith("revno")) {
QString revno = line.mid(QString("revno: ").length());
revno = revno.left(revno.indexOf(' '));
KDevelop::VcsRevision revision;
revision.setRevisionValue(revno.toLongLong(), KDevelop::VcsRevision::GlobalNumber);
commitInfo.setRevision(revision);
} else if (line.startsWith("committer: ")) {
QString commiter = line.mid(QString("committer: ").length());
commitInfo.setAuthor(commiter); // Author goes after commiter, but only if is different
} else if (line.startsWith("author")) {
QString author = line.mid(QString("author: ").length());
commitInfo.setAuthor(author); // It may override commiter (In fact commiter is not supported by VcsEvent)
} else if (line.startsWith("timestamp")) {
const QString formatString = "yyyy-MM-dd hh:mm:ss";
QString timestamp = line.mid(QString("timestamp: ddd ").length(), formatString.length());
commitInfo.setDate(QDateTime::fromString(timestamp, formatString));
} else if (line.startsWith("message")) {
atMessage = true;
}
} else if (atMessage && !afterMessage) {
if (!line.isEmpty() && line[0].isSpace()) {
message += line.trimmed() + "\n";
} else if (!line.isEmpty()) {
afterMessage = true;
// leave atMessage = true
currentAction = BazaarUtils::parseActionDescription(line);
} // if line is empty - ignore and get next
} else if (afterMessage) {
if (!line.isEmpty() && !line[0].isSpace()) {
currentAction = BazaarUtils::parseActionDescription(line);
} else if (!line.isEmpty()) {
fileToActionsMapping[line.trimmed()] |= currentAction;
} // if line is empty - ignore and get next
}
}
if (atMessage)
commitInfo.setMessage(message.trimmed());
for (auto i = fileToActionsMapping.begin(); i != fileToActionsMapping.end(); ++i) {
KDevelop::VcsItemEvent itemEvent;
itemEvent.setRepositoryLocation(i.key());
itemEvent.setActions(i.value());
commitInfo.addItem(itemEvent);
}
return commitInfo;
}
KDevelop::VcsItemEvent::Action BazaarUtils::parseActionDescription(const QString& action)
{
if (action == "added:") {
return KDevelop::VcsItemEvent::Added;
} else if (action == "modified:") {
return KDevelop::VcsItemEvent::Modified;
} else if (action == "removed:") {
return KDevelop::VcsItemEvent::Deleted;
} else if (action == "kind changed:") {
return KDevelop::VcsItemEvent::Replaced; // Best approximation
} else if (action.startsWith("renamed")) {
return KDevelop::VcsItemEvent::Modified; // Best approximation
} else {
qCritical("Unsupported action: %s", action.toLocal8Bit().constData());
return KDevelop::VcsItemEvent::Action();
}
}
KUrl::List BazaarUtils::handleRecursion(const KUrl::List& listOfUrls, KDevelop::IBasicVersionControl::RecursionMode recursion)
{
if (recursion == KDevelop::IBasicVersionControl::Recursive) {
return listOfUrls; // Nothing to do
} else {
KUrl::List result;
for (const auto url : listOfUrls) {
if (url.isLocalFile() && QFileInfo(url.toLocalFile()).isFile()) {
result.push_back(url);
}
}
return result;
}
}