You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
794 lines
23 KiB
794 lines
23 KiB
/* *********************************************************************** * |
|
* XINX * |
|
* Copyright (C) 2009 by Ulrich Van Den Hekke * |
|
* ulrich.vdh@shadoware.org * |
|
* * |
|
* 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 3 of the License, or * |
|
* (at your option) any later version. * |
|
* * |
|
* 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/>. * |
|
* *********************************************************************** */ |
|
|
|
// Xinx header |
|
#include "rcs_svn.h" |
|
#include <core/xinxconfig.h> |
|
#include <plugins/xinxpluginsloader.h> |
|
#include "authentificationformimpl.h" |
|
|
|
// Qt header |
|
#include <QTextStream> |
|
#include <QRegExp> |
|
#include <QDir> |
|
#include <QApplication> |
|
#include <QDesktopServices> |
|
#include <QDebug> |
|
#include <QFileDialog> |
|
#include <QInputDialog> |
|
|
|
// Svn |
|
#include <svncpp/status.hpp> |
|
#include <apr_time.h> |
|
#include <svncpp/targets.hpp> |
|
|
|
/* SubVersionContextListener */ |
|
|
|
SubVersionContextListener::SubVersionContextListener(RCS_SVN * parent) : _cancel(false), _parent(parent) |
|
{ |
|
connect(this, SIGNAL(signal_login()), this, SLOT(slot_login()), Qt::BlockingQueuedConnection); |
|
connect(this, SIGNAL(signal_cert_prompt()), this, SLOT(slot_cert_prompt()), Qt::BlockingQueuedConnection); |
|
connect(this, SIGNAL(signal_cert_password_prompt()), this, SLOT(slot_cert_password_prompt()), Qt::BlockingQueuedConnection); |
|
} |
|
|
|
SubVersionContextListener::~SubVersionContextListener() |
|
{ |
|
|
|
} |
|
|
|
void SubVersionContextListener::slot_login() |
|
{ |
|
AuthentificationFormImpl dlg(qApp->activeWindow()); |
|
dlg.setRealm(_login.realm); |
|
dlg.setUsername(_login.username); |
|
dlg.setPassword(_login.password); |
|
dlg.setIsPasswordSaved(_login.may_be_save); |
|
|
|
if (dlg.exec()) |
|
{ |
|
_login.username = dlg.username(); |
|
_login.password = dlg.password(); |
|
_login.may_be_save = dlg.isPasswordSaved(); |
|
|
|
_login.result = true; |
|
return; |
|
} |
|
|
|
_login.result = false; |
|
} |
|
|
|
bool SubVersionContextListener::contextGetLogin(const std::string& realm, std::string& username, std::string& password, bool& maySave) |
|
{ |
|
_login.realm = QString::fromStdString(realm); |
|
_login.username = QString::fromStdString(username); |
|
_login.password = QString::fromStdString(password); |
|
_login.may_be_save = maySave; |
|
|
|
emit signal_login(); |
|
|
|
username = _login.username.toStdString(); |
|
password = _login.password.toStdString(); |
|
maySave = _login.may_be_save; |
|
|
|
return _login.result; |
|
} |
|
|
|
bool SubVersionContextListener::contextCancel() |
|
{ |
|
// Variable isCancel |
|
return _cancel; |
|
} |
|
|
|
void SubVersionContextListener::contextNotify(const char* path, svn_wc_notify_action_t action, svn_node_kind_t kind, const char* mime_type, svn_wc_notify_state_t content_state, svn_wc_notify_state_t prop_state, svn_revnum_t revision) |
|
{ |
|
RCS::struct_rcs_infos informations; |
|
|
|
RCS::rcsLog niveau = RCS::LogNormal; |
|
QString actionStr; |
|
switch (action) |
|
{ |
|
case svn_wc_notify_add: |
|
informations = _parent->info(QString::fromAscii(path)); |
|
actionStr = tr("Add"); |
|
niveau = RCS::LogLocallyModified; |
|
emit _parent->stateChanged(QString::fromAscii(path), informations); |
|
break; |
|
case svn_wc_notify_copy: |
|
informations = _parent->info(QString::fromAscii(path)); |
|
actionStr = tr("Copy"); |
|
niveau = RCS::LogLocallyModified; |
|
emit _parent->stateChanged(QString::fromAscii(path), informations); |
|
break; |
|
case svn_wc_notify_delete: |
|
informations = _parent->info(QString::fromAscii(path)); |
|
actionStr = tr("Delete"); |
|
niveau = RCS::LogLocallyModified; |
|
emit _parent->stateChanged(QString::fromAscii(path), informations); |
|
break; |
|
case svn_wc_notify_restore: |
|
informations = _parent->info(QString::fromAscii(path)); |
|
actionStr = tr("Restore"); |
|
niveau = RCS::LogLocallyModified; |
|
emit _parent->stateChanged(QString::fromAscii(path), informations); |
|
break; |
|
case svn_wc_notify_revert: |
|
informations = _parent->info(QString::fromAscii(path)); |
|
actionStr = tr("Revert"); |
|
niveau = RCS::LogLocallyModified; |
|
emit _parent->stateChanged(QString::fromAscii(path), informations); |
|
break; |
|
case svn_wc_notify_failed_revert: |
|
actionStr = tr("Failed revert"); |
|
niveau = RCS::LogError; |
|
break; |
|
case svn_wc_notify_resolved: |
|
actionStr = tr("Resolved"); |
|
break; |
|
case svn_wc_notify_skip: |
|
actionStr = tr("Skip"); |
|
niveau = RCS::LogError; |
|
break; |
|
case svn_wc_notify_update_delete: |
|
informations = _parent->info(QString::fromAscii(path)); |
|
actionStr = tr("Update delete"); |
|
niveau = RCS::LogRemotlyModified; |
|
emit _parent->stateChanged(QString::fromAscii(path), informations); |
|
return; |
|
break; |
|
case svn_wc_notify_update_add: |
|
informations = _parent->info(QString::fromAscii(path)); |
|
actionStr = tr("Update add"); |
|
niveau = RCS::LogRemotlyModified; |
|
emit _parent->stateChanged(QString::fromAscii(path), informations); |
|
return; |
|
break; |
|
case svn_wc_notify_update_update: |
|
informations = _parent->info(QString::fromAscii(path)); |
|
actionStr = tr("Update update"); |
|
niveau = RCS::LogRemotlyModified; |
|
emit _parent->stateChanged(QString::fromAscii(path), informations); |
|
return; |
|
break; |
|
informations = _parent->info(QString::fromAscii(path)); |
|
case svn_wc_notify_update_completed: |
|
actionStr = tr("Update completed"); |
|
niveau = RCS::LogRemotlyModified; |
|
emit _parent->stateChanged(QString::fromAscii(path), informations); |
|
return; |
|
break; |
|
case svn_wc_notify_update_external: |
|
actionStr = tr("Update external"); |
|
niveau = RCS::LogRemotlyModified; |
|
return; |
|
break; |
|
case svn_wc_notify_status_completed: |
|
actionStr = tr("Status completed"); |
|
return; |
|
break; |
|
case svn_wc_notify_status_external: |
|
actionStr = tr("Status external"); |
|
break; |
|
case svn_wc_notify_commit_modified: |
|
informations = _parent->info(QString::fromAscii(path)); |
|
actionStr = tr("Commit modified"); |
|
niveau = RCS::LogLocallyModified; |
|
emit _parent->stateChanged(QString::fromAscii(path), informations); |
|
break; |
|
case svn_wc_notify_commit_added: |
|
informations = _parent->info(QString::fromAscii(path)); |
|
actionStr = tr("Commit added"); |
|
niveau = RCS::LogLocallyModified; |
|
emit _parent->stateChanged(QString::fromAscii(path), informations); |
|
break; |
|
case svn_wc_notify_commit_deleted: |
|
informations = _parent->info(QString::fromAscii(path)); |
|
actionStr = tr("Commit deleted"); |
|
niveau = RCS::LogLocallyModified; |
|
emit _parent->stateChanged(QString::fromAscii(path), informations); |
|
break; |
|
case svn_wc_notify_commit_replaced: |
|
informations = _parent->info(QString::fromAscii(path)); |
|
actionStr = tr("Commit replaced"); |
|
niveau = RCS::LogLocallyModified; |
|
emit _parent->stateChanged(QString::fromAscii(path), informations); |
|
break; |
|
case svn_wc_notify_commit_postfix_txdelta: |
|
informations = _parent->info(QString::fromAscii(path)); |
|
actionStr = tr("Commit postfix txdelta"); |
|
niveau = RCS::LogLocallyModified; |
|
emit _parent->stateChanged(QString::fromAscii(path), informations); |
|
return; |
|
break; |
|
case svn_wc_notify_blame_revision: |
|
actionStr = tr("Blame revision"); |
|
break; |
|
case svn_wc_notify_locked: |
|
actionStr = tr("Locked"); |
|
break; |
|
case svn_wc_notify_unlocked: |
|
actionStr = tr("Unlocked"); |
|
break; |
|
case svn_wc_notify_failed_lock: |
|
actionStr = tr("Failed lock"); |
|
niveau = RCS::LogError; |
|
break; |
|
case svn_wc_notify_failed_unlock: |
|
actionStr = tr("Failed unlock"); |
|
niveau = RCS::LogError; |
|
break; |
|
case svn_wc_notify_exists: |
|
actionStr = tr("Exists"); |
|
break; |
|
case svn_wc_notify_changelist_set: |
|
actionStr = tr("Changelist set"); |
|
break; |
|
case svn_wc_notify_changelist_clear: |
|
actionStr = tr("Changelist clear"); |
|
break; |
|
case svn_wc_notify_changelist_moved: |
|
actionStr = tr("Changelist moved"); |
|
break; |
|
case svn_wc_notify_merge_begin: |
|
actionStr = tr("Merge begin"); |
|
break; |
|
case svn_wc_notify_foreign_merge_begin: |
|
actionStr = tr("Foreign merge begin"); |
|
break; |
|
case svn_wc_notify_update_replace: |
|
actionStr = tr("Update replace"); |
|
break; |
|
case svn_wc_notify_property_added: |
|
actionStr = tr("Property added"); |
|
break; |
|
case svn_wc_notify_property_modified: |
|
actionStr = tr("Property modified"); |
|
break; |
|
case svn_wc_notify_property_deleted: |
|
actionStr = tr("Property deleted"); |
|
break; |
|
case svn_wc_notify_property_deleted_nonexistent: |
|
actionStr = tr("Property deleted nonexistent"); |
|
break; |
|
case svn_wc_notify_revprop_set: |
|
actionStr = tr("Revision property set"); |
|
break; |
|
case svn_wc_notify_revprop_deleted: |
|
actionStr = tr("Revision property deleted"); |
|
break; |
|
case svn_wc_notify_merge_completed: |
|
actionStr = tr("Merge completed"); |
|
break; |
|
case svn_wc_notify_tree_conflict: |
|
actionStr = tr("Tree conflict"); |
|
niveau = RCS::LogConflict; |
|
break; |
|
case svn_wc_notify_failed_external: |
|
actionStr = tr("Failed external"); |
|
niveau = RCS::LogError; |
|
break; |
|
}; |
|
|
|
const QString info = actionStr + " " + QString::fromAscii(path) + (revision >= 0 ? " (rev " + QString::number(revision) + ")" : QString()); |
|
|
|
// Affichage de la nofication |
|
emit _parent->alert(niveau, info); |
|
} |
|
|
|
bool SubVersionContextListener::contextGetLogMessage(std::string& msg) |
|
{ |
|
// Retourne le message utilisé pour le commit |
|
qDebug() << "contextGetLogMessage(" << QString::fromStdString(msg) << ")"; |
|
return true; |
|
} |
|
|
|
void SubVersionContextListener::slot_cert_prompt() |
|
{ |
|
_certificate_prompt.file_name = QFileDialog::getOpenFileName(qApp->activeWindow(), RCS_SVN::tr("Select a certificate file"), RCS_SVN::tr("Please select a certificate file."), RCS_SVN::tr("All files (*.*)")); |
|
_certificate_prompt.result = ! _certificate_prompt.file_name.isEmpty(); |
|
} |
|
|
|
bool SubVersionContextListener::contextSslClientCertPrompt(std::string& certFile) |
|
{ |
|
_certificate_prompt.file_name = QString::fromStdString(certFile); |
|
|
|
emit signal_cert_prompt(); |
|
|
|
certFile = _certificate_prompt.file_name.toStdString(); |
|
return _certificate_prompt.result; |
|
} |
|
|
|
void SubVersionContextListener::slot_cert_password_prompt() |
|
{ |
|
_certificate_password_prompt.password = QInputDialog::getText( |
|
qApp->activeWindow(), |
|
RCS_SVN::tr("Paswword for the certificate file"), |
|
RCS_SVN::tr("Please give the password for the certificate of %1").arg(_certificate_password_prompt.realm), |
|
QLineEdit::Password, _certificate_password_prompt.password); |
|
_certificate_password_prompt.result = !_certificate_password_prompt.password.isEmpty(); |
|
} |
|
|
|
bool SubVersionContextListener::contextSslClientCertPwPrompt(std::string& password, const std::string& realm, bool& maySave) |
|
{ |
|
_certificate_password_prompt.realm = QString::fromStdString(realm); |
|
_certificate_password_prompt.password = QString::fromStdString(password); |
|
_certificate_password_prompt.may_be_save = maySave; |
|
|
|
emit signal_cert_password_prompt(); |
|
|
|
password = _certificate_password_prompt.password.toStdString(); |
|
maySave = _certificate_password_prompt.may_be_save; |
|
|
|
return _certificate_password_prompt.result; |
|
} |
|
|
|
svn::ContextListener::SslServerTrustAnswer SubVersionContextListener::contextSslServerTrustPrompt(const svn::ContextListener::SslServerTrustData& data, apr_uint32_t& acceptedFailures) |
|
{ |
|
qDebug() << "contextSslServerTrustPrompt" << QString::fromStdString(data.realm); |
|
// Ouvre une boite de dialogue avec data |
|
// Expliquer en quoi le certificat n'est pas sur :There were errors validating the server certificate.\nDo you want to trust this certificate? |
|
//static const FailureEntry CERT_FAILURES [] = |
|
// {SVN_AUTH_SSL_UNKNOWNCA , _("- The certificate is not issued by a trusted authority.\n Use the fingerprint to validate the certificate manually!")}, |
|
// {SVN_AUTH_SSL_CNMISMATCH , _("- The certificate hostname does not match.")}, |
|
// {SVN_AUTH_SSL_NOTYETVALID , _("- The certificate is not yet valid.")}, |
|
// {SVN_AUTH_SSL_EXPIRED , _("- The certificate has expired.")}, |
|
// {SVN_AUTH_SSL_OTHER , _("- The certificate has an unknown error.")} |
|
/* |
|
const int count = sizeof(CERT_FAILURES)/sizeof(CERT_FAILURES[0]); |
|
for (int i=0; i < count; i++) |
|
{ |
|
if ((CERT_FAILURES[i].failure & trustData.failures) != 0) |
|
{ |
|
failureStr += CERT_FAILURES[i].descr; |
|
failureStr += wxT("\n"); |
|
} |
|
} |
|
*/ |
|
|
|
/* |
|
Affichage de : |
|
- Hostname.... |
|
|
|
*/ |
|
return svn::ContextListener::ACCEPT_PERMANENTLY; |
|
} |
|
|
|
/* RCS_SVN */ |
|
|
|
RCS_SVN::RCS_SVN(const QString & basePath) : RCS(basePath) |
|
{ |
|
// const QString configDirectory = QDesktopServices::storageLocation(QDesktopServices::DataLocation); |
|
// const QString homeDirectory = QDir::home().absoluteFilePath(configDirectory); |
|
|
|
// m_context = new svn::Context(QDir(homeDirectory).absoluteFilePath("SubVersion").toStdString ()); |
|
m_context = new svn::Context(); |
|
m_context->setListener(_listener = new SubVersionContextListener(this)); |
|
m_client = new svn::Client(m_context); |
|
} |
|
|
|
RCS_SVN::~RCS_SVN() |
|
{ |
|
delete m_client; |
|
delete m_context; |
|
} |
|
|
|
RCS::rcsFeatures RCS_SVN::features() const |
|
{ |
|
return RCS::RcsFeatureAdd | RCS::RcsFeatureRemove | RCS::RcsFeatureUpdateAndCommit /*| RCS::RcsFeatureBlame*/ | RCS::RcsFeatureRevert | RCS::RcsFeatureLog; |
|
} |
|
|
|
RCS::rcsState RCS_SVN::svnStateToRcsState(svn_wc_status_kind textState, svn_wc_status_kind reposTextStatus) |
|
{ |
|
switch (textState) |
|
{ |
|
case svn_wc_status_none: |
|
case svn_wc_status_unversioned: |
|
case svn_wc_status_obstructed: |
|
return RCS::Unknown; |
|
case svn_wc_status_normal: |
|
if (reposTextStatus == svn_wc_status_modified) |
|
{ |
|
return RCS::NeedsCheckout; |
|
} |
|
else |
|
{ |
|
return RCS::Updated; |
|
} |
|
case svn_wc_status_added: |
|
return RCS::LocallyAdded; |
|
case svn_wc_status_missing: |
|
return RCS::NeedsCheckout; |
|
case svn_wc_status_deleted: |
|
return RCS::LocallyRemoved; |
|
case svn_wc_status_replaced: |
|
case svn_wc_status_modified: |
|
case svn_wc_status_merged: |
|
return RCS::LocallyModified; |
|
case svn_wc_status_conflicted: |
|
return RCS::FileHadConflictsOnMerge; |
|
case svn_wc_status_ignored: |
|
return RCS::UnresolvedConflict; |
|
case svn_wc_status_external: |
|
return RCS::Updated; |
|
case svn_wc_status_incomplete: |
|
return RCS::NeedsCheckout; |
|
default: |
|
return RCS::Unknown; |
|
} |
|
} |
|
|
|
RCS::struct_rcs_infos RCS_SVN::svnInfoToRcsInfos(svn::Status infos) |
|
{ |
|
RCS::struct_rcs_infos rcsInfos = { QDir::fromNativeSeparators(infos.path()), RCS::NotManaged, "0", QDateTime() }; |
|
if (infos.isVersioned()) |
|
{ |
|
rcsInfos.version = QString("%1").arg(infos.entry().revision()); |
|
|
|
uint cmtDate = (quint64)infos.entry().cmtDate() / 1000000; |
|
rcsInfos.rcsDate = QDateTime::fromTime_t(cmtDate); |
|
} |
|
|
|
rcsInfos.state = svnStateToRcsState(infos.textStatus(), infos.reposTextStatus()); |
|
|
|
return rcsInfos; |
|
} |
|
|
|
RCS::struct_rcs_infos RCS_SVN::info(const QString & path) |
|
{ |
|
_listener->_cancel = false; |
|
|
|
RCS::struct_rcs_infos result = { QDir::fromNativeSeparators(path), RCS::NotManaged, "0", QDateTime() }; |
|
svn::StatusEntries entries; |
|
try |
|
{ |
|
try |
|
{ |
|
entries = m_client->status(qPrintable(path), /* descend */ false, /* get_all */ true, /* update */ true, /* no_ignore */ false, /* ignore_externals */ false); |
|
} |
|
catch (svn::ClientException e) |
|
{ |
|
emit alert(RCS::LogError, e.message()); |
|
entries = m_client->status(qPrintable(path), /* descend */ false, /* get_all */ true, /* update */ false, /* no_ignore */ false, /* ignore_externals */ false); |
|
} |
|
|
|
if (! entries.size()) |
|
{ |
|
result = svnInfoToRcsInfos(entries.at(0)); |
|
} |
|
} |
|
catch (svn::ClientException e) |
|
{ |
|
emit alert(RCS::LogError, e.message()); |
|
} |
|
|
|
return result; |
|
} |
|
|
|
QList<RCS::struct_rcs_infos> RCS_SVN::infos(const QString & path) |
|
{ |
|
_listener->_cancel = false; |
|
|
|
QList<RCS::struct_rcs_infos> result; |
|
svn::StatusEntries entries; |
|
try |
|
{ |
|
try |
|
{ |
|
entries = m_client->status(qPrintable(path), /* descend */ false, /* get_all */ true, /* update */ true, /* no_ignore */ false, /* ignore_externals */ false); |
|
} |
|
catch (svn::ClientException e) |
|
{ |
|
emit alert(RCS::LogError, e.message()); |
|
entries = m_client->status(qPrintable(path), /* descend */ false, /* get_all */ true, /* update */ false, /* no_ignore */ false, /* ignore_externals */ false); |
|
} |
|
|
|
for (size_t i = 0; i < entries.size(); i++) |
|
{ |
|
result << svnInfoToRcsInfos(entries.at(i)); |
|
} |
|
} |
|
catch (svn::ClientException e) |
|
{ |
|
emit alert(RCS::LogError, e.message()); |
|
} |
|
|
|
return result; |
|
} |
|
|
|
RCS::FilesOperation RCS_SVN::operations(const QStringList & paths) |
|
{ |
|
_listener->_cancel = false; |
|
|
|
RCS::FilesOperation operations; |
|
foreach(const QString & path, paths) |
|
{ |
|
svn::StatusEntries entries; |
|
try |
|
{ |
|
entries = m_client->status(qPrintable(path), /* descend */ true, /* get_all */ false, /* update */ false, /* no_ignore */ false, /* ignore_externals */ false); |
|
|
|
for (size_t i = 0; i < entries.size(); i++) |
|
{ |
|
svn::Status status = entries.at(i); |
|
|
|
RCS::FileOperation operation(QDir::fromNativeSeparators(status.path()), RCS::Nothing); |
|
|
|
switch (status.textStatus()) |
|
{ |
|
case svn_wc_status_unversioned: |
|
operation.operation = RCS::AddAndCommit; |
|
break; |
|
case svn_wc_status_added: |
|
case svn_wc_status_deleted: |
|
case svn_wc_status_replaced: |
|
case svn_wc_status_modified: |
|
case svn_wc_status_merged: |
|
operation.operation = RCS::Commit; |
|
break; |
|
case svn_wc_status_missing: |
|
operation.operation = RCS::RemoveAndCommit; |
|
break; |
|
default: |
|
break; |
|
} |
|
|
|
if ((QFileInfo(operation.filename).isFile() && paths.contains(operation.filename)) || (operation.operation != RCS::Nothing)) |
|
{ |
|
operations << operation; |
|
} |
|
} |
|
} |
|
catch (svn::ClientException e) |
|
{ |
|
emit alert(RCS::LogError, e.message()); |
|
} |
|
} |
|
|
|
return operations; |
|
} |
|
|
|
void RCS_SVN::update(const QStringList & paths) |
|
{ |
|
_listener->_cancel = false; |
|
|
|
/* Create the target list */ |
|
svn::Targets targets; |
|
foreach(const QString & path, paths) |
|
{ |
|
svn::Path svnPath(path.toStdString()); |
|
targets.push_back(svnPath); |
|
} |
|
|
|
/* Update */ |
|
try |
|
{ |
|
std::vector<svn_revnum_t> revisions = m_client->update(targets, svn::Revision::HEAD, true, false); |
|
emit alert(RCS::LogApplication, tr("Files updated.")); |
|
} |
|
catch (svn::ClientException e) |
|
{ |
|
emit alert(RCS::LogError, e.message()); |
|
} |
|
} |
|
|
|
void RCS_SVN::commit(const QStringList & paths, const QString & message) |
|
{ |
|
_listener->_cancel = false; |
|
|
|
_listener->_message = message; |
|
/* Create the target list */ |
|
svn::Targets targets; |
|
foreach(const QString & path, paths) |
|
{ |
|
svn::Path svnPath(path.toStdString()); |
|
targets.push_back(svnPath); |
|
} |
|
|
|
/* Commit */ |
|
try |
|
{ |
|
svn_revnum_t revision = m_client->commit(targets, message.toUtf8().data(), false, false); |
|
emit alert(RCS::LogApplication, tr("Files commited at revision %2.").arg(revision)); |
|
} |
|
catch (svn::ClientException e) |
|
{ |
|
emit alert(RCS::LogError, e.message()); |
|
} |
|
} |
|
|
|
void RCS_SVN::add(const QStringList & paths) |
|
{ |
|
_listener->_cancel = false; |
|
|
|
foreach(const QString & path, paths) |
|
{ |
|
try |
|
{ |
|
svn::Path svnPath(path.toStdString()); |
|
m_client->add(svnPath, false); |
|
} |
|
catch (svn::ClientException e) |
|
{ |
|
emit alert(RCS::LogError, e.message()); |
|
} |
|
} |
|
} |
|
|
|
void RCS_SVN::remove(const QStringList & paths) |
|
{ |
|
_listener->_cancel = false; |
|
|
|
foreach(const QString & path, paths) |
|
{ |
|
try |
|
{ |
|
svn::Path svnPath(path.toStdString()); |
|
m_client->remove(svnPath, false); |
|
} |
|
catch (svn::ClientException e) |
|
{ |
|
emit alert(RCS::LogError, e.message()); |
|
} |
|
} |
|
} |
|
|
|
void RCS_SVN::revert(const QStringList & paths) |
|
{ |
|
_listener->_cancel = false; |
|
|
|
svn::Targets targets; |
|
foreach(const QString & path, paths) |
|
{ |
|
svn::Path svnPath(path.toStdString()); |
|
targets.push_back(svnPath); |
|
} |
|
|
|
try |
|
{ |
|
m_client->revert(targets, false); |
|
} |
|
catch (svn::ClientException e) |
|
{ |
|
emit alert(RCS::LogError, e.message()); |
|
} |
|
} |
|
|
|
svn::Revision RCS_SVN::stringToRevision(const QString& rev) |
|
{ |
|
bool intConvert; |
|
svn_revnum_t revnumber = svn_revnum_t(rev.toInt(&intConvert)); |
|
if (intConvert) return svn::Revision(revnumber); |
|
|
|
QDateTime dateTime = QDateTime::fromString(rev, Qt::DefaultLocaleShortDate); |
|
if (dateTime.isValid()) |
|
{ |
|
return svn::Revision(apr_time_t(dateTime.toTime_t() * 1000000)); |
|
} |
|
|
|
return svn::Revision::UNSPECIFIED; |
|
} |
|
|
|
LogEntries RCS_SVN::log(const QString& path, const QString& revisionStart, const QString& revisionEnd) |
|
{ |
|
_listener->_cancel = false; |
|
|
|
LogEntries result; |
|
try |
|
{ |
|
svn::Revision svnRevisionStart = svn::Revision::START; |
|
svn::Revision svnRevisionEnd = svn::Revision::HEAD; |
|
|
|
if (! revisionStart.isEmpty()) |
|
{ |
|
svnRevisionStart = stringToRevision(revisionStart); |
|
} |
|
if (! revisionEnd.isEmpty()) |
|
{ |
|
svnRevisionEnd = stringToRevision(revisionEnd); |
|
} |
|
|
|
const svn::LogEntries* logs = m_client->log(qPrintable(path), svnRevisionStart, svnRevisionEnd, false); |
|
|
|
svn::LogEntries::const_iterator it = logs->begin(); |
|
while (it != logs->end()) |
|
{ |
|
LogEntry logEntry; |
|
svn::LogEntry logLine = *it; |
|
|
|
logEntry.dateTime = QDateTime::fromTime_t (quint64(logLine.date / 1000000)); |
|
logEntry.author = QString::fromStdString(logLine.author); |
|
logEntry.message = QString::fromStdString(logLine.message); |
|
logEntry.revision = QString::number(logLine.revision); |
|
|
|
/* |
|
std::list< svn::LogChangePathEntry >::iterator pathIt = logLine.changedPaths.begin(); |
|
while (pathIt != logLine.changedPaths.end()) |
|
{ |
|
LogPath logPath; |
|
svn::LogChangePathEntry logPathLine = *pathIt; |
|
logPath.path = QString::fromStdString(logPathLine.path); |
|
logPath.informations.append(QString("%1 (rev %2)").arg(QString::fromStdString(logPathLine.copyFromPath)).arg(QString::number(logPathLine.copyFromRevision))); |
|
|
|
logEntry.changedPath.append(logPath); |
|
} |
|
*/ |
|
|
|
result.append(logEntry); |
|
it++; |
|
} |
|
|
|
delete logs; |
|
} |
|
catch (svn::ClientException e) |
|
{ |
|
emit alert(RCS::LogError, e.message()); |
|
} |
|
|
|
return result; |
|
} |
|
|
|
void RCS_SVN::blame(const QString & path) |
|
{ |
|
_listener->_cancel = false; |
|
|
|
try |
|
{ |
|
svn::Path svnPath(path.toStdString()); |
|
svn::AnnotatedFile* annotatedFile = m_client->annotate(svnPath, svn::Revision::START, svn::Revision::HEAD); |
|
|
|
svn::AnnotatedFile::iterator it = annotatedFile->begin(); |
|
while (it != annotatedFile->end()) |
|
{ |
|
svn::AnnotateLine line = *it; |
|
emit alert(RCS::LogNormal, QString("%1 - %2").arg(line.lineNumber()).arg(QString::fromStdString(line.line()))); |
|
it++; |
|
} |
|
|
|
delete annotatedFile; |
|
} |
|
catch (svn::ClientException e) |
|
{ |
|
emit alert(RCS::LogError, e.message()); |
|
} |
|
} |
|
|
|
|
|
void RCS_SVN::updateToRevision(const QString & path, const QString & revision, QByteArray * content) |
|
{ |
|
_listener->_cancel = false; |
|
|
|
/* Create the target list */ |
|
svn::Path svnPath(path.toStdString()); |
|
|
|
/* Update */ |
|
try |
|
{ |
|
content->clear(); |
|
content->append(QString::fromStdString(m_client->cat(svnPath, svn::Revision(revision.toLong())))); |
|
emit alert(RCS::LogApplication, tr("Update %1 to revision %2.").arg(path).arg(revision)); |
|
} |
|
catch (svn::ClientException e) |
|
{ |
|
emit alert(RCS::LogError, e.message()); |
|
} |
|
} |
|
|
|
void RCS_SVN::abort() |
|
{ |
|
_listener->_cancel = true; |
|
}
|
|
|