Don't keep compiling/run if something failed.
[kdevelopdvcssupport.git] / plugins / subversion / svnclient.cpp
blob49d369a0e4a1487e3ff6b2e7887298261d5f3679
1 /***************************************************************************
2 * This file is part of KDevelop *
3 * Copyright 2007 Andreas Pakulat <apaku@gmx.de> *
4 * *
5 * Parts of the file are copied from the RapidSvn C++ library *
6 * Copyright (c) 2002-2006 The RapidSvn Group. All rights reserved. *
7 * *
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. *
12 * *
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. *
17 * *
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"
26 #include <QDateTime>
27 #include <QList>
29 #include <kdebug.h>
31 extern "C" {
32 #include <svn_client.h>
33 #include <svn_io.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, ...)
45 va_list ap;
46 char *msg;
47 svn_error_t * error;
49 va_start (ap, fmt);
50 msg = apr_pvsprintf (pool, fmt, ap);
51 va_end (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 )
59 if( outfile != 0 )
61 apr_file_close( outfile );
64 if( errfile != 0 )
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)
93 svn::Pool pool;
94 // null options
95 apr_array_header_t *options = svn_cstring_split( "", "\t\r\n", false, pool );
97 svn_error_t* error;
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 );
108 if( error != 0 )
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 );
116 if( error != 0 )
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 );
128 if ( error )
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);
136 if (aprstatus)
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);
143 if (aprstatus)
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);
154 if (error != NULL)
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)
170 svn::Pool pool;
171 // null options
172 apr_array_header_t *options = svn_cstring_split( "", "\t\r\n", false, pool );
175 svn_error_t* error;
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 );
186 if( error != 0 )
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 );
194 if( error != 0 )
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 );
206 if ( error )
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);
214 if (aprstatus)
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);
221 if (aprstatus)
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);
232 if (error != NULL)
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 );
242 static svn_error_t *
243 kdev_logReceiver (void *baton,
244 apr_hash_t * changedPaths,
245 svn_revnum_t rev,
246 const char *author,
247 const char *date,
248 const char *msg,
249 apr_pool_t * pool)
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);
264 hi != NULL;
265 hi = apr_hash_next (hi))
267 char *path;
268 void *val;
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 )
282 case 'A':
283 iev.setActions( KDevelop::VcsItemEvent::Added );
284 break;
285 case 'M':
286 iev.setActions( KDevelop::VcsItemEvent::Modified );
287 break;
288 case 'D':
289 iev.setActions( KDevelop::VcsItemEvent::Deleted );
290 break;
291 case 'R':
292 iev.setActions( KDevelop::VcsItemEvent::Replaced );
293 break;
295 ev.setActions( ev.actions() | iev.actions() );
296 ev.items().append( iev );
299 client->emitLogEventReceived( ev );
301 return NULL;
304 void SvnClient::log( const char* path,
305 const svn::Revision& start,
306 const svn::Revision& end,
307 int limit,
308 bool discoverChangedPaths,
309 bool strictNodeHistory )
310 throw (svn::ClientException)
312 svn::Pool pool;
313 svn::Targets target(path);
314 svn_error_t *error;
316 error = svn_client_log2 (
317 target.array(pool),
318 start.revision(),
319 end.revision(),
320 limit,
321 discoverChangedPaths ? 1 : 0,
322 strictNodeHistory ? 1 : 0,
323 kdev_logReceiver,
324 this,
325 m_ctxt->ctx(), // client ctx
326 pool);
328 if (error != NULL)
330 throw svn::ClientException (error);
334 static svn_error_t *
335 kdev_annotateReceiver ( void *baton,
336 apr_int64_t line_no,
337 svn_revnum_t revision,
338 const char *author,
339 const char *date,
340 const char *line,
341 apr_pool_t *pool )
343 Q_UNUSED(pool);
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 );
355 return NULL;
358 void SvnClient::blame( const svn::Path& path, const svn::Revision& start, const svn::Revision& end )
360 svn::Pool pool;
361 svn_error_t *error;
362 error = svn_client_blame (
363 path.c_str (),
364 start.revision (),
365 end.revision (),
366 kdev_annotateReceiver,
367 this,
368 m_ctxt->ctx(), // client ctx
369 pool);
371 if (error != NULL)
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 );