subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From hwri...@apache.org
Subject svn commit: r1329209 [6/38] - in /subversion/branches/javahl-ra: ./ build/ build/ac-macros/ build/generator/ build/generator/templates/ build/win32/ contrib/client-side/emacs/ contrib/client-side/vim/ contrib/server-side/mod_dontdothat/ notes/ notes/ap...
Date Mon, 23 Apr 2012 12:33:03 GMT
Modified: subversion/branches/javahl-ra/subversion/libsvn_client/add.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_client/add.c?rev=1329209&r1=1329208&r2=1329209&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_client/add.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_client/add.c Mon Apr 23 12:32:48 2012
@@ -47,6 +47,7 @@
 
 #include "private/svn_client_private.h"
 #include "private/svn_wc_private.h"
+#include "private/svn_ra_private.h"
 #include "private/svn_magic.h"
 
 #include "svn_private_config.h"
@@ -494,31 +495,27 @@ add_dir_recursive(const char *dir_abspat
 }
 
 
-struct add_with_write_lock_baton {
-  const char *local_abspath;
-  svn_depth_t depth;
-  svn_boolean_t force;
-  svn_boolean_t no_ignore;
-  svn_client_ctx_t *ctx;
-
-  /* Absolute path to the first existing parent directory of local_abspath.
-   * If not NULL, all missing parents of local_abspath must be created
-   * before local_abspath can be added. */
-  const char *existing_parent_abspath;
-};
-
-/* The main logic of the public svn_client_add4. */
+/* The main logic of the public svn_client_add4.
+ *
+ * EXISTING_PARENT_ABSPATH is the absolute path to the first existing
+ * parent directory of local_abspath. If not NULL, all missing parents
+ * of LOCAL_ABSPATH must be created before LOCAL_ABSPATH can be added. */
 static svn_error_t *
-add(void *baton, apr_pool_t *result_pool, apr_pool_t *scratch_pool)
+add(const char *local_abspath,
+    svn_depth_t depth,
+    svn_boolean_t force,
+    svn_boolean_t no_ignore,
+    const char *existing_parent_abspath,
+    svn_client_ctx_t *ctx,
+    apr_pool_t *scratch_pool)
 {
   svn_node_kind_t kind;
   svn_error_t *err;
-  struct add_with_write_lock_baton *b = baton;
   svn_magic__cookie_t *magic_cookie;
 
   svn_magic__init(&magic_cookie, scratch_pool);
 
-  if (b->existing_parent_abspath)
+  if (existing_parent_abspath)
     {
       const char *parent_abspath;
       const char *child_relpath;
@@ -526,9 +523,9 @@ add(void *baton, apr_pool_t *result_pool
       int i;
       apr_pool_t *iterpool;
 
-      parent_abspath = b->existing_parent_abspath;
-      child_relpath = svn_dirent_is_child(b->existing_parent_abspath,
-                                          b->local_abspath, NULL);
+      parent_abspath = existing_parent_abspath;
+      child_relpath = svn_dirent_is_child(existing_parent_abspath,
+                                          local_abspath, NULL);
       components = svn_path_decompose(child_relpath, scratch_pool);
       iterpool = svn_pool_create(scratch_pool);
       for (i = 0; i < components->nelts - 1; i++)
@@ -538,8 +535,8 @@ add(void *baton, apr_pool_t *result_pool
 
           svn_pool_clear(iterpool);
 
-          if (b->ctx->cancel_func)
-            SVN_ERR(b->ctx->cancel_func(b->ctx->cancel_baton));
+          if (ctx->cancel_func)
+            SVN_ERR(ctx->cancel_func(ctx->cancel_baton));
 
           component = APR_ARRAY_IDX(components, i, const char *);
           parent_abspath = svn_dirent_join(parent_abspath, component,
@@ -548,29 +545,27 @@ add(void *baton, apr_pool_t *result_pool
           if (disk_kind != svn_node_none && disk_kind != svn_node_dir)
             return svn_error_createf(SVN_ERR_CLIENT_NO_VERSIONED_PARENT, NULL,
                                      _("'%s' prevents creating parent of '%s'"),
-                                     parent_abspath, b->local_abspath);
+                                     parent_abspath, local_abspath);
 
           SVN_ERR(svn_io_make_dir_recursively(parent_abspath, scratch_pool));
-          SVN_ERR(svn_wc_add_from_disk(b->ctx->wc_ctx, parent_abspath,
-                                       b->ctx->notify_func2,
-                                       b->ctx->notify_baton2,
+          SVN_ERR(svn_wc_add_from_disk(ctx->wc_ctx, parent_abspath,
+                                       ctx->notify_func2, ctx->notify_baton2,
                                        scratch_pool));
         }
       svn_pool_destroy(iterpool);
     }
 
-  SVN_ERR(svn_io_check_path(b->local_abspath, &kind, scratch_pool));
+  SVN_ERR(svn_io_check_path(local_abspath, &kind, scratch_pool));
   if (kind == svn_node_dir)
     {
       /* We use add_dir_recursive for all directory targets
          and pass depth along no matter what it is, so that the
          target's depth will be set correctly. */
-      err = add_dir_recursive(b->local_abspath, b->depth,
-                              b->force, b->no_ignore, magic_cookie, b->ctx,
-                              scratch_pool);
+      err = add_dir_recursive(local_abspath, depth, force, no_ignore,
+                              magic_cookie, ctx, scratch_pool);
     }
   else if (kind == svn_node_file)
-    err = add_file(b->local_abspath, magic_cookie, b->ctx, scratch_pool);
+    err = add_file(local_abspath, magic_cookie, ctx, scratch_pool);
   else if (kind == svn_node_none)
     {
       svn_boolean_t tree_conflicted;
@@ -578,7 +573,7 @@ add(void *baton, apr_pool_t *result_pool
       /* Provide a meaningful error message if the node does not exist
        * on disk but is a tree conflict victim. */
       err = svn_wc_conflicted_p3(NULL, NULL, &tree_conflicted,
-                                 b->ctx->wc_ctx, b->local_abspath,
+                                 ctx->wc_ctx, local_abspath,
                                  scratch_pool);
       if (err)
         svn_error_clear(err);
@@ -587,22 +582,22 @@ add(void *baton, apr_pool_t *result_pool
                                  _("'%s' is an existing item in conflict; "
                                    "please mark the conflict as resolved "
                                    "before adding a new item here"),
-                                 svn_dirent_local_style(b->local_abspath,
+                                 svn_dirent_local_style(local_abspath,
                                                         scratch_pool));
 
       return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
                                _("'%s' not found"),
-                               svn_dirent_local_style(b->local_abspath,
+                               svn_dirent_local_style(local_abspath,
                                                       scratch_pool));
     }
   else
     return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
                              _("Unsupported node kind for path '%s'"),
-                             svn_dirent_local_style(b->local_abspath,
+                             svn_dirent_local_style(local_abspath,
                                                     scratch_pool));
 
   /* Ignore SVN_ERR_ENTRY_EXISTS when FORCE is set.  */
-  if (err && err->apr_err == SVN_ERR_ENTRY_EXISTS && b->force)
+  if (err && err->apr_err == SVN_ERR_ENTRY_EXISTS && force)
     {
       svn_error_clear(err);
       err = SVN_NO_ERROR;
@@ -675,7 +670,7 @@ svn_client_add4(const char *path,
 {
   const char *parent_abspath;
   const char *local_abspath;
-  struct add_with_write_lock_baton baton;
+  const char *existing_parent_abspath;
 
   if (svn_path_is_url(path))
     return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
@@ -695,30 +690,26 @@ svn_client_add4(const char *path,
   else
     parent_abspath = svn_dirent_dirname(local_abspath, pool);
 
-  baton.existing_parent_abspath = NULL;
+  existing_parent_abspath = NULL;
   if (add_parents)
     {
       apr_pool_t *subpool;
-      const char *existing_parent_abspath;
+      const char *existing_parent_abspath2;
 
       subpool = svn_pool_create(pool);
-      SVN_ERR(find_existing_parent(&existing_parent_abspath, ctx,
+      SVN_ERR(find_existing_parent(&existing_parent_abspath2, ctx,
                                    parent_abspath, pool, subpool));
-      if (strcmp(existing_parent_abspath, parent_abspath) != 0)
-        baton.existing_parent_abspath = existing_parent_abspath;
+      if (strcmp(existing_parent_abspath2, parent_abspath) != 0)
+        existing_parent_abspath = existing_parent_abspath2;
       svn_pool_destroy(subpool);
     }
 
-  baton.local_abspath = local_abspath;
-  baton.depth = depth;
-  baton.force = force;
-  baton.no_ignore = no_ignore;
-  baton.ctx = ctx;
-  SVN_ERR(svn_wc__call_with_write_lock(add, &baton, ctx->wc_ctx,
-                                       baton.existing_parent_abspath
-                                         ? baton.existing_parent_abspath
-                                         : parent_abspath,
-                                       FALSE, pool, pool));
+  SVN_WC__CALL_WITH_WRITE_LOCK(
+    add(local_abspath, depth, force, no_ignore, existing_parent_abspath,
+        ctx, pool),
+    ctx->wc_ctx,
+    existing_parent_abspath ? existing_parent_abspath : parent_abspath,
+    FALSE /* lock_anchor */, pool);
   return SVN_NO_ERROR;
 }
 
@@ -819,6 +810,11 @@ mkdir_urls(const apr_array_header_t *url
       const char *bname;
       svn_uri_split(&common, &bname, common, pool);
       APR_ARRAY_PUSH(targets, const char *) = bname;
+
+      if (*bname == '\0')
+        return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
+                                 _("There is no valid uri above '%s'"),
+                                 common);
     }
   else
     {
@@ -841,6 +837,12 @@ mkdir_urls(const apr_array_header_t *url
           const char *bname;
 
           svn_uri_split(&common, &bname, common, pool);
+
+          if (*bname == '\0')
+             return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
+                                      _("There is no valid uri above '%s'"),
+                                      common);
+
           for (i = 0; i < targets->nelts; i++)
             {
               const char *path = APR_ARRAY_IDX(targets, i, const char *);
@@ -895,6 +897,9 @@ mkdir_urls(const apr_array_header_t *url
                                                  ctx, pool));
 
   /* Fetch RA commit editor */
+  SVN_ERR(svn_ra__register_editor_shim_callbacks(ra_session,
+                        svn_client__get_shim_callbacks(ctx->wc_ctx, NULL,
+                                                       pool)));
   SVN_ERR(svn_ra_get_commit_editor3(ra_session, &editor, &edit_baton,
                                     commit_revprops,
                                     commit_callback,

Modified: subversion/branches/javahl-ra/subversion/libsvn_client/checkout.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_client/checkout.c?rev=1329209&r1=1329208&r2=1329209&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_client/checkout.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_client/checkout.c Mon Apr 23 12:32:48 2012
@@ -49,10 +49,7 @@
 
 static svn_error_t *
 initialize_area(const char *local_abspath,
-                const char *session_url,
-                const char *repos_root,
-                const char *uuid,
-                svn_revnum_t revnum,
+                const svn_client__pathrev_t *pathrev,
                 svn_depth_t depth,
                 svn_client_ctx_t *ctx,
                 apr_pool_t *pool)
@@ -61,8 +58,9 @@ initialize_area(const char *local_abspat
     depth = svn_depth_infinity;
 
   /* Make the unversioned directory into a versioned one.  */
-  SVN_ERR(svn_wc_ensure_adm4(ctx->wc_ctx, local_abspath, session_url,
-                             repos_root, uuid, revnum, depth, pool));
+  SVN_ERR(svn_wc_ensure_adm4(ctx->wc_ctx, local_abspath, pathrev->url,
+                             pathrev->repos_root_url, pathrev->repos_uuid,
+                             pathrev->rev, depth, pool));
   return SVN_NO_ERROR;
 }
 
@@ -73,7 +71,6 @@ svn_client__checkout_internal(svn_revnum
                               const char *local_abspath,
                               const svn_opt_revision_t *peg_revision,
                               const svn_opt_revision_t *revision,
-                              const svn_client__ra_session_from_path_results *ra_cache,
                               svn_depth_t depth,
                               svn_boolean_t ignore_externals,
                               svn_boolean_t allow_unver_obstructions,
@@ -82,12 +79,12 @@ svn_client__checkout_internal(svn_revnum
                               apr_pool_t *pool)
 {
   svn_error_t *err = NULL;
-  svn_revnum_t revnum;
   svn_boolean_t sleep_here = FALSE;
   svn_boolean_t *use_sleep = timestamp_sleep ? timestamp_sleep : &sleep_here;
-  const char *session_url;
   svn_node_kind_t kind;
-  const char *uuid, *repos_root;
+  apr_pool_t *session_pool = svn_pool_create(pool);
+  svn_ra_session_t *ra_session;
+  svn_client__pathrev_t *pathrev;
 
   /* Sanity check.  Without these, the checkout is meaningless. */
   SVN_ERR_ASSERT(local_abspath != NULL);
@@ -100,68 +97,23 @@ svn_client__checkout_internal(svn_revnum
       && (revision->kind != svn_opt_revision_head))
     return svn_error_create(SVN_ERR_CLIENT_BAD_REVISION, NULL, NULL);
 
-  {
-    svn_boolean_t have_repos_root_url;
-    svn_boolean_t have_repos_uuid;
-    svn_boolean_t have_session_url;
-    svn_boolean_t have_revnum;
-    svn_boolean_t have_kind;
-
-    if ((have_repos_root_url = (ra_cache && ra_cache->repos_root_url)))
-      repos_root = ra_cache->repos_root_url;
-
-    if ((have_repos_uuid = (ra_cache && ra_cache->repos_uuid)))
-      uuid = ra_cache->repos_uuid;
-
-    if ((have_session_url = (ra_cache && ra_cache->ra_session_url)))
-      session_url = ra_cache->ra_session_url;
-
-    if ((have_revnum = (ra_cache && SVN_IS_VALID_REVNUM(ra_cache->ra_revnum))))
-      revnum = ra_cache->ra_revnum;
-
-    if ((have_kind = (ra_cache && ra_cache->kind != svn_node_unknown)))
-      kind = ra_cache->kind;
-
-    if (! have_repos_root_url || ! have_repos_uuid || ! have_session_url ||
-        ! have_revnum || ! have_kind)
-      {
-        apr_pool_t *session_pool = svn_pool_create(pool);
-        svn_ra_session_t *ra_session;
-        svn_revnum_t tmp_revnum;
-        const char *tmp_session_url;
-
-        /* Get the RA connection. */
-        SVN_ERR(svn_client__ra_session_from_path(&ra_session, &tmp_revnum,
-                                                 &tmp_session_url, url, NULL,
-                                                 peg_revision, revision, ctx,
-                                                 session_pool));
-
-        if (! have_repos_root_url)
-          SVN_ERR(svn_ra_get_repos_root2(ra_session, &repos_root, pool));
-
-        if (! have_repos_uuid)
-          SVN_ERR(svn_ra_get_uuid2(ra_session, &uuid, pool));
-
-        if (! have_session_url)
-          session_url = apr_pstrdup(pool, tmp_session_url);
-
-        if (! have_revnum)
-          revnum = tmp_revnum;
-
-        if (! have_kind)
-          SVN_ERR(svn_ra_check_path(ra_session, "", revnum, &kind, pool));
-
-        svn_pool_destroy(session_pool);
-      }
-  }
+  /* Get the RA connection. */
+  SVN_ERR(svn_client__ra_session_from_path2(&ra_session, &pathrev,
+                                            url, NULL, peg_revision, revision,
+                                            ctx, session_pool));
+
+  pathrev = svn_client__pathrev_dup(pathrev, pool);
+  SVN_ERR(svn_ra_check_path(ra_session, "", pathrev->rev, &kind, pool));
+
+  svn_pool_destroy(session_pool);
 
   if (kind == svn_node_none)
     return svn_error_createf(SVN_ERR_RA_ILLEGAL_URL, NULL,
-                             _("URL '%s' doesn't exist"), session_url);
+                             _("URL '%s' doesn't exist"), pathrev->url);
   else if (kind == svn_node_file)
     return svn_error_createf
       (SVN_ERR_UNSUPPORTED_FEATURE , NULL,
-       _("URL '%s' refers to a file, not a directory"), session_url);
+       _("URL '%s' refers to a file, not a directory"), pathrev->url);
 
   SVN_ERR(svn_io_check_path(local_abspath, &kind, pool));
 
@@ -171,8 +123,7 @@ svn_client__checkout_internal(svn_revnum
          entries file should only have an entry for THIS_DIR with a
          URL, revnum, and an 'incomplete' flag.  */
       SVN_ERR(svn_io_make_dir_recursively(local_abspath, pool));
-      err = initialize_area(local_abspath, session_url,
-                            repos_root, uuid, revnum, depth, ctx, pool);
+      err = initialize_area(local_abspath, pathrev, depth, ctx, pool);
     }
   else if (kind == svn_node_dir)
     {
@@ -182,8 +133,7 @@ svn_client__checkout_internal(svn_revnum
       SVN_ERR(svn_wc_check_wc2(&wc_format, ctx->wc_ctx, local_abspath, pool));
       if (! wc_format)
         {
-          err = initialize_area(local_abspath, session_url,
-                                repos_root, uuid, revnum, depth, ctx, pool);
+          err = initialize_area(local_abspath, pathrev, depth, ctx, pool);
         }
       else
         {
@@ -194,7 +144,7 @@ svn_client__checkout_internal(svn_revnum
           /* If PATH's existing URL matches the incoming one, then
              just update.  This allows 'svn co' to restart an
              interrupted checkout.  Otherwise bail out. */
-          if (strcmp(entry_url, session_url) != 0)
+          if (strcmp(entry_url, pathrev->url) != 0)
             return svn_error_createf(
                           SVN_ERR_WC_OBSTRUCTED_UPDATE, NULL,
                           _("'%s' is already a working copy for a"
@@ -253,7 +203,7 @@ svn_client_checkout3(svn_revnum_t *resul
   SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, pool));
 
   return svn_client__checkout_internal(result_rev, URL, local_abspath,
-                                       peg_revision, revision, NULL, depth,
+                                       peg_revision, revision, depth,
                                        ignore_externals,
                                        allow_unver_obstructions, NULL,
                                        ctx, pool);

Modified: subversion/branches/javahl-ra/subversion/libsvn_client/client.h
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_client/client.h?rev=1329209&r1=1329208&r2=1329209&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_client/client.h (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_client/client.h Mon Apr 23 12:32:48 2012
@@ -36,6 +36,7 @@
 #include "svn_client.h"
 
 #include "private/svn_magic.h"
+#include "private/svn_client_private.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -143,10 +144,27 @@ svn_client__repos_locations(const char *
                             svn_client_ctx_t *ctx,
                             apr_pool_t *pool);
 
+/* Trace a line of history of a particular versioned resource back to a
+ * specific revision.
+ *
+ * Set *OP_LOC_P to the location that the object PEG_LOC had in
+ * revision OP_REVNUM.
+ *
+ * RA_SESSION is an open RA session to the correct repository; it may be
+ * temporarily reparented inside this function. */
+svn_error_t *
+svn_client__repos_location(svn_client__pathrev_t **op_loc_p,
+                           svn_ra_session_t *ra_session,
+                           const svn_client__pathrev_t *peg_loc,
+                           svn_revnum_t op_revnum,
+                           svn_client_ctx_t *ctx,
+                           apr_pool_t *result_pool,
+                           apr_pool_t *scratch_pool);
+
 
 /* Set *SEGMENTS to an array of svn_location_segment_t * objects, each
-   representing a reposition location segment for the history of PATH
-   (which is relative to RA_SESSION's session URL) in PEG_REVISION
+   representing a reposition location segment for the history of URL
+   in PEG_REVISION
    between END_REVISION and START_REVISION, ordered from oldest
    segment to youngest.  *SEGMENTS may be empty but it will never
    be NULL.
@@ -155,13 +173,16 @@ svn_client__repos_locations(const char *
    svn_ra_get_location_segments() interface, which see for the rules
    governing PEG_REVISION, START_REVISION, and END_REVISION.
 
+   RA_SESSION is an RA session open to the repository of URL; it may be
+   temporarily reparented within this function.
+
    CTX is the client context baton.
 
    Use POOL for all allocations.  */
 svn_error_t *
 svn_client__repos_location_segments(apr_array_header_t **segments,
                                     svn_ra_session_t *ra_session,
-                                    const char *path,
+                                    const char *url,
                                     svn_revnum_t peg_revision,
                                     svn_revnum_t start_revision,
                                     svn_revnum_t end_revision,
@@ -169,22 +190,26 @@ svn_client__repos_location_segments(apr_
                                     apr_pool_t *pool);
 
 
-/* Set *ANCESTOR_PATH and *ANCESTOR_REVISION to the youngest common
-   ancestor path (a path relative to the root of the repository) and
-   revision, respectively, of the two locations identified as
-   PATH_OR_URL1@REV1 and PATH_OR_URL2@REV1.  Use the authentication
-   baton cached in CTX to authenticate against the repository.
-   This function assumes that PATH_OR_URL1@REV1 and PATH_OR_URL2@REV1
-   both refer to the same repository.  Use POOL for all allocations. */
-svn_error_t *
-svn_client__get_youngest_common_ancestor(const char **ancestor_path,
-                                         svn_revnum_t *ancestor_revision,
-                                         const char *path_or_url1,
-                                         svn_revnum_t rev1,
-                                         const char *path_or_url2,
-                                         svn_revnum_t rev2,
+/* Find the common ancestor of two locations in a repository.
+   Ancestry is determined by the 'copy-from' relationship and the normal
+   successor relationship.
+
+   Set *ANCESTOR_P to the location of the youngest common ancestor of
+   LOC1 and LOC2.  If the locations have no common ancestor (including if
+   they don't have the same repository root URL), set *ANCESTOR_P to NULL.
+
+   Use the authentication baton cached in CTX to authenticate against
+   the repository.  Use POOL for all allocations.
+
+   See also svn_client__youngest_common_ancestor().
+*/
+svn_error_t *
+svn_client__get_youngest_common_ancestor(svn_client__pathrev_t **ancestor_p,
+                                         const svn_client__pathrev_t *loc1,
+                                         const svn_client__pathrev_t *loc2,
                                          svn_client_ctx_t *ctx,
-                                         apr_pool_t *pool);
+                                         apr_pool_t *result_pool,
+                                         apr_pool_t *scratch_pool);
 
 /* Given PATH_OR_URL, which contains either a working copy path or an
    absolute URL, a peg revision PEG_REVISION, and a desired revision
@@ -198,8 +223,9 @@ svn_client__get_youngest_common_ancestor
    and should only be used if PATH_OR_URL is a url
      ### else NULL? what's it for?
 
-   If PEG_REVISION's kind is svn_opt_revision_unspecified, it is
-   interpreted as "head" for a URL or "working" for a working-copy path.
+   If PEG_REVISION->kind is 'unspecified', the peg revision is 'head'
+   for a URL or 'working' for a WC path.  If REVISION->kind is
+   'unspecified', the operative revision is the peg revision.
 
    Store the resulting ra_session in *RA_SESSION_P.  Store the actual
    revision number of the object in *REV_P, and the final resulting
@@ -220,12 +246,24 @@ svn_client__ra_session_from_path(svn_ra_
                                  svn_client_ctx_t *ctx,
                                  apr_pool_t *pool);
 
+/* Like svn_client__ra_session_from_path() but returning a path-rev
+ * instead of separate URL and rev outputs.  RESOLVED_LOC_P may be NULL
+ * if not wanted. */
+svn_error_t *
+svn_client__ra_session_from_path2(svn_ra_session_t **ra_session_p,
+                                 svn_client__pathrev_t **resolved_loc_p,
+                                 const char *path_or_url,
+                                 const char *base_dir_abspath,
+                                 const svn_opt_revision_t *peg_revision,
+                                 const svn_opt_revision_t *revision,
+                                 svn_client_ctx_t *ctx,
+                                 apr_pool_t *pool);
+
 /* Ensure that RA_SESSION's session URL matches SESSION_URL,
-   reparenting that session if necessary.  If reparenting occurs,
-   store the previous session URL in *OLD_SESSION_URL (so that if the
+   reparenting that session if necessary.
+   Store the previous session URL in *OLD_SESSION_URL (so that if the
    reparenting is meant to be temporary, the caller can reparent the
-   session back to where it was); otherwise set *OLD_SESSION_URL to
-   NULL.
+   session back to where it was).
 
    If SESSION_URL is NULL, treat this as a magic value meaning "point
    the RA session to the root of the repository".
@@ -240,8 +278,7 @@ svn_client__ra_session_from_path(svn_ra_
 
        [...]
 
-       if (old_session_url)
-         SVN_ERR(svn_ra_reparent(ra_session, old_session_url, pool));
+       SVN_ERR(svn_ra_reparent(ra_session, old_session_url, pool));
 */
 svn_error_t *
 svn_client__ensure_ra_session_url(const char **old_session_url,
@@ -468,36 +505,6 @@ svn_client__update_internal(svn_revnum_t
                             svn_client_ctx_t *ctx,
                             apr_pool_t *pool);
 
-/* Structure holding the results of svn_client__ra_session_from_path()
-   plus the repository root URL and UUID and the node kind for the
-   input URL, REVISION and PEG_REVISION .  See
-   svn_client__ra_session_from_path() for the meaning of these fields.
-   This structure is used by svn_client__checkout_internal() to save
-   one or more round-trips if the client already gathered some of this
-   information.  Not all the fields need to be filled in.  */
-typedef struct svn_client__ra_session_from_path_results
-{
-  /* The repository root URL.  A NULL value means the root URL is
-     unknown.*/
-  const char *repos_root_url;
-
-  /* The repository UUID.  A NULL value means the UUID is unknown.  */
-  const char *repos_uuid;
-
-  /* The actual final resulting URL for the input URL.  This may be
-     different because of copy history.  A NULL value means the
-     resulting URL is unknown.  */
-  const char *ra_session_url;
-
-  /* The actual final resulting revision for the input URL.  An
-     invalid revnum as determined by SVN_IS_VALID_REVNUM() means the
-     revnum is unknown.  */
-  svn_revnum_t ra_revnum;
-
-  /* An optional node kind for the URL.  svn_node_unknown if unknown */
-  svn_node_kind_t kind;
-} svn_client__ra_session_from_path_results;
-
 /* Checkout into LOCAL_ABSPATH a working copy of URL at REVISION, and (if not
    NULL) set RESULT_REV to the checked out revision.
 
@@ -534,7 +541,6 @@ svn_client__checkout_internal(svn_revnum
                               const char *local_abspath,
                               const svn_opt_revision_t *peg_revision,
                               const svn_opt_revision_t *revision,
-                              const svn_client__ra_session_from_path_results *ra_cache,
                               svn_depth_t depth,
                               svn_boolean_t ignore_externals,
                               svn_boolean_t allow_unver_obstructions,
@@ -842,7 +848,7 @@ svn_client__get_copy_committables(svn_cl
                                   apr_pool_t *scratch_pool);
 
 /* A qsort()-compatible sort routine for sorting an array of
-   svn_client_commit_item_t's by their URL member. */
+   svn_client_commit_item_t *'s by their URL member. */
 int svn_client__sort_commit_item_urls(const void *a, const void *b);
 
 
@@ -1073,6 +1079,11 @@ svn_client__get_normalized_stream(svn_st
                                   apr_pool_t *result_pool,
                                   apr_pool_t *scratch_pool);
 
+/* Return a set of callbacks to use with the Ev2 shims. */
+svn_delta_shim_callbacks_t *
+svn_client__get_shim_callbacks(svn_wc_context_t *wc_ctx,
+                               apr_hash_t *relpath_map,
+                               apr_pool_t *result_pool);
 
 /* Return true if KIND is a revision kind that is dependent on the working
  * copy. Otherwise, return false. */

Modified: subversion/branches/javahl-ra/subversion/libsvn_client/cmdline.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_client/cmdline.c?rev=1329209&r1=1329208&r2=1329209&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_client/cmdline.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_client/cmdline.c Mon Apr 23 12:32:48 2012
@@ -168,7 +168,6 @@ svn_client_args_to_target_array2(apr_arr
   int i;
   svn_boolean_t rel_url_found = FALSE;
   const char *root_url = NULL;
-  svn_error_t *err = SVN_NO_ERROR;
   apr_array_header_t *input_targets =
     apr_array_make(pool, DEFAULT_ARRAY_SIZE, sizeof(const char *));
   apr_array_header_t *output_targets =
@@ -348,6 +347,7 @@ svn_client_args_to_target_array2(apr_arr
       if (root_url == NULL)
         {
           const char *current_abspath;
+          svn_error_t *err;
 
           SVN_ERR(svn_dirent_get_absolute(&current_abspath, "", pool));
           err = svn_client_get_repos_root(&root_url, NULL /* uuid */,
@@ -391,11 +391,17 @@ svn_client_args_to_target_array2(apr_arr
   else
     *targets_p = output_targets;
 
-  if (reserved_names && ! err)
-    for (i = 0; i < reserved_names->nelts; ++i)
-      err = svn_error_createf(SVN_ERR_RESERVED_FILENAME_SPECIFIED, err,
-                              _("'%s' ends in a reserved name"),
-                              APR_ARRAY_IDX(reserved_names, i, const char *));
+  if (reserved_names)
+    {
+      svn_error_t *err = SVN_NO_ERROR;
+
+      for (i = 0; i < reserved_names->nelts; ++i)
+        err = svn_error_createf(SVN_ERR_RESERVED_FILENAME_SPECIFIED, err,
+                                _("'%s' ends in a reserved name"),
+                                APR_ARRAY_IDX(reserved_names, i,
+                                              const char *));
+      return svn_error_trace(err);
+    }
 
-  return svn_error_trace(err);
+  return SVN_NO_ERROR;
 }

Modified: subversion/branches/javahl-ra/subversion/libsvn_client/commit.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_client/commit.c?rev=1329209&r1=1329208&r2=1329209&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_client/commit.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_client/commit.c Mon Apr 23 12:32:48 2012
@@ -49,6 +49,8 @@
 
 #include "client.h"
 #include "private/svn_wc_private.h"
+#include "private/svn_subr_private.h"
+#include "private/svn_ra_private.h"
 #include "private/svn_magic.h"
 
 #include "svn_private_config.h"
@@ -76,7 +78,7 @@ typedef struct import_ctx_t
 } import_ctx_t;
 
 
-/* Apply PATH's contents (as a delta against the empty string) to
+/* Apply LOCAL_ABSPATH's contents (as a delta against the empty string) to
    FILE_BATON in EDITOR.  Use POOL for any temporary allocation.
    PROPERTIES is the set of node properties set on this file.
 
@@ -86,7 +88,7 @@ typedef struct import_ctx_t
 /* ### how does this compare against svn_wc_transmit_text_deltas2() ??? */
 
 static svn_error_t *
-send_file_contents(const char *path,
+send_file_contents(const char *local_abspath,
                    void *file_baton,
                    const svn_delta_editor_t *editor,
                    apr_hash_t *properties,
@@ -134,30 +136,36 @@ send_file_contents(const char *path,
 
   if (special)
     {
-      SVN_ERR(svn_subst_read_specialfile(&contents, path, pool, pool));
+      SVN_ERR(svn_subst_read_specialfile(&contents, local_abspath,
+                                         pool, pool));
     }
   else
     {
       /* Open the working copy file. */
-      SVN_ERR(svn_stream_open_readonly(&contents, path, pool, pool));
+      SVN_ERR(svn_stream_open_readonly(&contents, local_abspath, pool, pool));
 
       /* If we have EOL styles or keywords, then detranslate the file. */
       if (svn_subst_translation_required(eol_style, eol, keywords,
                                          FALSE, TRUE))
         {
-          svn_boolean_t repair = FALSE;
+          if (eol_style == svn_subst_eol_style_unknown)
+            return svn_error_createf(SVN_ERR_IO_UNKNOWN_EOL, NULL,
+                                    _("%s property on '%s' contains "
+                                      "unrecognized EOL-style '%s'"),
+                                    SVN_PROP_EOL_STYLE,
+                                    svn_dirent_local_style(local_abspath,
+                                                           pool),
+                                    eol_style_val->data);
 
+          /* We're importing, so translate files with 'native' eol-style to
+           * repository-normal form, not to this platform's native EOL. */
           if (eol_style == svn_subst_eol_style_native)
             eol = SVN_SUBST_NATIVE_EOL_STR;
-          else if (eol_style == svn_subst_eol_style_fixed)
-            repair = TRUE;
-          else if (eol_style != svn_subst_eol_style_none)
-            return svn_error_create(SVN_ERR_IO_UNKNOWN_EOL, NULL, NULL);
 
           /* Wrap the working copy stream with a filter to detranslate it. */
           contents = svn_subst_stream_translated(contents,
                                                  eol,
-                                                 repair,
+                                                 TRUE /* repair */,
                                                  keywords,
                                                  FALSE /* expand */,
                                                  pool);
@@ -185,8 +193,9 @@ send_file_contents(const char *path,
 static svn_error_t *
 import_file(const svn_delta_editor_t *editor,
             void *dir_baton,
-            const char *path,
+            const char *local_abspath,
             const char *edit_path,
+            const svn_io_dirent2_t *dirent,
             import_ctx_t *import_ctx,
             svn_client_ctx_t *ctx,
             apr_pool_t *pool)
@@ -197,12 +206,8 @@ import_file(const svn_delta_editor_t *ed
   const char *text_checksum;
   apr_hash_t* properties;
   apr_hash_index_t *hi;
-  svn_node_kind_t kind;
-  svn_boolean_t is_special;
-
-  SVN_ERR(svn_path_check_valid(path, pool));
 
-  SVN_ERR(svn_io_check_special_path(path, &kind, &is_special, pool));
+  SVN_ERR(svn_path_check_valid(local_abspath, pool));
 
   /* Add the file, using the pool from the FILES hash. */
   SVN_ERR(editor->add_file(edit_path, dir_baton, NULL, SVN_INVALID_REVNUM,
@@ -211,10 +216,10 @@ import_file(const svn_delta_editor_t *ed
   /* Remember that the repository was modified */
   import_ctx->repos_changed = TRUE;
 
-  if (! is_special)
+  if (! dirent->special)
     {
       /* add automatic properties */
-      SVN_ERR(svn_client__get_auto_props(&properties, &mimetype, path,
+      SVN_ERR(svn_client__get_auto_props(&properties, &mimetype, local_abspath,
                                          import_ctx->magic_cookie,
                                          ctx, pool));
     }
@@ -235,7 +240,8 @@ import_file(const svn_delta_editor_t *ed
   if (ctx->notify_func2)
     {
       svn_wc_notify_t *notify
-        = svn_wc_create_notify(path, svn_wc_notify_commit_added, pool);
+        = svn_wc_create_notify(local_abspath, svn_wc_notify_commit_added,
+                               pool);
       notify->kind = svn_node_file;
       notify->mime_type = mimetype;
       notify->content_state = notify->prop_state
@@ -247,7 +253,7 @@ import_file(const svn_delta_editor_t *ed
   /* If this is a special file, we need to set the svn:special
      property and create a temporary detranslated version in order to
      send to the server. */
-  if (is_special)
+  if (dirent->special)
     {
       apr_hash_set(properties, SVN_PROP_SPECIAL, APR_HASH_KEY_STRING,
                    svn_string_create(SVN_PROP_BOOLEAN_TRUE, pool));
@@ -259,75 +265,53 @@ import_file(const svn_delta_editor_t *ed
     }
 
   /* Now, transmit the file contents. */
-  SVN_ERR(send_file_contents(path, file_baton, editor,
+  SVN_ERR(send_file_contents(local_abspath, file_baton, editor,
                              properties, digest, pool));
 
   /* Finally, close the file. */
   text_checksum =
-    svn_checksum_to_cstring(svn_checksum__from_digest(digest, svn_checksum_md5,
-                                                      pool), pool);
+    svn_checksum_to_cstring(svn_checksum__from_digest_md5(digest, pool), pool);
 
   return editor->close_file(file_baton, text_checksum, pool);
 }
 
 
-/* Import directory PATH into the repository directory indicated by
- * DIR_BATON in EDITOR.  EDIT_PATH is the path imported as the root
- * directory, so all edits are relative to that.
- *
- * DEPTH is the depth at this point in the descent (it may be changed
- * for recursive calls).
- *
- * Accumulate file paths and their batons in FILES, which must be
- * non-null.  (These are used to send postfix textdeltas later).
- *
- * EXCLUDES is a hash whose keys are absolute paths to exclude from
- * the import (values are unused).
+/* Return in CHILDREN a mapping of basenames to dirents for the importable
+ * children of DIR_ABSPATH.  EXCLUDES is a hash of absolute paths to filter
+ * out.  IGNORES, if non-NULL, is a list of basenames to filter out.
+ * FILTER_CALLBACK and FILTER_BATON will be called for each absolute path,
+ * allowing users to further filter the list of returned entries.
  *
- * If NO_IGNORE is FALSE, don't import files or directories that match
- * ignore patterns.
- *
- * If CTX->NOTIFY_FUNC is non-null, invoke it with CTX->NOTIFY_BATON for each
- * directory.
- *
- * Use POOL for any temporary allocation.  */
+ * Results are returned in RESULT_POOL; use SCRATCH_POOL for temporary data.*/
 static svn_error_t *
-import_dir(const svn_delta_editor_t *editor,
-           void *dir_baton,
-           const char *path,
-           const char *edit_path,
-           svn_depth_t depth,
-           apr_hash_t *excludes,
-           svn_boolean_t no_ignore,
-           svn_boolean_t ignore_unknown_node_types,
-           import_ctx_t *import_ctx,
-           svn_client_ctx_t *ctx,
-           apr_pool_t *pool)
+get_filtered_children(apr_hash_t **children,
+                      const char *dir_abspath,
+                      apr_hash_t *excludes,
+                      apr_array_header_t *ignores,
+                      svn_client_import_filter_func_t filter_callback,
+                      void *filter_baton,
+                      svn_client_ctx_t *ctx,
+                      apr_pool_t *result_pool,
+                      apr_pool_t *scratch_pool)
 {
-  apr_pool_t *subpool = svn_pool_create(pool);  /* iteration pool */
   apr_hash_t *dirents;
   apr_hash_index_t *hi;
-  apr_array_header_t *ignores;
-
-  SVN_ERR(svn_path_check_valid(path, pool));
-
-  if (!no_ignore)
-    SVN_ERR(svn_wc_get_default_ignores(&ignores, ctx->config, pool));
+  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
 
-  SVN_ERR(svn_io_get_dirents3(&dirents, path, TRUE, pool, pool));
+  SVN_ERR(svn_io_get_dirents3(&dirents, dir_abspath, TRUE, result_pool,
+                              scratch_pool));
 
-  for (hi = apr_hash_first(pool, dirents); hi; hi = apr_hash_next(hi))
+  for (hi = apr_hash_first(scratch_pool, dirents); hi; hi = apr_hash_next(hi))
     {
-      const char *this_path, *this_edit_path, *abs_path;
-      const char *filename = svn__apr_hash_index_key(hi);
-      const svn_io_dirent_t *dirent = svn__apr_hash_index_val(hi);
+      const char *base_name = svn__apr_hash_index_key(hi);
+      const svn_io_dirent2_t *dirent = svn__apr_hash_index_val(hi);
+      const char *local_abspath;
 
-      svn_pool_clear(subpool);
+      svn_pool_clear(iterpool);
 
-      if (ctx->cancel_func)
-        SVN_ERR(ctx->cancel_func(ctx->cancel_baton));
+      local_abspath = svn_dirent_join(dir_abspath, base_name, iterpool);
 
-      if (svn_wc_is_adm_dir(filename, subpool))
+      if (svn_wc_is_adm_dir(base_name, iterpool))
         {
           /* If someone's trying to import a directory named the same
              as our administrative directories, that's probably not
@@ -338,82 +322,125 @@ import_dir(const svn_delta_editor_t *edi
           if (ctx->notify_func2)
             {
               svn_wc_notify_t *notify
-                = svn_wc_create_notify(svn_dirent_join(path, filename,
-                                                       subpool),
-                                       svn_wc_notify_skip, subpool);
+                = svn_wc_create_notify(svn_dirent_join(local_abspath, base_name,
+                                                       iterpool),
+                                       svn_wc_notify_skip, iterpool);
               notify->kind = svn_node_dir;
               notify->content_state = notify->prop_state
                 = svn_wc_notify_state_inapplicable;
               notify->lock_state = svn_wc_notify_lock_state_inapplicable;
-              (*ctx->notify_func2)(ctx->notify_baton2, notify, subpool);
+              (*ctx->notify_func2)(ctx->notify_baton2, notify, iterpool);
             }
+
+          apr_hash_set(dirents, base_name, APR_HASH_KEY_STRING, NULL);
+          continue;
+        }
+            /* If this is an excluded path, exclude it. */
+      if (apr_hash_get(excludes, local_abspath, APR_HASH_KEY_STRING))
+        {
+          apr_hash_set(dirents, base_name, APR_HASH_KEY_STRING, NULL);
           continue;
         }
 
-      /* Typically, we started importing from ".", in which case
-         edit_path is "".  So below, this_path might become "./blah",
-         and this_edit_path might become "blah", for example. */
-      this_path = svn_dirent_join(path, filename, subpool);
-      this_edit_path = svn_relpath_join(edit_path, filename, subpool);
-
-      /* If this is an excluded path, exclude it. */
-      SVN_ERR(svn_dirent_get_absolute(&abs_path, this_path, subpool));
-      if (apr_hash_get(excludes, abs_path, APR_HASH_KEY_STRING))
-        continue;
-
-      if ((!no_ignore) && svn_wc_match_ignore_list(filename, ignores,
-                                                   subpool))
-        continue;
-
-      if (dirent->kind == svn_node_dir && depth >= svn_depth_immediates)
+      if (ignores && svn_wc_match_ignore_list(base_name, ignores, iterpool))
         {
-          void *this_dir_baton;
+          apr_hash_set(dirents, base_name, APR_HASH_KEY_STRING, NULL);
+          continue;
+        }
 
-          /* Add the new subdirectory, getting a descent baton from
-             the editor. */
-          SVN_ERR(editor->add_directory(this_edit_path, dir_baton,
-                                        NULL, SVN_INVALID_REVNUM, subpool,
-                                        &this_dir_baton));
+      if (filter_callback)
+        {
+          svn_boolean_t filter = FALSE;
 
-          /* Remember that the repository was modified */
-          import_ctx->repos_changed = TRUE;
+          SVN_ERR(filter_callback(filter_baton, &filter, local_abspath,
+                                  dirent, iterpool));
 
-          /* By notifying before the recursive call below, we display
-             a directory add before displaying adds underneath the
-             directory.  To do it the other way around, just move this
-             after the recursive call. */
-          if (ctx->notify_func2)
+          if (filter)
             {
-              svn_wc_notify_t *notify
-                = svn_wc_create_notify(this_path, svn_wc_notify_commit_added,
-                                       subpool);
-              notify->kind = svn_node_dir;
-              notify->content_state = notify->prop_state
-                = svn_wc_notify_state_inapplicable;
-              notify->lock_state = svn_wc_notify_lock_state_inapplicable;
-              (*ctx->notify_func2)(ctx->notify_baton2, notify, subpool);
+              apr_hash_set(dirents, base_name, APR_HASH_KEY_STRING, NULL);
+              continue;
             }
+        }
+    }
+  svn_pool_destroy(iterpool);
 
-          /* Recurse. */
-          {
-            svn_depth_t depth_below_here = depth;
-            if (depth == svn_depth_immediates)
-              depth_below_here = svn_depth_empty;
-
-            SVN_ERR(import_dir(editor, this_dir_baton, this_path,
-                               this_edit_path, depth_below_here, excludes,
-                               no_ignore, ignore_unknown_node_types,
-                               import_ctx, ctx,
-                               subpool));
-          }
+  *children = dirents;
+  return SVN_NO_ERROR;
+}
 
-          /* Finally, close the sub-directory. */
-          SVN_ERR(editor->close_directory(this_dir_baton, subpool));
+static svn_error_t *
+import_dir(const svn_delta_editor_t *editor,
+           void *dir_baton,
+           const char *local_abspath,
+           const char *edit_path,
+           svn_depth_t depth,
+           apr_hash_t *excludes,
+           svn_boolean_t no_ignore,
+           svn_boolean_t ignore_unknown_node_types,
+           svn_client_import_filter_func_t filter_callback,
+           void *filter_baton,
+           import_ctx_t *import_ctx,
+           svn_client_ctx_t *ctx,
+           apr_pool_t *pool);
+
+
+/* Import the children of DIR_ABSPATH, with other arguments similar to
+ * import_dir(). */
+static svn_error_t *
+import_children(const char *dir_abspath,
+                const char *edit_path,
+                apr_hash_t *dirents,
+                const svn_delta_editor_t *editor,
+                void *dir_baton,
+                svn_depth_t depth,
+                apr_hash_t *excludes,
+                svn_boolean_t no_ignore,
+                svn_boolean_t ignore_unknown_node_types,
+                svn_client_import_filter_func_t filter_callback,
+                void *filter_baton,
+                import_ctx_t *import_ctx,
+                svn_client_ctx_t *ctx,
+                apr_pool_t *scratch_pool)
+{
+  apr_hash_index_t *hi;
+  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+
+  for (hi = apr_hash_first(scratch_pool, dirents); hi; hi = apr_hash_next(hi))
+    {
+      const char *this_abspath, *this_edit_path;
+      const char *filename = svn__apr_hash_index_key(hi);
+      const svn_io_dirent2_t *dirent = svn__apr_hash_index_val(hi);
+
+      svn_pool_clear(iterpool);
+
+      if (ctx->cancel_func)
+        SVN_ERR(ctx->cancel_func(ctx->cancel_baton));
+
+      /* Typically, we started importing from ".", in which case
+         edit_path is "".  So below, this_path might become "./blah",
+         and this_edit_path might become "blah", for example. */
+      this_abspath = svn_dirent_join(dir_abspath, filename, iterpool);
+      this_edit_path = svn_relpath_join(edit_path, filename, iterpool);
+
+      if (dirent->kind == svn_node_dir && depth >= svn_depth_immediates)
+        {
+          /* Recurse. */
+          svn_depth_t depth_below_here = depth;
+          if (depth == svn_depth_immediates)
+            depth_below_here = svn_depth_empty;
+
+          SVN_ERR(import_dir(editor, dir_baton, this_abspath,
+                             this_edit_path, depth_below_here, excludes,
+                             no_ignore, ignore_unknown_node_types,
+                             filter_callback, filter_baton,
+                             import_ctx, ctx,
+                             iterpool));
         }
       else if (dirent->kind == svn_node_file && depth >= svn_depth_files)
         {
-          SVN_ERR(import_file(editor, dir_baton, this_path,
-                              this_edit_path, import_ctx, ctx, subpool));
+          SVN_ERR(import_file(editor, dir_baton, this_abspath,
+                              this_edit_path, dirent,
+                              import_ctx, ctx, iterpool));
         }
       else if (dirent->kind != svn_node_dir && dirent->kind != svn_node_file)
         {
@@ -423,24 +450,115 @@ import_dir(const svn_delta_editor_t *edi
               if (ctx->notify_func2)
                 {
                   svn_wc_notify_t *notify
-                    = svn_wc_create_notify(this_path,
-                                           svn_wc_notify_skip, subpool);
+                    = svn_wc_create_notify(this_abspath,
+                                           svn_wc_notify_skip, iterpool);
                   notify->kind = svn_node_dir;
                   notify->content_state = notify->prop_state
                     = svn_wc_notify_state_inapplicable;
                   notify->lock_state = svn_wc_notify_lock_state_inapplicable;
-                  (*ctx->notify_func2)(ctx->notify_baton2, notify, subpool);
+                  (*ctx->notify_func2)(ctx->notify_baton2, notify, iterpool);
                 }
             }
           else
             return svn_error_createf
               (SVN_ERR_NODE_UNKNOWN_KIND, NULL,
                _("Unknown or unversionable type for '%s'"),
-               svn_dirent_local_style(this_path, subpool));
+               svn_dirent_local_style(this_abspath, iterpool));
         }
     }
 
-  svn_pool_destroy(subpool);
+  svn_pool_destroy(iterpool);
+  return SVN_NO_ERROR;
+}
+
+
+/* Import directory LOCAL_ABSPATH into the repository directory indicated by
+ * DIR_BATON in EDITOR.  EDIT_PATH is the path imported as the root
+ * directory, so all edits are relative to that.
+ *
+ * DEPTH is the depth at this point in the descent (it may be changed
+ * for recursive calls).
+ *
+ * Accumulate file paths and their batons in FILES, which must be
+ * non-null.  (These are used to send postfix textdeltas later).
+ *
+ * EXCLUDES is a hash whose keys are absolute paths to exclude from
+ * the import (values are unused).
+ *
+ * If NO_IGNORE is FALSE, don't import files or directories that match
+ * ignore patterns.
+ *
+ * If FILTER_CALLBACK is not NULL, call it with FILTER_BATON on each to be
+ * imported node below LOCAL_ABSPATH to allow filtering nodes.
+ *
+ * If CTX->NOTIFY_FUNC is non-null, invoke it with CTX->NOTIFY_BATON for each
+ * directory.
+ *
+ * Use POOL for any temporary allocation.  */
+static svn_error_t *
+import_dir(const svn_delta_editor_t *editor,
+           void *dir_baton,
+           const char *local_abspath,
+           const char *edit_path,
+           svn_depth_t depth,
+           apr_hash_t *excludes,
+           svn_boolean_t no_ignore,
+           svn_boolean_t ignore_unknown_node_types,
+           svn_client_import_filter_func_t filter_callback,
+           void *filter_baton,
+           import_ctx_t *import_ctx,
+           svn_client_ctx_t *ctx,
+           apr_pool_t *pool)
+{
+  apr_hash_t *dirents;
+  apr_array_header_t *ignores = NULL;
+  void *this_dir_baton;
+
+  SVN_ERR(svn_path_check_valid(local_abspath, pool));
+
+  if (!no_ignore)
+    SVN_ERR(svn_wc_get_default_ignores(&ignores, ctx->config, pool));
+
+  SVN_ERR(get_filtered_children(&dirents, local_abspath, excludes, ignores,
+                                filter_callback, filter_baton, ctx,
+                                pool, pool));
+
+  /* Import this directory, but not yet its children. */
+  {
+    /* Add the new subdirectory, getting a descent baton from the editor. */
+    SVN_ERR(editor->add_directory(edit_path, dir_baton, NULL,
+                                  SVN_INVALID_REVNUM, pool, &this_dir_baton));
+
+    /* Remember that the repository was modified */
+    import_ctx->repos_changed = TRUE;
+
+    /* By notifying before the recursive call below, we display
+       a directory add before displaying adds underneath the
+       directory.  To do it the other way around, just move this
+       after the recursive call. */
+    if (ctx->notify_func2)
+      {
+        svn_wc_notify_t *notify
+          = svn_wc_create_notify(local_abspath, svn_wc_notify_commit_added,
+                                 pool);
+        notify->kind = svn_node_dir;
+        notify->content_state = notify->prop_state
+          = svn_wc_notify_state_inapplicable;
+        notify->lock_state = svn_wc_notify_lock_state_inapplicable;
+        (*ctx->notify_func2)(ctx->notify_baton2, notify, pool);
+      }
+  }
+
+  /* Now import the children recursively. */
+  SVN_ERR(import_children(local_abspath, edit_path, dirents, editor,
+                          this_dir_baton, depth, excludes, no_ignore,
+                          ignore_unknown_node_types,
+                          filter_callback, filter_baton,
+                          import_ctx, ctx, pool));
+
+  /* Finally, close the sub-directory. */
+  SVN_ERR(editor->close_directory(this_dir_baton, pool));
+
   return SVN_NO_ERROR;
 }
 
@@ -481,7 +599,7 @@ import_dir(const svn_delta_editor_t *edi
  * not necessarily the root.)
  */
 static svn_error_t *
-import(const char *path,
+import(const char *local_abspath,
        const apr_array_header_t *new_entries,
        const svn_delta_editor_t *editor,
        void *edit_baton,
@@ -489,15 +607,17 @@ import(const char *path,
        apr_hash_t *excludes,
        svn_boolean_t no_ignore,
        svn_boolean_t ignore_unknown_node_types,
+       svn_client_import_filter_func_t filter_callback,
+       void *filter_baton,
        svn_client_ctx_t *ctx,
        apr_pool_t *pool)
 {
   void *root_baton;
-  svn_node_kind_t kind;
-  apr_array_header_t *ignores;
+  apr_array_header_t *ignores = NULL;
   apr_array_header_t *batons = NULL;
   const char *edit_path = "";
   import_ctx_t *import_ctx = apr_pcalloc(pool, sizeof(*import_ctx));
+  const svn_io_dirent2_t *dirent;
 
   svn_magic__init(&import_ctx->magic_cookie, pool);
 
@@ -508,7 +628,7 @@ import(const char *path,
                             pool, &root_baton));
 
   /* Import a file or a directory tree. */
-  SVN_ERR(svn_io_check_path(path, &kind, pool));
+  SVN_ERR(svn_io_stat_dirent(&dirent, local_abspath, FALSE, pool, pool));
 
   /* Make the intermediate directory components necessary for properly
      rooting our import source tree.  */
@@ -525,7 +645,7 @@ import(const char *path,
           /* If this is the last path component, and we're importing a
              file, then this component is the name of the file, not an
              intermediate directory. */
-          if ((i == new_entries->nelts - 1) && (kind == svn_node_file))
+          if ((i == new_entries->nelts - 1) && (dirent->kind == svn_node_file))
             break;
 
           APR_ARRAY_PUSH(batons, void *) = root_baton;
@@ -538,7 +658,7 @@ import(const char *path,
           import_ctx->repos_changed = TRUE;
         }
     }
-  else if (kind == svn_node_file)
+  else if (dirent->kind == svn_node_file)
     {
       return svn_error_create
         (SVN_ERR_NODE_UNKNOWN_KIND, NULL,
@@ -553,32 +673,46 @@ import(const char *path,
      if something underneath it also has our reserved name, then we'll
      error. */
 
-  if (kind == svn_node_file)
+  if (dirent->kind == svn_node_file)
     {
+      /* This code path ignores EXCLUDES and FILTER, but they don't make
+         much sense for a single file import anyway. */
       svn_boolean_t ignores_match = FALSE;
 
       if (!no_ignore)
         {
           SVN_ERR(svn_wc_get_default_ignores(&ignores, ctx->config, pool));
-          ignores_match = svn_wc_match_ignore_list(path, ignores, pool);
+          ignores_match = svn_wc_match_ignore_list(local_abspath,
+                                                   ignores, pool);
         }
       if (!ignores_match)
-        SVN_ERR(import_file(editor, root_baton, path, edit_path,
-                            import_ctx, ctx, pool));
+        SVN_ERR(import_file(editor, root_baton, local_abspath, edit_path,
+                            dirent, import_ctx, ctx, pool));
     }
-  else if (kind == svn_node_dir)
+  else if (dirent->kind == svn_node_dir)
     {
-      SVN_ERR(import_dir(editor, root_baton, path, edit_path,
-                         depth, excludes, no_ignore,
-                         ignore_unknown_node_types, import_ctx, ctx, pool));
+      apr_hash_t *dirents;
+
+      if (!no_ignore)
+        SVN_ERR(svn_wc_get_default_ignores(&ignores, ctx->config, pool));
+
+      SVN_ERR(get_filtered_children(&dirents, local_abspath, excludes, ignores,
+                                    filter_callback, filter_baton, ctx,
+                                    pool, pool));
+
+      SVN_ERR(import_children(local_abspath, edit_path, dirents, editor,
+                              root_baton, depth, excludes, no_ignore,
+                              ignore_unknown_node_types,
+                              filter_callback, filter_baton,
+                              import_ctx, ctx, pool));
 
     }
-  else if (kind == svn_node_none
-           || kind == svn_node_unknown)
+  else if (dirent->kind == svn_node_none
+           || dirent->kind == svn_node_unknown)
     {
       return svn_error_createf(SVN_ERR_NODE_UNKNOWN_KIND, NULL,
                                _("'%s' does not exist"),
-                               svn_dirent_local_style(path, pool));
+                               svn_dirent_local_style(local_abspath, pool));
     }
 
   /* Close up shop; it's time to go home. */
@@ -625,16 +759,13 @@ capture_commit_info(const svn_commit_inf
 
 
 static svn_error_t *
-get_ra_editor(svn_ra_session_t **ra_session,
-              const svn_delta_editor_t **editor,
+get_ra_editor(const svn_delta_editor_t **editor,
               void **edit_baton,
+              svn_ra_session_t *ra_session,
               svn_client_ctx_t *ctx,
-              const char *base_url,
-              const char *base_dir_abspath,
               const char *log_msg,
               const apr_array_header_t *commit_items,
               const apr_hash_t *revprop_table,
-              svn_boolean_t is_commit,
               apr_hash_t *lock_tokens,
               svn_boolean_t keep_locks,
               svn_commit_callback2_t commit_callback,
@@ -642,32 +773,43 @@ get_ra_editor(svn_ra_session_t **ra_sess
               apr_pool_t *pool)
 {
   apr_hash_t *commit_revprops;
-
-  /* Open an RA session to URL. */
-  SVN_ERR(svn_client__open_ra_session_internal(ra_session, NULL, base_url,
-                                               base_dir_abspath, commit_items,
-                                               is_commit, !is_commit,
-                                               ctx, pool));
-
-  /* If this is an import (aka, not a commit), we need to verify that
-     our repository URL exists. */
-  if (! is_commit)
-    {
-      svn_node_kind_t kind;
-
-      SVN_ERR(svn_ra_check_path(*ra_session, "", SVN_INVALID_REVNUM,
-                                &kind, pool));
-      if (kind == svn_node_none)
-        return svn_error_createf(SVN_ERR_FS_NO_SUCH_ENTRY, NULL,
-                                 _("Path '%s' does not exist"),
-                                 base_url);
-    }
+  apr_hash_t *relpath_map = NULL;
 
   SVN_ERR(svn_client__ensure_revprop_table(&commit_revprops, revprop_table,
                                            log_msg, ctx, pool));
 
+#ifdef ENABLE_EV2_SHIMS
+  if (commit_items)
+    {
+      int i;
+      apr_pool_t *iterpool = svn_pool_create(pool);
+
+      relpath_map = apr_hash_make(pool);
+      for (i = 0; i < commit_items->nelts; i++)
+        {
+          svn_client_commit_item3_t *item = APR_ARRAY_IDX(commit_items, i,
+                                                  svn_client_commit_item3_t *);
+          const char *relpath;
+
+          if (!item->path)
+            continue;
+
+          svn_pool_clear(iterpool);
+          SVN_ERR(svn_wc__node_get_origin(NULL, NULL, &relpath, NULL, NULL, NULL,
+                                          ctx->wc_ctx, item->path, FALSE, pool,
+                                          iterpool));
+          if (relpath)
+            apr_hash_set(relpath_map, relpath, APR_HASH_KEY_STRING, item->path);
+        }
+      svn_pool_destroy(iterpool);
+    }
+#endif
+
   /* Fetch RA commit editor. */
-  SVN_ERR(svn_ra_get_commit_editor3(*ra_session, editor, edit_baton,
+  SVN_ERR(svn_ra__register_editor_shim_callbacks(ra_session,
+                        svn_client__get_shim_callbacks(ctx->wc_ctx,
+                                                       relpath_map, pool)));
+  SVN_ERR(svn_ra_get_commit_editor3(ra_session, editor, edit_baton,
                                     commit_revprops, commit_callback,
                                     commit_baton, lock_tokens, keep_locks,
                                     pool));
@@ -679,36 +821,39 @@ get_ra_editor(svn_ra_session_t **ra_sess
 /*** Public Interfaces. ***/
 
 svn_error_t *
-svn_client_import4(const char *path,
+svn_client_import5(const char *path,
                    const char *url,
                    svn_depth_t depth,
                    svn_boolean_t no_ignore,
                    svn_boolean_t ignore_unknown_node_types,
                    const apr_hash_t *revprop_table,
+                   svn_client_import_filter_func_t filter_callback,
+                   void *filter_baton,
                    svn_commit_callback2_t commit_callback,
                    void *commit_baton,
                    svn_client_ctx_t *ctx,
-                   apr_pool_t *pool)
+                   apr_pool_t *scratch_pool)
 {
   svn_error_t *err = SVN_NO_ERROR;
   const char *log_msg = "";
   const svn_delta_editor_t *editor;
   void *edit_baton;
   svn_ra_session_t *ra_session;
-  apr_hash_t *excludes = apr_hash_make(pool);
+  apr_hash_t *excludes = apr_hash_make(scratch_pool);
   svn_node_kind_t kind;
   const char *local_abspath;
-  apr_array_header_t *new_entries = apr_array_make(pool, 4,
+  apr_array_header_t *new_entries = apr_array_make(scratch_pool, 4,
                                                    sizeof(const char *));
   const char *temp;
   const char *dir;
-  apr_pool_t *subpool;
+  apr_hash_t *commit_revprops;
+  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
 
   if (svn_path_is_url(path))
     return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
                              _("'%s' is not a local path"), path);
 
-  SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, pool));
+  SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, scratch_pool));
 
   /* Create a new commit item and add it to the array. */
   if (SVN_CLIENT__HAS_LOG_MSG_FUNC(ctx))
@@ -719,58 +864,55 @@ svn_client_import4(const char *path,
       svn_client_commit_item3_t *item;
       const char *tmp_file;
       apr_array_header_t *commit_items
-        = apr_array_make(pool, 1, sizeof(item));
+        = apr_array_make(scratch_pool, 1, sizeof(item));
 
-      item = svn_client_commit_item3_create(pool);
-      item->path = apr_pstrdup(pool, path);
+      item = svn_client_commit_item3_create(scratch_pool);
+      item->path = apr_pstrdup(scratch_pool, path);
       item->state_flags = SVN_CLIENT_COMMIT_ITEM_ADD;
       APR_ARRAY_PUSH(commit_items, svn_client_commit_item3_t *) = item;
 
       SVN_ERR(svn_client__get_log_msg(&log_msg, &tmp_file, commit_items,
-                                      ctx, pool));
+                                      ctx, scratch_pool));
       if (! log_msg)
         return SVN_NO_ERROR;
       if (tmp_file)
         {
           const char *abs_path;
-          SVN_ERR(svn_dirent_get_absolute(&abs_path, tmp_file, pool));
+          SVN_ERR(svn_dirent_get_absolute(&abs_path, tmp_file, scratch_pool));
           apr_hash_set(excludes, abs_path, APR_HASH_KEY_STRING, (void *)1);
         }
     }
 
-  SVN_ERR(svn_io_check_path(local_abspath, &kind, pool));
+  SVN_ERR(svn_io_check_path(local_abspath, &kind, scratch_pool));
+
+  SVN_ERR(svn_client__open_ra_session_internal(&ra_session, NULL, url, NULL,
+                                               NULL, FALSE, TRUE, ctx,
+                                               scratch_pool));
 
   /* Figure out all the path components we need to create just to have
      a place to stick our imported tree. */
-  subpool = svn_pool_create(pool);
-  do
-    {
-      svn_pool_clear(subpool);
+  SVN_ERR(svn_ra_check_path(ra_session, "", SVN_INVALID_REVNUM, &kind,
+                            iterpool));
 
-      /* See if the user is interested in cancelling this operation. */
-      if (ctx->cancel_func)
-        SVN_ERR(ctx->cancel_func(ctx->cancel_baton));
+  /* We can import into directories, but if a file already exists, that's
+     an error. */
+  if (kind == svn_node_file)
+    return svn_error_createf
+      (SVN_ERR_ENTRY_EXISTS, NULL,
+       _("Path '%s' already exists"), url);
 
-      if (err)
-        {
-          /* If get_ra_editor below failed we either tried to open
-             an invalid url, or else some other kind of error.  In case
-             the url was bad we back up a directory and try again. */
+  while (kind == svn_node_none)
+    {
+      svn_pool_clear(iterpool);
 
-          if (err->apr_err != SVN_ERR_FS_NO_SUCH_ENTRY)
-            return err;
-          else
-            svn_error_clear(err);
+      svn_uri_split(&temp, &dir, url, scratch_pool);
+      APR_ARRAY_PUSH(new_entries, const char *) = dir;
+      url = temp;
+      SVN_ERR(svn_ra_reparent(ra_session, url, iterpool));
 
-          svn_uri_split(&temp, &dir, url, pool);
-          APR_ARRAY_PUSH(new_entries, const char *) = dir;
-          url = temp;
-        }
+      SVN_ERR(svn_ra_check_path(ra_session, "", SVN_INVALID_REVNUM, &kind,
+                                iterpool));
     }
-  while ((err = get_ra_editor(&ra_session,
-                              &editor, &edit_baton, ctx, url, NULL,
-                              log_msg, NULL, revprop_table, FALSE, NULL, TRUE,
-                              commit_callback, commit_baton, subpool)));
 
   /* Reverse the order of the components we added to our NEW_ENTRIES array. */
   if (new_entries->nelts)
@@ -789,14 +931,6 @@ svn_client_import4(const char *path,
         }
     }
 
-  /* An empty NEW_ENTRIES list the first call to get_ra_editor() above
-     succeeded.  That means that URL corresponds to an already
-     existing filesystem entity. */
-  if (kind == svn_node_file && (! new_entries->nelts))
-    return svn_error_createf
-      (SVN_ERR_ENTRY_EXISTS, NULL,
-       _("Path '%s' already exists"), url);
-
   /* The repository doesn't know about the reserved administrative
      directory. */
   if (new_entries->nelts
@@ -807,25 +941,37 @@ svn_client_import4(const char *path,
       && svn_wc_is_adm_dir(temp = APR_ARRAY_IDX(new_entries,
                                                 new_entries->nelts - 1,
                                                 const char *),
-                           pool))
+                           scratch_pool))
     return svn_error_createf
       (SVN_ERR_CL_ADM_DIR_RESERVED, NULL,
        _("'%s' is a reserved name and cannot be imported"),
-       /* ### Is svn_path_local_style() really necessary for this? */
-       svn_dirent_local_style(temp, pool));
+       svn_dirent_local_style(temp, scratch_pool));
 
+  SVN_ERR(svn_client__ensure_revprop_table(&commit_revprops, revprop_table,
+                                           log_msg, ctx, scratch_pool));
+
+  /* Fetch RA commit editor. */
+  SVN_ERR(svn_ra__register_editor_shim_callbacks(ra_session,
+                        svn_client__get_shim_callbacks(ctx->wc_ctx,
+                                                       NULL, scratch_pool)));
+  SVN_ERR(svn_ra_get_commit_editor3(ra_session, &editor, &edit_baton,
+                                    commit_revprops, commit_callback,
+                                    commit_baton, NULL, TRUE,
+                                    scratch_pool));
 
   /* If an error occurred during the commit, abort the edit and return
      the error.  We don't even care if the abort itself fails.  */
-  if ((err = import(path, new_entries, editor, edit_baton,
+  if ((err = import(local_abspath, new_entries, editor, edit_baton,
                     depth, excludes, no_ignore,
-                    ignore_unknown_node_types, ctx, subpool)))
+                    ignore_unknown_node_types,
+                    filter_callback, filter_baton,
+                    ctx, iterpool)))
     {
-      svn_error_clear(editor->abort_edit(edit_baton, subpool));
-      return err;
+      svn_error_clear(editor->abort_edit(edit_baton, iterpool));
+      return svn_error_trace(err);
     }
 
-  svn_pool_destroy(subpool);
+  svn_pool_destroy(iterpool);
 
   return SVN_NO_ERROR;
 }
@@ -1253,7 +1399,7 @@ append_externals_as_explicit_targets(apr
 
               rel_target = svn_dirent_skip_ancestor(base_abspath,
                                                     xinfo->local_abspath);
-              
+
               SVN_ERR_ASSERT(rel_target != NULL && *rel_target != '\0');
 
               APR_ARRAY_PUSH(rel_targets, const char *) =
@@ -1489,7 +1635,7 @@ svn_client_commit6(const apr_array_heade
               svn_boolean_t found_delete_half =
                 (apr_hash_get(committables->by_path, delete_op_root_abspath,
                                APR_HASH_KEY_STRING) != NULL);
-              
+
               if (!found_delete_half)
                 {
                   const char *delete_half_parent_abspath;
@@ -1618,10 +1764,17 @@ svn_client_commit6(const apr_array_heade
   cb.pool = pool;
 
   cmt_err = svn_error_trace(
-                 get_ra_editor(&ra_session, &editor, &edit_baton, ctx,
-                               base_url, base_abspath, log_msg,
-                               commit_items, revprop_table, TRUE, lock_tokens,
-                               keep_locks, capture_commit_info,
+          svn_client__open_ra_session_internal(&ra_session, NULL, base_url,
+                                               base_abspath, commit_items,
+                                               TRUE, FALSE, ctx, pool));
+
+  if (cmt_err)
+    goto cleanup;
+
+  cmt_err = svn_error_trace(
+                 get_ra_editor(&editor, &edit_baton, ra_session, ctx,
+                               log_msg, commit_items, revprop_table,
+                               lock_tokens, keep_locks, capture_commit_info,
                                &cb, pool));
 
   if (cmt_err)

Modified: subversion/branches/javahl-ra/subversion/libsvn_client/commit_util.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_client/commit_util.c?rev=1329209&r1=1329208&r2=1329209&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_client/commit_util.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_client/commit_util.c Mon Apr 23 12:32:48 2012
@@ -44,6 +44,7 @@
 
 #include "svn_private_config.h"
 #include "private/svn_wc_private.h"
+#include "private/svn_client_private.h"
 
 /*** Uncomment this to turn on commit driver debugging. ***/
 /*
@@ -416,14 +417,17 @@ bail_on_tree_conflicted_ancestor(svn_wc_
    by recursing deeper into a dir target. (This is used to skip all file
    externals that aren't explicit commit targets.)
 
+   DANGLERS is a hash table mapping const char* absolute paths of a parent
+   to a const char * absolute path of a child. See the comment about
+   danglers at the top of svn_client__harvest_committables().
+
    If CANCEL_FUNC is non-null, call it with CANCEL_BATON to see
    if the user has cancelled the operation.
 
    Any items added to COMMITTABLES are allocated from the COMITTABLES
    hash pool, not POOL.  SCRATCH_POOL is used for temporary allocations. */
 static svn_error_t *
-harvest_committables(svn_wc_context_t *wc_ctx,
-                     const char *local_abspath,
+harvest_committables(const char *local_abspath,
                      svn_client__committables_t *committables,
                      apr_hash_t *lock_tokens,
                      const char *repos_root_url,
@@ -435,15 +439,18 @@ harvest_committables(svn_wc_context_t *w
                      svn_boolean_t skip_files,
                      svn_boolean_t skip_dirs,
                      svn_boolean_t is_explicit_target,
+                     apr_hash_t *danglers,
                      svn_client__check_url_kind_t check_url_func,
                      void *check_url_baton,
                      svn_cancel_func_t cancel_func,
                      void *cancel_baton,
                      svn_wc_notify_func2_t notify_func,
                      void *notify_baton,
+                     svn_client_ctx_t *ctx,
                      apr_pool_t *result_pool,
                      apr_pool_t *scratch_pool)
 {
+  svn_wc_context_t *wc_ctx = ctx->wc_ctx;
   svn_boolean_t text_mod = FALSE;
   svn_boolean_t prop_mod = FALSE;
   apr_byte_t state_flags = 0;
@@ -621,27 +628,21 @@ harvest_committables(svn_wc_context_t *w
       /* We should check if we should really add a delete operation */
       if (check_url_func)
         {
-          svn_revnum_t revision;
-          const char *repos_relpath;
+          svn_client__pathrev_t *origin;
+          const char *repos_url;
           svn_node_kind_t kind;
 
           /* Determine from what parent we would be the deleted child */
-          SVN_ERR(svn_wc__node_get_origin(NULL, &revision, &repos_relpath,
-                                          NULL, NULL, wc_ctx,
-                                          svn_dirent_dirname(local_abspath,
-                                                             scratch_pool),
-                                          FALSE, scratch_pool, scratch_pool));
+          SVN_ERR(svn_client__wc_node_get_origin(
+                    &origin, svn_dirent_dirname(local_abspath, scratch_pool),
+                    ctx, scratch_pool, scratch_pool));
+
+          repos_url = svn_path_url_add_component2(
+                        origin->url, svn_dirent_basename(local_abspath, NULL),
+                        scratch_pool);
 
-          repos_relpath = svn_relpath_join(repos_relpath,
-                                           svn_dirent_basename(local_abspath,
-                                                               NULL),
-                                           scratch_pool);
-
-          SVN_ERR(check_url_func(check_url_baton, &kind,
-                                 svn_path_url_add_component2(repos_root_url,
-                                                             repos_relpath,
-                                                             scratch_pool),
-                                 revision, scratch_pool));
+          SVN_ERR(check_url_func(check_url_baton, &kind, repos_url, origin->rev,
+                                 scratch_pool));
 
           if (kind == svn_node_none)
             return SVN_NO_ERROR; /* This node can't be deleted */
@@ -684,7 +685,7 @@ harvest_committables(svn_wc_context_t *w
 
           SVN_ERR(svn_wc__node_get_origin(NULL, &cf_rev,
                                       &cf_relpath, NULL,
-                                      NULL,
+                                      NULL, NULL,
                                       wc_ctx, local_abspath, FALSE,
                                       scratch_pool, scratch_pool));
 
@@ -814,6 +815,45 @@ harvest_committables(svn_wc_context_t *w
         }
     }
 
+  /* Make sure we check for dangling children on additions */
+  if (state_flags && is_added && is_explicit_target && danglers)
+    {
+      /* If a node is added, it's parent must exist in the repository at the
+         time of committing */
+
+      svn_boolean_t parent_added;
+      const char *parent_abspath = svn_dirent_dirname(local_abspath,
+                                                      scratch_pool);
+
+      SVN_ERR(svn_wc__node_is_added(&parent_added, wc_ctx, parent_abspath,
+                                    scratch_pool));
+
+      if (parent_added)
+        {
+          const char *copy_root_abspath;
+          svn_boolean_t parent_is_copy;
+
+          /* The parent is added, so either it is a copy, or a locally added
+           * directory. In either case, we require the op-root of the parent
+           * to be part of the commit. See issue #4059. */
+          SVN_ERR(svn_wc__node_get_origin(&parent_is_copy, NULL, NULL, NULL,
+                                          NULL, &copy_root_abspath,
+                                          wc_ctx, parent_abspath,
+                                          FALSE, scratch_pool, scratch_pool));
+
+          if (parent_is_copy)
+            parent_abspath = copy_root_abspath;
+
+          if (!apr_hash_get(danglers, parent_abspath, APR_HASH_KEY_STRING))
+            {
+              apr_hash_set(danglers,
+                           apr_pstrdup(result_pool, parent_abspath),
+                           APR_HASH_KEY_STRING,
+                           apr_pstrdup(result_pool, local_abspath));
+            }
+        }
+    }
+
   if (db_kind != svn_node_dir || depth <= svn_depth_empty)
     return SVN_NO_ERROR;
 
@@ -852,7 +892,7 @@ harvest_committables(svn_wc_context_t *w
             this_commit_relpath = svn_relpath_join(commit_relpath, name,
                                                    iterpool);
 
-          SVN_ERR(harvest_committables(wc_ctx, this_abspath,
+          SVN_ERR(harvest_committables(this_abspath,
                                        committables, lock_tokens,
                                        repos_root_url,
                                        this_commit_relpath,
@@ -863,11 +903,11 @@ harvest_committables(svn_wc_context_t *w
                                        (depth < svn_depth_files),
                                        (depth < svn_depth_immediates),
                                        FALSE, /* IS_EXPLICIT_TARGET */
+                                       danglers,
                                        check_url_func, check_url_baton,
                                        cancel_func, cancel_baton,
                                        notify_func, notify_baton,
-                                       result_pool,
-                                       iterpool));
+                                       ctx, result_pool, iterpool));
         }
 
       svn_pool_destroy(iterpool);
@@ -1032,13 +1072,13 @@ svn_client__harvest_committables(svn_cli
    * Since we don't know what's included in the commit until we've
    * harvested all the targets, we can't reliably check this as we
    * go.  So in `danglers', we record named targets whose parents
-   * are unversioned, then after harvesting the total commit group, we
-   * check to make sure those parents are included.
+   * do not yet exist in the repository. Then after harvesting the total
+   * commit group, we check to make sure those parents are included.
    *
-   * Each key of danglers is an unversioned parent.  The (const char *)
-   * value is one of that parent's children which is named as part of
-   * the commit; the child is included only to make a better error
-   * message.
+   * Each key of danglers is a parent which does not exist in the
+   * repository.  The (const char *) value is one of that parent's
+   * children which is named as part of the commit; the child is
+   * included only to make a better error message.
    *
    * (The reason we don't bother to check unnamed -- i.e, implicit --
    * targets is that they can only join the commit if their parents
@@ -1063,10 +1103,8 @@ svn_client__harvest_committables(svn_cli
   for (i = 0; i < targets->nelts; ++i)
     {
       const char *target_abspath;
-      svn_boolean_t is_added;
       svn_node_kind_t kind;
       const char *repos_root_url;
-      svn_error_t *err;
 
       svn_pool_clear(iterpool);
 
@@ -1103,35 +1141,6 @@ svn_client__harvest_committables(svn_cli
                                           target_abspath,
                                           result_pool, iterpool));
 
-      /* Handle an added/replaced node. */
-      SVN_ERR(svn_wc__node_is_added(&is_added, ctx->wc_ctx, target_abspath,
-                                    iterpool));
-      if (is_added)
-        {
-          /* This node is added. Is the parent also added? */
-          const char *parent_abspath = svn_dirent_dirname(target_abspath,
-                                                          iterpool);
-          err = svn_wc__node_is_added(&is_added, ctx->wc_ctx, parent_abspath,
-                                      iterpool);
-          if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
-            return svn_error_createf(
-                SVN_ERR_WC_CORRUPT, err,
-                _("'%s' is scheduled for addition within unversioned parent"),
-                svn_dirent_local_style(target_abspath, iterpool));
-          SVN_ERR(err);
-
-          if (is_added)
-            {
-              /* Copy the parent and target into pool; iterpool
-                 lasts only for this loop iteration, and we check
-                 danglers after the loop is over. */
-              apr_hash_set(danglers,
-                           apr_pstrdup(scratch_pool, parent_abspath),
-                           APR_HASH_KEY_STRING,
-                           apr_pstrdup(scratch_pool, target_abspath));
-            }
-        }
-
       /* Handle our TARGET. */
       /* Make sure this isn't inside a working copy subtree that is
        * marked as tree-conflicted. */
@@ -1140,7 +1149,7 @@ svn_client__harvest_committables(svn_cli
                                                ctx->notify_baton2,
                                                iterpool));
 
-      SVN_ERR(harvest_committables(ctx->wc_ctx, target_abspath,
+      SVN_ERR(harvest_committables(target_abspath,
                                    *committables, *lock_tokens,
                                    repos_root_url,
                                    NULL /* COMMIT_RELPATH */,
@@ -1148,10 +1157,11 @@ svn_client__harvest_committables(svn_cli
                                    depth, just_locked, changelist_hash,
                                    FALSE, FALSE,
                                    TRUE /* IS_EXPLICIT_TARGET */,
+                                   danglers,
                                    check_url_func, check_url_baton,
                                    ctx->cancel_func, ctx->cancel_baton,
                                    ctx->notify_func2, ctx->notify_baton2,
-                                   result_pool, iterpool));
+                                   ctx, result_pool, iterpool));
     }
 
   hdb.wc_ctx = ctx->wc_ctx;
@@ -1170,31 +1180,31 @@ svn_client__harvest_committables(svn_cli
 
       svn_pool_clear(iterpool);
 
-       if (! look_up_committable(*committables, dangling_parent, iterpool))
-         {
-           const char *dangling_child = svn__apr_hash_index_val(hi);
-
-           if (ctx->notify_func2 != NULL)
-             {
-               svn_wc_notify_t *notify;
-
-               notify = svn_wc_create_notify(dangling_child,
-                                             svn_wc_notify_failed_no_parent,
-                                             scratch_pool);
-
-               ctx->notify_func2(ctx->notify_baton2, notify, iterpool);
-             }
-
-           return svn_error_createf(
-                            SVN_ERR_ILLEGAL_TARGET, NULL,
-                            _("'%s' is not under version control "
-                              "and is not part of the commit, "
-                              "yet its child '%s' is part of the commit"),
-                            /* Probably one or both of these is an entry, but
-                               safest to local_stylize just in case. */
-                            svn_dirent_local_style(dangling_parent, iterpool),
-                            svn_dirent_local_style(dangling_child, iterpool));
-         }
+      if (! look_up_committable(*committables, dangling_parent, iterpool))
+        {
+          const char *dangling_child = svn__apr_hash_index_val(hi);
+
+          if (ctx->notify_func2 != NULL)
+            {
+              svn_wc_notify_t *notify;
+
+              notify = svn_wc_create_notify(dangling_child,
+                                            svn_wc_notify_failed_no_parent,
+                                            scratch_pool);
+
+              ctx->notify_func2(ctx->notify_baton2, notify, iterpool);
+            }
+
+          return svn_error_createf(
+                           SVN_ERR_ILLEGAL_TARGET, NULL,
+                           _("'%s' is not known to exist in the repository "
+                             "and is not part of the commit, "
+                             "yet its child '%s' is part of the commit"),
+                           /* Probably one or both of these is an entry, but
+                              safest to local_stylize just in case. */
+                           svn_dirent_local_style(dangling_parent, iterpool),
+                           svn_dirent_local_style(dangling_child, iterpool));
+        }
     }
 
   svn_pool_destroy(iterpool);
@@ -1231,8 +1241,7 @@ harvest_copy_committables(void *baton, v
                                          pair->dst_abspath_or_url, pool);
 
   /* Handle this SRC. */
-  SVN_ERR(harvest_committables(btn->ctx->wc_ctx,
-                               pair->src_abspath_or_url,
+  SVN_ERR(harvest_committables(pair->src_abspath_or_url,
                                btn->committables, NULL,
                                repos_root_url,
                                commit_relpath,
@@ -1242,13 +1251,14 @@ harvest_copy_committables(void *baton, v
                                NULL,
                                FALSE, FALSE, /* skip files, dirs */
                                TRUE, /* IS_EXPLICIT_TARGET (don't care) */
+                               NULL,
                                btn->check_url_func,
                                btn->check_url_baton,
                                btn->ctx->cancel_func,
                                btn->ctx->cancel_baton,
                                btn->ctx->notify_func2,
                                btn->ctx->notify_baton2,
-                               btn->result_pool, pool));
+                               btn->ctx, btn->result_pool, pool));
 
   hdb.wc_ctx = btn->ctx->wc_ctx;
   hdb.cancel_func = btn->ctx->cancel_func;



Mime
View raw message