You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by ju...@apache.org on 2012/11/30 19:13:02 UTC
svn commit: r1415773 [4/6] - in /subversion/branches/tree-read-api: ./
build/ac-macros/ build/generator/ notes/ subversion/bindings/cxxhl/
subversion/include/ subversion/include/private/ subversion/libsvn_client/
subversion/libsvn_delta/ subversion/lib...
Modified: subversion/branches/tree-read-api/subversion/libsvn_wc/update_editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_wc/update_editor.c?rev=1415773&r1=1415772&r2=1415773&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_wc/update_editor.c (original)
+++ subversion/branches/tree-read-api/subversion/libsvn_wc/update_editor.c Fri Nov 30 18:12:52 2012
@@ -2394,9 +2394,9 @@ close_directory(void *dir_baton,
if (db->add_existed)
{
/* This node already exists. Grab the current pristine properties. */
- SVN_ERR(svn_wc__get_pristine_props(&base_props,
- eb->db, db->local_abspath,
- scratch_pool, scratch_pool));
+ SVN_ERR(svn_wc__db_read_pristine_props(&base_props,
+ eb->db, db->local_abspath,
+ scratch_pool, scratch_pool));
}
else if (!db->adding_dir)
{
@@ -3975,6 +3975,7 @@ close_file(void *file_baton,
apr_pool_t *scratch_pool = fb->pool; /* Destroyed at function exit */
svn_boolean_t keep_recorded_info = FALSE;
const svn_checksum_t *new_checksum;
+ apr_array_header_t *iprops = NULL;
if (fb->skip_this)
{
@@ -4076,9 +4077,9 @@ close_file(void *file_baton,
if (fb->add_existed)
{
/* This node already exists. Grab the current pristine properties. */
- SVN_ERR(svn_wc__get_pristine_props(¤t_base_props,
- eb->db, fb->local_abspath,
- scratch_pool, scratch_pool));
+ SVN_ERR(svn_wc__db_read_pristine_props(¤t_base_props,
+ eb->db, fb->local_abspath,
+ scratch_pool, scratch_pool));
current_actual_props = local_actual_props;
}
else if (!fb->adding_file)
@@ -4299,6 +4300,22 @@ close_file(void *file_baton,
scratch_pool);
}
+ /* Any inherited props to be set set for this base node? */
+ if (eb->wcroot_iprops)
+ {
+ iprops = apr_hash_get(eb->wcroot_iprops, fb->local_abspath,
+ APR_HASH_KEY_STRING);
+
+ /* close_edit may also update iprops for switched nodes, catching
+ those for which close_directory is never called (e.g. a switch
+ with no changes). So as a minor optimization we remove any
+ iprops from the hash so as not to set them again in
+ close_edit. */
+ if (iprops)
+ apr_hash_set(eb->wcroot_iprops, fb->local_abspath,
+ APR_HASH_KEY_STRING, NULL);
+ }
+
SVN_ERR(svn_wc__db_base_add_file(eb->db, fb->local_abspath,
eb->wcroot_abspath,
fb->new_relpath,
@@ -4317,6 +4334,7 @@ close_file(void *file_baton,
(fb->add_existed && fb->adding_file),
(! fb->shadowed) && new_base_props,
new_actual_props,
+ iprops,
keep_recorded_info,
(fb->shadowed && fb->obstruction_found),
conflict_skel,
@@ -4998,147 +5016,25 @@ svn_wc__check_wc_root(svn_boolean_t *wc_
const char *local_abspath,
apr_pool_t *scratch_pool)
{
- const char *parent_abspath, *name;
- const char *repos_relpath, *repos_root, *repos_uuid;
- svn_wc__db_status_t status;
- svn_kind_t my_kind;
-
- if (!kind)
- kind = &my_kind;
-
- /* Initialize our return values to the most common (code-wise) values. */
- *wc_root = TRUE;
- if (switched)
- *switched = FALSE;
-
- SVN_ERR(svn_wc__db_read_info(&status, kind, NULL, &repos_relpath,
- &repos_root, &repos_uuid, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL,
- db, local_abspath,
- scratch_pool, scratch_pool));
-
- if (repos_relpath == NULL)
- {
- /* If we inherit our URL, then we can't be a root, nor switched. */
- *wc_root = FALSE;
- return SVN_NO_ERROR;
- }
- if (*kind != svn_kind_dir)
- {
- /* File/symlinks cannot be a root. */
- *wc_root = FALSE;
- }
- else if (status == svn_wc__db_status_added
- || status == svn_wc__db_status_deleted)
- {
- *wc_root = FALSE;
- }
- else 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."),
- svn_dirent_local_style(local_abspath, scratch_pool));
- }
- else if (svn_dirent_is_root(local_abspath, strlen(local_abspath)))
- return SVN_NO_ERROR;
-
- if (!*wc_root && switched == NULL )
- return SVN_NO_ERROR; /* No more info needed */
-
- svn_dirent_split(&parent_abspath, &name, local_abspath, scratch_pool);
-
- /* Check if the node is recorded in the parent */
- if (*wc_root)
- {
- svn_boolean_t is_root;
- SVN_ERR(svn_wc__db_is_wcroot(&is_root, db, local_abspath, scratch_pool));
-
- if (is_root)
- {
- /* We're not in the (versioned) parent directory's list of
- children, so we must be the root of a distinct working copy. */
- return SVN_NO_ERROR;
- }
- }
-
- {
- const char *parent_repos_root;
- const char *parent_repos_relpath;
- const char *parent_repos_uuid;
-
- SVN_ERR(svn_wc__db_scan_base_repos(&parent_repos_relpath,
- &parent_repos_root,
- &parent_repos_uuid,
- db, parent_abspath,
- scratch_pool, scratch_pool));
-
- if (strcmp(repos_root, parent_repos_root) != 0
- || strcmp(repos_uuid, parent_repos_uuid) != 0)
- {
- /* This should never happen (### until we get mixed-repos working
- copies). If we're in the parent, then we should be from the
- same repository. For this situation, just declare us the root
- of a separate, unswitched working copy. */
- return SVN_NO_ERROR;
- }
-
- *wc_root = FALSE;
-
- if (switched)
- {
- const char *expected_relpath = svn_relpath_join(parent_repos_relpath,
- name, scratch_pool);
-
- *switched = (strcmp(expected_relpath, repos_relpath) != 0);
- }
- }
-
- return SVN_NO_ERROR;
+ return svn_error_trace(
+ svn_wc__db_is_switched(wc_root, switched, kind,
+ db, local_abspath,
+ scratch_pool));
}
svn_error_t *
-svn_wc__internal_is_wc_root(svn_boolean_t *wc_root,
- svn_wc__db_t *db,
- const char *local_abspath,
- apr_pool_t *scratch_pool)
+svn_wc_check_root(svn_boolean_t *is_wcroot,
+ svn_boolean_t *is_switched,
+ svn_kind_t *kind,
+ svn_wc_context_t *wc_ctx,
+ const char *local_abspath,
+ apr_pool_t *scratch_pool)
{
- svn_boolean_t is_root;
- svn_boolean_t is_switched;
- svn_kind_t kind;
- svn_error_t *err;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
- err = svn_wc__check_wc_root(&is_root, &kind, &is_switched,
- db, local_abspath, scratch_pool);
-
- if (err)
- {
- if (err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND &&
- err->apr_err != SVN_ERR_WC_NOT_WORKING_COPY)
- return svn_error_trace(err);
-
- return svn_error_create(SVN_ERR_ENTRY_NOT_FOUND, err, err->message);
- }
-
- *wc_root = is_root || is_switched;
-
- return SVN_NO_ERROR;
-}
-
-svn_error_t *
-svn_wc_is_wc_root2(svn_boolean_t *wc_root,
- svn_wc_context_t *wc_ctx,
- const char *local_abspath,
- apr_pool_t *scratch_pool)
-{
- return svn_error_trace(svn_wc__internal_is_wc_root(wc_root, wc_ctx->db,
- local_abspath,
- scratch_pool));
+ return svn_error_trace(svn_wc__db_is_switched(is_wcroot,is_switched, kind,
+ wc_ctx->db, local_abspath,
+ scratch_pool));
}
svn_error_t*
Modified: subversion/branches/tree-read-api/subversion/libsvn_wc/wc-metadata.sql
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_wc/wc-metadata.sql?rev=1415773&r1=1415772&r2=1415773&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_wc/wc-metadata.sql (original)
+++ subversion/branches/tree-read-api/subversion/libsvn_wc/wc-metadata.sql Fri Nov 30 18:12:52 2012
@@ -585,13 +585,14 @@ CREATE UNIQUE INDEX I_EXTERNALS_DEFINED
-- STMT_UPGRADE_TO_20
-UPDATE BASE_NODE SET checksum=(SELECT checksum FROM pristine
- WHERE md5_checksum=BASE_NODE.checksum)
-WHERE EXISTS(SELECT 1 FROM pristine WHERE md5_checksum=BASE_NODE.checksum);
-
-UPDATE WORKING_NODE SET checksum=(SELECT checksum FROM pristine
- WHERE md5_checksum=WORKING_NODE.checksum)
-WHERE EXISTS(SELECT 1 FROM pristine WHERE md5_checksum=WORKING_NODE.checksum);
+UPDATE BASE_NODE SET checksum = (SELECT checksum FROM pristine
+ WHERE md5_checksum = BASE_NODE.checksum)
+WHERE EXISTS (SELECT 1 FROM pristine WHERE md5_checksum = BASE_NODE.checksum);
+
+UPDATE WORKING_NODE SET checksum = (SELECT checksum FROM pristine
+ WHERE md5_checksum = WORKING_NODE.checksum)
+WHERE EXISTS (SELECT 1 FROM pristine
+ WHERE md5_checksum = WORKING_NODE.checksum);
INSERT INTO NODES (
wc_id, local_relpath, op_depth, parent_relpath,
@@ -731,9 +732,9 @@ LIMIT 1
-- STMT_UPGRADE_TO_28
-UPDATE NODES SET checksum=(SELECT checksum FROM pristine
- WHERE md5_checksum=nodes.checksum)
-WHERE EXISTS(SELECT 1 FROM pristine WHERE md5_checksum=nodes.checksum);
+UPDATE NODES SET checksum = (SELECT checksum FROM pristine
+ WHERE md5_checksum = nodes.checksum)
+WHERE EXISTS (SELECT 1 FROM pristine WHERE md5_checksum = nodes.checksum);
PRAGMA user_version = 28;
Modified: subversion/branches/tree-read-api/subversion/libsvn_wc/wc-queries.sql
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_wc/wc-queries.sql?rev=1415773&r1=1415772&r2=1415773&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_wc/wc-queries.sql (original)
+++ subversion/branches/tree-read-api/subversion/libsvn_wc/wc-queries.sql Fri Nov 30 18:12:52 2012
@@ -29,7 +29,7 @@
-- STMT_SELECT_NODE_INFO
SELECT op_depth, repos_id, repos_path, presence, kind, revision, checksum,
translated_size, changed_revision, changed_date, changed_author, depth,
- symlink_target, last_mod_time, properties, moved_here
+ symlink_target, last_mod_time, properties, moved_here, inherited_props
FROM nodes
WHERE wc_id = ?1 AND local_relpath = ?2
ORDER BY op_depth DESC
@@ -38,6 +38,7 @@ ORDER BY op_depth DESC
SELECT op_depth, nodes.repos_id, nodes.repos_path, presence, kind, revision,
checksum, translated_size, changed_revision, changed_date, changed_author,
depth, symlink_target, last_mod_time, properties, moved_here,
+ inherited_props,
/* All the columns until now must match those returned by
STMT_SELECT_NODE_INFO. The implementation of svn_wc__db_read_info()
assumes that these columns are followed by the lock information) */
@@ -798,9 +799,9 @@ INSERT OR REPLACE INTO nodes (
wc_id, local_relpath, op_depth, parent_relpath, repos_id, repos_path,
revision, presence, depth, kind, changed_revision, changed_date,
changed_author, checksum, properties, dav_cache, symlink_target,
- file_external )
+ inherited_props, file_external )
VALUES (?1, ?2, 0,
- ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, ?15, ?16,
+ ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, ?15, ?16, ?17,
(SELECT file_external FROM nodes
WHERE wc_id = ?1
AND local_relpath = ?2
@@ -1444,22 +1445,29 @@ SET inherited_props = ?3
WHERE (wc_id = ?1 AND local_relpath = ?2 AND op_depth = 0)
/* Select a single path if its base node has cached inherited properties. */
--- STMT_SELECT_INODES
-SELECT local_relpath FROM nodes
+-- STMT_SELECT_IPROPS_NODE
+SELECT local_relpath, repos_path FROM nodes
WHERE wc_id = ?1
AND local_relpath = ?2
AND op_depth = 0
AND (inherited_props not null)
-/* Select all paths whose base nodes at or below a given path, which
+/* Select all paths whose base nodes are below a given path, which
have cached inherited properties. */
--- STMT_SELECT_INODES_RECURSIVE
-SELECT local_relpath FROM nodes
+-- STMT_SELECT_IPROPS_RECURSIVE
+SELECT local_relpath, repos_path FROM nodes
WHERE wc_id = ?1
AND IS_STRICT_DESCENDANT_OF(local_relpath, ?2)
AND op_depth = 0
AND (inherited_props not null)
+-- STMT_SELECT_IPROPS_CHILDREN
+SELECT local_relpath, repos_path FROM nodes
+WHERE wc_id = ?1
+ AND parent_relpath = ?2
+ AND op_depth = 0
+ AND (inherited_props not null)
+
/* ------------------------------------------------------------------------- */
/* Grab all the statements related to the schema. */
Modified: subversion/branches/tree-read-api/subversion/libsvn_wc/wc.h
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_wc/wc.h?rev=1415773&r1=1415772&r2=1415773&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_wc/wc.h (original)
+++ subversion/branches/tree-read-api/subversion/libsvn_wc/wc.h Fri Nov 30 18:12:52 2012
@@ -607,23 +607,6 @@ svn_wc__internal_get_repos_relpath(const
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
-/* Internal version of svn_wc__get_iprops() */
-svn_error_t *
-svn_wc__internal_get_iprops(apr_array_header_t **inherited_props,
- svn_wc__db_t *db,
- const char *local_abspath,
- const char *propname,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool);
-
-/* Internal version of svn_wc_is_wc_root2() */
-svn_error_t *
-svn_wc__internal_is_wc_root(svn_boolean_t *wc_root,
- svn_wc__db_t *db,
- const char *local_abspath,
- apr_pool_t *scratch_pool);
-
-
/* Upgrade the wc sqlite database given in SDB for the wc located at
WCROOT_ABSPATH. It's current/starting format is given by START_FORMAT.
After the upgrade is complete (to as far as the automatic upgrade will
@@ -772,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 */
Modified: subversion/branches/tree-read-api/subversion/libsvn_wc/wc_db.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_wc/wc_db.c?rev=1415773&r1=1415772&r2=1415773&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_wc/wc_db.c (original)
+++ subversion/branches/tree-read-api/subversion/libsvn_wc/wc_db.c Fri Nov 30 18:12:52 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"
@@ -320,6 +321,7 @@ static svn_error_t *
db_read_pristine_props(apr_hash_t **props,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
+ svn_boolean_t deleted_ok,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
@@ -381,7 +383,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 +1791,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 +1835,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 +1878,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 +1921,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)
{
@@ -3636,7 +3653,7 @@ cross_db_copy(svn_wc__db_wcroot_t *src_w
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
src_wcroot, src_relpath, scratch_pool, scratch_pool));
- SVN_ERR(db_read_pristine_props(&props, src_wcroot, src_relpath,
+ SVN_ERR(db_read_pristine_props(&props, src_wcroot, src_relpath, FALSE,
scratch_pool, scratch_pool));
blank_iwb(&iwb);
@@ -5085,7 +5102,7 @@ set_props_txn(void *baton,
/* Check if the props are modified. If no changes, then wipe out the
ACTUAL props. PRISTINE_PROPS==NULL means that any
ACTUAL props are okay as provided, so go ahead and set them. */
- SVN_ERR(db_read_pristine_props(&pristine_props, wcroot, local_relpath,
+ SVN_ERR(db_read_pristine_props(&pristine_props, wcroot, local_relpath, FALSE,
scratch_pool, scratch_pool));
if (spb->props && pristine_props)
{
@@ -7663,7 +7680,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)
@@ -8825,7 +8842,7 @@ db_read_props(void *baton,
return SVN_NO_ERROR;
/* No local changes. Return the pristine props for this node. */
- SVN_ERR(db_read_pristine_props(&rpb->props, wcroot, local_relpath,
+ SVN_ERR(db_read_pristine_props(&rpb->props, wcroot, local_relpath, FALSE,
rpb->result_pool, scratch_pool));
if (rpb->props == NULL)
{
@@ -8873,6 +8890,7 @@ static svn_error_t *
db_read_pristine_props(apr_hash_t **props,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
+ svn_boolean_t deleted_ok,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
@@ -8900,9 +8918,8 @@ db_read_pristine_props(apr_hash_t **prop
presence = svn_sqlite__column_token(stmt, 1, presence_map);
/* For "base-deleted", it is obvious the pristine props are located
- in the BASE table. Fall through to fetch them.
- ### BH: Is this really the behavior we want here? */
- if (presence == svn_wc__db_status_base_deleted)
+ below the current node. Fetch the NODE from the next record. */
+ if (presence == svn_wc__db_status_base_deleted && deleted_ok)
{
SVN_ERR(svn_sqlite__step(&have_row, stmt));
@@ -8928,8 +8945,13 @@ db_read_pristine_props(apr_hash_t **prop
return SVN_NO_ERROR;
}
- *props = NULL;
- return svn_error_trace(svn_sqlite__reset(stmt));
+ return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS,
+ svn_sqlite__reset(stmt),
+ _("The node '%s' has a status that"
+ " has no properties."),
+ path_for_error_message(wcroot,
+ local_relpath,
+ scratch_pool));
}
@@ -8949,7 +8971,7 @@ svn_wc__db_read_pristine_props(apr_hash_
local_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
- SVN_ERR(db_read_pristine_props(props, wcroot, local_relpath,
+ SVN_ERR(db_read_pristine_props(props, wcroot, local_relpath, TRUE,
result_pool, scratch_pool));
return SVN_NO_ERROR;
}
@@ -9014,6 +9036,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 +9084,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);
- if (repos_relpath && repos_relpath[0] == '\0')
+ rcib.result_pool = result_pool;
+
+ /* 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 +9360,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 +9420,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 +9945,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 +10015,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 +10105,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 +12744,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/tree-read-api/subversion/libsvn_wc/wc_db.h
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_wc/wc_db.h?rev=1415773&r1=1415772&r2=1415773&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_wc/wc_db.h (original)
+++ subversion/branches/tree-read-api/subversion/libsvn_wc/wc_db.h Fri Nov 30 18:12:52 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/tree-read-api/subversion/mod_dav_svn/reports/update.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/mod_dav_svn/reports/update.c?rev=1415773&r1=1415772&r2=1415773&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/mod_dav_svn/reports/update.c (original)
+++ subversion/branches/tree-read-api/subversion/mod_dav_svn/reports/update.c Fri Nov 30 18:12:52 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/tree-read-api/subversion/mod_dav_svn/repos.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/mod_dav_svn/repos.c?rev=1415773&r1=1415772&r2=1415773&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/mod_dav_svn/repos.c (original)
+++ subversion/branches/tree-read-api/subversion/mod_dav_svn/repos.c Fri Nov 30 18:12:52 2012
@@ -2596,121 +2596,6 @@ is_parent_resource(const dav_resource *r
}
-#if 0
-/* Given an apache request R and a ROOT_PATH to the svn location
- block, set *KIND to the node-kind of the URI's associated
- (revision, path) pair, if possible.
-
- Public uris, baseline collections, version resources, and working
- (non-baseline) resources all have associated (revision, path)
- pairs, and thus one of {svn_node_file, svn_node_dir, svn_node_none}
- will be returned.
-
- If URI is something more abstract, then set *KIND to
- svn_node_unknown. This is true for baselines, working baselines,
- version controled configurations, activities, histories, and other
- private resources.
-*/
-static dav_error *
-resource_kind(request_rec *r,
- const char *uri,
- const char *root_path,
- svn_node_kind_t *kind)
-{
- dav_error *derr;
- svn_error_t *serr;
- dav_resource *resource;
- svn_revnum_t base_rev;
- svn_fs_root_t *base_rev_root;
- char *saved_uri;
-
- /* Temporarily insert the uri that the user actually wants us to
- convert into a resource. Typically, this is already r->uri, so
- this is usually a no-op. But sometimes the caller may pass in
- the Destination: header uri.
-
- ### WHAT WE REALLY WANT here is to refactor get_resource,
- so that some alternate interface actually allows us to specify
- the URI to process, i.e. not always process r->uri.
- */
- saved_uri = r->uri;
- r->uri = apr_pstrdup(r->pool, uri);
-
- /* parse the uri and prep the associated resource. */
- derr = get_resource(r, root_path,
- /* ### I can't believe that every single
- parser ignores the LABEL and USE_CHECKED_IN
- args below!! */
- "ignored_label", 1,
- &resource);
- /* Restore r back to normal. */
- r->uri = saved_uri;
-
- if (derr)
- return derr;
-
- if (resource->type == DAV_RESOURCE_TYPE_REGULAR)
- {
- /* Either a public URI or a bc. In both cases, prep_regular()
- has already set the 'exists' and 'collection' flags by
- querying the appropriate revision root and path. */
- if (! resource->exists)
- *kind = svn_node_none;
- else
- *kind = resource->collection ? svn_node_dir : svn_node_file;
- }
-
- else if (resource->type == DAV_RESOURCE_TYPE_VERSION)
- {
- if (resource->baselined) /* bln */
- *kind = svn_node_unknown;
-
- else /* ver */
- {
- derr = fs_check_path(kind, resource->info->root.root,
- resource->info->repos_path, r->pool);
- if (derr != NULL)
- return derr;
- }
- }
-
- else if (resource->type == DAV_RESOURCE_TYPE_WORKING)
- {
- if (resource->baselined) /* wbl */
- *kind = svn_node_unknown;
-
- else /* wrk */
- {
- /* don't call fs_check_path on the txn, but on the original
- revision that the txn is based on. */
- base_rev = svn_fs_txn_base_revision(resource->info->root.txn);
- serr = svn_fs_revision_root(&base_rev_root,
- resource->info->repos->fs,
- base_rev, r->pool);
- if (serr)
- return dav_svn__convert_err
- (serr, HTTP_INTERNAL_SERVER_ERROR,
- apr_psprintf(r->pool,
- "Could not open root of revision %ld",
- base_rev),
- r->pool);
-
- derr = fs_check_path(kind, base_rev_root,
- resource->info->repos_path, r->pool);
- if (derr != NULL)
- return derr;
- }
- }
-
- else
- /* act, his, vcc, or some other private resource */
- *kind = svn_node_unknown;
-
- return NULL;
-}
-#endif
-
-
static dav_error *
open_stream(const dav_resource *resource,
dav_stream_mode mode,
@@ -2730,14 +2615,13 @@ open_stream(const dav_resource *resource
}
}
-#if 1
+ /* ### TODO: Can we support range writes someday? */
if (mode == DAV_MODE_WRITE_SEEKABLE)
{
return dav_svn__new_error(resource->pool, HTTP_NOT_IMPLEMENTED, 0,
"Resource body writes cannot use ranges "
"(at this time).");
}
-#endif
/* start building the stream structure */
*stream = apr_pcalloc(resource->pool, sizeof(**stream));
Modified: subversion/branches/tree-read-api/subversion/svn/cl.h
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/svn/cl.h?rev=1415773&r1=1415772&r2=1415773&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/svn/cl.h (original)
+++ subversion/branches/tree-read-api/subversion/svn/cl.h Fri Nov 30 18:12:52 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/tree-read-api/subversion/svn/info-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/svn/info-cmd.c?rev=1415773&r1=1415772&r2=1415773&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/svn/info-cmd.c (original)
+++ subversion/branches/tree-read-api/subversion/svn/info-cmd.c Fri Nov 30 18:12:52 2012
@@ -102,8 +102,22 @@ print_info_xml(void *baton,
"revision", rev_str,
NULL);
+ /* "<url> xx </url>" */
svn_cl__xml_tagged_cdata(&sb, pool, "url", info->URL);
+ if (info->repos_root_URL)
+ {
+ /* "<relative-url> xx </relative-url>" */
+ svn_cl__xml_tagged_cdata(&sb, pool, "relative-url",
+ apr_pstrcat(pool, "^/",
+ svn_path_uri_encode(
+ svn_uri_skip_ancestor(
+ info->repos_root_URL,
+ info->URL, pool),
+ pool),
+ NULL));
+ }
+
if (info->repos_root_URL || info->repos_UUID)
{
/* "<repository>" */
@@ -308,6 +322,13 @@ print_info(void *baton,
if (info->URL)
SVN_ERR(svn_cmdline_printf(pool, _("URL: %s\n"), info->URL));
+ if (info->URL && info->repos_root_URL)
+ SVN_ERR(svn_cmdline_printf(pool, _("Relative URL: ^/%s\n"),
+ svn_path_uri_encode(
+ svn_uri_skip_ancestor(info->repos_root_URL,
+ info->URL, pool),
+ pool)));
+
if (info->repos_root_URL)
SVN_ERR(svn_cmdline_printf(pool, _("Repository Root: %s\n"),
info->repos_root_URL));
Modified: subversion/branches/tree-read-api/subversion/svn/list-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/svn/list-cmd.c?rev=1415773&r1=1415772&r2=1415773&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/svn/list-cmd.c (original)
+++ subversion/branches/tree-read-api/subversion/svn/list-cmd.c Fri Nov 30 18:12:52 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,13 +57,18 @@ print_dirent(void *baton,
const svn_dirent_t *dirent,
const svn_lock_t *lock,
const char *abs_path,
- apr_pool_t *pool)
+ const char *external_parent_url,
+ const char *external_target,
+ apr_pool_t *scratch_pool)
{
struct print_baton *pb = baton;
const char *entryname;
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)
@@ -70,7 +80,7 @@ print_dirent(void *baton,
if (strcmp(path, "") == 0)
{
if (dirent->kind == svn_node_file)
- entryname = svn_dirent_basename(abs_path, pool);
+ entryname = svn_dirent_basename(abs_path, scratch_pool);
else if (pb->verbose)
entryname = ".";
else
@@ -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(scratch_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)
{
@@ -110,12 +138,13 @@ print_dirent(void *baton,
timestr[0] = '\0';
/* we need it in UTF-8. */
- SVN_ERR(svn_utf_cstring_to_utf8(&utf8_timestr, timestr, pool));
+ SVN_ERR(svn_utf_cstring_to_utf8(&utf8_timestr, timestr, scratch_pool));
- sizestr = apr_psprintf(pool, "%" SVN_FILESIZE_T_FMT, dirent->size);
+ sizestr = apr_psprintf(scratch_pool, "%" SVN_FILESIZE_T_FMT,
+ dirent->size);
return svn_cmdline_printf
- (pool, "%7ld %-8.8s %c %10s %12s %s%s\n",
+ (scratch_pool, "%7ld %-8.8s %c %10s %12s %s%s\n",
dirent->created_rev,
dirent->last_author ? dirent->last_author : " ? ",
lock ? 'O' : ' ',
@@ -126,14 +155,14 @@ print_dirent(void *baton,
}
else
{
- return svn_cmdline_printf(pool, "%s%s\n", entryname,
+ return svn_cmdline_printf(scratch_pool, "%s%s\n", entryname,
(dirent->kind == svn_node_dir)
? "/" : "");
}
}
-/* 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 +170,21 @@ print_dirent_xml(void *baton,
const svn_dirent_t *dirent,
const svn_lock_t *lock,
const char *abs_path,
- apr_pool_t *pool)
+ const char *external_parent_url,
+ const char *external_target,
+ apr_pool_t *scratch_pool)
{
struct print_baton *pb = baton;
const char *entryname;
- svn_stringbuf_t *sb;
+ svn_stringbuf_t *sb = svn_stringbuf_create_empty(scratch_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 = ".";
+ entryname = svn_dirent_basename(abs_path, scratch_pool);
else
/* Don't bother to list if no useful information will be shown. */
return SVN_NO_ERROR;
@@ -162,49 +194,73 @@ 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, scratch_pool, "external");
+ pb->in_external = FALSE;
+ }
+
+ svn_xml_make_open_tag(&sb, scratch_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",
+ svn_xml_make_open_tag(&sb, scratch_pool, svn_xml_normal, "entry",
"kind", svn_cl__node_kind_str_xml(dirent->kind),
NULL);
- svn_cl__xml_tagged_cdata(&sb, pool, "name", entryname);
+ svn_cl__xml_tagged_cdata(&sb, scratch_pool, "name", entryname);
if (dirent->kind == svn_node_file)
{
svn_cl__xml_tagged_cdata
- (&sb, pool, "size",
- apr_psprintf(pool, "%" SVN_FILESIZE_T_FMT, dirent->size));
+ (&sb, scratch_pool, "size",
+ apr_psprintf(scratch_pool, "%" SVN_FILESIZE_T_FMT, dirent->size));
}
- svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "commit",
+ svn_xml_make_open_tag(&sb, scratch_pool, svn_xml_normal, "commit",
"revision",
- apr_psprintf(pool, "%ld", dirent->created_rev),
+ apr_psprintf(scratch_pool, "%ld", dirent->created_rev),
NULL);
- svn_cl__xml_tagged_cdata(&sb, pool, "author", dirent->last_author);
+ svn_cl__xml_tagged_cdata(&sb, scratch_pool, "author", dirent->last_author);
if (dirent->time)
- svn_cl__xml_tagged_cdata(&sb, pool, "date",
- svn_time_to_cstring(dirent->time, pool));
- svn_xml_make_close_tag(&sb, pool, "commit");
+ svn_cl__xml_tagged_cdata(&sb, scratch_pool, "date",
+ svn_time_to_cstring(dirent->time, scratch_pool));
+ svn_xml_make_close_tag(&sb, scratch_pool, "commit");
if (lock)
{
- svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "lock", NULL);
- svn_cl__xml_tagged_cdata(&sb, pool, "token", lock->token);
- svn_cl__xml_tagged_cdata(&sb, pool, "owner", lock->owner);
- svn_cl__xml_tagged_cdata(&sb, pool, "comment", lock->comment);
- svn_cl__xml_tagged_cdata(&sb, pool, "created",
+ svn_xml_make_open_tag(&sb, scratch_pool, svn_xml_normal, "lock", NULL);
+ svn_cl__xml_tagged_cdata(&sb, scratch_pool, "token", lock->token);
+ svn_cl__xml_tagged_cdata(&sb, scratch_pool, "owner", lock->owner);
+ svn_cl__xml_tagged_cdata(&sb, scratch_pool, "comment", lock->comment);
+ svn_cl__xml_tagged_cdata(&sb, scratch_pool, "created",
svn_time_to_cstring(lock->creation_date,
- pool));
+ scratch_pool));
if (lock->expiration_date != 0)
- svn_cl__xml_tagged_cdata(&sb, pool, "expires",
+ svn_cl__xml_tagged_cdata(&sb, scratch_pool, "expires",
svn_time_to_cstring
- (lock->expiration_date, pool));
- svn_xml_make_close_tag(&sb, pool, "lock");
+ (lock->expiration_date, scratch_pool));
+ svn_xml_make_close_tag(&sb, scratch_pool, "lock");
}
- svn_xml_make_close_tag(&sb, pool, "entry");
+ svn_xml_make_close_tag(&sb, scratch_pool, "entry");
return svn_cl__error_checked_fputs(sb->data, stdout);
}
@@ -225,6 +281,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 +324,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 +363,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 +390,35 @@ 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"));
- else
- return SVN_NO_ERROR;
+ 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);
}
Modified: subversion/branches/tree-read-api/subversion/svn/propedit-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/svn/propedit-cmd.c?rev=1415773&r1=1415772&r2=1415773&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/svn/propedit-cmd.c (original)
+++ subversion/branches/tree-read-api/subversion/svn/propedit-cmd.c Fri Nov 30 18:12:52 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/tree-read-api/subversion/svn/propget-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/svn/propget-cmd.c?rev=1415773&r1=1415772&r2=1415773&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/svn/propget-cmd.c (original)
+++ subversion/branches/tree-read-api/subversion/svn/propget-cmd.c Fri Nov 30 18:12:52 2012
@@ -147,6 +147,7 @@ print_properties_xml(const char *pname,
All other arguments are as per print_properties. */
static svn_error_t *
print_single_prop(svn_string_t *propval,
+ const char *target_abspath_or_url,
const char *abspath_or_URL,
const char *wc_path_prefix,
svn_stream_t *out,
@@ -171,9 +172,24 @@ print_single_prop(svn_string_t *propval,
/* In verbose mode, print exactly same as "proplist" does;
* otherwise, print a brief header. */
if (inherited_property)
- header = apr_psprintf(scratch_pool, like_proplist
- ? _("Properties inherited from '%s':\n")
- : "%s - ", abspath_or_URL);
+ {
+ if (like_proplist)
+ {
+ if (! svn_path_is_url(target_abspath_or_url))
+ target_abspath_or_url =
+ svn_cl__local_style_skip_ancestor(wc_path_prefix,
+ target_abspath_or_url,
+ scratch_pool);
+ header = apr_psprintf(
+ scratch_pool,
+ _("Inherited properties on '%s',\nfrom '%s':\n"),
+ target_abspath_or_url, abspath_or_URL);
+ }
+ else
+ {
+ header = apr_psprintf(scratch_pool, "%s - ", abspath_or_URL);
+ }
+ }
else
header = apr_psprintf(scratch_pool, like_proplist
? _("Properties on '%s':\n")
@@ -218,6 +234,8 @@ print_single_prop(svn_string_t *propval,
value. INHERITED_PROPS is a depth-first ordered array of
svn_prop_inherited_item_t * structures.
+ TARGET_ABSPATH_OR_URL is the path which inherits INHERITED_PROPS.
+
PROPS may be an empty hash, but is never null. INHERITED_PROPS may be
null.
@@ -234,6 +252,7 @@ print_single_prop(svn_string_t *propval,
like "svn proplist -v" does. */
static svn_error_t *
print_properties(svn_stream_t *out,
+ const char *target_abspath_or_url,
const char *pname_utf8,
apr_hash_t *props,
apr_array_header_t *inherited_props,
@@ -259,7 +278,7 @@ print_properties(svn_stream_t *out,
APR_ARRAY_IDX(inherited_props, i, svn_prop_inherited_item_t *);
svn_string_t *propval = svn__apr_hash_index_val(apr_hash_first(pool,
iprop->prop_hash));
- SVN_ERR(print_single_prop(propval,
+ SVN_ERR(print_single_prop(propval, target_abspath_or_url,
iprop->path_or_url,
path_prefix, out, pname_utf8,
print_filenames, omit_newline,
@@ -276,8 +295,8 @@ print_properties(svn_stream_t *out,
svn_pool_clear(iterpool);
- SVN_ERR(print_single_prop(propval, filename, path_prefix,
- out, pname_utf8, print_filenames,
+ SVN_ERR(print_single_prop(propval, target_abspath_or_url, filename,
+ path_prefix, out, pname_utf8, print_filenames,
omit_newline, like_proplist, FALSE,
iterpool));
}
@@ -443,7 +462,8 @@ svn_cl__propget(apr_getopt_t *os,
print_filenames = ((opt_state->depth > svn_depth_empty
|| targets->nelts > 1
|| apr_hash_count(props) > 1
- || opt_state->verbose)
+ || opt_state->verbose
+ || opt_state->show_inherited_props)
&& (! opt_state->strict));
omit_newline = opt_state->strict;
like_proplist = opt_state->verbose && !opt_state->strict;
@@ -455,7 +475,7 @@ svn_cl__propget(apr_getopt_t *os,
subpool));
else
SVN_ERR(print_properties(
- out, pname_utf8,
+ out, truepath, pname_utf8,
props,
opt_state->show_inherited_props ? inherited_props : NULL,
print_filenames,
Modified: subversion/branches/tree-read-api/subversion/svn/proplist-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/svn/proplist-cmd.c?rev=1415773&r1=1415772&r2=1415773&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/svn/proplist-cmd.c (original)
+++ subversion/branches/tree-read-api/subversion/svn/proplist-cmd.c Fri Nov 30 18:12:52 2012
@@ -151,12 +151,13 @@ proplist_receiver(void *baton,
{
if (svn_path_is_url(iprop->path_or_url))
SVN_ERR(svn_cmdline_printf(
- iterpool, _("Properties inherited from '%s':\n"),
- iprop->path_or_url));
+ iterpool, _("Inherited properties on '%s',\nfrom '%s':\n"),
+ name_local, iprop->path_or_url));
else
SVN_ERR(svn_cmdline_printf(
- iterpool, _("Properties inherited from '%s':\n"),
- svn_dirent_local_style(iprop->path_or_url, iterpool)));
+ iterpool, _("Inherited properties on '%s',\nfrom '%s':\n"),
+ name_local, svn_dirent_local_style(iprop->path_or_url,
+ iterpool)));
}
SVN_ERR(svn_cl__print_prop_hash(NULL, iprop->prop_hash,
Modified: subversion/branches/tree-read-api/subversion/svn/props.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/svn/props.c?rev=1415773&r1=1415772&r2=1415773&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/svn/props.c (original)
+++ subversion/branches/tree-read-api/subversion/svn/props.c Fri Nov 30 18:12:52 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 *
@@ -209,9 +211,10 @@ svn_cl__check_boolean_prop_val(const cha
svn_stringbuf_strip_whitespace(propbuf);
if (propbuf->data[0] == '\0'
- || strcmp(propbuf->data, "no") == 0
- || strcmp(propbuf->data, "off") == 0
- || strcmp(propbuf->data, "false") == 0)
+ || svn_cstring_casecmp(propbuf->data, "0") == 0
+ || svn_cstring_casecmp(propbuf->data, "no") == 0
+ || svn_cstring_casecmp(propbuf->data, "off") == 0
+ || svn_cstring_casecmp(propbuf->data, "false") == 0)
{
svn_error_t *err = svn_error_createf
(SVN_ERR_BAD_PROPERTY_VALUE, NULL,
@@ -223,3 +226,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 similarity testing */
+};
+
+struct simprop_t
+{
+ const char *propname; /* The original svn: property name */
+ svn_string_t name; /* The property name without the svn: prefix */
+ 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 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/tree-read-api/subversion/svn/propset-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/svn/propset-cmd.c?rev=1415773&r1=1415772&r2=1415773&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/svn/propset-cmd.c (original)
+++ subversion/branches/tree-read-api/subversion/svn/propset-cmd.c Fri Nov 30 18:12:52 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. */