You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by rh...@apache.org on 2010/03/09 01:32:53 UTC

svn commit: r920592 - /subversion/trunk/subversion/libsvn_wc/adm_crawler.c

Author: rhuijben
Date: Tue Mar  9 00:32:53 2010
New Revision: 920592

URL: http://svn.apache.org/viewvc?rev=920592&view=rev
Log:
* subversion/libsvn_wc/adm_crawler.c
  (svn_wc_crawl_revisions5): Collect data directly from BASE_NODE instead
    of deriving it from WORKING_NODE and then looking for more details.

Modified:
    subversion/trunk/subversion/libsvn_wc/adm_crawler.c

Modified: subversion/trunk/subversion/libsvn_wc/adm_crawler.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/adm_crawler.c?rev=920592&r1=920591&r2=920592&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/adm_crawler.c (original)
+++ subversion/trunk/subversion/libsvn_wc/adm_crawler.c Tue Mar  9 00:32:53 2010
@@ -757,106 +757,133 @@
                         void *external_baton,
                         svn_wc_notify_func2_t notify_func,
                         void *notify_baton,
-                        apr_pool_t *pool)
+                        apr_pool_t *scratch_pool)
 {
   svn_wc__db_t *db = wc_ctx->db;
   svn_error_t *fserr, *err;
-  svn_revnum_t base_rev = SVN_INVALID_REVNUM, target_rev;
+  svn_revnum_t target_rev = SVN_INVALID_REVNUM;
   svn_boolean_t missing = FALSE;
   svn_boolean_t start_empty;
   svn_wc__db_status_t status;
-  svn_wc__db_kind_t target_kind;
-  const char *repos_relpath, *repos_root_url;
-  svn_depth_t target_depth;
-  svn_boolean_t replaced = FALSE;
-  svn_wc__db_lock_t *target_lock;
-  svn_boolean_t target_exists = TRUE;
+  svn_wc__db_kind_t target_kind = svn_wc__db_kind_unknown;
+  const char *repos_relpath=NULL, *repos_root=NULL;
+  svn_depth_t target_depth = svn_depth_unknown;
+  svn_wc__db_lock_t *target_lock = NULL;
+  svn_boolean_t explicit_rev;
   SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
 
   /* The first thing we do is get the base_rev from the working copy's
      ROOT_DIRECTORY.  This is the first revnum that entries will be
      compared to. */
-  err = svn_wc__db_read_info(&status, &target_kind, &target_rev,
-                             &repos_relpath, &repos_root_url,
-                             NULL, NULL, NULL, NULL, NULL,
-                             &target_depth, NULL, NULL, NULL, NULL, NULL,
-                             NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-                             &target_lock,
-                             db, local_abspath, pool, pool);
+  err = svn_wc__db_base_get_info(&status, &target_kind, &target_rev,
+                                 &repos_relpath, &repos_root,
+                                 NULL, NULL, NULL, NULL, NULL,
+                                 &target_depth, NULL, NULL, NULL,
+                                 &target_lock,
+                                 db, local_abspath, scratch_pool,
+                                 scratch_pool);
 
-  if (err)
-    {
-      if (err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND)
-        return svn_error_return(err);
+  {
+    svn_boolean_t has_base = TRUE;
 
-      svn_error_clear(err);
-      target_exists = FALSE;
+    if (err)
+      {
+        if (err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND)
+          return svn_error_return(err);
 
-      /* Set output values of svn_wc__db_read_info to their empty values */
-      status = svn_wc__db_status_not_present;
-      target_kind = svn_wc__db_kind_unknown;
-      target_rev = -1;
-      repos_relpath = NULL;
-      repos_root_url = NULL;
-      target_depth = svn_depth_unknown;
-      target_lock = NULL;
-    }
-
-  if (status == svn_wc__db_status_added)
-    SVN_ERR(svn_wc__internal_is_replaced(&replaced, db, local_abspath, pool));
-
-  if (!target_exists ||
-      (status == svn_wc__db_status_not_present) ||
-      (target_kind == svn_wc__db_kind_dir && !replaced &&
-           (status == svn_wc__db_status_added ||
-            status == svn_wc__db_status_absent ||
-            status == svn_wc__db_status_excluded ||
-            status == svn_wc__db_status_obstructed ||
-            status == svn_wc__db_status_obstructed_add ||
-            status == svn_wc__db_status_obstructed_delete)))
-    {
-      /* Don't check the exclude flag for the target.
-
-       If we report the target itself as excluded, the server will
-       send us nothing about the target -- but we want to permit
-       targets to be explicitly pulled in.  For example, 'svn up A'
-       should always work, even if its parent is svn_depth_empty or
-       svn_depth_files, or even if A was explicitly excluded from a
-       parent at svn_depth_immediates or svn_depth_infinity.
-       Whatever the case, we want A back now. */
+        svn_error_clear(err);
+        has_base = FALSE;
+        SVN_ERR(svn_wc__db_read_kind(&target_kind, db, local_abspath, TRUE,
+                                     scratch_pool));
 
-      if (!SVN_IS_VALID_REVNUM(base_rev))
-        {
-          const char *dir_abspath = svn_dirent_dirname(local_abspath, pool);
+        if (target_kind == svn_wc__db_kind_file
+            || target_kind == svn_wc__db_kind_symlink)
+          status = svn_wc__db_status_absent; /* Crawl via parent dir */
+        else
+          status = svn_wc__db_status_not_present; /* As checkout */
+      }
 
-          SVN_ERR(find_base_rev(&base_rev, db, dir_abspath, dir_abspath,
-                                pool));
-        }
+    /* ### Check the parentstub if we don't find a BASE. But don't
+           do this if we already have the info we want or we break
+           some copy scenarios. */
+    if (!has_base && target_kind == svn_wc__db_kind_dir)
+      {
+        svn_boolean_t not_present;
+        svn_revnum_t rev = SVN_INVALID_REVNUM;
+        err = svn_wc__db_temp_is_dir_deleted(&not_present, &rev,
+                                             db, local_abspath, scratch_pool);
+
+        if (err && (err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND
+                    || err->apr_err == SVN_ERR_WC_NOT_WORKING_COPY))
+          {
+            svn_error_clear(err);
+            not_present = FALSE;
+          }
+        else
+          SVN_ERR(err);
 
-      /* There aren't any versioned paths to crawl which are known to
-         the repository. */
+        if (not_present)
+          status = svn_wc__db_status_not_present;
+
+        if (!SVN_IS_VALID_REVNUM(target_rev))
+          target_rev = rev;
+      }
+  }
+
+  if ((status == svn_wc__db_status_not_present)
+      || (target_kind == svn_wc__db_kind_dir
+          && status != svn_wc__db_status_normal
+          && status != svn_wc__db_status_incomplete))
+    {
+      /* The target does not exist or is a local addition */
+
+      if (!SVN_IS_VALID_REVNUM(target_rev))
+        target_rev = 0;
 
-      /* If no versioned path exists, we use the requested depth, which
-         is the depth at which the new path should be brought in.  Default
-         to infinity if no explicit depth was given. */
       if (depth == svn_depth_unknown)
         depth = svn_depth_infinity;
 
-      SVN_ERR(reporter->set_path(report_baton, "", base_rev, depth,
-                                 status == svn_wc__db_status_incomplete,
-                                 target_lock ? target_lock->token : NULL,
-                                 pool));
-      SVN_ERR(reporter->delete_path(report_baton, "", pool));
+      SVN_ERR(reporter->set_path(report_baton, "", target_rev, depth,
+                                 FALSE,
+                                 NULL,
+                                 scratch_pool));
+      SVN_ERR(reporter->delete_path(report_baton, "", scratch_pool));
 
       /* Finish the report, which causes the update editor to be
          driven. */
-      return reporter->finish_report(report_baton, pool);
+      SVN_ERR(reporter->finish_report(report_baton, scratch_pool));
+
+      return SVN_NO_ERROR;
     }
 
-  base_rev = target_rev;
+  if (!repos_root || !repos_relpath)
+    {
+      err = svn_wc__db_scan_base_repos(&repos_relpath, &repos_root, NULL,
+                                      db, local_abspath,
+                                      scratch_pool, scratch_pool);
 
-  if (!SVN_IS_VALID_REVNUM(base_rev))
-    SVN_ERR(find_base_rev(&base_rev, db, local_abspath, local_abspath, pool));
+      if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
+        svn_error_clear(err);
+      else
+        SVN_ERR(err);
+
+      /* Ok, that leaves a local addition. Deleted and not existing nodes
+         are already handled. */
+      if (!repos_root || !repos_relpath)
+        SVN_ERR(svn_wc__db_scan_addition(NULL, NULL, &repos_relpath,
+                                         &repos_root, NULL, NULL, NULL, NULL,
+                                         NULL, db, local_abspath,
+                                         scratch_pool, scratch_pool));
+    }
+
+  if (!SVN_IS_VALID_REVNUM(target_rev))
+    {
+      SVN_ERR(find_base_rev(&target_rev, db, local_abspath, local_abspath,
+                            scratch_pool));
+      explicit_rev = TRUE;
+    }
+  else
+    explicit_rev = FALSE;
 
   start_empty = (status == svn_wc__db_status_incomplete);
   if (depth_compatibility_trick
@@ -872,13 +899,13 @@
   /* The first call to the reporter merely informs it that the
      top-level directory being updated is at BASE_REV.  Its PATH
      argument is ignored. */
-  SVN_ERR(reporter->set_path(report_baton, "", base_rev, target_depth,
-                             start_empty, NULL, pool));
+  SVN_ERR(reporter->set_path(report_baton, "", target_rev, target_depth,
+                             start_empty, NULL, scratch_pool));
 
   if (status != svn_wc__db_status_deleted)
     {
       apr_finfo_t info;
-      err = svn_io_stat(&info, local_abspath, APR_FINFO_MIN, pool);
+      err = svn_io_stat(&info, local_abspath, APR_FINFO_MIN, scratch_pool);
       if (err)
         {
           if (APR_STATUS_IS_ENOENT(err->apr_err))
@@ -895,7 +922,7 @@
       err = restore_node(&restored, wc_ctx->db, local_abspath,
                          target_kind, use_commit_times,
                          notify_func, notify_baton,
-                         pool);
+                         scratch_pool);
 
       if (err)
           goto abort_report;
@@ -910,7 +937,7 @@
         {
           /* Report missing directories as deleted to retrieve them
              from the repository. */
-          err = reporter->delete_path(report_baton, "", pool);
+          err = reporter->delete_path(report_baton, "", scratch_pool);
           if (err)
             goto abort_report;
         }
@@ -921,7 +948,7 @@
           err = report_revisions_and_depths(wc_ctx->db,
                                             local_abspath,
                                             "",
-                                            base_rev,
+                                            target_rev,
                                             reporter, report_baton,
                                             external_func, external_baton,
                                             notify_func, notify_baton,
@@ -930,7 +957,7 @@
                                             depth_compatibility_trick,
                                             start_empty,
                                             use_commit_times,
-                                            pool);
+                                            scratch_pool);
           if (err)
             goto abort_report;
         }
@@ -940,93 +967,82 @@
            target_kind == svn_wc__db_kind_symlink)
     {
       svn_boolean_t skip_set_path  = FALSE;
-
-      if (repos_relpath)
-        {
-          const char *parent_abspath, *base;
-          svn_wc__db_status_t parent_status;
-          const char *parent_repos_relpath;
-
-          svn_dirent_split(local_abspath, &parent_abspath, &base, pool);
-
-          /* We can assume a file is in the same repository as its parent
-             directory, so we only look at the relpath. */
-          err = svn_wc__db_read_info(&parent_status, NULL, NULL,
+      const char *parent_abspath, *base;
+      svn_wc__db_status_t parent_status;
+      const char *parent_repos_relpath;
+
+      svn_dirent_split(local_abspath, &parent_abspath, &base,
+                       scratch_pool);
+
+      /* We can assume a file is in the same repository as its parent
+         directory, so we only look at the relpath. */
+      err = svn_wc__db_base_get_info(&parent_status, NULL, NULL,
                                      &parent_repos_relpath, NULL, NULL, NULL,
                                      NULL, NULL, NULL, NULL, NULL, NULL,
-                                     NULL, NULL, NULL, NULL, NULL, NULL,
-                                     NULL, NULL, NULL, NULL, NULL,
-                                     db, parent_abspath, pool, pool);
+                                     NULL, NULL,
+                                     db, parent_abspath,
+                                     scratch_pool, scratch_pool);
 
-          if (err)
-            goto abort_report;
+      if (err)
+        goto abort_report;
 
-          if (!parent_repos_relpath &&
-              parent_status == svn_wc__db_status_added)
-            {
-              err = svn_wc__db_scan_addition(NULL, NULL,
-                                             &parent_repos_relpath, NULL,
-                                             NULL, NULL, NULL, NULL, NULL,
-                                             db, parent_abspath,
-                                             pool, pool);
-            }
-          else if (!parent_repos_relpath)
-            err = svn_wc__db_scan_base_repos(&parent_repos_relpath, NULL,
-                                             NULL,
-                                             db, parent_abspath,
-                                             pool, pool);
+      if (!parent_repos_relpath)
+        err = svn_wc__db_scan_base_repos(&parent_repos_relpath, NULL,
+                                         NULL,
+                                         db, parent_abspath,
+                                         scratch_pool, scratch_pool);
+
+      if (err)
+        goto abort_report;
 
+      if (strcmp(repos_relpath,
+                 svn_relpath_join(parent_repos_relpath, base,
+                                  scratch_pool)) != 0)
+        {
+          /* This file is disjoint with respect to its parent
+             directory.  Since we are looking at the actual target of
+             the report (not some file in a subdirectory of a target
+             directory), and that target is a file, we need to pass an
+             empty string to link_path. */
+          err = reporter->link_path(report_baton,
+                                    "",
+                                    svn_path_url_add_component2(
+                                                    repos_root,
+                                                    repos_relpath,
+                                                    scratch_pool),
+                                    target_rev,
+                                    target_depth,
+                                    FALSE,
+                                    target_lock ? target_lock->token : NULL,
+                                    scratch_pool);
           if (err)
             goto abort_report;
-
-          if (strcmp(repos_relpath,
-                     svn_relpath_join(parent_repos_relpath, base, pool)) != 0)
-            {
-              /* This file is disjoint with respect to its parent
-                 directory.  Since we are looking at the actual target of
-                 the report (not some file in a subdirectory of a target
-                 directory), and that target is a file, we need to pass an
-                 empty string to link_path. */
-              err = reporter->link_path(report_baton,
-                                        "",
-                                        svn_path_url_add_component2(
-                                                        repos_root_url,
-                                                        repos_relpath,
-                                                        pool),
-                                        base_rev,
-                                        target_depth,
-                                        FALSE,
-                                        target_lock ? target_lock->token : NULL,
-                                        pool);
-              if (err)
-                goto abort_report;
-              skip_set_path = TRUE;
-            }
+          skip_set_path = TRUE;
         }
 
-      if (!skip_set_path && (target_rev != base_rev || target_lock))
+      if (!skip_set_path && (explicit_rev || target_lock))
         {
           /* If this entry is a file node, we just want to report that
              node's revision.  Since we are looking at the actual target
              of the report (not some file in a subdirectory of a target
              directory), and that target is a file, we need to pass an
              empty string to set_path. */
-          err = reporter->set_path(report_baton, "", base_rev,
+          err = reporter->set_path(report_baton, "", target_rev,
                                    target_depth,
                                    FALSE,
                                    target_lock ? target_lock->token : NULL,
-                                   pool);
+                                   scratch_pool);
           if (err)
             goto abort_report;
         }
     }
 
   /* Finish the report, which causes the update editor to be driven. */
-  return reporter->finish_report(report_baton, pool);
+  return reporter->finish_report(report_baton, scratch_pool);
 
  abort_report:
   /* Clean up the fs transaction. */
-  if ((fserr = reporter->abort_report(report_baton, pool)))
+  if ((fserr = reporter->abort_report(report_baton, scratch_pool)))
     {
       fserr = svn_error_quick_wrap(fserr, _("Error aborting report"));
       svn_error_compose(err, fserr);