diff --git a/plugins/subversion/kdevsvncpp/context.cpp b/plugins/subversion/kdevsvncpp/context.cpp
index a90cdd7eb3..703ce81e7d 100644
--- a/plugins/subversion/kdevsvncpp/context.cpp
+++ b/plugins/subversion/kdevsvncpp/context.cpp
@@ -1,714 +1,722 @@
/*
* ====================================================================
* Copyright (c) 2002-2009 The RapidSvn Group. All rights reserved.
*
* 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 (in the file GPL.txt.
* If not, see .
*
* This software consists of voluntary contributions made by many
* individuals. For exact contribution history, see the revision
* history and logs, available at http://rapidsvn.tigris.org/.
* ====================================================================
*/
/**
* @todo implement 1.3 SVN api:
*
* SVN_CLIENT_COMMIT_ITEM_LOCK_TOKEN
* svn_client_add3
* svn_client_copy2
* svn_client_commit3
* svn_client_delete2
* svn_client_move3
* svn_client_mkdir2
* svn_client_import2
* svn_client_info
*/
// Apache Portable Runtime
#include "apr_xlate.h"
// Subversion api
#include "svn_auth.h"
#include "svn_config.h"
#include "svn_subst.h"
//#include "svn_utf.h"
// svncpp
#include "kdevsvncpp/apr.hpp"
#include "kdevsvncpp/context.hpp"
#include "kdevsvncpp/context_listener.hpp"
namespace svn
{
struct Context::Data
{
public:
/** The usage of Apr makes sure Apr is initialized
* before any use of apr functions.
*/
Apr apr;
ContextListener * listener;
bool logIsSet;
int promptCounter;
Pool pool;
svn_client_ctx_t * ctx;
std::string username;
std::string password;
std::string logMessage;
std::string configDir;
/**
* translate native c-string to utf8
*/
static svn_error_t *
translateString(const char * str, const char ** newStr,
apr_pool_t * /*pool*/)
{
// due to problems with apr_xlate we dont perform
// any conversion at this place. YOU will have to make
// sure any strings passed are UTF 8 strings
// svn_string_t *string = svn_string_create ("", pool);
//
// string->data = str;
// string->len = strlen (str);
//
// const char * encoding = APR_LOCALE_CHARSET;
//
// SVN_ERR (svn_subst_translate_string (&string, string,
// encoding, pool));
//
// *newStr = string->data;
*newStr = str;
return SVN_NO_ERROR;
}
/**
* the @a baton is interpreted as Data *
* Several checks are performed on the baton:
* - baton == 0?
* - baton->Data
* - listener set?
*
* @param baton
* @param data returned data if everything is OK
* @retval SVN_NO_ERROR if everything is fine
* @retval SVN_ERR_CANCELLED on invalid values
*/
static svn_error_t *
getData(void * baton, Data ** data)
{
if (baton == NULL)
return svn_error_create(SVN_ERR_CANCELLED, NULL,
"invalid baton");
Data * data_ = static_cast (baton);
if (data_->listener == 0)
return svn_error_create(SVN_ERR_CANCELLED, NULL,
"invalid listener");
*data = data_;
return SVN_NO_ERROR;
}
Data(const std::string & configDir_)
: listener(0), logIsSet(false),
promptCounter(0), configDir(configDir_)
{
const char * c_configDir = 0;
if (configDir.length() > 0)
c_configDir = configDir.c_str();
// make sure the configuration directory exists
svn_config_ensure(c_configDir, pool);
// initialize authentication providers
// * simple
// * username
// * simple prompt
// * ssl server trust file
// * ssl server trust prompt
// * ssl client cert pw file
// * ssl client cert pw prompt
// * ssl client cert file
// ===================
// 8 providers
apr_array_header_t *providers =
apr_array_make(pool, 8,
sizeof(svn_auth_provider_object_t *));
svn_auth_provider_object_t *provider;
svn_client_get_simple_provider(
&provider,
pool);
*(svn_auth_provider_object_t **)apr_array_push(providers) =
provider;
svn_client_get_username_provider(
&provider,
pool);
*(svn_auth_provider_object_t **)apr_array_push(providers) =
provider;
svn_client_get_simple_prompt_provider(
&provider,
onSimplePrompt,
this,
100000000, // not very nice. should be infinite...
pool);
*(svn_auth_provider_object_t **)apr_array_push(providers) =
provider;
// add ssl providers
// file first then prompt providers
svn_client_get_ssl_server_trust_file_provider(&provider, pool);
*(svn_auth_provider_object_t **)apr_array_push(providers) =
provider;
svn_client_get_ssl_client_cert_file_provider(&provider, pool);
*(svn_auth_provider_object_t **)apr_array_push(providers) =
provider;
svn_client_get_ssl_client_cert_pw_file_provider(&provider, pool);
*(svn_auth_provider_object_t **)apr_array_push(providers) =
provider;
svn_client_get_ssl_server_trust_prompt_provider(
&provider, onSslServerTrustPrompt, this, pool);
*(svn_auth_provider_object_t **)apr_array_push(providers) =
provider;
// plugged in 3 as the retry limit - what is a good limit?
svn_client_get_ssl_client_cert_pw_prompt_provider(
&provider, onSslClientCertPwPrompt, this, 3, pool);
*(svn_auth_provider_object_t **)apr_array_push(providers) =
provider;
svn_auth_baton_t *ab;
svn_auth_open(&ab, providers, pool);
// initialize ctx structure
svn_client_create_context(&ctx, pool);
// get the config based on the configDir passed in
svn_config_get_config(&ctx->config, c_configDir, pool);
+ // disable external diff and diff3 commands
+ svn_config_t *config = (svn_config_t *)apr_hash_get(
+ ctx->config, SVN_CONFIG_CATEGORY_CONFIG, APR_HASH_KEY_STRING);
+ svn_config_set(config, SVN_CONFIG_SECTION_HELPERS,
+ SVN_CONFIG_OPTION_DIFF_CMD, NULL);
+ svn_config_set(config, SVN_CONFIG_SECTION_HELPERS,
+ SVN_CONFIG_OPTION_DIFF3_CMD, NULL);
+
// tell the auth functions where the config is
svn_auth_set_parameter(ab, SVN_AUTH_PARAM_CONFIG_DIR,
c_configDir);
ctx->auth_baton = ab;
ctx->log_msg_func = onLogMsg;
ctx->log_msg_baton = this;
ctx->notify_func = onNotify;
ctx->notify_baton = this;
ctx->cancel_func = onCancel;
ctx->cancel_baton = this;
#if (SVN_VER_MAJOR >= 1) && (SVN_VER_MINOR >= 2)
ctx->notify_func2 = onNotify2;
ctx->notify_baton2 = this;
#endif
}
void setAuthCache(bool value)
{
void *param = 0;
if (!value)
param = (void *)"1";
svn_auth_set_parameter(ctx->auth_baton,
SVN_AUTH_PARAM_NO_AUTH_CACHE,
param);
}
/** @see Context::setLogin */
void setLogin(const char * usr, const char * pwd)
{
username = usr;
password = pwd;
svn_auth_baton_t * ab = ctx->auth_baton;
svn_auth_set_parameter(ab, SVN_AUTH_PARAM_DEFAULT_USERNAME,
username.c_str());
svn_auth_set_parameter(ab, SVN_AUTH_PARAM_DEFAULT_PASSWORD,
password.c_str());
}
/** @see Context::setLogMessage */
void setLogMessage(const char * msg)
{
logMessage = msg;
logIsSet = true;
}
/**
* this function gets called by the subversion api function
* when a log message is needed. This is the case on a commit
* for example
*/
static svn_error_t *
onLogMsg(const char **log_msg,
const char **tmp_file,
apr_array_header_t *, //UNUSED commit_items
void *baton,
apr_pool_t * pool)
{
Data * data = NULL;
SVN_ERR(getData(baton, &data));
std::string msg;
if (data->logIsSet)
msg = data->getLogMessage();
else
{
if (!data->retrieveLogMessage(msg))
return svn_error_create(SVN_ERR_CANCELLED, NULL, "");
}
*log_msg = apr_pstrdup(pool, msg.c_str());
*tmp_file = NULL;
return SVN_NO_ERROR;
}
/**
* this is the callback function for the subversion
* api functions to signal the progress of an action
*/
static void
onNotify(void * baton,
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)
{
if (baton == 0)
return;
Data * data = static_cast (baton);
data->notify(path, action, kind, mime_type, content_state,
prop_state, revision);
}
#if (SVN_VER_MAJOR >= 1) && (SVN_VER_MINOR >= 2)
/**
* this is the callback function for the subversion 1.2
* api functions to signal the progress of an action
*
* @todo right now we forward only to @a onNotify,
* but maybe we should a notify2 to the listener
* @since subversion 1.2
*/
static void
onNotify2(void*baton,const svn_wc_notify_t *action,apr_pool_t *)
{
if (!baton)
return;
// for now forward the call to @a onNotify
onNotify(baton, action->path, action->action,
action->kind, action->mime_type,
action->content_state, action->prop_state,
action->revision);
}
#endif
/**
* this is the callback function for the subversion
* api functions to signal the progress of an action
*/
static svn_error_t *
onCancel(void * baton)
{
if (baton == 0)
return SVN_NO_ERROR;
Data * data = static_cast (baton);
if (data->cancel())
return svn_error_create(SVN_ERR_CANCELLED, NULL, "cancelled by user");
else
return SVN_NO_ERROR;
}
/**
* @see svn_auth_simple_prompt_func_t
*/
static svn_error_t *
onSimplePrompt(svn_auth_cred_simple_t **cred,
void *baton,
const char *realm,
const char *username,
svn_boolean_t _may_save,
apr_pool_t *pool)
{
Data * data = NULL;
SVN_ERR(getData(baton, &data));
bool may_save = _may_save != 0;
if (!data->retrieveLogin(username, realm, may_save))
return svn_error_create(SVN_ERR_CANCELLED, NULL, "");
svn_auth_cred_simple_t* lcred = (svn_auth_cred_simple_t*)
apr_palloc(pool, sizeof(svn_auth_cred_simple_t));
/* SVN_ERR (svn_utf_cstring_to_utf8 (
&lcred->password,
data->getPassword (), pool));
SVN_ERR (svn_utf_cstring_to_utf8 (
&lcred->username,
data->getUsername (), pool)); */
lcred->password = data->getPassword();
lcred->username = data->getUsername();
// tell svn if the credentials need to be saved
lcred->may_save = may_save;
*cred = lcred;
return SVN_NO_ERROR;
}
/**
* @see svn_auth_ssl_server_trust_prompt_func_t
*/
static svn_error_t *
onSslServerTrustPrompt(svn_auth_cred_ssl_server_trust_t **cred,
void *baton,
const char *realm,
apr_uint32_t failures,
const svn_auth_ssl_server_cert_info_t *info,
svn_boolean_t may_save,
apr_pool_t *pool)
{
Data * data = NULL;
SVN_ERR(getData(baton, &data));
ContextListener::SslServerTrustData trustData(failures);
if (realm != NULL)
trustData.realm = realm;
trustData.hostname = info->hostname;
trustData.fingerprint = info->fingerprint;
trustData.validFrom = info->valid_from;
trustData.validUntil = info->valid_until;
trustData.issuerDName = info->issuer_dname;
trustData.maySave = may_save != 0;
apr_uint32_t acceptedFailures;
ContextListener::SslServerTrustAnswer answer =
data->listener->contextSslServerTrustPrompt(
trustData, acceptedFailures);
if (answer == ContextListener::DONT_ACCEPT)
*cred = NULL;
else
{
svn_auth_cred_ssl_server_trust_t *cred_ =
(svn_auth_cred_ssl_server_trust_t*)
apr_palloc(pool, sizeof(svn_auth_cred_ssl_server_trust_t));
if (answer == ContextListener::ACCEPT_PERMANENTLY)
{
cred_->may_save = 1;
cred_->accepted_failures = acceptedFailures;
}
*cred = cred_;
}
return SVN_NO_ERROR;
}
/**
* @see svn_auth_ssl_client_cert_prompt_func_t
*/
static svn_error_t *
onSslClientCertPrompt(svn_auth_cred_ssl_client_cert_t **cred,
void *baton,
apr_pool_t *pool)
{
Data * data = NULL;
SVN_ERR(getData(baton, &data));
std::string certFile;
if (!data->listener->contextSslClientCertPrompt(certFile))
return svn_error_create(SVN_ERR_CANCELLED, NULL, "");
svn_auth_cred_ssl_client_cert_t *cred_ =
(svn_auth_cred_ssl_client_cert_t*)
apr_palloc(pool, sizeof(svn_auth_cred_ssl_client_cert_t));
/* SVN_ERR (svn_utf_cstring_to_utf8 (
&cred_->cert_file,
certFile.c_str (),
pool)); */
cred_->cert_file = certFile.c_str();
*cred = cred_;
return SVN_NO_ERROR;
}
/**
* @see svn_auth_ssl_client_cert_pw_prompt_func_t
*/
static svn_error_t *
onSslClientCertPwPrompt(
svn_auth_cred_ssl_client_cert_pw_t **cred,
void *baton,
const char *realm,
svn_boolean_t maySave,
apr_pool_t *pool)
{
Data * data = NULL;
SVN_ERR(getData(baton, &data));
std::string password;
bool may_save = maySave != 0;
if (!data->listener->contextSslClientCertPwPrompt(password, realm, may_save))
return svn_error_create(SVN_ERR_CANCELLED, NULL, "");
svn_auth_cred_ssl_client_cert_pw_t *cred_ =
(svn_auth_cred_ssl_client_cert_pw_t *)
apr_palloc(pool, sizeof(svn_auth_cred_ssl_client_cert_pw_t));
/* SVN_ERR (svn_utf_cstring_to_utf8 (
&cred_->password,
password.c_str (),
pool)); */
cred_->password = password.c_str();
cred_->may_save = may_save;
*cred = cred_;
return SVN_NO_ERROR;
}
const char *
getUsername() const
{
return username.c_str();
}
const char *
getPassword() const
{
return password.c_str();
}
const char *
getLogMessage() const
{
return logMessage.c_str();
}
/**
* if the @a listener is set, use it to retrieve the log
* message using ContextListener::contextGetLogMessage.
* This return values is given back, then.
*
* if the @a listener is not set the its checked whether
* the log message has been set using @a setLogMessage
* yet. If not, return false otherwise true
*
* @param msg log message
* @retval false cancel
*/
bool
retrieveLogMessage(std::string & msg)
{
bool ok;
if (listener == 0)
return false;
ok = listener->contextGetLogMessage(logMessage);
if (ok)
msg = logMessage;
else
logIsSet = false;
return ok;
}
/**
* if the @a listener is set and no password has been
* set yet, use it to retrieve login and password using
* ContextListener::contextGetLogin.
*
* if the @a listener is not set, check if setLogin
* has been called yet.
*
* @return continue?
* @retval false cancel
*/
bool
retrieveLogin(const char * username_,
const char * realm,
bool &may_save)
{
bool ok;
if (listener == 0)
return false;
if (username_ == NULL)
username = "";
else
username = username_;
ok = listener->contextGetLogin(realm, username, password, may_save);
return ok;
}
/**
* if the @a listener is set call the method
* @a contextNotify
*/
void
notify(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)
{
if (listener != 0)
{
listener->contextNotify(path, action, kind, mime_type,
content_state, prop_state, revision);
}
}
/**
* if the @a listener is set call the method
* @a contextCancel
*/
bool
cancel()
{
if (listener != 0)
{
return listener->contextCancel();
}
else
{
// don't cancel if no listener
return false;
}
}
};
Context::Context(const std::string &configDir)
{
m = new Data(configDir);
}
Context::Context(const Context & src)
{
m = new Data(src.m->configDir);
setLogin(src.getUsername(), src.getPassword());
}
Context::~Context()
{
delete m;
}
void
Context::setAuthCache(bool value)
{
m->setAuthCache(value);
}
void
Context::setLogin(const char * username, const char * password)
{
m->setLogin(username, password);
}
Context::operator svn_client_ctx_t * ()
{
return m->ctx;
}
svn_client_ctx_t *
Context::ctx()
{
return m->ctx;
}
void
Context::setLogMessage(const char * msg)
{
m->setLogMessage(msg);
}
const char *
Context::getUsername() const
{
return m->getUsername();
}
const char *
Context::getPassword() const
{
return m->getPassword();
}
const char *
Context::getLogMessage() const
{
return m->getLogMessage();
}
void
Context::setListener(ContextListener * listener)
{
m->listener = listener;
}
ContextListener *
Context::getListener() const
{
return m->listener;
}
void
Context::reset()
{
m->promptCounter = 0;
m->logIsSet = false;
}
}
/* -----------------------------------------------------------------
* local variables:
* eval: (load-file "../../rapidsvn-dev.el")
* end:
*/
diff --git a/plugins/subversion/svndiffjob.cpp b/plugins/subversion/svndiffjob.cpp
index 7cd799b196..b722a7f276 100644
--- a/plugins/subversion/svndiffjob.cpp
+++ b/plugins/subversion/svndiffjob.cpp
@@ -1,480 +1,479 @@
/***************************************************************************
* This file is part of KDevelop *
* Copyright 2007 Andreas Pakulat *
* *
* 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 "svndiffjob.h"
#include "svndiffjob_p.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "kdevsvncpp/path.hpp"
#include "kdevsvncpp/revision.hpp"
#include "icore.h"
#include "iruncontroller.h"
#include "svnclient.h"
#include "svncatjob.h"
///@todo The subversion library returns borked diffs, where the headers are at the end. This function
/// takes those headers, and moves them into the correct place to create a valid working diff.
/// Find the source of this problem.
QString repairDiff(QString diff) {
kDebug() << "diff before repair:" << diff;
QStringList lines = diff.split('\n');
QMap headers;
for(int a = 0; a < lines.size()-1; ++a) {
if(lines[a].startsWith("Index: ") && lines[a+1].startsWith("=====")) {
QString fileName = lines[a].mid(strlen("Index: ")).trimmed();
headers[fileName] = lines[a];
kDebug() << "found header for" << fileName;
lines[a] = QString();
if(lines[a+1].startsWith("======")) {
headers[fileName] += '\n' + lines[a+1];
lines[a+1] = QString();
}
}
}
QRegExp spaceRegExp("\\s");
for(int a = 0; a < lines.size()-1; ++a) {
if(lines[a].startsWith("--- ")) {
QString tail = lines[a].mid(strlen("--- "));
if(tail.indexOf(spaceRegExp) != -1) {
QString file = tail.left(tail.indexOf(spaceRegExp));
kDebug() << "checking for" << file;
if(headers.contains(file)) {
kDebug() << "adding header for" << file << ":" << headers[file];
lines[a] = headers[file] + '\n' + lines[a];
}
}
}
}
QString ret = lines.join("\n");
kDebug() << "repaired diff:" << ret;
return ret;
}
//@TODO: Handle raw diffs by using SvnCatJob to fetch both files/revisions
SvnInternalDiffJob::SvnInternalDiffJob( SvnJobBase* parent )
: SvnInternalJobBase( parent ), m_recursive( true ),
m_ignoreAncestry( false ), m_ignoreContentType( false ),
m_noDiffOnDelete( false )
{
m_pegRevision.setRevisionValue( KDevelop::VcsRevision::Head,
KDevelop::VcsRevision::Special );
}
void SvnInternalDiffJob::run()
{
initBeforeRun();
SvnClient cli(m_ctxt);
try
{
QString diff;
if( destination().isValid() )
{
QByteArray srcba;
if( source().type() == KDevelop::VcsLocation::LocalLocation )
{
KUrl url = source().localUrl();
if( url.isLocalFile() )
{
srcba = url.toLocalFile( KUrl::RemoveTrailingSlash ).toUtf8();
}else
{
srcba = url.url( KUrl::RemoveTrailingSlash ).toUtf8();
}
}else
{
srcba = source().repositoryServer().toUtf8();
}
QByteArray dstba;
if( destination().type() == KDevelop::VcsLocation::LocalLocation )
{
KUrl url = destination().localUrl();
if( url.isLocalFile() )
{
dstba = url.toLocalFile( KUrl::RemoveTrailingSlash ).toUtf8();
}else
{
dstba = url.url().toUtf8();
}
}else
{
dstba = destination().repositoryServer().toUtf8();
}
svn::Revision srcRev = createSvnCppRevisionFromVcsRevision( srcRevision() );
svn::Revision dstRev = createSvnCppRevisionFromVcsRevision( dstRevision() );
if( srcba.isEmpty() || ( dstba.isEmpty() && srcRev.kind() == svn_opt_revision_unspecified
&& dstRev.kind() == svn_opt_revision_unspecified ) )
{
throw svn::ClientException( "Not enough information for a diff");
}
diff = cli.diff( svn::Path( srcba.data() ), srcRev, svn::Path( dstba.data() ),
dstRev, recursive(), ignoreAncestry(),
noDiffOnDelete(), ignoreContentType() );
}else
{
QByteArray srcba;
if( source().type() == KDevelop::VcsLocation::LocalLocation )
{
KUrl url = source().localUrl();
if( url.isLocalFile() )
{
srcba = url.toLocalFile( KUrl::RemoveTrailingSlash ).toUtf8();
}else
{
srcba = url.url().toUtf8();
}
}else
{
srcba = source().repositoryServer().toUtf8();
}
svn::Revision pegRev = createSvnCppRevisionFromVcsRevision( pegRevision() );
svn::Revision srcRev = createSvnCppRevisionFromVcsRevision( srcRevision() );
svn::Revision dstRev = createSvnCppRevisionFromVcsRevision( dstRevision() );
if( srcba.isEmpty() || pegRev.kind() == svn_opt_revision_unspecified
|| dstRev.kind() == svn_opt_revision_unspecified
|| srcRev.kind() == svn_opt_revision_unspecified)
{
throw svn::ClientException( "Not enough information for a diff");
}
- //@TODO: Make sure there's no diff-cmd set via the users configuration file, can be done only via C api
diff = cli.diff( svn::Path( srcba.data() ), pegRev, srcRev,
dstRev, recursive(), ignoreAncestry(),
noDiffOnDelete(), ignoreContentType() );
}
diff = repairDiff(diff);
emit gotDiff( diff );
}catch( svn::ClientException ce )
{
kDebug(9510) << "Exception while doing a diff: "
<< m_source.localUrl() << m_source.repositoryServer() << m_srcRevision.prettyValue()
<< m_destination.localUrl() << m_destination.repositoryServer() << m_dstRevision.prettyValue()
<< QString::fromUtf8( ce.message() );
setErrorMessage( QString::fromUtf8( ce.message() ) );
m_success = false;
}
}
void SvnInternalDiffJob::setSource( const KDevelop::VcsLocation& src )
{
QMutexLocker l( m_mutex );
m_source = src;
}
void SvnInternalDiffJob::setDestination( const KDevelop::VcsLocation& dst )
{
QMutexLocker l( m_mutex );
m_destination = dst;
}
void SvnInternalDiffJob::setSrcRevision( const KDevelop::VcsRevision& srcRev )
{
QMutexLocker l( m_mutex );
m_srcRevision = srcRev;
}
void SvnInternalDiffJob::setDstRevision( const KDevelop::VcsRevision& dstRev )
{
QMutexLocker l( m_mutex );
m_dstRevision = dstRev;
}
void SvnInternalDiffJob::setPegRevision( const KDevelop::VcsRevision& pegRev )
{
QMutexLocker l( m_mutex );
m_pegRevision = pegRev;
}
void SvnInternalDiffJob::setRecursive( bool recursive )
{
QMutexLocker l( m_mutex );
m_recursive = recursive;
}
void SvnInternalDiffJob::setIgnoreAncestry( bool ignoreAncestry )
{
QMutexLocker l( m_mutex );
m_ignoreAncestry = ignoreAncestry;
}
void SvnInternalDiffJob::setIgnoreContentType( bool ignoreContentType )
{
QMutexLocker l( m_mutex );
m_ignoreContentType = ignoreContentType;
}
void SvnInternalDiffJob::setNoDiffOnDelete( bool noDiffOnDelete )
{
QMutexLocker l( m_mutex );
m_noDiffOnDelete = noDiffOnDelete;
}
bool SvnInternalDiffJob::recursive() const
{
QMutexLocker l( m_mutex );
return m_recursive;
}
bool SvnInternalDiffJob::ignoreAncestry() const
{
QMutexLocker l( m_mutex );
return m_ignoreAncestry;
}
bool SvnInternalDiffJob::ignoreContentType() const
{
QMutexLocker l( m_mutex );
return m_ignoreContentType;
}
bool SvnInternalDiffJob::noDiffOnDelete() const
{
QMutexLocker l( m_mutex );
return m_noDiffOnDelete;
}
KDevelop::VcsLocation SvnInternalDiffJob::source() const
{
QMutexLocker l( m_mutex );
return m_source;
}
KDevelop::VcsLocation SvnInternalDiffJob::destination() const
{
QMutexLocker l( m_mutex );
return m_destination;
}
KDevelop::VcsRevision SvnInternalDiffJob::srcRevision() const
{
QMutexLocker l( m_mutex );
return m_srcRevision;
}
KDevelop::VcsRevision SvnInternalDiffJob::dstRevision() const
{
QMutexLocker l( m_mutex );
return m_dstRevision;
}
KDevelop::VcsRevision SvnInternalDiffJob::pegRevision() const
{
QMutexLocker l( m_mutex );
return m_pegRevision;
}
SvnDiffJob::SvnDiffJob( KDevSvnPlugin* parent )
: SvnJobBase( parent, KDevelop::OutputJob::Silent )
{
setType( KDevelop::VcsJob::Add );
m_job = new SvnInternalDiffJob( this );
setObjectName(i18n("Subversion Diff"));
}
QVariant SvnDiffJob::fetchResults()
{
return qVariantFromValue( m_diff );
}
void SvnDiffJob::start()
{
disconnect( m_job, SIGNAL(done(ThreadWeaver::Job*)), this, SLOT(internalJobDone(ThreadWeaver::Job*)) );
if( !m_job->source().isValid()
|| ( !m_job->destination().isValid() &&
( m_job->srcRevision().revisionType() == KDevelop::VcsRevision::Invalid
|| m_job->dstRevision().revisionType() == KDevelop::VcsRevision::Invalid ) )
)
{
internalJobFailed( m_job );
setErrorText( i18n( "Not enough information given to execute diff" ) );
}else
{
connect( m_job, SIGNAL(gotDiff(QString)),
this, SLOT(setDiff(QString)),
Qt::QueuedConnection );
ThreadWeaver::Weaver::instance()->enqueue( m_job );
}
}
SvnInternalJobBase* SvnDiffJob::internalJob() const
{
return m_job;
}
void SvnDiffJob::setSource( const KDevelop::VcsLocation& source )
{
if( status() == KDevelop::VcsJob::JobNotStarted )
m_job->setSource( source );
}
void SvnDiffJob::setDestination( const KDevelop::VcsLocation& destination )
{
if( status() == KDevelop::VcsJob::JobNotStarted )
m_job->setDestination( destination );
}
void SvnDiffJob::setPegRevision( const KDevelop::VcsRevision& pegRevision )
{
if( status() == KDevelop::VcsJob::JobNotStarted )
m_job->setPegRevision( pegRevision );
}
void SvnDiffJob::setSrcRevision( const KDevelop::VcsRevision& srcRevision )
{
if( status() == KDevelop::VcsJob::JobNotStarted )
m_job->setSrcRevision( srcRevision );
}
void SvnDiffJob::setDstRevision( const KDevelop::VcsRevision& dstRevision )
{
if( status() == KDevelop::VcsJob::JobNotStarted )
m_job->setDstRevision( dstRevision );
}
void SvnDiffJob::setRecursive( bool recursive )
{
if( status() == KDevelop::VcsJob::JobNotStarted )
m_job->setRecursive( recursive );
}
void SvnDiffJob::setIgnoreAncestry( bool ignoreAncestry )
{
if( status() == KDevelop::VcsJob::JobNotStarted )
m_job->setIgnoreAncestry( ignoreAncestry );
}
void SvnDiffJob::setIgnoreContentType( bool ignoreContentType )
{
if( status() == KDevelop::VcsJob::JobNotStarted )
m_job->setIgnoreContentType( ignoreContentType );
}
void SvnDiffJob::setNoDiffOnDelete( bool noDiffOnDelete )
{
if( status() == KDevelop::VcsJob::JobNotStarted )
m_job->setNoDiffOnDelete( noDiffOnDelete );
}
void SvnDiffJob::setDiff( const QString& diff )
{
m_diff = KDevelop::VcsDiff();
m_diff.setBaseDiff(KUrl("/"));
m_diff.setType( KDevelop::VcsDiff::DiffUnified );
m_diff.setContentType( KDevelop::VcsDiff::Text );
m_diff.setDiff( diff );
QRegExp fileRe("(?:^|\n)Index: ([^\n]+)\n");
QStringList paths;
int pos = 0;
while( ( pos = fileRe.indexIn( diff, pos ) ) != -1 )
{
paths << fileRe.cap(1);
pos += fileRe.matchedLength();
}
if (paths.isEmpty()) {
internalJobDone( m_job );
emit resultsReady( this );
return;
}
foreach( const QString &s, paths )
{
if( !s.isEmpty() )
{
SvnCatJob* job = new SvnCatJob( m_part );
KDevelop::VcsLocation l = m_job->source();
if( l.type() == KDevelop::VcsLocation::LocalLocation )
{
l.setLocalUrl( KUrl( s ) );
}else
{
QString repoLocation = KUrl( l.repositoryServer() ).toLocalFile( KUrl::RemoveTrailingSlash );
QFileInfo fi( repoLocation );
if( s == fi.fileName() )
{
l.setRepositoryServer( l.repositoryServer() );
}else
{
l.setRepositoryServer( l.repositoryServer() + '/' + s );
}
}
job->setSource( l );
job->setPegRevision( m_job->pegRevision() );
job->setSrcRevision( m_job->srcRevision() );
m_catJobMap[job] = l;
connect( job, SIGNAL(resultsReady(KDevelop::VcsJob*)), this, SLOT(addLeftText(KDevelop::VcsJob*)) );
connect( job, SIGNAL(result(KJob*)), this, SLOT(removeJob(KJob*)) );
KDevelop::ICore::self()->runController()->registerJob(job);
}
}
}
void SvnDiffJob::addLeftText( KDevelop::VcsJob* job )
{
if( m_catJobMap.contains( job ) )
{
QVariant v = job->fetchResults();
m_diff.addLeftText( m_catJobMap[job], v.toString() );
m_catJobMap.remove(job);
// KJobs delete themselves when finished
}
if( m_catJobMap.isEmpty() )
{
internalJobDone( m_job );
emit resultsReady( this );
}
}
void SvnDiffJob::removeJob( KJob* job )
{
if( job->error() != 0 )
{
KDevelop::VcsJob* j = dynamic_cast( job );
if( j )
{
if( m_catJobMap.contains( j ) )
{
m_catJobMap.remove(j);
// KJobs delete themselves when finished
}
}
}
if( m_catJobMap.isEmpty() )
{
internalJobDone( m_job );
emit resultsReady( this );
}
}
void SvnDiffJob::setDiffType( KDevelop::VcsDiff::Type type )
{
m_diffType = type;
}
#include "svndiffjob.moc"
#include "svndiffjob_p.moc"