I took a stab at writing the JavaHL boiler-plate code for this, as attached, 
though I'm unfamiliar with JavaHL. It seems to require modifying 5 java files 
and creating 3 new ones. Is that right, JavaHL experts? It seems a lot.

The implementation in the core library is empty, as yet, in the attached patch.

- Julian


>>  interface MergeinfoDiffCallback {
>>    void mergeinfoDiff(int revision,
>>                       Map<String, Mergeinfo> pathToAddedMergeinfo,
>>                       Map<String, Mergeinfo> pathToRemovedMergeinfo);
>>  }
>> 
>>  void getMergeinfoDiff(String rootPath,
>>                        long fromRev, long toRev,
>>                        MergeinfoDiffCallback callback)
>>                        throws ClientException;
Add boiler-plate code in JavaHL for a new API to get per-revision mergeinfo
diffs.

Suggested by: Marc Strapetz <marc.strapetz{_AT_}syntevo.com>

* subversion/include/svn_ra.h,
  subversion/libsvn_ra/ra_loader.c
  (svn_ra_get_mergeinfo): New function, with an empty implementation.

In subversion/bindings/javahl/:

* native/MergeinfoDiffCallback.h,
  native/MergeinfoDiffCallback.cpp
    New files, copied from LogMessageCallback.* and adjusted.

* native/org_apache_subversion_javahl_remote_RemoteSession.cpp
  (Java_org_apache_subversion_javahl_remote_RemoteSession_getMergeinfoDiffs):
    New function.

* native/RemoteSession.h,
  native/RemoteSession.cpp
  (getMergeinfoDiffs): New method.

* src/org/apache/subversion/javahl/callback/MergeinfoDiffCallback.java
  New file, copied from LogMessageCallback.java and adjusted.

* src/org/apache/subversion/javahl/ISVNRemote.java
  (getMergeinfoDiffs): New method.

* src/org/apache/subversion/javahl/remote/RemoteSession.java
  (svn_ra_get_mergeinfo_diffs): New function.
--This line, and those below, will be ignored--

Index: subversion/bindings/javahl/native/MergeinfoDiffCallback.cpp
===================================================================
--- subversion/bindings/javahl/native/MergeinfoDiffCallback.cpp	(revision 1568992)
+++ subversion/bindings/javahl/native/MergeinfoDiffCallback.cpp	(working copy)
@@ -17,60 +17,65 @@
  *    KIND, either express or implied.  See the License for the
  *    specific language governing permissions and limitations
  *    under the License.
  * ====================================================================
  * @endcopyright
  *
- * @file LogMessageCallback.cpp
- * @brief Implementation of the class LogMessageCallback
+ * @file MergeinfoDiffCallback.cpp
+ * @brief Implementation of the class MergeinfoDiffCallback
  */
 
-#include "LogMessageCallback.h"
+#include "MergeinfoDiffCallback.h"
 #include "CreateJ.h"
 #include "EnumMapper.h"
 #include "JNIUtil.h"
 #include "svn_time.h"
 #include "svn_sorts.h"
 #include "svn_compat.h"
 
 /**
- * Create a LogMessageCallback object
+ * Create a MergeinfoDiffCallback object
  * @param jcallback the Java callback object.
  */
-LogMessageCallback::LogMessageCallback(jobject jcallback)
+MergeinfoDiffCallback::MergeinfoDiffCallback(jobject jcallback)
 {
   m_callback = jcallback;
 }
 
 /**
- * Destroy a LogMessageCallback object
+ * Destroy a MergeinfoDiffCallback object
  */
-LogMessageCallback::~LogMessageCallback()
+MergeinfoDiffCallback::~MergeinfoDiffCallback()
 {
   // The m_callback does not need to be destroyed because it is the
-  // passed in parameter to the Java SVNClientInterface.logMessages
+  // passed in parameter to the Java ISVNRemote.getMergeinfoDiffs
   // method.
 }
 
 svn_error_t *
-LogMessageCallback::callback(void *baton,
-                             svn_log_entry_t *log_entry,
-                             apr_pool_t *pool)
+MergeinfoDiffCallback::callback(void *baton,
+                                svn_revnum_t revision,
+                                svn_mergeinfo_t *added_mergeinfo,
+                                svn_mergeinfo_t *deleted_mergeinfo,
+                                apr_pool_t *pool)
 {
   if (baton)
-    return static_cast<LogMessageCallback *>(baton)->singleMessage(
-            log_entry, pool);
+    return static_cast<MergeinfoDiffCallback *>(baton)->singleMessage(
+            revision, added_mergeinfo, deleted_mergeinfo, pool);
 
   return SVN_NO_ERROR;
 }
 
 /**
- * Callback called for a single log message
+ * Callback called for a single mergeinfo diff
  */
 svn_error_t *
-LogMessageCallback::singleMessage(svn_log_entry_t *log_entry, apr_pool_t *pool)
+MergeinfoDiffCallback::singleMessage(svn_revnum_t revision,
+                                     svn_mergeinfo_t *added_mergeinfo,
+                                     svn_mergeinfo_t *deleted_mergeinfo,
+                                     apr_pool_t *pool)
 {
   JNIEnv *env = JNIUtil::getEnv();
 
   // Create a local frame for our references
   env->PushLocalFrame(LOCAL_FRAME_SIZE);
   if (JNIUtil::isJavaExceptionThrown())
@@ -78,55 +83,41 @@ LogMessageCallback::singleMessage(svn_lo
 
   // The method id will not change during the time this library is
   // loaded, so it can be cached.
   static jmethodID sm_mid = 0;
   if (sm_mid == 0)
     {
-      jclass clazz = env->FindClass(JAVA_PACKAGE"/callback/LogMessageCallback");
+      jclass clazz = env->FindClass(JAVA_PACKAGE"/callback/MergeinfoDiffCallback");
       if (JNIUtil::isJavaExceptionThrown())
         POP_AND_RETURN(SVN_NO_ERROR);
 
       sm_mid = env->GetMethodID(clazz,
                                 "singleMessage",
-                                "(Ljava/util/Set;JLjava/util/Map;Z)V");
+                                "(JLjava/util/Map;Ljava/util/Map;)V");
       if (JNIUtil::isJavaExceptionThrown())
         POP_AND_RETURN(SVN_NO_ERROR);
     }
 
-  jobject jChangedPaths = NULL;
-  if (log_entry->changed_paths)
+  jobject jAddedMergeinfo = NULL;
+  if (added_mergeinfo)
     {
-      apr_hash_index_t *hi;
-      std::vector<jobject> jcps;
-
-      for (hi = apr_hash_first(pool, log_entry->changed_paths);
-           hi;
-           hi = apr_hash_next(hi))
-        {
-          const char *path =
-            reinterpret_cast<const char *>(svn__apr_hash_index_key(hi));
-          svn_log_changed_path2_t *log_item =
-            reinterpret_cast<svn_log_changed_path2_t *>(svn__apr_hash_index_val(hi));
-
-          jobject cp = CreateJ::ChangedPath(path, log_item);
-
-          jcps.push_back(cp);
-        }
-
-      jChangedPaths = CreateJ::Set(jcps);
+      // TODO:
+      // jAddedMergeinfo = MergeinfoAsMap(added_mergeinfo);
     }
 
-  jobject jrevprops = NULL;
-  if (log_entry->revprops != NULL && apr_hash_count(log_entry->revprops) > 0)
-    jrevprops = CreateJ::PropertyMap(log_entry->revprops, pool);
+  jobject jDeletedMergeinfo = NULL;
+  if (deleted_mergeinfo)
+    {
+      // TODO:
+      // jDeletedMergeinfo = MergeinfoAsMap(deleted_mergeinfo);
+    }
 
   env->CallVoidMethod(m_callback,
                       sm_mid,
-                      jChangedPaths,
-                      (jlong)log_entry->revision,
-                      jrevprops,
-                      (jboolean)log_entry->has_children);
+                      (jlong)revision,
+                      jAddedMergeinfo,
+                      jDeletedMergeinfo);
   // No need to check for an exception here, because we return anyway.
 
   env->PopLocalFrame(NULL);
   return SVN_NO_ERROR;
 }
Index: subversion/bindings/javahl/native/MergeinfoDiffCallback.h
===================================================================
--- subversion/bindings/javahl/native/MergeinfoDiffCallback.h	(revision 1568992)
+++ subversion/bindings/javahl/native/MergeinfoDiffCallback.h	(working copy)
@@ -17,40 +17,45 @@
  *    KIND, either express or implied.  See the License for the
  *    specific language governing permissions and limitations
  *    under the License.
  * ====================================================================
  * @endcopyright
  *
- * @file LogMessageCallback.h
- * @brief Interface of the class LogMessageCallback
+ * @file MergeinfoDiffCallback.h
+ * @brief Interface of the class MergeinfoDiffCallback
  */
 
-#ifndef LOGMESSAGECALLBACK_H
-#define LOGMESSAGECALLBACK_H
+#ifndef MERGEINFODIFFCALLBACK_H
+#define MERGEINFODIFFCALLBACK_H
 
 #include <jni.h>
 #include "svn_client.h"
 
 /**
  * This class holds a Java callback object, which will receive every
- * log message for which the callback information is requested.
+ * mergeinfo diff for which the callback information is requested.
  */
-class LogMessageCallback
+class MergeinfoDiffCallback
 {
  public:
-  LogMessageCallback(jobject jcallback);
-  ~LogMessageCallback();
+  MergeinfoDiffCallback(jobject jcallback);
+  ~MergeinfoDiffCallback();
 
   static svn_error_t *callback(void *baton,
-                               svn_log_entry_t *log_entry,
+                               svn_revnum_t revision,
+                               svn_mergeinfo_t *added_mergeinfo,
+                               svn_mergeinfo_t *deleted_mergeinfo,
                                apr_pool_t *pool);
  protected:
-  svn_error_t *singleMessage(svn_log_entry_t *log_entry, apr_pool_t *pool);
+  svn_error_t *singleMessage(svn_revnum_t revision,
+                             svn_mergeinfo_t *added_mergeinfo,
+                             svn_mergeinfo_t *deleted_mergeinfo,
+                             apr_pool_t *pool);
 
  private:
   /**
    * This a local reference to the Java object.
    */
   jobject m_callback;
 };
 
-#endif  // LOGMESSAGECALLBACK_H
+#endif  // MERGEINFODIFFCALLBACK_H
Index: subversion/bindings/javahl/native/org_apache_subversion_javahl_remote_RemoteSession.cpp
===================================================================
--- subversion/bindings/javahl/native/org_apache_subversion_javahl_remote_RemoteSession.cpp	(revision 1569061)
+++ subversion/bindings/javahl/native/org_apache_subversion_javahl_remote_RemoteSession.cpp	(working copy)
@@ -222,12 +222,25 @@
   RemoteSession *ras = RemoteSession::getCppObject(jthis);
   CPPADDR_NULL_PTR(ras, NULL);
 
   return ras->getMergeinfo(jpaths, jrevision, jinherit, jinclude_descendants);
 }
 
+JNIEXPORT void JNICALL
+Java_org_apache_subversion_javahl_remote_RemoteSession_getMergeinfoDiffs(
+    JNIEnv *env, jobject jthis, jstring jrelpath, jlong jfromRev, jlong jtoRev,
+    jobject jmergeinfo_diff_callback)
+{
+  JNIEntry(SVNReposAccess, nativeGetMergeinfoDiffs);
+  RemoteSession *ras = RemoteSession::getCppObject(jthis);
+  CPPADDR_NULL_PTR(ras,);
+
+  ras->getMergeinfoDiffs(jrelpath, jfromRev, jtoRev,
+                         jmergeinfo_diff_callback);
+}
+
 // TODO: update
 // TODO: switch
 
 JNIEXPORT void JNICALL
 Java_org_apache_subversion_javahl_remote_RemoteSession_nativeStatus(
     JNIEnv *env, jobject jthis, jstring jstatus_target, jlong jrevision,
Index: subversion/bindings/javahl/native/RemoteSession.cpp
===================================================================
--- subversion/bindings/javahl/native/RemoteSession.cpp	(revision 1569061)
+++ subversion/bindings/javahl/native/RemoteSession.cpp	(working copy)
@@ -39,12 +39,13 @@
 #include "svn_delta.h"
 
 #include "CreateJ.h"
 #include "EnumMapper.h"
 #include "Iterator.h"
 #include "LogMessageCallback.h"
+#include "MergeinfoDiffCallback.h"
 #include "OutputStream.h"
 #include "Prompter.h"
 #include "Revision.h"
 #include "RemoteSession.h"
 #include "EditorProxy.h"
 #include "StateReporter.h"
@@ -759,12 +760,31 @@
       env->DeleteLocalRef(jmergeinfo);
     }
 
   return jcatalog;
 }
 
+void
+RemoteSession::getMergeinfoDiffs(jstring jpath,
+                                 jlong jfromRev, jlong jtoRev,
+                                 jobject jcallback)
+{
+  SVN::Pool subPool(pool);
+  Relpath path(jpath, subPool);
+  if (JNIUtil::isJavaExceptionThrown())
+    return;
+  SVN_JNI_ERR(path.error_occurred(),);
+
+  MergeinfoDiffCallback receiver(jcallback);
+  SVN_JNI_ERR(svn_ra_get_mergeinfo_diffs(
+                  m_session, path.c_str(),
+                  svn_revnum_t(jfromRev), svn_revnum_t(jtoRev),
+                  receiver.callback, &receiver,
+                  subPool.getPool()),);
+}
+
 // TODO: update
 // TODO: switch
 
 namespace {
 svn_error_t*
 status_unlock_func(void* baton, const char* path, apr_pool_t* scratch_pool)
Index: subversion/bindings/javahl/native/RemoteSession.h
===================================================================
--- subversion/bindings/javahl/native/RemoteSession.h	(revision 1569061)
+++ subversion/bindings/javahl/native/RemoteSession.h	(working copy)
@@ -78,12 +78,14 @@ class RemoteSession : public SVNBase
     jlong getFile(jlong jrevision, jstring jpath,
                   jobject jcontents, jobject jproperties);
     jlong getDirectory(jlong jrevision, jstring jpath, jint jdirent_fields,
                        jobject jdirents, jobject jproperties);
     jobject getMergeinfo(jobject jpaths, jlong jrevision, jobject jinherit,
                          jboolean jinclude_descendants);
+    void getMergeinfoDiffs(jstring jrootPath, jlong jfromRev, jlong jtoRev,
+                           jobject jcallback);
     // TODO: update
     // TODO: switch
     void status(jobject jthis, jstring jstatus_target,
                 jlong jrevision, jobject jdepth,
                 jobject jstatus_editor, jobject jreporter);
     // TODO: diff
Index: subversion/bindings/javahl/src/org/apache/subversion/javahl/callback/MergeinfoDiffCallback.java
===================================================================
--- subversion/bindings/javahl/src/org/apache/subversion/javahl/callback/MergeinfoDiffCallback.java	(revision 1568992)
+++ subversion/bindings/javahl/src/org/apache/subversion/javahl/callback/MergeinfoDiffCallback.java	(working copy)
@@ -21,46 +21,27 @@
  * @endcopyright
  */
 
 package org.apache.subversion.javahl.callback;
 
 import org.apache.subversion.javahl.ISVNClient;
-import org.apache.subversion.javahl.types.ChangePath;
+import org.apache.subversion.javahl.types.Mergeinfo;
 
 import java.util.Map;
-import java.util.Set;
 
 /**
- * This interface is used to receive every log message for the log
- * messages found by a {@link ISVNClient#logMessages} call.
- *
- * All log messages are returned in a list, which is terminated by an
- * invocation of this callback with the revision set to SVN_INVALID_REVNUM.
- *
- * If the includeMergedRevisions parameter to {@link ISVNClient#logMessages}
- * is true, then messages returned through this callback may have the
- * hasChildren parameter set.  This parameter indicates that a separate list,
- * which includes messages for merged revisions, will immediately follow.
- * This list is also terminated with SVN_INVALID_REVNUM, after which the
- * previous log message list continues.
- *
- * Log message lists may be nested arbitrarily deep, depending on the ancestry
- * of the requested paths.
+ * This interface is used to receive each mergeinfo diff
+ * found by a {@link ISVNRemote#getMergeinfoDiffs} call.
  */
-public interface LogMessageCallback
+public interface MergeinfoDiffCallback
 {
     /**
      * The method will be called for every log message.
      *
-     * @param changedPaths   a set of the paths that were changed
-     * @param revision       the revision of the commit
-     * @param revprops       All of the requested revision properties,
-     *                       possibly including svn:date, svn:author,
-     *                       and svn:log.
-     * @param hasChildren    when merge sensitive option was requested,
-     *                       whether or not this entry has child entries.
+     * @param revision                  the revision of the commit
+     * @param pathToAddedMergeinfo      mapping from path to added mergeinfo
+     * @param pathToDeletedMergeinfo    mapping from path to deleted mergeinfo
      */
-    public void singleMessage(Set<ChangePath> changedPaths,
-                              long revision,
-                              Map<String, byte[]> revprops,
-                              boolean hasChildren);
+    public void mergeinfoDiff(long revision,
+                              Map<String, Mergeinfo> pathToAddedMergeinfo,
+                              Map<String, Mergeinfo> pathToRemovedMergeinfo);
 }
Index: subversion/bindings/javahl/src/org/apache/subversion/javahl/ISVNRemote.java
===================================================================
--- subversion/bindings/javahl/src/org/apache/subversion/javahl/ISVNRemote.java	(revision 1569061)
+++ subversion/bindings/javahl/src/org/apache/subversion/javahl/ISVNRemote.java	(working copy)
@@ -337,12 +337,20 @@ public interface ISVNRemote
      */
     Map<String, Mergeinfo> getMergeinfo(Iterable<String> paths, long revision,
                                         Mergeinfo.Inheritance inherit,
                                         boolean includeDescendants)
             throws ClientException;
 
+    /**
+     * TODO: Doc string...
+     */
+    void getMergeinfoDiffs(String rootPath,
+                           long fromRev, long toRev,
+                           MergeinfoDiffCallback callback)
+            throws ClientException;
+
     // TODO: update
     // TODO: switch
 
     /**
      * Ask for a description of the status of a working copy with
      * respect to <code>revision</code> of the session's repository,
Index: subversion/bindings/javahl/src/org/apache/subversion/javahl/remote/RemoteSession.java
===================================================================
--- subversion/bindings/javahl/src/org/apache/subversion/javahl/remote/RemoteSession.java	(revision 1569061)
+++ subversion/bindings/javahl/src/org/apache/subversion/javahl/remote/RemoteSession.java	(working copy)
@@ -182,12 +182,20 @@ public class RemoteSession extends JNIOb
     public native Map<String, Mergeinfo>
         getMergeinfo(Iterable<String> paths, long revision,
                      Mergeinfo.Inheritance inherit,
                      boolean includeDescendants)
             throws ClientException;
 
+    public void getMergeinfoDiffs(String rootPath,
+                                  long fromRev, long toRev,
+                                  MergeinfoDiffCallback callback)
+            throws ClientException
+    {
+        nativeGetMergeinfoDiffs(rootPath, fromRev, toRev, callback);
+    }
+
     // TODO: update
     // TODO: switch
 
     public ISVNReporter status(String statusTarget,
                                long revision, Depth depth,
                                RemoteStatus receiver)
@@ -335,12 +343,17 @@ public class RemoteSession extends JNIOb
             throws ClientException;
     private native long nativeGetDirectory(long revision, String path,
                                            int direntFields,
                                            Map<String, DirEntry> dirents,
                                            Map<String, byte[]> properties)
             throws ClientException;
+    private native void nativeGetMergeinfoDiffs(String rootPath,
+                                                long fromRev,
+                                                long toRev,
+                                                MergeinfoDiffCallback callback)
+            throws ClientException;
     private native void nativeStatus(String statusTarget,
                                      long revision, Depth depth,
                                      ISVNEditor statusEditor,
                                      ISVNReporter reporter)
             throws ClientException;
     private native boolean nativeHasCapability(String capability)
Index: subversion/include/svn_ra.h
===================================================================
--- subversion/include/svn_ra.h	(revision 1569061)
+++ subversion/include/svn_ra.h	(working copy)
@@ -1187,12 +1187,40 @@
                      svn_revnum_t revision,
                      svn_mergeinfo_inheritance_t inherit,
                      svn_boolean_t include_descendants,
                      apr_pool_t *pool);
 
 /**
+ * TODO: ...
+ *
+ * @since New in 1.9.
+ */
+typedef svn_error_t *(*svn_ra_mergeinfo_diff_func_t)(
+    void *baton,
+    svn_revnum_t revision,
+    svn_mergeinfo_t *added_mergeinfo,
+    svn_mergeinfo_t *deleted_mergeinfo,
+    apr_pool_t *scratch_pool);
+
+/**
+ * TODO: ...
+ *
+ * RELPATH is relative to the URL of SESSION.
+ *
+ * @since New in 1.9.
+ */
+svn_error_t *
+svn_ra_get_mergeinfo_diffs(svn_ra_session_t *session,
+                           const char *relpath,
+                           svn_revnum_t from_rev,
+                           svn_revnum_t to_rev,
+                           svn_ra_mergeinfo_diff_func_t mergeinfo_diff_func,
+                           void *mergeinfo_diff_baton,
+                           apr_pool_t *scratch_pool);
+
+/**
  * Ask the RA layer to update a working copy to a new revision.
  *
  * The client initially provides an @a update_editor/@a update_baton to the
  * RA layer; this editor contains knowledge of where the change will
  * begin in the working copy (when @c open_root() is called).
  *
Index: subversion/libsvn_ra/ra_loader.c
===================================================================
--- subversion/libsvn_ra/ra_loader.c	(revision 1569061)
+++ subversion/libsvn_ra/ra_loader.c	(working copy)
@@ -826,12 +826,33 @@
   return session->vtable->get_mergeinfo(session, catalog, paths,
                                         revision, inherit,
                                         include_descendants, pool);
 }
 
 svn_error_t *
+svn_ra_get_mergeinfo_diffs(svn_ra_session_t *session,
+                           const char *relpath,
+                           svn_revnum_t from_rev,
+                           svn_revnum_t to_rev,
+                           svn_ra_mergeinfo_diff_func_t mergeinfo_diff_func,
+                           void *mergeinfo_diff_baton,
+                           apr_pool_t *scratch_pool)
+{
+  SVN_ERR_ASSERT(svn_relpath_is_canonical(relpath));
+  SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(from_rev));
+  SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(to_rev));
+  SVN_ERR_ASSERT(from_rev <= to_rev);
+
+  /* If server supports the mergeinfo-diffs capability, then use it,
+   * else report an unsupported feature. (Or do we want to fall back to
+   * fetching all the mergeinfo and diffing it on the client side?) */
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
 svn_ra_do_update3(svn_ra_session_t *session,
                   const svn_ra_reporter3_t **reporter,
                   void **report_baton,
                   svn_revnum_t revision_to_update_to,
                   const char *update_target,
                   svn_depth_t depth,

Reply via email to