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 0032 // svncpp 0033 #include "client_impl.h" 0034 #include "helper.h" 0035 0036 // Subversion api 0037 #include <svn_client.h> 0038 #include <svn_path.h> 0039 #include <svn_sorts.h> 0040 0041 #include "client_parameter.h" 0042 #include "context_listener.h" 0043 #include "dirent.h" 0044 #include "exception.h" 0045 #include "info_entry.h" 0046 #include "pool.h" 0047 #include "status.h" 0048 #include "svnqt_defines.h" 0049 #include "targets.h" 0050 #include "url.h" 0051 #include <QCoreApplication> 0052 0053 namespace svn 0054 { 0055 0056 struct LogBaton { 0057 ContextWP context; 0058 LogEntriesMap *logEntries; 0059 QList<qlonglong> *revstack; 0060 StringArray excludeList; 0061 LogBaton() 0062 : logEntries(nullptr) 0063 , revstack(nullptr) 0064 { 0065 } 0066 }; 0067 0068 struct StatusEntriesBaton { 0069 StatusEntries entries; 0070 apr_pool_t *pool; 0071 ContextWP m_Context; 0072 StatusEntriesBaton() 0073 : entries() 0074 , pool(nullptr) 0075 { 0076 } 0077 }; 0078 0079 struct InfoEntriesBaton { 0080 InfoEntries entries; 0081 apr_pool_t *pool; 0082 ContextWP m_Context; 0083 InfoEntriesBaton() 0084 : entries() 0085 , pool(nullptr) 0086 { 0087 } 0088 }; 0089 0090 static svn_error_t *logMapReceiver2(void *baton, svn_log_entry_t *log_entry, apr_pool_t *pool) 0091 { 0092 Q_UNUSED(pool); 0093 LogBaton *l_baton = static_cast<LogBaton *>(baton); 0094 ContextP l_context = l_baton->context; 0095 if (l_context.isNull()) { 0096 return SVN_NO_ERROR; 0097 } 0098 svn_client_ctx_t *ctx = l_context->ctx(); 0099 if (ctx && ctx->cancel_func) { 0100 SVN_ERR(ctx->cancel_func(ctx->cancel_baton)); 0101 } 0102 QList<qlonglong> *rstack = l_baton->revstack; 0103 if (!SVN_IS_VALID_REVNUM(log_entry->revision)) { 0104 if (rstack && !rstack->isEmpty()) { 0105 rstack->pop_front(); 0106 } 0107 return SVN_NO_ERROR; 0108 } 0109 LogEntriesMap *entries = l_baton->logEntries; 0110 (*entries)[log_entry->revision] = LogEntry(log_entry, l_baton->excludeList); 0111 /// @TODO insert it into last logentry 0112 if (rstack) { 0113 (*entries)[log_entry->revision].m_MergedInRevisions = (*rstack); 0114 if (log_entry->has_children) { 0115 rstack->push_front(log_entry->revision); 0116 } 0117 } 0118 return SVN_NO_ERROR; 0119 } 0120 0121 static svn_error_t *InfoEntryFunc(void *baton, const char *path, const svn_client_info2_t *info, apr_pool_t *) 0122 { 0123 InfoEntriesBaton *seb = static_cast<InfoEntriesBaton *>(baton); 0124 if (seb->m_Context) { 0125 /* check every loop for cancel of operation */ 0126 ContextP l_context = seb->m_Context; 0127 if (!l_context) { 0128 return svn_error_create(SVN_ERR_CANCELLED, nullptr, QCoreApplication::translate("svnqt", "Cancelled by user.").toUtf8()); 0129 } 0130 svn_client_ctx_t *ctx = l_context->ctx(); 0131 if (ctx && ctx->cancel_func) { 0132 SVN_ERR(ctx->cancel_func(ctx->cancel_baton)); 0133 } 0134 } 0135 seb->entries.push_back(InfoEntry(info, path)); 0136 return nullptr; 0137 } 0138 0139 static svn_error_t *StatusEntriesFunc(void *baton, const char *path, const svn_client_status_t *status, apr_pool_t *pool) 0140 { 0141 // use own pool - the parameter will cleared between loops! 0142 Q_UNUSED(pool); 0143 StatusEntriesBaton *seb = static_cast<StatusEntriesBaton *>(baton); 0144 if (seb->m_Context) { 0145 /* check every loop for cancel of operation */ 0146 ContextP l_context = seb->m_Context; 0147 if (!l_context) { 0148 return svn_error_create(SVN_ERR_CANCELLED, nullptr, QCoreApplication::translate("svnqt", "Cancelled by user.").toUtf8()); 0149 } 0150 svn_client_ctx_t *ctx = l_context->ctx(); 0151 if (ctx && ctx->cancel_func) { 0152 SVN_ERR(ctx->cancel_func(ctx->cancel_baton)); 0153 } 0154 } 0155 0156 seb->entries.push_back(StatusPtr(new Status(path, status))); 0157 return nullptr; 0158 } 0159 0160 static StatusEntries localStatus(const StatusParameter ¶ms, const ContextP &context) 0161 { 0162 svn_error_t *error; 0163 svn_revnum_t revnum; 0164 Revision rev(Revision::HEAD); 0165 Pool pool; 0166 StatusEntriesBaton baton; 0167 0168 baton.pool = pool; 0169 0170 error = svn_client_status5(&revnum, 0171 *context, 0172 params.path().path().toUtf8(), 0173 rev, 0174 internal::DepthToSvn(params.depth()), // see svn::Depth 0175 params.all(), // get all not only interesting 0176 params.update(), // check for updates 0177 params.noIgnore(), // hide ignored files or not 0178 params.ignoreExternals(), // hide external 0179 true, // depth as sticky - TODO 0180 params.changeList().array(pool), 0181 StatusEntriesFunc, 0182 &baton, 0183 pool); 0184 0185 Client_impl::checkErrorThrow(error); 0186 return baton.entries; 0187 } 0188 0189 static StatusPtr dirEntryToStatus(const Path &path, const DirEntry &dirEntry) 0190 { 0191 QString url = path.path() + QLatin1Char('/') + dirEntry.name(); 0192 return StatusPtr(new Status(url, dirEntry)); 0193 } 0194 0195 static StatusPtr infoEntryToStatus(const Path &, const InfoEntry &infoEntry) 0196 { 0197 return StatusPtr(new Status(infoEntry.url().toString(), infoEntry)); 0198 } 0199 0200 static StatusEntries remoteStatus(Client *client, const StatusParameter ¶ms, const ContextP &) 0201 { 0202 const DirEntries dirEntries = client->list(params.path(), params.revision(), params.revision(), params.depth(), params.detailedRemote()); 0203 0204 StatusEntries entries; 0205 for (const DirEntry &dirEntry : dirEntries) { 0206 if (dirEntry.name().isEmpty()) { 0207 continue; 0208 } 0209 entries.push_back(dirEntryToStatus(params.path(), dirEntry)); 0210 } 0211 return entries; 0212 } 0213 0214 StatusEntries Client_impl::status(const StatusParameter ¶ms) 0215 { 0216 if (Url::isValid(params.path().path())) { 0217 return remoteStatus(this, params, m_context); 0218 } 0219 return localStatus(params, m_context); 0220 } 0221 0222 static StatusPtr localSingleStatus(const Path &path, const ContextP &context, bool update = false) 0223 { 0224 svn_error_t *error; 0225 Pool pool; 0226 StatusEntriesBaton baton; 0227 svn_revnum_t revnum; 0228 Revision rev(Revision::HEAD); 0229 0230 baton.pool = pool; 0231 0232 error = svn_client_status5(&revnum, 0233 *context, 0234 path.path().toUtf8(), 0235 rev, 0236 svn_depth_empty, // not recurse 0237 true, // get all not only interesting 0238 update, // check for updates 0239 false, // hide ignored files or not 0240 false, // hide external 0241 true, // depth as sticky 0242 nullptr, 0243 StatusEntriesFunc, 0244 &baton, 0245 pool); 0246 0247 Client_impl::checkErrorThrow(error); 0248 if (baton.entries.isEmpty()) { 0249 return StatusPtr(new Status()); 0250 } 0251 0252 return baton.entries.at(0); 0253 } 0254 0255 static StatusPtr remoteSingleStatus(Client *client, const Path &path, const Revision &revision, const ContextP &) 0256 { 0257 const InfoEntries infoEntries = client->info(path, DepthEmpty, revision, Revision(Revision::UNDEFINED)); 0258 if (infoEntries.isEmpty()) { 0259 return StatusPtr(new Status()); 0260 } 0261 return infoEntryToStatus(path, infoEntries.at(0)); 0262 } 0263 0264 StatusPtr Client_impl::singleStatus(const Path &path, bool update, const Revision &revision) 0265 { 0266 if (Url::isValid(path.path())) { 0267 return remoteSingleStatus(this, path, revision, m_context); 0268 } 0269 return localSingleStatus(path, m_context, update); 0270 } 0271 0272 bool Client_impl::log(const LogParameter ¶ms, LogEntriesMap &log_target) 0273 { 0274 Pool pool; 0275 LogBaton l_baton; 0276 QList<qlonglong> revstack; 0277 l_baton.context = m_context; 0278 l_baton.excludeList = params.excludeList(); 0279 l_baton.logEntries = &log_target; 0280 l_baton.revstack = &revstack; 0281 svn_error_t *error; 0282 0283 error = svn_client_log5(params.targets().array(pool), 0284 params.peg().revision(), 0285 svn::internal::RevisionRangesToHash(params.revisions()).array(pool), 0286 params.limit(), 0287 params.discoverChangedPathes() ? 1 : 0, 0288 params.strictNodeHistory() ? 1 : 0, 0289 params.includeMergedRevisions() ? 1 : 0, 0290 params.revisionProperties().array(pool), 0291 logMapReceiver2, 0292 &l_baton, 0293 *m_context, // client ctx 0294 pool); 0295 checkErrorThrow(error); 0296 return true; 0297 } 0298 0299 InfoEntries Client_impl::info(const Path &_p, Depth depth, const Revision &rev, const Revision &peg_revision, const StringArray &changelists) 0300 { 0301 Pool pool; 0302 svn_error_t *error = nullptr; 0303 InfoEntriesBaton baton; 0304 0305 baton.pool = pool; 0306 baton.m_Context = m_context; 0307 svn_opt_revision_t pegr; 0308 const char *truepath = nullptr; 0309 bool internal_peg = false; 0310 QByteArray _buf = _p.cstr(); 0311 0312 error = svn_opt_parse_path(&pegr, &truepath, _buf, pool); 0313 checkErrorThrow(error); 0314 if (!truepath) { 0315 throw ClientException("no path given!"); 0316 } 0317 if (peg_revision.kind() == svn_opt_revision_unspecified) { 0318 if ((svn_path_is_url(_p.cstr())) && (pegr.kind == svn_opt_revision_unspecified)) { 0319 pegr.kind = svn_opt_revision_head; 0320 internal_peg = true; 0321 } 0322 } 0323 0324 error = svn_client_info3(truepath, 0325 internal_peg ? &pegr : peg_revision.revision(), 0326 rev.revision(), 0327 internal::DepthToSvn(depth), 0328 false, // TODO parameter for fetch exclueded 0329 false, // TODO parameter for fetch_actual_only 0330 changelists.array(pool), 0331 &InfoEntryFunc, 0332 &baton, 0333 *m_context, 0334 pool); 0335 0336 checkErrorThrow(error); 0337 return baton.entries; 0338 } 0339 } 0340 0341 /* ----------------------------------------------------------------- 0342 * local variables: 0343 * eval: (load-file "../../rapidsvn-dev.el") 0344 * end: 0345 */