Hi Stefan!

A few questions and a WIP patch for making the patch code deal with
property targets being dirs.

* How should we deal with SVN_ERR_ILLEGAL_TARGET? svn_wc_prop_set()
  throws one of those if we for instance try to set svn:executable on a
  dir or svn:ignore on a file. Should we do some kind of skipped prop
  notification?

* Are you ok with the change I made in resolve_target_path()? If we only
  have property changes to a file than it's ok to have a dir as a
  target.

* What should we do if the target dir for a property is locally_deleted?
  I think we should skip it (that's what the code does right now).

I said to you earlier on IRC that I didn't quite understand how we
determined if we had a valid patch target. Do you agree with my doc
change for resolve_target_path() and the two sections below?

* Do you agree on this definition:
  ! target->skipped => We have an add/del/mod for target
  target->node_kind_on_disk => We have a mod for target. (special case:
  if we're adding to an existing file we might have an add if the target
  already is the expected result after patching).

* For properties I have:
  ! target->skipped && is_prop_hunk => We have an add/del/mod for
  prop_target.
  prop_target->content_info->stream => We have a mod for prop_target.

My recent work has been an attempt to make the matching/applying part as
generic as possible, e.g. work for both properties and texts. My limited
testing suggests I've succeeded with that. But I'll have to introduce a
couple of if statements and flags to distinguish between props and text
changes.


[[[
Enable the patch code to use dirs as targets if we only have property
changes.

* subversion/libsvn_client/patch.c
  (patch_target_t): Add fields 'has_text_changes' and 'has_prop_changes'
    to be able to decide if we should install tmp files for text and/or
    props. It's needed since we may have a dir as a target for a
    property. If we'd try to copy the tmp file for the text changes onto
    a dir we get an error.
  (resolve_target_path): Add new parameter 'only_prop_changes' to help
    us determine the case when a dir is a valid target.
  (init_patch_target): Update caller of resolve_target_path().
  (apply_hunk): Record if we've done any changes to props or text
    content.
  (apply_patches): Only call install_patched_target() if we have changed
    the text contents.
]]]

Thanks,
Daniel
Index: subversion/libsvn_client/patch.c
===================================================================
--- subversion/libsvn_client/patch.c	(revision 979179)
+++ subversion/libsvn_client/patch.c	(arbetskopia)
@@ -186,6 +186,12 @@ typedef struct patch_target_t {
   /* True if the target has the executable bit set. */
   svn_boolean_t executable;
 
+  /* True if the patch changes the text of the target */
+  svn_boolean_t has_text_changes;
+
+  /* True if the patch changes any of the properties of the target */
+  svn_boolean_t has_prop_changes;
+
   /* All the information that is specifict to the content of the target. */
   target_content_info_t *content_info;
 
@@ -303,6 +309,9 @@ obtain_eol_and_keywords_for_file(apr_hash_t **keyw
  * If possible, determine TARGET->WC_PATH, TARGET->ABS_PATH, TARGET->KIND,
  * TARGET->ADDED, and TARGET->PARENT_DIR_EXISTS.
  * Indicate in TARGET->SKIPPED whether the target should be skipped.
+ * The target should be skipped if the versioned path does not exist or does
+ * not match our expected type, e.g. it should be a file unless we're
+ * dealing with a patch that has ONLY_PROP_CHANGES.
  * STRIP_COUNT specifies the number of leading path components
  * which should be stripped from target paths in the patch.
  * Use RESULT_POOL for allocations of fields in TARGET.
@@ -312,6 +321,7 @@ resolve_target_path(patch_target_t *target,
                     const char *path_from_patchfile,
                     const char *local_abspath,
                     int strip_count,
+                    svn_boolean_t only_prop_changes,
                     svn_wc_context_t *wc_ctx,
                     apr_pool_t *result_pool,
                     apr_pool_t *scratch_pool)
@@ -341,6 +351,8 @@ resolve_target_path(patch_target_t *target,
     {
       target->local_relpath = svn_dirent_is_child(local_abspath, stripped_path,
                                                   result_pool);
+
+      /* ### We need to allow setting props on the wc root dir */
       if (! target->local_relpath)
         {
           /* The target path is either outside of the working copy
@@ -403,7 +415,9 @@ resolve_target_path(patch_target_t *target,
     }
   SVN_ERR(svn_wc_read_kind(&target->db_kind, wc_ctx, target->local_abspath,
                            FALSE, scratch_pool));
-  if (target->db_kind == svn_node_dir)
+
+  /* We allow properties to have dirs as targets */
+  if (target->db_kind == svn_node_dir && ! only_prop_changes)
     {
       /* ### We cannot yet replace a locally deleted dir with a file,
        * ### but some day we might want to allow it. */
@@ -502,6 +516,7 @@ init_patch_target(patch_target_t **patch_target,
 {
   patch_target_t *target;
   target_content_info_t *content_info; 
+  svn_boolean_t only_prop_changes = patch->hunks->nelts == 0 ? TRUE : FALSE;
 
   content_info = apr_pcalloc(result_pool, sizeof(*content_info));
 
@@ -525,8 +540,8 @@ init_patch_target(patch_target_t **patch_target,
   target->pool = result_pool;
 
   SVN_ERR(resolve_target_path(target, patch->new_filename,
-                              base_dir, strip_count, wc_ctx,
-                              result_pool, scratch_pool));
+                              base_dir, strip_count, only_prop_changes, 
+                              wc_ctx, result_pool, scratch_pool));
   if (! target->skipped)
     {
       const char *diff_header;
@@ -1350,6 +1365,11 @@ apply_hunk(patch_target_t *target, target_content_
   while (! eof);
   svn_pool_destroy(iterpool);
 
+  if (is_prop_hunk)
+    target->has_prop_changes = TRUE;
+  else
+    target->has_text_changes = TRUE;
+
   return SVN_NO_ERROR;
 }
 
@@ -2328,9 +2348,14 @@ apply_patches(void *baton,
                              patch_target_info_t *) = target_info;
 
               if (! target->skipped)
-                SVN_ERR(install_patched_target(target, btn->abs_wc_path,
-                                               btn->ctx, btn->dry_run,
-                                               iterpool));
+                {
+                  if (target->has_text_changes)
+                    SVN_ERR(install_patched_target(target, btn->abs_wc_path,
+                                                   btn->ctx, btn->dry_run,
+                                                   iterpool));
+                  if (target->has_prop_changes)
+                    ; /* ### Here we'll going to call install_patched_prop_target() */
+                }
               SVN_ERR(send_patch_notification(target, btn->ctx, iterpool));
             }
 

Reply via email to