1251881Speter/*
2251881Speter * notify.c:  feedback handlers for cmdline client.
3251881Speter *
4251881Speter * ====================================================================
5251881Speter *    Licensed to the Apache Software Foundation (ASF) under one
6251881Speter *    or more contributor license agreements.  See the NOTICE file
7251881Speter *    distributed with this work for additional information
8251881Speter *    regarding copyright ownership.  The ASF licenses this file
9251881Speter *    to you under the Apache License, Version 2.0 (the
10251881Speter *    "License"); you may not use this file except in compliance
11251881Speter *    with the License.  You may obtain a copy of the License at
12251881Speter *
13251881Speter *      http://www.apache.org/licenses/LICENSE-2.0
14251881Speter *
15251881Speter *    Unless required by applicable law or agreed to in writing,
16251881Speter *    software distributed under the License is distributed on an
17251881Speter *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18251881Speter *    KIND, either express or implied.  See the License for the
19251881Speter *    specific language governing permissions and limitations
20251881Speter *    under the License.
21251881Speter * ====================================================================
22251881Speter */
23251881Speter
24251881Speter/* ==================================================================== */
25251881Speter
26251881Speter
27251881Speter
28251881Speter/*** Includes. ***/
29251881Speter
30251881Speter#define APR_WANT_STDIO
31251881Speter#define APR_WANT_STRFUNC
32251881Speter#include <apr_want.h>
33251881Speter
34251881Speter#include "svn_cmdline.h"
35251881Speter#include "svn_pools.h"
36251881Speter#include "svn_dirent_uri.h"
37251881Speter#include "svn_path.h"
38251881Speter#include "svn_sorts.h"
39251881Speter#include "svn_hash.h"
40251881Speter#include "cl.h"
41251881Speter#include "private/svn_subr_private.h"
42362181Sdim#include "private/svn_sorts_private.h"
43251881Speter#include "private/svn_dep_compat.h"
44251881Speter
45251881Speter#include "svn_private_config.h"
46251881Speter
47251881Speter
48251881Speter/* Baton for notify and friends. */
49251881Speterstruct notify_baton
50251881Speter{
51251881Speter  svn_boolean_t received_some_change;
52251881Speter  svn_boolean_t is_checkout;
53251881Speter  svn_boolean_t is_export;
54251881Speter  svn_boolean_t is_wc_to_repos_copy;
55251881Speter  svn_boolean_t sent_first_txdelta;
56289180Speter  int in_external;
57362181Sdim  svn_revnum_t progress_revision;
58251881Speter  svn_boolean_t had_print_error; /* Used to not keep printing error messages
59251881Speter                                    when we've already had one print error. */
60251881Speter
61251881Speter  svn_cl__conflict_stats_t *conflict_stats;
62251881Speter
63251881Speter  /* The cwd, for use in decomposing absolute paths. */
64251881Speter  const char *path_prefix;
65251881Speter};
66251881Speter
67251881Speter/* Conflict stats for operations such as update and merge. */
68251881Speterstruct svn_cl__conflict_stats_t
69251881Speter{
70251881Speter  apr_pool_t *stats_pool;
71251881Speter  apr_hash_t *text_conflicts, *prop_conflicts, *tree_conflicts;
72251881Speter  int text_conflicts_resolved, prop_conflicts_resolved, tree_conflicts_resolved;
73251881Speter  int skipped_paths;
74251881Speter};
75251881Speter
76251881Spetersvn_cl__conflict_stats_t *
77251881Spetersvn_cl__conflict_stats_create(apr_pool_t *pool)
78251881Speter{
79251881Speter  svn_cl__conflict_stats_t *conflict_stats
80251881Speter    = apr_palloc(pool, sizeof(*conflict_stats));
81251881Speter
82251881Speter  conflict_stats->stats_pool = pool;
83251881Speter  conflict_stats->text_conflicts = apr_hash_make(pool);
84251881Speter  conflict_stats->prop_conflicts = apr_hash_make(pool);
85251881Speter  conflict_stats->tree_conflicts = apr_hash_make(pool);
86251881Speter  conflict_stats->text_conflicts_resolved = 0;
87251881Speter  conflict_stats->prop_conflicts_resolved = 0;
88251881Speter  conflict_stats->tree_conflicts_resolved = 0;
89251881Speter  conflict_stats->skipped_paths = 0;
90251881Speter  return conflict_stats;
91251881Speter}
92251881Speter
93251881Speter/* Add the PATH (as a key, with a meaningless value) into the HASH in NB. */
94251881Speterstatic void
95251881Speterstore_path(struct notify_baton *nb, apr_hash_t *hash, const char *path)
96251881Speter{
97251881Speter  svn_hash_sets(hash, apr_pstrdup(nb->conflict_stats->stats_pool, path), "");
98251881Speter}
99251881Speter
100251881Spetervoid
101251881Spetersvn_cl__conflict_stats_resolved(svn_cl__conflict_stats_t *conflict_stats,
102251881Speter                                const char *path_local,
103251881Speter                                svn_wc_conflict_kind_t conflict_kind)
104251881Speter{
105251881Speter  switch (conflict_kind)
106251881Speter    {
107251881Speter      case svn_wc_conflict_kind_text:
108251881Speter        if (svn_hash_gets(conflict_stats->text_conflicts, path_local))
109251881Speter          {
110251881Speter            svn_hash_sets(conflict_stats->text_conflicts, path_local, NULL);
111251881Speter            conflict_stats->text_conflicts_resolved++;
112251881Speter          }
113251881Speter        break;
114251881Speter      case svn_wc_conflict_kind_property:
115251881Speter        if (svn_hash_gets(conflict_stats->prop_conflicts, path_local))
116251881Speter          {
117251881Speter            svn_hash_sets(conflict_stats->prop_conflicts, path_local, NULL);
118251881Speter            conflict_stats->prop_conflicts_resolved++;
119251881Speter          }
120251881Speter        break;
121251881Speter      case svn_wc_conflict_kind_tree:
122251881Speter        if (svn_hash_gets(conflict_stats->tree_conflicts, path_local))
123251881Speter          {
124251881Speter            svn_hash_sets(conflict_stats->tree_conflicts, path_local, NULL);
125251881Speter            conflict_stats->tree_conflicts_resolved++;
126251881Speter          }
127251881Speter        break;
128251881Speter    }
129251881Speter}
130251881Speter
131251881Speterstatic const char *
132251881Speterremaining_str(apr_pool_t *pool, int n_remaining)
133251881Speter{
134289180Speter  return apr_psprintf(pool, Q_("%d remaining",
135251881Speter                               "%d remaining",
136251881Speter                               n_remaining),
137251881Speter                      n_remaining);
138251881Speter}
139251881Speter
140251881Speterstatic const char *
141251881Speterresolved_str(apr_pool_t *pool, int n_resolved)
142251881Speter{
143251881Speter  return apr_psprintf(pool, Q_("and %d already resolved",
144251881Speter                               "and %d already resolved",
145251881Speter                               n_resolved),
146251881Speter                      n_resolved);
147251881Speter}
148251881Speter
149251881Spetersvn_error_t *
150362181Sdimsvn_cl__conflict_stats_get_paths(apr_array_header_t **conflicted_paths,
151362181Sdim                                 svn_cl__conflict_stats_t *conflict_stats,
152362181Sdim                                 apr_pool_t *result_pool,
153362181Sdim                                 apr_pool_t *scratch_pool)
154362181Sdim{
155362181Sdim
156362181Sdim  int n_text = apr_hash_count(conflict_stats->text_conflicts);
157362181Sdim  int n_prop = apr_hash_count(conflict_stats->prop_conflicts);
158362181Sdim  int n_tree = apr_hash_count(conflict_stats->tree_conflicts);
159362181Sdim  apr_hash_t *all_conflicts;
160362181Sdim
161362181Sdim  *conflicted_paths = NULL;
162362181Sdim  if (n_text == 0 && n_prop == 0 && n_tree == 0)
163362181Sdim      return SVN_NO_ERROR;
164362181Sdim
165362181Sdim  /* Use a hash table to ensure paths with multiple conflicts are
166362181Sdim   * returned just once. */
167362181Sdim  all_conflicts = apr_hash_make(result_pool);
168362181Sdim  if (n_text > 0)
169362181Sdim    {
170362181Sdim      apr_array_header_t *k_text;
171362181Sdim      int i;
172362181Sdim
173362181Sdim      SVN_ERR(svn_hash_keys(&k_text, conflict_stats->text_conflicts,
174362181Sdim                            scratch_pool));
175362181Sdim      for (i = 0; i < k_text->nelts; i++)
176362181Sdim        {
177362181Sdim          const char *path = APR_ARRAY_IDX(k_text, i, const char *);
178362181Sdim
179362181Sdim          svn_hash_sets(all_conflicts, path, "");
180362181Sdim        }
181362181Sdim    }
182362181Sdim
183362181Sdim  if (n_prop > 0)
184362181Sdim    {
185362181Sdim      apr_array_header_t *k_prop;
186362181Sdim      int i;
187362181Sdim
188362181Sdim      SVN_ERR(svn_hash_keys(&k_prop, conflict_stats->prop_conflicts,
189362181Sdim                            scratch_pool));
190362181Sdim      for (i = 0; i < k_prop->nelts; i++)
191362181Sdim        {
192362181Sdim          const char *path = APR_ARRAY_IDX(k_prop, i, const char *);
193362181Sdim
194362181Sdim          svn_hash_sets(all_conflicts, path, "");
195362181Sdim        }
196362181Sdim    }
197362181Sdim
198362181Sdim  if (n_tree > 0)
199362181Sdim    {
200362181Sdim      apr_array_header_t *k_tree;
201362181Sdim      int i;
202362181Sdim
203362181Sdim      SVN_ERR(svn_hash_keys(&k_tree, conflict_stats->tree_conflicts,
204362181Sdim                            scratch_pool));
205362181Sdim      for (i = 0; i < k_tree->nelts; i++)
206362181Sdim        {
207362181Sdim          const char *path = APR_ARRAY_IDX(k_tree, i, const char *);
208362181Sdim
209362181Sdim          svn_hash_sets(all_conflicts, path, "");
210362181Sdim        }
211362181Sdim    }
212362181Sdim
213362181Sdim  SVN_ERR(svn_hash_keys(conflicted_paths, all_conflicts, result_pool));
214362181Sdim  svn_sort__array(*conflicted_paths, svn_sort_compare_paths);
215362181Sdim
216362181Sdim  return SVN_NO_ERROR;
217362181Sdim}
218362181Sdim
219362181Sdimsvn_error_t *
220289180Spetersvn_cl__print_conflict_stats(svn_cl__conflict_stats_t *conflict_stats,
221289180Speter                             apr_pool_t *scratch_pool)
222251881Speter{
223289180Speter  int n_text = apr_hash_count(conflict_stats->text_conflicts);
224289180Speter  int n_prop = apr_hash_count(conflict_stats->prop_conflicts);
225289180Speter  int n_tree = apr_hash_count(conflict_stats->tree_conflicts);
226289180Speter  int n_text_r = conflict_stats->text_conflicts_resolved;
227289180Speter  int n_prop_r = conflict_stats->prop_conflicts_resolved;
228289180Speter  int n_tree_r = conflict_stats->tree_conflicts_resolved;
229251881Speter
230251881Speter  if (n_text > 0 || n_text_r > 0
231251881Speter      || n_prop > 0 || n_prop_r > 0
232251881Speter      || n_tree > 0 || n_tree_r > 0
233289180Speter      || conflict_stats->skipped_paths > 0)
234251881Speter    SVN_ERR(svn_cmdline_printf(scratch_pool,
235251881Speter                               _("Summary of conflicts:\n")));
236251881Speter
237251881Speter  if (n_text_r == 0 && n_prop_r == 0 && n_tree_r == 0)
238251881Speter    {
239251881Speter      if (n_text > 0)
240251881Speter        SVN_ERR(svn_cmdline_printf(scratch_pool,
241251881Speter          _("  Text conflicts: %d\n"),
242251881Speter          n_text));
243251881Speter      if (n_prop > 0)
244251881Speter        SVN_ERR(svn_cmdline_printf(scratch_pool,
245251881Speter          _("  Property conflicts: %d\n"),
246251881Speter          n_prop));
247251881Speter      if (n_tree > 0)
248251881Speter        SVN_ERR(svn_cmdline_printf(scratch_pool,
249251881Speter          _("  Tree conflicts: %d\n"),
250251881Speter          n_tree));
251251881Speter    }
252251881Speter  else
253251881Speter    {
254251881Speter      if (n_text > 0 || n_text_r > 0)
255251881Speter        SVN_ERR(svn_cmdline_printf(scratch_pool,
256251881Speter                                   _("  Text conflicts: %s (%s)\n"),
257251881Speter                                   remaining_str(scratch_pool, n_text),
258251881Speter                                   resolved_str(scratch_pool, n_text_r)));
259251881Speter      if (n_prop > 0 || n_prop_r > 0)
260251881Speter        SVN_ERR(svn_cmdline_printf(scratch_pool,
261251881Speter                                   _("  Property conflicts: %s (%s)\n"),
262251881Speter                                   remaining_str(scratch_pool, n_prop),
263251881Speter                                   resolved_str(scratch_pool, n_prop_r)));
264251881Speter      if (n_tree > 0 || n_tree_r > 0)
265251881Speter        SVN_ERR(svn_cmdline_printf(scratch_pool,
266251881Speter                                   _("  Tree conflicts: %s (%s)\n"),
267251881Speter                                   remaining_str(scratch_pool, n_tree),
268251881Speter                                   resolved_str(scratch_pool, n_tree_r)));
269251881Speter    }
270289180Speter  if (conflict_stats->skipped_paths > 0)
271251881Speter    SVN_ERR(svn_cmdline_printf(scratch_pool,
272251881Speter                               _("  Skipped paths: %d\n"),
273289180Speter                               conflict_stats->skipped_paths));
274251881Speter
275251881Speter  return SVN_NO_ERROR;
276251881Speter}
277251881Speter
278289180Spetersvn_error_t *
279289180Spetersvn_cl__notifier_print_conflict_stats(void *baton, apr_pool_t *scratch_pool)
280251881Speter{
281251881Speter  struct notify_baton *nb = baton;
282289180Speter
283289180Speter  SVN_ERR(svn_cl__print_conflict_stats(nb->conflict_stats, scratch_pool));
284289180Speter  return SVN_NO_ERROR;
285289180Speter}
286289180Speter
287289180Speter/* The body for notify() function with standard error handling semantic.
288289180Speter * Handling of errors implemented at caller side. */
289289180Speterstatic svn_error_t *
290289180Speternotify_body(struct notify_baton *nb,
291289180Speter            const svn_wc_notify_t *n,
292289180Speter            apr_pool_t *pool)
293289180Speter{
294251881Speter  char statchar_buf[5] = "    ";
295251881Speter  const char *path_local;
296251881Speter
297251881Speter  if (n->url)
298251881Speter    path_local = n->url;
299251881Speter  else
300251881Speter    {
301289180Speter      /* Skip the path prefix in N, if supplied, or else the path prefix
302289180Speter         in NB (which was set to the current working directory). */
303251881Speter      if (n->path_prefix)
304251881Speter        path_local = svn_cl__local_style_skip_ancestor(n->path_prefix, n->path,
305251881Speter                                                       pool);
306289180Speter      else
307251881Speter        path_local = svn_cl__local_style_skip_ancestor(nb->path_prefix, n->path,
308251881Speter                                                       pool);
309251881Speter    }
310251881Speter
311251881Speter  switch (n->action)
312251881Speter    {
313251881Speter    case svn_wc_notify_skip:
314251881Speter      nb->conflict_stats->skipped_paths++;
315251881Speter      if (n->content_state == svn_wc_notify_state_missing)
316251881Speter        {
317289180Speter          SVN_ERR(svn_cmdline_printf(pool,
318289180Speter                                     _("Skipped missing target: '%s'\n"),
319289180Speter                                     path_local));
320251881Speter        }
321251881Speter      else if (n->content_state == svn_wc_notify_state_source_missing)
322251881Speter        {
323289180Speter          SVN_ERR(svn_cmdline_printf(
324289180Speter                    pool,
325289180Speter                    _("Skipped target: '%s' -- copy-source is missing\n"),
326289180Speter                    path_local));
327251881Speter        }
328362181Sdim      else if (n->content_state == svn_wc_notify_state_obstructed)
329362181Sdim        {
330362181Sdim          SVN_ERR(svn_cmdline_printf(
331362181Sdim                    pool,
332362181Sdim                    _("Skipped '%s' -- obstructed by unversioned node\n"),
333362181Sdim                    path_local));
334362181Sdim        }
335251881Speter      else
336251881Speter        {
337289180Speter          SVN_ERR(svn_cmdline_printf(pool, _("Skipped '%s'\n"), path_local));
338251881Speter        }
339251881Speter      break;
340251881Speter    case svn_wc_notify_update_skip_obstruction:
341251881Speter      nb->conflict_stats->skipped_paths++;
342289180Speter      SVN_ERR(svn_cmdline_printf(
343289180Speter                pool,
344289180Speter                _("Skipped '%s' -- An obstructing working copy was found\n"),
345289180Speter                path_local));
346251881Speter      break;
347251881Speter    case svn_wc_notify_update_skip_working_only:
348251881Speter      nb->conflict_stats->skipped_paths++;
349289180Speter      SVN_ERR(svn_cmdline_printf(
350289180Speter                pool, _("Skipped '%s' -- Has no versioned parent\n"),
351289180Speter                path_local));
352251881Speter      break;
353251881Speter    case svn_wc_notify_update_skip_access_denied:
354251881Speter      nb->conflict_stats->skipped_paths++;
355289180Speter      SVN_ERR(svn_cmdline_printf(
356289180Speter                pool, _("Skipped '%s' -- Access denied\n"),
357289180Speter                path_local));
358251881Speter      break;
359251881Speter    case svn_wc_notify_skip_conflicted:
360251881Speter      nb->conflict_stats->skipped_paths++;
361289180Speter      SVN_ERR(svn_cmdline_printf(
362289180Speter                pool, _("Skipped '%s' -- Node remains in conflict\n"),
363289180Speter                path_local));
364251881Speter      break;
365251881Speter    case svn_wc_notify_update_delete:
366251881Speter    case svn_wc_notify_exclude:
367251881Speter      nb->received_some_change = TRUE;
368289180Speter      SVN_ERR(svn_cmdline_printf(pool, "D    %s\n", path_local));
369251881Speter      break;
370251881Speter    case svn_wc_notify_update_broken_lock:
371289180Speter      SVN_ERR(svn_cmdline_printf(pool, "B    %s\n", path_local));
372251881Speter      break;
373251881Speter
374251881Speter    case svn_wc_notify_update_external_removed:
375251881Speter      nb->received_some_change = TRUE;
376251881Speter      if (n->err && n->err->message)
377251881Speter        {
378289180Speter          SVN_ERR(svn_cmdline_printf(pool, _("Removed external '%s': %s\n"),
379289180Speter                                     path_local, n->err->message));
380251881Speter        }
381251881Speter      else
382251881Speter        {
383289180Speter          SVN_ERR(svn_cmdline_printf(pool, _("Removed external '%s'\n"),
384289180Speter                                     path_local));
385251881Speter        }
386251881Speter      break;
387251881Speter
388251881Speter    case svn_wc_notify_left_local_modifications:
389289180Speter      SVN_ERR(svn_cmdline_printf(pool, _("Left local modifications as '%s'\n"),
390289180Speter                                 path_local));
391251881Speter      break;
392251881Speter
393251881Speter    case svn_wc_notify_update_replace:
394251881Speter      nb->received_some_change = TRUE;
395289180Speter      SVN_ERR(svn_cmdline_printf(pool, "R    %s\n", path_local));
396251881Speter      break;
397251881Speter
398251881Speter    case svn_wc_notify_update_add:
399251881Speter      nb->received_some_change = TRUE;
400251881Speter      if (n->content_state == svn_wc_notify_state_conflicted)
401251881Speter        {
402251881Speter          store_path(nb, nb->conflict_stats->text_conflicts, path_local);
403289180Speter          SVN_ERR(svn_cmdline_printf(pool, "C    %s\n", path_local));
404251881Speter        }
405251881Speter      else
406251881Speter        {
407289180Speter          SVN_ERR(svn_cmdline_printf(pool, "A    %s\n", path_local));
408251881Speter        }
409251881Speter      break;
410251881Speter
411251881Speter    case svn_wc_notify_exists:
412251881Speter      nb->received_some_change = TRUE;
413251881Speter      if (n->content_state == svn_wc_notify_state_conflicted)
414251881Speter        {
415251881Speter          store_path(nb, nb->conflict_stats->text_conflicts, path_local);
416251881Speter          statchar_buf[0] = 'C';
417251881Speter        }
418251881Speter      else
419251881Speter        statchar_buf[0] = 'E';
420251881Speter
421251881Speter      if (n->prop_state == svn_wc_notify_state_conflicted)
422251881Speter        {
423251881Speter          store_path(nb, nb->conflict_stats->prop_conflicts, path_local);
424251881Speter          statchar_buf[1] = 'C';
425251881Speter        }
426251881Speter      else if (n->prop_state == svn_wc_notify_state_merged)
427251881Speter        statchar_buf[1] = 'G';
428251881Speter
429289180Speter      SVN_ERR(svn_cmdline_printf(pool, "%s %s\n", statchar_buf, path_local));
430251881Speter      break;
431251881Speter
432251881Speter    case svn_wc_notify_restore:
433289180Speter      SVN_ERR(svn_cmdline_printf(pool, _("Restored '%s'\n"),
434289180Speter                                 path_local));
435251881Speter      break;
436251881Speter
437251881Speter    case svn_wc_notify_revert:
438289180Speter      SVN_ERR(svn_cmdline_printf(pool, _("Reverted '%s'\n"),
439289180Speter                                 path_local));
440251881Speter      break;
441251881Speter
442251881Speter    case svn_wc_notify_failed_revert:
443289180Speter      SVN_ERR(svn_cmdline_printf(pool, _("Failed to revert '%s' -- "
444289180Speter                                         "try updating instead.\n"),
445289180Speter                                 path_local));
446251881Speter      break;
447251881Speter
448251881Speter    case svn_wc_notify_resolved:
449289180Speter      SVN_ERR(svn_cmdline_printf(pool,
450289180Speter                                 _("Resolved conflicted state of '%s'\n"),
451289180Speter                                 path_local));
452251881Speter      break;
453251881Speter
454362181Sdim    case svn_wc_notify_resolved_text:
455362181Sdim      SVN_ERR(svn_cmdline_printf(pool,
456362181Sdim                                 _("Merge conflicts in '%s' marked as "
457362181Sdim                                   "resolved.\n"),
458362181Sdim                                 path_local));
459362181Sdim      break;
460362181Sdim
461362181Sdim    case svn_wc_notify_resolved_prop:
462362181Sdim      SVN_ERR_ASSERT(n->prop_name && strlen(n->prop_name) > 0);
463362181Sdim      SVN_ERR(svn_cmdline_printf(pool,
464362181Sdim                                 _("Conflict in property '%s' at '%s' marked "
465362181Sdim                                   "as resolved.\n"),
466362181Sdim                                 n->prop_name, path_local));
467362181Sdim      break;
468362181Sdim
469362181Sdim    case svn_wc_notify_resolved_tree:
470362181Sdim      SVN_ERR(svn_cmdline_printf(pool,
471362181Sdim                                 _("Tree conflict at '%s' marked as "
472362181Sdim                                   "resolved.\n"),
473362181Sdim                                 path_local));
474362181Sdim      break;
475362181Sdim
476362181Sdim    case svn_wc_notify_begin_search_tree_conflict_details:
477362181Sdim      SVN_ERR(svn_cmdline_printf(pool,
478362181Sdim                                 _("Searching tree conflict details for '%s' "
479362181Sdim                                   "in repository:\n"),
480362181Sdim                                 path_local));
481362181Sdim      nb->progress_revision = 0;
482362181Sdim      break;
483362181Sdim
484362181Sdim    case svn_wc_notify_tree_conflict_details_progress:
485362181Sdim      /* First printf is to obliterate any previous progress printf,
486362181Sdim         assuming no more than 10 digit revisions.  Avoid i18n so the
487362181Sdim         text length is known.  We only need to do this if the new
488362181Sdim         revision is 4 digits less than the previous revision but that
489362181Sdim         requires counting digits.  Dividing by 1000 works well
490362181Sdim         enough: it triggers when needed, it sometimes triggers when
491362181Sdim         not needed, but in typical cases it doesn't trigger as the
492362181Sdim         revisions don't vary much. */
493362181Sdim      if (n->revision < nb->progress_revision / 1000)
494362181Sdim        SVN_ERR(svn_cmdline_printf(pool, "\rChecking r             "));
495362181Sdim      SVN_ERR(svn_cmdline_printf(pool, "\rChecking r%ld...", n->revision));
496362181Sdim      nb->progress_revision = n->revision;
497362181Sdim      break;
498362181Sdim
499362181Sdim    case svn_wc_notify_end_search_tree_conflict_details:
500362181Sdim      SVN_ERR(svn_cmdline_printf(pool, _(" done\n")));
501362181Sdim      nb->progress_revision = 0;
502362181Sdim      break;
503362181Sdim
504251881Speter    case svn_wc_notify_add:
505251881Speter      /* We *should* only get the MIME_TYPE if PATH is a file.  If we
506251881Speter         do get it, and the mime-type is not textual, note that this
507251881Speter         is a binary addition. */
508251881Speter      if (n->mime_type && (svn_mime_type_is_binary(n->mime_type)))
509251881Speter        {
510289180Speter          SVN_ERR(svn_cmdline_printf(pool, "A  (bin)  %s\n",
511289180Speter                                     path_local));
512251881Speter        }
513251881Speter      else
514251881Speter        {
515289180Speter          SVN_ERR(svn_cmdline_printf(pool, "A         %s\n",
516289180Speter                                     path_local));
517251881Speter        }
518251881Speter      break;
519251881Speter
520251881Speter    case svn_wc_notify_delete:
521251881Speter      nb->received_some_change = TRUE;
522289180Speter      SVN_ERR(svn_cmdline_printf(pool, "D         %s\n",
523289180Speter                                 path_local));
524251881Speter      break;
525251881Speter
526251881Speter    case svn_wc_notify_patch:
527251881Speter      {
528251881Speter        nb->received_some_change = TRUE;
529251881Speter        if (n->content_state == svn_wc_notify_state_conflicted)
530251881Speter          {
531251881Speter            store_path(nb, nb->conflict_stats->text_conflicts, path_local);
532251881Speter            statchar_buf[0] = 'C';
533251881Speter          }
534251881Speter        else if (n->kind == svn_node_file)
535251881Speter          {
536251881Speter            if (n->content_state == svn_wc_notify_state_merged)
537251881Speter              statchar_buf[0] = 'G';
538251881Speter            else if (n->content_state == svn_wc_notify_state_changed)
539251881Speter              statchar_buf[0] = 'U';
540251881Speter          }
541251881Speter
542251881Speter        if (n->prop_state == svn_wc_notify_state_conflicted)
543251881Speter          {
544251881Speter            store_path(nb, nb->conflict_stats->prop_conflicts, path_local);
545251881Speter            statchar_buf[1] = 'C';
546251881Speter          }
547362181Sdim        else if (n->prop_state == svn_wc_notify_state_merged)
548362181Sdim          statchar_buf[1] = 'G';
549251881Speter        else if (n->prop_state == svn_wc_notify_state_changed)
550362181Sdim          statchar_buf[1] = 'U';
551251881Speter
552251881Speter        if (statchar_buf[0] != ' ' || statchar_buf[1] != ' ')
553251881Speter          {
554289180Speter            SVN_ERR(svn_cmdline_printf(pool, "%s      %s\n",
555289180Speter                                       statchar_buf, path_local));
556251881Speter          }
557251881Speter      }
558251881Speter      break;
559251881Speter
560251881Speter    case svn_wc_notify_patch_applied_hunk:
561251881Speter      nb->received_some_change = TRUE;
562251881Speter      if (n->hunk_original_start != n->hunk_matched_line)
563251881Speter        {
564251881Speter          apr_uint64_t off;
565251881Speter          const char *s;
566251881Speter          const char *minus;
567251881Speter
568251881Speter          if (n->hunk_matched_line > n->hunk_original_start)
569251881Speter            {
570251881Speter              /* If we are patching from the start of an empty file,
571251881Speter                 it is nicer to show offset 0 */
572251881Speter              if (n->hunk_original_start == 0 && n->hunk_matched_line == 1)
573251881Speter                off = 0; /* No offset, just adding */
574251881Speter              else
575251881Speter                off = n->hunk_matched_line - n->hunk_original_start;
576251881Speter
577251881Speter              minus = "";
578251881Speter            }
579251881Speter          else
580251881Speter            {
581251881Speter              off = n->hunk_original_start - n->hunk_matched_line;
582251881Speter              minus = "-";
583251881Speter            }
584251881Speter
585251881Speter          /* ### We're creating the localized strings without
586251881Speter           * ### APR_INT64_T_FMT since it isn't translator-friendly */
587251881Speter          if (n->hunk_fuzz)
588251881Speter            {
589251881Speter
590251881Speter              if (n->prop_name)
591251881Speter                {
592251881Speter                  s = _(">         applied hunk ## -%lu,%lu +%lu,%lu ## "
593251881Speter                        "with offset %s");
594251881Speter
595289180Speter                  SVN_ERR(svn_cmdline_printf(pool,
596289180Speter                                             apr_pstrcat(pool, s,
597289180Speter                                                         "%"APR_UINT64_T_FMT
598289180Speter                                                         " and fuzz %lu (%s)\n",
599289180Speter                                                         SVN_VA_NULL),
600289180Speter                                             n->hunk_original_start,
601289180Speter                                             n->hunk_original_length,
602289180Speter                                             n->hunk_modified_start,
603289180Speter                                             n->hunk_modified_length,
604289180Speter                                             minus, off, n->hunk_fuzz,
605289180Speter                                             n->prop_name));
606251881Speter                }
607251881Speter              else
608251881Speter                {
609251881Speter                  s = _(">         applied hunk @@ -%lu,%lu +%lu,%lu @@ "
610251881Speter                        "with offset %s");
611251881Speter
612289180Speter                  SVN_ERR(svn_cmdline_printf(pool,
613289180Speter                                             apr_pstrcat(pool, s,
614289180Speter                                                         "%"APR_UINT64_T_FMT
615289180Speter                                                         " and fuzz %lu\n",
616289180Speter                                                         SVN_VA_NULL),
617289180Speter                                             n->hunk_original_start,
618289180Speter                                             n->hunk_original_length,
619289180Speter                                             n->hunk_modified_start,
620289180Speter                                             n->hunk_modified_length,
621289180Speter                                             minus, off, n->hunk_fuzz));
622251881Speter                }
623251881Speter            }
624251881Speter          else
625251881Speter            {
626251881Speter
627251881Speter              if (n->prop_name)
628251881Speter                {
629251881Speter                  s = _(">         applied hunk ## -%lu,%lu +%lu,%lu ## "
630251881Speter                        "with offset %s");
631289180Speter                  SVN_ERR(svn_cmdline_printf(pool,
632289180Speter                                              apr_pstrcat(pool, s,
633289180Speter                                                          "%"APR_UINT64_T_FMT" (%s)\n",
634289180Speter                                                          SVN_VA_NULL),
635289180Speter                                              n->hunk_original_start,
636289180Speter                                              n->hunk_original_length,
637289180Speter                                              n->hunk_modified_start,
638289180Speter                                              n->hunk_modified_length,
639289180Speter                                              minus, off, n->prop_name));
640251881Speter                }
641251881Speter              else
642251881Speter                {
643251881Speter                  s = _(">         applied hunk @@ -%lu,%lu +%lu,%lu @@ "
644251881Speter                        "with offset %s");
645289180Speter                  SVN_ERR(svn_cmdline_printf(pool,
646289180Speter                                             apr_pstrcat(pool, s,
647289180Speter                                                         "%"APR_UINT64_T_FMT"\n",
648289180Speter                                                         SVN_VA_NULL),
649289180Speter                                             n->hunk_original_start,
650289180Speter                                             n->hunk_original_length,
651289180Speter                                             n->hunk_modified_start,
652289180Speter                                             n->hunk_modified_length,
653289180Speter                                             minus, off));
654251881Speter                }
655251881Speter            }
656251881Speter        }
657251881Speter      else if (n->hunk_fuzz)
658251881Speter        {
659251881Speter          if (n->prop_name)
660289180Speter            SVN_ERR(svn_cmdline_printf(pool,
661251881Speter                          _(">         applied hunk ## -%lu,%lu +%lu,%lu ## "
662251881Speter                                        "with fuzz %lu (%s)\n"),
663251881Speter                                        n->hunk_original_start,
664251881Speter                                        n->hunk_original_length,
665251881Speter                                        n->hunk_modified_start,
666251881Speter                                        n->hunk_modified_length,
667251881Speter                                        n->hunk_fuzz,
668289180Speter                                        n->prop_name));
669251881Speter          else
670289180Speter            SVN_ERR(svn_cmdline_printf(pool,
671251881Speter                          _(">         applied hunk @@ -%lu,%lu +%lu,%lu @@ "
672251881Speter                                        "with fuzz %lu\n"),
673251881Speter                                        n->hunk_original_start,
674251881Speter                                        n->hunk_original_length,
675251881Speter                                        n->hunk_modified_start,
676251881Speter                                        n->hunk_modified_length,
677289180Speter                                        n->hunk_fuzz));
678251881Speter
679251881Speter        }
680251881Speter      break;
681251881Speter
682251881Speter    case svn_wc_notify_patch_rejected_hunk:
683251881Speter      nb->received_some_change = TRUE;
684251881Speter
685251881Speter      if (n->prop_name)
686289180Speter        SVN_ERR(svn_cmdline_printf(pool,
687289180Speter                                   _(">         rejected hunk "
688289180Speter                                     "## -%lu,%lu +%lu,%lu ## (%s)\n"),
689289180Speter                                   n->hunk_original_start,
690289180Speter                                   n->hunk_original_length,
691289180Speter                                   n->hunk_modified_start,
692289180Speter                                   n->hunk_modified_length,
693289180Speter                                   n->prop_name));
694251881Speter      else
695289180Speter        SVN_ERR(svn_cmdline_printf(pool,
696289180Speter                                   _(">         rejected hunk "
697289180Speter                                     "@@ -%lu,%lu +%lu,%lu @@\n"),
698289180Speter                                   n->hunk_original_start,
699289180Speter                                   n->hunk_original_length,
700289180Speter                                   n->hunk_modified_start,
701289180Speter                                   n->hunk_modified_length));
702251881Speter      break;
703251881Speter
704251881Speter    case svn_wc_notify_patch_hunk_already_applied:
705251881Speter      nb->received_some_change = TRUE;
706251881Speter      if (n->prop_name)
707289180Speter        SVN_ERR(svn_cmdline_printf(pool,
708289180Speter                                   _(">         hunk "
709289180Speter                                     "## -%lu,%lu +%lu,%lu ## "
710289180Speter                                     "already applied (%s)\n"),
711289180Speter                                   n->hunk_original_start,
712289180Speter                                   n->hunk_original_length,
713289180Speter                                   n->hunk_modified_start,
714289180Speter                                   n->hunk_modified_length,
715289180Speter                                   n->prop_name));
716251881Speter      else
717289180Speter        SVN_ERR(svn_cmdline_printf(pool,
718289180Speter                                   _(">         hunk "
719289180Speter                                     "@@ -%lu,%lu +%lu,%lu @@ "
720289180Speter                                     "already applied\n"),
721289180Speter                                   n->hunk_original_start,
722289180Speter                                   n->hunk_original_length,
723289180Speter                                   n->hunk_modified_start,
724289180Speter                                   n->hunk_modified_length));
725251881Speter      break;
726251881Speter
727251881Speter    case svn_wc_notify_update_update:
728251881Speter    case svn_wc_notify_merge_record_info:
729251881Speter      {
730251881Speter        if (n->content_state == svn_wc_notify_state_conflicted)
731251881Speter          {
732251881Speter            store_path(nb, nb->conflict_stats->text_conflicts, path_local);
733251881Speter            statchar_buf[0] = 'C';
734251881Speter          }
735251881Speter        else if (n->kind == svn_node_file)
736251881Speter          {
737251881Speter            if (n->content_state == svn_wc_notify_state_merged)
738251881Speter              statchar_buf[0] = 'G';
739251881Speter            else if (n->content_state == svn_wc_notify_state_changed)
740251881Speter              statchar_buf[0] = 'U';
741251881Speter          }
742251881Speter
743251881Speter        if (n->prop_state == svn_wc_notify_state_conflicted)
744251881Speter          {
745251881Speter            store_path(nb, nb->conflict_stats->prop_conflicts, path_local);
746251881Speter            statchar_buf[1] = 'C';
747251881Speter          }
748251881Speter        else if (n->prop_state == svn_wc_notify_state_merged)
749251881Speter          statchar_buf[1] = 'G';
750251881Speter        else if (n->prop_state == svn_wc_notify_state_changed)
751251881Speter          statchar_buf[1] = 'U';
752251881Speter
753251881Speter        if (n->lock_state == svn_wc_notify_lock_state_unlocked)
754251881Speter          statchar_buf[2] = 'B';
755251881Speter
756251881Speter        if (statchar_buf[0] != ' ' || statchar_buf[1] != ' ')
757251881Speter          nb->received_some_change = TRUE;
758251881Speter
759251881Speter        if (statchar_buf[0] != ' ' || statchar_buf[1] != ' '
760251881Speter            || statchar_buf[2] != ' ')
761251881Speter          {
762289180Speter            SVN_ERR(svn_cmdline_printf(pool, "%s %s\n",
763289180Speter                                       statchar_buf, path_local));
764251881Speter          }
765251881Speter      }
766251881Speter      break;
767251881Speter
768251881Speter    case svn_wc_notify_update_external:
769251881Speter      /* Remember that we're now "inside" an externals definition. */
770289180Speter      ++nb->in_external;
771251881Speter
772251881Speter      /* Currently this is used for checkouts and switches too.  If we
773251881Speter         want different output, we'll have to add new actions. */
774289180Speter      SVN_ERR(svn_cmdline_printf(pool,
775289180Speter                                 _("\nFetching external item into '%s':\n"),
776289180Speter                                 path_local));
777251881Speter      break;
778251881Speter
779251881Speter    case svn_wc_notify_failed_external:
780251881Speter      /* If we are currently inside the handling of an externals
781251881Speter         definition, then we can simply present n->err as a warning
782251881Speter         and feel confident that after this, we aren't handling that
783251881Speter         externals definition any longer. */
784251881Speter      if (nb->in_external)
785251881Speter        {
786251881Speter          svn_handle_warning2(stderr, n->err, "svn: ");
787289180Speter          --nb->in_external;
788289180Speter          SVN_ERR(svn_cmdline_printf(pool, "\n"));
789251881Speter        }
790251881Speter      /* Otherwise, we'll just print two warnings.  Why?  Because
791251881Speter         svn_handle_warning2() only shows the single "best message",
792251881Speter         but we have two pretty important ones: that the external at
793251881Speter         '/some/path' didn't pan out, and then the more specific
794251881Speter         reason why (from n->err). */
795251881Speter      else
796251881Speter        {
797251881Speter          svn_error_t *warn_err =
798289180Speter            svn_error_createf(SVN_ERR_CL_ERROR_PROCESSING_EXTERNALS, NULL,
799251881Speter                              _("Error handling externals definition for '%s':"),
800251881Speter                              path_local);
801251881Speter          svn_handle_warning2(stderr, warn_err, "svn: ");
802251881Speter          svn_error_clear(warn_err);
803251881Speter          svn_handle_warning2(stderr, n->err, "svn: ");
804251881Speter        }
805251881Speter      break;
806251881Speter
807251881Speter    case svn_wc_notify_update_started:
808251881Speter      if (! (nb->in_external ||
809251881Speter             nb->is_checkout ||
810251881Speter             nb->is_export))
811251881Speter        {
812289180Speter          SVN_ERR(svn_cmdline_printf(pool, _("Updating '%s':\n"),
813289180Speter                                     path_local));
814251881Speter        }
815251881Speter      break;
816251881Speter
817251881Speter    case svn_wc_notify_update_completed:
818251881Speter      {
819251881Speter        if (SVN_IS_VALID_REVNUM(n->revision))
820251881Speter          {
821251881Speter            if (nb->is_export)
822251881Speter              {
823289180Speter                SVN_ERR(svn_cmdline_printf(
824289180Speter                          pool, nb->in_external
825289180Speter                            ? _("Exported external at revision %ld.\n")
826289180Speter                            : _("Exported revision %ld.\n"),
827289180Speter                          n->revision));
828251881Speter              }
829251881Speter            else if (nb->is_checkout)
830251881Speter              {
831289180Speter                SVN_ERR(svn_cmdline_printf(
832289180Speter                          pool, nb->in_external
833289180Speter                            ? _("Checked out external at revision %ld.\n")
834289180Speter                            : _("Checked out revision %ld.\n"),
835289180Speter                          n->revision));
836251881Speter              }
837251881Speter            else
838251881Speter              {
839251881Speter                if (nb->received_some_change)
840251881Speter                  {
841251881Speter                    nb->received_some_change = FALSE;
842289180Speter                    SVN_ERR(svn_cmdline_printf(
843289180Speter                              pool, nb->in_external
844289180Speter                                ? _("Updated external to revision %ld.\n")
845289180Speter                                : _("Updated to revision %ld.\n"),
846289180Speter                              n->revision));
847251881Speter                  }
848251881Speter                else
849251881Speter                  {
850289180Speter                    SVN_ERR(svn_cmdline_printf(
851289180Speter                              pool, nb->in_external
852289180Speter                                ? _("External at revision %ld.\n")
853289180Speter                                : _("At revision %ld.\n"),
854289180Speter                               n->revision));
855251881Speter                  }
856251881Speter              }
857251881Speter          }
858251881Speter        else  /* no revision */
859251881Speter          {
860251881Speter            if (nb->is_export)
861251881Speter              {
862289180Speter                SVN_ERR(svn_cmdline_printf(
863289180Speter                          pool, nb->in_external
864289180Speter                            ? _("External export complete.\n")
865289180Speter                            : _("Export complete.\n")));
866251881Speter              }
867251881Speter            else if (nb->is_checkout)
868251881Speter              {
869289180Speter                SVN_ERR(svn_cmdline_printf(
870289180Speter                          pool, nb->in_external
871289180Speter                            ? _("External checkout complete.\n")
872289180Speter                            : _("Checkout complete.\n")));
873251881Speter              }
874251881Speter            else
875251881Speter              {
876289180Speter                SVN_ERR(svn_cmdline_printf(
877289180Speter                          pool, nb->in_external
878289180Speter                            ? _("External update complete.\n")
879289180Speter                            : _("Update complete.\n")));
880251881Speter              }
881251881Speter          }
882251881Speter      }
883251881Speter
884251881Speter      if (nb->in_external)
885251881Speter        {
886289180Speter          --nb->in_external;
887289180Speter          SVN_ERR(svn_cmdline_printf(pool, "\n"));
888251881Speter        }
889251881Speter      break;
890251881Speter
891251881Speter    case svn_wc_notify_status_external:
892289180Speter      SVN_ERR(svn_cmdline_printf(
893289180Speter        pool, _("\nPerforming status on external item at '%s':\n"),
894289180Speter        path_local));
895251881Speter      break;
896251881Speter
897289180Speter    case svn_wc_notify_info_external:
898289180Speter      SVN_ERR(svn_cmdline_printf(
899289180Speter         pool, _("\nPerforming info on external item at '%s':\n"),
900289180Speter         path_local));
901289180Speter      break;
902289180Speter
903251881Speter    case svn_wc_notify_status_completed:
904251881Speter      if (SVN_IS_VALID_REVNUM(n->revision))
905289180Speter        SVN_ERR(svn_cmdline_printf(pool,
906289180Speter                                   _("Status against revision: %6ld\n"),
907289180Speter                                   n->revision));
908251881Speter      break;
909251881Speter
910251881Speter    case svn_wc_notify_commit_modified:
911251881Speter      /* xgettext: Align the %s's on this and the following 4 messages */
912289180Speter      SVN_ERR(svn_cmdline_printf(pool,
913289180Speter                                 nb->is_wc_to_repos_copy
914289180Speter                                   ? _("Sending copy of       %s\n")
915289180Speter                                   : _("Sending        %s\n"),
916289180Speter                                 path_local));
917251881Speter      break;
918251881Speter
919251881Speter    case svn_wc_notify_commit_added:
920251881Speter    case svn_wc_notify_commit_copied:
921251881Speter      if (n->mime_type && svn_mime_type_is_binary(n->mime_type))
922251881Speter        {
923289180Speter          SVN_ERR(svn_cmdline_printf(pool,
924289180Speter                                     nb->is_wc_to_repos_copy
925289180Speter                                       ? _("Adding copy of (bin)  %s\n")
926289180Speter                                       : _("Adding  (bin)  %s\n"),
927289180Speter                                     path_local));
928251881Speter        }
929251881Speter      else
930251881Speter        {
931289180Speter          SVN_ERR(svn_cmdline_printf(pool,
932289180Speter                                     nb->is_wc_to_repos_copy
933289180Speter                                       ? _("Adding copy of        %s\n")
934289180Speter                                       : _("Adding         %s\n"),
935289180Speter                                     path_local));
936251881Speter        }
937251881Speter      break;
938251881Speter
939251881Speter    case svn_wc_notify_commit_deleted:
940289180Speter      SVN_ERR(svn_cmdline_printf(pool,
941289180Speter                                 nb->is_wc_to_repos_copy
942289180Speter                                   ? _("Deleting copy of      %s\n")
943289180Speter                                   : _("Deleting       %s\n"),
944289180Speter                                 path_local));
945251881Speter      break;
946251881Speter
947251881Speter    case svn_wc_notify_commit_replaced:
948251881Speter    case svn_wc_notify_commit_copied_replaced:
949289180Speter      SVN_ERR(svn_cmdline_printf(pool,
950289180Speter                                 nb->is_wc_to_repos_copy
951289180Speter                                   ? _("Replacing copy of     %s\n")
952289180Speter                                   : _("Replacing      %s\n"),
953289180Speter                                 path_local));
954251881Speter      break;
955251881Speter
956251881Speter    case svn_wc_notify_commit_postfix_txdelta:
957251881Speter      if (! nb->sent_first_txdelta)
958251881Speter        {
959251881Speter          nb->sent_first_txdelta = TRUE;
960289180Speter          SVN_ERR(svn_cmdline_printf(pool,
961289180Speter                                     _("Transmitting file data ")));
962251881Speter        }
963251881Speter
964289180Speter      SVN_ERR(svn_cmdline_printf(pool, "."));
965251881Speter      break;
966251881Speter
967251881Speter    case svn_wc_notify_locked:
968289180Speter      SVN_ERR(svn_cmdline_printf(pool, _("'%s' locked by user '%s'.\n"),
969289180Speter                                 path_local, n->lock->owner));
970251881Speter      break;
971251881Speter
972251881Speter    case svn_wc_notify_unlocked:
973289180Speter      SVN_ERR(svn_cmdline_printf(pool, _("'%s' unlocked.\n"),
974289180Speter                                 path_local));
975251881Speter      break;
976251881Speter
977251881Speter    case svn_wc_notify_failed_lock:
978251881Speter    case svn_wc_notify_failed_unlock:
979251881Speter      svn_handle_warning2(stderr, n->err, "svn: ");
980251881Speter      break;
981251881Speter
982251881Speter    case svn_wc_notify_changelist_set:
983289180Speter      SVN_ERR(svn_cmdline_printf(pool, "A [%s] %s\n",
984289180Speter                                 n->changelist_name, path_local));
985251881Speter      break;
986251881Speter
987251881Speter    case svn_wc_notify_changelist_clear:
988251881Speter    case svn_wc_notify_changelist_moved:
989289180Speter      SVN_ERR(svn_cmdline_printf(pool,
990289180Speter                                 "D [%s] %s\n",
991289180Speter                                 n->changelist_name, path_local));
992251881Speter      break;
993251881Speter
994251881Speter    case svn_wc_notify_merge_begin:
995251881Speter      if (n->merge_range == NULL)
996289180Speter        SVN_ERR(svn_cmdline_printf(pool,
997289180Speter                                   _("--- Merging differences between "
998289180Speter                                     "repository URLs into '%s':\n"),
999289180Speter                                   path_local));
1000251881Speter      else if (n->merge_range->start == n->merge_range->end - 1
1001251881Speter          || n->merge_range->start == n->merge_range->end)
1002289180Speter        SVN_ERR(svn_cmdline_printf(pool, _("--- Merging r%ld into '%s':\n"),
1003289180Speter                                   n->merge_range->end, path_local));
1004251881Speter      else if (n->merge_range->start - 1 == n->merge_range->end)
1005289180Speter        SVN_ERR(svn_cmdline_printf(pool,
1006289180Speter                                   _("--- Reverse-merging r%ld into '%s':\n"),
1007289180Speter                                   n->merge_range->start, path_local));
1008251881Speter      else if (n->merge_range->start < n->merge_range->end)
1009289180Speter        SVN_ERR(svn_cmdline_printf(pool,
1010289180Speter                                   _("--- Merging r%ld through r%ld into "
1011289180Speter                                     "'%s':\n"),
1012289180Speter                                   n->merge_range->start + 1,
1013289180Speter                                   n->merge_range->end, path_local));
1014251881Speter      else /* n->merge_range->start > n->merge_range->end - 1 */
1015289180Speter        SVN_ERR(svn_cmdline_printf(pool,
1016289180Speter                                   _("--- Reverse-merging r%ld through r%ld "
1017289180Speter                                     "into '%s':\n"),
1018289180Speter                                   n->merge_range->start,
1019289180Speter                                   n->merge_range->end + 1, path_local));
1020251881Speter      break;
1021251881Speter
1022251881Speter    case svn_wc_notify_merge_record_info_begin:
1023251881Speter      if (!n->merge_range)
1024251881Speter        {
1025289180Speter          SVN_ERR(svn_cmdline_printf(pool,
1026289180Speter                                     _("--- Recording mergeinfo for merge "
1027289180Speter                                       "between repository URLs into '%s':\n"),
1028289180Speter                                     path_local));
1029251881Speter        }
1030251881Speter      else
1031251881Speter        {
1032251881Speter          if (n->merge_range->start == n->merge_range->end - 1
1033251881Speter              || n->merge_range->start == n->merge_range->end)
1034289180Speter            SVN_ERR(svn_cmdline_printf(
1035251881Speter              pool,
1036251881Speter              _("--- Recording mergeinfo for merge of r%ld into '%s':\n"),
1037289180Speter              n->merge_range->end, path_local));
1038251881Speter          else if (n->merge_range->start - 1 == n->merge_range->end)
1039289180Speter            SVN_ERR(svn_cmdline_printf(
1040251881Speter              pool,
1041251881Speter              _("--- Recording mergeinfo for reverse merge of r%ld into '%s':\n"),
1042289180Speter              n->merge_range->start, path_local));
1043251881Speter           else if (n->merge_range->start < n->merge_range->end)
1044289180Speter             SVN_ERR(svn_cmdline_printf(
1045251881Speter               pool,
1046251881Speter               _("--- Recording mergeinfo for merge of r%ld through r%ld into '%s':\n"),
1047289180Speter               n->merge_range->start + 1, n->merge_range->end, path_local));
1048251881Speter           else /* n->merge_range->start > n->merge_range->end - 1 */
1049289180Speter             SVN_ERR(svn_cmdline_printf(
1050251881Speter               pool,
1051251881Speter               _("--- Recording mergeinfo for reverse merge of r%ld through r%ld into '%s':\n"),
1052289180Speter               n->merge_range->start, n->merge_range->end + 1, path_local));
1053251881Speter        }
1054251881Speter      break;
1055251881Speter
1056251881Speter    case svn_wc_notify_merge_elide_info:
1057289180Speter      SVN_ERR(svn_cmdline_printf(pool,
1058289180Speter                                 _("--- Eliding mergeinfo from '%s':\n"),
1059289180Speter                                 path_local));
1060251881Speter      break;
1061251881Speter
1062251881Speter    case svn_wc_notify_foreign_merge_begin:
1063251881Speter      if (n->merge_range == NULL)
1064289180Speter        SVN_ERR(svn_cmdline_printf(pool,
1065289180Speter                                   _("--- Merging differences between "
1066289180Speter                                     "foreign repository URLs into '%s':\n"),
1067289180Speter                                   path_local));
1068251881Speter      else if (n->merge_range->start == n->merge_range->end - 1
1069251881Speter          || n->merge_range->start == n->merge_range->end)
1070289180Speter        SVN_ERR(svn_cmdline_printf(pool,
1071289180Speter                                   _("--- Merging (from foreign repository) "
1072289180Speter                                     "r%ld into '%s':\n"),
1073289180Speter                                   n->merge_range->end, path_local));
1074251881Speter      else if (n->merge_range->start - 1 == n->merge_range->end)
1075289180Speter        SVN_ERR(svn_cmdline_printf(pool,
1076289180Speter                                   _("--- Reverse-merging (from foreign "
1077289180Speter                                     "repository) r%ld into '%s':\n"),
1078289180Speter                                   n->merge_range->start, path_local));
1079251881Speter      else if (n->merge_range->start < n->merge_range->end)
1080289180Speter        SVN_ERR(svn_cmdline_printf(pool,
1081289180Speter                                   _("--- Merging (from foreign repository) "
1082289180Speter                                     "r%ld through r%ld into '%s':\n"),
1083289180Speter                                   n->merge_range->start + 1,
1084289180Speter                                   n->merge_range->end, path_local));
1085251881Speter      else /* n->merge_range->start > n->merge_range->end - 1 */
1086289180Speter        SVN_ERR(svn_cmdline_printf(pool,
1087289180Speter                                   _("--- Reverse-merging (from foreign "
1088289180Speter                                     "repository) r%ld through r%ld into "
1089289180Speter                                     "'%s':\n"),
1090289180Speter                                   n->merge_range->start,
1091289180Speter                                   n->merge_range->end + 1, path_local));
1092251881Speter      break;
1093251881Speter
1094251881Speter    case svn_wc_notify_tree_conflict:
1095251881Speter      store_path(nb, nb->conflict_stats->tree_conflicts, path_local);
1096289180Speter      SVN_ERR(svn_cmdline_printf(pool, "   C %s\n", path_local));
1097251881Speter      break;
1098251881Speter
1099251881Speter    case svn_wc_notify_update_shadowed_add:
1100251881Speter      nb->received_some_change = TRUE;
1101289180Speter      SVN_ERR(svn_cmdline_printf(pool, "   A %s\n", path_local));
1102251881Speter      break;
1103251881Speter
1104251881Speter    case svn_wc_notify_update_shadowed_update:
1105251881Speter      nb->received_some_change = TRUE;
1106289180Speter      SVN_ERR(svn_cmdline_printf(pool, "   U %s\n", path_local));
1107251881Speter      break;
1108251881Speter
1109251881Speter    case svn_wc_notify_update_shadowed_delete:
1110251881Speter      nb->received_some_change = TRUE;
1111289180Speter      SVN_ERR(svn_cmdline_printf(pool, "   D %s\n", path_local));
1112251881Speter      break;
1113251881Speter
1114251881Speter    case svn_wc_notify_property_modified:
1115251881Speter    case svn_wc_notify_property_added:
1116289180Speter      SVN_ERR(svn_cmdline_printf(pool,
1117289180Speter                                 _("property '%s' set on '%s'\n"),
1118289180Speter                                 n->prop_name, path_local));
1119251881Speter      break;
1120251881Speter
1121251881Speter    case svn_wc_notify_property_deleted:
1122289180Speter      SVN_ERR(svn_cmdline_printf(pool,
1123289180Speter                                 _("property '%s' deleted from '%s'.\n"),
1124289180Speter                                 n->prop_name, path_local));
1125251881Speter      break;
1126251881Speter
1127251881Speter    case svn_wc_notify_property_deleted_nonexistent:
1128289180Speter      SVN_ERR(svn_cmdline_printf(pool,
1129289180Speter                                 _("Attempting to delete nonexistent "
1130289180Speter                                   "property '%s' on '%s'\n"), n->prop_name,
1131289180Speter                                 path_local));
1132251881Speter      break;
1133251881Speter
1134251881Speter    case svn_wc_notify_revprop_set:
1135289180Speter      SVN_ERR(svn_cmdline_printf(pool,
1136251881Speter                           _("property '%s' set on repository revision %ld\n"),
1137289180Speter                           n->prop_name, n->revision));
1138251881Speter      break;
1139251881Speter
1140251881Speter    case svn_wc_notify_revprop_deleted:
1141289180Speter      SVN_ERR(svn_cmdline_printf(pool,
1142251881Speter                     _("property '%s' deleted from repository revision %ld\n"),
1143289180Speter                     n->prop_name, n->revision));
1144251881Speter      break;
1145251881Speter
1146251881Speter    case svn_wc_notify_upgraded_path:
1147289180Speter      SVN_ERR(svn_cmdline_printf(pool, _("Upgraded '%s'\n"), path_local));
1148251881Speter      break;
1149251881Speter
1150251881Speter    case svn_wc_notify_url_redirect:
1151289180Speter      SVN_ERR(svn_cmdline_printf(pool, _("Redirecting to URL '%s':\n"),
1152289180Speter                                 n->url));
1153251881Speter      break;
1154251881Speter
1155251881Speter    case svn_wc_notify_path_nonexistent:
1156289180Speter      SVN_ERR(svn_cmdline_printf(pool, "%s\n",
1157289180Speter                apr_psprintf(pool, _("'%s' is not under version control"),
1158289180Speter                             path_local)));
1159251881Speter      break;
1160251881Speter
1161251881Speter    case svn_wc_notify_conflict_resolver_starting:
1162251881Speter      /* Once all operations invoke the interactive conflict resolution after
1163251881Speter       * they've completed, we can run svn_cl__notifier_print_conflict_stats()
1164251881Speter       * here. */
1165251881Speter      break;
1166251881Speter
1167251881Speter    case svn_wc_notify_conflict_resolver_done:
1168251881Speter      break;
1169251881Speter
1170251881Speter    case svn_wc_notify_foreign_copy_begin:
1171251881Speter      if (n->merge_range == NULL)
1172251881Speter        {
1173289180Speter          SVN_ERR(svn_cmdline_printf(
1174251881Speter                           pool,
1175251881Speter                           _("--- Copying from foreign repository URL '%s':\n"),
1176289180Speter                           n->url));
1177251881Speter        }
1178251881Speter      break;
1179251881Speter
1180251881Speter    case svn_wc_notify_move_broken:
1181289180Speter      SVN_ERR(svn_cmdline_printf(pool,
1182289180Speter                                 _("Breaking move with source path '%s'\n"),
1183289180Speter                                 path_local));
1184251881Speter      break;
1185251881Speter
1186289180Speter    case svn_wc_notify_cleanup_external:
1187289180Speter      SVN_ERR(svn_cmdline_printf
1188289180Speter                (pool, _("Performing cleanup on external item at '%s'.\n"),
1189289180Speter                 path_local));
1190289180Speter      break;
1191289180Speter
1192289180Speter    case svn_wc_notify_commit_finalizing:
1193289180Speter      if (nb->sent_first_txdelta)
1194289180Speter        {
1195289180Speter          SVN_ERR(svn_cmdline_printf(pool, _("done\n")));
1196289180Speter        }
1197289180Speter      SVN_ERR(svn_cmdline_printf(pool, _("Committing transaction...\n")));
1198289180Speter      break;
1199289180Speter
1200251881Speter    default:
1201251881Speter      break;
1202251881Speter    }
1203251881Speter
1204289180Speter  SVN_ERR(svn_cmdline_fflush(stdout));
1205251881Speter
1206289180Speter  return SVN_NO_ERROR;
1207289180Speter}
1208251881Speter
1209289180Speter/* This implements `svn_wc_notify_func2_t'.
1210289180Speter * NOTE: This function can't fail, so we just ignore any print errors. */
1211289180Speterstatic void
1212289180Speternotify(void *baton, const svn_wc_notify_t *n, apr_pool_t *pool)
1213289180Speter{
1214289180Speter  struct notify_baton *nb = baton;
1215289180Speter  svn_error_t *err;
1216289180Speter
1217289180Speter  err = notify_body(nb, n, pool);
1218289180Speter
1219251881Speter  /* If we had no errors before, print this error to stderr. Else, don't print
1220251881Speter     anything.  The user already knows there were some output errors,
1221251881Speter     so there is no point in flooding her with an error per notification. */
1222289180Speter  if (err && !nb->had_print_error)
1223251881Speter    {
1224251881Speter      nb->had_print_error = TRUE;
1225251881Speter      /* Issue #3014:
1226251881Speter       * Don't print anything on broken pipes. The pipe was likely
1227251881Speter       * closed by the process at the other end. We expect that
1228251881Speter       * process to perform error reporting as necessary.
1229251881Speter       *
1230251881Speter       * ### This assumes that there is only one error in a chain for
1231251881Speter       * ### SVN_ERR_IO_PIPE_WRITE_ERROR. See svn_cmdline_fputs(). */
1232251881Speter      if (err->apr_err != SVN_ERR_IO_PIPE_WRITE_ERROR)
1233251881Speter        svn_handle_error2(err, stderr, FALSE, "svn: ");
1234251881Speter    }
1235251881Speter  svn_error_clear(err);
1236251881Speter}
1237251881Speter
1238251881Spetersvn_error_t *
1239251881Spetersvn_cl__get_notifier(svn_wc_notify_func2_t *notify_func_p,
1240251881Speter                     void **notify_baton_p,
1241251881Speter                     svn_cl__conflict_stats_t *conflict_stats,
1242251881Speter                     apr_pool_t *pool)
1243251881Speter{
1244251881Speter  struct notify_baton *nb = apr_pcalloc(pool, sizeof(*nb));
1245251881Speter
1246251881Speter  nb->received_some_change = FALSE;
1247251881Speter  nb->sent_first_txdelta = FALSE;
1248251881Speter  nb->is_checkout = FALSE;
1249251881Speter  nb->is_export = FALSE;
1250251881Speter  nb->is_wc_to_repos_copy = FALSE;
1251289180Speter  nb->in_external = 0;
1252362181Sdim  nb->progress_revision = 0;
1253251881Speter  nb->had_print_error = FALSE;
1254251881Speter  nb->conflict_stats = conflict_stats;
1255251881Speter  SVN_ERR(svn_dirent_get_absolute(&nb->path_prefix, "", pool));
1256251881Speter
1257251881Speter  *notify_func_p = notify;
1258251881Speter  *notify_baton_p = nb;
1259251881Speter  return SVN_NO_ERROR;
1260251881Speter}
1261251881Speter
1262251881Spetersvn_error_t *
1263251881Spetersvn_cl__notifier_mark_checkout(void *baton)
1264251881Speter{
1265251881Speter  struct notify_baton *nb = baton;
1266251881Speter
1267251881Speter  nb->is_checkout = TRUE;
1268251881Speter  return SVN_NO_ERROR;
1269251881Speter}
1270251881Speter
1271251881Spetersvn_error_t *
1272251881Spetersvn_cl__notifier_mark_export(void *baton)
1273251881Speter{
1274251881Speter  struct notify_baton *nb = baton;
1275251881Speter
1276251881Speter  nb->is_export = TRUE;
1277251881Speter  return SVN_NO_ERROR;
1278251881Speter}
1279251881Speter
1280251881Spetersvn_error_t *
1281251881Spetersvn_cl__notifier_mark_wc_to_repos_copy(void *baton)
1282251881Speter{
1283251881Speter  struct notify_baton *nb = baton;
1284251881Speter
1285251881Speter  nb->is_wc_to_repos_copy = TRUE;
1286251881Speter  return SVN_NO_ERROR;
1287251881Speter}
1288251881Speter
1289251881Spetervoid
1290251881Spetersvn_cl__check_externals_failed_notify_wrapper(void *baton,
1291251881Speter                                              const svn_wc_notify_t *n,
1292251881Speter                                              apr_pool_t *pool)
1293251881Speter{
1294251881Speter  struct svn_cl__check_externals_failed_notify_baton *nwb = baton;
1295251881Speter
1296251881Speter  if (n->action == svn_wc_notify_failed_external)
1297251881Speter    nwb->had_externals_error = TRUE;
1298251881Speter
1299251881Speter  if (nwb->wrapped_func)
1300251881Speter    nwb->wrapped_func(nwb->wrapped_baton, n, pool);
1301251881Speter}
1302