mirror of
https://bitbucket.org/smil3y/kde-extraapps.git
synced 2025-02-25 11:22:55 +00:00
336 lines
11 KiB
C++
336 lines
11 KiB
C++
/***************************************************************************
|
|
* This file is part of KDevelop *
|
|
* Copyright 2007 Andreas Pakulat <apaku@gmx.de> *
|
|
* *
|
|
* Parts of the file are copied from the RapidSvn C++ library *
|
|
* Copyright (c) 2002-2006 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 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 "svnclient.h"
|
|
|
|
#include <QDateTime>
|
|
#include <QList>
|
|
|
|
#include <kdebug.h>
|
|
|
|
extern "C" {
|
|
#include <svn_client.h>
|
|
#include <svn_io.h>
|
|
}
|
|
#include "kdevsvncpp/targets.hpp"
|
|
#include "kdevsvncpp/pool.hpp"
|
|
|
|
#include <kstandarddirs.h>
|
|
|
|
#include <vcs/vcsrevision.h>
|
|
#include <vcs/vcsannotation.h>
|
|
|
|
void fail (apr_pool_t *pool, apr_status_t status, const char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
char *msg;
|
|
svn_error_t * error;
|
|
|
|
va_start (ap, fmt);
|
|
msg = apr_pvsprintf (pool, fmt, ap);
|
|
va_end (ap);
|
|
|
|
error = svn_error_create (status, NULL, msg);
|
|
throw svn::ClientException (error);
|
|
}
|
|
|
|
void cleanup( apr_file_t* outfile, const char* outfileName, apr_file_t* errfile, const char* errfileName, const svn::Pool& pool )
|
|
{
|
|
if( outfile != 0 )
|
|
{
|
|
apr_file_close( outfile );
|
|
}
|
|
|
|
if( errfile != 0 )
|
|
{
|
|
apr_file_close( outfile );
|
|
}
|
|
|
|
if( outfileName != 0 )
|
|
{
|
|
svn_error_clear( svn_io_remove_file ( outfileName, pool ) );
|
|
}
|
|
|
|
|
|
if( errfileName != 0 )
|
|
{
|
|
svn_error_clear( svn_io_remove_file ( errfileName, pool ) );
|
|
}
|
|
|
|
}
|
|
|
|
SvnClient::SvnClient( svn::Context* ctx )
|
|
: QObject(0), svn::Client( ctx ), m_ctxt( ctx )
|
|
{
|
|
}
|
|
|
|
QString SvnClient::diff( const svn::Path& src, const svn::Revision& srcRev,
|
|
const svn::Path& dst, const svn::Revision& dstRev,
|
|
const bool recurse, const bool ignoreAncestry,
|
|
const bool noDiffDeleted, const bool ignoreContentType )
|
|
throw (svn::ClientException)
|
|
{
|
|
svn::Pool pool;
|
|
// null options
|
|
apr_array_header_t *options = svn_cstring_split( "", "\t\r\n", false, pool );
|
|
|
|
svn_error_t* error;
|
|
|
|
const char* outfileName = 0;
|
|
apr_file_t* outfile = 0;
|
|
const char* errfileName = 0;
|
|
apr_file_t* errfile = 0;
|
|
|
|
QByteArray ba = QString(KStandardDirs::locateLocal("tmp","")+"kdevelop_svn_diff" ).toUtf8();
|
|
|
|
error = svn_io_open_unique_file( &outfile, &outfileName, ba.data(), ".tmp", false, pool );
|
|
|
|
if( error != 0 )
|
|
{
|
|
::cleanup( outfile, outfileName, errfile, errfileName, pool );
|
|
throw svn::ClientException( error );
|
|
}
|
|
|
|
error = svn_io_open_unique_file( &errfile, &errfileName, ba.data(), ".tmp", false, pool );
|
|
|
|
if( error != 0 )
|
|
{
|
|
::cleanup( outfile, outfileName, errfile, errfileName, pool );
|
|
throw svn::ClientException( error );
|
|
}
|
|
|
|
error = svn_client_diff3( options,
|
|
src.c_str(), srcRev.revision(),
|
|
dst.c_str(), dstRev.revision(),
|
|
recurse, ignoreAncestry, noDiffDeleted,
|
|
ignoreContentType, "UTF-8",
|
|
outfile, errfile, m_ctxt->ctx(), pool );
|
|
if ( error )
|
|
{
|
|
::cleanup( outfile, outfileName, errfile, errfileName, pool );
|
|
throw svn::ClientException(error);
|
|
}
|
|
|
|
// then we reopen outfile for reading
|
|
apr_status_t aprstatus = apr_file_close (outfile);
|
|
if (aprstatus)
|
|
{
|
|
::cleanup (outfile, outfileName, errfile, errfileName, pool);
|
|
::fail (pool, aprstatus, "failed to close '%s'", outfileName);
|
|
}
|
|
|
|
aprstatus = apr_file_open (&outfile, outfileName, APR_READ, APR_OS_DEFAULT, pool);
|
|
if (aprstatus)
|
|
{
|
|
::cleanup (outfile, outfileName, errfile, errfileName, pool);
|
|
::fail (pool, aprstatus, "failed to open '%s'", outfileName);
|
|
}
|
|
|
|
|
|
svn_stringbuf_t* stringbuf;
|
|
// now we can read the diff output from outfile and return that
|
|
error = svn_stringbuf_from_aprfile (&stringbuf, outfile, pool);
|
|
|
|
if (error != NULL)
|
|
{
|
|
::cleanup (outfile, outfileName, errfile, errfileName, pool);
|
|
throw svn::ClientException (error);
|
|
}
|
|
|
|
::cleanup (outfile, outfileName, errfile, errfileName, pool);
|
|
return QString::fromUtf8( stringbuf->data );
|
|
}
|
|
|
|
QString SvnClient::diff( const svn::Path& src, const svn::Revision& pegRev,
|
|
const svn::Revision& srcRev, const svn::Revision& dstRev,
|
|
const bool recurse, const bool ignoreAncestry,
|
|
const bool noDiffDeleted, const bool ignoreContentType )
|
|
throw (svn::ClientException)
|
|
{
|
|
svn::Pool pool;
|
|
// null options
|
|
apr_array_header_t *options = svn_cstring_split( "", "\t\r\n", false, pool );
|
|
|
|
|
|
svn_error_t* error;
|
|
|
|
const char* outfileName = 0;
|
|
apr_file_t* outfile = 0;
|
|
const char* errfileName = 0;
|
|
apr_file_t* errfile = 0;
|
|
|
|
QByteArray ba = KStandardDirs::locateLocal("tmp","").toUtf8();
|
|
|
|
error = svn_io_open_unique_file( &outfile, &outfileName, ba.data(), ".tmp", false, pool );
|
|
|
|
if( error != 0 )
|
|
{
|
|
::cleanup( outfile, outfileName, errfile, errfileName, pool );
|
|
throw svn::ClientException( error );
|
|
}
|
|
|
|
error = svn_io_open_unique_file( &errfile, &errfileName, ba.data(), ".tmp", false, pool );
|
|
|
|
if( error != 0 )
|
|
{
|
|
::cleanup( outfile, outfileName, errfile, errfileName, pool );
|
|
throw svn::ClientException( error );
|
|
}
|
|
|
|
error = svn_client_diff_peg3( options,
|
|
src.c_str(), pegRev.revision(),
|
|
srcRev.revision(), dstRev.revision(),
|
|
recurse, ignoreAncestry, noDiffDeleted,
|
|
ignoreContentType, "UTF-8",
|
|
outfile, errfile, m_ctxt->ctx(), pool );
|
|
if ( error )
|
|
{
|
|
::cleanup( outfile, outfileName, errfile, errfileName, pool );
|
|
throw svn::ClientException(error);
|
|
}
|
|
|
|
// then we reopen outfile for reading
|
|
apr_status_t aprstatus = apr_file_close (outfile);
|
|
if (aprstatus)
|
|
{
|
|
::cleanup (outfile, outfileName, errfile, errfileName, pool);
|
|
::fail (pool, aprstatus, "failed to close '%s'", outfileName);
|
|
}
|
|
|
|
aprstatus = apr_file_open (&outfile, outfileName, APR_READ, APR_OS_DEFAULT, pool);
|
|
if (aprstatus)
|
|
{
|
|
::cleanup (outfile, outfileName, errfile, errfileName, pool);
|
|
::fail (pool, aprstatus, "failed to open '%s'", outfileName);
|
|
}
|
|
|
|
|
|
svn_stringbuf_t* stringbuf;
|
|
// now we can read the diff output from outfile and return that
|
|
error = svn_stringbuf_from_aprfile (&stringbuf, outfile, pool);
|
|
|
|
if (error != NULL)
|
|
{
|
|
::cleanup (outfile, outfileName, errfile, errfileName, pool);
|
|
throw svn::ClientException(error);
|
|
}
|
|
|
|
::cleanup (outfile, outfileName, errfile, errfileName, pool);
|
|
return QString::fromUtf8( stringbuf->data );
|
|
}
|
|
|
|
static svn_error_t *
|
|
kdev_logReceiver (void *baton,
|
|
apr_hash_t * changedPaths,
|
|
svn_revnum_t rev,
|
|
const char *author,
|
|
const char *date,
|
|
const char *msg,
|
|
apr_pool_t * pool)
|
|
{
|
|
SvnClient* client = (SvnClient *) baton;
|
|
|
|
KDevelop::VcsEvent ev;
|
|
ev.setAuthor( QString::fromUtf8( author ) );
|
|
ev.setDate( QDateTime::fromString( QString::fromUtf8( date ), Qt::ISODate ) );
|
|
ev.setMessage( QString::fromUtf8( msg ) );
|
|
KDevelop::VcsRevision vcsrev;
|
|
vcsrev.setRevisionValue( QVariant( qlonglong( rev ) ), KDevelop::VcsRevision::GlobalNumber );
|
|
ev.setRevision( vcsrev );
|
|
|
|
if (changedPaths != NULL)
|
|
{
|
|
for (apr_hash_index_t *hi = apr_hash_first (pool, changedPaths);
|
|
hi != NULL;
|
|
hi = apr_hash_next (hi))
|
|
{
|
|
char *path;
|
|
void *val;
|
|
apr_hash_this (hi, (const void **)&path, NULL, &val);
|
|
|
|
svn_log_changed_path_t *log_item = reinterpret_cast<svn_log_changed_path_t *> (val);
|
|
KDevelop::VcsItemEvent iev;
|
|
iev.setRepositoryLocation( QString::fromUtf8( path ) );
|
|
iev.setRepositoryCopySourceLocation( QString::fromUtf8( log_item->copyfrom_path ) );
|
|
KDevelop::VcsRevision irev;
|
|
irev.setRevisionValue( QVariant( qlonglong( log_item->copyfrom_rev ) ),
|
|
KDevelop::VcsRevision::GlobalNumber );
|
|
iev.setRepositoryCopySourceRevision( irev );
|
|
switch( log_item->action )
|
|
{
|
|
case 'A':
|
|
iev.setActions( KDevelop::VcsItemEvent::Added );
|
|
break;
|
|
case 'M':
|
|
iev.setActions( KDevelop::VcsItemEvent::Modified );
|
|
break;
|
|
case 'D':
|
|
iev.setActions( KDevelop::VcsItemEvent::Deleted );
|
|
break;
|
|
case 'R':
|
|
iev.setActions( KDevelop::VcsItemEvent::Replaced );
|
|
break;
|
|
}
|
|
|
|
ev.items().append( iev );
|
|
}
|
|
}
|
|
client->emitLogEventReceived( ev );
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void SvnClient::log( const char* path,
|
|
const svn::Revision& start,
|
|
const svn::Revision& end,
|
|
int limit,
|
|
bool discoverChangedPaths,
|
|
bool strictNodeHistory )
|
|
throw (svn::ClientException)
|
|
{
|
|
svn::Pool pool;
|
|
svn::Targets target(path);
|
|
svn_error_t *error;
|
|
|
|
error = svn_client_log2 (
|
|
target.array(pool),
|
|
start.revision(),
|
|
end.revision(),
|
|
limit,
|
|
discoverChangedPaths ? 1 : 0,
|
|
strictNodeHistory ? 1 : 0,
|
|
kdev_logReceiver,
|
|
this,
|
|
m_ctxt->ctx(), // client ctx
|
|
pool);
|
|
|
|
if (error != NULL)
|
|
{
|
|
throw svn::ClientException (error);
|
|
}
|
|
}
|
|
|
|
void SvnClient::emitLogEventReceived( const KDevelop::VcsEvent& ev )
|
|
{
|
|
emit logEventReceived( ev );
|
|
}
|