summaryrefslogtreecommitdiff
path: root/subversion/svn/notify.c
diff options
context:
space:
mode:
Diffstat (limited to 'subversion/svn/notify.c')
-rw-r--r--subversion/svn/notify.c413
1 files changed, 276 insertions, 137 deletions
diff --git a/subversion/svn/notify.c b/subversion/svn/notify.c
index a785e53..6498fb1 100644
--- a/subversion/svn/notify.c
+++ b/subversion/svn/notify.c
@@ -35,7 +35,11 @@
#include "svn_pools.h"
#include "svn_dirent_uri.h"
#include "svn_path.h"
+#include "svn_sorts.h"
+#include "svn_hash.h"
#include "cl.h"
+#include "private/svn_subr_private.h"
+#include "private/svn_dep_compat.h"
#include "svn_private_config.h"
@@ -47,56 +51,154 @@ struct notify_baton
svn_boolean_t is_checkout;
svn_boolean_t is_export;
svn_boolean_t is_wc_to_repos_copy;
- svn_boolean_t suppress_summary_lines;
svn_boolean_t sent_first_txdelta;
svn_boolean_t in_external;
svn_boolean_t had_print_error; /* Used to not keep printing error messages
when we've already had one print error. */
- /* Conflict stats for update and merge. */
- unsigned int text_conflicts;
- unsigned int prop_conflicts;
- unsigned int tree_conflicts;
- unsigned int skipped_paths;
+ svn_cl__conflict_stats_t *conflict_stats;
/* The cwd, for use in decomposing absolute paths. */
const char *path_prefix;
};
-
-svn_error_t *
-svn_cl__print_conflict_stats(void *notify_baton, apr_pool_t *pool)
+/* Conflict stats for operations such as update and merge. */
+struct svn_cl__conflict_stats_t
{
- struct notify_baton *nb = notify_baton;
- unsigned int text_conflicts;
- unsigned int prop_conflicts;
- unsigned int tree_conflicts;
- unsigned int skipped_paths;
+ apr_pool_t *stats_pool;
+ apr_hash_t *text_conflicts, *prop_conflicts, *tree_conflicts;
+ int text_conflicts_resolved, prop_conflicts_resolved, tree_conflicts_resolved;
+ int skipped_paths;
+};
- text_conflicts = nb->text_conflicts;
- prop_conflicts = nb->prop_conflicts;
- tree_conflicts = nb->tree_conflicts;
- skipped_paths = nb->skipped_paths;
+svn_cl__conflict_stats_t *
+svn_cl__conflict_stats_create(apr_pool_t *pool)
+{
+ svn_cl__conflict_stats_t *conflict_stats
+ = apr_palloc(pool, sizeof(*conflict_stats));
+
+ conflict_stats->stats_pool = pool;
+ conflict_stats->text_conflicts = apr_hash_make(pool);
+ conflict_stats->prop_conflicts = apr_hash_make(pool);
+ conflict_stats->tree_conflicts = apr_hash_make(pool);
+ conflict_stats->text_conflicts_resolved = 0;
+ conflict_stats->prop_conflicts_resolved = 0;
+ conflict_stats->tree_conflicts_resolved = 0;
+ conflict_stats->skipped_paths = 0;
+ return conflict_stats;
+}
- if (text_conflicts > 0 || prop_conflicts > 0
- || tree_conflicts > 0 || skipped_paths > 0)
- SVN_ERR(svn_cmdline_printf(pool, "%s", _("Summary of conflicts:\n")));
+/* Add the PATH (as a key, with a meaningless value) into the HASH in NB. */
+static void
+store_path(struct notify_baton *nb, apr_hash_t *hash, const char *path)
+{
+ svn_hash_sets(hash, apr_pstrdup(nb->conflict_stats->stats_pool, path), "");
+}
- if (text_conflicts > 0)
- SVN_ERR(svn_cmdline_printf
- (pool, _(" Text conflicts: %u\n"), text_conflicts));
+void
+svn_cl__conflict_stats_resolved(svn_cl__conflict_stats_t *conflict_stats,
+ const char *path_local,
+ svn_wc_conflict_kind_t conflict_kind)
+{
+ switch (conflict_kind)
+ {
+ case svn_wc_conflict_kind_text:
+ if (svn_hash_gets(conflict_stats->text_conflicts, path_local))
+ {
+ svn_hash_sets(conflict_stats->text_conflicts, path_local, NULL);
+ conflict_stats->text_conflicts_resolved++;
+ }
+ break;
+ case svn_wc_conflict_kind_property:
+ if (svn_hash_gets(conflict_stats->prop_conflicts, path_local))
+ {
+ svn_hash_sets(conflict_stats->prop_conflicts, path_local, NULL);
+ conflict_stats->prop_conflicts_resolved++;
+ }
+ break;
+ case svn_wc_conflict_kind_tree:
+ if (svn_hash_gets(conflict_stats->tree_conflicts, path_local))
+ {
+ svn_hash_sets(conflict_stats->tree_conflicts, path_local, NULL);
+ conflict_stats->tree_conflicts_resolved++;
+ }
+ break;
+ }
+}
- if (prop_conflicts > 0)
- SVN_ERR(svn_cmdline_printf
- (pool, _(" Property conflicts: %u\n"), prop_conflicts));
+static const char *
+remaining_str(apr_pool_t *pool, int n_remaining)
+{
+ return apr_psprintf(pool, Q_("%d remaining",
+ "%d remaining",
+ n_remaining),
+ n_remaining);
+}
- if (tree_conflicts > 0)
- SVN_ERR(svn_cmdline_printf
- (pool, _(" Tree conflicts: %u\n"), tree_conflicts));
+static const char *
+resolved_str(apr_pool_t *pool, int n_resolved)
+{
+ return apr_psprintf(pool, Q_("and %d already resolved",
+ "and %d already resolved",
+ n_resolved),
+ n_resolved);
+}
- if (skipped_paths > 0)
- SVN_ERR(svn_cmdline_printf
- (pool, _(" Skipped paths: %u\n"), skipped_paths));
+svn_error_t *
+svn_cl__notifier_print_conflict_stats(void *baton, apr_pool_t *scratch_pool)
+{
+ struct notify_baton *nb = baton;
+ int n_text = apr_hash_count(nb->conflict_stats->text_conflicts);
+ int n_prop = apr_hash_count(nb->conflict_stats->prop_conflicts);
+ int n_tree = apr_hash_count(nb->conflict_stats->tree_conflicts);
+ int n_text_r = nb->conflict_stats->text_conflicts_resolved;
+ int n_prop_r = nb->conflict_stats->prop_conflicts_resolved;
+ int n_tree_r = nb->conflict_stats->tree_conflicts_resolved;
+
+ if (n_text > 0 || n_text_r > 0
+ || n_prop > 0 || n_prop_r > 0
+ || n_tree > 0 || n_tree_r > 0
+ || nb->conflict_stats->skipped_paths > 0)
+ SVN_ERR(svn_cmdline_printf(scratch_pool,
+ _("Summary of conflicts:\n")));
+
+ if (n_text_r == 0 && n_prop_r == 0 && n_tree_r == 0)
+ {
+ if (n_text > 0)
+ SVN_ERR(svn_cmdline_printf(scratch_pool,
+ _(" Text conflicts: %d\n"),
+ n_text));
+ if (n_prop > 0)
+ SVN_ERR(svn_cmdline_printf(scratch_pool,
+ _(" Property conflicts: %d\n"),
+ n_prop));
+ if (n_tree > 0)
+ SVN_ERR(svn_cmdline_printf(scratch_pool,
+ _(" Tree conflicts: %d\n"),
+ n_tree));
+ }
+ else
+ {
+ if (n_text > 0 || n_text_r > 0)
+ SVN_ERR(svn_cmdline_printf(scratch_pool,
+ _(" Text conflicts: %s (%s)\n"),
+ remaining_str(scratch_pool, n_text),
+ resolved_str(scratch_pool, n_text_r)));
+ if (n_prop > 0 || n_prop_r > 0)
+ SVN_ERR(svn_cmdline_printf(scratch_pool,
+ _(" Property conflicts: %s (%s)\n"),
+ remaining_str(scratch_pool, n_prop),
+ resolved_str(scratch_pool, n_prop_r)));
+ if (n_tree > 0 || n_tree_r > 0)
+ SVN_ERR(svn_cmdline_printf(scratch_pool,
+ _(" Tree conflicts: %s (%s)\n"),
+ remaining_str(scratch_pool, n_tree),
+ resolved_str(scratch_pool, n_tree_r)));
+ }
+ if (nb->conflict_stats->skipped_paths > 0)
+ SVN_ERR(svn_cmdline_printf(scratch_pool,
+ _(" Skipped paths: %d\n"),
+ nb->conflict_stats->skipped_paths));
return SVN_NO_ERROR;
}
@@ -126,7 +228,7 @@ notify(void *baton, const svn_wc_notify_t *n, apr_pool_t *pool)
switch (n->action)
{
case svn_wc_notify_skip:
- nb->skipped_paths++;
+ nb->conflict_stats->skipped_paths++;
if (n->content_state == svn_wc_notify_state_missing)
{
if ((err = svn_cmdline_printf
@@ -149,28 +251,28 @@ notify(void *baton, const svn_wc_notify_t *n, apr_pool_t *pool)
}
break;
case svn_wc_notify_update_skip_obstruction:
- nb->skipped_paths++;
+ nb->conflict_stats->skipped_paths++;
if ((err = svn_cmdline_printf(
pool, _("Skipped '%s' -- An obstructing working copy was found\n"),
path_local)))
goto print_error;
break;
case svn_wc_notify_update_skip_working_only:
- nb->skipped_paths++;
+ nb->conflict_stats->skipped_paths++;
if ((err = svn_cmdline_printf(
pool, _("Skipped '%s' -- Has no versioned parent\n"),
path_local)))
goto print_error;
break;
case svn_wc_notify_update_skip_access_denied:
- nb->skipped_paths++;
+ nb->conflict_stats->skipped_paths++;
if ((err = svn_cmdline_printf(
pool, _("Skipped '%s' -- Access denied\n"),
path_local)))
goto print_error;
break;
case svn_wc_notify_skip_conflicted:
- nb->skipped_paths++;
+ nb->conflict_stats->skipped_paths++;
if ((err = svn_cmdline_printf(
pool, _("Skipped '%s' -- Node remains in conflict\n"),
path_local)))
@@ -182,6 +284,10 @@ notify(void *baton, const svn_wc_notify_t *n, apr_pool_t *pool)
if ((err = svn_cmdline_printf(pool, "D %s\n", path_local)))
goto print_error;
break;
+ case svn_wc_notify_update_broken_lock:
+ if ((err = svn_cmdline_printf(pool, "B %s\n", path_local)))
+ goto print_error;
+ break;
case svn_wc_notify_update_external_removed:
nb->received_some_change = TRUE;
@@ -199,6 +305,12 @@ notify(void *baton, const svn_wc_notify_t *n, apr_pool_t *pool)
}
break;
+ case svn_wc_notify_left_local_modifications:
+ if ((err = svn_cmdline_printf(pool, "Left local modifications as '%s'\n",
+ path_local)))
+ goto print_error;
+ break;
+
case svn_wc_notify_update_replace:
nb->received_some_change = TRUE;
if ((err = svn_cmdline_printf(pool, "R %s\n", path_local)))
@@ -209,7 +321,7 @@ notify(void *baton, const svn_wc_notify_t *n, apr_pool_t *pool)
nb->received_some_change = TRUE;
if (n->content_state == svn_wc_notify_state_conflicted)
{
- nb->text_conflicts++;
+ store_path(nb, nb->conflict_stats->text_conflicts, path_local);
if ((err = svn_cmdline_printf(pool, "C %s\n", path_local)))
goto print_error;
}
@@ -224,7 +336,7 @@ notify(void *baton, const svn_wc_notify_t *n, apr_pool_t *pool)
nb->received_some_change = TRUE;
if (n->content_state == svn_wc_notify_state_conflicted)
{
- nb->text_conflicts++;
+ store_path(nb, nb->conflict_stats->text_conflicts, path_local);
statchar_buf[0] = 'C';
}
else
@@ -232,7 +344,7 @@ notify(void *baton, const svn_wc_notify_t *n, apr_pool_t *pool)
if (n->prop_state == svn_wc_notify_state_conflicted)
{
- nb->prop_conflicts++;
+ store_path(nb, nb->conflict_stats->prop_conflicts, path_local);
statchar_buf[1] = 'C';
}
else if (n->prop_state == svn_wc_notify_state_merged)
@@ -298,7 +410,7 @@ notify(void *baton, const svn_wc_notify_t *n, apr_pool_t *pool)
nb->received_some_change = TRUE;
if (n->content_state == svn_wc_notify_state_conflicted)
{
- nb->text_conflicts++;
+ store_path(nb, nb->conflict_stats->text_conflicts, path_local);
statchar_buf[0] = 'C';
}
else if (n->kind == svn_node_file)
@@ -311,7 +423,7 @@ notify(void *baton, const svn_wc_notify_t *n, apr_pool_t *pool)
if (n->prop_state == svn_wc_notify_state_conflicted)
{
- nb->prop_conflicts++;
+ store_path(nb, nb->conflict_stats->prop_conflicts, path_local);
statchar_buf[1] = 'C';
}
else if (n->prop_state == svn_wc_notify_state_changed)
@@ -336,7 +448,13 @@ notify(void *baton, const svn_wc_notify_t *n, apr_pool_t *pool)
if (n->hunk_matched_line > n->hunk_original_start)
{
- off = n->hunk_matched_line - n->hunk_original_start;
+ /* If we are patching from the start of an empty file,
+ it is nicer to show offset 0 */
+ if (n->hunk_original_start == 0 && n->hunk_matched_line == 1)
+ off = 0; /* No offset, just adding */
+ else
+ off = n->hunk_matched_line - n->hunk_original_start;
+
minus = "";
}
else
@@ -504,7 +622,7 @@ notify(void *baton, const svn_wc_notify_t *n, apr_pool_t *pool)
{
if (n->content_state == svn_wc_notify_state_conflicted)
{
- nb->text_conflicts++;
+ store_path(nb, nb->conflict_stats->text_conflicts, path_local);
statchar_buf[0] = 'C';
}
else if (n->kind == svn_node_file)
@@ -517,7 +635,7 @@ notify(void *baton, const svn_wc_notify_t *n, apr_pool_t *pool)
if (n->prop_state == svn_wc_notify_state_conflicted)
{
- nb->prop_conflicts++;
+ store_path(nb, nb->conflict_stats->prop_conflicts, path_local);
statchar_buf[1] = 'C';
}
else if (n->prop_state == svn_wc_notify_state_merged)
@@ -583,8 +701,7 @@ notify(void *baton, const svn_wc_notify_t *n, apr_pool_t *pool)
break;
case svn_wc_notify_update_started:
- if (! (nb->suppress_summary_lines ||
- nb->in_external ||
+ if (! (nb->in_external ||
nb->is_checkout ||
nb->is_export))
{
@@ -596,77 +713,74 @@ notify(void *baton, const svn_wc_notify_t *n, apr_pool_t *pool)
case svn_wc_notify_update_completed:
{
- if (! nb->suppress_summary_lines)
+ if (SVN_IS_VALID_REVNUM(n->revision))
{
- if (SVN_IS_VALID_REVNUM(n->revision))
+ if (nb->is_export)
+ {
+ if ((err = svn_cmdline_printf
+ (pool, nb->in_external
+ ? _("Exported external at revision %ld.\n")
+ : _("Exported revision %ld.\n"),
+ n->revision)))
+ goto print_error;
+ }
+ else if (nb->is_checkout)
+ {
+ if ((err = svn_cmdline_printf
+ (pool, nb->in_external
+ ? _("Checked out external at revision %ld.\n")
+ : _("Checked out revision %ld.\n"),
+ n->revision)))
+ goto print_error;
+ }
+ else
{
- if (nb->is_export)
+ if (nb->received_some_change)
{
+ nb->received_some_change = FALSE;
if ((err = svn_cmdline_printf
(pool, nb->in_external
- ? _("Exported external at revision %ld.\n")
- : _("Exported revision %ld.\n"),
+ ? _("Updated external to revision %ld.\n")
+ : _("Updated to revision %ld.\n"),
n->revision)))
goto print_error;
}
- else if (nb->is_checkout)
+ else
{
if ((err = svn_cmdline_printf
(pool, nb->in_external
- ? _("Checked out external at revision %ld.\n")
- : _("Checked out revision %ld.\n"),
+ ? _("External at revision %ld.\n")
+ : _("At revision %ld.\n"),
n->revision)))
goto print_error;
}
- else
- {
- if (nb->received_some_change)
- {
- nb->received_some_change = FALSE;
- if ((err = svn_cmdline_printf
- (pool, nb->in_external
- ? _("Updated external to revision %ld.\n")
- : _("Updated to revision %ld.\n"),
- n->revision)))
- goto print_error;
- }
- else
- {
- if ((err = svn_cmdline_printf
- (pool, nb->in_external
- ? _("External at revision %ld.\n")
- : _("At revision %ld.\n"),
- n->revision)))
- goto print_error;
- }
- }
}
- else /* no revision */
+ }
+ else /* no revision */
+ {
+ if (nb->is_export)
{
- if (nb->is_export)
- {
- if ((err = svn_cmdline_printf
- (pool, nb->in_external
- ? _("External export complete.\n")
- : _("Export complete.\n"))))
- goto print_error;
- }
- else if (nb->is_checkout)
- {
- if ((err = svn_cmdline_printf
- (pool, nb->in_external
- ? _("External checkout complete.\n")
- : _("Checkout complete.\n"))))
- goto print_error;
- }
- else
- {
- if ((err = svn_cmdline_printf
- (pool, nb->in_external
- ? _("External update complete.\n")
- : _("Update complete.\n"))))
- goto print_error;
- }
+ if ((err = svn_cmdline_printf
+ (pool, nb->in_external
+ ? _("External export complete.\n")
+ : _("Export complete.\n"))))
+ goto print_error;
+ }
+ else if (nb->is_checkout)
+ {
+ if ((err = svn_cmdline_printf
+ (pool, nb->in_external
+ ? _("External checkout complete.\n")
+ : _("Checkout complete.\n"))))
+ goto print_error;
+ }
+ else
+ {
+ if ((err = svn_cmdline_printf
+ (pool, nb->in_external
+ ? _("External update complete.\n")
+ : _("Update complete.\n"))))
+ goto print_error;
}
}
}
@@ -898,7 +1012,7 @@ notify(void *baton, const svn_wc_notify_t *n, apr_pool_t *pool)
break;
case svn_wc_notify_tree_conflict:
- nb->tree_conflicts++;
+ store_path(nb, nb->conflict_stats->tree_conflicts, path_local);
if ((err = svn_cmdline_printf(pool, " C %s\n", path_local)))
goto print_error;
break;
@@ -923,50 +1037,50 @@ notify(void *baton, const svn_wc_notify_t *n, apr_pool_t *pool)
case svn_wc_notify_property_modified:
case svn_wc_notify_property_added:
- err = svn_cmdline_printf(pool,
- _("property '%s' set on '%s'\n"),
- n->prop_name, path_local);
- if (err)
- goto print_error;
+ err = svn_cmdline_printf(pool,
+ _("property '%s' set on '%s'\n"),
+ n->prop_name, path_local);
+ if (err)
+ goto print_error;
break;
case svn_wc_notify_property_deleted:
- err = svn_cmdline_printf(pool,
- _("property '%s' deleted from '%s'.\n"),
- n->prop_name, path_local);
- if (err)
- goto print_error;
+ err = svn_cmdline_printf(pool,
+ _("property '%s' deleted from '%s'.\n"),
+ n->prop_name, path_local);
+ if (err)
+ goto print_error;
break;
case svn_wc_notify_property_deleted_nonexistent:
- err = svn_cmdline_printf(pool,
- _("Attempting to delete nonexistent "
- "property '%s' on '%s'\n"), n->prop_name,
- path_local);
- if (err)
- goto print_error;
+ err = svn_cmdline_printf(pool,
+ _("Attempting to delete nonexistent "
+ "property '%s' on '%s'\n"), n->prop_name,
+ path_local);
+ if (err)
+ goto print_error;
break;
case svn_wc_notify_revprop_set:
- err = svn_cmdline_printf(pool,
- _("property '%s' set on repository revision %ld\n"),
- n->prop_name, n->revision);
+ err = svn_cmdline_printf(pool,
+ _("property '%s' set on repository revision %ld\n"),
+ n->prop_name, n->revision);
if (err)
goto print_error;
break;
case svn_wc_notify_revprop_deleted:
- err = svn_cmdline_printf(pool,
+ err = svn_cmdline_printf(pool,
_("property '%s' deleted from repository revision %ld\n"),
n->prop_name, n->revision);
- if (err)
- goto print_error;
+ if (err)
+ goto print_error;
break;
case svn_wc_notify_upgraded_path:
- err = svn_cmdline_printf(pool, _("Upgraded '%s'\n"), path_local);
- if (err)
- goto print_error;
+ err = svn_cmdline_printf(pool, _("Upgraded '%s'\n"), path_local);
+ if (err)
+ goto print_error;
break;
case svn_wc_notify_url_redirect:
@@ -977,7 +1091,37 @@ notify(void *baton, const svn_wc_notify_t *n, apr_pool_t *pool)
break;
case svn_wc_notify_path_nonexistent:
- err = svn_cmdline_printf(pool, _("'%s' is not under version control"),
+ err = svn_cmdline_printf(pool, "%s\n",
+ apr_psprintf(pool, _("'%s' is not under version control"),
+ path_local));
+ if (err)
+ goto print_error;
+ break;
+
+ case svn_wc_notify_conflict_resolver_starting:
+ /* Once all operations invoke the interactive conflict resolution after
+ * they've completed, we can run svn_cl__notifier_print_conflict_stats()
+ * here. */
+ break;
+
+ case svn_wc_notify_conflict_resolver_done:
+ break;
+
+ case svn_wc_notify_foreign_copy_begin:
+ if (n->merge_range == NULL)
+ {
+ err = svn_cmdline_printf(
+ pool,
+ _("--- Copying from foreign repository URL '%s':\n"),
+ n->url);
+ if (err)
+ goto print_error;
+ }
+ break;
+
+ case svn_wc_notify_move_broken:
+ err = svn_cmdline_printf(pool,
+ _("Breaking move with source path '%s'\n"),
path_local);
if (err)
goto print_error;
@@ -1016,7 +1160,7 @@ notify(void *baton, const svn_wc_notify_t *n, apr_pool_t *pool)
svn_error_t *
svn_cl__get_notifier(svn_wc_notify_func2_t *notify_func_p,
void **notify_baton_p,
- svn_boolean_t suppress_summary_lines,
+ svn_cl__conflict_stats_t *conflict_stats,
apr_pool_t *pool)
{
struct notify_baton *nb = apr_pcalloc(pool, sizeof(*nb));
@@ -1026,13 +1170,9 @@ svn_cl__get_notifier(svn_wc_notify_func2_t *notify_func_p,
nb->is_checkout = FALSE;
nb->is_export = FALSE;
nb->is_wc_to_repos_copy = FALSE;
- nb->suppress_summary_lines = suppress_summary_lines;
nb->in_external = FALSE;
nb->had_print_error = FALSE;
- nb->text_conflicts = 0;
- nb->prop_conflicts = 0;
- nb->tree_conflicts = 0;
- nb->skipped_paths = 0;
+ nb->conflict_stats = conflict_stats;
SVN_ERR(svn_dirent_get_absolute(&nb->path_prefix, "", pool));
*notify_func_p = notify;
@@ -1080,4 +1220,3 @@ svn_cl__check_externals_failed_notify_wrapper(void *baton,
if (nwb->wrapped_func)
nwb->wrapped_func(nwb->wrapped_baton, n, pool);
}
-