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

[PATCH] --reverse option to invert -c/--change

From: Bart Robinson <lomew_at_pobox.com>
Date: 2006-01-12 23:02:15 CET

Hi,
Here is a patch to help flesh out the utility of the -c/--change
option.

Some background in this thread:
http://svn.haxx.se/dev/archive-2005-10/1324.shtml
(should I put that in the commit message?)

E.g.,
  svn merge -c 100 --reverse URL
same as
  svn merge -r100:99 URL

Do the tests look ok? I'm not a python stud so I just basically
imitated what Dan Berlin did in r17054.

All tests pass aside from a utf8 one that was SKIP'd.

Thanks
-- bart

[[[
Add a --reverse option reverse the sense of the -c/--change option,
making it possible to back out changes with -c rather than -r.

* subversion/svn/cl.h
  (svn_cl__longopt_t): Add enum for '--reverse' option.

* subversion/svn/main.c
  (svn_cl__options): Add 'reverse' option.
  (svn_cl__cmd_table): Merge and diff can take 'reverse' argument.
  (main): Handle parsing for 'reverse'.

* subversion/tests/cmdline/diff_tests.py
  (diff_pure_repository_update_a_file): Modify test to also verify
  that '--reverse' may not be used with '-r', only '-c'.
  (diff_only_property_change): Modify test to also use '--reverse'
  with '-c'.

* subversion/tests/cmdline/merge_tests.py
  (merge_with_implicit_target_using_c_and_reverse): New test: a copy
  of merge_with_implicit_target that uses the '-c' and '--reverse'
  options.
  (test_list): Add the new test.
]]]

Index: subversion/svn/cl.h
===================================================================
--- subversion/svn/cl.h (revision 18084)
+++ subversion/svn/cl.h (working copy)
@@ -76,7 +76,8 @@ typedef enum {
   svn_cl__strict_opt,
   svn_cl__targets_opt,
   svn_cl__version_opt,
- svn_cl__xml_opt
+ svn_cl__xml_opt,
+ svn_cl__reverse_opt
 } svn_cl__longopt_t;
 
 
Index: subversion/svn/main.c
===================================================================
--- subversion/svn/main.c (revision 18084)
+++ subversion/svn/main.c (working copy)
@@ -149,6 +149,8 @@ const apr_getopt_option_t svn_cl__option
                     N_("maximum number of log entries")},
   {"no-unlock", svn_cl__no_unlock_opt, 0,
                     N_("don't unlock the targets")},
+ {"reverse", svn_cl__reverse_opt, 0,
+ N_("reverse operation sense (use with -c)")},
   {0, 0, 0, 0}
 };
 
@@ -273,8 +275,8 @@ const svn_opt_subcommand_desc_t svn_cl__
 
   { "diff", svn_cl__diff, {"di"}, N_
     ("Display the differences between two paths.\n"
- "usage: 1. diff [-c M | -r N[:M]] [TARGET[@REV]...]\n"
- " 2. diff [-c M | -r N[:M]] --old=OLD-TGT[@OLDREV] [--new=NEW-TGT[@NEWREV]] \\\n"
+ "usage: 1. diff [-c M | -r N[:M]] [--reverse] [TARGET[@REV]...]\n"
+ " 2. diff [-c M | -r N[:M]] [--reverse] --old=OLD-TGT[@OLDREV] [--new=NEW-TGT[@NEWREV]] \\\n"
      " [PATH...]\n"
      " 3. diff OLD-URL[@OLDREV] NEW-URL[@NEWREV]\n"
      "\n"
@@ -285,6 +287,7 @@ const svn_opt_subcommand_desc_t svn_cl__
      " must be specified. M defaults to the current working version if any\n"
      " TARGET is a working copy path, otherwise it defaults to HEAD.\n"
      " The '-c M' option is equivalent to '-r N:M' where N = M-1.\n"
+ " Specifying --reverse will reverse this to mean '-r M:N'\n"
      "\n"
      " 2. Display the differences between OLD-TGT as it was seen in OLDREV and\n"
      " NEW-TGT as it was seen in NEWREV. PATHs, if given, are relative to\n"
@@ -293,12 +296,14 @@ const svn_opt_subcommand_desc_t svn_cl__
      " NEW-TGT defaults to OLD-TGT if not specified. -r N makes OLDREV default\n"
      " to N, -r N:M makes OLDREV default to N and NEWREV default to M,\n"
      " -c M makes OLDREV default to M-1 and NEWREV default to M.\n"
+ " --reverse will reverse the sense of -c M to make OLDREV default to M\n"
+ " and NEWREV default to M-1."
      "\n"
      " 3. Shorthand for 'svn diff --old=OLD-URL[@OLDREV] --new=NEW-URL[@NEWREV]'\n"
      "\n"
      " Use just 'svn diff' to display local modifications in a working copy.\n"),
     {'r', 'c', svn_cl__old_cmd_opt, svn_cl__new_cmd_opt, 'N',
- svn_cl__diff_cmd_opt, 'x', svn_cl__no_diff_deleted,
+ svn_cl__reverse_opt, svn_cl__diff_cmd_opt, 'x', svn_cl__no_diff_deleted,
      svn_cl__notice_ancestry_opt, svn_cl__force_opt, SVN_CL__AUTH_OPTIONS,
      svn_cl__config_dir_opt} },
 
@@ -420,7 +425,7 @@ const svn_opt_subcommand_desc_t svn_cl__
     ("Apply the differences between two sources to a working copy path.\n"
      "usage: 1. merge sourceURL1[@N] sourceURL2[@M] [WCPATH]\n"
      " 2. merge sourceWCPATH1@N sourceWCPATH2@M [WCPATH]\n"
- " 3. merge [-c M | -r N:M] SOURCE[@REV] [WCPATH]\n"
+ " 3. merge [-c M | -r N:M] [--reverse] SOURCE[@REV] [WCPATH]\n"
      "\n"
      " 1. In the first form, the source URLs are specified at revisions\n"
      " N and M. These are the two sources to be compared. The revisions\n"
@@ -434,14 +439,15 @@ const svn_opt_subcommand_desc_t svn_cl__
      " in which case the corresponding URL is used. This URL in\n"
      " revision REV is compared as it existed between revisions N and \n"
      " M. If REV is not specified, HEAD is assumed. The '-c M'\n"
- " option is equivalent to '-r N:M' where N = M-1.\n"
+ " option is equivalent to '-r N:M' where N = M-1. --reverse will\n"
+ " reverse this sense to mean '-r M:N' (for backing out a change).\n"
      "\n"
      " WCPATH is the working copy path that will receive the changes.\n"
      " If WCPATH is omitted, a default value of '.' is assumed, unless\n"
      " the sources have identical basenames that match a file within '.':\n"
      " in which case, the differences will be applied to that file.\n"),
     {'r', 'c', 'N', 'q', svn_cl__force_opt, svn_cl__dry_run_opt,
- svn_cl__merge_cmd_opt, svn_cl__ignore_ancestry_opt,
+ svn_cl__reverse_opt, svn_cl__merge_cmd_opt, svn_cl__ignore_ancestry_opt,
      SVN_CL__AUTH_OPTIONS, svn_cl__config_dir_opt} },
 
   { "mkdir", svn_cl__mkdir, {0}, N_
@@ -780,6 +786,8 @@ main (int argc, const char * const *argv
   svn_cl__cmd_baton_t command_baton;
   svn_auth_baton_t *ab;
   svn_config_t *cfg;
+ svn_boolean_t opt_c_given = FALSE;
+ svn_boolean_t reverse_opt_sense = FALSE;
   
   /* Initialize the app. */
   if (svn_cmdline_init ("svn", stderr) != EXIT_SUCCESS)
@@ -905,6 +913,7 @@ case 'c':
             }
           opt_state.start_revision.value.number = opt_state.end_revision.value.number - 1;
           opt_state.start_revision.kind = svn_opt_revision_number;
+ opt_c_given = TRUE;
         }
         break;
       case 'r':
@@ -1110,6 +1119,9 @@ main (int argc, const char * const *argv
       case svn_cl__no_unlock_opt:
         opt_state.no_unlock = TRUE;
         break;
+ case svn_cl__reverse_opt:
+ reverse_opt_sense = TRUE;
+ break;
       default:
         /* Hmmm. Perhaps this would be a good place to squirrel away
            opts that commands like svn diff might need. Hmmm indeed. */
@@ -1117,6 +1129,29 @@ main (int argc, const char * const *argv
       }
     }
 
+ /* If --reverse was given, flip the -c option, if given.
+ If there was no -c option, flag an error.
+ Note that we don't want to flip start/end if they did -r N:M explicitly,
+ only if they did -c. */
+ if (reverse_opt_sense)
+ {
+ if (opt_c_given)
+ {
+ /* Swap start and end. */
+ svn_revnum_t start = opt_state.start_revision.value.number;
+ opt_state.start_revision.value.number =
+ opt_state.end_revision.value.number;
+ opt_state.end_revision.value.number = start;
+ }
+ else
+ {
+ err = svn_error_create
+ (SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("Cannot specify --revision without -c"));
+ return svn_cmdline_handle_exit_error (err, pool, "svn: ");
+ }
+ }
+
   /* ### This really belongs in libsvn_client. The trouble is,
      there's no one place there to run it from, no
      svn_client_init(). We'd have to add it to all the public
Index: subversion/tests/cmdline/diff_tests.py
===================================================================
--- subversion/tests/cmdline/diff_tests.py (revision 18084)
+++ subversion/tests/cmdline/diff_tests.py (working copy)
@@ -629,6 +629,16 @@ def diff_pure_repository_update_a_file(s
                                                    svntest.main.wc_passwd)
     if check_update_added_file(diff_output): raise svntest.Failure
 
+ # Make sure specifying --reverse without a reversable co-argument fails.
+ expected_output = "svn: Cannot specify --revision without.*"
+ svntest.actions.run_and_verify_svn(None, None, expected_output,
+ 'diff', '-r', '4:5',
+ '--reverse',
+ '--username',
+ svntest.main.wc_author,
+ '--password',
+ svntest.main.wc_passwd)
+
     diff_output, err_output = svntest.main.run_svn(None, 'diff', '-r', 'head')
     if check_add_a_file_in_a_subdir_reverse(diff_output): raise svntest.Failure
 
@@ -671,6 +681,9 @@ def diff_only_property_change(sbox):
     svntest.actions.run_and_verify_svn(None, expected_reverse_output, [],
                                        'diff', '-r', '2:1')
 
+ svntest.actions.run_and_verify_svn(None, expected_reverse_output, [],
+ 'diff', '-c', '2', '--reverse')
+
     svntest.actions.run_and_verify_svn(None, expected_output, [],
                                        'diff', '-r', '1')
 
Index: subversion/tests/cmdline/merge_tests.py
===================================================================
--- subversion/tests/cmdline/merge_tests.py (revision 18084)
+++ subversion/tests/cmdline/merge_tests.py (working copy)
@@ -1282,6 +1282,72 @@ def merge_with_implicit_target (sbox):
 
 #----------------------------------------------------------------------
 
+def merge_with_implicit_target_using_c_and_reverse (sbox):
+ "merge using the -c and --reverse options"
+
+ sbox.build()
+ wc_dir = sbox.wc_dir
+
+ # Change mu for revision 2
+ mu_path = os.path.join(wc_dir, 'A', 'mu')
+ orig_mu_text = svntest.tree.get_text(mu_path)
+ added_mu_text = ""
+ for x in range(2,11):
+ added_mu_text = added_mu_text + 'This is line ' + `x` + ' in mu\n'
+ svntest.main.file_append(mu_path, added_mu_text)
+
+ # Create expected output tree for initial commit
+ expected_output = wc.State(wc_dir, {
+ 'A/mu' : Item(verb='Sending'),
+ })
+
+ # Create expected status tree; all local revisions should be at 1,
+ # but mu should be at revision 2.
+ expected_status = svntest.actions.get_virginal_state(wc_dir, 2)
+ expected_status.tweak(wc_rev=1)
+ expected_status.tweak('A/mu', wc_rev=2)
+
+ # Initial commit.
+ svntest.actions.run_and_verify_commit (wc_dir,
+ expected_output,
+ expected_status,
+ None,
+ None, None, None, None,
+ wc_dir)
+
+ # Make the "other" working copy
+ other_wc = sbox.add_wc_path('other')
+ svntest.actions.duplicate_dir(wc_dir, other_wc)
+
+ # Try the merge without an explicit target; it should succeed.
+ # Can't use run_and_verify_merge cuz it expects a directory argument.
+ mu_url = svntest.main.current_repo_url + '/A/mu'
+ was_cwd = os.getcwd()
+ try:
+ os.chdir(os.path.join(other_wc, 'A'))
+
+ # merge using URL for sourcepath
+ svntest.actions.run_and_verify_svn(None, ['U mu\n'], [],
+ 'merge', '-c', '2', '--reverse', mu_url)
+
+ # sanity-check resulting file
+ if (svntest.tree.get_text('mu') != orig_mu_text):
+ raise svntest.Failure
+
+ # merge using filename for sourcepath
+ # Cannot use run_and_verify_merge with a file target
+ svntest.actions.run_and_verify_svn(None, ['G mu\n'], [],
+ 'merge', '-c', '2', 'mu')
+
+ # sanity-check resulting file
+ if (svntest.tree.get_text('mu') != orig_mu_text + added_mu_text):
+ raise svntest.Failure
+
+ finally:
+ os.chdir(was_cwd)
+
+#----------------------------------------------------------------------
+
 def merge_with_prev (sbox):
   "merge operations using PREV revision"
 
@@ -3208,6 +3274,7 @@ test_list = [ None,
               delete_file_and_dir,
               simple_property_merges,
               merge_with_implicit_target,
+ merge_with_implicit_target_using_c_and_reverse,
               merge_catches_nonexistent_target,
               merge_tree_deleted_in_target,
               merge_similar_unrelated_trees,

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org
Received on Fri Jan 13 00:22:44 2006

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

This site is subject to the Apache Privacy Policy and the Apache Public Forum Archive Policy.