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

377 lines
14 KiB
C++

/***************************************************************************
* This file is part of KDevelop *
* Copyright 2007 Andreas Pakulat <apaku@gmx.de> *
* Copyright 2007 Dukju Ahn <dukjuahn@gmail.com> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Library General Public License as *
* published by the Free Software Foundation; either version 2 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 Library General Public *
* License along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#include "svninternaljobbase.h"
#include <QMutex>
#include <QDateTime>
#include <QCoreApplication>
#include <iostream>
#include <ThreadWeaver.h>
#include <klocale.h>
#include <kdebug.h>
extern "C" {
#include <svn_auth.h>
}
#include <vcs/vcsrevision.h>
#include <svnjobbase.h>
#include "kdevsvncpp/context.hpp"
#include "kdevsvncpp/apr.hpp"
#include "kdevsvncpp/revision.hpp"
SvnInternalJobBase::SvnInternalJobBase( SvnJobBase* parent )
: ThreadWeaver::Job( parent ), m_ctxt( new svn::Context() ),
m_guiSemaphore( 0 ), m_mutex( new QMutex() ), m_killMutex( new QMutex() ),
m_success( true ), sendFirstDelta( false ), killed( false )
{
m_ctxt->setListener(this);
connect( this, SIGNAL(failed(ThreadWeaver::Job*)),
parent, SLOT(internalJobFailed(ThreadWeaver::Job*)), Qt::QueuedConnection );
connect( this, SIGNAL(done(ThreadWeaver::Job*)),
parent, SLOT(internalJobDone(ThreadWeaver::Job*)), Qt::QueuedConnection );
connect( this, SIGNAL(started(ThreadWeaver::Job*)),
parent, SLOT(internalJobStarted(ThreadWeaver::Job*)), Qt::QueuedConnection );
}
SvnInternalJobBase::~SvnInternalJobBase()
{
m_ctxt->setListener(0);
delete m_ctxt;
m_ctxt = 0;
}
bool SvnInternalJobBase::contextGetLogin( const std::string& realm,
std::string& username, std::string& password,
bool& maySave )
{
emit needLogin( QString::fromUtf8( realm.c_str() ) );
m_guiSemaphore.acquire( 1 );
QMutexLocker l(m_mutex);
if( m_login_username.isEmpty() || m_login_password.isEmpty() )
return false;
username = std::string( m_login_username.toUtf8() );
password = std::string( m_login_password.toUtf8() );
maySave = this->m_maySave;
return true;
}
void SvnInternalJobBase::contextNotify( const char* path, svn_wc_notify_action_t action,
svn_node_kind_t kind, const char* mimetype,
svn_wc_notify_state_t contentState,
svn_wc_notify_state_t propState, svn_revnum_t rev )
{
QString notifyString;
switch( action ){
case svn_wc_notify_add:
notifyString = i18nc( "A file was marked to be added to svn", "Added %1", QString::fromUtf8( path ) );
break;
case svn_wc_notify_delete:
notifyString = i18nc( "A file was marked for deletion from svn", "Deleted %1", QString::fromUtf8( path ) );
break;
// various update notifications
case svn_wc_notify_update_delete:
notifyString = i18nc( "A file was deleted during an svn update operation", "Deleted %1", QString::fromUtf8( path ) );
break;
case svn_wc_notify_update_add:
notifyString = i18nc( "A file was added during an svn update operation", "Added %1", QString::fromUtf8( path ) );
break;
case svn_wc_notify_update_update:
/* If this is an inoperative dir change, do no notification.
An inoperative dir change is when a directory gets closed
without any props having been changed. */
if (! ((kind == svn_node_dir)
&& ((propState == svn_wc_notify_state_inapplicable)
|| (propState == svn_wc_notify_state_unknown)
|| (propState == svn_wc_notify_state_unchanged)))) {
if (kind == svn_node_file) {
if (contentState == svn_wc_notify_state_conflicted)
notifyString = "Conflict On File";
else if (contentState == svn_wc_notify_state_merged)
notifyString = "File Merged";
else if (contentState == svn_wc_notify_state_changed)
notifyString = "File Updated";
}
if (propState == svn_wc_notify_state_conflicted)
notifyString += " Conflict On Property";
else if (propState == svn_wc_notify_state_merged)
notifyString += " Properties Merged";
else if (propState == svn_wc_notify_state_changed)
notifyString += " Properties Updated";
else
notifyString += ' ';
if (! ((contentState == svn_wc_notify_state_unchanged
|| contentState == svn_wc_notify_state_unknown)
&& (propState == svn_wc_notify_state_unchanged
|| propState == svn_wc_notify_state_unknown)))
notifyString += QString( " " ) + QString::fromUtf8( path );
}
break;
case svn_wc_notify_update_completed:
// The last notification in an update (including updates of externals).
notifyString = i18n("Revision %1", rev );
break;
case svn_wc_notify_update_external:
notifyString = i18n("Updating externals: %1", QString::fromUtf8( path ) );
break;
case svn_wc_notify_status_completed:
break;
case svn_wc_notify_status_external:
break;
// various commit notifications
case svn_wc_notify_commit_modified:
notifyString = i18n( "Sending %1", QString::fromUtf8( path ) );
break;
case svn_wc_notify_commit_added:
if( mimetype ){
notifyString = i18n( "Adding %1 using mimetype %2.", QString::fromUtf8( path ), mimetype );
} else {
notifyString = i18n( "Adding %1.", QString::fromUtf8( path ) );
}
break;
case svn_wc_notify_commit_deleted:
notifyString = i18n( "Deleting %1.", QString::fromUtf8( path ) );
break;
case svn_wc_notify_commit_replaced:
notifyString = i18n( "Replacing %1.", QString::fromUtf8( path ) );
break;
case svn_wc_notify_commit_postfix_txdelta:
if ( sendFirstDelta ) {
sendFirstDelta = false;
notifyString=i18n("Transmitting file data ");
} else {
notifyString='.';
}
break;
case svn_wc_notify_blame_revision:
notifyString = i18n( "Blame finished for revision %1, path %2", rev, QString::fromUtf8( path ) );
break;
case svn_wc_notify_revert:
notifyString = i18n( "Reverted working copy %1", QString::fromUtf8( path ) );
break;
case svn_wc_notify_failed_revert:
notifyString = i18n( "Reverting failed on working copy %1", QString::fromUtf8( path ) );
break;
case svn_wc_notify_copy:
notifyString = i18n( "Copied %1", QString::fromUtf8( path ) );
break;
default:
break;
}
emit showNotification( QString::fromUtf8( path ), notifyString );
}
bool SvnInternalJobBase::contextCancel()
{
QMutexLocker lock( m_killMutex );
return killed;
}
bool SvnInternalJobBase::contextGetLogMessage( std::string& msg )
{
emit needCommitMessage();
m_guiSemaphore.acquire( 1 );
QMutexLocker l( m_mutex );
QByteArray ba = m_commitMessage.toUtf8();
msg = std::string( ba.data() );
return true;
}
void SvnInternalJobBase::initBeforeRun()
{
connect( this, SIGNAL(needCommitMessage()),
parent(), SLOT(askForCommitMessage()), Qt::QueuedConnection );
connect( this, SIGNAL(needLogin(QString)),
parent(), SLOT(askForLogin(QString)), Qt::QueuedConnection );
connect( this, SIGNAL( needSslServerTrust( const QStringList&,
const QString&, const QString&, const QString&,
const QString&, const QString&, const QString& ) ),
parent(), SLOT( askForSslServerTrust( const QStringList&,
const QString&, const QString&, const QString&,
const QString&, const QString&, const QString& ) ), Qt::QueuedConnection );
connect( this, SIGNAL(showNotification(QString,QString)),
parent(), SLOT(showNotification(QString,QString)), Qt::QueuedConnection );
connect( this, SIGNAL(needSslClientCert(QString)),
parent(), SLOT(askForSslClientCert(QString)), Qt::QueuedConnection );
connect( this, SIGNAL(needSslClientCertPassword(QString)),
parent(), SLOT(askForSslClientCertPassword(QString)), Qt::QueuedConnection );
}
svn::ContextListener::SslServerTrustAnswer SvnInternalJobBase::contextSslServerTrustPrompt(
const svn::ContextListener::SslServerTrustData& data,
apr_uint32_t& acceptedFailures )
{
std::string host = data.hostname;
std::string print = data.fingerprint;
std::string from = data.validFrom;
std::string until = data.validUntil;
std::string issue = data.issuerDName;
std::string realm = data.realm;
acceptedFailures = data.failures;
QStringList failures;
if( data.failures & SVN_AUTH_SSL_NOTYETVALID )
{
failures << i18n("Certificate is not yet valid.");
}
if( data.failures & SVN_AUTH_SSL_EXPIRED )
{
failures << i18n("Certificate has expired.");
}
if( data.failures & SVN_AUTH_SSL_CNMISMATCH )
{
failures << i18n("Certificate's CN (hostname) doesn't match the remote hostname.");
}
if( data.failures & SVN_AUTH_SSL_UNKNOWNCA )
{
failures << i18n("Certificate authority is unknown.");
}
if( data.failures & SVN_AUTH_SSL_NOTYETVALID )
{
failures << i18n("Other unknown error.");
}
emit needSslServerTrust( failures,
QString::fromUtf8( host.c_str() ),
QString::fromUtf8( print.c_str() ),
QString::fromUtf8( from.c_str() ),
QString::fromUtf8( until.c_str() ),
QString::fromUtf8( issue.c_str() ),
QString::fromUtf8( realm.c_str() ) );
m_guiSemaphore.acquire(1);
QMutexLocker l(m_mutex);
return m_trustAnswer;
}
bool SvnInternalJobBase::contextSslClientCertPrompt( std::string& cert )
{
emit needSslClientCert( QString::fromUtf8( cert.c_str() ) );
m_guiSemaphore.acquire( 1 );
return true;
}
bool SvnInternalJobBase::contextSslClientCertPwPrompt( std::string& pw, const std::string& realm,
bool& maySave )
{
Q_UNUSED(pw);
Q_UNUSED(maySave);
emit needSslClientCertPassword( QString::fromUtf8( realm.c_str() ) );
m_guiSemaphore.acquire( 1 );
return false;
}
bool SvnInternalJobBase::success() const
{
return m_success;
}
svn::Revision SvnInternalJobBase::createSvnCppRevisionFromVcsRevision( const KDevelop::VcsRevision& revision )
{
svn::Revision rev;
QVariant value = revision.revisionValue();
switch( revision.revisionType() )
{
case KDevelop::VcsRevision::Special:
{
if( value.canConvert<KDevelop::VcsRevision::RevisionSpecialType>() )
{
KDevelop::VcsRevision::RevisionSpecialType specialtype =
value.value<KDevelop::VcsRevision::RevisionSpecialType>();
switch( specialtype )
{
case KDevelop::VcsRevision::Head:
rev = svn::Revision( svn::Revision::HEAD );
break;
case KDevelop::VcsRevision::Working:
rev = svn::Revision( svn::Revision::WORKING );
break;
case KDevelop::VcsRevision::Base:
rev = svn::Revision( svn::Revision::BASE );
break;
case KDevelop::VcsRevision::Previous:
rev = svn::Revision( svn_opt_revision_previous );
break;
case KDevelop::VcsRevision::Start:
rev = svn::Revision( svn::Revision::START );
break;
default:
break;
}
}
break;
}
case KDevelop::VcsRevision::GlobalNumber:
case KDevelop::VcsRevision::FileNumber:
{
bool ok;
qlonglong number = value.toLongLong(&ok);
if( ok )
{
rev = svn::Revision( number );
}
break;
}
case KDevelop::VcsRevision::Date:
{
QDateTime dt = value.toDateTime();
if( dt.isValid() )
{
rev = svn::Revision( dt.toTime_t() );
}
break;
}
default:
break;
}
return rev;
}
void SvnInternalJobBase::setErrorMessage( const QString& msg )
{
QMutexLocker lock( m_mutex );
m_errorMessage = msg;
}
QString SvnInternalJobBase::errorMessage() const
{
QMutexLocker lock( m_mutex );
return m_errorMessage;
}
void SvnInternalJobBase::kill()
{
QMutexLocker lock( m_killMutex );
killed = true;
}
#include "moc_svninternaljobbase.cpp"