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 /* ==================================================================== */
25 #define APR_WANT_STDIO
26 #define APR_WANT_STRFUNC
29 #include "svn_cmdline.h"
30 #include "svn_pools.h"
34 #include "svn_private_config.h"
37 /* Baton for notify and friends. */
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. */
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
;
61 if (svn_path_is_url(n
->path
))
64 path_local
= svn_path_local_style(n
->path
, pool
);
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"),
78 if ((err
= svn_cmdline_printf
79 (pool
, _("Skipped '%s'\n"), path_local
)))
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
)))
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
)))
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
)))
105 if ((err
= svn_cmdline_printf(pool
, "A %s\n", path_local
)))
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';
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
)))
126 case svn_wc_notify_restore
:
127 if ((err
= svn_cmdline_printf(pool
, _("Restored '%s'\n"),
132 case svn_wc_notify_revert
:
133 if ((err
= svn_cmdline_printf(pool
, _("Reverted '%s'\n"),
138 case svn_wc_notify_failed_revert
:
139 if (( err
= svn_cmdline_printf(pool
, _("Failed to revert '%s' -- "
140 "try updating instead.\n"),
145 case svn_wc_notify_resolved
:
146 if ((err
= svn_cmdline_printf(pool
,
147 _("Resolved conflicted state of '%s'\n"),
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",
164 if ((err
= svn_cmdline_printf(pool
, "A %s\n",
170 case svn_wc_notify_delete
:
171 nb
->received_some_change
= TRUE
;
172 if ((err
= svn_cmdline_printf(pool
, "D %s\n",
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
)))
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"),
233 case svn_wc_notify_update_completed
:
235 if (! nb
->suppress_final_line
)
237 if (SVN_IS_VALID_REVNUM(n
->revision
))
241 if ((err
= svn_cmdline_printf
242 (pool
, nb
->in_external
243 ? _("Exported external at revision %ld.\n")
244 : _("Exported revision %ld.\n"),
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"),
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"),
270 if ((err
= svn_cmdline_printf
271 (pool
, nb
->in_external
272 ? _("External at revision %ld.\n")
273 : _("At revision %ld.\n"),
279 else /* no revision */
283 if ((err
= svn_cmdline_printf
284 (pool
, nb
->in_external
285 ? _("External export complete.\n")
286 : _("Export complete.\n"))))
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"))))
299 if ((err
= svn_cmdline_printf
300 (pool
, nb
->in_external
301 ? _("External update complete.\n")
302 : _("Update complete.\n"))))
310 nb
->in_external
= FALSE
;
311 if ((err
= svn_cmdline_printf(pool
, "\n")))
316 case svn_wc_notify_status_external
:
317 if ((err
= svn_cmdline_printf
318 (pool
, _("\nPerforming status on external item at '%s'\n"),
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"),
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
,
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"),
349 if ((err
= svn_cmdline_printf(pool
,
356 case svn_wc_notify_commit_deleted
:
357 if ((err
= svn_cmdline_printf(pool
, _("Deleting %s\n"),
362 case svn_wc_notify_commit_replaced
:
363 if ((err
= svn_cmdline_printf(pool
,
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 "))))
378 if ((err
= svn_cmdline_printf(pool
, ".")))
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
)))
388 case svn_wc_notify_unlocked
:
389 if ((err
= svn_cmdline_printf(pool
, _("'%s' unlocked.\n"),
394 case svn_wc_notify_failed_lock
:
395 case svn_wc_notify_failed_unlock
:
396 svn_handle_warning(stderr
, n
->err
);
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
)))
406 case svn_wc_notify_changelist_clear
:
407 if ((err
= svn_cmdline_printf(pool
,
408 _("Path '%s' is no longer a member of "
414 case svn_wc_notify_changelist_failed
:
415 svn_handle_warning(stderr
, n
->err
);
416 svn_error_clear(n
->err
);
419 case svn_wc_notify_changelist_moved
:
420 svn_handle_warning(stderr
, n
->err
);
421 svn_error_clear(n
->err
);
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"),
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 "
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 "
448 n
->merge_range
->start
,
449 n
->merge_range
->end
+ 1, path_local
);
458 if ((err
= svn_cmdline_fflush(stdout
)))
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
);
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
,
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
;