1289177Speter/*
2289177Speter * notify.c:  feedback handlers for cmdline client.
3289177Speter *
4289177Speter * ====================================================================
5289177Speter *    Licensed to the Apache Software Foundation (ASF) under one
6289177Speter *    or more contributor license agreements.  See the NOTICE file
7289177Speter *    distributed with this work for additional information
8289177Speter *    regarding copyright ownership.  The ASF licenses this file
9289177Speter *    to you under the Apache License, Version 2.0 (the
10289177Speter *    "License"); you may not use this file except in compliance
11289177Speter *    with the License.  You may obtain a copy of the License at
12289177Speter *
13289177Speter *      http://www.apache.org/licenses/LICENSE-2.0
14289177Speter *
15289177Speter *    Unless required by applicable law or agreed to in writing,
16289177Speter *    software distributed under the License is distributed on an
17289177Speter *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18289177Speter *    KIND, either express or implied.  See the License for the
19289177Speter *    specific language governing permissions and limitations
20289177Speter *    under the License.
21289177Speter * ====================================================================
22289177Speter */
23289177Speter
24289177Speter/* ==================================================================== */
25289177Speter
26289177Speter
27289177Speter
28289177Speter/*** Includes. ***/
29289177Speter
30289177Speter#define APR_WANT_STDIO
31289177Speter#define APR_WANT_STRFUNC
32289177Speter#include <apr_want.h>
33289177Speter
34289177Speter#include "svn_cmdline.h"
35289177Speter#include "svn_pools.h"
36289177Speter#include "svn_dirent_uri.h"
37289177Speter#include "svn_path.h"
38289177Speter#include "svn_sorts.h"
39289177Speter#include "cl.h"
40289177Speter
41289177Speter#include "svn_private_config.h"
42289177Speter
43289177Speter
44289177Speter/* Baton for notify and friends. */
45289177Speterstruct notify_baton
46289177Speter{
47289177Speter  svn_boolean_t received_some_change;
48289177Speter  svn_boolean_t is_checkout;
49289177Speter  svn_boolean_t is_export;
50289177Speter  svn_boolean_t is_wc_to_repos_copy;
51289177Speter  svn_boolean_t sent_first_txdelta;
52289177Speter  svn_boolean_t in_external;
53289177Speter  svn_boolean_t had_print_error; /* Used to not keep printing error messages
54289177Speter                                    when we've already had one print error. */
55289177Speter
56289177Speter  /* Conflict stats for update and merge. */
57289177Speter  unsigned int text_conflicts;
58289177Speter  unsigned int prop_conflicts;
59289177Speter  unsigned int tree_conflicts;
60289177Speter  unsigned int skipped_paths;
61289177Speter  apr_hash_t *conflicted_paths;
62289177Speter
63289177Speter  /* The cwd, for use in decomposing absolute paths. */
64289177Speter  const char *path_prefix;
65289177Speter};
66289177Speter
67289177Speter
68289177Speter/* Add a conflicted path to the list of conflicted paths stored
69289177Speter * in the notify baton. */
70289177Speterstatic void
71289177Speteradd_conflicted_path(struct notify_baton *nb, const char *path)
72289177Speter{
73289177Speter  apr_hash_set(nb->conflicted_paths,
74289177Speter               apr_pstrdup(apr_hash_pool_get(nb->conflicted_paths), path),
75289177Speter               APR_HASH_KEY_STRING, "");
76289177Speter}
77289177Speter
78289177Speter/* This implements `svn_wc_notify_func2_t'.
79289177Speter * NOTE: This function can't fail, so we just ignore any print errors. */
80289177Speterstatic void
81289177Speternotify(void *baton, const svn_wc_notify_t *n, apr_pool_t *pool)
82289177Speter{
83289177Speter  struct notify_baton *nb = baton;
84289177Speter  char statchar_buf[5] = "    ";
85289177Speter  const char *path_local;
86289177Speter  svn_error_t *err;
87289177Speter
88289177Speter  if (n->url)
89289177Speter    path_local = n->url;
90289177Speter  else
91289177Speter    {
92289177Speter      if (n->path_prefix)
93289177Speter        path_local = svn_cl__local_style_skip_ancestor(n->path_prefix, n->path,
94289177Speter                                                       pool);
95289177Speter      else /* skip nb->path_prefix, if it's non-null */
96289177Speter        path_local = svn_cl__local_style_skip_ancestor(nb->path_prefix, n->path,
97289177Speter                                                       pool);
98289177Speter    }
99289177Speter
100289177Speter  switch (n->action)
101289177Speter    {
102289177Speter    case svn_wc_notify_skip:
103289177Speter      nb->skipped_paths++;
104289177Speter      if (n->content_state == svn_wc_notify_state_missing)
105289177Speter        {
106289177Speter          if ((err = svn_cmdline_printf
107289177Speter               (pool, _("Skipped missing target: '%s'\n"),
108289177Speter                path_local)))
109289177Speter            goto print_error;
110289177Speter        }
111289177Speter      else if (n->content_state == svn_wc_notify_state_source_missing)
112289177Speter        {
113289177Speter          if ((err = svn_cmdline_printf
114289177Speter               (pool, _("Skipped target: '%s' -- copy-source is missing\n"),
115289177Speter                path_local)))
116289177Speter            goto print_error;
117289177Speter        }
118289177Speter      else
119289177Speter        {
120289177Speter          if ((err = svn_cmdline_printf
121289177Speter               (pool, _("Skipped '%s'\n"), path_local)))
122289177Speter            goto print_error;
123289177Speter        }
124289177Speter      break;
125289177Speter    case svn_wc_notify_update_skip_obstruction:
126289177Speter      nb->skipped_paths++;
127289177Speter      if ((err = svn_cmdline_printf(
128289177Speter            pool, _("Skipped '%s' -- An obstructing working copy was found\n"),
129289177Speter            path_local)))
130289177Speter        goto print_error;
131289177Speter      break;
132289177Speter    case svn_wc_notify_update_skip_working_only:
133289177Speter      nb->skipped_paths++;
134289177Speter      if ((err = svn_cmdline_printf(
135289177Speter            pool, _("Skipped '%s' -- Has no versioned parent\n"),
136289177Speter            path_local)))
137289177Speter        goto print_error;
138289177Speter      break;
139289177Speter    case svn_wc_notify_update_skip_access_denied:
140289177Speter      nb->skipped_paths++;
141289177Speter      if ((err = svn_cmdline_printf(
142289177Speter            pool, _("Skipped '%s' -- Access denied\n"),
143289177Speter            path_local)))
144289177Speter        goto print_error;
145289177Speter      break;
146289177Speter    case svn_wc_notify_skip_conflicted:
147289177Speter      nb->skipped_paths++;
148289177Speter      if ((err = svn_cmdline_printf(
149289177Speter            pool, _("Skipped '%s' -- Node remains in conflict\n"),
150289177Speter            path_local)))
151289177Speter        goto print_error;
152289177Speter      break;
153289177Speter    case svn_wc_notify_update_delete:
154289177Speter    case svn_wc_notify_exclude:
155289177Speter      nb->received_some_change = TRUE;
156289177Speter      if ((err = svn_cmdline_printf(pool, "D    %s\n", path_local)))
157289177Speter        goto print_error;
158289177Speter      break;
159289177Speter    case svn_wc_notify_update_broken_lock:
160289177Speter      if ((err = svn_cmdline_printf(pool, "B    %s\n", path_local)))
161289177Speter        goto print_error;
162289177Speter      break;
163289177Speter
164289177Speter    case svn_wc_notify_update_external_removed:
165289177Speter      nb->received_some_change = TRUE;
166289177Speter      if (n->err && n->err->message)
167289177Speter        {
168289177Speter          if ((err = svn_cmdline_printf(pool, "Removed external '%s': %s\n",
169289177Speter              path_local, n->err->message)))
170289177Speter            goto print_error;
171289177Speter        }
172289177Speter      else
173289177Speter        {
174289177Speter          if ((err = svn_cmdline_printf(pool, "Removed external '%s'\n",
175289177Speter                                        path_local)))
176289177Speter            goto print_error;
177289177Speter        }
178289177Speter      break;
179289177Speter
180289177Speter    case svn_wc_notify_left_local_modifications:
181289177Speter      if ((err = svn_cmdline_printf(pool, "Left local modifications as '%s'\n",
182289177Speter                                        path_local)))
183289177Speter        goto print_error;
184289177Speter      break;
185289177Speter
186289177Speter    case svn_wc_notify_update_replace:
187289177Speter      nb->received_some_change = TRUE;
188289177Speter      if ((err = svn_cmdline_printf(pool, "R    %s\n", path_local)))
189289177Speter        goto print_error;
190289177Speter      break;
191289177Speter
192289177Speter    case svn_wc_notify_update_add:
193289177Speter      nb->received_some_change = TRUE;
194289177Speter      if (n->content_state == svn_wc_notify_state_conflicted)
195289177Speter        {
196289177Speter          nb->text_conflicts++;
197289177Speter          add_conflicted_path(nb, n->path);
198289177Speter          if ((err = svn_cmdline_printf(pool, "C    %s\n", path_local)))
199289177Speter            goto print_error;
200289177Speter        }
201289177Speter      else
202289177Speter        {
203289177Speter          if ((err = svn_cmdline_printf(pool, "A    %s\n", path_local)))
204289177Speter            goto print_error;
205289177Speter        }
206289177Speter      break;
207289177Speter
208289177Speter    case svn_wc_notify_exists:
209289177Speter      nb->received_some_change = TRUE;
210289177Speter      if (n->content_state == svn_wc_notify_state_conflicted)
211289177Speter        {
212289177Speter          nb->text_conflicts++;
213289177Speter          add_conflicted_path(nb, n->path);
214289177Speter          statchar_buf[0] = 'C';
215289177Speter        }
216289177Speter      else
217289177Speter        statchar_buf[0] = 'E';
218289177Speter
219289177Speter      if (n->prop_state == svn_wc_notify_state_conflicted)
220289177Speter        {
221289177Speter          nb->prop_conflicts++;
222289177Speter          add_conflicted_path(nb, n->path);
223289177Speter          statchar_buf[1] = 'C';
224289177Speter        }
225289177Speter      else if (n->prop_state == svn_wc_notify_state_merged)
226289177Speter        statchar_buf[1] = 'G';
227289177Speter
228289177Speter      if ((err = svn_cmdline_printf(pool, "%s %s\n", statchar_buf, path_local)))
229289177Speter        goto print_error;
230289177Speter      break;
231289177Speter
232289177Speter    case svn_wc_notify_restore:
233289177Speter      if ((err = svn_cmdline_printf(pool, _("Restored '%s'\n"),
234289177Speter                                    path_local)))
235289177Speter        goto print_error;
236289177Speter      break;
237289177Speter
238289177Speter    case svn_wc_notify_revert:
239289177Speter      if ((err = svn_cmdline_printf(pool, _("Reverted '%s'\n"),
240289177Speter                                    path_local)))
241289177Speter        goto print_error;
242289177Speter      break;
243289177Speter
244289177Speter    case svn_wc_notify_failed_revert:
245289177Speter      if (( err = svn_cmdline_printf(pool, _("Failed to revert '%s' -- "
246289177Speter                                             "try updating instead.\n"),
247289177Speter                                     path_local)))
248289177Speter        goto print_error;
249289177Speter      break;
250289177Speter
251289177Speter    case svn_wc_notify_resolved:
252289177Speter      if ((err = svn_cmdline_printf(pool,
253289177Speter                                    _("Resolved conflicted state of '%s'\n"),
254289177Speter                                    path_local)))
255289177Speter        goto print_error;
256289177Speter      break;
257289177Speter
258289177Speter    case svn_wc_notify_add:
259289177Speter      /* We *should* only get the MIME_TYPE if PATH is a file.  If we
260289177Speter         do get it, and the mime-type is not textual, note that this
261289177Speter         is a binary addition. */
262289177Speter      if (n->mime_type && (svn_mime_type_is_binary(n->mime_type)))
263289177Speter        {
264289177Speter          if ((err = svn_cmdline_printf(pool, "A  (bin)  %s\n",
265289177Speter                                        path_local)))
266289177Speter            goto print_error;
267289177Speter        }
268289177Speter      else
269289177Speter        {
270289177Speter          if ((err = svn_cmdline_printf(pool, "A         %s\n",
271289177Speter                                        path_local)))
272289177Speter            goto print_error;
273289177Speter        }
274289177Speter      break;
275289177Speter
276289177Speter    case svn_wc_notify_delete:
277289177Speter      nb->received_some_change = TRUE;
278289177Speter      if ((err = svn_cmdline_printf(pool, "D         %s\n",
279289177Speter                                    path_local)))
280289177Speter        goto print_error;
281289177Speter      break;
282289177Speter
283289177Speter    case svn_wc_notify_patch:
284289177Speter      {
285289177Speter        nb->received_some_change = TRUE;
286289177Speter        if (n->content_state == svn_wc_notify_state_conflicted)
287289177Speter          {
288289177Speter            nb->text_conflicts++;
289289177Speter            add_conflicted_path(nb, n->path);
290289177Speter            statchar_buf[0] = 'C';
291289177Speter          }
292289177Speter        else if (n->kind == svn_node_file)
293289177Speter          {
294289177Speter            if (n->content_state == svn_wc_notify_state_merged)
295289177Speter              statchar_buf[0] = 'G';
296289177Speter            else if (n->content_state == svn_wc_notify_state_changed)
297289177Speter              statchar_buf[0] = 'U';
298289177Speter          }
299289177Speter
300289177Speter        if (n->prop_state == svn_wc_notify_state_conflicted)
301289177Speter          {
302289177Speter            nb->prop_conflicts++;
303289177Speter            add_conflicted_path(nb, n->path);
304289177Speter            statchar_buf[1] = 'C';
305289177Speter          }
306289177Speter        else if (n->prop_state == svn_wc_notify_state_changed)
307289177Speter              statchar_buf[1] = 'U';
308289177Speter
309289177Speter        if (statchar_buf[0] != ' ' || statchar_buf[1] != ' ')
310289177Speter          {
311289177Speter            if ((err = svn_cmdline_printf(pool, "%s      %s\n",
312289177Speter                                          statchar_buf, path_local)))
313289177Speter              goto print_error;
314289177Speter          }
315289177Speter      }
316289177Speter      break;
317289177Speter
318289177Speter    case svn_wc_notify_patch_applied_hunk:
319289177Speter      nb->received_some_change = TRUE;
320289177Speter      if (n->hunk_original_start != n->hunk_matched_line)
321289177Speter        {
322289177Speter          apr_uint64_t off;
323289177Speter          const char *s;
324289177Speter          const char *minus;
325289177Speter
326289177Speter          if (n->hunk_matched_line > n->hunk_original_start)
327289177Speter            {
328289177Speter              off = n->hunk_matched_line - n->hunk_original_start;
329289177Speter              minus = "";
330289177Speter            }
331289177Speter          else
332289177Speter            {
333289177Speter              off = n->hunk_original_start - n->hunk_matched_line;
334289177Speter              minus = "-";
335289177Speter            }
336289177Speter
337289177Speter          /* ### We're creating the localized strings without
338289177Speter           * ### APR_INT64_T_FMT since it isn't translator-friendly */
339289177Speter          if (n->hunk_fuzz)
340289177Speter            {
341289177Speter
342289177Speter              if (n->prop_name)
343289177Speter                {
344289177Speter                  s = _(">         applied hunk ## -%lu,%lu +%lu,%lu ## "
345289177Speter                        "with offset %s");
346289177Speter
347289177Speter                  err = svn_cmdline_printf(pool,
348289177Speter                                           apr_pstrcat(pool, s,
349289177Speter                                                       "%"APR_UINT64_T_FMT
350289177Speter                                                       " and fuzz %lu (%s)\n",
351289177Speter                                                       SVN_VA_NULL),
352289177Speter                                           n->hunk_original_start,
353289177Speter                                           n->hunk_original_length,
354289177Speter                                           n->hunk_modified_start,
355289177Speter                                           n->hunk_modified_length,
356289177Speter                                           minus, off, n->hunk_fuzz,
357289177Speter                                           n->prop_name);
358289177Speter                }
359289177Speter              else
360289177Speter                {
361289177Speter                  s = _(">         applied hunk @@ -%lu,%lu +%lu,%lu @@ "
362289177Speter                        "with offset %s");
363289177Speter
364289177Speter                  err = svn_cmdline_printf(pool,
365289177Speter                                           apr_pstrcat(pool, s,
366289177Speter                                                       "%"APR_UINT64_T_FMT
367289177Speter                                                       " and fuzz %lu\n",
368289177Speter                                                       SVN_VA_NULL),
369289177Speter                                           n->hunk_original_start,
370289177Speter                                           n->hunk_original_length,
371289177Speter                                           n->hunk_modified_start,
372289177Speter                                           n->hunk_modified_length,
373289177Speter                                           minus, off, n->hunk_fuzz);
374289177Speter                }
375289177Speter
376289177Speter              if (err)
377289177Speter                goto print_error;
378289177Speter            }
379289177Speter          else
380289177Speter            {
381289177Speter
382289177Speter              if (n->prop_name)
383289177Speter                {
384289177Speter                  s = _(">         applied hunk ## -%lu,%lu +%lu,%lu ## "
385289177Speter                        "with offset %s");
386289177Speter                  err = svn_cmdline_printf(pool,
387289177Speter                                            apr_pstrcat(pool, s,
388289177Speter                                                        "%"APR_UINT64_T_FMT" (%s)\n",
389289177Speter                                                        SVN_VA_NULL),
390289177Speter                                            n->hunk_original_start,
391289177Speter                                            n->hunk_original_length,
392289177Speter                                            n->hunk_modified_start,
393289177Speter                                            n->hunk_modified_length,
394289177Speter                                            minus, off, n->prop_name);
395289177Speter                }
396289177Speter              else
397289177Speter                {
398289177Speter                  s = _(">         applied hunk @@ -%lu,%lu +%lu,%lu @@ "
399289177Speter                        "with offset %s");
400289177Speter                  err = svn_cmdline_printf(pool,
401289177Speter                                           apr_pstrcat(pool, s,
402289177Speter                                                       "%"APR_UINT64_T_FMT"\n",
403289177Speter                                                       SVN_VA_NULL),
404289177Speter                                           n->hunk_original_start,
405289177Speter                                           n->hunk_original_length,
406289177Speter                                           n->hunk_modified_start,
407289177Speter                                           n->hunk_modified_length,
408289177Speter                                           minus, off);
409289177Speter                }
410289177Speter
411289177Speter              if (err)
412289177Speter                goto print_error;
413289177Speter            }
414289177Speter        }
415289177Speter      else if (n->hunk_fuzz)
416289177Speter        {
417289177Speter          if (n->prop_name)
418289177Speter            err = svn_cmdline_printf(pool,
419289177Speter                          _(">         applied hunk ## -%lu,%lu +%lu,%lu ## "
420289177Speter                                        "with fuzz %lu (%s)\n"),
421289177Speter                                        n->hunk_original_start,
422289177Speter                                        n->hunk_original_length,
423289177Speter                                        n->hunk_modified_start,
424289177Speter                                        n->hunk_modified_length,
425289177Speter                                        n->hunk_fuzz,
426289177Speter                                        n->prop_name);
427289177Speter          else
428289177Speter            err = svn_cmdline_printf(pool,
429289177Speter                          _(">         applied hunk @@ -%lu,%lu +%lu,%lu @@ "
430289177Speter                                        "with fuzz %lu\n"),
431289177Speter                                        n->hunk_original_start,
432289177Speter                                        n->hunk_original_length,
433289177Speter                                        n->hunk_modified_start,
434289177Speter                                        n->hunk_modified_length,
435289177Speter                                        n->hunk_fuzz);
436289177Speter          if (err)
437289177Speter            goto print_error;
438289177Speter
439289177Speter        }
440289177Speter      break;
441289177Speter
442289177Speter    case svn_wc_notify_patch_rejected_hunk:
443289177Speter      nb->received_some_change = TRUE;
444289177Speter
445289177Speter      if (n->prop_name)
446289177Speter        err = svn_cmdline_printf(pool,
447289177Speter                                 _(">         rejected hunk "
448289177Speter                                   "## -%lu,%lu +%lu,%lu ## (%s)\n"),
449289177Speter                                 n->hunk_original_start,
450289177Speter                                 n->hunk_original_length,
451289177Speter                                 n->hunk_modified_start,
452289177Speter                                 n->hunk_modified_length,
453289177Speter                                 n->prop_name);
454289177Speter      else
455289177Speter        err = svn_cmdline_printf(pool,
456289177Speter                                 _(">         rejected hunk "
457289177Speter                                   "@@ -%lu,%lu +%lu,%lu @@\n"),
458289177Speter                                 n->hunk_original_start,
459289177Speter                                 n->hunk_original_length,
460289177Speter                                 n->hunk_modified_start,
461289177Speter                                 n->hunk_modified_length);
462289177Speter      if (err)
463289177Speter        goto print_error;
464289177Speter      break;
465289177Speter
466289177Speter    case svn_wc_notify_patch_hunk_already_applied:
467289177Speter      nb->received_some_change = TRUE;
468289177Speter      if (n->prop_name)
469289177Speter        err = svn_cmdline_printf(pool,
470289177Speter                                 _(">         hunk "
471289177Speter                                   "## -%lu,%lu +%lu,%lu ## "
472289177Speter                                   "already applied (%s)\n"),
473289177Speter                                 n->hunk_original_start,
474289177Speter                                 n->hunk_original_length,
475289177Speter                                 n->hunk_modified_start,
476289177Speter                                 n->hunk_modified_length,
477289177Speter                                 n->prop_name);
478289177Speter      else
479289177Speter        err = svn_cmdline_printf(pool,
480289177Speter                                 _(">         hunk "
481289177Speter                                   "@@ -%lu,%lu +%lu,%lu @@ "
482289177Speter                                   "already applied\n"),
483289177Speter                                 n->hunk_original_start,
484289177Speter                                 n->hunk_original_length,
485289177Speter                                 n->hunk_modified_start,
486289177Speter                                 n->hunk_modified_length);
487289177Speter      if (err)
488289177Speter        goto print_error;
489289177Speter      break;
490289177Speter
491289177Speter    case svn_wc_notify_update_update:
492289177Speter    case svn_wc_notify_merge_record_info:
493289177Speter      {
494289177Speter        if (n->content_state == svn_wc_notify_state_conflicted)
495289177Speter          {
496289177Speter            nb->text_conflicts++;
497289177Speter            add_conflicted_path(nb, n->path);
498289177Speter            statchar_buf[0] = 'C';
499289177Speter          }
500289177Speter        else if (n->kind == svn_node_file)
501289177Speter          {
502289177Speter            if (n->content_state == svn_wc_notify_state_merged)
503289177Speter              statchar_buf[0] = 'G';
504289177Speter            else if (n->content_state == svn_wc_notify_state_changed)
505289177Speter              statchar_buf[0] = 'U';
506289177Speter          }
507289177Speter
508289177Speter        if (n->prop_state == svn_wc_notify_state_conflicted)
509289177Speter          {
510289177Speter            nb->prop_conflicts++;
511289177Speter            add_conflicted_path(nb, n->path);
512289177Speter            statchar_buf[1] = 'C';
513289177Speter          }
514289177Speter        else if (n->prop_state == svn_wc_notify_state_merged)
515289177Speter          statchar_buf[1] = 'G';
516289177Speter        else if (n->prop_state == svn_wc_notify_state_changed)
517289177Speter          statchar_buf[1] = 'U';
518289177Speter
519289177Speter        if (n->lock_state == svn_wc_notify_lock_state_unlocked)
520289177Speter          statchar_buf[2] = 'B';
521289177Speter
522289177Speter        if (statchar_buf[0] != ' ' || statchar_buf[1] != ' ')
523289177Speter          nb->received_some_change = TRUE;
524289177Speter
525289177Speter        if (statchar_buf[0] != ' ' || statchar_buf[1] != ' '
526289177Speter            || statchar_buf[2] != ' ')
527289177Speter          {
528289177Speter            if ((err = svn_cmdline_printf(pool, "%s %s\n",
529289177Speter                                          statchar_buf, path_local)))
530289177Speter              goto print_error;
531289177Speter          }
532289177Speter      }
533289177Speter      break;
534289177Speter
535289177Speter    case svn_wc_notify_update_external:
536289177Speter      /* Remember that we're now "inside" an externals definition. */
537289177Speter      nb->in_external = TRUE;
538289177Speter
539289177Speter      /* Currently this is used for checkouts and switches too.  If we
540289177Speter         want different output, we'll have to add new actions. */
541289177Speter      if ((err = svn_cmdline_printf(pool,
542289177Speter                                    _("\nFetching external item into '%s':\n"),
543289177Speter                                    path_local)))
544289177Speter        goto print_error;
545289177Speter      break;
546289177Speter
547289177Speter    case svn_wc_notify_failed_external:
548289177Speter      /* If we are currently inside the handling of an externals
549289177Speter         definition, then we can simply present n->err as a warning
550289177Speter         and feel confident that after this, we aren't handling that
551289177Speter         externals definition any longer. */
552289177Speter      if (nb->in_external)
553289177Speter        {
554289177Speter          svn_handle_warning2(stderr, n->err, "svn: ");
555289177Speter          nb->in_external = FALSE;
556289177Speter          if ((err = svn_cmdline_printf(pool, "\n")))
557289177Speter            goto print_error;
558289177Speter        }
559289177Speter      /* Otherwise, we'll just print two warnings.  Why?  Because
560289177Speter         svn_handle_warning2() only shows the single "best message",
561289177Speter         but we have two pretty important ones: that the external at
562289177Speter         '/some/path' didn't pan out, and then the more specific
563289177Speter         reason why (from n->err). */
564289177Speter      else
565289177Speter        {
566289177Speter          svn_error_t *warn_err =
567289177Speter            svn_error_createf(SVN_ERR_BASE, NULL,
568289177Speter                              _("Error handling externals definition for '%s':"),
569289177Speter                              path_local);
570289177Speter          svn_handle_warning2(stderr, warn_err, "svn: ");
571289177Speter          svn_error_clear(warn_err);
572289177Speter          svn_handle_warning2(stderr, n->err, "svn: ");
573289177Speter        }
574289177Speter      break;
575289177Speter
576289177Speter    case svn_wc_notify_update_started:
577289177Speter      if (! (nb->in_external ||
578289177Speter             nb->is_checkout ||
579289177Speter             nb->is_export))
580289177Speter        {
581289177Speter          if ((err = svn_cmdline_printf(pool, _("Updating '%s':\n"),
582289177Speter                                        path_local)))
583289177Speter            goto print_error;
584289177Speter        }
585289177Speter      break;
586289177Speter
587289177Speter    case svn_wc_notify_update_completed:
588289177Speter      {
589289177Speter        if (SVN_IS_VALID_REVNUM(n->revision))
590289177Speter          {
591289177Speter            if (nb->is_export)
592289177Speter              {
593289177Speter                if ((err = svn_cmdline_printf
594289177Speter                     (pool, nb->in_external
595289177Speter                      ? _("Exported external at revision %ld.\n")
596289177Speter                      : _("Exported revision %ld.\n"),
597289177Speter                      n->revision)))
598289177Speter                  goto print_error;
599289177Speter              }
600289177Speter            else if (nb->is_checkout)
601289177Speter              {
602289177Speter                if ((err = svn_cmdline_printf
603289177Speter                     (pool, nb->in_external
604289177Speter                      ? _("Checked out external at revision %ld.\n")
605289177Speter                      : _("Checked out revision %ld.\n"),
606289177Speter                      n->revision)))
607289177Speter                  goto print_error;
608289177Speter              }
609289177Speter            else
610289177Speter              {
611289177Speter                if (nb->received_some_change)
612289177Speter                  {
613289177Speter                    nb->received_some_change = FALSE;
614289177Speter                    if ((err = svn_cmdline_printf
615289177Speter                         (pool, nb->in_external
616289177Speter                          ? _("Updated external to revision %ld.\n")
617289177Speter                          : _("Updated to revision %ld.\n"),
618289177Speter                          n->revision)))
619289177Speter                      goto print_error;
620289177Speter                  }
621289177Speter                else
622289177Speter                  {
623289177Speter                    if ((err = svn_cmdline_printf
624289177Speter                         (pool, nb->in_external
625289177Speter                          ? _("External at revision %ld.\n")
626289177Speter                          : _("At revision %ld.\n"),
627289177Speter                          n->revision)))
628289177Speter                      goto print_error;
629289177Speter                  }
630289177Speter              }
631289177Speter          }
632289177Speter        else  /* no revision */
633289177Speter          {
634289177Speter            if (nb->is_export)
635289177Speter              {
636289177Speter                if ((err = svn_cmdline_printf
637289177Speter                     (pool, nb->in_external
638289177Speter                      ? _("External export complete.\n")
639289177Speter                      : _("Export complete.\n"))))
640289177Speter                  goto print_error;
641289177Speter              }
642289177Speter            else if (nb->is_checkout)
643289177Speter              {
644289177Speter                if ((err = svn_cmdline_printf
645289177Speter                     (pool, nb->in_external
646289177Speter                      ? _("External checkout complete.\n")
647289177Speter                      : _("Checkout complete.\n"))))
648289177Speter                  goto print_error;
649289177Speter              }
650289177Speter            else
651289177Speter              {
652289177Speter                if ((err = svn_cmdline_printf
653289177Speter                     (pool, nb->in_external
654289177Speter                      ? _("External update complete.\n")
655289177Speter                      : _("Update complete.\n"))))
656289177Speter                  goto print_error;
657289177Speter              }
658289177Speter          }
659289177Speter      }
660289177Speter
661289177Speter      if (nb->in_external)
662289177Speter        {
663289177Speter          nb->in_external = FALSE;
664289177Speter          if ((err = svn_cmdline_printf(pool, "\n")))
665289177Speter            goto print_error;
666289177Speter        }
667289177Speter      break;
668289177Speter
669289177Speter    case svn_wc_notify_status_external:
670289177Speter      if ((err = svn_cmdline_printf
671289177Speter           (pool, _("\nPerforming status on external item at '%s':\n"),
672289177Speter            path_local)))
673289177Speter        goto print_error;
674289177Speter      break;
675289177Speter
676289177Speter    case svn_wc_notify_status_completed:
677289177Speter      if (SVN_IS_VALID_REVNUM(n->revision))
678289177Speter        if ((err = svn_cmdline_printf(pool,
679289177Speter                                      _("Status against revision: %6ld\n"),
680289177Speter                                      n->revision)))
681289177Speter          goto print_error;
682289177Speter      break;
683289177Speter
684289177Speter    case svn_wc_notify_commit_modified:
685289177Speter      /* xgettext: Align the %s's on this and the following 4 messages */
686289177Speter      if ((err = svn_cmdline_printf(pool,
687289177Speter                                    nb->is_wc_to_repos_copy
688289177Speter                                      ? _("Sending copy of       %s\n")
689289177Speter                                      : _("Sending        %s\n"),
690289177Speter                                    path_local)))
691289177Speter        goto print_error;
692289177Speter      break;
693289177Speter
694289177Speter    case svn_wc_notify_commit_added:
695289177Speter    case svn_wc_notify_commit_copied:
696289177Speter      if (n->mime_type && svn_mime_type_is_binary(n->mime_type))
697289177Speter        {
698289177Speter          if ((err = svn_cmdline_printf(pool,
699289177Speter                                        nb->is_wc_to_repos_copy
700289177Speter                                          ? _("Adding copy of (bin)  %s\n")
701289177Speter                                          : _("Adding  (bin)  %s\n"),
702289177Speter                                        path_local)))
703289177Speter          goto print_error;
704289177Speter        }
705289177Speter      else
706289177Speter        {
707289177Speter          if ((err = svn_cmdline_printf(pool,
708289177Speter                                        nb->is_wc_to_repos_copy
709289177Speter                                          ? _("Adding copy of        %s\n")
710289177Speter                                          : _("Adding         %s\n"),
711289177Speter                                        path_local)))
712289177Speter            goto print_error;
713289177Speter        }
714289177Speter      break;
715289177Speter
716289177Speter    case svn_wc_notify_commit_deleted:
717289177Speter      if ((err = svn_cmdline_printf(pool,
718289177Speter                                    nb->is_wc_to_repos_copy
719289177Speter                                      ? _("Deleting copy of      %s\n")
720289177Speter                                      : _("Deleting       %s\n"),
721289177Speter                                    path_local)))
722289177Speter        goto print_error;
723289177Speter      break;
724289177Speter
725289177Speter    case svn_wc_notify_commit_replaced:
726289177Speter    case svn_wc_notify_commit_copied_replaced:
727289177Speter      if ((err = svn_cmdline_printf(pool,
728289177Speter                                    nb->is_wc_to_repos_copy
729289177Speter                                      ? _("Replacing copy of     %s\n")
730289177Speter                                      : _("Replacing      %s\n"),
731289177Speter                                    path_local)))
732289177Speter        goto print_error;
733289177Speter      break;
734289177Speter
735289177Speter    case svn_wc_notify_commit_postfix_txdelta:
736289177Speter      if (! nb->sent_first_txdelta)
737289177Speter        {
738289177Speter          nb->sent_first_txdelta = TRUE;
739289177Speter          if ((err = svn_cmdline_printf(pool,
740289177Speter                                        _("Transmitting file data "))))
741289177Speter            goto print_error;
742289177Speter        }
743289177Speter
744289177Speter      if ((err = svn_cmdline_printf(pool, ".")))
745289177Speter        goto print_error;
746289177Speter      break;
747289177Speter
748289177Speter    case svn_wc_notify_locked:
749289177Speter      if ((err = svn_cmdline_printf(pool, _("'%s' locked by user '%s'.\n"),
750289177Speter                                    path_local, n->lock->owner)))
751289177Speter        goto print_error;
752289177Speter      break;
753289177Speter
754289177Speter    case svn_wc_notify_unlocked:
755289177Speter      if ((err = svn_cmdline_printf(pool, _("'%s' unlocked.\n"),
756289177Speter                                    path_local)))
757289177Speter        goto print_error;
758289177Speter      break;
759289177Speter
760289177Speter    case svn_wc_notify_failed_lock:
761289177Speter    case svn_wc_notify_failed_unlock:
762289177Speter      svn_handle_warning2(stderr, n->err, "svn: ");
763289177Speter      break;
764289177Speter
765289177Speter    case svn_wc_notify_changelist_set:
766289177Speter      if ((err = svn_cmdline_printf(pool, "A [%s] %s\n",
767289177Speter                                    n->changelist_name, path_local)))
768289177Speter        goto print_error;
769289177Speter      break;
770289177Speter
771289177Speter    case svn_wc_notify_changelist_clear:
772289177Speter    case svn_wc_notify_changelist_moved:
773289177Speter      if ((err = svn_cmdline_printf(pool,
774289177Speter                                    "D [%s] %s\n",
775289177Speter                                    n->changelist_name, path_local)))
776289177Speter        goto print_error;
777289177Speter      break;
778289177Speter
779289177Speter    case svn_wc_notify_merge_begin:
780289177Speter      if (n->merge_range == NULL)
781289177Speter        err = svn_cmdline_printf(pool,
782289177Speter                                 _("--- Merging differences between "
783289177Speter                                   "repository URLs into '%s':\n"),
784289177Speter                                 path_local);
785289177Speter      else if (n->merge_range->start == n->merge_range->end - 1
786289177Speter          || n->merge_range->start == n->merge_range->end)
787289177Speter        err = svn_cmdline_printf(pool, _("--- Merging r%ld into '%s':\n"),
788289177Speter                                 n->merge_range->end, path_local);
789289177Speter      else if (n->merge_range->start - 1 == n->merge_range->end)
790289177Speter        err = svn_cmdline_printf(pool,
791289177Speter                                 _("--- Reverse-merging r%ld into '%s':\n"),
792289177Speter                                 n->merge_range->start, path_local);
793289177Speter      else if (n->merge_range->start < n->merge_range->end)
794289177Speter        err = svn_cmdline_printf(pool,
795289177Speter                                 _("--- Merging r%ld through r%ld into "
796289177Speter                                   "'%s':\n"),
797289177Speter                                 n->merge_range->start + 1,
798289177Speter                                 n->merge_range->end, path_local);
799289177Speter      else /* n->merge_range->start > n->merge_range->end - 1 */
800289177Speter        err = svn_cmdline_printf(pool,
801289177Speter                                 _("--- Reverse-merging r%ld through r%ld "
802289177Speter                                   "into '%s':\n"),
803289177Speter                                 n->merge_range->start,
804289177Speter                                 n->merge_range->end + 1, path_local);
805289177Speter      if (err)
806289177Speter        goto print_error;
807289177Speter      break;
808289177Speter
809289177Speter    case svn_wc_notify_merge_record_info_begin:
810289177Speter      if (!n->merge_range)
811289177Speter        {
812289177Speter          err = svn_cmdline_printf(pool,
813289177Speter                                   _("--- Recording mergeinfo for merge "
814289177Speter                                     "between repository URLs into '%s':\n"),
815289177Speter                                   path_local);
816289177Speter        }
817289177Speter      else
818289177Speter        {
819289177Speter          if (n->merge_range->start == n->merge_range->end - 1
820289177Speter              || n->merge_range->start == n->merge_range->end)
821289177Speter            err = svn_cmdline_printf(
822289177Speter              pool,
823289177Speter              _("--- Recording mergeinfo for merge of r%ld into '%s':\n"),
824289177Speter              n->merge_range->end, path_local);
825289177Speter          else if (n->merge_range->start - 1 == n->merge_range->end)
826289177Speter            err = svn_cmdline_printf(
827289177Speter              pool,
828289177Speter              _("--- Recording mergeinfo for reverse merge of r%ld into '%s':\n"),
829289177Speter              n->merge_range->start, path_local);
830289177Speter           else if (n->merge_range->start < n->merge_range->end)
831289177Speter             err = svn_cmdline_printf(
832289177Speter               pool,
833289177Speter               _("--- Recording mergeinfo for merge of r%ld through r%ld into '%s':\n"),
834289177Speter               n->merge_range->start + 1, n->merge_range->end, path_local);
835289177Speter           else /* n->merge_range->start > n->merge_range->end - 1 */
836289177Speter             err = svn_cmdline_printf(
837289177Speter               pool,
838289177Speter               _("--- Recording mergeinfo for reverse merge of r%ld through r%ld into '%s':\n"),
839289177Speter               n->merge_range->start, n->merge_range->end + 1, path_local);
840289177Speter        }
841289177Speter
842289177Speter      if (err)
843289177Speter        goto print_error;
844289177Speter      break;
845289177Speter
846289177Speter    case svn_wc_notify_merge_elide_info:
847289177Speter      if ((err = svn_cmdline_printf(pool,
848289177Speter                                    _("--- Eliding mergeinfo from '%s':\n"),
849289177Speter                                    path_local)))
850289177Speter        goto print_error;
851289177Speter      break;
852289177Speter
853289177Speter    case svn_wc_notify_foreign_merge_begin:
854289177Speter      if (n->merge_range == NULL)
855289177Speter        err = svn_cmdline_printf(pool,
856289177Speter                                 _("--- Merging differences between "
857289177Speter                                   "foreign repository URLs into '%s':\n"),
858289177Speter                                 path_local);
859289177Speter      else if (n->merge_range->start == n->merge_range->end - 1
860289177Speter          || n->merge_range->start == n->merge_range->end)
861289177Speter        err = svn_cmdline_printf(pool,
862289177Speter                                 _("--- Merging (from foreign repository) "
863289177Speter                                   "r%ld into '%s':\n"),
864289177Speter                                 n->merge_range->end, path_local);
865289177Speter      else if (n->merge_range->start - 1 == n->merge_range->end)
866289177Speter        err = svn_cmdline_printf(pool,
867289177Speter                                 _("--- Reverse-merging (from foreign "
868289177Speter                                   "repository) r%ld into '%s':\n"),
869289177Speter                                 n->merge_range->start, path_local);
870289177Speter      else if (n->merge_range->start < n->merge_range->end)
871289177Speter        err = svn_cmdline_printf(pool,
872289177Speter                                 _("--- Merging (from foreign repository) "
873289177Speter                                   "r%ld through r%ld into '%s':\n"),
874289177Speter                                 n->merge_range->start + 1,
875289177Speter                                 n->merge_range->end, path_local);
876289177Speter      else /* n->merge_range->start > n->merge_range->end - 1 */
877289177Speter        err = svn_cmdline_printf(pool,
878289177Speter                                 _("--- Reverse-merging (from foreign "
879289177Speter                                   "repository) r%ld through r%ld into "
880289177Speter                                   "'%s':\n"),
881289177Speter                                 n->merge_range->start,
882289177Speter                                 n->merge_range->end + 1, path_local);
883289177Speter      if (err)
884289177Speter        goto print_error;
885289177Speter      break;
886289177Speter
887289177Speter    case svn_wc_notify_tree_conflict:
888289177Speter      nb->tree_conflicts++;
889289177Speter      add_conflicted_path(nb, n->path);
890289177Speter      if ((err = svn_cmdline_printf(pool, "   C %s\n", path_local)))
891289177Speter        goto print_error;
892289177Speter      break;
893289177Speter
894289177Speter    case svn_wc_notify_update_shadowed_add:
895289177Speter      nb->received_some_change = TRUE;
896289177Speter      if ((err = svn_cmdline_printf(pool, "   A %s\n", path_local)))
897289177Speter        goto print_error;
898289177Speter      break;
899289177Speter
900289177Speter    case svn_wc_notify_update_shadowed_update:
901289177Speter      nb->received_some_change = TRUE;
902289177Speter      if ((err = svn_cmdline_printf(pool, "   U %s\n", path_local)))
903289177Speter        goto print_error;
904289177Speter      break;
905289177Speter
906289177Speter    case svn_wc_notify_update_shadowed_delete:
907289177Speter      nb->received_some_change = TRUE;
908289177Speter      if ((err = svn_cmdline_printf(pool, "   D %s\n", path_local)))
909289177Speter        goto print_error;
910289177Speter      break;
911289177Speter
912289177Speter    case svn_wc_notify_property_modified:
913289177Speter    case svn_wc_notify_property_added:
914289177Speter        err = svn_cmdline_printf(pool,
915289177Speter                                 _("property '%s' set on '%s'\n"),
916289177Speter                                 n->prop_name, path_local);
917289177Speter        if (err)
918289177Speter          goto print_error;
919289177Speter      break;
920289177Speter
921289177Speter    case svn_wc_notify_property_deleted:
922289177Speter        err = svn_cmdline_printf(pool,
923289177Speter                                 _("property '%s' deleted from '%s'.\n"),
924289177Speter                                 n->prop_name, path_local);
925289177Speter        if (err)
926289177Speter          goto print_error;
927289177Speter      break;
928289177Speter
929289177Speter    case svn_wc_notify_property_deleted_nonexistent:
930289177Speter        err = svn_cmdline_printf(pool,
931289177Speter                                 _("Attempting to delete nonexistent "
932289177Speter                                   "property '%s' on '%s'\n"), n->prop_name,
933289177Speter                                   path_local);
934289177Speter        if (err)
935289177Speter          goto print_error;
936289177Speter      break;
937289177Speter
938289177Speter    case svn_wc_notify_revprop_set:
939289177Speter        err = svn_cmdline_printf(pool,
940289177Speter                          _("property '%s' set on repository revision %ld\n"),
941289177Speter                          n->prop_name, n->revision);
942289177Speter        if (err)
943289177Speter          goto print_error;
944289177Speter      break;
945289177Speter
946289177Speter    case svn_wc_notify_revprop_deleted:
947289177Speter        err = svn_cmdline_printf(pool,
948289177Speter                     _("property '%s' deleted from repository revision %ld\n"),
949289177Speter                     n->prop_name, n->revision);
950289177Speter        if (err)
951289177Speter          goto print_error;
952289177Speter      break;
953289177Speter
954289177Speter    case svn_wc_notify_upgraded_path:
955289177Speter        err = svn_cmdline_printf(pool, _("Upgraded '%s'\n"), path_local);
956289177Speter        if (err)
957289177Speter          goto print_error;
958289177Speter      break;
959289177Speter
960289177Speter    case svn_wc_notify_url_redirect:
961289177Speter      err = svn_cmdline_printf(pool, _("Redirecting to URL '%s':\n"),
962289177Speter                               n->url);
963289177Speter      if (err)
964289177Speter        goto print_error;
965289177Speter      break;
966289177Speter
967289177Speter    case svn_wc_notify_path_nonexistent:
968289177Speter      err = svn_cmdline_printf(pool, _("'%s' is not under version control"),
969289177Speter                               path_local);
970289177Speter      if (err)
971289177Speter        goto print_error;
972289177Speter      break;
973289177Speter
974289177Speter    case svn_wc_notify_conflict_resolver_starting:
975289177Speter      /* Once all operations invoke the interactive conflict resolution after
976289177Speter       * they've completed, we can run svn_cl__print_conflict_stats() here. */
977289177Speter      break;
978289177Speter
979289177Speter    case svn_wc_notify_conflict_resolver_done:
980289177Speter      break;
981289177Speter
982289177Speter    default:
983289177Speter      break;
984289177Speter    }
985289177Speter
986289177Speter  if ((err = svn_cmdline_fflush(stdout)))
987289177Speter    goto print_error;
988289177Speter
989289177Speter  return;
990289177Speter
991289177Speter print_error:
992289177Speter  /* If we had no errors before, print this error to stderr. Else, don't print
993289177Speter     anything.  The user already knows there were some output errors,
994289177Speter     so there is no point in flooding her with an error per notification. */
995289177Speter  if (!nb->had_print_error)
996289177Speter    {
997289177Speter      nb->had_print_error = TRUE;
998289177Speter      /* Issue #3014:
999289177Speter       * Don't print anything on broken pipes. The pipe was likely
1000289177Speter       * closed by the process at the other end. We expect that
1001289177Speter       * process to perform error reporting as necessary.
1002289177Speter       *
1003289177Speter       * ### This assumes that there is only one error in a chain for
1004289177Speter       * ### SVN_ERR_IO_PIPE_WRITE_ERROR. See svn_cmdline_fputs(). */
1005289177Speter      if (err->apr_err != SVN_ERR_IO_PIPE_WRITE_ERROR)
1006289177Speter        svn_handle_error2(err, stderr, FALSE, "svn: ");
1007289177Speter    }
1008289177Speter  svn_error_clear(err);
1009289177Speter}
1010289177Speter
1011289177Speter
1012289177Spetersvn_error_t *
1013289177Spetersvn_cl__get_notifier(svn_wc_notify_func2_t *notify_func_p,
1014289177Speter                     void **notify_baton_p,
1015289177Speter                     apr_pool_t *pool)
1016289177Speter{
1017289177Speter  struct notify_baton *nb = apr_pcalloc(pool, sizeof(*nb));
1018289177Speter
1019289177Speter  nb->received_some_change = FALSE;
1020289177Speter  nb->sent_first_txdelta = FALSE;
1021289177Speter  nb->is_checkout = FALSE;
1022289177Speter  nb->is_export = FALSE;
1023289177Speter  nb->is_wc_to_repos_copy = FALSE;
1024289177Speter  nb->in_external = FALSE;
1025289177Speter  nb->had_print_error = FALSE;
1026289177Speter  nb->text_conflicts = 0;
1027289177Speter  nb->prop_conflicts = 0;
1028289177Speter  nb->tree_conflicts = 0;
1029289177Speter  nb->skipped_paths = 0;
1030289177Speter  nb->conflicted_paths = apr_hash_make(pool);
1031289177Speter  SVN_ERR(svn_dirent_get_absolute(&nb->path_prefix, "", pool));
1032289177Speter
1033289177Speter  *notify_func_p = notify;
1034289177Speter  *notify_baton_p = nb;
1035289177Speter  return SVN_NO_ERROR;
1036289177Speter}
1037289177Speter
1038289177Spetersvn_error_t *
1039289177Spetersvn_cl__notifier_mark_export(void *baton)
1040289177Speter{
1041289177Speter  struct notify_baton *nb = baton;
1042289177Speter
1043289177Speter  nb->is_export = TRUE;
1044289177Speter  return SVN_NO_ERROR;
1045289177Speter}
1046