On the 'pristines-on-demand-on-mwf' branch: notify when hydrating.

* subversion/include/svn_wc.h
  (svn_wc_notify_action_t): Add a new action type.
  (svn_wc_notify_t): Add a generic 'dict' field.

* subversion/libsvn_client/textbase.c
  (textbase_hydrate_baton_t,
   textbase_hydrate_cb): Remember when we're hydrating and how many files.
    Notify when starting and for each file.
  (svn_client__textbase_sync): Notify when hydrating is finished.

* subversion/svn/notify.c
  (notify_baton,
   svn_cl__notifier_get_wc_was_upgraded,
   notify_body,
   svn_cl__get_notifier): Print hydration notifications.
--This line, and those below, will be ignored--

Index: subversion/include/svn_wc.h
===================================================================
--- subversion/include/svn_wc.h	(revision 1899151)
+++ subversion/include/svn_wc.h	(working copy)
@@ -1302,12 +1302,16 @@ typedef enum svn_wc_notify_action_t
   svn_wc_notify_tree_conflict_details_progress,
 
   /** Done searching the repository for details about a conflict.
    * @since New in 1.10. */
   svn_wc_notify_end_search_tree_conflict_details,
 
+  /** Generic notification, with parameters in @c dict.
+   * @since New in 1.15. */
+  svn_wc_notify_dict,
+
   /** A warning, specified in #svn_wc_notify_t.err.
    * @since New in 1.15. */
   svn_wc_notify_warning,
 
 } svn_wc_notify_action_t;
 
@@ -1490,12 +1494,16 @@ typedef struct svn_wc_notify_t {
   svn_linenum_t hunk_matched_line;
 
   /** The fuzz factor the hunk was applied with.
    * @since New in 1.7 */
   svn_linenum_t hunk_fuzz;
 
+  /** Generic notification fields.
+   * @since New in 1.15 */
+  apr_hash_t *dict;
+
   /* NOTE: Add new fields at the end to preserve binary compatibility.
      Also, if you add fields here, you have to update svn_wc_create_notify
      and svn_wc_dup_notify. */
 } svn_wc_notify_t;
 
 /**
Index: subversion/libsvn_client/textbase.c
===================================================================
--- subversion/libsvn_client/textbase.c	(revision 1899151)
+++ subversion/libsvn_client/textbase.c	(working copy)
@@ -20,22 +20,25 @@
  *    under the License.
  * ====================================================================
  */
 
 #include "svn_path.h"
 
+#include "svn_hash.h"
 #include "private/svn_wc_private.h"
 
 #include "client.h"
 
 /* A baton for use with textbase_hydrate_cb(). */
 typedef struct textbase_hydrate_baton_t
 {
   apr_pool_t *pool;
   svn_client_ctx_t *ctx;
   svn_ra_session_t *ra_session;
+  svn_boolean_t hydrating_started;
+  int hydrated_files_count;
 } textbase_hydrate_baton_t;
 
 /* Implements svn_wc__textbase_hydrate_cb_t. */
 static svn_error_t *
 textbase_hydrate_cb(void *baton,
                     const char *repos_root_url,
@@ -66,24 +69,50 @@ textbase_hydrate_cb(void *baton,
          session, but pass it on to the caller so that it could be reused
          further on. */
 
       /* Open the RA session that does not correspond to a working copy.
          At this point we know that we don't have a local copy of the contents,
          so rechecking that in get_wc_contents() is just a waste of time. */
+      SVN_DBG(("### open a new session for hydrating"));
       SVN_ERR(svn_client__open_ra_session_internal(&session, NULL, url, NULL,
                                                    NULL, FALSE, FALSE, b->ctx,
                                                    b->pool, scratch_pool));
       b->ra_session = session;
     }
 
+  if (!b->hydrating_started)
+    {
+      if (b->ctx->notify_func2)
+        {
+          svn_wc_notify_t *notify
+            = svn_wc_create_notify(".", svn_wc_notify_dict, scratch_pool);
+          notify->dict = apr_hash_make(scratch_pool);
+          svn_hash_sets(notify->dict, "action", "hydrating_start");
+          b->ctx->notify_func2(b->ctx->notify_baton2, notify, scratch_pool);
+        }
+      b->hydrating_started = TRUE;
+    }
+
+  if (b->ctx->notify_func2)
+    {
+      svn_wc_notify_t *notify
+        = svn_wc_create_notify(".", svn_wc_notify_dict, scratch_pool);
+      notify->revision = revision;
+      notify->url = url;
+      notify->dict = apr_hash_make(scratch_pool);
+      svn_hash_sets(notify->dict, "action", "hydrating_file");
+      b->ctx->notify_func2(b->ctx->notify_baton2, notify, scratch_pool);
+    }
+
   SVN_ERR(svn_client__ensure_ra_session_url(&old_url, b->ra_session, url,
                                             scratch_pool));
   err = svn_ra_get_file(b->ra_session, "", revision, contents,
                         NULL, NULL, scratch_pool);
   err = svn_error_compose_create(err, svn_stream_close(contents));
 
+  b->hydrated_files_count++;
   return svn_error_trace(err);
 }
 
 svn_error_t *
 svn_client__textbase_sync(const char *local_abspath,
                           svn_boolean_t allow_hydrate,
@@ -92,18 +121,33 @@ svn_client__textbase_sync(const char *lo
                           apr_pool_t *scratch_pool)
 {
   textbase_hydrate_baton_t baton = {0};
 
   SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
 
+  /* SVN_DBG(("textbase_sync(%d,%d) '%s'", allow_hydrate, allow_dehydrate, local_abspath)); */
+
   baton.pool = scratch_pool;
   baton.ctx = ctx;
   baton.ra_session = NULL;
 
   SVN_ERR(svn_wc__textbase_sync(ctx->wc_ctx, local_abspath,
                                 allow_hydrate, allow_dehydrate,
                                 textbase_hydrate_cb, &baton,
                                 ctx->cancel_func, ctx->cancel_baton,
                                 scratch_pool));
+  if (baton.hydrated_files_count)
+    {
+      if (ctx->notify_func2)
+        {
+          svn_wc_notify_t *notify
+            = svn_wc_create_notify(".", svn_wc_notify_dict, scratch_pool);
+          notify->dict = apr_hash_make(scratch_pool);
+          svn_hash_sets(notify->dict, "action", "hydrating_end");
+          svn_hash_sets(notify->dict, "count",
+                        apr_psprintf(scratch_pool, "%d", baton.hydrated_files_count));
+          ctx->notify_func2(ctx->notify_baton2, notify, scratch_pool);
+        }
+    }
 
   return SVN_NO_ERROR;
 }
Index: subversion/svn/notify.c
===================================================================
--- subversion/svn/notify.c	(revision 1899151)
+++ subversion/svn/notify.c	(working copy)
@@ -50,12 +50,13 @@ struct notify_baton
 {
   svn_boolean_t received_some_change;
   svn_boolean_t is_checkout;
   svn_boolean_t is_export;
   svn_boolean_t is_wc_to_repos_copy;
   svn_boolean_t sent_first_txdelta;
+  svn_boolean_t hydrating;
   int in_external;
   svn_revnum_t progress_revision;
   svn_boolean_t had_print_error; /* Used to not keep printing error messages
                                     when we've already had one print error. */
   svn_boolean_t wc_was_upgraded;
 
@@ -290,12 +291,25 @@ svn_cl__notifier_get_wc_was_upgraded(voi
 {
   struct notify_baton *nb = baton;
 
   return nb->wc_was_upgraded;
 }
 
+static const char *
+nb_dict(const svn_wc_notify_t *n,
+        const char *key)
+{
+  if (n->dict)
+    {
+      const char *s = svn_hash_gets(n->dict, key);
+      if (s)
+        return s;
+    }
+  return "";
+}
+
 /* The body for notify() function with standard error handling semantic.
  * Handling of errors implemented at caller side. */
 static svn_error_t *
 notify_body(struct notify_baton *nb,
             const svn_wc_notify_t *n,
             apr_pool_t *pool)
@@ -1204,12 +1218,33 @@ notify_body(struct notify_baton *nb,
         {
           SVN_ERR(svn_cmdline_printf(pool, _("done\n")));
         }
       SVN_ERR(svn_cmdline_printf(pool, _("Committing transaction...\n")));
       break;
 
+    case svn_wc_notify_dict:
+      if (strcmp(nb_dict(n, "action"), "hydrating_start") == 0)
+        {
+          SVN_ERR(svn_cmdline_printf(pool, _("  Hydrating text bases ")));
+          nb->hydrating = TRUE;
+        }
+      else if (strcmp(nb_dict(n, "action"), "hydrating_file") == 0)
+        {
+          SVN_ERR(svn_cmdline_printf(pool, "."));
+        }
+      else if (strcmp(nb_dict(n, "action"), "hydrating_end") == 0)
+        {
+          if (nb->hydrating)
+            {
+              SVN_ERR(svn_cmdline_printf(pool, _("\n  Hydrated %s text bases\n"),
+                                         nb_dict(n, "count")));
+              nb->hydrating = FALSE;
+            }
+        }
+      break;
+
     case svn_wc_notify_warning:
       /* using handle_error rather than handle_warning in order to show the
        * whole error chain; the latter only shows one error in the chain */
       svn_handle_error2(n->err, stderr, FALSE, "svn: warning: ");
       break;
 
@@ -1258,12 +1293,13 @@ svn_cl__get_notifier(svn_wc_notify_func2
                      apr_pool_t *pool)
 {
   struct notify_baton *nb = apr_pcalloc(pool, sizeof(*nb));
 
   nb->received_some_change = FALSE;
   nb->sent_first_txdelta = FALSE;
+  nb->hydrating = FALSE;
   nb->is_checkout = FALSE;
   nb->is_export = FALSE;
   nb->is_wc_to_repos_copy = FALSE;
   nb->in_external = 0;
   nb->progress_revision = 0;
   nb->had_print_error = FALSE;
