You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by cm...@apache.org on 2012/11/27 23:13:38 UTC
svn commit: r1414433 [3/4] - in /subversion/branches/issue-4194-dev: ./
build/ac-macros/ subversion/include/ subversion/include/private/
subversion/libsvn_client/ subversion/libsvn_delta/ subversion/libsvn_diff/
subversion/libsvn_fs_fs/ subversion/libs...
Modified: subversion/branches/issue-4194-dev/subversion/libsvn_wc/wc_db.c
URL: http://svn.apache.org/viewvc/subversion/branches/issue-4194-dev/subversion/libsvn_wc/wc_db.c?rev=1414433&r1=1414432&r2=1414433&view=diff
==============================================================================
--- subversion/branches/issue-4194-dev/subversion/libsvn_wc/wc_db.c (original)
+++ subversion/branches/issue-4194-dev/subversion/libsvn_wc/wc_db.c Tue Nov 27 22:13:24 2012
@@ -32,6 +32,7 @@
#include "svn_dirent_uri.h"
#include "svn_path.h"
#include "svn_hash.h"
+#include "svn_sorts.h"
#include "svn_wc.h"
#include "svn_checksum.h"
#include "svn_pools.h"
@@ -381,7 +382,18 @@ wclock_owns_lock(svn_boolean_t *own_lock
svn_boolean_t exact,
apr_pool_t *scratch_pool);
+/* Baton for db_is_switched */
+struct db_is_switched_baton_t
+{
+ svn_boolean_t *is_switched;
+ svn_kind_t *kind;
+};
+static svn_error_t *
+db_is_switched(void *baton,
+ svn_wc__db_wcroot_t *wcroot,
+ const char *local_relpath,
+ apr_pool_t *scratch_pool);
/* Return the absolute path, in local path style, of LOCAL_RELPATH
in WCROOT. */
@@ -1778,6 +1790,7 @@ svn_wc__db_base_add_file(svn_wc__db_t *d
svn_boolean_t delete_working,
svn_boolean_t update_actual_props,
apr_hash_t *new_actual_props,
+ apr_array_header_t *new_iprops,
svn_boolean_t keep_recorded_info,
svn_boolean_t insert_base_deleted,
const svn_skel_t *conflict,
@@ -1821,6 +1834,7 @@ svn_wc__db_base_add_file(svn_wc__db_t *d
ibb.checksum = checksum;
ibb.dav_cache = dav_cache;
+ ibb.iprops = new_iprops;
if (update_actual_props)
{
@@ -1863,6 +1877,7 @@ svn_wc__db_base_add_symlink(svn_wc__db_t
svn_boolean_t delete_working,
svn_boolean_t update_actual_props,
apr_hash_t *new_actual_props,
+ apr_array_header_t *new_iprops,
svn_boolean_t keep_recorded_info,
svn_boolean_t insert_base_deleted,
const svn_skel_t *conflict,
@@ -1905,6 +1920,7 @@ svn_wc__db_base_add_symlink(svn_wc__db_t
ibb.target = target;
ibb.dav_cache = dav_cache;
+ ibb.iprops = new_iprops;
if (update_actual_props)
{
@@ -7663,7 +7679,7 @@ read_info(svn_wc__db_status_t *status,
if (op_depth != 0)
*lock = NULL;
else
- *lock = lock_from_columns(stmt_info, 16, 17, 18, 19, result_pool);
+ *lock = lock_from_columns(stmt_info, 17, 18, 19, 20, result_pool);
}
if (have_work)
@@ -9014,6 +9030,45 @@ svn_wc__db_prop_retrieve_recursive(apr_h
return svn_error_trace(svn_sqlite__reset(stmt));
}
+/* Baton for db_read_cached_iprops */
+struct read_cached_iprops_baton_t
+{
+ apr_array_header_t *iprops;
+ apr_pool_t *result_pool;
+};
+
+/* Implements svn_wc__db_txn_callback_t for svn_wc__db_read_cached_iprops */
+static svn_error_t *
+db_read_cached_iprops(void *baton,
+ svn_wc__db_wcroot_t *wcroot,
+ const char *local_relpath,
+ apr_pool_t *scratch_pool)
+{
+ struct read_cached_iprops_baton_t *rib = baton;
+ svn_sqlite__stmt_t *stmt;
+ svn_boolean_t have_row;
+
+ SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_SELECT_IPROPS));
+ SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
+ SVN_ERR(svn_sqlite__step(&have_row, stmt));
+
+ if (!have_row)
+ {
+ return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND,
+ svn_sqlite__reset(stmt),
+ _("The node '%s' was not found."),
+ path_for_error_message(wcroot, local_relpath,
+ scratch_pool));
+ }
+
+ SVN_ERR(svn_sqlite__column_iprops(&rib->iprops, stmt, 0,
+ rib->result_pool, scratch_pool));
+
+ SVN_ERR(svn_sqlite__reset(stmt));
+
+ return SVN_NO_ERROR;
+}
+
svn_error_t *
svn_wc__db_read_cached_iprops(apr_array_header_t **iprops,
svn_wc__db_t *db,
@@ -9023,91 +9078,269 @@ svn_wc__db_read_cached_iprops(apr_array_
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
- svn_sqlite__stmt_t *stmt;
- svn_boolean_t have_row;
- const char *repos_root_url;
- svn_revnum_t revision;
- int op_depth;
- const char *repos_relpath;
+ struct read_cached_iprops_baton_t rcib;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
- SVN_ERR(svn_wc__db_read_info(NULL, NULL,
- &revision, &repos_relpath, &repos_root_url,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, db, local_abspath, result_pool,
- scratch_pool));
+ SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath,
+ db, local_abspath,
+ scratch_pool, scratch_pool));
+ VERIFY_USABLE_WCROOT(wcroot);
+
+ rcib.result_pool = result_pool;
- if (repos_relpath && repos_relpath[0] == '\0')
+ /* Don't use with_txn yet, as we perform just a single transaction */
+ SVN_ERR(db_read_cached_iprops(&rcib, wcroot, local_relpath, scratch_pool));
+
+ if (rcib.iprops)
+ *iprops = rcib.iprops;
+ else
{
- /* LOCAL_ABSPATH reflects the root of the repository, so there is
- no parents to inherit from. */
*iprops = apr_array_make(result_pool, 0,
sizeof(svn_prop_inherited_item_t *));
}
- else
+
+ return SVN_NO_ERROR;
+}
+
+/* Remove all prop name value pairs from PROP_HASH where the property
+ name is not PROPNAME. */
+static void
+filter_unwanted_props(apr_hash_t *prop_hash,
+ const char * propname,
+ apr_pool_t *scratch_pool)
+{
+ apr_hash_index_t *hi;
+
+ for (hi = apr_hash_first(scratch_pool, prop_hash);
+ hi;
+ hi = apr_hash_next(hi))
{
- SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath,
- db, local_abspath,
- scratch_pool,
- scratch_pool));
- VERIFY_USABLE_WCROOT(wcroot);
- SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
- STMT_SELECT_IPROPS));
- SVN_ERR(op_depth_of(&op_depth, wcroot, local_relpath));
- SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
- SVN_ERR(svn_sqlite__step(&have_row, stmt));
+ const char *ipropname = svn__apr_hash_index_key(hi);
- if (!have_row)
+ if (strcmp(ipropname, propname) != 0)
+ apr_hash_set(prop_hash, ipropname, APR_HASH_KEY_STRING, NULL);
+ }
+ return;
+}
+
+/* Baton for db_read_inherited_props */
+struct read_inherited_props_baton_t
+{
+ apr_array_header_t *iprops;
+ const char *propname;
+ apr_pool_t *result_pool;
+};
+
+/* Implements svn_wc__db_txn_callback_t for svn_wc__db_read_inherited_props */
+static svn_error_t *
+db_read_inherited_props(void *baton,
+ svn_wc__db_wcroot_t *wcroot,
+ const char *local_relpath,
+ apr_pool_t *scratch_pool)
+{
+ struct read_inherited_props_baton_t *ripb = baton;
+ int i;
+ apr_array_header_t *cached_iprops = NULL;
+ const char *parent_relpath = local_relpath;
+ svn_boolean_t is_wc_root = FALSE;
+ apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+ apr_pool_t *result_pool = ripb->result_pool;
+
+ ripb->iprops = apr_array_make(ripb->result_pool, 1,
+ sizeof(svn_prop_inherited_item_t *));
+
+ /* Walk up to the root of the WC looking for inherited properties. When we
+ reach the WC root also check for cached inherited properties. */
+ while (TRUE)
+ {
+ apr_hash_t *actual_props;
+ svn_boolean_t is_switched;
+ struct db_is_switched_baton_t swb;
+
+ svn_pool_clear(iterpool);
+
+ swb.is_switched = &is_switched;
+ swb.kind = NULL;
+
+ if (*parent_relpath == '\0')
{
- /* No cached iprops. */
- *iprops = NULL;
+ is_switched = FALSE;
+ is_wc_root = TRUE;
}
else
+ SVN_ERR(db_is_switched(&swb, wcroot, parent_relpath, scratch_pool));
+
+ if (is_switched || is_wc_root)
{
- SVN_ERR(svn_sqlite__column_iprops(iprops, stmt, 0, result_pool,
- scratch_pool));
- }
+ struct read_cached_iprops_baton_t rib;
+ is_wc_root = TRUE;
- SVN_ERR(svn_sqlite__reset(stmt));
+ rib.result_pool = scratch_pool;
+
+ /* If the WC root is also the root of the repository then by
+ definition there are no inheritable properties to be had,
+ but checking for that is just as expensive as fetching them
+ anyway. */
+
+ /* Grab the cached inherited properties for the WC root. */
+ SVN_ERR(db_read_cached_iprops(&rib, wcroot, parent_relpath,
+ iterpool));
+
+ cached_iprops = rib.iprops;
+ }
+
+ /* If PARENT_ABSPATH is a true parent of LOCAL_ABSPATH, then
+ LOCAL_ABSPATH can inherit properties from it. */
+ if (strcmp(local_relpath, parent_relpath) != 0)
+ {
+ struct db_read_props_baton_t rpb;
+ rpb.result_pool = result_pool;
+
+ SVN_ERR(db_read_props(&rpb, wcroot, parent_relpath, iterpool));
+
+ actual_props = rpb.props;
+
+ if (actual_props)
+ {
+ /* If we only want PROPNAME filter out any other properties. */
+ if (ripb->propname)
+ filter_unwanted_props(actual_props, ripb->propname, iterpool);
+
+ if (apr_hash_count(actual_props))
+ {
+ svn_prop_inherited_item_t *iprop_elt =
+ apr_pcalloc(ripb->result_pool,
+ sizeof(svn_prop_inherited_item_t));
+ iprop_elt->path_or_url = svn_dirent_join(wcroot->abspath,
+ parent_relpath,
+ result_pool);
+
+ iprop_elt->prop_hash = actual_props;
+ /* Build the output array in depth-first order. */
+ svn_sort__array_insert(&iprop_elt, ripb->iprops, 0);
+ }
+ }
+ }
+
+ /* Inheritance only goes as far as the nearest WC root. */
+ if (is_wc_root)
+ break;
+
+ /* Keep looking for the WC root. */
+ parent_relpath = svn_relpath_dirname(parent_relpath, scratch_pool);
+ }
+
+ if (cached_iprops)
+ {
+ for (i = cached_iprops->nelts - 1; i >= 0; i--)
+ {
+ svn_prop_inherited_item_t *cached_iprop =
+ APR_ARRAY_IDX(cached_iprops, i, svn_prop_inherited_item_t *);
+
+ /* An empty property hash in the iprops cache means there are no
+ inherited properties. */
+ if (apr_hash_count(cached_iprop->prop_hash) == 0)
+ continue;
+
+ if (ripb->propname)
+ filter_unwanted_props(cached_iprop->prop_hash, ripb->propname,
+ scratch_pool);
+
+ /* If we didn't filter everything then keep this iprop. */
+ if (apr_hash_count(cached_iprop->prop_hash))
+ svn_sort__array_insert(&cached_iprop, ripb->iprops, 0);
+ }
}
+ svn_pool_destroy(iterpool);
return SVN_NO_ERROR;
}
-/* Recursive body of svn_wc__db_get_children_with_cached_iprops. */
-static svn_error_t *
-get_children_with_cached_iprops(apr_hash_t *iprop_paths,
- svn_depth_t depth,
- const char *local_abspath,
+svn_error_t *
+svn_wc__db_read_inherited_props(apr_array_header_t **iprops,
svn_wc__db_t *db,
+ const char *local_abspath,
+ const char *propname,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
- svn_sqlite__stmt_t *stmt;
- svn_boolean_t have_row;
+ struct read_inherited_props_baton_t ripb;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
- SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
- local_abspath, scratch_pool,
- scratch_pool));
+ SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath,
+ db, local_abspath,
+ scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
- if (depth == svn_depth_empty
- || depth == svn_depth_files
- || depth == svn_depth_immediates)
+
+ ripb.iprops = NULL;
+ ripb.propname = propname;
+ ripb.result_pool = result_pool;
+
+ SVN_ERR(svn_wc__db_with_txn(wcroot, local_relpath, db_read_inherited_props,
+ &ripb, scratch_pool));
+
+ *iprops = ripb.iprops;
+ return SVN_NO_ERROR;
+}
+
+/* Baton for get_children_with_cached_iprops */
+struct get_children_with_cached_baton_t
+{
+ svn_depth_t depth;
+ apr_hash_t *iprop_paths;
+ apr_pool_t *result_pool;
+};
+
+/* Implements svn_wc__db_txn_callback_t for
+ svn_wc__db_get_children_with_cached_iprops. */
+static svn_error_t *
+get_children_with_cached_iprops(void *baton,
+ svn_wc__db_wcroot_t *wcroot,
+ const char *local_relpath,
+ apr_pool_t *scratch_pool)
+{
+ struct get_children_with_cached_baton_t *cwcb = baton;
+ svn_sqlite__stmt_t *stmt;
+ svn_boolean_t have_row;
+ apr_hash_t *iprop_paths = cwcb->iprop_paths;
+ apr_pool_t *result_pool = cwcb->result_pool;
+
+ /* First check if LOCAL_RELPATH itself has iprops */
+ SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+ STMT_SELECT_IPROPS_NODE));
+ SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
+ SVN_ERR(svn_sqlite__step(&have_row, stmt));
+
+ if (have_row)
+ {
+ const char *relpath_with_cache = svn_sqlite__column_text(stmt, 0,
+ NULL);
+ const char *abspath_with_cache = svn_dirent_join(wcroot->abspath,
+ relpath_with_cache,
+ result_pool);
+ apr_hash_set(iprop_paths, abspath_with_cache, APR_HASH_KEY_STRING,
+ svn_sqlite__column_text(stmt, 1, result_pool));
+ }
+ SVN_ERR(svn_sqlite__reset(stmt));
+
+ if (cwcb->depth == svn_depth_empty)
+ return SVN_NO_ERROR;
+
+ /* Now fetch information for children or all descendants */
+ if (cwcb->depth == svn_depth_files
+ || cwcb->depth == svn_depth_immediates)
{
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
- STMT_SELECT_INODES));
+ STMT_SELECT_IPROPS_CHILDREN));
}
else /* Default to svn_depth_infinity. */
{
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
- STMT_SELECT_INODES_RECURSIVE));
+ STMT_SELECT_IPROPS_RECURSIVE));
}
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
@@ -9121,46 +9354,50 @@ get_children_with_cached_iprops(apr_hash
relpath_with_cache,
result_pool);
apr_hash_set(iprop_paths, abspath_with_cache, APR_HASH_KEY_STRING,
- abspath_with_cache);
+ svn_sqlite__column_text(stmt, 1, result_pool));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
}
SVN_ERR(svn_sqlite__reset(stmt));
- if (depth == svn_depth_files || depth == svn_depth_immediates)
+ /* For depth files we should filter non files */
+ if (cwcb->depth == svn_depth_files)
{
- const apr_array_header_t *rel_children;
- int i;
+ apr_hash_index_t *hi;
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
- SVN_ERR(svn_wc__db_read_children_of_working_node(&rel_children,
- db, local_abspath,
- scratch_pool,
- scratch_pool));
- for (i = 0; i < rel_children->nelts; i++)
+ for (hi = apr_hash_first(scratch_pool, iprop_paths);
+ hi;
+ hi = apr_hash_next(hi))
{
- const char *child_abspath;
+ const char *child_abspath = svn__apr_hash_index_key(hi);
+ const char *child_relpath;
+ svn_kind_t child_kind;
svn_pool_clear(iterpool);
- child_abspath = svn_dirent_join(
- local_abspath, APR_ARRAY_IDX(rel_children, i, const char *),
- iterpool);
- if (depth == svn_depth_files)
- {
- svn_kind_t child_kind;
+ child_relpath = svn_dirent_is_child(local_relpath, child_abspath,
+ NULL);
- SVN_ERR(svn_wc__db_read_kind(&child_kind, db, child_abspath,
- FALSE, FALSE, iterpool));
- if (child_kind != svn_kind_file)
- continue;
+ if (! child_relpath)
+ {
+ continue; /* local_relpath itself */
}
- SVN_ERR(get_children_with_cached_iprops(iprop_paths,
- svn_depth_empty,
- child_abspath, db,
- result_pool,
- iterpool));
+ SVN_ERR(svn_wc__db_base_get_info_internal(NULL, &child_kind, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL,
+ wcroot, child_relpath,
+ scratch_pool,
+ scratch_pool));
+
+ /* Filter if not a file */
+ if (child_kind != svn_kind_file)
+ {
+ apr_hash_set(iprop_paths, child_abspath, APR_HASH_KEY_STRING,
+ NULL);
+ }
}
svn_pool_destroy(iterpool);
@@ -9177,10 +9414,26 @@ svn_wc__db_get_children_with_cached_ipro
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
- *iprop_paths = apr_hash_make(result_pool);
- SVN_ERR(get_children_with_cached_iprops(*iprop_paths, depth,
- local_abspath, db, result_pool,
- scratch_pool));
+ svn_wc__db_wcroot_t *wcroot;
+ const char *local_relpath;
+ struct get_children_with_cached_baton_t cwcb;
+
+ SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
+
+ SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
+ local_abspath, scratch_pool,
+ scratch_pool));
+ VERIFY_USABLE_WCROOT(wcroot);
+
+ cwcb.iprop_paths = apr_hash_make(result_pool);
+ cwcb.depth = depth;
+ cwcb.result_pool = result_pool;
+
+ SVN_ERR(svn_wc__db_with_txn(wcroot, local_relpath,
+ get_children_with_cached_iprops, &cwcb,
+ scratch_pool));
+
+ *iprop_paths = cwcb.iprop_paths;
return SVN_NO_ERROR;
}
@@ -9686,6 +9939,7 @@ commit_node(void *baton,
svn_sqlite__stmt_t *stmt_act;
svn_boolean_t have_act;
svn_string_t prop_blob = { 0 };
+ svn_string_t inherited_prop_blob = { 0 };
const char *changelist = NULL;
const char *parent_relpath;
svn_wc__db_status_t new_presence;
@@ -9755,6 +10009,10 @@ commit_node(void *baton,
prop_blob.data = svn_sqlite__column_blob(stmt_info, 14, &prop_blob.len,
scratch_pool);
+ inherited_prop_blob.data = svn_sqlite__column_blob(stmt_info, 16,
+ &inherited_prop_blob.len,
+ scratch_pool);
+
if (cb->keep_changelist && have_act)
changelist = svn_sqlite__column_text(stmt_act, 0, scratch_pool);
@@ -9841,6 +10099,11 @@ commit_node(void *baton,
scratch_pool));
SVN_ERR(svn_sqlite__bind_properties(stmt, 15, cb->new_dav_cache,
scratch_pool));
+ if (inherited_prop_blob.data != NULL)
+ {
+ SVN_ERR(svn_sqlite__bind_blob(stmt, 17, inherited_prop_blob.data,
+ inherited_prop_blob.len));
+ }
SVN_ERR(svn_sqlite__step_done(stmt));
@@ -12475,6 +12738,118 @@ svn_wc__db_is_wcroot(svn_boolean_t *is_r
return SVN_NO_ERROR;
}
+/* This implements svn_wc__db_txn_callback_t for svn_wc_db__is_switched */
+static svn_error_t *
+db_is_switched(void *baton,
+ svn_wc__db_wcroot_t *wcroot,
+ const char *local_relpath,
+ apr_pool_t *scratch_pool)
+{
+ struct db_is_switched_baton_t *isb = baton;
+ svn_wc__db_status_t status;
+ apr_int64_t repos_id;
+ const char *repos_relpath;
+ const char *name;
+ const char *parent_local_relpath;
+ apr_int64_t parent_repos_id;
+ const char *parent_repos_relpath;
+
+ SVN_ERR_ASSERT(*local_relpath != '\0'); /* Handled in wrapper */
+
+ SVN_ERR(read_info(&status, isb->kind, NULL, &repos_relpath, &repos_id, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ wcroot, local_relpath, scratch_pool, scratch_pool));
+
+ if (status == svn_wc__db_status_server_excluded
+ || status == svn_wc__db_status_excluded
+ || status == svn_wc__db_status_not_present)
+ {
+ return svn_error_createf(
+ SVN_ERR_WC_PATH_NOT_FOUND, NULL,
+ _("The node '%s' was not found."),
+ path_for_error_message(wcroot, local_relpath,
+ scratch_pool));
+ }
+ else if (! repos_relpath)
+ {
+ /* Node is shadowed; easy out */
+ if (isb->is_switched)
+ *isb->is_switched = FALSE;
+
+ return SVN_NO_ERROR;
+ }
+
+ if (! isb->is_switched)
+ return SVN_NO_ERROR;
+
+ svn_relpath_split(&parent_local_relpath, &name, local_relpath, scratch_pool);
+
+ SVN_ERR(svn_wc__db_base_get_info_internal(NULL, NULL, NULL,
+ &parent_repos_relpath,
+ &parent_repos_id, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ wcroot, parent_local_relpath,
+ scratch_pool, scratch_pool));
+
+ if (repos_id != parent_repos_id)
+ *isb->is_switched = TRUE;
+ else
+ {
+ const char *expected_relpath;
+
+ expected_relpath = svn_relpath_join(parent_repos_relpath, name,
+ scratch_pool);
+
+ *isb->is_switched = (strcmp(expected_relpath, repos_relpath) != 0);
+ }
+
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_wc__db_is_switched(svn_boolean_t *is_wcroot,
+ svn_boolean_t *is_switched,
+ svn_kind_t *kind,
+ svn_wc__db_t *db,
+ const char *local_abspath,
+ apr_pool_t *scratch_pool)
+{
+ svn_wc__db_wcroot_t *wcroot;
+ const char *local_relpath;
+ struct db_is_switched_baton_t isb;
+
+ SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
+
+ SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
+ local_abspath, scratch_pool, scratch_pool));
+ VERIFY_USABLE_WCROOT(wcroot);
+
+ if (is_switched)
+ *is_switched = FALSE;
+
+ if (*local_relpath == '\0')
+ {
+ /* Easy out */
+ if (is_wcroot)
+ *is_wcroot = TRUE;
+
+ if (kind)
+ *kind = svn_kind_dir;
+ return SVN_NO_ERROR;
+ }
+
+ if (is_wcroot)
+ *is_wcroot = FALSE;
+
+ isb.is_switched = is_switched;
+ isb.kind = kind;
+
+ return svn_error_trace(svn_wc__db_with_txn(wcroot, local_relpath,
+ db_is_switched, &isb,
+ scratch_pool));
+}
+
svn_error_t *
svn_wc__db_temp_wcroot_tempdir(const char **temp_dir_abspath,
Modified: subversion/branches/issue-4194-dev/subversion/libsvn_wc/wc_db.h
URL: http://svn.apache.org/viewvc/subversion/branches/issue-4194-dev/subversion/libsvn_wc/wc_db.h?rev=1414433&r1=1414432&r2=1414433&view=diff
==============================================================================
--- subversion/branches/issue-4194-dev/subversion/libsvn_wc/wc_db.h (original)
+++ subversion/branches/issue-4194-dev/subversion/libsvn_wc/wc_db.h Tue Nov 27 22:13:24 2012
@@ -512,6 +512,7 @@ svn_wc__db_base_add_file(svn_wc__db_t *d
svn_boolean_t delete_working,
svn_boolean_t update_actual_props,
apr_hash_t *new_actual_props,
+ apr_array_header_t *new_iprops,
svn_boolean_t keep_recorded_info,
svn_boolean_t insert_base_deleted,
const svn_skel_t *conflict,
@@ -594,6 +595,7 @@ svn_wc__db_base_add_symlink(svn_wc__db_t
svn_boolean_t delete_working,
svn_boolean_t update_actual_props,
apr_hash_t *new_actual_props,
+ apr_array_header_t *new_iprops,
svn_boolean_t keep_recorded_info,
svn_boolean_t insert_base_deleted,
const svn_skel_t *conflict,
@@ -2092,6 +2094,26 @@ svn_wc__db_read_pristine_props(apr_hash_
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
+
+/**
+ * Set @a *inherited_props to a depth-first ordered array of
+ * #svn_prop_inherited_item_t * structures representing the properties
+ * inherited by @a local_abspath from the ACTUAL tree above
+ * @a local_abspath (looking through to the WORKING or BASE tree as
+ * required), up to and including the root of the working copy and
+ * any cached inherited properties inherited by the root.
+ *
+ * Allocate @a *inherited_props in @a result_pool. Use @a scratch_pool
+ * for temporary allocations.
+ */
+svn_error_t *
+svn_wc__db_read_inherited_props(apr_array_header_t **iprops,
+ svn_wc__db_t *db,
+ const char *local_abspath,
+ const char *propname,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool);
+
/* Read a BASE node's inherited property information.
Set *IPROPS to to a depth-first ordered array of
@@ -2114,9 +2136,11 @@ svn_wc__db_read_cached_iprops(apr_array_
/* Find BASE nodes with cached inherited properties.
Set *IPROPS_PATHS to a hash mapping const char * absolute working copy
- paths to the same for each path in the working copy at or below
- LOCAL_ABSPATH, limited by DEPTH, that has cached inherited properties
- for the BASE node of the path. Allocate *IPROP_PATHS in RESULT_POOL.
+ paths to the repos_relpath of the path for each path in the working copy
+ at or below LOCAL_ABSPATH, limited by DEPTH, that has cached inherited
+ properties for the BASE node of the path.
+
+ Allocate *IPROP_PATHS in RESULT_POOL.
Use SCRATCH_POOL for temporary allocations. */
svn_error_t *
svn_wc__db_get_children_with_cached_iprops(apr_hash_t **iprop_paths,
@@ -2288,6 +2312,21 @@ svn_wc__db_is_wcroot(svn_boolean_t *is_r
const char *local_abspath,
apr_pool_t *scratch_pool);
+/* Checks if LOCAL_ABSPATH is a working copy root, switched and a directory.
+ With these answers we can answer all 'is anchor' questions that we need for
+ the different ra operations with just a single sqlite transaction and
+ filestat.
+
+ All output arguments can be null to specify that the result is not
+ interesting to the caller
+ */
+svn_error_t *
+svn_wc__db_is_switched(svn_boolean_t *is_wcroot,
+ svn_boolean_t *is_switched,
+ svn_kind_t *kind,
+ svn_wc__db_t *db,
+ const char *local_abspath,
+ apr_pool_t *scratch_pool);
/* @} */
Modified: subversion/branches/issue-4194-dev/subversion/mod_dav_svn/reports/update.c
URL: http://svn.apache.org/viewvc/subversion/branches/issue-4194-dev/subversion/mod_dav_svn/reports/update.c?rev=1414433&r1=1414432&r2=1414433&view=diff
==============================================================================
--- subversion/branches/issue-4194-dev/subversion/mod_dav_svn/reports/update.c (original)
+++ subversion/branches/issue-4194-dev/subversion/mod_dav_svn/reports/update.c Tue Nov 27 22:13:24 2012
@@ -618,12 +618,8 @@ send_propchange(item_baton_t *b,
{
const char *qname;
- /* Ensure that the property name is XML-safe.
- apr_xml_quote_string() doesn't realloc if there is nothing to
- quote, so dup the name, but only if necessary. */
- qname = apr_xml_quote_string(b->pool, name, 1);
- if (qname == name)
- qname = apr_pstrdup(b->pool, name);
+ /* Ensure that the property name is XML-safe. */
+ qname = apr_xml_quote_string(pool, name, 1);
if (value)
{
Modified: subversion/branches/issue-4194-dev/subversion/svn/cl.h
URL: http://svn.apache.org/viewvc/subversion/branches/issue-4194-dev/subversion/svn/cl.h?rev=1414433&r1=1414432&r2=1414433&view=diff
==============================================================================
--- subversion/branches/issue-4194-dev/subversion/svn/cl.h (original)
+++ subversion/branches/issue-4194-dev/subversion/svn/cl.h Tue Nov 27 22:13:24 2012
@@ -767,6 +767,22 @@ const char *
svn_cl__operation_str_human_readable(svn_wc_operation_t operation,
apr_pool_t *pool);
+/* If PROPNAME looks like but is not identical to one of the svn:
+ * poperties, raise an error and suggest a better spelling. Names that
+ * raise errors look like this:
+ *
+ * - start with svn: but do not exactly match a known property; or,
+ * - start with a 3-letter prefix that differs in only one letter
+ * from "svn:", and the rest exactly matches a known propery.
+ *
+ * If REVPROP is TRUE, only check revision property names; otherwise
+ * only check node property names.
+ *
+ * Use SCRATCH_POOL for temporary allocations.
+ */
+svn_error_t *
+svn_cl__check_svn_prop_name(const char *propname, svn_boolean_t revprop,
+ apr_pool_t *scratch_pool);
/* If PROPNAME is one of the svn: properties with a boolean value, and
* PROPVAL looks like an attempt to turn the property off (i.e., it's
Modified: subversion/branches/issue-4194-dev/subversion/svn/list-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/issue-4194-dev/subversion/svn/list-cmd.c?rev=1414433&r1=1414432&r2=1414433&view=diff
==============================================================================
--- subversion/branches/issue-4194-dev/subversion/svn/list-cmd.c (original)
+++ subversion/branches/issue-4194-dev/subversion/svn/list-cmd.c Tue Nov 27 22:13:24 2012
@@ -42,9 +42,14 @@
struct print_baton {
svn_boolean_t verbose;
svn_client_ctx_t *ctx;
+
+ /* To keep track of last seen external information. */
+ const char *last_external_parent_url;
+ const char *last_external_target;
+ svn_boolean_t in_external;
};
-/* This implements the svn_client_list_func_t API, printing a single
+/* This implements the svn_client_list_func2_t API, printing a single
directory entry in text format. */
static svn_error_t *
print_dirent(void *baton,
@@ -52,6 +57,8 @@ print_dirent(void *baton,
const svn_dirent_t *dirent,
const svn_lock_t *lock,
const char *abs_path,
+ const char *external_parent_url,
+ const char *external_target,
apr_pool_t *pool)
{
struct print_baton *pb = baton;
@@ -59,6 +66,9 @@ print_dirent(void *baton,
static const char *time_format_long = NULL;
static const char *time_format_short = NULL;
+ SVN_ERR_ASSERT((external_parent_url == NULL && external_target == NULL) ||
+ (external_parent_url && external_target));
+
if (time_format_long == NULL)
time_format_long = _("%b %d %H:%M");
if (time_format_short == NULL)
@@ -79,6 +89,24 @@ print_dirent(void *baton,
}
else
entryname = path;
+
+ if (external_parent_url && external_target)
+ {
+ if ((pb->last_external_parent_url == NULL
+ && pb->last_external_target == NULL)
+ || (strcmp(pb->last_external_parent_url, external_parent_url) != 0
+ || strcmp(pb->last_external_target, external_target) != 0))
+ {
+ SVN_ERR(svn_cmdline_printf(pool,
+ _("Listing external '%s'"
+ " defined on '%s':\n"),
+ external_target,
+ external_parent_url));
+
+ pb->last_external_parent_url = external_parent_url;
+ pb->last_external_target = external_target;
+ }
+ }
if (pb->verbose)
{
@@ -133,7 +161,7 @@ print_dirent(void *baton,
}
-/* This implements the svn_client_list_func_t API, printing a single dirent
+/* This implements the svn_client_list_func2_t API, printing a single dirent
in XML format. */
static svn_error_t *
print_dirent_xml(void *baton,
@@ -141,18 +169,21 @@ print_dirent_xml(void *baton,
const svn_dirent_t *dirent,
const svn_lock_t *lock,
const char *abs_path,
+ const char *external_parent_url,
+ const char *external_target,
apr_pool_t *pool)
{
struct print_baton *pb = baton;
const char *entryname;
- svn_stringbuf_t *sb;
+ svn_stringbuf_t *sb = svn_stringbuf_create_empty(pool);
+
+ SVN_ERR_ASSERT((external_parent_url == NULL && external_target == NULL) ||
+ (external_parent_url && external_target));
if (strcmp(path, "") == 0)
{
if (dirent->kind == svn_node_file)
entryname = svn_dirent_basename(abs_path, pool);
- else if (pb->verbose)
- entryname = ".";
else
/* Don't bother to list if no useful information will be shown. */
return SVN_NO_ERROR;
@@ -162,8 +193,32 @@ print_dirent_xml(void *baton,
if (pb->ctx->cancel_func)
SVN_ERR(pb->ctx->cancel_func(pb->ctx->cancel_baton));
+
+ if (external_parent_url && external_target)
+ {
+ if ((pb->last_external_parent_url == NULL
+ && pb->last_external_target == NULL)
+ || (strcmp(pb->last_external_parent_url, external_parent_url) != 0
+ || strcmp(pb->last_external_target, external_target) != 0))
+ {
+ if (pb->in_external)
+ {
+ /* The external item being listed is different from the previous
+ one, so close the tag. */
+ svn_xml_make_close_tag(&sb, pool, "external");
+ pb->in_external = FALSE;
+ }
+
+ svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "external",
+ "parent_url", external_parent_url,
+ "target", external_target,
+ NULL);
- sb = svn_stringbuf_create_empty(pool);
+ pb->last_external_parent_url = external_parent_url;
+ pb->last_external_target = external_target;
+ pb->in_external = TRUE;
+ }
+ }
svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "entry",
"kind", svn_cl__node_kind_str_xml(dirent->kind),
@@ -225,6 +280,8 @@ svn_cl__list(apr_getopt_t *os,
struct print_baton pb;
svn_boolean_t seen_nonexistent_target = FALSE;
svn_error_t *err;
+ svn_error_t *externals_err = SVN_NO_ERROR;
+ struct svn_cl__check_externals_failed_notify_baton nwb;
SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os,
opt_state->targets,
@@ -266,12 +323,27 @@ svn_cl__list(apr_getopt_t *os,
if (opt_state->depth == svn_depth_unknown)
opt_state->depth = svn_depth_immediates;
+ if (opt_state->include_externals)
+ {
+ nwb.wrapped_func = ctx->notify_func2;
+ nwb.wrapped_baton = ctx->notify_baton2;
+ nwb.had_externals_error = FALSE;
+ ctx->notify_func2 = svn_cl__check_externals_failed_notify_wrapper;
+ ctx->notify_baton2 = &nwb;
+ }
+
/* For each target, try to list it. */
for (i = 0; i < targets->nelts; i++)
{
const char *target = APR_ARRAY_IDX(targets, i, const char *);
const char *truepath;
svn_opt_revision_t peg_revision;
+
+ /* Initialize the following variables for
+ every list target. */
+ pb.last_external_parent_url = NULL;
+ pb.last_external_target = NULL;
+ pb.in_external = FALSE;
svn_pool_clear(subpool);
@@ -290,11 +362,12 @@ svn_cl__list(apr_getopt_t *os,
SVN_ERR(svn_cl__error_checked_fputs(sb->data, stdout));
}
- err = svn_client_list2(truepath, &peg_revision,
+ err = svn_client_list3(truepath, &peg_revision,
&(opt_state->start_revision),
opt_state->depth,
dirent_fields,
(opt_state->xml || opt_state->verbose),
+ opt_state->include_externals,
opt_state->xml ? print_dirent_xml : print_dirent,
&pb, ctx, subpool);
@@ -316,20 +389,38 @@ svn_cl__list(apr_getopt_t *os,
if (opt_state->xml)
{
svn_stringbuf_t *sb = svn_stringbuf_create_empty(pool);
+
+ if (pb.in_external)
+ {
+ /* close the final external item's tag */
+ svn_xml_make_close_tag(&sb, pool, "external");
+ pb.in_external = FALSE;
+ }
+
svn_xml_make_close_tag(&sb, pool, "list");
SVN_ERR(svn_cl__error_checked_fputs(sb->data, stdout));
}
}
svn_pool_destroy(subpool);
+
+ if (opt_state->include_externals && nwb.had_externals_error)
+ {
+ externals_err = svn_error_create(SVN_ERR_CL_ERROR_PROCESSING_EXTERNALS,
+ NULL,
+ _("Failure occurred processing one or "
+ "more externals definitions"));
+ }
if (opt_state->xml && ! opt_state->incremental)
SVN_ERR(svn_cl__xml_print_footer("lists", pool));
if (seen_nonexistent_target)
- return svn_error_create(
- SVN_ERR_ILLEGAL_TARGET, NULL,
- _("Could not list all targets because some targets don't exist"));
+ {
+ err = svn_error_create(SVN_ERR_ILLEGAL_TARGET, NULL,
+ _("Could not list all targets because some targets don't exist"));
+ return svn_error_compose_create(externals_err, err);
+ }
else
- return SVN_NO_ERROR;
+ return svn_error_compose_create(externals_err, err);
}
Modified: subversion/branches/issue-4194-dev/subversion/svn/main.c
URL: http://svn.apache.org/viewvc/subversion/branches/issue-4194-dev/subversion/svn/main.c?rev=1414433&r1=1414432&r2=1414433&view=diff
==============================================================================
--- subversion/branches/issue-4194-dev/subversion/svn/main.c (original)
+++ subversion/branches/issue-4194-dev/subversion/svn/main.c Tue Nov 27 22:13:24 2012
@@ -131,7 +131,7 @@ typedef enum svn_cl__longopt_t {
opt_include_externals,
opt_show_inherited_props,
opt_search,
- opt_search_and,
+ opt_search_and
} svn_cl__longopt_t;
@@ -624,7 +624,9 @@ const svn_opt_subcommand_desc2_t svn_cl_
" If locked, the letter 'O'. (Use 'svn info URL' to see details)\n"
" Size (in bytes)\n"
" Date and time of the last commit\n"),
- {'r', 'v', 'R', opt_depth, opt_incremental, opt_xml} },
+ {'r', 'v', 'R', opt_depth, opt_incremental, opt_xml,
+ opt_include_externals },
+ {{opt_include_externals, N_("include externals definitions")}} },
{ "lock", svn_cl__lock, {0}, N_
("Lock working copy paths or URLs in the repository, so that\n"
Modified: subversion/branches/issue-4194-dev/subversion/svn/propedit-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/issue-4194-dev/subversion/svn/propedit-cmd.c?rev=1414433&r1=1414432&r2=1414433&view=diff
==============================================================================
--- subversion/branches/issue-4194-dev/subversion/svn/propedit-cmd.c (original)
+++ subversion/branches/issue-4194-dev/subversion/svn/propedit-cmd.c Tue Nov 27 22:13:24 2012
@@ -84,6 +84,9 @@ svn_cl__propedit(apr_getopt_t *os,
return svn_error_createf(SVN_ERR_CLIENT_PROPERTY_NAME, NULL,
_("'%s' is not a valid Subversion property name"),
pname_utf8);
+ if (!opt_state->force)
+ SVN_ERR(svn_cl__check_svn_prop_name(pname_utf8, opt_state->revprop, pool));
+
if (opt_state->encoding && !svn_prop_needs_translation(pname_utf8))
return svn_error_create
(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
Modified: subversion/branches/issue-4194-dev/subversion/svn/props.c
URL: http://svn.apache.org/viewvc/subversion/branches/issue-4194-dev/subversion/svn/props.c?rev=1414433&r1=1414432&r2=1414433&view=diff
==============================================================================
--- subversion/branches/issue-4194-dev/subversion/svn/props.c (original)
+++ subversion/branches/issue-4194-dev/subversion/svn/props.c Tue Nov 27 22:13:24 2012
@@ -27,6 +27,8 @@
/*** Includes. ***/
+#include <stdlib.h>
+
#include <apr_hash.h>
#include "svn_cmdline.h"
#include "svn_string.h"
@@ -40,10 +42,10 @@
#include "svn_base64.h"
#include "cl.h"
+#include "private/svn_string_private.h"
#include "private/svn_cmdline_private.h"
#include "svn_private_config.h"
-
svn_error_t *
@@ -223,3 +225,191 @@ svn_cl__check_boolean_prop_val(const cha
}
}
+
+/* Context for sorting property names */
+struct simprop_context_t
+{
+ svn_string_t name; /* The name of the property we're comparing with */
+ svn_membuf_t buffer; /* Buffer for similariry testing */
+};
+
+struct simprop_t
+{
+ const char *propname; /* The original svn: property name */
+ svn_string_t name; /* The property name without the svn: prefx */
+ unsigned int score; /* The similarity score */
+ apr_size_t diff; /* Number of chars different from context.name */
+ struct simprop_context_t *context; /* Sorting context for qsort() */
+};
+
+/* Similarity test between two property names */
+static APR_INLINE unsigned int
+simprop_key_diff(const svn_string_t *key, const svn_string_t *ctx,
+ svn_membuf_t *buffer, apr_size_t *diff)
+{
+ apr_size_t lcs;
+ const unsigned int score = svn_string__similarity(key, ctx, buffer, &lcs);
+ if (key->len > ctx->len)
+ *diff = key->len - lcs;
+ else
+ *diff = ctx->len - lcs;
+ return score;
+}
+
+/* Key comparator for qsort for simprop_t */
+static int
+simprop_compare(const void *pkeya, const void *pkeyb)
+{
+ struct simprop_t *const keya = *(struct simprop_t *const *)pkeya;
+ struct simprop_t *const keyb = *(struct simprop_t *const *)pkeyb;
+ struct simprop_context_t *const context = keya->context;
+
+ if (keya->score == -1)
+ keya->score = simprop_key_diff(&keya->name, &context->name,
+ &context->buffer, &keya->diff);
+ if (keyb->score == -1)
+ keyb->score = simprop_key_diff(&keyb->name, &context->name,
+ &context->buffer, &keyb->diff);
+
+ return (keya->score < keyb->score ? 1
+ : (keya->score > keyb->score ? -1
+ : (keya->diff > keyb->diff ? 1
+ : (keya->diff < keyb->diff ? -1 : 0))));
+}
+
+svn_error_t *
+svn_cl__check_svn_prop_name(const char *propname, svn_boolean_t revprop,
+ apr_pool_t *scratch_pool)
+{
+ static const char *const nodeprops[] =
+ {
+ SVN_PROP_NODE_ALL_PROPS
+ };
+ static const apr_size_t nodeprops_len = sizeof(nodeprops)/sizeof(*nodeprops);
+
+ static const char *const revprops[] =
+ {
+ SVN_PROP_REVISION_ALL_PROPS
+ };
+ static const apr_size_t revprops_len = sizeof(revprops)/sizeof(*revprops);
+
+ const char *const *const proplist = (revprop ? revprops : nodeprops);
+ const apr_size_t numprops = (revprop ? revprops_len : nodeprops_len);
+
+ struct simprop_t **propkeys;
+ struct simprop_t *propbuf;
+ apr_size_t i;
+
+ struct simprop_context_t context;
+ svn_string_t prefix;
+
+ context.name.data = propname;
+ context.name.len = strlen(propname);
+ prefix.data = SVN_PROP_PREFIX;
+ prefix.len = strlen(SVN_PROP_PREFIX);
+
+ svn_membuf__create(&context.buffer, 0, scratch_pool);
+
+ /* First, check if the name is even close to being in the svn: namespace.
+ It must contain a colon in the right place, and we only allow
+ one-char typos or a single transposition. */
+ if (context.name.len < prefix.len
+ || context.name.data[prefix.len - 1] != prefix.data[prefix.len - 1])
+ return SVN_NO_ERROR; /* Wrong prefix, ignore */
+ else
+ {
+ apr_size_t lcs;
+ const apr_size_t name_len = context.name.len;
+ context.name.len = prefix.len; /* Only check up to the prefix length */
+ svn_string__similarity(&context.name, &prefix, &context.buffer, &lcs);
+ context.name.len = name_len; /* Restore the original propname length */
+ if (lcs < prefix.len - 1)
+ return SVN_NO_ERROR; /* Wrong prefix, ignore */
+
+ /* If the prefix is slightly different, the rest must be
+ identical in order to trigger the error. */
+ if (lcs == prefix.len - 1)
+ {
+ for (i = 0; i < numprops; ++i)
+ {
+ if (0 == strcmp(proplist[i] + prefix.len, propname + prefix.len))
+ return svn_error_createf(
+ SVN_ERR_CLIENT_PROPERTY_NAME, NULL,
+ _("'%s' is not a valid %s property name; did you mean '%s'?"
+ "\n(To set the '%s' property, re-run with '--force'.)"),
+ propname, SVN_PROP_PREFIX, proplist[i], propname);
+ }
+ return SVN_NO_ERROR;
+ }
+ }
+
+ /* Now find the closest match from amongst a the set of reserved
+ node or revision property names. Skip the prefix while matching,
+ we already know that it's the same and looking at it would only
+ skew the results. */
+ propkeys = apr_palloc(scratch_pool,
+ numprops * sizeof(struct simprop_t*));
+ propbuf = apr_palloc(scratch_pool,
+ numprops * sizeof(struct simprop_t));
+ context.name.data += prefix.len;
+ context.name.len -= prefix.len;
+ for (i = 0; i < numprops; ++i)
+ {
+ propkeys[i] = &propbuf[i];
+ propbuf[i].propname = proplist[i];
+ propbuf[i].name.data = proplist[i] + prefix.len;
+ propbuf[i].name.len = strlen(propbuf[i].name.data);
+ propbuf[i].score = (unsigned int)-1;
+ propbuf[i].context = &context;
+ }
+
+ qsort(propkeys, numprops, sizeof(*propkeys), simprop_compare);
+
+ if (0 == propkeys[0]->diff)
+ return SVN_NO_ERROR; /* We found an exact match. */
+
+ /* See if we can suggest a sane alternative spelling */
+ for (i = 0; i < numprops; ++i)
+ if (propkeys[i]->score < 666) /* 2/3 similarity required */
+ break;
+
+ switch (i)
+ {
+ case 0:
+ /* The best alternative isn't good enough */
+ return svn_error_createf(
+ SVN_ERR_CLIENT_PROPERTY_NAME, NULL,
+ _("'%s' is not a valid %s property name;"
+ " re-run with '--force' to set it"),
+ propname, SVN_PROP_PREFIX);
+
+ case 1:
+ /* There is only one good candidate */
+ return svn_error_createf(
+ SVN_ERR_CLIENT_PROPERTY_NAME, NULL,
+ _("'%s' is not a valid %s property name; did you mean '%s'?\n"
+ "(To set the '%s' property, re-run with '--force'.)"),
+ propname, SVN_PROP_PREFIX, propkeys[0]->propname, propname);
+
+ case 2:
+ /* Suggest a list of the most likely candidates */
+ return svn_error_createf(
+ SVN_ERR_CLIENT_PROPERTY_NAME, NULL,
+ _("'%s' is not a valid %s property name\n"
+ "Did you mean '%s' or '%s'?\n"
+ "(To set the '%s' property, re-run with '--force'.)"),
+ propname, SVN_PROP_PREFIX,
+ propkeys[0]->propname, propkeys[1]->propname, propname);
+
+ default:
+ /* Never suggest more than three candidates */
+ return svn_error_createf(
+ SVN_ERR_CLIENT_PROPERTY_NAME, NULL,
+ _("'%s' is not a valid %s property name\n"
+ "Did you mean '%s', '%s' or '%s'?\n"
+ "(To set the '%s' property, re-run with '--force'.)"),
+ propname, SVN_PROP_PREFIX,
+ propkeys[0]->propname, propkeys[1]->propname, propkeys[2]->propname,
+ propname);
+ }
+}
Modified: subversion/branches/issue-4194-dev/subversion/svn/propset-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/issue-4194-dev/subversion/svn/propset-cmd.c?rev=1414433&r1=1414432&r2=1414433&view=diff
==============================================================================
--- subversion/branches/issue-4194-dev/subversion/svn/propset-cmd.c (original)
+++ subversion/branches/issue-4194-dev/subversion/svn/propset-cmd.c Tue Nov 27 22:13:24 2012
@@ -67,6 +67,9 @@ svn_cl__propset(apr_getopt_t *os,
return svn_error_createf(SVN_ERR_CLIENT_PROPERTY_NAME, NULL,
_("'%s' is not a valid Subversion property name"),
pname_utf8);
+ if (!opt_state->force)
+ SVN_ERR(svn_cl__check_svn_prop_name(pname_utf8, opt_state->revprop,
+ scratch_pool));
/* Get the PROPVAL from either an external file, or from the command
line. */
Modified: subversion/branches/issue-4194-dev/subversion/svnlook/main.c
URL: http://svn.apache.org/viewvc/subversion/branches/issue-4194-dev/subversion/svnlook/main.c?rev=1414433&r1=1414432&r2=1414433&view=diff
==============================================================================
--- subversion/branches/issue-4194-dev/subversion/svnlook/main.c (original)
+++ subversion/branches/issue-4194-dev/subversion/svnlook/main.c Tue Nov 27 22:13:24 2012
@@ -52,6 +52,7 @@
#include "svn_version.h"
#include "svn_xml.h"
+#include "private/svn_diff_private.h"
#include "private/svn_cmdline_private.h"
#include "private/svn_fspath.h"
@@ -95,7 +96,8 @@ enum
svnlook__copy_info,
svnlook__xml_opt,
svnlook__ignore_properties,
- svnlook__properties_only
+ svnlook__properties_only,
+ svnlook__diff_cmd
};
/*
@@ -127,6 +129,9 @@ static const apr_getopt_option_t options
{"no-diff-deleted", svnlook__no_diff_deleted, 0,
N_("do not print differences for deleted files")},
+ {"diff-cmd", svnlook__diff_cmd, 1,
+ N_("use ARG as diff command")},
+
{"ignore-properties", svnlook__ignore_properties, 0,
N_("ignore properties during the operation")},
@@ -158,37 +163,23 @@ static const apr_getopt_option_t options
N_("output in XML")},
{"extensions", 'x', 1,
- N_("Default: '-u'. When Subversion is invoking an\n"
- " "
- " external diff program, ARG is simply passed along\n"
- " "
- " to the program. But when Subversion is using its\n"
- " "
- " default internal diff implementation, or when\n"
- " "
- " Subversion is displaying blame annotations, ARG\n"
- " "
- " could be any of the following:\n"
- " "
- " -u (--unified):\n"
- " "
- " Output 3 lines of unified context.\n"
- " "
- " -b (--ignore-space-change):\n"
- " "
- " Ignore changes in the amount of white space.\n"
- " "
- " -w (--ignore-all-space):\n"
- " "
- " Ignore all white space.\n"
- " "
- " --ignore-eol-style:\n"
- " "
- " Ignore changes in EOL style\n"
- " "
- " -p (--show-c-function):\n"
- " "
- " Show C function name in diff output.")},
+ N_("Specify differencing options for external diff or\n"
+ " "
+ "internal diff. Default: '-u'. Options are\n"
+ " "
+ "separated by spaces. Internal diff takes:\n"
+ " "
+ " -u, --unified: Show 3 lines of unified context\n"
+ " "
+ " -b, --ignore-space-change: Ignore changes in\n"
+ " "
+ " amount of white space\n"
+ " "
+ " -w, --ignore-all-space: Ignore all white space\n"
+ " "
+ " --ignore-eol-style: Ignore changes in EOL style\n"
+ " "
+ " -p, --show-c-function: Show C function name")},
{"quiet", 'q', 0,
N_("no progress (only errors) to stderr")},
@@ -226,8 +217,8 @@ static const svn_opt_subcommand_desc2_t
N_("usage: svnlook diff REPOS_PATH\n\n"
"Print GNU-style diffs of changed files and properties.\n"),
{'r', 't', svnlook__no_diff_deleted, svnlook__no_diff_added,
- svnlook__diff_copy_from, 'x', svnlook__ignore_properties,
- svnlook__properties_only} },
+ svnlook__diff_copy_from, svnlook__diff_cmd, 'x',
+ svnlook__ignore_properties, svnlook__properties_only} },
{"dirs-changed", subcommand_dirschanged, {0},
N_("usage: svnlook dirs-changed REPOS_PATH\n\n"
@@ -331,6 +322,7 @@ struct svnlook_opt_state
svn_boolean_t quiet; /* --quiet */
svn_boolean_t ignore_properties; /* --ignore_properties */
svn_boolean_t properties_only; /* --properties-only */
+ const char *diff_cmd; /* --diff-cmd */
};
@@ -352,6 +344,7 @@ typedef struct svnlook_ctxt_t
const apr_array_header_t *diff_options;
svn_boolean_t ignore_properties;
svn_boolean_t properties_only;
+ const char *diff_cmd;
} svnlook_ctxt_t;
@@ -791,66 +784,16 @@ generate_label(const char **label,
return SVN_NO_ERROR;
}
-/* A helper function used by display_prop_diffs.
- TOKEN is a string holding a property value.
- If TOKEN is empty, or is already terminated by an EOL marker,
- return TOKEN unmodified. Else, return a new string consisting
- of the concatenation of TOKEN and the system's default EOL marker.
- The new string is allocated from POOL.
- If HAD_EOL is not NULL, indicate in *HAD_EOL if the token had a EOL. */
-static const svn_string_t *
-maybe_append_eol(const svn_string_t *token, svn_boolean_t *had_eol,
- apr_pool_t *pool)
-{
- const char *curp;
-
- if (had_eol)
- *had_eol = FALSE;
-
- if (token->len == 0)
- return token;
-
- curp = token->data + token->len - 1;
- if (*curp == '\r')
- {
- if (had_eol)
- *had_eol = TRUE;
- return token;
- }
- else if (*curp != '\n')
- {
- return svn_string_createf(pool, "%s%s", token->data, APR_EOL_STR);
- }
- else
- {
- if (had_eol)
- *had_eol = TRUE;
- return token;
- }
-}
-
-/*
- * Constant diff output separator strings
- */
-static const char equal_string[] =
- "===================================================================";
-static const char under_string[] =
- "___________________________________________________________________";
-
/* Helper function to display differences in properties of a file */
static svn_error_t *
-display_prop_diffs(const apr_array_header_t *propchanges,
+display_prop_diffs(svn_stream_t *outstream,
+ const char *encoding,
+ const apr_array_header_t *propchanges,
apr_hash_t *original_props,
const char *path,
apr_pool_t *pool)
{
- const char *encoding = svn_cmdline_output_encoding(pool);
- svn_stream_t *outstream;
- apr_pool_t *iterpool;
- int i;
-
- SVN_ERR(svn_stream_for_stdout(&outstream, pool));
SVN_ERR(svn_stream_printf_from_utf8(outstream, encoding, pool,
_("%sProperty changes on: %s%s"),
@@ -859,90 +802,24 @@ display_prop_diffs(const apr_array_heade
APR_EOL_STR));
SVN_ERR(svn_stream_printf_from_utf8(outstream, encoding, pool,
- "%s" APR_EOL_STR, under_string));
-
- iterpool = svn_pool_create(pool);
- for (i = 0; i < propchanges->nelts; i++)
- {
- const char *action;
- const svn_string_t *original_value;
- const svn_prop_t *propchange
- = &APR_ARRAY_IDX(propchanges, i, svn_prop_t);
-
- SVN_ERR(check_cancel(NULL));
+ SVN_DIFF__UNDER_STRING APR_EOL_STR));
- if (original_props)
- original_value = apr_hash_get(original_props,
- propchange->name, APR_HASH_KEY_STRING);
- else
- original_value = NULL;
-
- svn_pool_clear(iterpool);
+ SVN_ERR(check_cancel(NULL));
- if (! original_value)
- action = "Added";
- else if (! propchange->value)
- action = "Deleted";
- else
- action = "Modified";
- SVN_ERR(svn_stream_printf_from_utf8(outstream, encoding, iterpool,
- "%s: %s%s", action,
- propchange->name, APR_EOL_STR));
-
- {
- svn_diff_t *diff;
- svn_diff_file_options_t options;
- const svn_string_t *tmp;
- const svn_string_t *orig;
- const svn_string_t *val;
- svn_boolean_t val_has_eol;
-
- /* The last character in a property is often not a newline.
- An eol character is appended to prevent the diff API to add a
- '\ No newline at end of file' line. We add
- '\ No newline at end of property' manually if needed. */
- tmp = original_value ? original_value
- : svn_string_create_empty(iterpool);
- orig = maybe_append_eol(tmp, NULL, iterpool);
-
- tmp = propchange->value ? propchange->value :
- svn_string_create_empty(iterpool);
- val = maybe_append_eol(tmp, &val_has_eol, iterpool);
-
- SVN_ERR(svn_diff_mem_string_diff(&diff, orig, val, &options,
- iterpool));
-
- /* UNIX patch will try to apply a diff even if the diff header
- * is missing. It tries to be helpful by asking the user for a
- * target filename when it can't determine the target filename
- * from the diff header. But there usually are no files which
- * UNIX patch could apply the property diff to, so we use "##"
- * instead of "@@" as the default hunk delimiter for property diffs.
- * We also supress the diff header. */
- SVN_ERR(svn_diff_mem_string_output_unified2(
- outstream, diff, FALSE, "##",
- svn_dirent_local_style(path, iterpool),
- svn_dirent_local_style(path, iterpool),
- encoding, orig, val, iterpool));
- if (!val_has_eol)
- {
- const char *s = "\\ No newline at end of property" APR_EOL_STR;
- SVN_ERR(svn_stream_puts(outstream, s));
- }
- }
- }
- svn_pool_destroy(iterpool);
+ SVN_ERR(svn_diff__display_prop_diffs(
+ outstream, encoding, propchanges, original_props,
+ FALSE /* pretty_print_mergeinfo */, pool));
- SVN_ERR(svn_stream_close(outstream));
- return svn_cmdline_fflush(stdout);
+ return SVN_NO_ERROR;
}
-
/* Recursively print all nodes in the tree that have been modified
(do not include directories affected only by "bubble-up"). */
static svn_error_t *
-print_diff_tree(svn_fs_root_t *root,
+print_diff_tree(svn_stream_t *out_stream,
+ const char *encoding,
+ svn_fs_root_t *root,
svn_fs_root_t *base_root,
svn_repos_node_t *node,
const char *path /* UTF-8! */,
@@ -1063,59 +940,46 @@ print_diff_tree(svn_fs_root_t *root,
if (do_diff && (! c->properties_only))
{
- svn_stringbuf_appendcstr(header, equal_string);
- svn_stringbuf_appendcstr(header, "\n");
+ svn_stringbuf_appendcstr(header, SVN_DIFF__EQUAL_STRING "\n");
if (binary)
{
svn_stringbuf_appendcstr(header, _("(Binary files differ)\n\n"));
- SVN_ERR(svn_cmdline_printf(pool, "%s", header->data));
+ SVN_ERR(svn_stream_printf_from_utf8(out_stream, encoding, pool,
+ "%s", header->data));
}
else
{
- svn_diff_t *diff;
- svn_diff_file_options_t *opts = svn_diff_file_options_create(pool);
-
- if (c->diff_options)
- SVN_ERR(svn_diff_file_options_parse(opts, c->diff_options, pool));
-
- SVN_ERR(svn_diff_file_diff_2(&diff, orig_path,
- new_path, opts, pool));
-
- if (svn_diff_contains_diffs(diff))
+ if (c->diff_cmd)
{
- svn_stream_t *ostream;
- const char *orig_label, *new_label;
+ apr_file_t *outfile;
+ apr_file_t *errfile;
+ const char *outfilename;
+ const char *errfilename;
+ svn_stream_t *stream;
+ svn_stream_t *err_stream;
+ const char **diff_cmd_argv;
+ int diff_cmd_argc;
+ int exitcode;
+ const char *orig_label;
+ const char *new_label;
+
+ diff_cmd_argv = NULL;
+ diff_cmd_argc = c->diff_options->nelts;
+ if (diff_cmd_argc)
+ {
+ int i;
+ diff_cmd_argv = apr_palloc(pool,
+ diff_cmd_argc * sizeof(char *));
+ for (i = 0; i < diff_cmd_argc; i++)
+ SVN_ERR(svn_utf_cstring_to_utf8(&diff_cmd_argv[i],
+ APR_ARRAY_IDX(c->diff_options, i, const char *),
+ pool));
+ }
/* Print diff header. */
- SVN_ERR(svn_cmdline_printf(pool, "%s", header->data));
-
- /* This fflush() might seem odd, but it was added to deal
- with this bug report:
-
- http://subversion.tigris.org/servlets/ReadMsg?\
- list=dev&msgNo=140782
-
- From: "Steve Hay" <SteveHay{_AT_}planit.com>
- To: <de...@subversion.tigris.org>
- Subject: svnlook diff output in wrong order when redirected
- Date: Fri, 4 Jul 2008 16:34:15 +0100
- Message-ID: <1B32FF956ABF414C9BCE5E487A1497E702014F62@\
- ukmail02.planit.group>
-
- Adding the fflush() fixed the bug (not everyone could
- reproduce it, but those who could confirmed the fix).
- Later in the thread, Daniel Shahaf speculated as to
- why the fix works:
-
- "Because svn_cmdline_printf() uses the standard
- 'FILE *stdout' to write to stdout, while
- svn_stream_for_stdout() uses (through
- apr_file_open_stdout()) Windows API's to get a
- handle for stdout?" */
- SVN_ERR(svn_cmdline_fflush(stdout));
-
- SVN_ERR(svn_stream_for_stdout(&ostream, pool));
+ SVN_ERR(svn_stream_printf_from_utf8(out_stream, encoding, pool,
+ "%s", header->data));
if (orig_empty)
SVN_ERR(generate_label(&orig_label, NULL, path, pool));
@@ -1123,26 +987,89 @@ print_diff_tree(svn_fs_root_t *root,
SVN_ERR(generate_label(&orig_label, base_root,
base_path, pool));
SVN_ERR(generate_label(&new_label, root, path, pool));
- SVN_ERR(svn_diff_file_output_unified3
- (ostream, diff, orig_path, new_path,
- orig_label, new_label,
- svn_cmdline_output_encoding(pool), NULL,
- opts->show_c_function, pool));
- SVN_ERR(svn_stream_close(ostream));
- SVN_ERR(svn_cmdline_printf(pool, "\n"));
+
+ /* We deal in streams, but svn_io_run_diff2() deals in file
+ handles, unfortunately, so we need to make these temporary
+ files, and then copy the contents to our stream. */
+ SVN_ERR(svn_io_open_unique_file3(&outfile, &outfilename, NULL,
+ svn_io_file_del_on_pool_cleanup, pool, pool));
+ SVN_ERR(svn_io_open_unique_file3(&errfile, &errfilename, NULL,
+ svn_io_file_del_on_pool_cleanup, pool, pool));
+
+ SVN_ERR(svn_io_run_diff2(".",
+ diff_cmd_argv,
+ diff_cmd_argc,
+ orig_label, new_label,
+ orig_path, new_path,
+ &exitcode, outfile, errfile,
+ c->diff_cmd, pool));
+
+ SVN_ERR(svn_io_file_close(outfile, pool));
+ SVN_ERR(svn_io_file_close(errfile, pool));
+
+ /* Now, open and copy our files to our output streams. */
+ SVN_ERR(svn_stream_for_stderr(&err_stream, pool));
+ SVN_ERR(svn_stream_open_readonly(&stream, outfilename,
+ pool, pool));
+ SVN_ERR(svn_stream_copy3(stream,
+ svn_stream_disown(out_stream, pool),
+ NULL, NULL, pool));
+ SVN_ERR(svn_stream_open_readonly(&stream, errfilename,
+ pool, pool));
+ SVN_ERR(svn_stream_copy3(stream,
+ svn_stream_disown(err_stream, pool),
+ NULL, NULL, pool));
+
+ SVN_ERR(svn_stream_printf_from_utf8(out_stream, encoding, pool,
+ "\n"));
diff_header_printed = TRUE;
}
- else if (! node->prop_mod &&
- ((! c->no_diff_added && node->action == 'A') ||
- (! c->no_diff_deleted && node->action == 'D')))
+ else
{
- /* There was an empty file added or deleted in this revision.
- * We can't print a diff, but we can at least print
- * a diff header since we know what happened to this file. */
- SVN_ERR(svn_cmdline_printf(pool, "%s", header->data));
+ svn_diff_t *diff;
+ svn_diff_file_options_t *opts = svn_diff_file_options_create(pool);
+
+ if (c->diff_options)
+ SVN_ERR(svn_diff_file_options_parse(opts, c->diff_options, pool));
+
+ SVN_ERR(svn_diff_file_diff_2(&diff, orig_path,
+ new_path, opts, pool));
+
+ if (svn_diff_contains_diffs(diff))
+ {
+ const char *orig_label, *new_label;
+
+ /* Print diff header. */
+ SVN_ERR(svn_stream_printf_from_utf8(out_stream, encoding, pool,
+ "%s", header->data));
+
+ if (orig_empty)
+ SVN_ERR(generate_label(&orig_label, NULL, path, pool));
+ else
+ SVN_ERR(generate_label(&orig_label, base_root,
+ base_path, pool));
+ SVN_ERR(generate_label(&new_label, root, path, pool));
+ SVN_ERR(svn_diff_file_output_unified3
+ (out_stream, diff, orig_path, new_path,
+ orig_label, new_label,
+ svn_cmdline_output_encoding(pool), NULL,
+ opts->show_c_function, pool));
+ SVN_ERR(svn_stream_printf_from_utf8(out_stream, encoding, pool,
+ "\n"));
+ diff_header_printed = TRUE;
+ }
+ else if (! node->prop_mod &&
+ ((! c->no_diff_added && node->action == 'A') ||
+ (! c->no_diff_deleted && node->action == 'D')))
+ {
+ /* There was an empty file added or deleted in this revision.
+ * We can't print a diff, but we can at least print
+ * a diff header since we know what happened to this file. */
+ SVN_ERR(svn_stream_printf_from_utf8(out_stream, encoding, pool,
+ "%s", header->data));
+ }
}
}
- SVN_ERR(svn_cmdline_fflush(stdout));
}
/* Make sure we delete any temporary files. */
@@ -1182,12 +1109,17 @@ print_diff_tree(svn_fs_root_t *root,
pool));
SVN_ERR(generate_label(&new_label, root, path, pool));
- SVN_ERR(svn_cmdline_printf(pool, "Index: %s\n", path));
- SVN_ERR(svn_cmdline_printf(pool, "%s\n", equal_string));
- SVN_ERR(svn_cmdline_printf(pool, "--- %s\n", orig_label));
- SVN_ERR(svn_cmdline_printf(pool, "+++ %s\n", new_label));
+ SVN_ERR(svn_stream_printf_from_utf8(out_stream, encoding, pool,
+ "Index: %s\n", path));
+ SVN_ERR(svn_stream_printf_from_utf8(out_stream, encoding, pool,
+ SVN_DIFF__EQUAL_STRING "\n"));
+ /* --- <label1>
+ * +++ <label2> */
+ SVN_ERR(svn_diff__unidiff_write_header(
+ out_stream, encoding, orig_label, new_label, pool));
}
- SVN_ERR(display_prop_diffs(props, base_proptable, path, pool));
+ SVN_ERR(display_prop_diffs(out_stream, encoding,
+ props, base_proptable, path, pool));
}
}
@@ -1198,7 +1130,7 @@ print_diff_tree(svn_fs_root_t *root,
/* Recursively handle the node's children. */
subpool = svn_pool_create(pool);
- SVN_ERR(print_diff_tree(root, base_root, node,
+ SVN_ERR(print_diff_tree(out_stream, encoding, root, base_root, node,
svn_dirent_join(path, node->name, subpool),
svn_dirent_join(base_path, node->name, subpool),
c, tmpdir, subpool));
@@ -1206,7 +1138,7 @@ print_diff_tree(svn_fs_root_t *root,
{
svn_pool_clear(subpool);
node = node->sibling;
- SVN_ERR(print_diff_tree(root, base_root, node,
+ SVN_ERR(print_diff_tree(out_stream, encoding, root, base_root, node,
svn_dirent_join(path, node->name, subpool),
svn_dirent_join(base_path, node->name, subpool),
c, tmpdir, subpool));
@@ -1569,12 +1501,40 @@ do_diff(svnlook_ctxt_t *c, apr_pool_t *p
if (tree)
{
const char *tmpdir;
+ svn_stream_t *out_stream;
+ const char *encoding = svn_cmdline_output_encoding(pool);
SVN_ERR(svn_fs_revision_root(&base_root, c->fs, base_rev_id, pool));
SVN_ERR(svn_io_temp_dir(&tmpdir, pool));
- SVN_ERR(print_diff_tree(root, base_root, tree, "", "",
- c, tmpdir, pool));
+ /* This fflush() might seem odd, but it was added to deal
+ with this bug report:
+
+ http://subversion.tigris.org/servlets/ReadMsg?\
+ list=dev&msgNo=140782
+
+ From: "Steve Hay" <SteveHay{_AT_}planit.com>
+ To: <de...@subversion.tigris.org>
+ Subject: svnlook diff output in wrong order when redirected
+ Date: Fri, 4 Jul 2008 16:34:15 +0100
+ Message-ID: <1B32FF956ABF414C9BCE5E487A1497E702014F62@\
+ ukmail02.planit.group>
+
+ Adding the fflush() fixed the bug (not everyone could
+ reproduce it, but those who could confirmed the fix).
+ Later in the thread, Daniel Shahaf speculated as to
+ why the fix works:
+
+ "Because svn_cmdline_printf() uses the standard
+ 'FILE *stdout' to write to stdout, while
+ svn_stream_for_stdout() uses (through
+ apr_file_open_stdout()) Windows API's to get a
+ handle for stdout?" */
+ SVN_ERR(svn_cmdline_fflush(stdout));
+ SVN_ERR(svn_stream_for_stdout(&out_stream, pool));
+
+ SVN_ERR(print_diff_tree(out_stream, encoding, root, base_root, tree,
+ "", "", c, tmpdir, pool));
}
return SVN_NO_ERROR;
}
@@ -1945,6 +1905,7 @@ get_ctxt_baton(svnlook_ctxt_t **baton_p,
" \t\n\r", TRUE, pool);
baton->ignore_properties = opt_state->ignore_properties;
baton->properties_only = opt_state->properties_only;
+ baton->diff_cmd = opt_state->diff_cmd;
if (baton->txn_name)
SVN_ERR(svn_fs_open_txn(&(baton->txn), baton->fs,
@@ -2454,6 +2415,10 @@ main(int argc, const char *argv[])
opt_state.properties_only = TRUE;
break;
+ case svnlook__diff_cmd:
+ opt_state.diff_cmd = opt_arg;
+ break;
+
default:
SVN_INT_ERR(subcommand_help(NULL, NULL, pool));
svn_pool_destroy(pool);
Modified: subversion/branches/issue-4194-dev/subversion/svnmucc/svnmucc.c
URL: http://svn.apache.org/viewvc/subversion/branches/issue-4194-dev/subversion/svnmucc/svnmucc.c?rev=1414433&r1=1414432&r2=1414433&view=diff
==============================================================================
--- subversion/branches/issue-4194-dev/subversion/svnmucc/svnmucc.c (original)
+++ subversion/branches/issue-4194-dev/subversion/svnmucc/svnmucc.c Tue Nov 27 22:13:24 2012
@@ -926,7 +926,7 @@ usage(apr_pool_t *pool, int exit_val)
" -X, --extra-args ARG append arguments from file ARG (one per line;\n"
" use \"-\" to read from standard input)\n"
" --config-dir ARG use ARG to override the config directory\n"
- " --config-option ARG use ARG so override a configuration option\n"
+ " --config-option ARG use ARG to override a configuration option\n"
" --no-auth-cache do not cache authentication tokens\n"
" --version print version information\n";
svn_error_clear(svn_cmdline_fputs(msg, stream, pool));
Modified: subversion/branches/issue-4194-dev/subversion/svnrdump/svnrdump.c
URL: http://svn.apache.org/viewvc/subversion/branches/issue-4194-dev/subversion/svnrdump/svnrdump.c?rev=1414433&r1=1414432&r2=1414433&view=diff
==============================================================================
--- subversion/branches/issue-4194-dev/subversion/svnrdump/svnrdump.c (original)
+++ subversion/branches/issue-4194-dev/subversion/svnrdump/svnrdump.c Tue Nov 27 22:13:24 2012
@@ -39,6 +39,7 @@
#include "svnrdump.h"
#include "private/svn_cmdline_private.h"
+#include "private/svn_ra_private.h"
@@ -248,6 +249,81 @@ replay_revend(svn_revnum_t revision,
return SVN_NO_ERROR;
}
+#ifdef USE_EV2_IMPL
+/* Print dumpstream-formatted information about REVISION.
+ * Implements the `svn_ra_replay_revstart_callback_t' interface.
+ */
+static svn_error_t *
+replay_revstart_v2(svn_revnum_t revision,
+ void *replay_baton,
+ svn_editor_t **editor,
+ apr_hash_t *rev_props,
+ apr_pool_t *pool)
+{
+ struct replay_baton *rb = replay_baton;
+ apr_hash_t *normal_props;
+ svn_stringbuf_t *propstring;
+ svn_stream_t *stdout_stream;
+ svn_stream_t *revprop_stream;
+
+ SVN_ERR(svn_stream_for_stdout(&stdout_stream, pool));
+
+ /* Revision-number: 19 */
+ SVN_ERR(svn_stream_printf(stdout_stream, pool,
+ SVN_REPOS_DUMPFILE_REVISION_NUMBER
+ ": %ld\n", revision));
+ SVN_ERR(svn_rdump__normalize_props(&normal_props, rev_props, pool));
+ propstring = svn_stringbuf_create_ensure(0, pool);
+ revprop_stream = svn_stream_from_stringbuf(propstring, pool);
+ SVN_ERR(svn_hash_write2(normal_props, revprop_stream, "PROPS-END", pool));
+ SVN_ERR(svn_stream_close(revprop_stream));
+
+ /* Prop-content-length: 13 */
+ SVN_ERR(svn_stream_printf(stdout_stream, pool,
+ SVN_REPOS_DUMPFILE_PROP_CONTENT_LENGTH
+ ": %" APR_SIZE_T_FMT "\n", propstring->len));
+
+ /* Content-length: 29 */
+ SVN_ERR(svn_stream_printf(stdout_stream, pool,
+ SVN_REPOS_DUMPFILE_CONTENT_LENGTH
+ ": %" APR_SIZE_T_FMT "\n\n", propstring->len));
+
+ /* Property data. */
+ SVN_ERR(svn_stream_write(stdout_stream, propstring->data,
+ &(propstring->len)));
+
+ SVN_ERR(svn_stream_puts(stdout_stream, "\n"));
+ SVN_ERR(svn_stream_close(stdout_stream));
+
+ SVN_ERR(svn_rdump__get_dump_editor_v2(editor, revision,
+ rb->stdout_stream,
+ rb->extra_ra_session,
+ check_cancel, NULL, pool, pool));
+
+ return SVN_NO_ERROR;
+}
+
+/* Print progress information about the dump of REVISION.
+ Implements the `svn_ra_replay_revfinish_callback_t' interface. */
+static svn_error_t *
+replay_revend_v2(svn_revnum_t revision,
+ void *replay_baton,
+ svn_editor_t *editor,
+ apr_hash_t *rev_props,
+ apr_pool_t *pool)
+{
+ /* No resources left to free. */
+ struct replay_baton *rb = replay_baton;
+
+ SVN_ERR(svn_editor_complete(editor));
+
+ if (! rb->quiet)
+ SVN_ERR(svn_cmdline_fprintf(stderr, pool, "* Dumped revision %lu.\n",
+ revision));
+ return SVN_NO_ERROR;
+}
+#endif
+
/* Initialize the RA layer, and set *CTX to a new client context baton
* allocated from POOL. Use CONFIG_DIR and pass USERNAME, PASSWORD,
* CONFIG_DIR and NO_AUTH_CACHE to initialize the authorization baton.
@@ -391,9 +467,16 @@ replay_revisions(svn_ra_session_t *sessi
if (incremental)
{
+#ifndef USE_EV2_IMPL
SVN_ERR(svn_ra_replay_range(session, start_revision, end_revision,
0, TRUE, replay_revstart, replay_revend,
replay_baton, pool));
+#else
+ SVN_ERR(svn_ra__replay_range_ev2(session, start_revision, end_revision,
+ 0, TRUE, replay_revstart_v2,
+ replay_revend_v2, replay_baton,
+ NULL, NULL, NULL, NULL, pool));
+#endif
}
else
{
@@ -432,9 +515,16 @@ replay_revisions(svn_ra_session_t *sessi
/* Now go pick up additional revisions in the range, if any. */
if (start_revision <= end_revision)
+#ifndef USE_EV2_IMPL
SVN_ERR(svn_ra_replay_range(session, start_revision, end_revision,
0, TRUE, replay_revstart, replay_revend,
replay_baton, pool));
+#else
+ SVN_ERR(svn_ra__replay_range_ev2(session, start_revision, end_revision,
+ 0, TRUE, replay_revstart_v2,
+ replay_revend_v2, replay_baton,
+ NULL, NULL, NULL, NULL, pool));
+#endif
}
SVN_ERR(svn_stream_close(stdout_stream));
Modified: subversion/branches/issue-4194-dev/subversion/svnrdump/svnrdump.h
URL: http://svn.apache.org/viewvc/subversion/branches/issue-4194-dev/subversion/svnrdump/svnrdump.h?rev=1414433&r1=1414432&r2=1414433&view=diff
==============================================================================
--- subversion/branches/issue-4194-dev/subversion/svnrdump/svnrdump.h (original)
+++ subversion/branches/issue-4194-dev/subversion/svnrdump/svnrdump.h Tue Nov 27 22:13:24 2012
@@ -53,6 +53,17 @@ svn_rdump__get_dump_editor(const svn_del
void *cancel_baton,
apr_pool_t *pool);
+/* Same as above, only returns an Ev2 editor. */
+svn_error_t *
+svn_rdump__get_dump_editor_v2(svn_editor_t **editor,
+ svn_revnum_t revision,
+ svn_stream_t *stream,
+ svn_ra_session_t *ra_session,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
+ apr_pool_t *scratch_pool,
+ apr_pool_t *result_pool);
+
/**
* Load the dumpstream carried in @a stream to the location described
Modified: subversion/branches/issue-4194-dev/subversion/svnserve/cyrus_auth.c
URL: http://svn.apache.org/viewvc/subversion/branches/issue-4194-dev/subversion/svnserve/cyrus_auth.c?rev=1414433&r1=1414432&r2=1414433&view=diff
==============================================================================
--- subversion/branches/issue-4194-dev/subversion/svnserve/cyrus_auth.c (original)
+++ subversion/branches/issue-4194-dev/subversion/svnserve/cyrus_auth.c Tue Nov 27 22:13:24 2012
@@ -98,7 +98,7 @@ static int canonicalize_username(sasl_co
static sasl_callback_t callbacks[] =
{
- { SASL_CB_CANON_USER, (void*)canonicalize_username, NULL },
+ { SASL_CB_CANON_USER, (int (*)(void))canonicalize_username, NULL },
{ SASL_CB_LIST_END, NULL, NULL }
};
Modified: subversion/branches/issue-4194-dev/subversion/tests/cmdline/diff_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/issue-4194-dev/subversion/tests/cmdline/diff_tests.py?rev=1414433&r1=1414432&r2=1414433&view=diff
==============================================================================
--- subversion/branches/issue-4194-dev/subversion/tests/cmdline/diff_tests.py (original)
+++ subversion/branches/issue-4194-dev/subversion/tests/cmdline/diff_tests.py Tue Nov 27 22:13:24 2012
@@ -196,8 +196,14 @@ def make_diff_prop_added(pname, pval):
def make_diff_prop_modified(pname, pval1, pval2):
"""Return a property diff for modification of property PNAME, old value
- PVAL1, new value PVAL2. PVAL is a single string with no embedded
- newlines. Return the result as a list of newline-terminated strings."""
+ PVAL1, new value PVAL2.
+
+ PVAL is a single string with no embedded newlines. A newline at the
+ end is significant: without it, we add an extra line saying '\ No
+ newline at end of property'.
+
+ Return the result as a list of newline-terminated strings.
+ """
return [
"Modified: " + pname + "\n",
"## -1 +1 ##\n",
@@ -4075,6 +4081,43 @@ def diff_properties_only(sbox):
'diff', '--properties-only',
'-r', 'PREV', 'iota')
+def diff_properties_no_newline(sbox):
+ "diff props; check no-newline-at-end messages"
+
+ sbox.build()
+ old_cwd = os.getcwd()
+ os.chdir(sbox.wc_dir)
+ sbox.wc_dir = ''
+
+ no_nl = "\\ No newline at end of property\n"
+ propchange_header = "Modified: p.*\n"
+
+ subtests = [
+ ('p1', 'val1', 'val2' ),
+ ('p2', 'val1', 'val2\n'),
+ ('p3', 'val1\n', 'val2' ),
+ ('p4', 'val1\n', 'val2\n'),
+ ]
+
+ # The "before" state.
+ for pname, old_val, new_val in subtests:
+ sbox.simple_propset(pname, old_val, 'iota')
+ sbox.simple_commit() # r2
+
+ # Test one change at a time. (Because, with multiple changes, the order
+ # may not be predictable.)
+ for pname, old_val, new_val in subtests:
+ expected_output = \
+ make_diff_header("iota", "revision 1", "working copy") + \
+ make_diff_prop_header("iota") + \
+ make_diff_prop_modified(pname, old_val, new_val)
+
+ sbox.simple_propset(pname, new_val, 'iota')
+ svntest.actions.run_and_verify_svn(None, expected_output, [], 'diff')
+ svntest.actions.run_and_verify_svn(None, None, [], 'revert', 'iota')
+
+ os.chdir(old_cwd)
+
########################################################################
#Run the tests
@@ -4146,6 +4189,7 @@ test_list = [ None,
diff_deleted_url,
diff_arbitrary_files_and_dirs,
diff_properties_only,
+ diff_properties_no_newline,
]
if __name__ == '__main__':