1 /*
2 * Port for usage with qt-framework and development for kdesvn
3 * Copyright (C) 2005-2009 by Rajko Albrecht (ral@alwins-world.de)
4 * http://kdesvn.alwins-world.de
5 */
6 /*
7 * ====================================================================
8 * Copyright (c) 2002-2005 The RapidSvn Group. All rights reserved.
9 * dev@rapidsvn.tigris.org
10 *
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
15 *
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
20 *
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library (in the file LGPL.txt); if not,
23 * write to the Free Software Foundation, Inc., 51 Franklin St,
24 * Fifth Floor, Boston, MA 02110-1301 USA
25 *
26 * This software consists of voluntary contributions made by many
27 * individuals. For exact contribution history, see the revision
28 * history and logs, available at http://rapidsvn.tigris.org/.
29 * ====================================================================
30 */
31 #if defined( _MSC_VER) && _MSC_VER <= 1200
32 #pragma warning( disable: 4786 )// debug symbol truncated
33 #endif
34 // svncpp
35 #include "svnqt/client_impl.h"
36
37 // subversion api
38 #include "svn_client.h"
39
40 #include "svnqt/exception.h"
41 #include "svnqt/pool.h"
42 #include "svnqt/targets.h"
43 #include "svnqt/svnqt_defines.h"
44 #include "svnqt/stringarray.h"
45 #include "svnqt/client_parameter.h"
46 #include "svnqt/client_commit_parameter.h"
47 #include "svnqt/client_update_parameter.h"
48 #include "svnqt/url.h"
49
50 #include "svnqt/helper.h"
51
52 #include <QCoreApplication>
53
54 namespace svn
55 {
56 struct mBaton {
mBatonsvn::mBaton57 mBaton(): m_context(), m_revision(Revision::UNDEFINED), m_date(), author(), commit_error(), repos_root() {}
58 ContextWP m_context;
59 svn::Revision m_revision;
60 QString m_date, author, commit_error, repos_root;
61 };
62
commit_callback2(const svn_commit_info_t * commit_info,void * baton,apr_pool_t * pool)63 static svn_error_t *commit_callback2(const svn_commit_info_t *commit_info, void *baton, apr_pool_t *pool)
64 {
65 Q_UNUSED(pool);
66 mBaton *m_baton = (mBaton *)baton;
67 ContextP m_context = m_baton->m_context;
68 if (!m_context) {
69 return svn_error_create(SVN_ERR_CANCELLED, nullptr, QCoreApplication::translate("svnqt", "Cancelled by user.").toUtf8());
70 }
71 svn_client_ctx_t *ctx = m_context->ctx();
72 if (ctx && ctx->cancel_func) {
73 SVN_ERR(ctx->cancel_func(ctx->cancel_baton));
74 }
75 m_baton->author = QString::fromUtf8(commit_info->author);
76 m_baton->commit_error = QString::fromUtf8(commit_info->post_commit_err);
77 m_baton->m_date = QString::fromUtf8(commit_info->date);
78 m_baton->repos_root = QString::fromUtf8(commit_info->repos_root);
79 m_baton->m_revision = commit_info->revision;
80 return SVN_NO_ERROR;
81 }
82
83 Revision
checkout(const CheckoutParameter & parameters)84 Client_impl::checkout(const CheckoutParameter ¶meters)
85 {
86 Pool subPool;
87 svn_revnum_t revnum = 0;
88 svn_error_t *error = nullptr;
89 error = svn_client_checkout3(&revnum,
90 parameters.moduleName().cstr(),
91 parameters.destination().cstr(),
92 parameters.peg().revision(),
93 parameters.revision().revision(),
94 internal::DepthToSvn(parameters.depth()),
95 parameters.ignoreExternals(),
96 parameters.overWrite(),
97 *m_context,
98 subPool);
99 if (error != nullptr) {
100 throw ClientException(error);
101 }
102 return Revision(revnum);
103 }
104
105 Revision
remove(const Targets & targets,bool force,bool keep_local,const PropertiesMap & revProps)106 Client_impl::remove(const Targets &targets,
107 bool force,
108 bool keep_local,
109 const PropertiesMap &revProps
110 )
111 {
112 Pool pool;
113 svn_error_t *error;
114
115 mBaton _baton;
116 _baton.m_context = m_context;
117 error = svn_client_delete4(
118 targets.array(pool),
119 force,
120 keep_local,
121 map2hash(revProps, pool),
122 commit_callback2,
123 &_baton,
124 *m_context,
125 pool
126 );
127
128 if (error != nullptr) {
129 throw ClientException(error);
130 }
131 return _baton.m_revision;
132 }
133
134 void
revert(const Targets & targets,Depth depth,const StringArray & changelist)135 Client_impl::revert(const Targets &targets,
136 Depth depth,
137 const StringArray &changelist
138 )
139 {
140 Pool pool;
141
142 svn_error_t *error =
143 svn_client_revert2((targets.array(pool)),
144 internal::DepthToSvn(depth),
145 changelist.array(pool),
146 *m_context,
147 pool);
148 if (error != nullptr) {
149 throw ClientException(error);
150 }
151 }
152
153 void
add(const Path & path,svn::Depth depth,bool force,bool no_ignore,bool add_parents)154 Client_impl::add(const Path &path,
155 svn::Depth depth, bool force, bool no_ignore, bool add_parents)
156 {
157 Pool pool;
158 // todo svn 1.8: svn_client_add5
159 svn_error_t *error =
160 svn_client_add4(path.cstr(),
161 internal::DepthToSvn(depth),
162 force,
163 no_ignore,
164 add_parents,
165 *m_context,
166 pool);
167 if (error != nullptr) {
168 throw ClientException(error);
169 }
170 }
171
172 Revisions
update(const UpdateParameter & params)173 Client_impl::update(const UpdateParameter ¶ms)
174 {
175 Pool pool;
176 Revisions resulting;
177 svn_error_t *error;
178
179 apr_pool_t *apr_pool = pool.pool();
180 apr_array_header_t *apr_revisions = apr_array_make(apr_pool,
181 params.targets().size(),
182 sizeof(svn_revnum_t));
183 error = svn_client_update4(&apr_revisions, params.targets().array(pool), params.revision(),
184 internal::DepthToSvn(params.depth()), params.sticky_depth(),
185 params.ignore_externals(), params.allow_unversioned(),
186 params.add_as_modification(), params.make_parents(),
187 *m_context, pool
188 );
189
190 if (error != nullptr) {
191 throw ClientException(error);
192 }
193 for (int i = 0; i < apr_revisions->nelts; ++i) {
194 svn_revnum_t *_rev =
195 &APR_ARRAY_IDX(apr_revisions, i, svn_revnum_t);
196
197 resulting.push_back((*_rev));
198 }
199 return resulting;
200 }
201
202 svn::Revision
commit(const CommitParameter & parameters)203 Client_impl::commit(const CommitParameter ¶meters)
204 {
205 Pool pool;
206
207 mBaton _baton;
208 _baton.m_context = m_context;
209 m_context->setLogMessage(parameters.message());
210 svn_error_t *error =
211 #if SVN_API_VERSION >= SVN_VERSION_CHECK(1,8,0)
212 svn_client_commit6(
213 #else
214 svn_client_commit5(
215 #endif
216 parameters.targets().array(pool),
217 internal::DepthToSvn(parameters.depth()),
218 parameters.keepLocks(),
219 parameters.keepChangeList(),
220 parameters.commitAsOperations(),
221 #if SVN_API_VERSION >= SVN_VERSION_CHECK(1,8,0)
222 false, /* file externals */
223 false, /* dir externals */
224 #endif
225 parameters.changeList().array(pool),
226 map2hash(parameters.revisionProperties(), pool),
227 commit_callback2,
228 &_baton,
229 *m_context,
230 pool
231 );
232
233 if (error != nullptr) {
234 throw ClientException(error);
235 }
236 return _baton.m_revision;
237 }
238
239 Revision
copy(const CopyParameter & parameter)240 Client_impl::copy(const CopyParameter ¶meter)
241 {
242 if (parameter.srcPath().size() < 1) {
243 throw ClientException("Wrong size of sources.");
244 }
245
246 Pool pool;
247 apr_array_header_t *sources = apr_array_make(pool, parameter.srcPath().size(), sizeof(svn_client_copy_source_t *));
248 // not using .array() 'cause some extra information is needed for copy
249 for (const Path &path : parameter.srcPath().targets()) {
250 svn_client_copy_source_t *source = (svn_client_copy_source_t *)apr_palloc(pool, sizeof(svn_client_copy_source_t));
251 source->path = apr_pstrdup(pool, path.path().toUtf8());
252 source->revision = parameter.srcRevision().revision();
253 source->peg_revision = parameter.pegRevision().revision();
254 APR_ARRAY_PUSH(sources, svn_client_copy_source_t *) = source;
255 }
256 mBaton _baton;
257 _baton.m_context = m_context;
258
259 svn_error_t *error =
260 svn_client_copy6(
261 sources,
262 parameter.destination().cstr(),
263 parameter.asChild(), parameter.makeParent(), parameter.ignoreExternal(),
264 map2hash(parameter.properties(), pool),
265 commit_callback2, &_baton,
266 *m_context, pool);
267
268 if (error != nullptr) {
269 throw ClientException(error);
270 }
271 return _baton.m_revision;
272 }
273
274 Revision
copy(const Path & srcPath,const Revision & srcRevision,const Path & destPath)275 Client_impl::copy(const Path &srcPath,
276 const Revision &srcRevision,
277 const Path &destPath)
278 {
279 return copy(CopyParameter(srcPath, destPath).srcRevision(srcRevision).asChild(true).makeParent(false));
280 }
281
move(const CopyParameter & parameter)282 svn::Revision Client_impl::move(const CopyParameter ¶meter)
283 {
284 Pool pool;
285
286 // todo svn 1.8: svn_client_move7
287 mBaton _baton;
288 _baton.m_context = m_context;
289 svn_error_t *error = svn_client_move6(
290 parameter.srcPath().array(pool),
291 parameter.destination().cstr(),
292 parameter.asChild(),
293 parameter.makeParent(),
294 map2hash(parameter.properties(), pool),
295 commit_callback2,
296 &_baton,
297 *m_context,
298 pool
299 );
300
301 if (error != nullptr) {
302 throw ClientException(error);
303 }
304 return _baton.m_revision;
305
306 }
307
308 svn::Revision
mkdir(const Targets & targets,const QString & msg,bool makeParent,const PropertiesMap & revProps)309 Client_impl::mkdir(const Targets &targets,
310 const QString &msg,
311 bool makeParent,
312 const PropertiesMap &revProps
313 )
314 {
315 Pool pool;
316 m_context->setLogMessage(msg);
317
318
319
320 svn_error_t *error = nullptr;
321 mBaton _baton;
322 _baton.m_context = m_context;
323 error = svn_client_mkdir4
324 (
325 const_cast<apr_array_header_t *>(targets.array(pool)),
326 makeParent,
327 map2hash(revProps, pool),
328 commit_callback2, &_baton,
329 *m_context, pool
330 );
331 /* important! otherwise next op on repository uses that logmessage again! */
332 m_context->setLogMessage(QString());
333
334 if (error != nullptr) {
335 throw ClientException(error);
336 }
337
338 return _baton.m_revision;
339 }
340
341 void
cleanup(const Path & path)342 Client_impl::cleanup(const Path &path)
343 {
344 Pool subPool;
345 apr_pool_t *apr_pool = subPool.pool();
346
347 svn_error_t *error =
348 svn_client_cleanup(path.cstr(), *m_context, apr_pool);
349
350 if (error != nullptr) {
351 throw ClientException(error);
352 }
353 }
354
resolve(const Path & path,Depth depth,const ConflictResult & resolution)355 void Client_impl::resolve(const Path &path, Depth depth, const ConflictResult &resolution)
356 {
357 Pool pool;
358 const svn_wc_conflict_result_t *aResult = resolution.result(pool);
359 svn_error_t *error = svn_client_resolve(path.cstr(), internal::DepthToSvn(depth), aResult->choice, *m_context, pool);
360
361 if (error != nullptr) {
362 throw ClientException(error);
363 }
364 }
365
366 Revision
doExport(const CheckoutParameter & params)367 Client_impl::doExport(const CheckoutParameter ¶ms)
368 {
369 Pool pool;
370 svn_revnum_t revnum = 0;
371 QByteArray _neolBA;
372 const char *_neol;
373 if (params.nativeEol().isNull()) {
374 _neol = nullptr;
375 } else {
376 _neolBA = params.nativeEol().toUtf8();
377 _neol = _neolBA.constData();
378 }
379 svn_error_t *error =
380 svn_client_export5(
381 &revnum,
382 params.moduleName().cstr(),
383 params.destination().cstr(),
384 params.peg().revision(),
385 params.revision().revision(),
386 params.overWrite(),
387 params.ignoreExternals(),
388 params.ignoreKeywords(),
389 internal::DepthToSvn(params.depth()),
390 _neol,
391 *m_context,
392 pool);
393 if (error != nullptr) {
394 throw ClientException(error);
395 }
396 return Revision(revnum);
397 }
398
399 Revision
doSwitch(const Path & path,const Url & url,const Revision & revision,Depth depth,const Revision & peg,bool sticky_depth,bool ignore_externals,bool allow_unversioned,bool ignore_ancestry)400 Client_impl::doSwitch(
401 const Path &path,
402 const Url &url,
403 const Revision &revision,
404 Depth depth,
405 const Revision &peg,
406 bool sticky_depth,
407 bool ignore_externals,
408 bool allow_unversioned,
409 bool ignore_ancestry
410 )
411 {
412 Pool pool;
413 svn_revnum_t revnum = 0;
414 svn_error_t *error = svn_client_switch3(
415 &revnum,
416 path.cstr(),
417 url.cstr(),
418 peg.revision(),
419 revision.revision(),
420 internal::DepthToSvn(depth),
421 sticky_depth,
422 ignore_externals,
423 allow_unversioned,
424 ignore_ancestry,
425 *m_context,
426 pool
427 );
428 if (error != nullptr) {
429 throw ClientException(error);
430 }
431 return Revision(revnum);
432 }
433
434 Revision
import(const Path & path,const Url & importRepository,const QString & message,svn::Depth depth,bool no_ignore,bool no_unknown_nodetype,const PropertiesMap & revProps)435 Client_impl::import(const Path &path,
436 const Url &importRepository,
437 const QString &message,
438 svn::Depth depth,
439 bool no_ignore, bool no_unknown_nodetype,
440 const PropertiesMap &revProps
441 )
442
443 {
444 Pool pool;
445
446 m_context->setLogMessage(message);
447 // todo svn 1.8: svn_client_import5
448 mBaton _baton;
449 _baton.m_context = m_context;
450 svn_error_t *error =
451 svn_client_import4(path.cstr(),
452 importRepository.cstr(),
453 internal::DepthToSvn(depth), no_ignore, no_unknown_nodetype,
454 map2hash(revProps, pool),
455 commit_callback2, &_baton,
456 *m_context, pool);
457
458 /* important! otherwise next op on repository uses that logmessage again! */
459 m_context->setLogMessage(QString());
460
461 if (error != nullptr) {
462 throw ClientException(error);
463 }
464 return _baton.m_revision;
465 }
466
467 void
relocate(const Path & path,const Url & from_url,const Url & to_url,bool recurse,bool ignore_externals)468 Client_impl::relocate(const Path &path,
469 const Url &from_url,
470 const Url &to_url,
471 bool recurse,
472 bool ignore_externals)
473 {
474 Q_UNUSED(recurse);
475 Pool pool;
476 svn_error_t *error =
477 svn_client_relocate2(path.cstr(),
478 from_url.cstr(),
479 to_url.cstr(),
480 ignore_externals,
481 *m_context,
482 pool);
483
484 if (error != nullptr) {
485 throw ClientException(error);
486 }
487 }
488
489 }
490
491 /* -----------------------------------------------------------------
492 * local variables:
493 * eval: (load-file "../../rapidsvn-dev.el")
494 * end:
495 */
496