[svn.haxx.se] · SVN Dev · SVN Users · SVN Org · TSVN Dev · TSVN Users · Subclipse Dev · Subclipse Users · this month's index

about that patch: duplicate not a duplicate?

From: Neels J Hofmeyr <neels_at_elego.de>
Date: Fri, 15 Jan 2010 12:51:14 +0100

Hi Greg,

I committed a wc-ng patch weeeks ago, where there was a helper function that
you said was duplicate functionality to svn_wc__internal_node_get_url().
Because I was busy with a customer at the time I reverted the commit.

Looking at it again, I think it's not a duplicate but a misnomer. I'd like
to get your approval on this patch since you complained about it initially.

A helper function in the original patch was called get_node_uri(). I renamed
that to get_node_base_rev_and_url_components(), because that's what it
really does. svn_wc__internal_node_get_url() is not suitable because
 - It returns the URL in one string, but it's needed in separate
   repos-root and path-in-repos strings.
 - It does not return the base revision, which is also needed in that
   context, and which can be obtained in the same call to wc_db.
 - It uses svn_wc__db_read_info(), but it looks to me like
   svn_wc__db_base_get_info() is the better choice, since that
   context explicitly wants the BASE information.

Here is the entire patch again based on current trunk.

Thanks,
~Neels

wc-ng: Remove use of svn_wc_entry_t from tree-conflict detection during update.
Keep the outcome identical, avoid fixing.

Changes in behavior are pending and discussed on dev@:
http://subversion.tigris.org/ds/viewMessage.do?dsForumId=462&dsMessageId=2415071
Subject: Re: wc-ng patch review
Date: Fri, 06 Nov 2009 11:43:05 +0000
Message-ID: <1257507785.8865.46.camel_at_edith.foad.me.uk>

* subversion/libsvn_wc/update_editor.c
  (SVN_WC_CONFLICT_REASON_NONE): New local #define.
  (get_node_working_state, get_node_base_rev_and_url_components):
    New static functions, for check_tree_conflict().
  (check_tree_conflict): Replace svn_wc_entry_t use with calls to the WC DB
    via the new helper functions. Remove obsolete check for duplicate tree
    conflict involving an add of a file external (cannot reproduce).
--This line, and those below, will be ignored--
Index: subversion/libsvn_wc/update_editor.c
===================================================================
--- subversion/libsvn_wc/update_editor.c (revision 899602)
+++ subversion/libsvn_wc/update_editor.c (working copy)
@@ -1537,6 +1537,175 @@ tree_has_local_mods(svn_boolean_t *modif
 }
 
 
+#define SVN_WC_CONFLICT_REASON_NONE (svn_wc_conflict_reason_t)(-1)
+
+/* Query a node's local status found in DB at LOCAL_ABSPATH.
+ *
+ * Return POSSIBLE_CONFLICT_REASON, which is the current status / schedule /
+ * difference-between-BASE-and-WORKING of the node, paraphrased into an
+ * svn_wc_conflict_reason_t. For example, if the node is replaced by
+ * WORKING, this returns svn_wc_conflict_reason_replaced. If this node is
+ * not changed by WORKING, this returns SVN_WC_CONFLICT_REASON_NONE. If it's
+ * not SVN_WC_CONFLICT_REASON_NONE, POSSIBLE_CONFLICT_REASON can be plugged
+ * directly into a tree-conflict descriptor struct (i.e.
+ * svn_wc_conflict_description2_t) once this reason is found to conflict
+ * with an incoming action.
+ *
+ * Return LOCAL_ABSPATH's KIND in the BASE tree, which is
+ * - svn_node_file for a file or symlink,
+ * - svn_node_dir for a directory and
+ * - svn_node_none if not found in BASE;
+ * - svn_node_unknown in all other cases. ### TODO: check each of those
+ * "other cases" (e.g. DB reports "unknown", ...) and make this
+ * svn_node_none if possible.
+ */
+static svn_error_t*
+get_node_working_state(svn_wc_conflict_reason_t *possible_conflict_reason,
+ svn_node_kind_t *kind,
+ svn_wc__db_t *db,
+ const char *local_abspath,
+ apr_pool_t *scratch_pool)
+{
+ svn_error_t *err;
+ svn_wc__db_status_t status;
+ svn_wc__db_kind_t db_kind;
+ svn_boolean_t base_shadowed;
+
+ *possible_conflict_reason = SVN_WC_CONFLICT_REASON_NONE;
+ *kind = svn_node_unknown;
+
+ err = svn_wc__db_read_info(&status,
+ &db_kind,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL,
+ &base_shadowed,
+ NULL, NULL,
+ db,
+ local_abspath,
+ scratch_pool,
+ scratch_pool);
+
+ if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
+ {
+ svn_error_clear(err);
+ *possible_conflict_reason = svn_wc_conflict_reason_missing;
+ *kind = svn_node_none;
+ }
+ else
+ {
+ SVN_ERR(err);
+
+ /* Find the "reason" (local schedule) of the potential conflict. */
+ if (status == svn_wc__db_status_added
+ || status == svn_wc__db_status_obstructed_add)
+ {
+ *possible_conflict_reason = svn_wc_conflict_reason_added;
+ /* Is it a replace? */
+ if (base_shadowed)
+ {
+ svn_wc__db_status_t base_status;
+ SVN_ERR(svn_wc__db_base_get_info(&base_status, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL,
+ db, local_abspath,
+ scratch_pool,
+ scratch_pool));
+ if (base_status != svn_wc__db_status_not_present)
+ *possible_conflict_reason = svn_wc_conflict_reason_replaced;
+ }
+ }
+ else
+ if (status == svn_wc__db_status_deleted
+ || status == svn_wc__db_status_obstructed_delete)
+ *possible_conflict_reason = svn_wc_conflict_reason_deleted;
+
+ /* Translate the node kind. */
+ if (db_kind == svn_wc__db_kind_file
+ || db_kind == svn_wc__db_kind_symlink)
+ *kind = svn_node_file;
+ else
+ if (db_kind == svn_wc__db_kind_dir
+ || db_kind == svn_wc__db_kind_subdir)
+ *kind = svn_node_dir;
+ else
+ *kind = svn_node_unknown;
+ }
+
+ return SVN_NO_ERROR;
+}
+
+/* Find the source-left REVISON, REPOS_RELPATH and REPOS_ROOT_URL for
+ * recording a tree-conflict on node LOCAL_ABSPATH in DB.
+ */
+static svn_error_t*
+get_node_base_rev_and_url_components(svn_revnum_t *base_revision,
+ const char **repos_relpath,
+ const char **repos_root_url,
+ svn_wc__db_t *db,
+ const char *local_abspath,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ svn_error_t *err;
+ svn_boolean_t do_scan = FALSE;
+ *base_revision = SVN_INVALID_REVNUM;
+
+ /* First cover all the cases that have a base present.
+ * The only ones that lack a base are added, copied, moved_here.
+ */
+ err = svn_wc__db_base_get_info(NULL, NULL,
+ base_revision,
+ repos_relpath,
+ repos_root_url,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ db,
+ local_abspath,
+ result_pool,
+ scratch_pool);
+
+ if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
+ {
+ svn_error_clear(err);
+ do_scan = TRUE;
+ }
+ else
+ SVN_ERR(err);
+
+ if (do_scan || !SVN_IS_VALID_REVNUM(*base_revision) || !*repos_root_url)
+ {
+ /* No base found. Assume this is an 'add'. */
+ svn_wc__db_status_t added_status;
+
+ SVN_ERR(svn_wc__db_scan_addition(&added_status, NULL,
+ repos_relpath,
+ repos_root_url,
+ NULL, NULL, NULL, NULL,
+ base_revision,
+ db,
+ local_abspath,
+ result_pool,
+ scratch_pool));
+
+ /* If we ever hit a non-add here, we need to query the actual status
+ * of the node and handle other cases accordingly. */
+ SVN_ERR_ASSERT(added_status == svn_wc__db_status_added
+ || added_status == svn_wc__db_status_obstructed_add
+ || added_status == svn_wc__db_status_copied
+ || added_status == svn_wc__db_status_moved_here);
+ }
+
+ /* Legacy behaviour from svn_wc__get_entry() use.
+ * ### TODO check if this is still needed, and, if yes, why. */
+ if (*repos_root_url && !*repos_relpath)
+ *repos_relpath = "";
+
+ return SVN_NO_ERROR;
+}
+
+
 /* Check whether the incoming change ACTION on FULL_PATH would conflict with
  * LOCAL_ABSPATH's scheduled change. If so, then raise a tree conflict with
  * LOCAL_ABSPATH as the victim.
@@ -1572,86 +1741,64 @@ check_tree_conflict(svn_wc_conflict_desc
                     svn_boolean_t inside_deleted_subtree,
                     apr_pool_t *pool)
 {
- svn_wc_conflict_reason_t reason = (svn_wc_conflict_reason_t)(-1);
+ svn_wc_conflict_reason_t reason = SVN_WC_CONFLICT_REASON_NONE;
   svn_boolean_t all_mods_are_deletes = FALSE;
- const svn_wc_entry_t *entry;
- svn_error_t *err;
-
- err = svn_wc__get_entry(&entry, eb->db, local_abspath, TRUE,
- svn_node_unknown, FALSE, pool, pool);
-
- if (err && err->apr_err == SVN_ERR_NODE_UNEXPECTED_KIND)
- svn_error_clear(err);
- else
- SVN_ERR(err);
-
- if (entry)
- {
- svn_boolean_t hidden;
- SVN_ERR(svn_wc__db_node_hidden(&hidden, eb->db, local_abspath, pool));
+ svn_wc_conflict_reason_t possible_conflict_reason;
+ svn_node_kind_t kind;
 
- if (hidden)
- entry = NULL;
- }
+ SVN_ERR(get_node_working_state(&possible_conflict_reason, &kind,
+ eb->db, local_abspath, pool));
 
   switch (action)
     {
+
     case svn_wc_conflict_action_edit:
       /* Use case 1: Modifying a locally-deleted item.
          If LOCAL_ABSPATH is an incoming leaf edit within a local
          tree deletion then we will already have recorded a tree
          conflict on the locally deleted parent tree. No need
          to record a conflict within the conflict. */
- if ((entry->schedule == svn_wc_schedule_delete
- || entry->schedule == svn_wc_schedule_replace)
- && !inside_deleted_subtree)
- reason = entry->schedule == svn_wc_schedule_delete
- ? svn_wc_conflict_reason_deleted
- : svn_wc_conflict_reason_replaced;
+ if (!inside_deleted_subtree
+ && (possible_conflict_reason == svn_wc_conflict_reason_deleted
+ || possible_conflict_reason == svn_wc_conflict_reason_replaced))
+ reason = possible_conflict_reason;
       break;
 
     case svn_wc_conflict_action_add:
- /* Use case "3.5": Adding a locally-added item.
- *
- * When checking out a file-external, add_file() is called twice:
- * 1.) In the main update, a minimal entry is created.
- * 2.) In the external update, the file is added properly.
- * Don't raise a tree conflict the second time! */
- if (entry && !entry->file_external_path)
- reason = svn_wc_conflict_reason_added;
+ /* Use case "3.5": Adding a locally-added item. */
+ if (possible_conflict_reason == svn_wc_conflict_reason_added)
+ reason = possible_conflict_reason;
       break;
 
     case svn_wc_conflict_action_delete:
     case svn_wc_conflict_action_replace:
       /* Use case 3: Deleting a locally-deleted item. */
- if (entry->schedule == svn_wc_schedule_delete
- || entry->schedule == svn_wc_schedule_replace)
+ if (possible_conflict_reason == svn_wc_conflict_reason_deleted
+ || possible_conflict_reason == svn_wc_conflict_reason_replaced)
         {
           /* If LOCAL_ABSPATH is an incoming leaf deletion within a local
              tree deletion then we will already have recorded a tree
              conflict on the locally deleted parent tree. No need
              to record a conflict within the conflict. */
           if (!inside_deleted_subtree)
- reason = entry->schedule == svn_wc_schedule_delete
- ? svn_wc_conflict_reason_deleted
- : svn_wc_conflict_reason_replaced;
+ reason = possible_conflict_reason;
         }
       else
         {
           svn_boolean_t modified = FALSE;
 
           /* Use case 2: Deleting a locally-modified item. */
- if (entry->kind == svn_node_file)
+ if (kind == svn_node_file)
             {
- if (entry->schedule != svn_wc_schedule_normal)
+ if (possible_conflict_reason != SVN_WC_CONFLICT_REASON_NONE)
                 modified = TRUE;
               else
                 SVN_ERR(entry_has_local_mods(&modified, eb->db, local_abspath,
- entry->kind, pool));
- if (entry->schedule == svn_wc_schedule_delete)
+ kind, pool));
+ if (possible_conflict_reason == svn_wc_conflict_reason_deleted)
                 all_mods_are_deletes = TRUE;
             }
- else if (entry->kind == svn_node_dir)
+ else if (kind == svn_node_dir)
             {
               /* We must detect deep modifications in a directory tree,
                * but the update editor will not visit the subdirectories
@@ -1681,35 +1828,37 @@ check_tree_conflict(svn_wc_conflict_desc
 
   /* If a conflict was detected, append log commands to the log accumulator
    * to record it. */
- if (reason != (svn_wc_conflict_reason_t)(-1))
+ if (reason != SVN_WC_CONFLICT_REASON_NONE)
     {
       svn_wc_conflict_description2_t *conflict;
       const svn_wc_conflict_version_t *src_left_version;
       const svn_wc_conflict_version_t *src_right_version;
+ svn_revnum_t base_revision;
       const char *repos_url = NULL;
       const char *path_in_repos = NULL;
- svn_node_kind_t left_kind = (entry->schedule == svn_wc_schedule_add)
+ svn_node_kind_t left_kind = (reason == svn_wc_conflict_reason_added)
                                   ? svn_node_none
- : (entry->schedule == svn_wc_schedule_delete)
+ : (reason == svn_wc_conflict_reason_deleted)
                                     ? svn_node_unknown
- : entry->kind;
+ : kind;
 
       /* Source-left repository root URL and path in repository.
        * The Source-right ones will be the same for update.
        * For switch, only the path in repository will differ, because
        * a cross-repository switch is not possible. */
- repos_url = entry->repos;
- path_in_repos = svn_uri_is_child(repos_url, entry->url, pool);
- if (path_in_repos == NULL)
- path_in_repos = "";
+ SVN_ERR(get_node_base_rev_and_url_components(&base_revision,
+ &path_in_repos,
+ &repos_url, eb->db,
+ local_abspath, pool,
+ pool));
 
       src_left_version = svn_wc_conflict_version_create(repos_url,
                                                         path_in_repos,
- entry->revision,
+ base_revision,
                                                         left_kind,
                                                         pool);
 
- /* entry->kind is both base kind and working kind, because schedule
+ /* kind is both base kind and working kind, because schedule
        * replace-by-different-kind is not supported. */
       /* ### TODO: but in case the entry is locally removed, entry->kind
        * is svn_node_none and doesn't reflect the older kind. Then we
@@ -1744,7 +1893,7 @@ check_tree_conflict(svn_wc_conflict_desc
                                                          pool);
 
       conflict = svn_wc_conflict_description_create_tree2(
- local_abspath, entry->kind,
+ local_abspath, kind,
         eb->switch_url ? svn_wc_operation_switch : svn_wc_operation_update,
         src_left_version, src_right_version, pool);
       conflict->action = action;

Received on 2010-01-15 12:57:26 CET

This is an archived mail posted to the Subversion Dev mailing list.