Author: neels
Date: Tue Nov 27 22:29:23 2012
New Revision: 1414442
URL: http://svn.apache.org/viewvc?rev=1414442&view=rev
Log:
Change implementation of issue #4227: move the svn:externals duplication check
from svn_wc_parse_externals_description3() to svn_wc_canonicalize_svn_prop().
Thus, show duplication errors only during propset/propedit.
TODO: print warnings about duplicate targets during co/up/merge.
* subversion/include/svn_error_codes.h
(SVN_ERR_WC_DUPLICATE_EXTERNALS_TARGET): New error code.
* subversion/libsvn_wc/externals.c
(svn_wc_parse_externals_description3): Remove dup check.
(svn_wc__externals_find_target_dups): New function.
* subversion/libsvn_wc/wc.h
(svn_wc__externals_find_target_dups): Declare new function.
* subversion/libsvn_wc/props.c
(svn_wc_canonicalize_svn_prop):
Check against duplicate externals targets. Add missing "not" in comment.
Modified:
subversion/trunk/subversion/include/svn_error_codes.h
subversion/trunk/subversion/libsvn_wc/externals.c
subversion/trunk/subversion/libsvn_wc/props.c
subversion/trunk/subversion/libsvn_wc/wc.h
Modified: subversion/trunk/subversion/include/svn_error_codes.h
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/include/svn_error_codes.h?rev=1414442&r1=1414441&r2=1414442&view=diff
==============================================================================
--- subversion/trunk/subversion/include/svn_error_codes.h (original)
+++ subversion/trunk/subversion/include/svn_error_codes.h Tue Nov 27 22:29:23
2012
@@ -545,6 +545,11 @@ SVN_ERROR_START
SVN_ERR_WC_CATEGORY_START + 40,
"Mixed-revision working copy was found but not expected")
+ /** @since New in 1.8 */
+ SVN_ERRDEF(SVN_ERR_WC_DUPLICATE_EXTERNALS_TARGET,
+ SVN_ERR_WC_CATEGORY_START + 41,
+ "Duplicate targets in svn:externals property")
+
/* fs errors */
SVN_ERRDEF(SVN_ERR_FS_GENERAL,
Modified: subversion/trunk/subversion/libsvn_wc/externals.c
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/externals.c?rev=1414442&r1=1414441&r2=1414442&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/externals.c (original)
+++ subversion/trunk/subversion/libsvn_wc/externals.c Tue Nov 27 22:29:23 2012
@@ -164,10 +164,8 @@ svn_wc_parse_externals_description3(apr_
apr_pool_t *pool)
{
int i;
- unsigned int len;
apr_array_header_t *externals = NULL;
apr_array_header_t *lines = svn_cstring_split(desc, "\n\r", TRUE, pool);
- apr_hash_t *duplicate_check = apr_hash_make(pool);
const char *parent_directory_display = svn_path_is_url(parent_directory) ?
parent_directory : svn_dirent_local_style(parent_directory, pool);
@@ -332,21 +330,6 @@ svn_wc_parse_externals_description3(apr_
item->url = svn_dirent_canonicalize(item->url, pool);
}
- /* Has the same WC target path already been mentioned in this prop? */
- len = apr_hash_count(duplicate_check);
- apr_hash_set(duplicate_check, item->target_dir, APR_HASH_KEY_STRING, "");
- if (len == apr_hash_count(duplicate_check))
- {
- /* Hashtable length is unchanged. This must be a duplicate. */
- return svn_error_createf
- (SVN_ERR_CLIENT_INVALID_EXTERNALS_DESCRIPTION, NULL,
- _("Invalid %s property on '%s': "
- "target '%s' appears more than once"),
- SVN_PROP_EXTERNALS,
- parent_directory_display,
- item->target_dir);
- }
-
if (externals)
APR_ARRAY_PUSH(externals, svn_wc_external_item2_t *) = item;
}
@@ -357,6 +340,53 @@ svn_wc_parse_externals_description3(apr_
return SVN_NO_ERROR;
}
+svn_error_t *
+svn_wc__externals_find_target_dups(apr_array_header_t **duplicate_targets,
+ apr_array_header_t *externals,
+ apr_pool_t *pool,
+ apr_pool_t *scratch_pool)
+{
+ int i;
+ unsigned int len;
+ unsigned int len2;
+ const char *target;
+ apr_hash_t *targets = apr_hash_make(scratch_pool);
+ apr_hash_t *targets2 = NULL;
+ *duplicate_targets = NULL;
+
+ for (i = 0; i < externals->nelts; i++)
+ {
+ target = APR_ARRAY_IDX(externals, i,
+ svn_wc_external_item2_t*)->target_dir;
+ len = apr_hash_count(targets);
+ apr_hash_set(targets, target, APR_HASH_KEY_STRING, "");
+ if (len == apr_hash_count(targets))
+ {
+ /* Hashtable length is unchanged. This must be a duplicate. */
+
+ /* Collapse multiple duplicates of the same target by using a second
+ * hash layer. */
+ if (! targets2)
+ targets2 = apr_hash_make(scratch_pool);
+ len2 = apr_hash_count(targets2);
+ apr_hash_set(targets2, target, APR_HASH_KEY_STRING, "");
+ if (len2 < apr_hash_count(targets2))
+ {
+ /* The second hash list just got bigger, i.e. this target has
+ * not been counted as duplicate before. */
+ if (! *duplicate_targets)
+ {
+ *duplicate_targets = apr_array_make(
+ pool, 1, sizeof(svn_wc_external_item2_t*));
+ }
+ APR_ARRAY_PUSH((*duplicate_targets), const char *) = target;
+ }
+ /* Else, this same target has already been recorded as a duplicate,
+ * don't count it again. */
+ }
+ }
+ return SVN_NO_ERROR;
+}
struct edit_baton
{
Modified: subversion/trunk/subversion/libsvn_wc/props.c
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/props.c?rev=1414442&r1=1414441&r2=1414442&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/props.c (original)
+++ subversion/trunk/subversion/libsvn_wc/props.c Tue Nov 27 22:29:23 2012
@@ -2168,9 +2168,34 @@ svn_wc_canonicalize_svn_prop(const svn_s
an svn:externals line. As it happens, our parse code
checks for this, so all we have to is invoke it --
we're not interested in the parsed result, only in
- whether or the parsing errored. */
- SVN_ERR(svn_wc_parse_externals_description3
- (NULL, path, propval->data, FALSE, pool));
+ whether or not the parsing errored. */
+ apr_array_header_t *externals = NULL;
+ apr_array_header_t *duplicate_targets = NULL;
+ SVN_ERR(svn_wc_parse_externals_description3(&externals, path,
+ propval->data, FALSE,
+ /*scratch_*/pool));
+ SVN_ERR(svn_wc__externals_find_target_dups(&duplicate_targets,
+ externals,
+ /*scratch_*/pool,
+ /*scratch_*/pool));
+ if (duplicate_targets && duplicate_targets->nelts > 0)
+ {
+ const char *more_str = "";
+ if (duplicate_targets->nelts > 1)
+ {
+ more_str = apr_psprintf(/*scratch_*/pool,
+ _(" (%d more duplicate targets found)"),
+ duplicate_targets->nelts - 1);
+ }
+ return svn_error_createf(
+ SVN_ERR_WC_DUPLICATE_EXTERNALS_TARGET, NULL,
+ _("Invalid %s property on '%s': "
+ "target '%s' appears more than once%s"),
+ SVN_PROP_EXTERNALS,
+ svn_dirent_local_style(path, pool),
+ APR_ARRAY_IDX(duplicate_targets, 0, const char*),
+ more_str);
+ }
}
}
else if (strcmp(propname, SVN_PROP_KEYWORDS) == 0)
Modified: subversion/trunk/subversion/libsvn_wc/wc.h
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/wc.h?rev=1414442&r1=1414441&r2=1414442&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/wc.h (original)
+++ subversion/trunk/subversion/libsvn_wc/wc.h Tue Nov 27 22:29:23 2012
@@ -755,6 +755,16 @@ svn_wc__fetch_base_func(const char **fil
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
+/* Find duplicate targets in *EXTERNALS, a list of svn_wc_external_item2_t*
+ * elements, and store each target string in *DUPLICATE_TARGETS as const
+ * char * elements. *DUPLICATE_TARGETS will be NULL if no duplicates were
+ * found. */
+svn_error_t *
+svn_wc__externals_find_target_dups(apr_array_header_t **duplicate_targets,
+ apr_array_header_t *externals,
+ apr_pool_t *pool,
+ apr_pool_t *scratch_pool);
+
#ifdef __cplusplus
}
#endif /* __cplusplus */