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

This adds hydration feedback notification to the library.

This also makes 'svn' display these notifications, except in 'svn diff' and
'svn cat' which are primarily data output commands where notifications would
interfere with the primary output.

TODO: Update test expectations.

* subversion/include/svn_wc.h
  (svn_wc_notify_action_t): Add new action types.

* subversion/libsvn_client/textbase.c
  (textbase_hydrate_cb): Notify when hydrating each file.
  (svn_client__textbase_sync): Notify when hydrating starts and finishes.

* subversion/svn/notify.c
  (notify_baton,
   svn_cl__get_notifier): Remember when printing hydration notifications.
  (notify_body): Print hydration notifications.

* subversion/svn/cat-cmd.c
  (svn_cl__cat): Suppress all notifications.

* subversion/svn/diff-cmd.c
  (svn_cl__diff): Suppress all 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,28 @@ 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,
 
+  /** Hydrating (fetching text-bases): starting a batch of fetching
+   * within the WC subtree at @c svn_wc_notify_t.path. (Zero or more files
+   * may be fetched, each preceded by @c svn_wc_notify_hydrating_file.)
+   * @since New in 1.15. */
+  svn_wc_notify_hydrating_start,
+
+  /** Hydrating (fetching text-bases): about to fetch a file
+   * from @c svn_wc_notify_t.url at @c svn_wc_notify_t.revision.
+   * @since New in 1.15. */
+  svn_wc_notify_hydrating_file,
+
+  /** Hydrating (fetching text-bases): finished a batch of fetching
+   * within the WC subtree at @c svn_wc_notify_t.path.
+   * @since New in 1.15. */
+  svn_wc_notify_hydrating_end,
+
   /** A warning, specified in #svn_wc_notify_t.err.
    * @since New in 1.15. */
   svn_wc_notify_warning,
 
 } svn_wc_notify_action_t;
 
Index: subversion/libsvn_client/textbase.c
===================================================================
--- subversion/libsvn_client/textbase.c	(revision 1899151)
+++ subversion/libsvn_client/textbase.c	(working copy)
@@ -72,12 +72,22 @@ textbase_hydrate_cb(void *baton,
       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->ctx->notify_func2)
+    {
+      svn_wc_notify_t *notify
+        = svn_wc_create_notify(".", svn_wc_notify_hydrating_file,
+                               scratch_pool);
+      notify->revision = revision;
+      notify->url = url;
+      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));
 
@@ -92,18 +102,34 @@ 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));
 
   baton.pool = scratch_pool;
   baton.ctx = ctx;
   baton.ra_session = NULL;
 
+  if (ctx->notify_func2 && allow_hydrate)
+    {
+      svn_wc_notify_t *notify
+        = svn_wc_create_notify(local_abspath, svn_wc_notify_hydrating_start,
+                               scratch_pool);
+      ctx->notify_func2(ctx->notify_baton2, notify, scratch_pool);
+    }
+
   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 (ctx->notify_func2 && allow_hydrate)
+    {
+      svn_wc_notify_t *notify
+        = svn_wc_create_notify(local_abspath, svn_wc_notify_hydrating_end,
+                               scratch_pool);
+      ctx->notify_func2(ctx->notify_baton2, notify, scratch_pool);
+    }
+
   return SVN_NO_ERROR;
 }
Index: subversion/svn/cat-cmd.c
===================================================================
--- subversion/svn/cat-cmd.c	(revision 1899151)
+++ subversion/svn/cat-cmd.c	(working copy)
@@ -50,12 +50,15 @@ svn_cl__cat(apr_getopt_t *os,
   int i;
   svn_stream_t *out;
   apr_pool_t *subpool = svn_pool_create(pool);
   apr_array_header_t *errors = apr_array_make(pool, 0, sizeof(apr_status_t));
   svn_error_t *err;
 
+  /* Don't print any feedback notifications. (At least not on stdout.) */
+  ctx->notify_func2 = NULL;
+
   SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os,
                                                       opt_state->targets,
                                                       ctx, FALSE, pool));
 
   /* Cat cannot operate on an implicit '.' so a filename is required */
   if (! targets->nelts)
Index: subversion/svn/diff-cmd.c
===================================================================
--- subversion/svn/diff-cmd.c	(revision 1899151)
+++ subversion/svn/diff-cmd.c	(working copy)
@@ -219,12 +219,15 @@ svn_cl__diff(apr_getopt_t *os,
   svn_boolean_t show_copies_as_adds =
     opt_state->diff.patch_compatible || opt_state->diff.show_copies_as_adds;
   svn_boolean_t ignore_properties =
     opt_state->diff.patch_compatible || opt_state->diff.ignore_properties;
   int i;
 
+  /* Don't print any feedback notifications. (At least not on stdout.) */
+  ctx->notify_func2 = NULL;
+
   if (opt_state->extensions)
     options = svn_cstring_split(opt_state->extensions, " \t\n\r", TRUE, pool);
   else
     options = NULL;
 
   /* Get streams representing stdout and stderr, which is where
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_printed_start;
   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;
 
@@ -1204,12 +1205,32 @@ 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_hydrating_start:
+      nb->hydrating_printed_start = FALSE;
+      break;
+
+    case svn_wc_notify_hydrating_file:
+      if (!nb->hydrating_printed_start)
+        {
+          SVN_ERR(svn_cmdline_printf(pool, _("Fetching text bases ")));
+          nb->hydrating_printed_start = TRUE;
+        }
+      SVN_ERR(svn_cmdline_printf(pool, "."));
+      break;
+
+    case svn_wc_notify_hydrating_end:
+      if (nb->hydrating_printed_start)
+        {
+          SVN_ERR(svn_cmdline_printf(pool, _("done\n")));
+        }
+      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 +1279,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_printed_start = 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;
