Followup to r29625: fix getopt tests.
[svn.git] / subversion / svn / notify.c
blobb7a54f01bef8c5ffc22c8d06566027079cc49fc8
1 /*
2 * notify.c: feedback handlers for cmdline client.
4 * ====================================================================
5 * Copyright (c) 2000-2007 CollabNet. All rights reserved.
7 * This software is licensed as described in the file COPYING, which
8 * you should have received as part of this distribution. The terms
9 * are also available at http://subversion.tigris.org/license-1.html.
10 * If newer versions of this license are posted there, you may use a
11 * newer version instead, at your option.
13 * This software consists of voluntary contributions made by many
14 * individuals. For exact contribution history, see the revision
15 * history and logs, available at http://subversion.tigris.org/.
16 * ====================================================================
19 /* ==================================================================== */
23 /*** Includes. ***/
25 #define APR_WANT_STDIO
26 #define APR_WANT_STRFUNC
27 #include <apr_want.h>
29 #include "svn_cmdline.h"
30 #include "svn_pools.h"
31 #include "svn_path.h"
32 #include "cl.h"
34 #include "svn_private_config.h"
37 /* Baton for notify and friends. */
38 struct notify_baton
40 svn_boolean_t received_some_change;
41 svn_boolean_t is_checkout;
42 svn_boolean_t is_export;
43 svn_boolean_t suppress_final_line;
44 svn_boolean_t sent_first_txdelta;
45 svn_boolean_t in_external;
46 svn_boolean_t had_print_error; /* Used to not keep printing error messages
47 when we've already had one print error. */
51 /* This implements `svn_wc_notify_func2_t'.
52 * NOTE: This function can't fail, so we just ignore any print errors. */
53 static void
54 notify(void *baton, const svn_wc_notify_t *n, apr_pool_t *pool)
56 struct notify_baton *nb = baton;
57 char statchar_buf[5] = " ";
58 const char *path_local;
59 svn_error_t *err;
61 if (svn_path_is_url(n->path))
62 path_local = n->path;
63 else
64 path_local = svn_path_local_style(n->path, pool);
66 switch (n->action)
68 case svn_wc_notify_skip:
69 if (n->content_state == svn_wc_notify_state_missing)
71 if ((err = svn_cmdline_printf
72 (pool, _("Skipped missing target: '%s'\n"),
73 path_local)))
74 goto print_error;
76 else
78 if ((err = svn_cmdline_printf
79 (pool, _("Skipped '%s'\n"), path_local)))
80 goto print_error;
82 break;
84 case svn_wc_notify_update_delete:
85 nb->received_some_change = TRUE;
86 if ((err = svn_cmdline_printf(pool, "D %s\n", path_local)))
87 goto print_error;
88 break;
90 case svn_wc_notify_update_replace:
91 nb->received_some_change = TRUE;
92 if ((err = svn_cmdline_printf(pool, "R %s\n", path_local)))
93 goto print_error;
94 break;
96 case svn_wc_notify_update_add:
97 nb->received_some_change = TRUE;
98 if (n->content_state == svn_wc_notify_state_conflicted)
100 if ((err = svn_cmdline_printf(pool, "C %s\n", path_local)))
101 goto print_error;
103 else
105 if ((err = svn_cmdline_printf(pool, "A %s\n", path_local)))
106 goto print_error;
108 break;
110 case svn_wc_notify_exists:
111 nb->received_some_change = TRUE;
112 if (n->content_state == svn_wc_notify_state_conflicted)
113 statchar_buf[0] = 'C';
114 else
115 statchar_buf[0] = 'E';
117 if (n->prop_state == svn_wc_notify_state_conflicted)
118 statchar_buf[1] = 'C';
119 else if (n->prop_state == svn_wc_notify_state_merged)
120 statchar_buf[1] = 'G';
122 if ((err = svn_cmdline_printf(pool, "%s %s\n", statchar_buf, path_local)))
123 goto print_error;
124 break;
126 case svn_wc_notify_restore:
127 if ((err = svn_cmdline_printf(pool, _("Restored '%s'\n"),
128 path_local)))
129 goto print_error;
130 break;
132 case svn_wc_notify_revert:
133 if ((err = svn_cmdline_printf(pool, _("Reverted '%s'\n"),
134 path_local)))
135 goto print_error;
136 break;
138 case svn_wc_notify_failed_revert:
139 if (( err = svn_cmdline_printf(pool, _("Failed to revert '%s' -- "
140 "try updating instead.\n"),
141 path_local)))
142 goto print_error;
143 break;
145 case svn_wc_notify_resolved:
146 if ((err = svn_cmdline_printf(pool,
147 _("Resolved conflicted state of '%s'\n"),
148 path_local)))
149 goto print_error;
150 break;
152 case svn_wc_notify_add:
153 /* We *should* only get the MIME_TYPE if PATH is a file. If we
154 do get it, and the mime-type is not textual, note that this
155 is a binary addition. */
156 if (n->mime_type && (svn_mime_type_is_binary(n->mime_type)))
158 if ((err = svn_cmdline_printf(pool, "A (bin) %s\n",
159 path_local)))
160 goto print_error;
162 else
164 if ((err = svn_cmdline_printf(pool, "A %s\n",
165 path_local)))
166 goto print_error;
168 break;
170 case svn_wc_notify_delete:
171 nb->received_some_change = TRUE;
172 if ((err = svn_cmdline_printf(pool, "D %s\n",
173 path_local)))
174 goto print_error;
175 break;
177 case svn_wc_notify_update_update:
179 /* If this is an inoperative dir change, do no notification.
180 An inoperative dir change is when a directory gets closed
181 without any props having been changed. */
182 if (! ((n->kind == svn_node_dir)
183 && ((n->prop_state == svn_wc_notify_state_inapplicable)
184 || (n->prop_state == svn_wc_notify_state_unknown)
185 || (n->prop_state == svn_wc_notify_state_unchanged))))
187 if (n->kind == svn_node_file)
189 if (n->content_state == svn_wc_notify_state_conflicted)
190 statchar_buf[0] = 'C';
191 else if (n->content_state == svn_wc_notify_state_merged)
192 statchar_buf[0] = 'G';
193 else if (n->content_state == svn_wc_notify_state_changed)
194 statchar_buf[0] = 'U';
197 if (n->prop_state == svn_wc_notify_state_conflicted)
198 statchar_buf[1] = 'C';
199 else if (n->prop_state == svn_wc_notify_state_merged)
200 statchar_buf[1] = 'G';
201 else if (n->prop_state == svn_wc_notify_state_changed)
202 statchar_buf[1] = 'U';
204 if (n->lock_state == svn_wc_notify_lock_state_unlocked)
205 statchar_buf[2] = 'B';
207 if (statchar_buf[0] != ' ' || statchar_buf[1] != ' ')
208 nb->received_some_change = TRUE;
210 if (statchar_buf[0] != ' ' || statchar_buf[1] != ' '
211 || statchar_buf[2] != ' ')
213 if ((err = svn_cmdline_printf(pool, "%s %s\n",
214 statchar_buf, path_local)))
215 goto print_error;
219 break;
221 case svn_wc_notify_update_external:
222 /* Remember that we're now "inside" an externals definition. */
223 nb->in_external = TRUE;
225 /* Currently this is used for checkouts and switches too. If we
226 want different output, we'll have to add new actions. */
227 if ((err = svn_cmdline_printf(pool,
228 _("\nFetching external item into '%s'\n"),
229 path_local)))
230 goto print_error;
231 break;
233 case svn_wc_notify_update_completed:
235 if (! nb->suppress_final_line)
237 if (SVN_IS_VALID_REVNUM(n->revision))
239 if (nb->is_export)
241 if ((err = svn_cmdline_printf
242 (pool, nb->in_external
243 ? _("Exported external at revision %ld.\n")
244 : _("Exported revision %ld.\n"),
245 n->revision)))
246 goto print_error;
248 else if (nb->is_checkout)
250 if ((err = svn_cmdline_printf
251 (pool, nb->in_external
252 ? _("Checked out external at revision %ld.\n")
253 : _("Checked out revision %ld.\n"),
254 n->revision)))
255 goto print_error;
257 else
259 if (nb->received_some_change)
261 if ((err = svn_cmdline_printf
262 (pool, nb->in_external
263 ? _("Updated external to revision %ld.\n")
264 : _("Updated to revision %ld.\n"),
265 n->revision)))
266 goto print_error;
268 else
270 if ((err = svn_cmdline_printf
271 (pool, nb->in_external
272 ? _("External at revision %ld.\n")
273 : _("At revision %ld.\n"),
274 n->revision)))
275 goto print_error;
279 else /* no revision */
281 if (nb->is_export)
283 if ((err = svn_cmdline_printf
284 (pool, nb->in_external
285 ? _("External export complete.\n")
286 : _("Export complete.\n"))))
287 goto print_error;
289 else if (nb->is_checkout)
291 if ((err = svn_cmdline_printf
292 (pool, nb->in_external
293 ? _("External checkout complete.\n")
294 : _("Checkout complete.\n"))))
295 goto print_error;
297 else
299 if ((err = svn_cmdline_printf
300 (pool, nb->in_external
301 ? _("External update complete.\n")
302 : _("Update complete.\n"))))
303 goto print_error;
308 if (nb->in_external)
310 nb->in_external = FALSE;
311 if ((err = svn_cmdline_printf(pool, "\n")))
312 goto print_error;
314 break;
316 case svn_wc_notify_status_external:
317 if ((err = svn_cmdline_printf
318 (pool, _("\nPerforming status on external item at '%s'\n"),
319 path_local)))
320 goto print_error;
321 break;
323 case svn_wc_notify_status_completed:
324 if (SVN_IS_VALID_REVNUM(n->revision))
325 if ((err = svn_cmdline_printf(pool,
326 _("Status against revision: %6ld\n"),
327 n->revision)))
328 goto print_error;
329 break;
331 case svn_wc_notify_commit_modified:
332 /* xgettext: Align the %s's on this and the following 4 messages */
333 if ((err = svn_cmdline_printf(pool,
334 _("Sending %s\n"),
335 path_local)))
336 goto print_error;
337 break;
339 case svn_wc_notify_commit_added:
340 if (n->mime_type && svn_mime_type_is_binary(n->mime_type))
342 if ((err = svn_cmdline_printf(pool,
343 _("Adding (bin) %s\n"),
344 path_local)))
345 goto print_error;
347 else
349 if ((err = svn_cmdline_printf(pool,
350 _("Adding %s\n"),
351 path_local)))
352 goto print_error;
354 break;
356 case svn_wc_notify_commit_deleted:
357 if ((err = svn_cmdline_printf(pool, _("Deleting %s\n"),
358 path_local)))
359 goto print_error;
360 break;
362 case svn_wc_notify_commit_replaced:
363 if ((err = svn_cmdline_printf(pool,
364 _("Replacing %s\n"),
365 path_local)))
366 goto print_error;
367 break;
369 case svn_wc_notify_commit_postfix_txdelta:
370 if (! nb->sent_first_txdelta)
372 nb->sent_first_txdelta = TRUE;
373 if ((err = svn_cmdline_printf(pool,
374 _("Transmitting file data "))))
375 goto print_error;
378 if ((err = svn_cmdline_printf(pool, ".")))
379 goto print_error;
380 break;
382 case svn_wc_notify_locked:
383 if ((err = svn_cmdline_printf(pool, _("'%s' locked by user '%s'.\n"),
384 path_local, n->lock->owner)))
385 goto print_error;
386 break;
388 case svn_wc_notify_unlocked:
389 if ((err = svn_cmdline_printf(pool, _("'%s' unlocked.\n"),
390 path_local)))
391 goto print_error;
392 break;
394 case svn_wc_notify_failed_lock:
395 case svn_wc_notify_failed_unlock:
396 svn_handle_warning(stderr, n->err);
397 break;
399 case svn_wc_notify_changelist_set:
400 if ((err = svn_cmdline_printf(pool, _("Path '%s' is now a member of "
401 "changelist '%s'.\n"),
402 path_local, n->changelist_name)))
403 goto print_error;
404 break;
406 case svn_wc_notify_changelist_clear:
407 if ((err = svn_cmdline_printf(pool,
408 _("Path '%s' is no longer a member of "
409 "a changelist.\n"),
410 path_local)))
411 goto print_error;
412 break;
414 case svn_wc_notify_changelist_failed:
415 svn_handle_warning(stderr, n->err);
416 svn_error_clear(n->err);
417 break;
419 case svn_wc_notify_changelist_moved:
420 svn_handle_warning(stderr, n->err);
421 svn_error_clear(n->err);
422 break;
424 case svn_wc_notify_merge_begin:
425 if (n->merge_range == NULL)
426 err = svn_cmdline_printf(pool,
427 _("--- Merging differences between "
428 "repository URLs into '%s':\n"),
429 path_local);
430 else if (n->merge_range->start == n->merge_range->end - 1
431 || n->merge_range->start == n->merge_range->end)
432 err = svn_cmdline_printf(pool, _("--- Merging r%ld into '%s':\n"),
433 n->merge_range->end, path_local);
434 else if (n->merge_range->start - 1 == n->merge_range->end)
435 err = svn_cmdline_printf(pool,
436 _("--- Reverse-merging r%ld into '%s':\n"),
437 n->merge_range->start, path_local);
438 else if (n->merge_range->start < n->merge_range->end)
439 err = svn_cmdline_printf(pool,
440 _("--- Merging r%ld through r%ld into "
441 "'%s':\n"),
442 n->merge_range->start + 1,
443 n->merge_range->end, path_local);
444 else /* n->merge_range->start > n->merge_range->end - 1 */
445 err = svn_cmdline_printf(pool,
446 _("--- Reverse-merging r%ld through r%ld "
447 "into '%s':\n"),
448 n->merge_range->start,
449 n->merge_range->end + 1, path_local);
450 if (err)
451 goto print_error;
452 break;
454 default:
455 break;
458 if ((err = svn_cmdline_fflush(stdout)))
459 goto print_error;
461 return;
463 print_error:
464 /* If we had no errors before, print this error to stderr. Else, don't print
465 anything. The user already knows there were some output errors,
466 so there is no point in flooding her with an error per notification. */
467 if (!nb->had_print_error)
469 nb->had_print_error = TRUE;
470 svn_handle_error2(err, stderr, FALSE, "svn: ");
472 svn_error_clear(err);
476 void
477 svn_cl__get_notifier(svn_wc_notify_func2_t *notify_func_p,
478 void **notify_baton_p,
479 svn_boolean_t is_checkout,
480 svn_boolean_t is_export,
481 svn_boolean_t suppress_final_line,
482 apr_pool_t *pool)
484 struct notify_baton *nb = apr_palloc(pool, sizeof(*nb));
486 nb->received_some_change = FALSE;
487 nb->sent_first_txdelta = FALSE;
488 nb->is_checkout = is_checkout;
489 nb->is_export = is_export;
490 nb->suppress_final_line = suppress_final_line;
491 nb->in_external = FALSE;
492 nb->had_print_error = FALSE;
494 *notify_func_p = notify;
495 *notify_baton_p = nb;