1 /***************************************************************************
2 * This file is part of KDevelop *
3 * Copyright 2007 Andreas Pakulat <apaku@gmx.de> *
5 * Parts of the file are copied from the RapidSvn C++ library *
6 * Copyright (c) 2002-2006 The RapidSvn Group. All rights reserved. *
8 * This program is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU Library General Public License as *
10 * published by the Free Software Foundation; either version 2 of the *
11 * License, or (at your option) any later version. *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
18 * You should have received a copy of the GNU Library General Public *
19 * License along with this program; if not, write to the *
20 * Free Software Foundation, Inc., *
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
22 ***************************************************************************/
24 #include "svnclient.h"
32 #include <svn_client.h>
35 #include "kdevsvncpp/targets.hpp"
36 #include "kdevsvncpp/pool.hpp"
38 #include <kstandarddirs.h>
40 #include <vcs/vcsrevision.h>
41 #include <vcs/vcsannotation.h>
43 void fail (apr_pool_t
*pool
, apr_status_t status
, const char *fmt
, ...)
50 msg
= apr_pvsprintf (pool
, fmt
, ap
);
53 error
= svn_error_create (status
, NULL
, msg
);
54 throw svn::ClientException (error
);
57 void cleanup( apr_file_t
* outfile
, const char* outfileName
, apr_file_t
* errfile
, const char* errfileName
, const svn::Pool
& pool
)
61 apr_file_close( outfile
);
66 apr_file_close( outfile
);
69 if( outfileName
!= 0 )
71 svn_error_clear( svn_io_remove_file ( outfileName
, pool
) );
75 if( errfileName
!= 0 )
77 svn_error_clear( svn_io_remove_file ( errfileName
, pool
) );
82 SvnClient::SvnClient( svn::Context
* ctx
)
83 : QObject(0), svn::Client( ctx
), m_ctxt( ctx
)
87 QString
SvnClient::diff( const svn::Path
& src
, const svn::Revision
& srcRev
,
88 const svn::Path
& dst
, const svn::Revision
& dstRev
,
89 const bool recurse
, const bool ignoreAncestry
,
90 const bool noDiffDeleted
, const bool ignoreContentType
)
91 throw (svn::ClientException
)
95 apr_array_header_t
*options
= svn_cstring_split( "", "\t\r\n", false, pool
);
99 const char* outfileName
= 0;
100 apr_file_t
* outfile
= 0;
101 const char* errfileName
= 0;
102 apr_file_t
* errfile
= 0;
104 QByteArray ba
= (KStandardDirs::locateLocal("tmp","")+"kdevelop_svn_diff" ).toUtf8();
106 error
= svn_io_open_unique_file( &outfile
, &outfileName
, ba
.data(), ".tmp", FALSE
, pool
);
110 ::cleanup( outfile
, outfileName
, errfile
, errfileName
, pool
);
111 throw svn::ClientException( error
);
114 error
= svn_io_open_unique_file( &errfile
, &errfileName
, ba
.data(), ".tmp", FALSE
, pool
);
118 ::cleanup( outfile
, outfileName
, errfile
, errfileName
, pool
);
119 throw svn::ClientException( error
);
122 error
= svn_client_diff3( options
,
123 src
.c_str(), srcRev
.revision(),
124 dst
.c_str(), dstRev
.revision(),
125 recurse
, ignoreAncestry
, noDiffDeleted
,
126 ignoreContentType
, "UTF-8",
127 outfile
, errfile
, m_ctxt
->ctx(), pool
);
130 ::cleanup( outfile
, outfileName
, errfile
, errfileName
, pool
);
131 throw svn::ClientException(error
);
134 // then we reopen outfile for reading
135 apr_status_t aprstatus
= apr_file_close (outfile
);
138 ::cleanup (outfile
, outfileName
, errfile
, errfileName
, pool
);
139 ::fail (pool
, aprstatus
, "failed to close '%s'", outfileName
);
142 aprstatus
= apr_file_open (&outfile
, outfileName
, APR_READ
, APR_OS_DEFAULT
, pool
);
145 ::cleanup (outfile
, outfileName
, errfile
, errfileName
, pool
);
146 ::fail (pool
, aprstatus
, "failed to open '%s'", outfileName
);
150 svn_stringbuf_t
* stringbuf
;
151 // now we can read the diff output from outfile and return that
152 error
= svn_stringbuf_from_aprfile (&stringbuf
, outfile
, pool
);
156 ::cleanup (outfile
, outfileName
, errfile
, errfileName
, pool
);
157 throw svn::ClientException (error
);
160 ::cleanup (outfile
, outfileName
, errfile
, errfileName
, pool
);
161 return QString::fromUtf8( stringbuf
->data
);
164 QString
SvnClient::diff( const svn::Path
& src
, const svn::Revision
& pegRev
,
165 const svn::Revision
& srcRev
, const svn::Revision
& dstRev
,
166 const bool recurse
, const bool ignoreAncestry
,
167 const bool noDiffDeleted
, const bool ignoreContentType
)
168 throw (svn::ClientException
)
172 apr_array_header_t
*options
= svn_cstring_split( "", "\t\r\n", false, pool
);
177 const char* outfileName
= 0;
178 apr_file_t
* outfile
= 0;
179 const char* errfileName
= 0;
180 apr_file_t
* errfile
= 0;
182 QByteArray ba
= KStandardDirs::locateLocal("tmp","").toUtf8();
184 error
= svn_io_open_unique_file( &outfile
, &outfileName
, ba
.data(), ".tmp", FALSE
, pool
);
188 ::cleanup( outfile
, outfileName
, errfile
, errfileName
, pool
);
189 throw svn::ClientException( error
);
192 error
= svn_io_open_unique_file( &errfile
, &errfileName
, ba
.data(), ".tmp", FALSE
, pool
);
196 ::cleanup( outfile
, outfileName
, errfile
, errfileName
, pool
);
197 throw svn::ClientException( error
);
200 error
= svn_client_diff_peg3( options
,
201 src
.c_str(), pegRev
.revision(),
202 srcRev
.revision(), dstRev
.revision(),
203 recurse
, ignoreAncestry
, noDiffDeleted
,
204 ignoreContentType
, "UTF-8",
205 outfile
, errfile
, m_ctxt
->ctx(), pool
);
208 ::cleanup( outfile
, outfileName
, errfile
, errfileName
, pool
);
209 throw svn::ClientException(error
);
212 // then we reopen outfile for reading
213 apr_status_t aprstatus
= apr_file_close (outfile
);
216 ::cleanup (outfile
, outfileName
, errfile
, errfileName
, pool
);
217 ::fail (pool
, aprstatus
, "failed to close '%s'", outfileName
);
220 aprstatus
= apr_file_open (&outfile
, outfileName
, APR_READ
, APR_OS_DEFAULT
, pool
);
223 ::cleanup (outfile
, outfileName
, errfile
, errfileName
, pool
);
224 ::fail (pool
, aprstatus
, "failed to open '%s'", outfileName
);
228 svn_stringbuf_t
* stringbuf
;
229 // now we can read the diff output from outfile and return that
230 error
= svn_stringbuf_from_aprfile (&stringbuf
, outfile
, pool
);
234 ::cleanup (outfile
, outfileName
, errfile
, errfileName
, pool
);
235 throw svn::ClientException(error
);
238 ::cleanup (outfile
, outfileName
, errfile
, errfileName
, pool
);
239 return QString::fromUtf8( stringbuf
->data
);
243 kdev_logReceiver (void *baton
,
244 apr_hash_t
* changedPaths
,
251 SvnClient
* client
= (SvnClient
*) baton
;
253 KDevelop::VcsEvent ev
;
254 ev
.setAuthor( QString::fromUtf8( author
) );
255 ev
.setDate( QDateTime::fromString( QString::fromUtf8( date
), Qt::ISODate
) );
256 ev
.setMessage( QString::fromUtf8( msg
) );
257 KDevelop::VcsRevision vcsrev
;
258 vcsrev
.setRevisionValue( QVariant( qlonglong( rev
) ), KDevelop::VcsRevision::GlobalNumber
);
259 ev
.setRevision( vcsrev
);
261 if (changedPaths
!= NULL
)
263 for (apr_hash_index_t
*hi
= apr_hash_first (pool
, changedPaths
);
265 hi
= apr_hash_next (hi
))
269 apr_hash_this (hi
, (const void **)&path
, NULL
, &val
);
271 svn_log_changed_path_t
*log_item
= reinterpret_cast<svn_log_changed_path_t
*> (val
);
272 KDevelop::VcsItemEvent iev
;
273 iev
.setRepositoryLocation( QString::fromUtf8( path
) );
274 iev
.setRepositoryCopySourceLocation( QString::fromUtf8( log_item
->copyfrom_path
) );
275 KDevelop::VcsRevision irev
;
276 irev
.setRevisionValue( QVariant( qlonglong( log_item
->copyfrom_rev
) ),
277 KDevelop::VcsRevision::GlobalNumber
);
278 iev
.setRepositoryCopySourceRevision( irev
);
279 iev
.setRevision( vcsrev
);
280 switch( log_item
->action
)
283 iev
.setActions( KDevelop::VcsItemEvent::Added
);
286 iev
.setActions( KDevelop::VcsItemEvent::Modified
);
289 iev
.setActions( KDevelop::VcsItemEvent::Deleted
);
292 iev
.setActions( KDevelop::VcsItemEvent::Replaced
);
295 ev
.setActions( ev
.actions() | iev
.actions() );
296 ev
.items().append( iev
);
299 client
->emitLogEventReceived( ev
);
304 void SvnClient::log( const char* path
,
305 const svn::Revision
& start
,
306 const svn::Revision
& end
,
308 bool discoverChangedPaths
,
309 bool strictNodeHistory
)
310 throw (svn::ClientException
)
313 svn::Targets
target(path
);
316 error
= svn_client_log2 (
321 discoverChangedPaths
? 1 : 0,
322 strictNodeHistory
? 1 : 0,
325 m_ctxt
->ctx(), // client ctx
330 throw svn::ClientException (error
);
335 kdev_annotateReceiver ( void *baton
,
337 svn_revnum_t revision
,
344 SvnClient
* client
= reinterpret_cast<SvnClient
*>(baton
);
346 KDevelop::VcsAnnotationLine vcsline
;
347 vcsline
.setAuthor( QString::fromUtf8( author
) );
348 vcsline
.setDate( QDateTime::fromString( QString::fromUtf8( date
), Qt::ISODate
) );
349 vcsline
.setText( QString::fromUtf8( line
) );
350 KDevelop::VcsRevision rev
;
351 rev
.setRevisionValue( QVariant( qlonglong( revision
) ), KDevelop::VcsRevision::GlobalNumber
);
352 vcsline
.setRevision( rev
);
353 vcsline
.setLineNumber( line_no
);
354 client
->emitLineReceived( vcsline
);
358 void SvnClient::blame( const svn::Path
& path
, const svn::Revision
& start
, const svn::Revision
& end
)
362 error
= svn_client_blame (
366 kdev_annotateReceiver
,
368 m_ctxt
->ctx(), // client ctx
373 throw svn::ClientException (error
);
378 void SvnClient::emitLineReceived( const KDevelop::VcsAnnotationLine
& line
)
380 emit
lineReceived( line
);
383 void SvnClient::emitLogEventReceived( const KDevelop::VcsEvent
& ev
)
385 emit
logEventReceived( ev
);