File indexing completed on 2024-05-19 16:47:08

0001 /*
0002  * Port for usage with qt-framework and development for kdesvn
0003  * Copyright (C) 2005-2009 by Rajko Albrecht (ral@alwins-world.de)
0004  * http://kdesvn.alwins-world.de
0005  */
0006 /*
0007  * ====================================================================
0008  * Copyright (c) 2002-2005 The RapidSvn Group.  All rights reserved.
0009  * dev@rapidsvn.tigris.org
0010  *
0011  * This library is free software; you can redistribute it and/or
0012  * modify it under the terms of the GNU Lesser General Public
0013  * License as published by the Free Software Foundation; either
0014  * version 2.1 of the License, or (at your option) any later version.
0015  *
0016  * This library is distributed in the hope that it will be useful,
0017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0019  * Lesser General Public License for more details.
0020  *
0021  * You should have received a copy of the GNU Lesser General Public
0022  * License along with this library (in the file LGPL.txt); if not,
0023  * write to the Free Software Foundation, Inc., 51 Franklin St,
0024  * Fifth Floor, Boston, MA  02110-1301  USA
0025  *
0026  * This software consists of voluntary contributions made by many
0027  * individuals.  For exact contribution history, see the revision
0028  * history and logs, available at http://rapidsvn.tigris.org/.
0029  * ====================================================================
0030  */
0031 #if defined( _MSC_VER) && _MSC_VER <= 1200
0032 #pragma warning( disable: 4786 )// debug symbol truncated
0033 #endif
0034 // svncpp
0035 #include "svnqt/client_impl.h"
0036 
0037 // subversion api
0038 #include "svn_client.h"
0039 
0040 #include "svnqt/exception.h"
0041 #include "svnqt/pool.h"
0042 #include "svnqt/targets.h"
0043 #include "svnqt/svnqt_defines.h"
0044 #include "svnqt/stringarray.h"
0045 #include "svnqt/client_parameter.h"
0046 #include "svnqt/client_commit_parameter.h"
0047 #include "svnqt/client_update_parameter.h"
0048 #include "svnqt/url.h"
0049 
0050 #include "svnqt/helper.h"
0051 
0052 #include <QCoreApplication>
0053 
0054 namespace svn
0055 {
0056 struct mBaton {
0057     mBaton(): m_context(), m_revision(Revision::UNDEFINED), m_date(), author(), commit_error(), repos_root() {}
0058     ContextWP m_context;
0059     svn::Revision m_revision;
0060     QString m_date, author, commit_error, repos_root;
0061 };
0062 
0063 static svn_error_t *commit_callback2(const svn_commit_info_t *commit_info, void *baton, apr_pool_t *pool)
0064 {
0065     Q_UNUSED(pool);
0066     mBaton *m_baton = (mBaton *)baton;
0067     ContextP m_context = m_baton->m_context;
0068     if (!m_context) {
0069         return svn_error_create(SVN_ERR_CANCELLED, nullptr, QCoreApplication::translate("svnqt", "Cancelled by user.").toUtf8());
0070     }
0071     svn_client_ctx_t *ctx = m_context->ctx();
0072     if (ctx && ctx->cancel_func) {
0073         SVN_ERR(ctx->cancel_func(ctx->cancel_baton));
0074     }
0075     m_baton->author = QString::fromUtf8(commit_info->author);
0076     m_baton->commit_error = QString::fromUtf8(commit_info->post_commit_err);
0077     m_baton->m_date = QString::fromUtf8(commit_info->date);
0078     m_baton->repos_root = QString::fromUtf8(commit_info->repos_root);
0079     m_baton->m_revision = commit_info->revision;
0080     return SVN_NO_ERROR;
0081 }
0082 
0083 Revision
0084 Client_impl::checkout(const CheckoutParameter &parameters)
0085 {
0086     Pool subPool;
0087     svn_revnum_t revnum = 0;
0088     svn_error_t *error = nullptr;
0089     error = svn_client_checkout3(&revnum,
0090                                  parameters.moduleName().cstr(),
0091                                  parameters.destination().cstr(),
0092                                  parameters.peg().revision(),
0093                                  parameters.revision().revision(),
0094                                  internal::DepthToSvn(parameters.depth()),
0095                                  parameters.ignoreExternals(),
0096                                  parameters.overWrite(),
0097                                  *m_context,
0098                                  subPool);
0099     if (error != nullptr) {
0100         throw ClientException(error);
0101     }
0102     return Revision(revnum);
0103 }
0104 
0105 Revision
0106 Client_impl::remove(const Targets &targets,
0107                     bool force,
0108                     bool keep_local,
0109                     const PropertiesMap &revProps
0110                    )
0111 {
0112     Pool pool;
0113     svn_error_t *error;
0114 
0115     mBaton _baton;
0116     _baton.m_context = m_context;
0117     error = svn_client_delete4(
0118                 targets.array(pool),
0119                 force,
0120                 keep_local,
0121                 map2hash(revProps, pool),
0122                 commit_callback2,
0123                 &_baton,
0124                 *m_context,
0125                 pool
0126             );
0127 
0128     if (error != nullptr) {
0129         throw ClientException(error);
0130     }
0131     return _baton.m_revision;
0132 }
0133 
0134 void
0135 Client_impl::revert(const Targets &targets,
0136                     Depth depth,
0137                     const StringArray &changelist
0138                    )
0139 {
0140     Pool pool;
0141 
0142     svn_error_t *error =
0143         svn_client_revert2((targets.array(pool)),
0144                            internal::DepthToSvn(depth),
0145                            changelist.array(pool),
0146                            *m_context,
0147                            pool);
0148     if (error != nullptr) {
0149         throw ClientException(error);
0150     }
0151 }
0152 
0153 void
0154 Client_impl::add(const Path &path,
0155                  svn::Depth depth, bool force, bool no_ignore, bool add_parents)
0156 {
0157     Pool pool;
0158     // todo svn 1.8: svn_client_add5
0159     svn_error_t *error =
0160         svn_client_add4(path.cstr(),
0161                         internal::DepthToSvn(depth),
0162                         force,
0163                         no_ignore,
0164                         add_parents,
0165                         *m_context,
0166                         pool);
0167     if (error != nullptr) {
0168         throw ClientException(error);
0169     }
0170 }
0171 
0172 Revisions
0173 Client_impl::update(const UpdateParameter &params)
0174 {
0175     Pool pool;
0176     Revisions resulting;
0177     svn_error_t *error;
0178 
0179     apr_pool_t *apr_pool = pool.pool();
0180     apr_array_header_t *apr_revisions = apr_array_make(apr_pool,
0181                                                        params.targets().size(),
0182                                                        sizeof(svn_revnum_t));
0183     error = svn_client_update4(&apr_revisions, params.targets().array(pool), params.revision(),
0184                                internal::DepthToSvn(params.depth()), params.sticky_depth(),
0185                                params.ignore_externals(), params.allow_unversioned(),
0186                                params.add_as_modification(), params.make_parents(),
0187                                *m_context, pool
0188                               );
0189 
0190     if (error != nullptr) {
0191         throw ClientException(error);
0192     }
0193     for (int i = 0; i < apr_revisions->nelts; ++i) {
0194         svn_revnum_t *_rev =
0195             &APR_ARRAY_IDX(apr_revisions, i, svn_revnum_t);
0196 
0197         resulting.push_back((*_rev));
0198     }
0199     return resulting;
0200 }
0201 
0202 svn::Revision
0203 Client_impl::commit(const CommitParameter &parameters)
0204 {
0205     Pool pool;
0206 
0207     mBaton _baton;
0208     _baton.m_context = m_context;
0209     m_context->setLogMessage(parameters.message());
0210     svn_error_t *error =
0211 #if SVN_API_VERSION >= SVN_VERSION_CHECK(1,8,0)
0212         svn_client_commit6(
0213 #else
0214         svn_client_commit5(
0215 #endif
0216             parameters.targets().array(pool),
0217             internal::DepthToSvn(parameters.depth()),
0218             parameters.keepLocks(),
0219             parameters.keepChangeList(),
0220             parameters.commitAsOperations(),
0221 #if SVN_API_VERSION >= SVN_VERSION_CHECK(1,8,0)
0222             false, /* file externals */
0223             false, /* dir externals */
0224 #endif
0225             parameters.changeList().array(pool),
0226             map2hash(parameters.revisionProperties(), pool),
0227             commit_callback2,
0228             &_baton,
0229             *m_context,
0230             pool
0231         );
0232 
0233     if (error != nullptr) {
0234         throw ClientException(error);
0235     }
0236     return _baton.m_revision;
0237 }
0238 
0239 Revision
0240 Client_impl::copy(const CopyParameter &parameter)
0241 {
0242     if (parameter.srcPath().size() < 1) {
0243         throw ClientException("Wrong size of sources.");
0244     }
0245 
0246     Pool pool;
0247     apr_array_header_t *sources = apr_array_make(pool, parameter.srcPath().size(), sizeof(svn_client_copy_source_t *));
0248     // not using .array() 'cause some extra information is needed for copy
0249     for (const Path &path : parameter.srcPath().targets()) {
0250         svn_client_copy_source_t *source = (svn_client_copy_source_t *)apr_palloc(pool, sizeof(svn_client_copy_source_t));
0251         source->path = apr_pstrdup(pool, path.path().toUtf8());
0252         source->revision = parameter.srcRevision().revision();
0253         source->peg_revision = parameter.pegRevision().revision();
0254         APR_ARRAY_PUSH(sources, svn_client_copy_source_t *) = source;
0255     }
0256     mBaton _baton;
0257     _baton.m_context = m_context;
0258 
0259     svn_error_t *error =
0260         svn_client_copy6(
0261             sources,
0262             parameter.destination().cstr(),
0263             parameter.asChild(), parameter.makeParent(), parameter.ignoreExternal(),
0264             map2hash(parameter.properties(), pool),
0265             commit_callback2, &_baton,
0266             *m_context, pool);
0267 
0268     if (error != nullptr) {
0269         throw ClientException(error);
0270     }
0271     return _baton.m_revision;
0272 }
0273 
0274 Revision
0275 Client_impl::copy(const Path &srcPath,
0276                   const Revision &srcRevision,
0277                   const Path &destPath)
0278 {
0279     return copy(CopyParameter(srcPath, destPath).srcRevision(srcRevision).asChild(true).makeParent(false));
0280 }
0281 
0282 svn::Revision Client_impl::move(const CopyParameter &parameter)
0283 {
0284     Pool pool;
0285 
0286     // todo svn 1.8: svn_client_move7
0287     mBaton _baton;
0288     _baton.m_context = m_context;
0289     svn_error_t *error = svn_client_move6(
0290                              parameter.srcPath().array(pool),
0291                              parameter.destination().cstr(),
0292                              parameter.asChild(),
0293                              parameter.makeParent(),
0294                              map2hash(parameter.properties(), pool),
0295                              commit_callback2,
0296                              &_baton,
0297                              *m_context,
0298                              pool
0299                          );
0300 
0301     if (error != nullptr) {
0302         throw ClientException(error);
0303     }
0304     return _baton.m_revision;
0305 
0306 }
0307 
0308 svn::Revision
0309 Client_impl::mkdir(const Targets &targets,
0310                    const QString &msg,
0311                    bool makeParent,
0312                    const PropertiesMap &revProps
0313                   )
0314 {
0315     Pool pool;
0316     m_context->setLogMessage(msg);
0317 
0318 
0319 
0320     svn_error_t *error = nullptr;
0321     mBaton _baton;
0322     _baton.m_context = m_context;
0323     error = svn_client_mkdir4
0324             (
0325                 const_cast<apr_array_header_t *>(targets.array(pool)),
0326                 makeParent,
0327                 map2hash(revProps, pool),
0328                 commit_callback2, &_baton,
0329                 *m_context, pool
0330             );
0331     /* important! otherwise next op on repository uses that logmessage again! */
0332     m_context->setLogMessage(QString());
0333 
0334     if (error != nullptr) {
0335         throw ClientException(error);
0336     }
0337 
0338     return _baton.m_revision;
0339 }
0340 
0341 void
0342 Client_impl::cleanup(const Path &path)
0343 {
0344     Pool subPool;
0345     apr_pool_t *apr_pool = subPool.pool();
0346 
0347     svn_error_t *error =
0348         svn_client_cleanup(path.cstr(), *m_context, apr_pool);
0349 
0350     if (error != nullptr) {
0351         throw ClientException(error);
0352     }
0353 }
0354 
0355 void Client_impl::resolve(const Path &path, Depth depth, const ConflictResult &resolution)
0356 {
0357     Pool pool;
0358     const svn_wc_conflict_result_t *aResult = resolution.result(pool);
0359     svn_error_t *error = svn_client_resolve(path.cstr(), internal::DepthToSvn(depth), aResult->choice, *m_context, pool);
0360 
0361     if (error != nullptr) {
0362         throw ClientException(error);
0363     }
0364 }
0365 
0366 Revision
0367 Client_impl::doExport(const CheckoutParameter &params)
0368 {
0369     Pool pool;
0370     svn_revnum_t revnum = 0;
0371     QByteArray _neolBA;
0372     const char *_neol;
0373     if (params.nativeEol().isNull()) {
0374         _neol = nullptr;
0375     } else {
0376         _neolBA = params.nativeEol().toUtf8();
0377         _neol = _neolBA.constData();
0378     }
0379     svn_error_t *error =
0380         svn_client_export5(
0381                            &revnum,
0382                            params.moduleName().cstr(),
0383                            params.destination().cstr(),
0384                            params.peg().revision(),
0385                            params.revision().revision(),
0386                            params.overWrite(),
0387                            params.ignoreExternals(),
0388                            params.ignoreKeywords(),
0389                            internal::DepthToSvn(params.depth()),
0390                            _neol,
0391                            *m_context,
0392                            pool);
0393     if (error != nullptr) {
0394         throw ClientException(error);
0395     }
0396     return Revision(revnum);
0397 }
0398 
0399 Revision
0400 Client_impl::doSwitch(
0401     const Path &path,
0402     const Url &url,
0403     const Revision &revision,
0404     Depth depth,
0405     const Revision &peg,
0406     bool sticky_depth,
0407     bool ignore_externals,
0408     bool allow_unversioned,
0409     bool ignore_ancestry
0410 )
0411 {
0412     Pool pool;
0413     svn_revnum_t revnum = 0;
0414     svn_error_t *error = svn_client_switch3(
0415                 &revnum,
0416                 path.cstr(),
0417                 url.cstr(),
0418                 peg.revision(),
0419                 revision.revision(),
0420                 internal::DepthToSvn(depth),
0421                 sticky_depth,
0422                 ignore_externals,
0423                 allow_unversioned,
0424                 ignore_ancestry,
0425                 *m_context,
0426                 pool
0427             );
0428     if (error != nullptr) {
0429         throw ClientException(error);
0430     }
0431     return Revision(revnum);
0432 }
0433 
0434 Revision
0435 Client_impl::import(const Path &path,
0436                     const Url &importRepository,
0437                     const QString &message,
0438                     svn::Depth depth,
0439                     bool no_ignore, bool no_unknown_nodetype,
0440                     const PropertiesMap &revProps
0441                    )
0442 
0443 {
0444     Pool pool;
0445 
0446     m_context->setLogMessage(message);
0447     // todo svn 1.8: svn_client_import5
0448     mBaton _baton;
0449     _baton.m_context = m_context;
0450     svn_error_t *error =
0451         svn_client_import4(path.cstr(),
0452                            importRepository.cstr(),
0453                            internal::DepthToSvn(depth), no_ignore, no_unknown_nodetype,
0454                            map2hash(revProps, pool),
0455                            commit_callback2, &_baton,
0456                            *m_context, pool);
0457 
0458     /* important! otherwise next op on repository uses that logmessage again! */
0459     m_context->setLogMessage(QString());
0460 
0461     if (error != nullptr) {
0462         throw ClientException(error);
0463     }
0464     return _baton.m_revision;
0465 }
0466 
0467 void
0468 Client_impl::relocate(const Path &path,
0469                       const Url &from_url,
0470                       const Url &to_url,
0471                       bool recurse,
0472                       bool ignore_externals)
0473 {
0474     Q_UNUSED(recurse);
0475     Pool pool;
0476     svn_error_t *error =
0477         svn_client_relocate2(path.cstr(),
0478                              from_url.cstr(),
0479                              to_url.cstr(),
0480                              ignore_externals,
0481                              *m_context,
0482                              pool);
0483 
0484     if (error != nullptr) {
0485         throw ClientException(error);
0486     }
0487 }
0488 
0489 }
0490 
0491 /* -----------------------------------------------------------------
0492  * local variables:
0493  * eval: (load-file "../../rapidsvn-dev.el")
0494  * end:
0495  */