subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From s...@apache.org
Subject svn commit: r919460 - in /subversion/trunk/subversion: include/svn_client.h libsvn_client/patch.c svn/cl.h svn/main.c svn/patch-cmd.c tests/cmdline/patch_tests.py
Date Fri, 05 Mar 2010 15:57:24 GMT
Author: stsp
Date: Fri Mar  5 15:57:23 2010
New Revision: 919460

URL: http://svn.apache.org/viewvc?rev=919460&view=rev
Log:
Fix issue #3434, "svn patch API should have a patch target filter"

In addition to the requirements listed in issue #3434, allow the
filter list to contain glob patterns, and make the 'svn patch' command
capable of filtering patch targets.

* subversion/include/svn_client.h
  (svn_client_patch): Add FILTER_GLOBS parameter.

* subversion/libsvn_client/patch.c
  (): Include apr_fnmatch.h.
  (patch_target_t): New field FILTERED.
  (resolve_target_path, apply_one_patch): New paramter FILTER_GLOBS.
   If a target matches a glob in FILTER_GLOBS, mark it as filtered
   and return immediately.
  (apply_patches_baton_t): New field FILTER_GLOBS.
  (apply_patches): Ignore filtered targets.
  (svn_client_patch): Add FILTER_GLOBS parameter, stuff it into the
   apply_patches baton.

* subversion/svn/cl.h
  (svn_cl__opt_state_t): New field EXCLUDE_PATTERNS.

* subversion/svn/main.c
  (svn_cl__longopt_t): New field EXCLUDE_PATTERN.
  (svn_cl__options): Add --exclude-pattern option.
  (svn_cl__cmd_table): Make 'svn patch' accept the --exclude-pattern option.
  (main): Handle --exclude-pattern option.

* subversion/svn/patch-cmd.c
  (svn_cl__patch): Pass OPT_STATE->exclude_patterns on to svn_client_patch().

* subversion/tests/cmdline/patch_tests.py
  (patch_with_exclude_patterns): New test.
  (test_list): Add new test.

Modified:
    subversion/trunk/subversion/include/svn_client.h
    subversion/trunk/subversion/libsvn_client/patch.c
    subversion/trunk/subversion/svn/cl.h
    subversion/trunk/subversion/svn/main.c
    subversion/trunk/subversion/svn/patch-cmd.c
    subversion/trunk/subversion/tests/cmdline/patch_tests.py

Modified: subversion/trunk/subversion/include/svn_client.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/include/svn_client.h?rev=919460&r1=919459&r2=919460&view=diff
==============================================================================
--- subversion/trunk/subversion/include/svn_client.h (original)
+++ subversion/trunk/subversion/include/svn_client.h Fri Mar  5 15:57:23 2010
@@ -4848,6 +4848,10 @@
  * This is useful when applying a unidiff which was created with the
  * original and modified files swapped due to human error.
  *
+ * If @a filter_globs is not NULL, patch targets matching any glob
+ * pattern in @a filter_globs will not be patched. The match is performed
+ * on the target path as parsed from the patch file, after canonicalization.
+ *
  * If @a ctx->notify_func2 is non-NULL, invoke @a ctx->notify_func2 with
  * @a ctx->notify_baton2 as patching progresses.
  *
@@ -4862,6 +4866,7 @@
                  svn_boolean_t dry_run,
                  int strip_count,
                  svn_boolean_t reverse,
+                 apr_array_header_t *filter_globs,
                  svn_client_ctx_t *ctx,
                  apr_pool_t *pool);
 

Modified: subversion/trunk/subversion/libsvn_client/patch.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/patch.c?rev=919460&r1=919459&r2=919460&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/patch.c (original)
+++ subversion/trunk/subversion/libsvn_client/patch.c Fri Mar  5 15:57:23 2010
@@ -28,6 +28,7 @@
 /*** Includes. ***/
 
 #include <apr_hash.h>
+#include <apr_fnmatch.h>
 #include "svn_client.h"
 #include "svn_dirent_uri.h"
 #include "svn_io.h"
@@ -133,6 +134,9 @@
   /* True if the target had to be skipped for some reason. */
   svn_boolean_t skipped;
 
+  /* True if the target matches a filter glob pattern. */
+  svn_boolean_t filtered;
+
   /* True if at least one hunk was rejected. */
   svn_boolean_t had_rejects;
 
@@ -321,15 +325,18 @@
  * which should be stripped from target paths in the patch.
  * Upon success, allocate the patch target structure in RESULT_POOL.
  * Else, set *target to NULL.
+ * If a target matches a glob in FILTER_GLOBS, mark it as filtered.
  * Use SCRATCH_POOL for all other allocations. */
 static svn_error_t *
 init_patch_target(patch_target_t **patch_target,
                   const svn_patch_t *patch,
                   const char *base_dir,
                   svn_wc_context_t *wc_ctx, int strip_count,
+                  apr_array_header_t *filter_globs,
                   apr_pool_t *result_pool, apr_pool_t *scratch_pool)
 {
   patch_target_t *target;
+  int i;
 
   target = apr_pcalloc(result_pool, sizeof(*target));
 
@@ -337,6 +344,25 @@
                               base_dir, strip_count, wc_ctx,
                               result_pool, scratch_pool));
 
+  target->filtered = FALSE;
+  if (filter_globs)
+    {
+      for (i = 0; i < filter_globs->nelts; i++)
+        {
+          const char *glob;
+
+          glob = APR_ARRAY_IDX(filter_globs, i, const char *);
+          target->filtered = (apr_fnmatch(glob,
+                                          target->canon_path_from_patchfile,
+                                          APR_FNM_CASE_BLIND) == APR_SUCCESS);
+          if (target->filtered)
+            {
+              *patch_target = target;
+              return SVN_NO_ERROR;
+            }
+        }
+    }
+
   target->local_mods = FALSE;
   target->executable = FALSE;
 
@@ -1029,12 +1055,13 @@
  * in RESULT_POOL. Use WC_CTX as the working copy context.
  * STRIP_COUNT specifies the number of leading path components
  * which should be stripped from target paths in the patch.
+ * If a target matches a glob in FILTER_GLOBS, mark it as filtered.
  * Do temporary allocations in SCRATCH_POOL. */
 static svn_error_t *
 apply_one_patch(patch_target_t **patch_target, svn_patch_t *patch,
                 const char *abs_wc_path, svn_wc_context_t *wc_ctx,
-                int strip_count, apr_pool_t *result_pool,
-                apr_pool_t *scratch_pool)
+                int strip_count, apr_array_header_t *filter_globs,
+                apr_pool_t *result_pool, apr_pool_t *scratch_pool)
 {
   patch_target_t *target;
   apr_pool_t *iterpool;
@@ -1042,9 +1069,9 @@
   static const int MAX_FUZZ = 2;
 
   SVN_ERR(init_patch_target(&target, patch, abs_wc_path, wc_ctx, strip_count,
-                            result_pool, scratch_pool));
+                            filter_globs, result_pool, scratch_pool));
 
-  if (target->skipped)
+  if (target->skipped || target->filtered)
     {
       *patch_target = target;
       return SVN_NO_ERROR;
@@ -1351,6 +1378,9 @@
   /* Whether to apply the patch in reverse. */
   svn_boolean_t reverse;
 
+  /* Glob patterns. Files matching any of these patterns won't be patched. */
+  apr_array_header_t *filter_globs;
+
   /* The client context. */
   svn_client_ctx_t *ctx;
 } apply_patches_baton_t;
@@ -1403,8 +1433,11 @@
 
           SVN_ERR(apply_one_patch(&target, patch, btn->abs_wc_path,
                                   btn->ctx->wc_ctx, btn->strip_count,
-                                  scratch_pool, iterpool));
-          APR_ARRAY_PUSH(targets, patch_target_t *) = target;
+                                  btn->filter_globs, scratch_pool, iterpool));
+          if (target->filtered)
+            SVN_ERR(svn_diff__close_patch(patch));
+          else
+            APR_ARRAY_PUSH(targets, patch_target_t *) = target;
         }
     }
   while (patch);
@@ -1440,6 +1473,7 @@
                  svn_boolean_t dry_run,
                  int strip_count,
                  svn_boolean_t reverse,
+                 apr_array_header_t *filter_globs,
                  svn_client_ctx_t *ctx,
                  apr_pool_t *pool)
 {
@@ -1455,6 +1489,7 @@
   baton.ctx = ctx;
   baton.strip_count = strip_count;
   baton.reverse = reverse;
+  baton.filter_globs = filter_globs;
 
   SVN_ERR(svn_wc__call_with_write_lock(apply_patches, &baton,
                                        ctx->wc_ctx, local_abspath,

Modified: subversion/trunk/subversion/svn/cl.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svn/cl.h?rev=919460&r1=919459&r2=919460&view=diff
==============================================================================
--- subversion/trunk/subversion/svn/cl.h (original)
+++ subversion/trunk/subversion/svn/cl.h Fri Mar  5 15:57:23 2010
@@ -224,6 +224,7 @@
   int strip_count; /* number of leading path components to strip */
   svn_boolean_t ignore_keywords;  /* do not expand keywords */
   svn_boolean_t reverse_diff;     /* reverse a diff (e.g. when patching) */
+  apr_array_header_t *exclude_patterns; /* targets to exclude from operation */
 } svn_cl__opt_state_t;
 
 

Modified: subversion/trunk/subversion/svn/main.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svn/main.c?rev=919460&r1=919459&r2=919460&view=diff
==============================================================================
--- subversion/trunk/subversion/svn/main.c (original)
+++ subversion/trunk/subversion/svn/main.c Fri Mar  5 15:57:23 2010
@@ -117,6 +117,7 @@
   opt_show_copies_as_adds,
   opt_ignore_keywords,
   opt_reverse_diff,
+  opt_exclude_pattern,
 } svn_cl__longopt_t;
 
 /* Option codes and descriptions for the command line client.
@@ -347,6 +348,16 @@
                     N_("apply the unidiff in reverse\n"
                        "                             "
                        "[alias: --rd]")},
+  {"exclude-pattern", opt_exclude_pattern, 1,
+                    N_("do not operate on targets matching ARG,\n"
+                       "                             "
+                       "which may be a glob pattern such as '*.txt'.\n"
+                       "                             "
+                       "If this option is specified multiple times,\n"
+                       "                             "
+                       "all patterns are matched in turn.\n"
+                       "                             "
+                       "[alias: --ep]")},
   /* Long-opt Aliases
    *
    * These have NULL desriptions, but an option code that matches some
@@ -371,6 +382,7 @@
   {"ri",            opt_reintegrate, 0, NULL},
   {"sca",           opt_show_copies_as_adds, 0, NULL},
   {"ik",            opt_ignore_keywords, 0, NULL},
+  {"ep",            opt_exclude_pattern, 1, NULL},
 
   {0,               0, 0, 0},
 };
@@ -812,7 +824,7 @@
      "  for addition. Use 'svn revert' to undo deletions and additions you\n"
      "  do not agree with.\n"
      ),
-    {'q', opt_dry_run, 'p', opt_reverse_diff} },
+    {'q', opt_dry_run, 'p', opt_reverse_diff, opt_exclude_pattern} },
 
   { "propdel", svn_cl__propdel, {"pdel", "pd"}, N_
     ("Remove a property from files, dirs, or revisions.\n"
@@ -1727,6 +1739,12 @@
       case opt_reverse_diff:
         opt_state.reverse_diff = TRUE;
         break;
+      case opt_exclude_pattern:
+        if (opt_state.exclude_patterns == NULL)
+          opt_state.exclude_patterns = apr_array_make(pool, 1,
+                                                      sizeof (const char *));
+        APR_ARRAY_PUSH(opt_state.exclude_patterns, const char *) = opt_arg;
+        break;
       default:
         /* Hmmm. Perhaps this would be a good place to squirrel away
            opts that commands like svn diff might need. Hmmm indeed. */

Modified: subversion/trunk/subversion/svn/patch-cmd.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svn/patch-cmd.c?rev=919460&r1=919459&r2=919460&view=diff
==============================================================================
--- subversion/trunk/subversion/svn/patch-cmd.c (original)
+++ subversion/trunk/subversion/svn/patch-cmd.c Fri Mar  5 15:57:23 2010
@@ -78,7 +78,8 @@
 
   SVN_ERR(svn_client_patch(abs_patch_path, abs_target_path,
                            opt_state->dry_run, opt_state->strip_count,
-                           opt_state->reverse_diff, ctx, pool));
+                           opt_state->reverse_diff,
+                           opt_state->exclude_patterns, ctx, pool));
 
   if (! opt_state->quiet)
     SVN_ERR(svn_cl__print_conflict_stats(ctx->notify_baton2, pool));

Modified: subversion/trunk/subversion/tests/cmdline/patch_tests.py
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/patch_tests.py?rev=919460&r1=919459&r2=919460&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/patch_tests.py (original)
+++ subversion/trunk/subversion/tests/cmdline/patch_tests.py Fri Mar  5 15:57:23 2010
@@ -1677,6 +1677,165 @@
       expected_output = ["Reverted '" + mu_path + "'\n"]
       svntest.actions.run_and_verify_svn(None, expected_output, [], 'revert', '-R', wc_dir)
 
+def patch_with_exclude_patterns(sbox):
+  "patch with --exclude-patterns"
+
+  sbox.build()
+  wc_dir = sbox.wc_dir
+
+  patch_file_path = tempfile.mkstemp(dir=os.path.abspath(svntest.main.temp_dir))[1]
+  mu_path = os.path.join(wc_dir, 'A', 'mu')
+
+  mu_contents = [
+    "Dear internet user,\n",
+    "\n",
+    "We wish to congratulate you over your email success in our computer\n",
+    "Balloting. This is a Millennium Scientific Electronic Computer Draw\n",
+    "in which email addresses were used. All participants were selected\n",
+    "through a computer ballot system drawn from over 100,000 company\n",
+    "and 50,000,000 individual email addresses from all over the world.\n",
+    "\n",
+    "Your email address drew and have won the sum of  750,000 Euros\n",
+    "( Seven Hundred and Fifty Thousand Euros) in cash credited to\n",
+    "file with\n",
+    "    REFERENCE NUMBER: ESP/WIN/008/05/10/MA;\n",
+    "    WINNING NUMBER : 14-17-24-34-37-45-16\n",
+    "    BATCH NUMBERS :\n",
+    "    EULO/1007/444/606/08;\n",
+    "    SERIAL NUMBER: 45327\n",
+    "and PROMOTION DATE: 13th June. 2009\n",
+    "\n",
+    "To claim your winning prize, you are to contact the appointed\n",
+    "agent below as soon as possible for the immediate release of your\n",
+    "winnings with the below details.\n",
+    "\n",
+    "Again, we wish to congratulate you over your email success in our\n"
+    "computer Balloting.\n"
+  ]
+
+  # Set mu contents
+  svntest.main.file_write(mu_path, ''.join(mu_contents))
+  expected_output = svntest.wc.State(wc_dir, {
+    'A/mu'       : Item(verb='Sending'),
+    })
+  expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+  expected_status.tweak('A/mu', wc_rev=2)
+  svntest.actions.run_and_verify_commit(wc_dir, expected_output,
+                                        expected_status, None, wc_dir)
+
+  # Apply patch
+
+  unidiff_patch = [
+    "Index: A/D/gamma\n",
+    "===================================================================\n",
+    "--- A/D/gamma\t(revision 1)\n",
+    "+++ A/D/gamma\t(working copy)\n",
+    "@@ -1 +1 @@\n",
+    "-This is the file 'gamma'.\n",
+    "+It is the file 'gamma'.\n",
+    "Index: iota\n",
+    "===================================================================\n",
+    "--- iota\t(revision 1)\n",
+    "+++ iota\t(working copy)\n",
+    "@@ -1 +1,2 @@\n",
+    " This is the file 'iota'.\n",
+    "+Some more bytes\n",
+    "\n",
+    "Index: new\n",
+    "===================================================================\n",
+    "--- new	(revision 0)\n",
+    "+++ new	(revision 0)\n",
+    "@@ -0,0 +1 @@\n",
+    "+new\n",
+    "\n",
+    "--- A/mu.orig	2009-06-24 15:23:55.000000000 +0100\n",
+    "+++ A/mu	2009-06-24 15:21:23.000000000 +0100\n",
+    "@@ -6,6 +6,9 @@\n",
+    " through a computer ballot system drawn from over 100,000 company\n",
+    " and 50,000,000 individual email addresses from all over the world.\n",
+    " \n",
+    "+It is a promotional program aimed at encouraging internet users;\n",
+    "+therefore you do not need to buy ticket to enter for it.\n",
+    "+\n",
+    " Your email address drew and have won the sum of  750,000 Euros\n",
+    " ( Seven Hundred and Fifty Thousand Euros) in cash credited to\n",
+    " file with\n",
+    "@@ -14,11 +17,8 @@\n",
+    "     BATCH NUMBERS :\n",
+    "     EULO/1007/444/606/08;\n",
+    "     SERIAL NUMBER: 45327\n",
+    "-and PROMOTION DATE: 13th June. 2009\n",
+    "+and PROMOTION DATE: 14th June. 2009\n",
+    " \n",
+    " To claim your winning prize, you are to contact the appointed\n",
+    " agent below as soon as possible for the immediate release of your\n",
+    " winnings with the below details.\n",
+    "-\n",
+    "-Again, we wish to congratulate you over your email success in our\n",
+    "-computer Balloting.\n",
+    "Index: A/B/E/beta\n",
+    "===================================================================\n",
+    "--- A/B/E/beta	(revision 1)\n",
+    "+++ A/B/E/beta	(working copy)\n",
+    "@@ -1 +0,0 @@\n",
+    "-This is the file 'beta'.\n",
+  ]
+
+  svntest.main.file_write(patch_file_path, ''.join(unidiff_patch))
+
+  gamma_contents = "It is the file 'gamma'.\n"
+  iota_contents = "This is the file 'iota'.\nSome more bytes\n"
+  new_contents = "new\n"
+  mu_contents = [
+    "Dear internet user,\n",
+    "\n",
+    "We wish to congratulate you over your email success in our computer\n",
+    "Balloting. This is a Millennium Scientific Electronic Computer Draw\n",
+    "in which email addresses were used. All participants were selected\n",
+    "through a computer ballot system drawn from over 100,000 company\n",
+    "and 50,000,000 individual email addresses from all over the world.\n",
+    "\n",
+    "It is a promotional program aimed at encouraging internet users;\n",
+    "therefore you do not need to buy ticket to enter for it.\n",
+    "\n",
+    "Your email address drew and have won the sum of  750,000 Euros\n",
+    "( Seven Hundred and Fifty Thousand Euros) in cash credited to\n",
+    "file with\n",
+    "    REFERENCE NUMBER: ESP/WIN/008/05/10/MA;\n",
+    "    WINNING NUMBER : 14-17-24-34-37-45-16\n",
+    "    BATCH NUMBERS :\n",
+    "    EULO/1007/444/606/08;\n",
+    "    SERIAL NUMBER: 45327\n",
+    "and PROMOTION DATE: 14th June. 2009\n",
+    "\n",
+    "To claim your winning prize, you are to contact the appointed\n",
+    "agent below as soon as possible for the immediate release of your\n",
+    "winnings with the below details.\n",
+  ]
+
+  expected_output = [
+    'U         %s\n' % os.path.join(wc_dir, 'A', 'mu'),
+  ]
+
+  expected_disk = svntest.main.greek_state.copy()
+  expected_disk.tweak('A/mu', contents=''.join(mu_contents))
+
+  expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+  expected_status.tweak('A/mu', status='M ', wc_rev=2)
+
+  expected_skip = wc.State('', { })
+
+  svntest.actions.run_and_verify_patch(wc_dir, os.path.abspath(patch_file_path),
+                                       expected_output,
+                                       expected_disk,
+                                       expected_status,
+                                       expected_skip,
+                                       None, # expected err
+                                       1, # check-props
+                                       1, # dry-run
+                                       "--exclude-pattern", "A/*/gamma",
+                                       "--exclude-pattern", "new",
+                                       "--exclude-pattern", "*a")
 
 ########################################################################
 #Run the tests
@@ -1696,6 +1855,7 @@
               patch_no_svn_eol_style,
               patch_with_svn_eol_style,
               patch_with_svn_eol_style_uncommitted,
+              patch_with_exclude_patterns,
             ]
 
 if __name__ == '__main__':



Mime
View raw message