subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From julianf...@apache.org
Subject 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...
Date Fri, 30 Nov 2012 18:13:02 GMT
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(&current_base_props,
-                                         eb->db, fb->local_abspath,
-                                         scratch_pool, scratch_pool));
+      SVN_ERR(svn_wc__db_read_pristine_props(&current_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. */



Mime
View raw message