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"
42251881Speter#include "private/svn_dep_compat.h"
43251881Speter
44251881Speter#include "svn_private_config.h"
45251881Speter
46251881Speter
47251881Speter/* Baton for notify and friends. */
48251881Speterstruct notify_baton
49251881Speter{
50251881Speter  svn_boolean_t received_some_change;
51251881Speter  svn_boolean_t is_checkout;
52251881Speter  svn_boolean_t is_export;
53251881Speter  svn_boolean_t is_wc_to_repos_copy;
54251881Speter  svn_boolean_t sent_first_txdelta;
55299742Sdim  int in_external;
56251881Speter  svn_boolean_t had_print_error; /* Used to not keep printing error messages
57251881Speter                                    when we've already had one print error. */
58251881Speter
59251881Speter  svn_cl__conflict_stats_t *conflict_stats;
60251881Speter
61251881Speter  /* The cwd, for use in decomposing absolute paths. */
62251881Speter  const char *path_prefix;
63251881Speter};
64251881Speter
65251881Speter/* Conflict stats for operations such as update and merge. */
66251881Speterstruct svn_cl__conflict_stats_t
67251881Speter{
68251881Speter  apr_pool_t *stats_pool;
69251881Speter  apr_hash_t *text_conflicts, *prop_conflicts, *tree_conflicts;
70251881Speter  int text_conflicts_resolved, prop_conflicts_resolved, tree_conflicts_resolved;
71251881Speter  int skipped_paths;
72251881Speter};
73251881Speter
74251881Spetersvn_cl__conflict_stats_t *
75251881Spetersvn_cl__conflict_stats_create(apr_pool_t *pool)
76251881Speter{
77251881Speter  svn_cl__conflict_stats_t *conflict_stats
78251881Speter    = apr_palloc(pool, sizeof(*conflict_stats));
79251881Speter
80251881Speter  conflict_stats->stats_pool = pool;
81251881Speter  conflict_stats->text_conflicts = apr_hash_make(pool);
82251881Speter  conflict_stats->prop_conflicts = apr_hash_make(pool);
83251881Speter  conflict_stats->tree_conflicts = apr_hash_make(pool);
84251881Speter  conflict_stats->text_conflicts_resolved = 0;
85251881Speter  conflict_stats->prop_conflicts_resolved = 0;
86251881Speter  conflict_stats->tree_conflicts_resolved = 0;
87251881Speter  conflict_stats->skipped_paths = 0;
88251881Speter  return conflict_stats;
89251881Speter}
90251881Speter
91251881Speter/* Add the PATH (as a key, with a meaningless value) into the HASH in NB. */
92251881Speterstatic void
93251881Speterstore_path(struct notify_baton *nb, apr_hash_t *hash, const char *path)
94251881Speter{
95251881Speter  svn_hash_sets(hash, apr_pstrdup(nb->conflict_stats->stats_pool, path), "");
96251881Speter}
97251881Speter
98251881Spetervoid
99251881Spetersvn_cl__conflict_stats_resolved(svn_cl__conflict_stats_t *conflict_stats,
100251881Speter                                const char *path_local,
101251881Speter                                svn_wc_conflict_kind_t conflict_kind)
102251881Speter{
103251881Speter  switch (conflict_kind)
104251881Speter    {
105251881Speter      case svn_wc_conflict_kind_text:
106251881Speter        if (svn_hash_gets(conflict_stats->text_conflicts, path_local))
107251881Speter          {
108251881Speter            svn_hash_sets(conflict_stats->text_conflicts, path_local, NULL);
109251881Speter            conflict_stats->text_conflicts_resolved++;
110251881Speter          }
111251881Speter        break;
112251881Speter      case svn_wc_conflict_kind_property:
113251881Speter        if (svn_hash_gets(conflict_stats->prop_conflicts, path_local))
114251881Speter          {
115251881Speter            svn_hash_sets(conflict_stats->prop_conflicts, path_local, NULL);
116251881Speter            conflict_stats->prop_conflicts_resolved++;
117251881Speter          }
118251881Speter        break;
119251881Speter      case svn_wc_conflict_kind_tree:
120251881Speter        if (svn_hash_gets(conflict_stats->tree_conflicts, path_local))
121251881Speter          {
122251881Speter            svn_hash_sets(conflict_stats->tree_conflicts, path_local, NULL);
123251881Speter            conflict_stats->tree_conflicts_resolved++;
124251881Speter          }
125251881Speter        break;
126251881Speter    }
127251881Speter}
128251881Speter
129251881Speterstatic const char *
130251881Speterremaining_str(apr_pool_t *pool, int n_remaining)
131251881Speter{
132299742Sdim  return apr_psprintf(pool, Q_("%d remaining",
133251881Speter                               "%d remaining",
134251881Speter                               n_remaining),
135251881Speter                      n_remaining);
136251881Speter}
137251881Speter
138251881Speterstatic const char *
139251881Speterresolved_str(apr_pool_t *pool, int n_resolved)
140251881Speter{
141251881Speter  return apr_psprintf(pool, Q_("and %d already resolved",
142251881Speter                               "and %d already resolved",
143251881Speter                               n_resolved),
144251881Speter                      n_resolved);
145251881Speter}
146251881Speter
147251881Spetersvn_error_t *
148299742Sdimsvn_cl__print_conflict_stats(svn_cl__conflict_stats_t *conflict_stats,
149299742Sdim                             apr_pool_t *scratch_pool)
150251881Speter{
151299742Sdim  int n_text = apr_hash_count(conflict_stats->text_conflicts);
152299742Sdim  int n_prop = apr_hash_count(conflict_stats->prop_conflicts);
153299742Sdim  int n_tree = apr_hash_count(conflict_stats->tree_conflicts);
154299742Sdim  int n_text_r = conflict_stats->text_conflicts_resolved;
155299742Sdim  int n_prop_r = conflict_stats->prop_conflicts_resolved;
156299742Sdim  int n_tree_r = conflict_stats->tree_conflicts_resolved;
157251881Speter
158251881Speter  if (n_text > 0 || n_text_r > 0
159251881Speter      || n_prop > 0 || n_prop_r > 0
160251881Speter      || n_tree > 0 || n_tree_r > 0
161299742Sdim      || conflict_stats->skipped_paths > 0)
162251881Speter    SVN_ERR(svn_cmdline_printf(scratch_pool,
163251881Speter                               _("Summary of conflicts:\n")));
164251881Speter
165251881Speter  if (n_text_r == 0 && n_prop_r == 0 && n_tree_r == 0)
166251881Speter    {
167251881Speter      if (n_text > 0)
168251881Speter        SVN_ERR(svn_cmdline_printf(scratch_pool,
169251881Speter          _("  Text conflicts: %d\n"),
170251881Speter          n_text));
171251881Speter      if (n_prop > 0)
172251881Speter        SVN_ERR(svn_cmdline_printf(scratch_pool,
173251881Speter          _("  Property conflicts: %d\n"),
174251881Speter          n_prop));
175251881Speter      if (n_tree > 0)
176251881Speter        SVN_ERR(svn_cmdline_printf(scratch_pool,
177251881Speter          _("  Tree conflicts: %d\n"),
178251881Speter          n_tree));
179251881Speter    }
180251881Speter  else
181251881Speter    {
182251881Speter      if (n_text > 0 || n_text_r > 0)
183251881Speter        SVN_ERR(svn_cmdline_printf(scratch_pool,
184251881Speter                                   _("  Text conflicts: %s (%s)\n"),
185251881Speter                                   remaining_str(scratch_pool, n_text),
186251881Speter                                   resolved_str(scratch_pool, n_text_r)));
187251881Speter      if (n_prop > 0 || n_prop_r > 0)
188251881Speter        SVN_ERR(svn_cmdline_printf(scratch_pool,
189251881Speter                                   _("  Property conflicts: %s (%s)\n"),
190251881Speter                                   remaining_str(scratch_pool, n_prop),
191251881Speter                                   resolved_str(scratch_pool, n_prop_r)));
192251881Speter      if (n_tree > 0 || n_tree_r > 0)
193251881Speter        SVN_ERR(svn_cmdline_printf(scratch_pool,
194251881Speter                                   _("  Tree conflicts: %s (%s)\n"),
195251881Speter                                   remaining_str(scratch_pool, n_tree),
196251881Speter                                   resolved_str(scratch_pool, n_tree_r)));
197251881Speter    }
198299742Sdim  if (conflict_stats->skipped_paths > 0)
199251881Speter    SVN_ERR(svn_cmdline_printf(scratch_pool,
200251881Speter                               _("  Skipped paths: %d\n"),
201299742Sdim                               conflict_stats->skipped_paths));
202251881Speter
203251881Speter  return SVN_NO_ERROR;
204251881Speter}
205251881Speter
206299742Sdimsvn_error_t *
207299742Sdimsvn_cl__notifier_print_conflict_stats(void *baton, apr_pool_t *scratch_pool)
208251881Speter{
209251881Speter  struct notify_baton *nb = baton;
210299742Sdim
211299742Sdim  SVN_ERR(svn_cl__print_conflict_stats(nb->conflict_stats, scratch_pool));
212299742Sdim  return SVN_NO_ERROR;
213299742Sdim}
214299742Sdim
215299742Sdim/* The body for notify() function with standard error handling semantic.
216299742Sdim * Handling of errors implemented at caller side. */
217299742Sdimstatic svn_error_t *
218299742Sdimnotify_body(struct notify_baton *nb,
219299742Sdim            const svn_wc_notify_t *n,
220299742Sdim            apr_pool_t *pool)
221299742Sdim{
222251881Speter  char statchar_buf[5] = "    ";
223251881Speter  const char *path_local;
224251881Speter
225251881Speter  if (n->url)
226251881Speter    path_local = n->url;
227251881Speter  else
228251881Speter    {
229299742Sdim      /* Skip the path prefix in N, if supplied, or else the path prefix
230299742Sdim         in NB (which was set to the current working directory). */
231251881Speter      if (n->path_prefix)
232251881Speter        path_local = svn_cl__local_style_skip_ancestor(n->path_prefix, n->path,
233251881Speter                                                       pool);
234299742Sdim      else
235251881Speter        path_local = svn_cl__local_style_skip_ancestor(nb->path_prefix, n->path,
236251881Speter                                                       pool);
237251881Speter    }
238251881Speter
239251881Speter  switch (n->action)
240251881Speter    {
241251881Speter    case svn_wc_notify_skip:
242251881Speter      nb->conflict_stats->skipped_paths++;
243251881Speter      if (n->content_state == svn_wc_notify_state_missing)
244251881Speter        {
245299742Sdim          SVN_ERR(svn_cmdline_printf(pool,
246299742Sdim                                     _("Skipped missing target: '%s'\n"),
247299742Sdim                                     path_local));
248251881Speter        }
249251881Speter      else if (n->content_state == svn_wc_notify_state_source_missing)
250251881Speter        {
251299742Sdim          SVN_ERR(svn_cmdline_printf(
252299742Sdim                    pool,
253299742Sdim                    _("Skipped target: '%s' -- copy-source is missing\n"),
254299742Sdim                    path_local));
255251881Speter        }
256251881Speter      else
257251881Speter        {
258299742Sdim          SVN_ERR(svn_cmdline_printf(pool, _("Skipped '%s'\n"), path_local));
259251881Speter        }
260251881Speter      break;
261251881Speter    case svn_wc_notify_update_skip_obstruction:
262251881Speter      nb->conflict_stats->skipped_paths++;
263299742Sdim      SVN_ERR(svn_cmdline_printf(
264299742Sdim                pool,
265299742Sdim                _("Skipped '%s' -- An obstructing working copy was found\n"),
266299742Sdim                path_local));
267251881Speter      break;
268251881Speter    case svn_wc_notify_update_skip_working_only:
269251881Speter      nb->conflict_stats->skipped_paths++;
270299742Sdim      SVN_ERR(svn_cmdline_printf(
271299742Sdim                pool, _("Skipped '%s' -- Has no versioned parent\n"),
272299742Sdim                path_local));
273251881Speter      break;
274251881Speter    case svn_wc_notify_update_skip_access_denied:
275251881Speter      nb->conflict_stats->skipped_paths++;
276299742Sdim      SVN_ERR(svn_cmdline_printf(
277299742Sdim                pool, _("Skipped '%s' -- Access denied\n"),
278299742Sdim                path_local));
279251881Speter      break;
280251881Speter    case svn_wc_notify_skip_conflicted:
281251881Speter      nb->conflict_stats->skipped_paths++;
282299742Sdim      SVN_ERR(svn_cmdline_printf(
283299742Sdim                pool, _("Skipped '%s' -- Node remains in conflict\n"),
284299742Sdim                path_local));
285251881Speter      break;
286251881Speter    case svn_wc_notify_update_delete:
287251881Speter    case svn_wc_notify_exclude:
288251881Speter      nb->received_some_change = TRUE;
289299742Sdim      SVN_ERR(svn_cmdline_printf(pool, "D    %s\n", path_local));
290251881Speter      break;
291251881Speter    case svn_wc_notify_update_broken_lock:
292299742Sdim      SVN_ERR(svn_cmdline_printf(pool, "B    %s\n", path_local));
293251881Speter      break;
294251881Speter
295251881Speter    case svn_wc_notify_update_external_removed:
296251881Speter      nb->received_some_change = TRUE;
297251881Speter      if (n->err && n->err->message)
298251881Speter        {
299299742Sdim          SVN_ERR(svn_cmdline_printf(pool, _("Removed external '%s': %s\n"),
300299742Sdim                                     path_local, n->err->message));
301251881Speter        }
302251881Speter      else
303251881Speter        {
304299742Sdim          SVN_ERR(svn_cmdline_printf(pool, _("Removed external '%s'\n"),
305299742Sdim                                     path_local));
306251881Speter        }
307251881Speter      break;
308251881Speter
309251881Speter    case svn_wc_notify_left_local_modifications:
310299742Sdim      SVN_ERR(svn_cmdline_printf(pool, _("Left local modifications as '%s'\n"),
311299742Sdim                                 path_local));
312251881Speter      break;
313251881Speter
314251881Speter    case svn_wc_notify_update_replace:
315251881Speter      nb->received_some_change = TRUE;
316299742Sdim      SVN_ERR(svn_cmdline_printf(pool, "R    %s\n", path_local));
317251881Speter      break;
318251881Speter
319251881Speter    case svn_wc_notify_update_add:
320251881Speter      nb->received_some_change = TRUE;
321251881Speter      if (n->content_state == svn_wc_notify_state_conflicted)
322251881Speter        {
323251881Speter          store_path(nb, nb->conflict_stats->text_conflicts, path_local);
324299742Sdim          SVN_ERR(svn_cmdline_printf(pool, "C    %s\n", path_local));
325251881Speter        }
326251881Speter      else
327251881Speter        {
328299742Sdim          SVN_ERR(svn_cmdline_printf(pool, "A    %s\n", path_local));
329251881Speter        }
330251881Speter      break;
331251881Speter
332251881Speter    case svn_wc_notify_exists:
333251881Speter      nb->received_some_change = TRUE;
334251881Speter      if (n->content_state == svn_wc_notify_state_conflicted)
335251881Speter        {
336251881Speter          store_path(nb, nb->conflict_stats->text_conflicts, path_local);
337251881Speter          statchar_buf[0] = 'C';
338251881Speter        }
339251881Speter      else
340251881Speter        statchar_buf[0] = 'E';
341251881Speter
342251881Speter      if (n->prop_state == svn_wc_notify_state_conflicted)
343251881Speter        {
344251881Speter          store_path(nb, nb->conflict_stats->prop_conflicts, path_local);
345251881Speter          statchar_buf[1] = 'C';
346251881Speter        }
347251881Speter      else if (n->prop_state == svn_wc_notify_state_merged)
348251881Speter        statchar_buf[1] = 'G';
349251881Speter
350299742Sdim      SVN_ERR(svn_cmdline_printf(pool, "%s %s\n", statchar_buf, path_local));
351251881Speter      break;
352251881Speter
353251881Speter    case svn_wc_notify_restore:
354299742Sdim      SVN_ERR(svn_cmdline_printf(pool, _("Restored '%s'\n"),
355299742Sdim                                 path_local));
356251881Speter      break;
357251881Speter
358251881Speter    case svn_wc_notify_revert:
359299742Sdim      SVN_ERR(svn_cmdline_printf(pool, _("Reverted '%s'\n"),
360299742Sdim                                 path_local));
361251881Speter      break;
362251881Speter
363251881Speter    case svn_wc_notify_failed_revert:
364299742Sdim      SVN_ERR(svn_cmdline_printf(pool, _("Failed to revert '%s' -- "
365299742Sdim                                         "try updating instead.\n"),
366299742Sdim                                 path_local));
367251881Speter      break;
368251881Speter
369251881Speter    case svn_wc_notify_resolved:
370299742Sdim      SVN_ERR(svn_cmdline_printf(pool,
371299742Sdim                                 _("Resolved conflicted state of '%s'\n"),
372299742Sdim                                 path_local));
373251881Speter      break;
374251881Speter
375251881Speter    case svn_wc_notify_add:
376251881Speter      /* We *should* only get the MIME_TYPE if PATH is a file.  If we
377251881Speter         do get it, and the mime-type is not textual, note that this
378251881Speter         is a binary addition. */
379251881Speter      if (n->mime_type && (svn_mime_type_is_binary(n->mime_type)))
380251881Speter        {
381299742Sdim          SVN_ERR(svn_cmdline_printf(pool, "A  (bin)  %s\n",
382299742Sdim                                     path_local));
383251881Speter        }
384251881Speter      else
385251881Speter        {
386299742Sdim          SVN_ERR(svn_cmdline_printf(pool, "A         %s\n",
387299742Sdim                                     path_local));
388251881Speter        }
389251881Speter      break;
390251881Speter
391251881Speter    case svn_wc_notify_delete:
392251881Speter      nb->received_some_change = TRUE;
393299742Sdim      SVN_ERR(svn_cmdline_printf(pool, "D         %s\n",
394299742Sdim                                 path_local));
395251881Speter      break;
396251881Speter
397251881Speter    case svn_wc_notify_patch:
398251881Speter      {
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);
403251881Speter            statchar_buf[0] = 'C';
404251881Speter          }
405251881Speter        else if (n->kind == svn_node_file)
406251881Speter          {
407251881Speter            if (n->content_state == svn_wc_notify_state_merged)
408251881Speter              statchar_buf[0] = 'G';
409251881Speter            else if (n->content_state == svn_wc_notify_state_changed)
410251881Speter              statchar_buf[0] = 'U';
411251881Speter          }
412251881Speter
413251881Speter        if (n->prop_state == svn_wc_notify_state_conflicted)
414251881Speter          {
415251881Speter            store_path(nb, nb->conflict_stats->prop_conflicts, path_local);
416251881Speter            statchar_buf[1] = 'C';
417251881Speter          }
418251881Speter        else if (n->prop_state == svn_wc_notify_state_changed)
419251881Speter              statchar_buf[1] = 'U';
420251881Speter
421251881Speter        if (statchar_buf[0] != ' ' || statchar_buf[1] != ' ')
422251881Speter          {
423299742Sdim            SVN_ERR(svn_cmdline_printf(pool, "%s      %s\n",
424299742Sdim                                       statchar_buf, path_local));
425251881Speter          }
426251881Speter      }
427251881Speter      break;
428251881Speter
429251881Speter    case svn_wc_notify_patch_applied_hunk:
430251881Speter      nb->received_some_change = TRUE;
431251881Speter      if (n->hunk_original_start != n->hunk_matched_line)
432251881Speter        {
433251881Speter          apr_uint64_t off;
434251881Speter          const char *s;
435251881Speter          const char *minus;
436251881Speter
437251881Speter          if (n->hunk_matched_line > n->hunk_original_start)
438251881Speter            {
439251881Speter              /* If we are patching from the start of an empty file,
440251881Speter                 it is nicer to show offset 0 */
441251881Speter              if (n->hunk_original_start == 0 && n->hunk_matched_line == 1)
442251881Speter                off = 0; /* No offset, just adding */
443251881Speter              else
444251881Speter                off = n->hunk_matched_line - n->hunk_original_start;
445251881Speter
446251881Speter              minus = "";
447251881Speter            }
448251881Speter          else
449251881Speter            {
450251881Speter              off = n->hunk_original_start - n->hunk_matched_line;
451251881Speter              minus = "-";
452251881Speter            }
453251881Speter
454251881Speter          /* ### We're creating the localized strings without
455251881Speter           * ### APR_INT64_T_FMT since it isn't translator-friendly */
456251881Speter          if (n->hunk_fuzz)
457251881Speter            {
458251881Speter
459251881Speter              if (n->prop_name)
460251881Speter                {
461251881Speter                  s = _(">         applied hunk ## -%lu,%lu +%lu,%lu ## "
462251881Speter                        "with offset %s");
463251881Speter
464299742Sdim                  SVN_ERR(svn_cmdline_printf(pool,
465299742Sdim                                             apr_pstrcat(pool, s,
466299742Sdim                                                         "%"APR_UINT64_T_FMT
467299742Sdim                                                         " and fuzz %lu (%s)\n",
468299742Sdim                                                         SVN_VA_NULL),
469299742Sdim                                             n->hunk_original_start,
470299742Sdim                                             n->hunk_original_length,
471299742Sdim                                             n->hunk_modified_start,
472299742Sdim                                             n->hunk_modified_length,
473299742Sdim                                             minus, off, n->hunk_fuzz,
474299742Sdim                                             n->prop_name));
475251881Speter                }
476251881Speter              else
477251881Speter                {
478251881Speter                  s = _(">         applied hunk @@ -%lu,%lu +%lu,%lu @@ "
479251881Speter                        "with offset %s");
480251881Speter
481299742Sdim                  SVN_ERR(svn_cmdline_printf(pool,
482299742Sdim                                             apr_pstrcat(pool, s,
483299742Sdim                                                         "%"APR_UINT64_T_FMT
484299742Sdim                                                         " and fuzz %lu\n",
485299742Sdim                                                         SVN_VA_NULL),
486299742Sdim                                             n->hunk_original_start,
487299742Sdim                                             n->hunk_original_length,
488299742Sdim                                             n->hunk_modified_start,
489299742Sdim                                             n->hunk_modified_length,
490299742Sdim                                             minus, off, n->hunk_fuzz));
491251881Speter                }
492251881Speter            }
493251881Speter          else
494251881Speter            {
495251881Speter
496251881Speter              if (n->prop_name)
497251881Speter                {
498251881Speter                  s = _(">         applied hunk ## -%lu,%lu +%lu,%lu ## "
499251881Speter                        "with offset %s");
500299742Sdim                  SVN_ERR(svn_cmdline_printf(pool,
501299742Sdim                                              apr_pstrcat(pool, s,
502299742Sdim                                                          "%"APR_UINT64_T_FMT" (%s)\n",
503299742Sdim                                                          SVN_VA_NULL),
504299742Sdim                                              n->hunk_original_start,
505299742Sdim                                              n->hunk_original_length,
506299742Sdim                                              n->hunk_modified_start,
507299742Sdim                                              n->hunk_modified_length,
508299742Sdim                                              minus, off, n->prop_name));
509251881Speter                }
510251881Speter              else
511251881Speter                {
512251881Speter                  s = _(">         applied hunk @@ -%lu,%lu +%lu,%lu @@ "
513251881Speter                        "with offset %s");
514299742Sdim                  SVN_ERR(svn_cmdline_printf(pool,
515299742Sdim                                             apr_pstrcat(pool, s,
516299742Sdim                                                         "%"APR_UINT64_T_FMT"\n",
517299742Sdim                                                         SVN_VA_NULL),
518299742Sdim                                             n->hunk_original_start,
519299742Sdim                                             n->hunk_original_length,
520299742Sdim                                             n->hunk_modified_start,
521299742Sdim                                             n->hunk_modified_length,
522299742Sdim                                             minus, off));
523251881Speter                }
524251881Speter            }
525251881Speter        }
526251881Speter      else if (n->hunk_fuzz)
527251881Speter        {
528251881Speter          if (n->prop_name)
529299742Sdim            SVN_ERR(svn_cmdline_printf(pool,
530251881Speter                          _(">         applied hunk ## -%lu,%lu +%lu,%lu ## "
531251881Speter                                        "with fuzz %lu (%s)\n"),
532251881Speter                                        n->hunk_original_start,
533251881Speter                                        n->hunk_original_length,
534251881Speter                                        n->hunk_modified_start,
535251881Speter                                        n->hunk_modified_length,
536251881Speter                                        n->hunk_fuzz,
537299742Sdim                                        n->prop_name));
538251881Speter          else
539299742Sdim            SVN_ERR(svn_cmdline_printf(pool,
540251881Speter                          _(">         applied hunk @@ -%lu,%lu +%lu,%lu @@ "
541251881Speter                                        "with fuzz %lu\n"),
542251881Speter                                        n->hunk_original_start,
543251881Speter                                        n->hunk_original_length,
544251881Speter                                        n->hunk_modified_start,
545251881Speter                                        n->hunk_modified_length,
546299742Sdim                                        n->hunk_fuzz));
547251881Speter
548251881Speter        }
549251881Speter      break;
550251881Speter
551251881Speter    case svn_wc_notify_patch_rejected_hunk:
552251881Speter      nb->received_some_change = TRUE;
553251881Speter
554251881Speter      if (n->prop_name)
555299742Sdim        SVN_ERR(svn_cmdline_printf(pool,
556299742Sdim                                   _(">         rejected hunk "
557299742Sdim                                     "## -%lu,%lu +%lu,%lu ## (%s)\n"),
558299742Sdim                                   n->hunk_original_start,
559299742Sdim                                   n->hunk_original_length,
560299742Sdim                                   n->hunk_modified_start,
561299742Sdim                                   n->hunk_modified_length,
562299742Sdim                                   n->prop_name));
563251881Speter      else
564299742Sdim        SVN_ERR(svn_cmdline_printf(pool,
565299742Sdim                                   _(">         rejected hunk "
566299742Sdim                                     "@@ -%lu,%lu +%lu,%lu @@\n"),
567299742Sdim                                   n->hunk_original_start,
568299742Sdim                                   n->hunk_original_length,
569299742Sdim                                   n->hunk_modified_start,
570299742Sdim                                   n->hunk_modified_length));
571251881Speter      break;
572251881Speter
573251881Speter    case svn_wc_notify_patch_hunk_already_applied:
574251881Speter      nb->received_some_change = TRUE;
575251881Speter      if (n->prop_name)
576299742Sdim        SVN_ERR(svn_cmdline_printf(pool,
577299742Sdim                                   _(">         hunk "
578299742Sdim                                     "## -%lu,%lu +%lu,%lu ## "
579299742Sdim                                     "already applied (%s)\n"),
580299742Sdim                                   n->hunk_original_start,
581299742Sdim                                   n->hunk_original_length,
582299742Sdim                                   n->hunk_modified_start,
583299742Sdim                                   n->hunk_modified_length,
584299742Sdim                                   n->prop_name));
585251881Speter      else
586299742Sdim        SVN_ERR(svn_cmdline_printf(pool,
587299742Sdim                                   _(">         hunk "
588299742Sdim                                     "@@ -%lu,%lu +%lu,%lu @@ "
589299742Sdim                                     "already applied\n"),
590299742Sdim                                   n->hunk_original_start,
591299742Sdim                                   n->hunk_original_length,
592299742Sdim                                   n->hunk_modified_start,
593299742Sdim                                   n->hunk_modified_length));
594251881Speter      break;
595251881Speter
596251881Speter    case svn_wc_notify_update_update:
597251881Speter    case svn_wc_notify_merge_record_info:
598251881Speter      {
599251881Speter        if (n->content_state == svn_wc_notify_state_conflicted)
600251881Speter          {
601251881Speter            store_path(nb, nb->conflict_stats->text_conflicts, path_local);
602251881Speter            statchar_buf[0] = 'C';
603251881Speter          }
604251881Speter        else if (n->kind == svn_node_file)
605251881Speter          {
606251881Speter            if (n->content_state == svn_wc_notify_state_merged)
607251881Speter              statchar_buf[0] = 'G';
608251881Speter            else if (n->content_state == svn_wc_notify_state_changed)
609251881Speter              statchar_buf[0] = 'U';
610251881Speter          }
611251881Speter
612251881Speter        if (n->prop_state == svn_wc_notify_state_conflicted)
613251881Speter          {
614251881Speter            store_path(nb, nb->conflict_stats->prop_conflicts, path_local);
615251881Speter            statchar_buf[1] = 'C';
616251881Speter          }
617251881Speter        else if (n->prop_state == svn_wc_notify_state_merged)
618251881Speter          statchar_buf[1] = 'G';
619251881Speter        else if (n->prop_state == svn_wc_notify_state_changed)
620251881Speter          statchar_buf[1] = 'U';
621251881Speter
622251881Speter        if (n->lock_state == svn_wc_notify_lock_state_unlocked)
623251881Speter          statchar_buf[2] = 'B';
624251881Speter
625251881Speter        if (statchar_buf[0] != ' ' || statchar_buf[1] != ' ')
626251881Speter          nb->received_some_change = TRUE;
627251881Speter
628251881Speter        if (statchar_buf[0] != ' ' || statchar_buf[1] != ' '
629251881Speter            || statchar_buf[2] != ' ')
630251881Speter          {
631299742Sdim            SVN_ERR(svn_cmdline_printf(pool, "%s %s\n",
632299742Sdim                                       statchar_buf, path_local));
633251881Speter          }
634251881Speter      }
635251881Speter      break;
636251881Speter
637251881Speter    case svn_wc_notify_update_external:
638251881Speter      /* Remember that we're now "inside" an externals definition. */
639299742Sdim      ++nb->in_external;
640251881Speter
641251881Speter      /* Currently this is used for checkouts and switches too.  If we
642251881Speter         want different output, we'll have to add new actions. */
643299742Sdim      SVN_ERR(svn_cmdline_printf(pool,
644299742Sdim                                 _("\nFetching external item into '%s':\n"),
645299742Sdim                                 path_local));
646251881Speter      break;
647251881Speter
648251881Speter    case svn_wc_notify_failed_external:
649251881Speter      /* If we are currently inside the handling of an externals
650251881Speter         definition, then we can simply present n->err as a warning
651251881Speter         and feel confident that after this, we aren't handling that
652251881Speter         externals definition any longer. */
653251881Speter      if (nb->in_external)
654251881Speter        {
655251881Speter          svn_handle_warning2(stderr, n->err, "svn: ");
656299742Sdim          --nb->in_external;
657299742Sdim          SVN_ERR(svn_cmdline_printf(pool, "\n"));
658251881Speter        }
659251881Speter      /* Otherwise, we'll just print two warnings.  Why?  Because
660251881Speter         svn_handle_warning2() only shows the single "best message",
661251881Speter         but we have two pretty important ones: that the external at
662251881Speter         '/some/path' didn't pan out, and then the more specific
663251881Speter         reason why (from n->err). */
664251881Speter      else
665251881Speter        {
666251881Speter          svn_error_t *warn_err =
667299742Sdim            svn_error_createf(SVN_ERR_CL_ERROR_PROCESSING_EXTERNALS, NULL,
668251881Speter                              _("Error handling externals definition for '%s':"),
669251881Speter                              path_local);
670251881Speter          svn_handle_warning2(stderr, warn_err, "svn: ");
671251881Speter          svn_error_clear(warn_err);
672251881Speter          svn_handle_warning2(stderr, n->err, "svn: ");
673251881Speter        }
674251881Speter      break;
675251881Speter
676251881Speter    case svn_wc_notify_update_started:
677251881Speter      if (! (nb->in_external ||
678251881Speter             nb->is_checkout ||
679251881Speter             nb->is_export))
680251881Speter        {
681299742Sdim          SVN_ERR(svn_cmdline_printf(pool, _("Updating '%s':\n"),
682299742Sdim                                     path_local));
683251881Speter        }
684251881Speter      break;
685251881Speter
686251881Speter    case svn_wc_notify_update_completed:
687251881Speter      {
688251881Speter        if (SVN_IS_VALID_REVNUM(n->revision))
689251881Speter          {
690251881Speter            if (nb->is_export)
691251881Speter              {
692299742Sdim                SVN_ERR(svn_cmdline_printf(
693299742Sdim                          pool, nb->in_external
694299742Sdim                            ? _("Exported external at revision %ld.\n")
695299742Sdim                            : _("Exported revision %ld.\n"),
696299742Sdim                          n->revision));
697251881Speter              }
698251881Speter            else if (nb->is_checkout)
699251881Speter              {
700299742Sdim                SVN_ERR(svn_cmdline_printf(
701299742Sdim                          pool, nb->in_external
702299742Sdim                            ? _("Checked out external at revision %ld.\n")
703299742Sdim                            : _("Checked out revision %ld.\n"),
704299742Sdim                          n->revision));
705251881Speter              }
706251881Speter            else
707251881Speter              {
708251881Speter                if (nb->received_some_change)
709251881Speter                  {
710251881Speter                    nb->received_some_change = FALSE;
711299742Sdim                    SVN_ERR(svn_cmdline_printf(
712299742Sdim                              pool, nb->in_external
713299742Sdim                                ? _("Updated external to revision %ld.\n")
714299742Sdim                                : _("Updated to revision %ld.\n"),
715299742Sdim                              n->revision));
716251881Speter                  }
717251881Speter                else
718251881Speter                  {
719299742Sdim                    SVN_ERR(svn_cmdline_printf(
720299742Sdim                              pool, nb->in_external
721299742Sdim                                ? _("External at revision %ld.\n")
722299742Sdim                                : _("At revision %ld.\n"),
723299742Sdim                               n->revision));
724251881Speter                  }
725251881Speter              }
726251881Speter          }
727251881Speter        else  /* no revision */
728251881Speter          {
729251881Speter            if (nb->is_export)
730251881Speter              {
731299742Sdim                SVN_ERR(svn_cmdline_printf(
732299742Sdim                          pool, nb->in_external
733299742Sdim                            ? _("External export complete.\n")
734299742Sdim                            : _("Export complete.\n")));
735251881Speter              }
736251881Speter            else if (nb->is_checkout)
737251881Speter              {
738299742Sdim                SVN_ERR(svn_cmdline_printf(
739299742Sdim                          pool, nb->in_external
740299742Sdim                            ? _("External checkout complete.\n")
741299742Sdim                            : _("Checkout complete.\n")));
742251881Speter              }
743251881Speter            else
744251881Speter              {
745299742Sdim                SVN_ERR(svn_cmdline_printf(
746299742Sdim                          pool, nb->in_external
747299742Sdim                            ? _("External update complete.\n")
748299742Sdim                            : _("Update complete.\n")));
749251881Speter              }
750251881Speter          }
751251881Speter      }
752251881Speter
753251881Speter      if (nb->in_external)
754251881Speter        {
755299742Sdim          --nb->in_external;
756299742Sdim          SVN_ERR(svn_cmdline_printf(pool, "\n"));
757251881Speter        }
758251881Speter      break;
759251881Speter
760251881Speter    case svn_wc_notify_status_external:
761299742Sdim      SVN_ERR(svn_cmdline_printf(
762299742Sdim        pool, _("\nPerforming status on external item at '%s':\n"),
763299742Sdim        path_local));
764251881Speter      break;
765251881Speter
766299742Sdim    case svn_wc_notify_info_external:
767299742Sdim      SVN_ERR(svn_cmdline_printf(
768299742Sdim         pool, _("\nPerforming info on external item at '%s':\n"),
769299742Sdim         path_local));
770299742Sdim      break;
771299742Sdim
772251881Speter    case svn_wc_notify_status_completed:
773251881Speter      if (SVN_IS_VALID_REVNUM(n->revision))
774299742Sdim        SVN_ERR(svn_cmdline_printf(pool,
775299742Sdim                                   _("Status against revision: %6ld\n"),
776299742Sdim                                   n->revision));
777251881Speter      break;
778251881Speter
779251881Speter    case svn_wc_notify_commit_modified:
780251881Speter      /* xgettext: Align the %s's on this and the following 4 messages */
781299742Sdim      SVN_ERR(svn_cmdline_printf(pool,
782299742Sdim                                 nb->is_wc_to_repos_copy
783299742Sdim                                   ? _("Sending copy of       %s\n")
784299742Sdim                                   : _("Sending        %s\n"),
785299742Sdim                                 path_local));
786251881Speter      break;
787251881Speter
788251881Speter    case svn_wc_notify_commit_added:
789251881Speter    case svn_wc_notify_commit_copied:
790251881Speter      if (n->mime_type && svn_mime_type_is_binary(n->mime_type))
791251881Speter        {
792299742Sdim          SVN_ERR(svn_cmdline_printf(pool,
793299742Sdim                                     nb->is_wc_to_repos_copy
794299742Sdim                                       ? _("Adding copy of (bin)  %s\n")
795299742Sdim                                       : _("Adding  (bin)  %s\n"),
796299742Sdim                                     path_local));
797251881Speter        }
798251881Speter      else
799251881Speter        {
800299742Sdim          SVN_ERR(svn_cmdline_printf(pool,
801299742Sdim                                     nb->is_wc_to_repos_copy
802299742Sdim                                       ? _("Adding copy of        %s\n")
803299742Sdim                                       : _("Adding         %s\n"),
804299742Sdim                                     path_local));
805251881Speter        }
806251881Speter      break;
807251881Speter
808251881Speter    case svn_wc_notify_commit_deleted:
809299742Sdim      SVN_ERR(svn_cmdline_printf(pool,
810299742Sdim                                 nb->is_wc_to_repos_copy
811299742Sdim                                   ? _("Deleting copy of      %s\n")
812299742Sdim                                   : _("Deleting       %s\n"),
813299742Sdim                                 path_local));
814251881Speter      break;
815251881Speter
816251881Speter    case svn_wc_notify_commit_replaced:
817251881Speter    case svn_wc_notify_commit_copied_replaced:
818299742Sdim      SVN_ERR(svn_cmdline_printf(pool,
819299742Sdim                                 nb->is_wc_to_repos_copy
820299742Sdim                                   ? _("Replacing copy of     %s\n")
821299742Sdim                                   : _("Replacing      %s\n"),
822299742Sdim                                 path_local));
823251881Speter      break;
824251881Speter
825251881Speter    case svn_wc_notify_commit_postfix_txdelta:
826251881Speter      if (! nb->sent_first_txdelta)
827251881Speter        {
828251881Speter          nb->sent_first_txdelta = TRUE;
829299742Sdim          SVN_ERR(svn_cmdline_printf(pool,
830299742Sdim                                     _("Transmitting file data ")));
831251881Speter        }
832251881Speter
833299742Sdim      SVN_ERR(svn_cmdline_printf(pool, "."));
834251881Speter      break;
835251881Speter
836251881Speter    case svn_wc_notify_locked:
837299742Sdim      SVN_ERR(svn_cmdline_printf(pool, _("'%s' locked by user '%s'.\n"),
838299742Sdim                                 path_local, n->lock->owner));
839251881Speter      break;
840251881Speter
841251881Speter    case svn_wc_notify_unlocked:
842299742Sdim      SVN_ERR(svn_cmdline_printf(pool, _("'%s' unlocked.\n"),
843299742Sdim                                 path_local));
844251881Speter      break;
845251881Speter
846251881Speter    case svn_wc_notify_failed_lock:
847251881Speter    case svn_wc_notify_failed_unlock:
848251881Speter      svn_handle_warning2(stderr, n->err, "svn: ");
849251881Speter      break;
850251881Speter
851251881Speter    case svn_wc_notify_changelist_set:
852299742Sdim      SVN_ERR(svn_cmdline_printf(pool, "A [%s] %s\n",
853299742Sdim                                 n->changelist_name, path_local));
854251881Speter      break;
855251881Speter
856251881Speter    case svn_wc_notify_changelist_clear:
857251881Speter    case svn_wc_notify_changelist_moved:
858299742Sdim      SVN_ERR(svn_cmdline_printf(pool,
859299742Sdim                                 "D [%s] %s\n",
860299742Sdim                                 n->changelist_name, path_local));
861251881Speter      break;
862251881Speter
863251881Speter    case svn_wc_notify_merge_begin:
864251881Speter      if (n->merge_range == NULL)
865299742Sdim        SVN_ERR(svn_cmdline_printf(pool,
866299742Sdim                                   _("--- Merging differences between "
867299742Sdim                                     "repository URLs into '%s':\n"),
868299742Sdim                                   path_local));
869251881Speter      else if (n->merge_range->start == n->merge_range->end - 1
870251881Speter          || n->merge_range->start == n->merge_range->end)
871299742Sdim        SVN_ERR(svn_cmdline_printf(pool, _("--- Merging r%ld into '%s':\n"),
872299742Sdim                                   n->merge_range->end, path_local));
873251881Speter      else if (n->merge_range->start - 1 == n->merge_range->end)
874299742Sdim        SVN_ERR(svn_cmdline_printf(pool,
875299742Sdim                                   _("--- Reverse-merging r%ld into '%s':\n"),
876299742Sdim                                   n->merge_range->start, path_local));
877251881Speter      else if (n->merge_range->start < n->merge_range->end)
878299742Sdim        SVN_ERR(svn_cmdline_printf(pool,
879299742Sdim                                   _("--- Merging r%ld through r%ld into "
880299742Sdim                                     "'%s':\n"),
881299742Sdim                                   n->merge_range->start + 1,
882299742Sdim                                   n->merge_range->end, path_local));
883251881Speter      else /* n->merge_range->start > n->merge_range->end - 1 */
884299742Sdim        SVN_ERR(svn_cmdline_printf(pool,
885299742Sdim                                   _("--- Reverse-merging r%ld through r%ld "
886299742Sdim                                     "into '%s':\n"),
887299742Sdim                                   n->merge_range->start,
888299742Sdim                                   n->merge_range->end + 1, path_local));
889251881Speter      break;
890251881Speter
891251881Speter    case svn_wc_notify_merge_record_info_begin:
892251881Speter      if (!n->merge_range)
893251881Speter        {
894299742Sdim          SVN_ERR(svn_cmdline_printf(pool,
895299742Sdim                                     _("--- Recording mergeinfo for merge "
896299742Sdim                                       "between repository URLs into '%s':\n"),
897299742Sdim                                     path_local));
898251881Speter        }
899251881Speter      else
900251881Speter        {
901251881Speter          if (n->merge_range->start == n->merge_range->end - 1
902251881Speter              || n->merge_range->start == n->merge_range->end)
903299742Sdim            SVN_ERR(svn_cmdline_printf(
904251881Speter              pool,
905251881Speter              _("--- Recording mergeinfo for merge of r%ld into '%s':\n"),
906299742Sdim              n->merge_range->end, path_local));
907251881Speter          else if (n->merge_range->start - 1 == n->merge_range->end)
908299742Sdim            SVN_ERR(svn_cmdline_printf(
909251881Speter              pool,
910251881Speter              _("--- Recording mergeinfo for reverse merge of r%ld into '%s':\n"),
911299742Sdim              n->merge_range->start, path_local));
912251881Speter           else if (n->merge_range->start < n->merge_range->end)
913299742Sdim             SVN_ERR(svn_cmdline_printf(
914251881Speter               pool,
915251881Speter               _("--- Recording mergeinfo for merge of r%ld through r%ld into '%s':\n"),
916299742Sdim               n->merge_range->start + 1, n->merge_range->end, path_local));
917251881Speter           else /* n->merge_range->start > n->merge_range->end - 1 */
918299742Sdim             SVN_ERR(svn_cmdline_printf(
919251881Speter               pool,
920251881Speter               _("--- Recording mergeinfo for reverse merge of r%ld through r%ld into '%s':\n"),
921299742Sdim               n->merge_range->start, n->merge_range->end + 1, path_local));
922251881Speter        }
923251881Speter      break;
924251881Speter
925251881Speter    case svn_wc_notify_merge_elide_info:
926299742Sdim      SVN_ERR(svn_cmdline_printf(pool,
927299742Sdim                                 _("--- Eliding mergeinfo from '%s':\n"),
928299742Sdim                                 path_local));
929251881Speter      break;
930251881Speter
931251881Speter    case svn_wc_notify_foreign_merge_begin:
932251881Speter      if (n->merge_range == NULL)
933299742Sdim        SVN_ERR(svn_cmdline_printf(pool,
934299742Sdim                                   _("--- Merging differences between "
935299742Sdim                                     "foreign repository URLs into '%s':\n"),
936299742Sdim                                   path_local));
937251881Speter      else if (n->merge_range->start == n->merge_range->end - 1
938251881Speter          || n->merge_range->start == n->merge_range->end)
939299742Sdim        SVN_ERR(svn_cmdline_printf(pool,
940299742Sdim                                   _("--- Merging (from foreign repository) "
941299742Sdim                                     "r%ld into '%s':\n"),
942299742Sdim                                   n->merge_range->end, path_local));
943251881Speter      else if (n->merge_range->start - 1 == n->merge_range->end)
944299742Sdim        SVN_ERR(svn_cmdline_printf(pool,
945299742Sdim                                   _("--- Reverse-merging (from foreign "
946299742Sdim                                     "repository) r%ld into '%s':\n"),
947299742Sdim                                   n->merge_range->start, path_local));
948251881Speter      else if (n->merge_range->start < n->merge_range->end)
949299742Sdim        SVN_ERR(svn_cmdline_printf(pool,
950299742Sdim                                   _("--- Merging (from foreign repository) "
951299742Sdim                                     "r%ld through r%ld into '%s':\n"),
952299742Sdim                                   n->merge_range->start + 1,
953299742Sdim                                   n->merge_range->end, path_local));
954251881Speter      else /* n->merge_range->start > n->merge_range->end - 1 */
955299742Sdim        SVN_ERR(svn_cmdline_printf(pool,
956299742Sdim                                   _("--- Reverse-merging (from foreign "
957299742Sdim                                     "repository) r%ld through r%ld into "
958299742Sdim                                     "'%s':\n"),
959299742Sdim                                   n->merge_range->start,
960299742Sdim                                   n->merge_range->end + 1, path_local));
961251881Speter      break;
962251881Speter
963251881Speter    case svn_wc_notify_tree_conflict:
964251881Speter      store_path(nb, nb->conflict_stats->tree_conflicts, path_local);
965299742Sdim      SVN_ERR(svn_cmdline_printf(pool, "   C %s\n", path_local));
966251881Speter      break;
967251881Speter
968251881Speter    case svn_wc_notify_update_shadowed_add:
969251881Speter      nb->received_some_change = TRUE;
970299742Sdim      SVN_ERR(svn_cmdline_printf(pool, "   A %s\n", path_local));
971251881Speter      break;
972251881Speter
973251881Speter    case svn_wc_notify_update_shadowed_update:
974251881Speter      nb->received_some_change = TRUE;
975299742Sdim      SVN_ERR(svn_cmdline_printf(pool, "   U %s\n", path_local));
976251881Speter      break;
977251881Speter
978251881Speter    case svn_wc_notify_update_shadowed_delete:
979251881Speter      nb->received_some_change = TRUE;
980299742Sdim      SVN_ERR(svn_cmdline_printf(pool, "   D %s\n", path_local));
981251881Speter      break;
982251881Speter
983251881Speter    case svn_wc_notify_property_modified:
984251881Speter    case svn_wc_notify_property_added:
985299742Sdim      SVN_ERR(svn_cmdline_printf(pool,
986299742Sdim                                 _("property '%s' set on '%s'\n"),
987299742Sdim                                 n->prop_name, path_local));
988251881Speter      break;
989251881Speter
990251881Speter    case svn_wc_notify_property_deleted:
991299742Sdim      SVN_ERR(svn_cmdline_printf(pool,
992299742Sdim                                 _("property '%s' deleted from '%s'.\n"),
993299742Sdim                                 n->prop_name, path_local));
994251881Speter      break;
995251881Speter
996251881Speter    case svn_wc_notify_property_deleted_nonexistent:
997299742Sdim      SVN_ERR(svn_cmdline_printf(pool,
998299742Sdim                                 _("Attempting to delete nonexistent "
999299742Sdim                                   "property '%s' on '%s'\n"), n->prop_name,
1000299742Sdim                                 path_local));
1001251881Speter      break;
1002251881Speter
1003251881Speter    case svn_wc_notify_revprop_set:
1004299742Sdim      SVN_ERR(svn_cmdline_printf(pool,
1005251881Speter                           _("property '%s' set on repository revision %ld\n"),
1006299742Sdim                           n->prop_name, n->revision));
1007251881Speter      break;
1008251881Speter
1009251881Speter    case svn_wc_notify_revprop_deleted:
1010299742Sdim      SVN_ERR(svn_cmdline_printf(pool,
1011251881Speter                     _("property '%s' deleted from repository revision %ld\n"),
1012299742Sdim                     n->prop_name, n->revision));
1013251881Speter      break;
1014251881Speter
1015251881Speter    case svn_wc_notify_upgraded_path:
1016299742Sdim      SVN_ERR(svn_cmdline_printf(pool, _("Upgraded '%s'\n"), path_local));
1017251881Speter      break;
1018251881Speter
1019251881Speter    case svn_wc_notify_url_redirect:
1020299742Sdim      SVN_ERR(svn_cmdline_printf(pool, _("Redirecting to URL '%s':\n"),
1021299742Sdim                                 n->url));
1022251881Speter      break;
1023251881Speter
1024251881Speter    case svn_wc_notify_path_nonexistent:
1025299742Sdim      SVN_ERR(svn_cmdline_printf(pool, "%s\n",
1026299742Sdim                apr_psprintf(pool, _("'%s' is not under version control"),
1027299742Sdim                             path_local)));
1028251881Speter      break;
1029251881Speter
1030251881Speter    case svn_wc_notify_conflict_resolver_starting:
1031251881Speter      /* Once all operations invoke the interactive conflict resolution after
1032251881Speter       * they've completed, we can run svn_cl__notifier_print_conflict_stats()
1033251881Speter       * here. */
1034251881Speter      break;
1035251881Speter
1036251881Speter    case svn_wc_notify_conflict_resolver_done:
1037251881Speter      break;
1038251881Speter
1039251881Speter    case svn_wc_notify_foreign_copy_begin:
1040251881Speter      if (n->merge_range == NULL)
1041251881Speter        {
1042299742Sdim          SVN_ERR(svn_cmdline_printf(
1043251881Speter                           pool,
1044251881Speter                           _("--- Copying from foreign repository URL '%s':\n"),
1045299742Sdim                           n->url));
1046251881Speter        }
1047251881Speter      break;
1048251881Speter
1049251881Speter    case svn_wc_notify_move_broken:
1050299742Sdim      SVN_ERR(svn_cmdline_printf(pool,
1051299742Sdim                                 _("Breaking move with source path '%s'\n"),
1052299742Sdim                                 path_local));
1053251881Speter      break;
1054251881Speter
1055299742Sdim    case svn_wc_notify_cleanup_external:
1056299742Sdim      SVN_ERR(svn_cmdline_printf
1057299742Sdim                (pool, _("Performing cleanup on external item at '%s'.\n"),
1058299742Sdim                 path_local));
1059299742Sdim      break;
1060299742Sdim
1061299742Sdim    case svn_wc_notify_commit_finalizing:
1062299742Sdim      if (nb->sent_first_txdelta)
1063299742Sdim        {
1064299742Sdim          SVN_ERR(svn_cmdline_printf(pool, _("done\n")));
1065299742Sdim        }
1066299742Sdim      SVN_ERR(svn_cmdline_printf(pool, _("Committing transaction...\n")));
1067299742Sdim      break;
1068299742Sdim
1069251881Speter    default:
1070251881Speter      break;
1071251881Speter    }
1072251881Speter
1073299742Sdim  SVN_ERR(svn_cmdline_fflush(stdout));
1074251881Speter
1075299742Sdim  return SVN_NO_ERROR;
1076299742Sdim}
1077251881Speter
1078299742Sdim/* This implements `svn_wc_notify_func2_t'.
1079299742Sdim * NOTE: This function can't fail, so we just ignore any print errors. */
1080299742Sdimstatic void
1081299742Sdimnotify(void *baton, const svn_wc_notify_t *n, apr_pool_t *pool)
1082299742Sdim{
1083299742Sdim  struct notify_baton *nb = baton;
1084299742Sdim  svn_error_t *err;
1085299742Sdim
1086299742Sdim  err = notify_body(nb, n, pool);
1087299742Sdim
1088251881Speter  /* If we had no errors before, print this error to stderr. Else, don't print
1089251881Speter     anything.  The user already knows there were some output errors,
1090251881Speter     so there is no point in flooding her with an error per notification. */
1091299742Sdim  if (err && !nb->had_print_error)
1092251881Speter    {
1093251881Speter      nb->had_print_error = TRUE;
1094251881Speter      /* Issue #3014:
1095251881Speter       * Don't print anything on broken pipes. The pipe was likely
1096251881Speter       * closed by the process at the other end. We expect that
1097251881Speter       * process to perform error reporting as necessary.
1098251881Speter       *
1099251881Speter       * ### This assumes that there is only one error in a chain for
1100251881Speter       * ### SVN_ERR_IO_PIPE_WRITE_ERROR. See svn_cmdline_fputs(). */
1101251881Speter      if (err->apr_err != SVN_ERR_IO_PIPE_WRITE_ERROR)
1102251881Speter        svn_handle_error2(err, stderr, FALSE, "svn: ");
1103251881Speter    }
1104251881Speter  svn_error_clear(err);
1105251881Speter}
1106251881Speter
1107251881Spetersvn_error_t *
1108251881Spetersvn_cl__get_notifier(svn_wc_notify_func2_t *notify_func_p,
1109251881Speter                     void **notify_baton_p,
1110251881Speter                     svn_cl__conflict_stats_t *conflict_stats,
1111251881Speter                     apr_pool_t *pool)
1112251881Speter{
1113251881Speter  struct notify_baton *nb = apr_pcalloc(pool, sizeof(*nb));
1114251881Speter
1115251881Speter  nb->received_some_change = FALSE;
1116251881Speter  nb->sent_first_txdelta = FALSE;
1117251881Speter  nb->is_checkout = FALSE;
1118251881Speter  nb->is_export = FALSE;
1119251881Speter  nb->is_wc_to_repos_copy = FALSE;
1120299742Sdim  nb->in_external = 0;
1121251881Speter  nb->had_print_error = FALSE;
1122251881Speter  nb->conflict_stats = conflict_stats;
1123251881Speter  SVN_ERR(svn_dirent_get_absolute(&nb->path_prefix, "", pool));
1124251881Speter
1125251881Speter  *notify_func_p = notify;
1126251881Speter  *notify_baton_p = nb;
1127251881Speter  return SVN_NO_ERROR;
1128251881Speter}
1129251881Speter
1130251881Spetersvn_error_t *
1131251881Spetersvn_cl__notifier_mark_checkout(void *baton)
1132251881Speter{
1133251881Speter  struct notify_baton *nb = baton;
1134251881Speter
1135251881Speter  nb->is_checkout = TRUE;
1136251881Speter  return SVN_NO_ERROR;
1137251881Speter}
1138251881Speter
1139251881Spetersvn_error_t *
1140251881Spetersvn_cl__notifier_mark_export(void *baton)
1141251881Speter{
1142251881Speter  struct notify_baton *nb = baton;
1143251881Speter
1144251881Speter  nb->is_export = TRUE;
1145251881Speter  return SVN_NO_ERROR;
1146251881Speter}
1147251881Speter
1148251881Spetersvn_error_t *
1149251881Spetersvn_cl__notifier_mark_wc_to_repos_copy(void *baton)
1150251881Speter{
1151251881Speter  struct notify_baton *nb = baton;
1152251881Speter
1153251881Speter  nb->is_wc_to_repos_copy = TRUE;
1154251881Speter  return SVN_NO_ERROR;
1155251881Speter}
1156251881Speter
1157251881Spetervoid
1158251881Spetersvn_cl__check_externals_failed_notify_wrapper(void *baton,
1159251881Speter                                              const svn_wc_notify_t *n,
1160251881Speter                                              apr_pool_t *pool)
1161251881Speter{
1162251881Speter  struct svn_cl__check_externals_failed_notify_baton *nwb = baton;
1163251881Speter
1164251881Speter  if (n->action == svn_wc_notify_failed_external)
1165251881Speter    nwb->had_externals_error = TRUE;
1166251881Speter
1167251881Speter  if (nwb->wrapped_func)
1168251881Speter    nwb->wrapped_func(nwb->wrapped_baton, n, pool);
1169251881Speter}
1170