| /** |
| * @copyright |
| * ==================================================================== |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * ==================================================================== |
| * @endcopyright |
| * |
| * @file SVNClient.cpp |
| * @brief: Implementation of the SVNClient class |
| */ |
| |
| #include <vector> |
| #include <iostream> |
| #include <sstream> |
| #include <string> |
| |
| #include "SVNClient.h" |
| #include "JNIUtil.h" |
| #include "CopySources.h" |
| #include "DiffSummaryReceiver.h" |
| #include "ClientContext.h" |
| #include "Prompter.h" |
| #include "RemoteSession.h" |
| #include "Pool.h" |
| #include "Targets.h" |
| #include "Revision.h" |
| #include "OutputStream.h" |
| #include "RevisionRange.h" |
| #include "VersionExtended.h" |
| #include "BlameCallback.h" |
| #include "ProplistCallback.h" |
| #include "LogMessageCallback.h" |
| #include "InfoCallback.h" |
| #include "PatchCallback.h" |
| #include "CommitCallback.h" |
| #include "StatusCallback.h" |
| #include "ChangelistCallback.h" |
| #include "ListCallback.h" |
| #include "ImportFilterCallback.h" |
| #include "JNIByteArray.h" |
| #include "CommitMessage.h" |
| #include "EnumMapper.h" |
| #include "StringArray.h" |
| #include "PropertyTable.h" |
| #include "DiffOptions.h" |
| #include "CreateJ.h" |
| #include "JNIStringHolder.h" |
| |
| #include "svn_auth.h" |
| #include "svn_dso.h" |
| #include "svn_types.h" |
| #include "svn_client.h" |
| #include "svn_sorts.h" |
| #include "svn_time.h" |
| #include "svn_diff.h" |
| #include "svn_config.h" |
| #include "svn_io.h" |
| #include "svn_hash.h" |
| #include "svn_dirent_uri.h" |
| #include "svn_path.h" |
| #include "svn_utf.h" |
| #include "private/svn_subr_private.h" |
| #include "svn_private_config.h" |
| |
| #include "ExternalItem.hpp" |
| #include "jniwrapper/jni_list.hpp" |
| #include "jniwrapper/jni_stack.hpp" |
| #include "jniwrapper/jni_string_map.hpp" |
| |
| |
| SVNClient::SVNClient(jobject jthis_in) |
| : m_lastPath("", pool), context(jthis_in, pool) |
| { |
| } |
| |
| SVNClient::~SVNClient() |
| { |
| } |
| |
| SVNClient *SVNClient::getCppObject(jobject jthis) |
| { |
| static jfieldID fid = 0; |
| jlong cppAddr = SVNBase::findCppAddrForJObject(jthis, &fid, |
| JAVAHL_CLASS("/SVNClient")); |
| return (cppAddr == 0 ? NULL : reinterpret_cast<SVNClient *>(cppAddr)); |
| } |
| |
| void SVNClient::dispose(jobject jthis) |
| { |
| static jfieldID fid = 0; |
| SVNBase::dispose(jthis, &fid, JAVAHL_CLASS("/SVNClient")); |
| } |
| |
| jobject SVNClient::getVersionExtended(bool verbose) |
| { |
| JNIEnv *const env = JNIUtil::getEnv(); |
| |
| jclass clazz = env->FindClass(JAVAHL_CLASS("/types/VersionExtended")); |
| if (JNIUtil::isJavaExceptionThrown()) |
| return NULL; |
| |
| static volatile jmethodID ctor = 0; |
| if (!ctor) |
| { |
| ctor = env->GetMethodID(clazz, "<init>", "()V"); |
| if (JNIUtil::isJavaExceptionThrown()) |
| return NULL; |
| } |
| |
| static volatile jfieldID fid = 0; |
| if (!fid) |
| { |
| fid = env->GetFieldID(clazz, "cppAddr", "J"); |
| if (JNIUtil::isJavaExceptionThrown()) |
| return NULL; |
| } |
| |
| jobject j_ext_info = env->NewObject(clazz, ctor); |
| if (JNIUtil::isJavaExceptionThrown()) |
| return NULL; |
| |
| VersionExtended *vx = new VersionExtended(verbose); |
| env->SetLongField(j_ext_info, fid, vx->getCppAddr()); |
| |
| env->DeleteLocalRef(clazz); |
| return j_ext_info; |
| } |
| |
| jstring SVNClient::getAdminDirectoryName() |
| { |
| SVN::Pool subPool(pool); |
| jstring name = |
| JNIUtil::makeJString(svn_wc_get_adm_dir(subPool.getPool())); |
| if (JNIUtil::isJavaExceptionThrown()) |
| return NULL; |
| |
| return name; |
| } |
| |
| jboolean SVNClient::isAdminDirectory(const char *name) |
| { |
| SVN::Pool subPool(pool); |
| return svn_wc_is_adm_dir(name, subPool.getPool()) ? JNI_TRUE : JNI_FALSE; |
| } |
| |
| const char *SVNClient::getLastPath() |
| { |
| return m_lastPath.c_str(); |
| } |
| |
| /** |
| * List directory entries of a URL. |
| */ |
| void SVNClient::list(const char *url, Revision &revision, |
| Revision &pegRevision, svn_depth_t depth, |
| int direntFields, bool fetchLocks, |
| ListCallback *callback) |
| { |
| SVN::Pool subPool(pool); |
| svn_client_ctx_t *ctx = context.getContext(NULL, subPool); |
| if (ctx == NULL) |
| return; |
| |
| SVN_JNI_NULL_PTR_EX(url, "path or url", ); |
| |
| Path urlPath(url, subPool); |
| SVN_JNI_ERR(urlPath.error_occurred(), ); |
| |
| SVN_JNI_ERR(svn_client_list3(urlPath.c_str(), |
| pegRevision.revision(), |
| revision.revision(), |
| depth, |
| direntFields, |
| fetchLocks, |
| FALSE, // include_externals |
| ListCallback::callback, |
| callback, |
| ctx, subPool.getPool()), ); |
| } |
| |
| void |
| SVNClient::status(const char *path, svn_depth_t depth, |
| bool onServer, bool onDisk, bool getAll, |
| bool noIgnore, bool ignoreExternals, |
| bool depthAsSticky, StringArray &changelists, |
| StatusCallback *callback) |
| { |
| SVN::Pool subPool(pool); |
| svn_revnum_t youngest = SVN_INVALID_REVNUM; |
| svn_opt_revision_t rev; |
| |
| SVN_JNI_NULL_PTR_EX(path, "path", ); |
| |
| svn_client_ctx_t *ctx = context.getContext(NULL, subPool); |
| if (ctx == NULL) |
| return; |
| callback->setWcCtx(ctx->wc_ctx); |
| |
| Path checkedPath(path, subPool); |
| SVN_JNI_ERR(checkedPath.error_occurred(), ); |
| |
| rev.kind = svn_opt_revision_unspecified; |
| |
| SVN_JNI_ERR(svn_client_status6(&youngest, ctx, checkedPath.c_str(), |
| &rev, depth, |
| getAll, onServer, onDisk, |
| noIgnore, ignoreExternals, depthAsSticky, |
| changelists.array(subPool), |
| StatusCallback::callback, callback, |
| subPool.getPool()), ); |
| } |
| |
| /* Convert a vector of revision ranges to an APR array of same. */ |
| static apr_array_header_t * |
| rev_range_vector_to_apr_array(std::vector<RevisionRange> &revRanges, |
| SVN::Pool &subPool) |
| { |
| apr_array_header_t *ranges = |
| apr_array_make(subPool.getPool(), |
| static_cast<int>(revRanges.size()), |
| sizeof(svn_opt_revision_range_t *)); |
| |
| std::vector<RevisionRange>::const_iterator it; |
| for (it = revRanges.begin(); it != revRanges.end(); ++it) |
| { |
| const svn_opt_revision_range_t *range = it->toRange(subPool); |
| |
| if (range->start.kind == svn_opt_revision_unspecified |
| && range->end.kind == svn_opt_revision_unspecified) |
| { |
| svn_opt_revision_range_t *full = |
| reinterpret_cast<svn_opt_revision_range_t *> |
| (apr_pcalloc(subPool.getPool(), sizeof(*range))); |
| full->start.kind = svn_opt_revision_number; |
| full->start.value.number = 1; |
| full->end.kind = svn_opt_revision_head; |
| full->end.value.number = 0; |
| APR_ARRAY_PUSH(ranges, const svn_opt_revision_range_t *) = full; |
| } |
| else |
| { |
| APR_ARRAY_PUSH(ranges, const svn_opt_revision_range_t *) = range; |
| } |
| if (JNIUtil::isExceptionThrown()) |
| return NULL; |
| } |
| return ranges; |
| } |
| |
| void SVNClient::logMessages(const char *path, Revision &pegRevision, |
| std::vector<RevisionRange> &logRanges, |
| bool stopOnCopy, bool discoverPaths, |
| bool includeMergedRevisions, StringArray &revProps, |
| int limit, LogMessageCallback *callback) |
| { |
| SVN::Pool subPool(pool); |
| |
| SVN_JNI_NULL_PTR_EX(path, "path", ); |
| |
| svn_client_ctx_t *ctx = context.getContext(NULL, subPool); |
| if (ctx == NULL) |
| return; |
| |
| Targets target(path, subPool); |
| const apr_array_header_t *targets = target.array(subPool); |
| SVN_JNI_ERR(target.error_occurred(), ); |
| |
| apr_array_header_t *ranges = |
| rev_range_vector_to_apr_array(logRanges, subPool); |
| if (JNIUtil::isExceptionThrown()) |
| return; |
| |
| SVN_JNI_ERR(svn_client_log5(targets, pegRevision.revision(), ranges, |
| limit, discoverPaths, stopOnCopy, |
| includeMergedRevisions, |
| revProps.array(subPool), |
| LogMessageCallback::callback, callback, ctx, |
| subPool.getPool()), ); |
| } |
| |
| jlong SVNClient::checkout(const char *moduleName, const char *destPath, |
| Revision &revision, Revision &pegRevision, |
| svn_depth_t depth, bool ignoreExternals, |
| bool allowUnverObstructions) |
| { |
| SVN::Pool subPool; |
| |
| SVN_JNI_NULL_PTR_EX(moduleName, "moduleName", -1); |
| SVN_JNI_NULL_PTR_EX(destPath, "destPath", -1); |
| |
| Path url(moduleName, subPool); |
| Path path(destPath, subPool); |
| SVN_JNI_ERR(url.error_occurred(), -1); |
| SVN_JNI_ERR(path.error_occurred(), -1); |
| svn_revnum_t rev; |
| |
| svn_client_ctx_t *ctx = context.getContext(NULL, subPool); |
| if (ctx == NULL) |
| return -1; |
| |
| SVN_JNI_ERR(svn_client_checkout3(&rev, url.c_str(), |
| path.c_str(), |
| pegRevision.revision(), |
| revision.revision(), |
| depth, |
| ignoreExternals, |
| allowUnverObstructions, |
| ctx, |
| subPool.getPool()), |
| -1); |
| |
| return rev; |
| } |
| |
| void SVNClient::remove(Targets &targets, CommitMessage *message, bool force, |
| bool keep_local, PropertyTable &revprops, |
| CommitCallback *callback) |
| { |
| SVN::Pool subPool(pool); |
| svn_client_ctx_t *ctx = context.getContext(message, subPool); |
| if (ctx == NULL) |
| return; |
| |
| const apr_array_header_t *targets2 = targets.array(subPool); |
| SVN_JNI_ERR(targets.error_occurred(), ); |
| |
| SVN_JNI_ERR(svn_client_delete4(targets2, force, keep_local, |
| revprops.hash(subPool), |
| CommitCallback::callback, callback, |
| ctx, subPool.getPool()), ); |
| } |
| |
| void SVNClient::revert(StringArray &paths, svn_depth_t depth, |
| StringArray &changelists, |
| bool clear_changelists, |
| bool metadata_only) |
| { |
| SVN::Pool subPool(pool); |
| |
| svn_client_ctx_t *ctx = context.getContext(NULL, subPool); |
| if (ctx == NULL) |
| return; |
| |
| Targets targets(paths, subPool); |
| SVN_JNI_ERR(targets.error_occurred(), ); |
| SVN_JNI_ERR(svn_client_revert3(targets.array(subPool), depth, |
| changelists.array(subPool), |
| clear_changelists, |
| metadata_only, |
| ctx, subPool.getPool()), ); |
| } |
| |
| void SVNClient::add(const char *path, |
| svn_depth_t depth, bool force, |
| bool no_ignore, bool no_autoprops, |
| bool add_parents) |
| { |
| SVN::Pool subPool(pool); |
| |
| SVN_JNI_NULL_PTR_EX(path, "path", ); |
| |
| Path intPath(path, subPool); |
| SVN_JNI_ERR(intPath.error_occurred(), ); |
| svn_client_ctx_t *ctx = context.getContext(NULL, subPool); |
| if (ctx == NULL) |
| return; |
| |
| SVN_JNI_ERR(svn_client_add5(intPath.c_str(), depth, force, |
| no_ignore, no_autoprops, add_parents, ctx, |
| subPool.getPool()), ); |
| } |
| |
| jlongArray SVNClient::update(Targets &targets, Revision &revision, |
| svn_depth_t depth, bool depthIsSticky, |
| bool makeParents, bool ignoreExternals, |
| bool allowUnverObstructions) |
| { |
| SVN::Pool subPool(pool); |
| |
| svn_client_ctx_t *ctx = context.getContext(NULL, subPool); |
| apr_array_header_t *revs; |
| if (ctx == NULL) |
| return NULL; |
| |
| const apr_array_header_t *array = targets.array(subPool); |
| SVN_JNI_ERR(targets.error_occurred(), NULL); |
| SVN_JNI_ERR(svn_client_update4(&revs, array, |
| revision.revision(), |
| depth, |
| depthIsSticky, |
| ignoreExternals, |
| allowUnverObstructions, |
| TRUE /* adds_as_modification */, |
| makeParents, |
| ctx, subPool.getPool()), |
| NULL); |
| |
| JNIEnv *env = JNIUtil::getEnv(); |
| jlongArray jrevs = env->NewLongArray(revs->nelts); |
| if (JNIUtil::isJavaExceptionThrown()) |
| return NULL; |
| jlong *jrevArray = env->GetLongArrayElements(jrevs, NULL); |
| if (JNIUtil::isJavaExceptionThrown()) |
| return NULL; |
| for (int i = 0; i < revs->nelts; ++i) |
| { |
| jlong rev = APR_ARRAY_IDX(revs, i, svn_revnum_t); |
| jrevArray[i] = rev; |
| } |
| env->ReleaseLongArrayElements(jrevs, jrevArray, 0); |
| |
| return jrevs; |
| } |
| |
| void SVNClient::commit(Targets &targets, CommitMessage *message, |
| svn_depth_t depth, bool noUnlock, bool keepChangelist, |
| StringArray &changelists, PropertyTable &revprops, |
| CommitCallback *callback) |
| { |
| SVN::Pool subPool(pool); |
| const apr_array_header_t *targets2 = targets.array(subPool); |
| SVN_JNI_ERR(targets.error_occurred(), ); |
| svn_client_ctx_t *ctx = context.getContext(message, subPool); |
| if (ctx == NULL) |
| return; |
| |
| SVN_JNI_ERR(svn_client_commit6(targets2, depth, |
| noUnlock, keepChangelist, |
| TRUE, |
| FALSE, // include_file_externals |
| FALSE, // include_dir_externals |
| changelists.array(subPool), |
| revprops.hash(subPool), |
| CommitCallback::callback, callback, |
| ctx, subPool.getPool()), |
| ); |
| } |
| |
| |
| namespace { |
| typedef Java::ImmutableList<JavaHL::ExternalItem> PinList; |
| typedef Java::ImmutableMap<PinList> PinMap; |
| |
| struct PinListFunctor |
| { |
| explicit PinListFunctor(const Java::Env& env, SVN::Pool& pool, int refs_len) |
| : m_pool(pool), |
| m_refs(apr_array_make(pool.getPool(), refs_len, |
| sizeof(svn_wc_external_item2_t*))) |
| {} |
| |
| void operator()(const JavaHL::ExternalItem& item) |
| { |
| APR_ARRAY_PUSH(m_refs, svn_wc_external_item2_t*) = |
| item.get_external_item(m_pool); |
| } |
| |
| SVN::Pool& m_pool; |
| apr_array_header_t *m_refs; |
| }; |
| |
| struct PinMapFunctor |
| { |
| explicit PinMapFunctor(const Java::Env& env, SVN::Pool& pool) |
| : m_env(env), |
| m_pool(pool), |
| m_pin_set(svn_hash__make(pool.getPool())) |
| {} |
| |
| void operator()(const std::string& path, const PinList& refs) |
| { |
| PinListFunctor lf(m_env, m_pool, refs.length()); |
| refs.for_each(lf); |
| const char* key = static_cast<const char*>( |
| apr_pmemdup(m_pool.getPool(), path.c_str(), path.size() + 1)); |
| svn_hash_sets(m_pin_set, key, lf.m_refs); |
| } |
| |
| const Java::Env& m_env; |
| SVN::Pool& m_pool; |
| apr_hash_t *m_pin_set; |
| }; |
| |
| apr_hash_t *get_externals_to_pin(jobject jexternalsToPin, SVN::Pool& pool) |
| { |
| if (!jexternalsToPin) |
| return NULL; |
| |
| const Java::Env env; |
| JNIEnv *jenv = env.get(); |
| |
| try |
| { |
| PinMap pin_map(env, jexternalsToPin); |
| PinMapFunctor mf(env, pool); |
| pin_map.for_each(mf); |
| return mf.m_pin_set; |
| } |
| SVN_JAVAHL_JNI_CATCH; |
| return NULL; |
| } |
| } // anonymous namespace |
| |
| void SVNClient::copy(CopySources ©Sources, const char *destPath, |
| CommitMessage *message, bool copyAsChild, |
| bool makeParents, bool ignoreExternals, |
| bool metadataOnly, |
| bool pinExternals, jobject jexternalsToPin, |
| PropertyTable &revprops, CommitCallback *callback) |
| { |
| SVN::Pool subPool(pool); |
| |
| apr_array_header_t *srcs = copySources.array(subPool); |
| SVN_JNI_NULL_PTR_EX(srcs, "sources", ); |
| SVN_JNI_NULL_PTR_EX(destPath, "destPath", ); |
| Path destinationPath(destPath, subPool); |
| SVN_JNI_ERR(destinationPath.error_occurred(), ); |
| |
| svn_client_ctx_t *ctx = context.getContext(message, subPool); |
| if (ctx == NULL) |
| return; |
| |
| apr_hash_t *pin_set = get_externals_to_pin(jexternalsToPin, subPool); |
| if (!JNIUtil::isJavaExceptionThrown()) |
| SVN_JNI_ERR(svn_client_copy7(srcs, destinationPath.c_str(), |
| copyAsChild, makeParents, ignoreExternals, |
| metadataOnly, |
| pinExternals, pin_set, |
| revprops.hash(subPool), |
| CommitCallback::callback, callback, |
| ctx, subPool.getPool()), ); |
| } |
| |
| void SVNClient::move(Targets &srcPaths, const char *destPath, |
| CommitMessage *message, bool force, bool moveAsChild, |
| bool makeParents, bool metadataOnly, bool allowMixRev, |
| PropertyTable &revprops, CommitCallback *callback) |
| { |
| SVN::Pool subPool(pool); |
| |
| const apr_array_header_t *srcs = srcPaths.array(subPool); |
| SVN_JNI_ERR(srcPaths.error_occurred(), ); |
| SVN_JNI_NULL_PTR_EX(destPath, "destPath", ); |
| Path destinationPath(destPath, subPool); |
| SVN_JNI_ERR(destinationPath.error_occurred(), ); |
| |
| svn_client_ctx_t *ctx = context.getContext(message, subPool); |
| if (ctx == NULL) |
| return; |
| |
| SVN_JNI_ERR(svn_client_move7((apr_array_header_t *) srcs, |
| destinationPath.c_str(), moveAsChild, |
| makeParents, |
| allowMixRev, |
| metadataOnly, |
| revprops.hash(subPool), |
| CommitCallback::callback, callback, ctx, |
| subPool.getPool()), ); |
| } |
| |
| void SVNClient::mkdir(Targets &targets, CommitMessage *message, |
| bool makeParents, PropertyTable &revprops, |
| CommitCallback *callback) |
| { |
| SVN::Pool subPool(pool); |
| svn_client_ctx_t *ctx = context.getContext(message, subPool); |
| if (ctx == NULL) |
| return; |
| |
| const apr_array_header_t *targets2 = targets.array(subPool); |
| SVN_JNI_ERR(targets.error_occurred(), ); |
| |
| SVN_JNI_ERR(svn_client_mkdir4(targets2, makeParents, |
| revprops.hash(subPool), |
| CommitCallback::callback, callback, |
| ctx, subPool.getPool()), ); |
| } |
| |
| void SVNClient::cleanup(const char *path, |
| bool break_locks, |
| bool fix_recorded_timestamps, |
| bool clear_dav_cache, |
| bool remove_unused_pristines, |
| bool include_externals) |
| { |
| SVN::Pool subPool(pool); |
| SVN_JNI_NULL_PTR_EX(path, "path", ); |
| Path intPath(path, subPool); |
| SVN_JNI_ERR(intPath.error_occurred(), ); |
| |
| svn_client_ctx_t *ctx = context.getContext(NULL, subPool); |
| if (ctx == NULL) |
| return; |
| |
| SVN_JNI_ERR(svn_client_cleanup2(intPath.c_str(), |
| break_locks, |
| fix_recorded_timestamps, |
| clear_dav_cache, |
| remove_unused_pristines, |
| include_externals, |
| ctx, subPool.getPool()),); |
| } |
| |
| void SVNClient::resolve(const char *path, svn_depth_t depth, |
| svn_wc_conflict_choice_t choice) |
| { |
| SVN::Pool subPool(pool); |
| SVN_JNI_NULL_PTR_EX(path, "path", ); |
| Path intPath(path, subPool); |
| SVN_JNI_ERR(intPath.error_occurred(), ); |
| svn_client_ctx_t *ctx = context.getContext(NULL, subPool); |
| if (ctx == NULL) |
| return; |
| |
| SVN_JNI_ERR(svn_client_resolve(intPath.c_str(), depth, choice, |
| ctx, subPool.getPool()), ); |
| } |
| |
| jlong SVNClient::doExport(const char *srcPath, const char *destPath, |
| Revision &revision, Revision &pegRevision, |
| bool force, bool ignoreExternals, |
| bool ignoreKeywords, |
| svn_depth_t depth, const char *nativeEOL) |
| { |
| SVN::Pool subPool(pool); |
| SVN_JNI_NULL_PTR_EX(srcPath, "srcPath", -1); |
| SVN_JNI_NULL_PTR_EX(destPath, "destPath", -1); |
| Path sourcePath(srcPath, subPool); |
| SVN_JNI_ERR(sourcePath.error_occurred(), -1); |
| Path destinationPath(destPath, subPool); |
| SVN_JNI_ERR(destinationPath.error_occurred(), -1); |
| svn_revnum_t rev; |
| svn_client_ctx_t *ctx = context.getContext(NULL, subPool); |
| if (ctx == NULL) |
| return -1; |
| |
| SVN_JNI_ERR(svn_client_export5(&rev, sourcePath.c_str(), |
| destinationPath.c_str(), |
| pegRevision.revision(), |
| revision.revision(), force, |
| ignoreExternals, ignoreKeywords, |
| depth, |
| nativeEOL, ctx, |
| subPool.getPool()), |
| -1); |
| |
| return rev; |
| |
| } |
| |
| jlong SVNClient::doSwitch(const char *path, const char *url, |
| Revision &revision, Revision &pegRevision, |
| svn_depth_t depth, bool depthIsSticky, |
| bool ignoreExternals, |
| bool allowUnverObstructions, |
| bool ignoreAncestry) |
| { |
| SVN::Pool subPool(pool); |
| SVN_JNI_NULL_PTR_EX(path, "path", -1); |
| SVN_JNI_NULL_PTR_EX(url, "url", -1); |
| Path intUrl(url, subPool); |
| SVN_JNI_ERR(intUrl.error_occurred(), -1); |
| Path intPath(path, subPool); |
| SVN_JNI_ERR(intPath.error_occurred(), -1); |
| |
| svn_revnum_t rev; |
| svn_client_ctx_t *ctx = context.getContext(NULL, subPool); |
| if (ctx == NULL) |
| return -1; |
| |
| SVN_JNI_ERR(svn_client_switch3(&rev, intPath.c_str(), |
| intUrl.c_str(), |
| pegRevision.revision(), |
| revision.revision(), |
| depth, |
| depthIsSticky, |
| ignoreExternals, |
| allowUnverObstructions, |
| ignoreAncestry, |
| ctx, |
| subPool.getPool()), |
| -1); |
| |
| return rev; |
| } |
| |
| void SVNClient::doImport(const char *path, const char *url, |
| CommitMessage *message, svn_depth_t depth, |
| bool noIgnore, bool noAutoProps, |
| bool ignoreUnknownNodeTypes, |
| PropertyTable &revprops, |
| ImportFilterCallback *ifCallback, |
| CommitCallback *commitCallback) |
| { |
| SVN::Pool subPool(pool); |
| SVN_JNI_NULL_PTR_EX(path, "path", ); |
| SVN_JNI_NULL_PTR_EX(url, "url", ); |
| Path intPath(path, subPool); |
| SVN_JNI_ERR(intPath.error_occurred(), ); |
| Path intUrl(url, subPool); |
| SVN_JNI_ERR(intUrl.error_occurred(), ); |
| |
| svn_client_ctx_t *ctx = context.getContext(message, subPool); |
| if (ctx == NULL) |
| return; |
| |
| SVN_JNI_ERR(svn_client_import5(intPath.c_str(), intUrl.c_str(), depth, |
| noIgnore, noAutoProps, ignoreUnknownNodeTypes, |
| revprops.hash(subPool), |
| ImportFilterCallback::callback, ifCallback, |
| CommitCallback::callback, commitCallback, |
| ctx, subPool.getPool()), ); |
| } |
| |
| jobject |
| SVNClient::suggestMergeSources(const char *path, Revision &pegRevision) |
| { |
| SVN::Pool subPool(pool); |
| svn_client_ctx_t *ctx = context.getContext(NULL, subPool); |
| if (ctx == NULL) |
| return NULL; |
| |
| apr_array_header_t *sources; |
| SVN_JNI_ERR(svn_client_suggest_merge_sources(&sources, path, |
| pegRevision.revision(), |
| ctx, subPool.getPool()), |
| NULL); |
| |
| return CreateJ::StringSet(sources); |
| } |
| |
| void SVNClient::merge(const char *path1, Revision &revision1, |
| const char *path2, Revision &revision2, |
| const char *localPath, bool forceDelete, svn_depth_t depth, |
| bool ignoreMergeinfo, bool diffIgnoreAncestry, |
| bool dryRun, bool allowMixedRev, bool recordOnly) |
| { |
| SVN::Pool subPool(pool); |
| SVN_JNI_NULL_PTR_EX(path1, "path1", ); |
| SVN_JNI_NULL_PTR_EX(path2, "path2", ); |
| SVN_JNI_NULL_PTR_EX(localPath, "localPath", ); |
| Path intLocalPath(localPath, subPool); |
| SVN_JNI_ERR(intLocalPath.error_occurred(), ); |
| |
| Path srcPath1(path1, subPool); |
| SVN_JNI_ERR(srcPath1.error_occurred(), ); |
| |
| Path srcPath2(path2, subPool); |
| SVN_JNI_ERR(srcPath2.error_occurred(), ); |
| |
| svn_client_ctx_t *ctx = context.getContext(NULL, subPool); |
| if (ctx == NULL) |
| return; |
| |
| SVN_JNI_ERR(svn_client_merge5(srcPath1.c_str(), revision1.revision(), |
| srcPath2.c_str(), revision2.revision(), |
| intLocalPath.c_str(), |
| depth, |
| ignoreMergeinfo, diffIgnoreAncestry, |
| forceDelete, recordOnly, dryRun, |
| allowMixedRev, NULL, ctx, |
| subPool.getPool()), ); |
| } |
| |
| void SVNClient::merge(const char *path, Revision &pegRevision, |
| std::vector<RevisionRange> *rangesToMerge, |
| const char *localPath, bool forceDelete, svn_depth_t depth, |
| bool ignoreMergeinfo, bool diffIgnoreAncestry, |
| bool dryRun, bool allowMixedRev, bool recordOnly) |
| { |
| SVN::Pool subPool(pool); |
| SVN_JNI_NULL_PTR_EX(path, "path", ); |
| SVN_JNI_NULL_PTR_EX(localPath, "localPath", ); |
| Path intLocalPath(localPath, subPool); |
| SVN_JNI_ERR(intLocalPath.error_occurred(), ); |
| |
| Path srcPath(path, subPool); |
| SVN_JNI_ERR(srcPath.error_occurred(), ); |
| |
| svn_client_ctx_t *ctx = context.getContext(NULL, subPool); |
| if (ctx == NULL) |
| return; |
| |
| apr_array_header_t *ranges = |
| (!rangesToMerge ? NULL |
| : rev_range_vector_to_apr_array(*rangesToMerge, subPool)); |
| if (JNIUtil::isExceptionThrown()) |
| return; |
| |
| SVN_JNI_ERR(svn_client_merge_peg5(srcPath.c_str(), |
| ranges, |
| pegRevision.revision(), |
| intLocalPath.c_str(), |
| depth, |
| ignoreMergeinfo, diffIgnoreAncestry, |
| forceDelete, recordOnly, |
| dryRun, allowMixedRev, NULL, ctx, |
| subPool.getPool()), ); |
| } |
| |
| /* SVNClient::mergeReintegrate is implemented in deprecated.cpp. */ |
| |
| jobject |
| SVNClient::getMergeinfo(const char *target, Revision &pegRevision) |
| { |
| SVN::Pool subPool(pool); |
| svn_client_ctx_t *ctx = context.getContext(NULL, subPool); |
| if (ctx == NULL) |
| return NULL; |
| |
| svn_mergeinfo_t mergeinfo; |
| Path intLocalTarget(target, subPool); |
| SVN_JNI_ERR(intLocalTarget.error_occurred(), NULL); |
| SVN_JNI_ERR(svn_client_mergeinfo_get_merged(&mergeinfo, |
| intLocalTarget.c_str(), |
| pegRevision.revision(), ctx, |
| subPool.getPool()), |
| NULL); |
| if (mergeinfo == NULL) |
| return NULL; |
| return CreateJ::Mergeinfo(mergeinfo, subPool.getPool()); |
| } |
| |
| void SVNClient::getMergeinfoLog(int type, const char *pathOrURL, |
| Revision &pegRevision, |
| const char *mergeSourceURL, |
| Revision &srcPegRevision, |
| Revision &srcStartRevision, |
| Revision &srcEndRevision, |
| bool discoverChangedPaths, |
| svn_depth_t depth, |
| StringArray &revProps, |
| LogMessageCallback *callback) |
| { |
| SVN::Pool subPool(pool); |
| |
| svn_client_ctx_t *ctx = context.getContext(NULL, subPool); |
| if (ctx == NULL) |
| return; |
| |
| SVN_JNI_NULL_PTR_EX(pathOrURL, "path or url", ); |
| Path urlPath(pathOrURL, subPool); |
| SVN_JNI_ERR(urlPath.error_occurred(), ); |
| |
| SVN_JNI_NULL_PTR_EX(mergeSourceURL, "merge source url", ); |
| Path srcURL(mergeSourceURL, subPool); |
| SVN_JNI_ERR(srcURL.error_occurred(), ); |
| |
| SVN_JNI_ERR(svn_client_mergeinfo_log2((type == 1), |
| urlPath.c_str(), |
| pegRevision.revision(), |
| srcURL.c_str(), |
| srcPegRevision.revision(), |
| srcStartRevision.revision(), |
| srcEndRevision.revision(), |
| LogMessageCallback::callback, |
| callback, |
| discoverChangedPaths, |
| depth, |
| revProps.array(subPool), |
| ctx, |
| subPool.getPool()), ); |
| |
| return; |
| } |
| |
| /** |
| * Get a property. |
| */ |
| jbyteArray SVNClient::propertyGet(const char *path, const char *name, |
| Revision &revision, Revision &pegRevision, |
| StringArray &changelists) |
| { |
| SVN::Pool subPool(pool); |
| SVN_JNI_NULL_PTR_EX(path, "path", NULL); |
| SVN_JNI_NULL_PTR_EX(name, "name", NULL); |
| Path intPath(path, subPool); |
| SVN_JNI_ERR(intPath.error_occurred(), NULL); |
| |
| svn_client_ctx_t *ctx = context.getContext(NULL, subPool); |
| if (ctx == NULL) |
| return NULL; |
| |
| apr_hash_t *props; |
| SVN_JNI_ERR(svn_client_propget5(&props, NULL, name, |
| intPath.c_str(), pegRevision.revision(), |
| revision.revision(), NULL, svn_depth_empty, |
| changelists.array(subPool), ctx, |
| subPool.getPool(), subPool.getPool()), |
| NULL); |
| |
| apr_hash_index_t *hi; |
| // only one element since we disabled recurse |
| hi = apr_hash_first(subPool.getPool(), props); |
| if (hi == NULL) |
| return NULL; // no property with this name |
| |
| svn_string_t *propval; |
| apr_hash_this(hi, NULL, NULL, reinterpret_cast<void**>(&propval)); |
| |
| if (propval == NULL) |
| return NULL; |
| |
| return JNIUtil::makeJByteArray(propval); |
| } |
| |
| void SVNClient::properties(const char *path, Revision &revision, |
| Revision &pegRevision, svn_depth_t depth, |
| StringArray &changelists, |
| ProplistCallback *callback) |
| { |
| SVN::Pool subPool(pool); |
| SVN_JNI_NULL_PTR_EX(path, "path", ); |
| Path intPath(path, subPool); |
| SVN_JNI_ERR(intPath.error_occurred(), ); |
| |
| svn_client_ctx_t *ctx = context.getContext(NULL, subPool); |
| if (ctx == NULL) |
| return; |
| |
| SVN_JNI_ERR(svn_client_proplist4(intPath.c_str(), pegRevision.revision(), |
| revision.revision(), depth, |
| changelists.array(subPool), |
| callback->inherited(), |
| ProplistCallback::callback, callback, |
| ctx, subPool.getPool()), ); |
| } |
| |
| void SVNClient::propertySetLocal(Targets &targets, const char *name, |
| JNIByteArray &value, svn_depth_t depth, |
| StringArray &changelists, bool force) |
| { |
| SVN::Pool subPool(pool); |
| SVN_JNI_NULL_PTR_EX(name, "name", ); |
| |
| svn_string_t *val; |
| if (value.isNull()) |
| val = NULL; |
| else |
| val = svn_string_ncreate |
| (reinterpret_cast<const char *>(value.getBytes()), |
| value.getLength(), |
| subPool.getPool()); |
| |
| svn_client_ctx_t *ctx = context.getContext(NULL, subPool); |
| if (ctx == NULL) |
| return; |
| |
| const apr_array_header_t *targetsApr = targets.array(subPool); |
| SVN_JNI_ERR(svn_client_propset_local(name, val, targetsApr, |
| depth, force, |
| changelists.array(subPool), |
| ctx, subPool.getPool()), ); |
| } |
| |
| void SVNClient::propertySetRemote(const char *path, long base_rev, |
| const char *name, |
| CommitMessage *message, |
| JNIByteArray &value, bool force, |
| PropertyTable &revprops, |
| CommitCallback *callback) |
| { |
| SVN::Pool subPool(pool); |
| SVN_JNI_NULL_PTR_EX(name, "name", ); |
| |
| svn_string_t *val; |
| if (value.isNull()) |
| val = NULL; |
| else |
| val = svn_string_ncreate |
| (reinterpret_cast<const char *>(value.getBytes()), |
| value.getLength(), |
| subPool.getPool()); |
| |
| Path intPath(path, subPool); |
| SVN_JNI_ERR(intPath.error_occurred(), ); |
| |
| svn_client_ctx_t *ctx = context.getContext(message, subPool); |
| if (ctx == NULL) |
| return; |
| |
| SVN_JNI_ERR(svn_client_propset_remote(name, val, intPath.c_str(), |
| force, base_rev, |
| revprops.hash(subPool), |
| CommitCallback::callback, callback, |
| ctx, subPool.getPool()), ); |
| } |
| |
| void SVNClient::diff(const char *target1, Revision &revision1, |
| const char *target2, Revision &revision2, |
| Revision *pegRevision, const char *relativeToDir, |
| OutputStream &outputStream, svn_depth_t depth, |
| StringArray &changelists, |
| bool ignoreAncestry, bool noDiffDelete, bool force, |
| bool showCopiesAsAdds, bool ignoreProps, bool propsOnly, |
| DiffOptions const& options) |
| { |
| SVN::Pool subPool(pool); |
| const char *c_relToDir = relativeToDir ? |
| svn_dirent_canonicalize(relativeToDir, subPool.getPool()) : |
| relativeToDir; |
| bool noDiffAdded = false; /* ### Promote to argument */ |
| |
| SVN_JNI_NULL_PTR_EX(target1, "target", ); |
| // target2 is ignored when pegRevision is provided. |
| if (pegRevision == NULL) |
| SVN_JNI_NULL_PTR_EX(target2, "target2", ); |
| |
| svn_client_ctx_t *ctx = context.getContext(NULL, subPool); |
| if (ctx == NULL) |
| return; |
| |
| Path path1(target1, subPool); |
| SVN_JNI_ERR(path1.error_occurred(), ); |
| |
| apr_array_header_t *diffOptions = options.optionsArray(subPool); |
| |
| if (pegRevision) |
| { |
| SVN_JNI_ERR(svn_client_diff_peg6(diffOptions, |
| path1.c_str(), |
| pegRevision->revision(), |
| revision1.revision(), |
| revision2.revision(), |
| c_relToDir, |
| depth, |
| ignoreAncestry, |
| noDiffAdded, |
| noDiffDelete, |
| showCopiesAsAdds, |
| force, |
| ignoreProps, |
| propsOnly, |
| options.useGitDiffFormat(), |
| SVN_APR_LOCALE_CHARSET, |
| outputStream.getStream(subPool), |
| NULL /* error file */, |
| changelists.array(subPool), |
| ctx, |
| subPool.getPool()), |
| ); |
| } |
| else |
| { |
| // "Regular" diff (without a peg revision). |
| Path path2(target2, subPool); |
| SVN_JNI_ERR(path2.error_occurred(), ); |
| |
| SVN_JNI_ERR(svn_client_diff6(diffOptions, |
| path1.c_str(), |
| revision1.revision(), |
| path2.c_str(), |
| revision2.revision(), |
| c_relToDir, |
| depth, |
| ignoreAncestry, |
| noDiffAdded, |
| noDiffDelete, |
| showCopiesAsAdds, |
| force, |
| ignoreProps, |
| propsOnly, |
| options.useGitDiffFormat(), |
| SVN_APR_LOCALE_CHARSET, |
| outputStream.getStream(subPool), |
| NULL /* error stream */, |
| changelists.array(subPool), |
| ctx, |
| subPool.getPool()), |
| ); |
| } |
| } |
| |
| void SVNClient::diff(const char *target1, Revision &revision1, |
| const char *target2, Revision &revision2, |
| const char *relativeToDir, OutputStream &outputStream, |
| svn_depth_t depth, StringArray &changelists, |
| bool ignoreAncestry, bool noDiffDelete, bool force, |
| bool showCopiesAsAdds, bool ignoreProps, bool propsOnly, |
| DiffOptions const& options) |
| { |
| diff(target1, revision1, target2, revision2, NULL, relativeToDir, |
| outputStream, depth, changelists, ignoreAncestry, noDiffDelete, force, |
| showCopiesAsAdds, ignoreProps, propsOnly, options); |
| } |
| |
| void SVNClient::diff(const char *target, Revision &pegRevision, |
| Revision &startRevision, Revision &endRevision, |
| const char *relativeToDir, OutputStream &outputStream, |
| svn_depth_t depth, StringArray &changelists, |
| bool ignoreAncestry, bool noDiffDelete, bool force, |
| bool showCopiesAsAdds, bool ignoreProps, bool propsOnly, |
| DiffOptions const& options) |
| { |
| diff(target, startRevision, NULL, endRevision, &pegRevision, |
| relativeToDir, outputStream, depth, changelists, |
| ignoreAncestry, noDiffDelete, force, showCopiesAsAdds, |
| ignoreProps, propsOnly, options); |
| } |
| |
| void |
| SVNClient::diffSummarize(const char *target1, Revision &revision1, |
| const char *target2, Revision &revision2, |
| svn_depth_t depth, StringArray &changelists, |
| bool ignoreAncestry, |
| DiffSummaryReceiver &receiver) |
| { |
| SVN::Pool subPool(pool); |
| |
| SVN_JNI_NULL_PTR_EX(target1, "target1", ); |
| SVN_JNI_NULL_PTR_EX(target2, "target2", ); |
| |
| svn_client_ctx_t *ctx = context.getContext(NULL, subPool); |
| if (ctx == NULL) |
| return; |
| |
| Path path1(target1, subPool); |
| SVN_JNI_ERR(path1.error_occurred(), ); |
| Path path2(target2, subPool); |
| SVN_JNI_ERR(path2.error_occurred(), ); |
| |
| SVN_JNI_ERR(svn_client_diff_summarize2(path1.c_str(), revision1.revision(), |
| path2.c_str(), revision2.revision(), |
| depth, |
| ignoreAncestry, |
| changelists.array(subPool), |
| DiffSummaryReceiver::summarize, |
| &receiver, |
| ctx, subPool.getPool()), ); |
| } |
| |
| void |
| SVNClient::diffSummarize(const char *target, Revision &pegRevision, |
| Revision &startRevision, Revision &endRevision, |
| svn_depth_t depth, StringArray &changelists, |
| bool ignoreAncestry, DiffSummaryReceiver &receiver) |
| { |
| SVN::Pool subPool(pool); |
| |
| SVN_JNI_NULL_PTR_EX(target, "target", ); |
| |
| svn_client_ctx_t *ctx = context.getContext(NULL, subPool); |
| if (ctx == NULL) |
| return; |
| |
| Path path(target, subPool); |
| SVN_JNI_ERR(path.error_occurred(), ); |
| |
| SVN_JNI_ERR(svn_client_diff_summarize_peg2(path.c_str(), |
| pegRevision.revision(), |
| startRevision.revision(), |
| endRevision.revision(), |
| depth, |
| ignoreAncestry, |
| changelists.array(subPool), |
| DiffSummaryReceiver::summarize, |
| &receiver, ctx, |
| subPool.getPool()), ); |
| } |
| |
| apr_hash_t *SVNClient::streamFileContent(const char *path, |
| Revision &revision, |
| Revision &pegRevision, |
| bool expand_keywords, |
| bool return_props, |
| OutputStream &outputStream) |
| { |
| SVN::Pool subPool(pool); |
| SVN_JNI_NULL_PTR_EX(path, "path", NULL); |
| Path intPath(path, subPool); |
| SVN_JNI_ERR(intPath.error_occurred(), NULL); |
| |
| svn_client_ctx_t *ctx = context.getContext(NULL, subPool); |
| if (ctx == NULL) |
| return NULL; |
| |
| apr_hash_t *props = NULL; |
| SVN_JNI_ERR(svn_client_cat3((return_props ? &props : NULL), |
| outputStream.getStream(subPool), |
| intPath.c_str(), |
| pegRevision.revision(), revision.revision(), |
| expand_keywords, ctx, |
| subPool.getPool(), subPool.getPool()), |
| NULL); |
| return props; |
| } |
| |
| jbyteArray SVNClient::revProperty(const char *path, |
| const char *name, Revision &rev) |
| { |
| SVN::Pool subPool(pool); |
| SVN_JNI_NULL_PTR_EX(path, "path", NULL); |
| SVN_JNI_NULL_PTR_EX(name, "name", NULL); |
| Path intPath(path, subPool); |
| SVN_JNI_ERR(intPath.error_occurred(), NULL); |
| |
| svn_client_ctx_t *ctx = context.getContext(NULL, subPool); |
| if (ctx == NULL) |
| return NULL; |
| |
| const char *URL; |
| svn_string_t *propval; |
| svn_revnum_t set_rev; |
| SVN_JNI_ERR(svn_client_url_from_path2(&URL, intPath.c_str(), ctx, |
| subPool.getPool(), |
| subPool.getPool()), |
| NULL); |
| |
| if (URL == NULL) |
| { |
| SVN_JNI_ERR(svn_error_create(SVN_ERR_UNVERSIONED_RESOURCE, NULL, |
| _("Either a URL or versioned item is required.")), |
| NULL); |
| } |
| |
| SVN_JNI_ERR(svn_client_revprop_get(name, &propval, URL, |
| rev.revision(), &set_rev, ctx, |
| subPool.getPool()), |
| NULL); |
| if (propval == NULL) |
| return NULL; |
| |
| return JNIUtil::makeJByteArray(propval); |
| } |
| void SVNClient::relocate(const char *from, const char *to, const char *path, |
| bool ignoreExternals) |
| { |
| SVN::Pool subPool(pool); |
| SVN_JNI_NULL_PTR_EX(path, "path", ); |
| SVN_JNI_NULL_PTR_EX(from, "from", ); |
| SVN_JNI_NULL_PTR_EX(to, "to", ); |
| Path intPath(path, subPool); |
| SVN_JNI_ERR(intPath.error_occurred(), ); |
| |
| Path intFrom(from, subPool); |
| SVN_JNI_ERR(intFrom.error_occurred(), ); |
| |
| Path intTo(to, subPool); |
| SVN_JNI_ERR(intTo.error_occurred(), ); |
| |
| svn_client_ctx_t *ctx = context.getContext(NULL, subPool); |
| if (ctx == NULL) |
| return; |
| |
| SVN_JNI_ERR(svn_client_relocate2(intPath.c_str(), intFrom.c_str(), |
| intTo.c_str(), ignoreExternals, ctx, |
| subPool.getPool()), ); |
| } |
| |
| void SVNClient::blame(const char *path, Revision &pegRevision, |
| Revision &revisionStart, Revision &revisionEnd, |
| bool ignoreMimeType, bool includeMergedRevisions, |
| BlameCallback *callback, DiffOptions const& options) |
| { |
| SVN::Pool subPool(pool); |
| SVN_JNI_NULL_PTR_EX(path, "path", ); |
| Path intPath(path, subPool); |
| SVN_JNI_ERR(intPath.error_occurred(), ); |
| |
| svn_client_ctx_t *ctx = context.getContext(NULL, subPool); |
| if (ctx == NULL) |
| return; |
| |
| SVN_JNI_ERR(svn_client_blame5( |
| intPath.c_str(), pegRevision.revision(), revisionStart.revision(), |
| revisionEnd.revision(), |
| options.fileOptions(subPool), ignoreMimeType, |
| includeMergedRevisions, BlameCallback::callback, callback, ctx, |
| subPool.getPool()), |
| ); |
| } |
| |
| void SVNClient::addToChangelist(Targets &srcPaths, const char *changelist, |
| svn_depth_t depth, StringArray &changelists) |
| { |
| SVN::Pool subPool(pool); |
| svn_client_ctx_t *ctx = context.getContext(NULL, subPool); |
| |
| const apr_array_header_t *srcs = srcPaths.array(subPool); |
| SVN_JNI_ERR(srcPaths.error_occurred(), ); |
| |
| SVN_JNI_ERR(svn_client_add_to_changelist(srcs, changelist, depth, |
| changelists.array(subPool), |
| ctx, subPool.getPool()), ); |
| } |
| |
| void SVNClient::removeFromChangelists(Targets &srcPaths, svn_depth_t depth, |
| StringArray &changelists) |
| { |
| SVN::Pool subPool(pool); |
| svn_client_ctx_t *ctx = context.getContext(NULL, subPool); |
| |
| const apr_array_header_t *srcs = srcPaths.array(subPool); |
| SVN_JNI_ERR(srcPaths.error_occurred(), ); |
| |
| SVN_JNI_ERR(svn_client_remove_from_changelists(srcs, depth, |
| changelists.array(subPool), |
| ctx, subPool.getPool()), ); |
| } |
| |
| void SVNClient::getChangelists(const char *rootPath, |
| StringArray *changelists, |
| svn_depth_t depth, |
| ChangelistCallback *callback) |
| { |
| SVN::Pool subPool(pool); |
| svn_client_ctx_t *ctx = context.getContext(NULL, subPool); |
| |
| const apr_array_header_t *cl_array = (!changelists ? NULL |
| : changelists->array(subPool)); |
| |
| SVN_JNI_ERR(svn_client_get_changelists(rootPath, cl_array, |
| depth, ChangelistCallback::callback, |
| callback, ctx, subPool.getPool()), |
| ); |
| } |
| |
| void SVNClient::lock(Targets &targets, const char *comment, bool force) |
| { |
| SVN::Pool subPool(pool); |
| const apr_array_header_t *targetsApr = targets.array(subPool); |
| SVN_JNI_ERR(targets.error_occurred(), ); |
| svn_client_ctx_t *ctx = context.getContext(NULL, subPool); |
| |
| SVN_JNI_ERR(svn_client_lock(targetsApr, comment, force, ctx, |
| subPool.getPool()), ); |
| } |
| |
| void SVNClient::unlock(Targets &targets, bool force) |
| { |
| SVN::Pool subPool(pool); |
| |
| const apr_array_header_t *targetsApr = targets.array(subPool); |
| SVN_JNI_ERR(targets.error_occurred(), ); |
| svn_client_ctx_t *ctx = context.getContext(NULL, subPool); |
| SVN_JNI_ERR(svn_client_unlock( |
| targetsApr, force, ctx, subPool.getPool()), ); |
| } |
| void SVNClient::setRevProperty(const char *path, |
| const char *name, Revision &rev, |
| const char *value, const char *original_value, |
| bool force) |
| { |
| SVN::Pool subPool(pool); |
| SVN_JNI_NULL_PTR_EX(path, "path", ); |
| SVN_JNI_NULL_PTR_EX(name, "name", ); |
| Path intPath(path, subPool); |
| SVN_JNI_ERR(intPath.error_occurred(), ); |
| |
| svn_client_ctx_t *ctx = context.getContext(NULL, subPool); |
| if (ctx == NULL) |
| return; |
| |
| const char *URL; |
| SVN_JNI_ERR(svn_client_url_from_path2(&URL, intPath.c_str(), ctx, |
| subPool.getPool(), |
| subPool.getPool()), ); |
| |
| if (URL == NULL) |
| { |
| SVN_JNI_ERR(svn_error_create(SVN_ERR_UNVERSIONED_RESOURCE, NULL, |
| _("Either a URL or versioned item is required.")), |
| ); |
| } |
| |
| svn_string_t *val = svn_string_create(value, subPool.getPool()); |
| svn_string_t *orig_val; |
| if (original_value != NULL) |
| orig_val = svn_string_create(original_value, subPool.getPool()); |
| else |
| orig_val = NULL; |
| |
| svn_revnum_t set_revision; |
| SVN_JNI_ERR(svn_client_revprop_set2(name, val, orig_val, URL, rev.revision(), |
| &set_revision, force, ctx, |
| subPool.getPool()), ); |
| } |
| |
| jstring SVNClient::getVersionInfo(const char *path, const char *trailUrl, |
| bool lastChanged) |
| { |
| SVN::Pool subPool(pool); |
| SVN_JNI_NULL_PTR_EX(path, "path", NULL); |
| |
| Path intPath(path, subPool); |
| SVN_JNI_ERR(intPath.error_occurred(), NULL); |
| |
| int wc_format; |
| svn_client_ctx_t *ctx = context.getContext(NULL, subPool); |
| if (ctx == NULL) |
| return NULL; |
| SVN_JNI_ERR(svn_wc_check_wc2(&wc_format, ctx->wc_ctx, intPath.c_str(), |
| subPool.getPool()), |
| NULL); |
| |
| if (! wc_format) |
| { |
| svn_node_kind_t kind; |
| SVN_JNI_ERR(svn_io_check_path(intPath.c_str(), &kind, |
| subPool.getPool()), |
| NULL); |
| if (kind == svn_node_dir) |
| { |
| return JNIUtil::makeJString("exported"); |
| } |
| else |
| { |
| char buffer[2048]; |
| apr_snprintf(buffer, sizeof(buffer), |
| _("'%s' not versioned, and not exported\n"), path); |
| return JNIUtil::makeJString(buffer); |
| } |
| } |
| |
| svn_wc_revision_status_t *result; |
| const char *local_abspath; |
| |
| SVN_JNI_ERR(svn_dirent_get_absolute(&local_abspath, intPath.c_str(), |
| subPool.getPool()), NULL); |
| SVN_JNI_ERR(svn_wc_revision_status2(&result, ctx->wc_ctx, local_abspath, |
| trailUrl, lastChanged, |
| ctx->cancel_func, ctx->cancel_baton, |
| subPool.getPool(), |
| subPool.getPool()), NULL); |
| |
| std::ostringstream value; |
| value << result->min_rev; |
| if (result->min_rev != result->max_rev) |
| { |
| value << ":"; |
| value << result->max_rev; |
| } |
| if (result->modified) |
| value << "M"; |
| if (result->switched) |
| value << "S"; |
| if (result->sparse_checkout) |
| value << "P"; |
| |
| return JNIUtil::makeJString(value.str().c_str()); |
| } |
| |
| void SVNClient::upgrade(const char *path) |
| { |
| SVN::Pool subPool(pool); |
| SVN_JNI_NULL_PTR_EX(path, "path", ); |
| |
| svn_client_ctx_t *ctx = context.getContext(NULL, subPool); |
| if (ctx == NULL) |
| return; |
| |
| Path checkedPath(path, subPool); |
| SVN_JNI_ERR(checkedPath.error_occurred(), ); |
| |
| SVN_JNI_ERR(svn_client_upgrade(path, ctx, subPool.getPool()), ); |
| } |
| |
| jobject SVNClient::revProperties(const char *path, Revision &revision) |
| { |
| apr_hash_t *props; |
| SVN::Pool subPool(pool); |
| SVN_JNI_NULL_PTR_EX(path, "path", NULL); |
| Path intPath(path, subPool); |
| SVN_JNI_ERR(intPath.error_occurred(), NULL); |
| |
| svn_client_ctx_t *ctx = context.getContext(NULL, subPool); |
| const char *URL; |
| svn_revnum_t set_rev; |
| SVN_JNI_ERR(svn_client_url_from_path2(&URL, intPath.c_str(), ctx, |
| subPool.getPool(), |
| subPool.getPool()), |
| NULL); |
| |
| if (ctx == NULL) |
| return NULL; |
| |
| SVN_JNI_ERR(svn_client_revprop_list(&props, URL, revision.revision(), |
| &set_rev, ctx, subPool.getPool()), |
| NULL); |
| |
| return CreateJ::PropertyMap(props, subPool.getPool()); |
| } |
| |
| void |
| SVNClient::info(const char *path, |
| Revision &revision, Revision &pegRevision, svn_depth_t depth, |
| svn_boolean_t fetchExcluded, svn_boolean_t fetchActualOnly, |
| svn_boolean_t includeExternals, |
| StringArray &changelists, InfoCallback *callback) |
| { |
| SVN_JNI_NULL_PTR_EX(path, "path", ); |
| |
| SVN::Pool subPool(pool); |
| svn_client_ctx_t *ctx = context.getContext(NULL, subPool); |
| if (ctx == NULL) |
| return; |
| |
| Path checkedPath(path, subPool); |
| SVN_JNI_ERR(checkedPath.error_occurred(), ); |
| |
| SVN_JNI_ERR(svn_client_info4(checkedPath.c_str(), |
| pegRevision.revision(), |
| revision.revision(), depth, |
| fetchExcluded, fetchActualOnly, |
| includeExternals, |
| changelists.array(subPool), |
| InfoCallback::callback, callback, |
| ctx, subPool.getPool()), ); |
| } |
| |
| void |
| SVNClient::patch(const char *patchPath, const char *targetPath, bool dryRun, |
| int stripCount, bool reverse, bool ignoreWhitespace, |
| bool removeTempfiles, PatchCallback *callback) |
| { |
| SVN_JNI_NULL_PTR_EX(patchPath, "patchPath", ); |
| SVN_JNI_NULL_PTR_EX(targetPath, "targetPath", ); |
| |
| SVN::Pool subPool(pool); |
| svn_client_ctx_t *ctx = context.getContext(NULL, subPool); |
| if (ctx == NULL) |
| return; |
| |
| Path checkedPatchPath(patchPath, subPool); |
| SVN_JNI_ERR(checkedPatchPath.error_occurred(), ); |
| Path checkedTargetPath(targetPath, subPool); |
| SVN_JNI_ERR(checkedTargetPath.error_occurred(), ); |
| |
| // Should parameterize the following, instead of defaulting to FALSE |
| SVN_JNI_ERR(svn_client_patch(checkedPatchPath.c_str(), |
| checkedTargetPath.c_str(), |
| dryRun, stripCount, reverse, |
| ignoreWhitespace, removeTempfiles, |
| PatchCallback::callback, callback, |
| ctx, subPool.getPool()), ); |
| } |
| |
| void SVNClient::vacuum(const char *path, |
| bool remove_unversioned_items, |
| bool remove_ignored_items, |
| bool fix_recorded_timestamps, |
| bool remove_unused_pristines, |
| bool include_externals) |
| { |
| SVN_JNI_NULL_PTR_EX(path, "path", ); |
| |
| SVN::Pool subPool(pool); |
| svn_client_ctx_t *ctx = context.getContext(NULL, subPool); |
| if (ctx == NULL) |
| return; |
| |
| Path checkedPath(path, subPool); |
| SVN_JNI_ERR(checkedPath.error_occurred(),); |
| |
| SVN_JNI_ERR(svn_client_vacuum(checkedPath.c_str(), |
| remove_unversioned_items, |
| remove_ignored_items, |
| fix_recorded_timestamps, |
| remove_unused_pristines, |
| include_externals, |
| ctx, subPool.getPool()), ); |
| } |
| |
| jobject |
| SVNClient::openRemoteSession(const char* path, int retryAttempts) |
| { |
| static const svn_opt_revision_t HEAD = { svn_opt_revision_head, {0}}; |
| static const svn_opt_revision_t NONE = { svn_opt_revision_unspecified, {0}}; |
| |
| SVN_JNI_NULL_PTR_EX(path, "path", NULL); |
| |
| SVN::Pool subPool(pool); |
| svn_client_ctx_t *ctx = context.getContext(NULL, subPool); |
| if (ctx == NULL) |
| return NULL; |
| |
| Path checkedPath(path, subPool); |
| SVN_JNI_ERR(checkedPath.error_occurred(), NULL); |
| |
| struct PathInfo |
| { |
| std::string url; |
| std::string uuid; |
| static svn_error_t *callback(void *baton, |
| const char *, |
| const svn_client_info2_t *info, |
| apr_pool_t *) |
| { |
| PathInfo* const pi = static_cast<PathInfo*>(baton); |
| pi->url = info->URL; |
| pi->uuid = info->repos_UUID; |
| return SVN_NO_ERROR; |
| } |
| } path_info; |
| |
| SVN_JNI_ERR(svn_client_info4( |
| checkedPath.c_str(), &NONE, |
| (svn_path_is_url(checkedPath.c_str()) ? &HEAD : &NONE), |
| svn_depth_empty, FALSE, TRUE, FALSE, NULL, |
| PathInfo::callback, &path_info, |
| ctx, subPool.getPool()), |
| NULL); |
| |
| /* Decouple the RemoteSession's context from SVNClient's context |
| by creating a copy of the prompter here. */ |
| |
| jobject jremoteSession = RemoteSession::open( |
| retryAttempts, path_info.url.c_str(), path_info.uuid.c_str(), |
| context.getConfigDirectory(), |
| context.getUsername(), context.getPassword(), |
| context.clonePrompter(), context.getSelf(), |
| context.getConfigEventHandler(), context.getTunnelCallback()); |
| if (JNIUtil::isJavaExceptionThrown()) |
| jremoteSession = NULL; |
| |
| return jremoteSession; |
| } |
| |
| ClientContext & |
| SVNClient::getClientContext() |
| { |
| return context; |
| } |