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 &parameters)
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 &params)
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 &parameters)
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 &parameter)
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 &parameter)
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 &params)
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