File indexing completed on 2024-04-28 05:42: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  * https://kde.org/applications/development/org.kde.kdesvn
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/client_commit_parameter.h"
0041 #include "svnqt/client_parameter.h"
0042 #include "svnqt/client_update_parameter.h"
0043 #include "svnqt/exception.h"
0044 #include "svnqt/pool.h"
0045 #include "svnqt/stringarray.h"
0046 #include "svnqt/svnqt_defines.h"
0047 #include "svnqt/targets.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()
0058         : m_context()
0059         , m_revision(Revision::UNDEFINED)
0060         , m_date()
0061         , author()
0062         , commit_error()
0063         , repos_root()
0064     {
0065     }
0066     ContextWP m_context;
0067     svn::Revision m_revision;
0068     QString m_date, author, commit_error, repos_root;
0069 };
0070 
0071 static svn_error_t *commit_callback2(const svn_commit_info_t *commit_info, void *baton, apr_pool_t *pool)
0072 {
0073     Q_UNUSED(pool);
0074     mBaton *m_baton = (mBaton *)baton;
0075     ContextP m_context = m_baton->m_context;
0076     if (!m_context) {
0077         return svn_error_create(SVN_ERR_CANCELLED, nullptr, QCoreApplication::translate("svnqt", "Cancelled by user.").toUtf8());
0078     }
0079     svn_client_ctx_t *ctx = m_context->ctx();
0080     if (ctx && ctx->cancel_func) {
0081         SVN_ERR(ctx->cancel_func(ctx->cancel_baton));
0082     }
0083     m_baton->author = QString::fromUtf8(commit_info->author);
0084     m_baton->commit_error = QString::fromUtf8(commit_info->post_commit_err);
0085     m_baton->m_date = QString::fromUtf8(commit_info->date);
0086     m_baton->repos_root = QString::fromUtf8(commit_info->repos_root);
0087     m_baton->m_revision = commit_info->revision;
0088     return SVN_NO_ERROR;
0089 }
0090 
0091 Revision Client_impl::checkout(const CheckoutParameter &parameters)
0092 {
0093     Pool subPool;
0094     svn_revnum_t revnum = 0;
0095     svn_error_t *error = nullptr;
0096     error = svn_client_checkout3(&revnum,
0097                                  parameters.moduleName().cstr(),
0098                                  parameters.destination().cstr(),
0099                                  parameters.peg().revision(),
0100                                  parameters.revision().revision(),
0101                                  internal::DepthToSvn(parameters.depth()),
0102                                  parameters.ignoreExternals(),
0103                                  parameters.overWrite(),
0104                                  *m_context,
0105                                  subPool);
0106     if (error != nullptr) {
0107         throw ClientException(error);
0108     }
0109     return Revision(revnum);
0110 }
0111 
0112 Revision Client_impl::remove(const Targets &targets, bool force, bool keep_local, const PropertiesMap &revProps)
0113 {
0114     Pool pool;
0115     svn_error_t *error;
0116 
0117     mBaton _baton;
0118     _baton.m_context = m_context;
0119     error = svn_client_delete4(targets.array(pool), force, keep_local, map2hash(revProps, pool), commit_callback2, &_baton, *m_context, pool);
0120 
0121     if (error != nullptr) {
0122         throw ClientException(error);
0123     }
0124     return _baton.m_revision;
0125 }
0126 
0127 void Client_impl::revert(const Targets &targets, Depth depth, const StringArray &changelist)
0128 {
0129     Pool pool;
0130 
0131     svn_error_t *error = svn_client_revert2((targets.array(pool)), internal::DepthToSvn(depth), changelist.array(pool), *m_context, pool);
0132     if (error != nullptr) {
0133         throw ClientException(error);
0134     }
0135 }
0136 
0137 void Client_impl::add(const Path &path, svn::Depth depth, bool force, bool no_ignore, bool add_parents)
0138 {
0139     Pool pool;
0140     // todo svn 1.8: svn_client_add5
0141     svn_error_t *error = svn_client_add4(path.cstr(), internal::DepthToSvn(depth), force, no_ignore, add_parents, *m_context, pool);
0142     if (error != nullptr) {
0143         throw ClientException(error);
0144     }
0145 }
0146 
0147 Revisions Client_impl::update(const UpdateParameter &params)
0148 {
0149     Pool pool;
0150     Revisions resulting;
0151     svn_error_t *error;
0152 
0153     apr_pool_t *apr_pool = pool.pool();
0154     apr_array_header_t *apr_revisions = apr_array_make(apr_pool, params.targets().size(), sizeof(svn_revnum_t));
0155     error = svn_client_update4(&apr_revisions,
0156                                params.targets().array(pool),
0157                                params.revision(),
0158                                internal::DepthToSvn(params.depth()),
0159                                params.sticky_depth(),
0160                                params.ignore_externals(),
0161                                params.allow_unversioned(),
0162                                params.add_as_modification(),
0163                                params.make_parents(),
0164                                *m_context,
0165                                pool);
0166 
0167     if (error != nullptr) {
0168         throw ClientException(error);
0169     }
0170     for (int i = 0; i < apr_revisions->nelts; ++i) {
0171         svn_revnum_t *_rev = &APR_ARRAY_IDX(apr_revisions, i, svn_revnum_t);
0172 
0173         resulting.push_back((*_rev));
0174     }
0175     return resulting;
0176 }
0177 
0178 svn::Revision Client_impl::commit(const CommitParameter &parameters)
0179 {
0180     Pool pool;
0181 
0182     mBaton _baton;
0183     _baton.m_context = m_context;
0184     m_context->setLogMessage(parameters.message());
0185     svn_error_t *error =
0186 #if SVN_API_VERSION >= SVN_VERSION_CHECK(1, 8, 0)
0187         svn_client_commit6(
0188 #else
0189         svn_client_commit5(
0190 #endif
0191             parameters.targets().array(pool),
0192             internal::DepthToSvn(parameters.depth()),
0193             parameters.keepLocks(),
0194             parameters.keepChangeList(),
0195             parameters.commitAsOperations(),
0196 #if SVN_API_VERSION >= SVN_VERSION_CHECK(1, 8, 0)
0197             false, /* file externals */
0198             false, /* dir externals */
0199 #endif
0200             parameters.changeList().array(pool),
0201             map2hash(parameters.revisionProperties(), pool),
0202             commit_callback2,
0203             &_baton,
0204             *m_context,
0205             pool);
0206 
0207     if (error != nullptr) {
0208         throw ClientException(error);
0209     }
0210     return _baton.m_revision;
0211 }
0212 
0213 Revision Client_impl::copy(const CopyParameter &parameter)
0214 {
0215     if (parameter.srcPath().size() < 1) {
0216         throw ClientException("Wrong size of sources.");
0217     }
0218 
0219     Pool pool;
0220     apr_array_header_t *sources = apr_array_make(pool, parameter.srcPath().size(), sizeof(svn_client_copy_source_t *));
0221     // not using .array() 'cause some extra information is needed for copy
0222     for (const Path &path : parameter.srcPath().targets()) {
0223         svn_client_copy_source_t *source = (svn_client_copy_source_t *)apr_palloc(pool, sizeof(svn_client_copy_source_t));
0224         source->path = apr_pstrdup(pool, path.path().toUtf8());
0225         source->revision = parameter.srcRevision().revision();
0226         source->peg_revision = parameter.pegRevision().revision();
0227         APR_ARRAY_PUSH(sources, svn_client_copy_source_t *) = source;
0228     }
0229     mBaton _baton;
0230     _baton.m_context = m_context;
0231 
0232     svn_error_t *error = svn_client_copy6(sources,
0233                                           parameter.destination().cstr(),
0234                                           parameter.asChild(),
0235                                           parameter.makeParent(),
0236                                           parameter.ignoreExternal(),
0237                                           map2hash(parameter.properties(), pool),
0238                                           commit_callback2,
0239                                           &_baton,
0240                                           *m_context,
0241                                           pool);
0242 
0243     if (error != nullptr) {
0244         throw ClientException(error);
0245     }
0246     return _baton.m_revision;
0247 }
0248 
0249 Revision Client_impl::copy(const Path &srcPath, const Revision &srcRevision, const Path &destPath)
0250 {
0251     return copy(CopyParameter(srcPath, destPath).srcRevision(srcRevision).asChild(true).makeParent(false));
0252 }
0253 
0254 svn::Revision Client_impl::move(const CopyParameter &parameter)
0255 {
0256     Pool pool;
0257 
0258     // todo svn 1.8: svn_client_move7
0259     mBaton _baton;
0260     _baton.m_context = m_context;
0261     svn_error_t *error = svn_client_move6(parameter.srcPath().array(pool),
0262                                           parameter.destination().cstr(),
0263                                           parameter.asChild(),
0264                                           parameter.makeParent(),
0265                                           map2hash(parameter.properties(), pool),
0266                                           commit_callback2,
0267                                           &_baton,
0268                                           *m_context,
0269                                           pool);
0270 
0271     if (error != nullptr) {
0272         throw ClientException(error);
0273     }
0274     return _baton.m_revision;
0275 }
0276 
0277 svn::Revision Client_impl::mkdir(const Targets &targets, const QString &msg, bool makeParent, const PropertiesMap &revProps)
0278 {
0279     Pool pool;
0280     m_context->setLogMessage(msg);
0281 
0282     svn_error_t *error = nullptr;
0283     mBaton _baton;
0284     _baton.m_context = m_context;
0285     error = svn_client_mkdir4(const_cast<apr_array_header_t *>(targets.array(pool)),
0286                               makeParent,
0287                               map2hash(revProps, pool),
0288                               commit_callback2,
0289                               &_baton,
0290                               *m_context,
0291                               pool);
0292     /* important! otherwise next op on repository uses that logmessage again! */
0293     m_context->setLogMessage(QString());
0294 
0295     if (error != nullptr) {
0296         throw ClientException(error);
0297     }
0298 
0299     return _baton.m_revision;
0300 }
0301 
0302 void Client_impl::cleanup(const Path &path)
0303 {
0304     Pool subPool;
0305     apr_pool_t *apr_pool = subPool.pool();
0306 
0307     svn_error_t *error = svn_client_cleanup(path.cstr(), *m_context, apr_pool);
0308 
0309     if (error != nullptr) {
0310         throw ClientException(error);
0311     }
0312 }
0313 
0314 void Client_impl::resolve(const Path &path, Depth depth, const ConflictResult &resolution)
0315 {
0316     Pool pool;
0317     const svn_wc_conflict_result_t *aResult = resolution.result(pool);
0318     svn_error_t *error = svn_client_resolve(path.cstr(), internal::DepthToSvn(depth), aResult->choice, *m_context, pool);
0319 
0320     if (error != nullptr) {
0321         throw ClientException(error);
0322     }
0323 }
0324 
0325 Revision Client_impl::doExport(const CheckoutParameter &params)
0326 {
0327     Pool pool;
0328     svn_revnum_t revnum = 0;
0329     QByteArray _neolBA;
0330     const char *_neol;
0331     if (params.nativeEol().isNull()) {
0332         _neol = nullptr;
0333     } else {
0334         _neolBA = params.nativeEol().toUtf8();
0335         _neol = _neolBA.constData();
0336     }
0337     svn_error_t *error = svn_client_export5(&revnum,
0338                                             params.moduleName().cstr(),
0339                                             params.destination().cstr(),
0340                                             params.peg().revision(),
0341                                             params.revision().revision(),
0342                                             params.overWrite(),
0343                                             params.ignoreExternals(),
0344                                             params.ignoreKeywords(),
0345                                             internal::DepthToSvn(params.depth()),
0346                                             _neol,
0347                                             *m_context,
0348                                             pool);
0349     if (error != nullptr) {
0350         throw ClientException(error);
0351     }
0352     return Revision(revnum);
0353 }
0354 
0355 Revision Client_impl::doSwitch(const Path &path,
0356                                const Url &url,
0357                                const Revision &revision,
0358                                Depth depth,
0359                                const Revision &peg,
0360                                bool sticky_depth,
0361                                bool ignore_externals,
0362                                bool allow_unversioned,
0363                                bool ignore_ancestry)
0364 {
0365     Pool pool;
0366     svn_revnum_t revnum = 0;
0367     svn_error_t *error = svn_client_switch3(&revnum,
0368                                             path.cstr(),
0369                                             url.cstr(),
0370                                             peg.revision(),
0371                                             revision.revision(),
0372                                             internal::DepthToSvn(depth),
0373                                             sticky_depth,
0374                                             ignore_externals,
0375                                             allow_unversioned,
0376                                             ignore_ancestry,
0377                                             *m_context,
0378                                             pool);
0379     if (error != nullptr) {
0380         throw ClientException(error);
0381     }
0382     return Revision(revnum);
0383 }
0384 
0385 Revision Client_impl::import(const Path &path,
0386                              const Url &importRepository,
0387                              const QString &message,
0388                              svn::Depth depth,
0389                              bool no_ignore,
0390                              bool no_unknown_nodetype,
0391                              const PropertiesMap &revProps)
0392 
0393 {
0394     Pool pool;
0395 
0396     m_context->setLogMessage(message);
0397     // todo svn 1.8: svn_client_import5
0398     mBaton _baton;
0399     _baton.m_context = m_context;
0400     svn_error_t *error = svn_client_import4(path.cstr(),
0401                                             importRepository.cstr(),
0402                                             internal::DepthToSvn(depth),
0403                                             no_ignore,
0404                                             no_unknown_nodetype,
0405                                             map2hash(revProps, pool),
0406                                             commit_callback2,
0407                                             &_baton,
0408                                             *m_context,
0409                                             pool);
0410 
0411     /* important! otherwise next op on repository uses that logmessage again! */
0412     m_context->setLogMessage(QString());
0413 
0414     if (error != nullptr) {
0415         throw ClientException(error);
0416     }
0417     return _baton.m_revision;
0418 }
0419 
0420 void Client_impl::relocate(const Path &path, const Url &from_url, const Url &to_url, bool recurse, bool ignore_externals)
0421 {
0422     Q_UNUSED(recurse);
0423     Pool pool;
0424     svn_error_t *error = svn_client_relocate2(path.cstr(), from_url.cstr(), to_url.cstr(), ignore_externals, *m_context, pool);
0425 
0426     if (error != nullptr) {
0427         throw ClientException(error);
0428     }
0429 }
0430 
0431 }
0432 
0433 /* -----------------------------------------------------------------
0434  * local variables:
0435  * eval: (load-file "../../rapidsvn-dev.el")
0436  * end:
0437  */