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

[PATCH] svnpatch-diff branch current work

From: Charles Acknin <charlesacknin_at_gmail.com>
Date: 2007-07-12 21:21:50 CEST

Attached inline is the log and the patch of the work-in-progress I
should have committed last week right after the 'svnpatch-diff' branch
creation, or at least wisely submitted for review here, as per this
post today.

If anybody feel like reviewing in solitude, here it is :-)

Log:

[[[
Install --svnpatch command line option into 'svn diff' and provide
libsvn_client callbacks with svnpatch-format facilities when needed.

* subversion/svn/cl.h
  (svn_cl__longopt_t, svn_cl__opt_state_t): add command line option to enable
  svnpatch, and fix typo with 'svn_cl__no_diff_deleted'.

* subversion/svn/main.c
  (svn_cl__options): provide the command line with svnpatch support, and fix
  typo with 'svn_cl__no_diff_deleted'.

* subversion/svn/diff-cmd.c
  (svn_cl__diff): enable svnpatch when calling svn_client_diff[_peg]4.

* notes/svnpatch
  Import the design document.

* subversion/include/svn_client.h
  (svn_client_diff4, svn_client_diff_peg4): add 'svnpatch_format' argument to
  the signatures.

* subversion/libsvn_wc/diff.c
  (dir_diff): new function similar to what file_diff() does for files.
  (directory_elements_diff): call dir_diff() when svnpatch'ing.

* subversion/libsvn_client/diff.c
  (diff_cmd_baton): provide the structure with svnpatch_format boolean type and
  an svnpatch buffer.
  (svnpatch_append): new function that helps to generate the svnpatch buffer.
  (diff_props_changed, diff_content_changed, diff_file_added,
  diff_file_deleted_with_diff, diff_file_deleted_no_diff, diff_dir_added,
  diff_dir_deleted): turn on sketchy svnpatch creation calls.
  (do_diff): allocate some room for svnpatch bytes, and output when using
  svnpatch_format before returning.
  (svn_client_diff4, svn_client_diff_peg4): add 'svnpatch_format' as in its
  declaration.
  (svn_client_diff3, svn_client_diff_peg3): disable 'svnpatch_format'

* subversion/tests/cmdline/diff_tests.py
  (diff_svnpatch): new test to illustrate 'svn diff --svnpatch' behaviour
]]]

Patch:

[[[
Index: notes/svnpatch
===================================================================
--- notes/svnpatch (revision 0)
+++ notes/svnpatch (revision 0)
@@ -0,0 +1,119 @@
+This file documents the 'svnpatch' format that's used with both diff and patch
+subcommands.
+
+I HISTORY
+ -------
+
+[remind the reasons behind the design of such a new format]
+
+(We want something that supports any change and suitable enough for code
+review.)
+
+
+II SVNPATCH FORMAT IN A NUTSHELL
+ -----------------------------
+
+First off, let's define it. svnpatch format is made of two ordered parts:
+ * (a) human-readable: made of unidiff bytes
+ * (b) computer-readable: made of svn protocol bytes (ra_svn), gzip'ed,
+ base64-encoded
+
+But, as we're not in a client/server configuration:
+ - (b) only uses the svn protocol's Editor Command Set, there's no need for
+ the Main Command Set nor the Report Command Set
+ - a client reads Editor Commands from the patch, i.e. the patch silently
+ drives the client's editor
+ - the only direction the information takes is from the patch to the client
+ - svndiff1 is solely used instead of being able to choose between svndiff1
+ and svndiff0 (e.g. binary-change needs svndiff)
+
+Such a format can be seen as a subset of the svn protocol which:
+ - Capabilities and Edit Pipelining have nothing to do with as we can't adjust
+ once the patch is rock-hard written in the file nor negotiate anything
+ - commands are restricted to the Editor Command Set
+ - lacks revision numbers and checksums except for binary files (see VI
+ FUZZING)
+
+For more about Command Sets, consult libsvn_ra_svn/protocol.
+
+
+III BOUNDARIES BETWEEN THE TWO PARTS
+ --------------------------------
+
+Now since the svn protocol would be happy to handle just any change that a
+working copy comes with, rules have to be set up so that we meet our goals (see
+I HISTORY).
+
+Concretely, what's in each part?
+
+In (a):
+ - contextual differences
+ - property-changes (in a similar way to 'svn diff')
+ - new non-binary-file content
+
+In (b):
+ - tree-changes ({add,del,move,copy}-directory, {add,del,move,copy}-file)
+ - property-changes
+ - binary-changes
+
+Consequences are we face cases where one change's representation lives in the
+two parts of the patch. e.g. a modified-file move: the move is represented
+within (b) while contextual differences within (a); a file add: an add-file
+Editor Command in (b) plus its content in (a).
+
+Furthermore, we never end up with redundant information but with
+property-changes. A file copy with modifications generates (a) contextual
+diff, (b) add-file w/ copy-path.
+
+The only thing that's left unreadable is tree-changes as defined above.
+However, a higher level layer (e.g. GUIs) would perfectly be able to
+base64-decode, uncompress and read operations to visually-render the changes.
+
+
+IV SVNPATCH EDIT-ABILITY
+ --------------------
+
+Because encoded and compressed, the computer-readable chunk (b) is not directly
+editable. Should it be in cleartext, the user would still have to go through
+svn protocol writing manually -- calculate checksums and strings length, and
+place tokens, assumed to be not so friendly for the end-user. However, there's
+a much easier workaround: apply the patch, and then start editing the working
+copy with regular svn subcommands.
+
+
+V PATCHING
+ --------
+
+When it comes to applying an svnpatch patch (RAS syndrom), the 'svn patch'
+subcommand is a good friend. Here's what it does with the patch: (a) literally
+gets processed by /usr/bin/patch while (b) is handled with internal routines
+that read and drive editor functions out from it much like what's being
+performed by libsvn_ra_svn with a network stream.
+
+Now some words about the order to process (a) and (b). There might be cases
+when operations to a single file live in the two parts of the patch (see
+above). Because that's the way the svn protocol and 'svn diff' do, we stick
+with processing first (b) and then (a). This implies (a) provides diff against
+the most up-to-date indexes.
+
+When the Editor Command Set comes to be extended, 'svn patch' will face
+unexpected commands and/or syntax. As in libsvn_ra_svn, we warn the user with
+'unsupported command' messages and ignore its application.
+
+
+VI FUZZING a.k.a. DYSTOPIA
+ -----------------------
+
+As long as we'll be using /usr/bin/patch to apply (a), we'll have to go with
+/usr/bin/patch fuzzing. So we're left with (b) (which we'll parse first).
+Well, the svn protocol is not very sensitive to fuzzing since most operations
+include a revision number. However, to stick with this policy would widely
+lower the patch-application scope we're expecting. For instance, 'svn patch'
+would fail at deleting dir@REV when REV is different from the one that comes
+with the delete-entry Editor Command. Obviously we need loose here, and the
+solution is to free the svn protocol from revision numbers and checksums in our
+implementation for every change but binary-changes (for the checksums). (It
+would be insane to associate binary stuff with fuzzing in this world.) Now
+dealing with (b) patching is similar in many ways to (a)'s: we end up trying by
+all methods to drive the editor in the dark jungle, possibly failing in few
+cases shooting 'hunk failed' warnings.
Index: subversion/include/svn_client.h
===================================================================
--- subversion/include/svn_client.h (revision 25719)
+++ subversion/include/svn_client.h (working copy)
@@ -1964,6 +1964,8 @@
  * @note @a header_encoding doesn't affect headers generated by external
  * diff programs.
  *
+ * @a svnpatch_format set to @c TRUE enables the svnpatch format diff.
+ *
  * @since New in 1.5.
  */
  svn_error_t *svn_client_diff4(const apr_array_header_t *diff_options,
@@ -1975,6 +1977,7 @@
                               svn_boolean_t ignore_ancestry,
                               svn_boolean_t no_diff_deleted,
                               svn_boolean_t ignore_content_type,
+ svn_boolean_t svnpatch_format,
                               const char *header_encoding,
                               apr_file_t *outfile,
                               apr_file_t *errfile,
@@ -1986,7 +1989,8 @@
  * Similar to svn_client_diff4(), but with @a depth set according to
  * @a recurse: if @a recurse is true, set @a depth to @c
  * svn_depth_infinity, if @a recurse is false, set @a depth to @c
- * svn_depth_empty.
+ * svn_depth_empty. @a svnpatch_format is set to @c FALSE to disable
+ * any svnpatch format diff to take place.
  *
  * @deprecated Provided for backward compatibility with the 1.4 API.
  *
@@ -2072,6 +2076,7 @@
                                   svn_boolean_t ignore_ancestry,
                                   svn_boolean_t no_diff_deleted,
                                   svn_boolean_t ignore_content_type,
+ svn_boolean_t svnpatch_format,
                                   const char *header_encoding,
                                   apr_file_t *outfile,
                                   apr_file_t *errfile,
@@ -2082,7 +2087,8 @@
  * Similar to svn_client_diff_peg4(), but with @a depth set according
  * to @a recurse: if @a recurse is true, set @a depth to
  * @c svn_depth_infinity, if @a recurse is false, set @a depth to
- * @c svn_depth_files.
+ * @c svn_depth_files. @a svnpatch_format is set to @c FALSE to disable
+ * any svnpatch format diff to take place.
  *
  * @deprecated Provided for backward compatibility with the 1.4 API.
  *
Index: subversion/libsvn_wc/diff.c
===================================================================
--- subversion/libsvn_wc/diff.c (revision 25719)
+++ subversion/libsvn_wc/diff.c (working copy)
@@ -621,6 +621,43 @@
   return SVN_NO_ERROR;
 }

+/* Called from directory_elements_diff to trigger callbacks when
+ * svnpatch format is enabled. */
+static svn_error_t *
+dir_diff(struct dir_baton *dir_baton,
+ const char *path,
+ const svn_wc_entry_t *entry,
+ apr_pool_t *pool)
+{
+ switch(entry->schedule)
+ {
+ case svn_wc_schedule_replace:
+ case svn_wc_schedule_delete:
+ SVN_ERR(dir_baton->edit_baton->callbacks->dir_deleted
+ (NULL,
+ NULL,
+ path,
+ dir_baton->edit_baton->callback_baton));
+
+ /* So that 'replace' falls through */
+ if (entry->schedule == svn_wc_schedule_delete)
+ break;
+
+ case svn_wc_schedule_add:
+ SVN_ERR(dir_baton->edit_baton->callbacks->dir_added
+ (NULL,
+ NULL,
+ path,
+ entry->revision,
+ dir_baton->edit_baton->callback_baton));
+ break;
+
+ default:
+ break;
+ }
+ return SVN_NO_ERROR;
+}
+
 /* Called when the directory is closed to compare any elements that have
  * not yet been compared. This identifies local, working copy only
  * changes. At this stage we are dealing with files/directories that do
@@ -739,6 +776,9 @@
                  for that file. */
             }

+ /* Before we recurse, let's trigger directory's callbacks */
+ SVN_ERR(dir_diff(dir_baton, path, entry, subpool));
+
           /* Check the subdir if in the anchor (the subdir is the target), or
              if recursive */
           if (in_anchor_not_target
Index: subversion/libsvn_client/diff.c
===================================================================
--- subversion/libsvn_client/diff.c (revision 25719)
+++ subversion/libsvn_client/diff.c (working copy)
@@ -305,9 +305,35 @@
      unconditionally, even if the diffs are empty. */
   svn_boolean_t force_empty;

+ /* Should we enable svnpatch format */
+ svn_boolean_t svnpatch_format;
+
+ /* Buffer to store svnpatch-format bytes we're filling along calls to
+ client's callbacks, before we output it. */
+ svn_stringbuf_t *svnpatch_buff;
 };

+/* Somehow wraps svn_stringbuf_appendbytes in a printf-style fashion thanks to
+ apr_pvsprintf(). This could be moved into svn_string.h after some
+ generic-tweaking. (This needs diff_cmd_baton struct symbols, defined right
+ above) */
+svn_error_t *
+svnpatch_append(struct diff_cmd_baton *diff_cmd_baton, const char *fmt, ...)
+{
+ va_list ap;
+ char *buff;
+ apr_pool_t *subpool = svn_pool_create(diff_cmd_baton->pool);

+ va_start(ap, fmt);
+ buff = apr_pvsprintf(subpool, fmt, ap);
+ va_end(ap);
+ svn_stringbuf_appendbytes(diff_cmd_baton->svnpatch_buff, buff, strlen(buff));
+
+ svn_pool_destroy(subpool);
+ return SVN_NO_ERROR;
+}
+
+
  /* Generate a label for the diff output for file PATH at revision REVNUM.
    If REVNUM is invalid then it is assumed to be the current working
    copy. Assumes the paths are already in the desired style (local
@@ -350,6 +376,11 @@
   if (state)
     *state = svn_wc_notify_state_unknown;

+ if (diff_cmd_baton->svnpatch_format)
+ SVN_ERR(svnpatch_append(diff_cmd_baton,
+ APR_EOL_STR "diff_props_changed; path:%s",
+ path));
+
   svn_pool_destroy(subpool);
   return SVN_NO_ERROR;
 }
@@ -466,7 +497,7 @@
               (os, diff_cmd_baton->header_encoding, subpool,
                _("Cannot display: file marked as a binary type.%s"),
                APR_EOL_STR));
-
+
       if (mt1_binary && !mt2_binary)
         SVN_ERR(svn_stream_printf_from_utf8
                 (os, diff_cmd_baton->header_encoding, subpool,
@@ -489,6 +520,11 @@
                      mimetype1, mimetype2));
         }

+ if (diff_cmd_baton->svnpatch_format)
+ svnpatch_append(diff_cmd_baton,
+ APR_EOL_STR "diff_content_changed(binary); path:%s",
+ path);
+
       /* Exit early. */
       svn_pool_destroy(subpool);
       return SVN_NO_ERROR;
@@ -620,6 +656,11 @@
                             rev1, rev2,
                             mimetype1, mimetype2,
                             prop_changes, original_props, diff_baton));
+
+ if (diff_cmd_baton->svnpatch_format)
+ svnpatch_append(diff_cmd_baton,
+ APR_EOL_STR "diff_file_added; path:%s",
+ path);

   diff_cmd_baton->force_empty = FALSE;

@@ -640,6 +681,11 @@
 {
   struct diff_cmd_baton *diff_cmd_baton = diff_baton;

+ if (diff_cmd_baton->svnpatch_format)
+ svnpatch_append(diff_cmd_baton,
+ APR_EOL_STR "diff_file_deleted_with_diff; path:%s",
+ path);
+
   /* We don't list all the deleted properties. */
   return diff_file_changed(adm_access, state, NULL, path,
                            tmpfile1, tmpfile2,
@@ -667,6 +713,11 @@
   if (state)
     *state = svn_wc_notify_state_unknown;

+ if (diff_cmd_baton->svnpatch_format)
+ svnpatch_append(diff_cmd_baton,
+ APR_EOL_STR "diff_file_deleted_no_diff; path:%s",
+ path);
+
   SVN_ERR(file_printf_from_utf8
           (diff_cmd_baton->outfile,
            diff_cmd_baton->header_encoding,
@@ -687,9 +738,16 @@
                svn_revnum_t rev,
                void *diff_baton)
 {
+ struct diff_cmd_baton *diff_cmd_baton = diff_baton;
+
   if (state)
     *state = svn_wc_notify_state_unknown;

+ if (diff_cmd_baton->svnpatch_format)
+ svnpatch_append(diff_cmd_baton,
+ APR_EOL_STR "diff_dir_added; path:%s",
+ path);
+
   /* ### todo: send feedback to app */
   return SVN_NO_ERROR;
 }
@@ -701,9 +759,16 @@
                  const char *path,
                  void *diff_baton)
 {
+ struct diff_cmd_baton *diff_cmd_baton = diff_baton;
+
   if (state)
     *state = svn_wc_notify_state_unknown;

+ if (diff_cmd_baton->svnpatch_format)
+ svnpatch_append(diff_cmd_baton,
+ APR_EOL_STR "diff_dir_deleted; path:%s",
+ path);
+
   return SVN_NO_ERROR;
 }

@@ -1290,7 +1355,7 @@
 }

-/* This is basically just the guts of svn_client_diff[_peg]3(). */
+/* This is basically just the guts of svn_client_diff[_peg]4(). */
 static svn_error_t *
  do_diff(const struct diff_parameters *diff_param,
         const svn_wc_diff_callbacks2_t *callbacks,
@@ -1303,6 +1368,9 @@
   /* Check if paths/revisions are urls/local. */
   SVN_ERR(check_paths(diff_param, &diff_paths));

+ if (callback_baton->svnpatch_format)
+ callback_baton->svnpatch_buff = svn_stringbuf_create("", pool);
+
   if (diff_paths.is_repos1)
     {
       if (diff_paths.is_repos2)
@@ -1344,6 +1412,13 @@
         }
     }

+ if (callback_baton->svnpatch_format)
+ SVN_ERR(file_printf_from_utf8
+ (callback_baton->outfile,
+ callback_baton->header_encoding,
+ "%s" APR_EOL_STR,
+ callback_baton->svnpatch_buff->data));
+
   return SVN_NO_ERROR;
 }

@@ -1470,6 +1545,7 @@
                  svn_boolean_t ignore_ancestry,
                  svn_boolean_t no_diff_deleted,
                  svn_boolean_t ignore_content_type,
+ svn_boolean_t svnpatch_format,
                  const char *header_encoding,
                  apr_file_t *outfile,
                  apr_file_t *errfile,
@@ -1519,6 +1595,7 @@
   diff_cmd_baton.config = ctx->config;
   diff_cmd_baton.force_empty = FALSE;
   diff_cmd_baton.force_binary = ignore_content_type;
+ diff_cmd_baton.svnpatch_format = svnpatch_format;

   return do_diff(&diff_params, &diff_callbacks, &diff_cmd_baton, ctx, pool);
 }
@@ -1542,7 +1619,7 @@
   return svn_client_diff4(options, path1, revision1, path2,
                           revision2, SVN_DEPTH_FROM_RECURSE(recurse),
                           ignore_ancestry, no_diff_deleted,
- ignore_content_type, header_encoding,
+ ignore_content_type, FALSE, header_encoding,
                           outfile, errfile, ctx, pool);
 }

@@ -1596,6 +1673,7 @@
                      svn_boolean_t ignore_ancestry,
                      svn_boolean_t no_diff_deleted,
                      svn_boolean_t ignore_content_type,
+ svn_boolean_t svnpatch_format,
                      const char *header_encoding,
                      apr_file_t *outfile,
                      apr_file_t *errfile,
@@ -1641,6 +1719,7 @@
   diff_cmd_baton.config = ctx->config;
   diff_cmd_baton.force_empty = FALSE;
   diff_cmd_baton.force_binary = ignore_content_type;
+ diff_cmd_baton.svnpatch_format = svnpatch_format;

   return do_diff(&diff_params, &diff_callbacks, &diff_cmd_baton, ctx, pool);
 }
@@ -1670,6 +1749,7 @@
                               ignore_ancestry,
                               no_diff_deleted,
                               ignore_content_type,
+ FALSE,
                               header_encoding,
                               outfile,
                               errfile,
Index: subversion/tests/cmdline/diff_tests.py
===================================================================
--- subversion/tests/cmdline/diff_tests.py (revision 25719)
+++ subversion/tests/cmdline/diff_tests.py (working copy)
@@ -2597,6 +2597,88 @@
   svntest.actions.run_and_verify_svn(None, expected_output, [],
                                      'diff', '-r3:4', kappa_path)

+def diff_svnpatch(sbox):
+ "test svnpatch format in various ways"
+
+ sbox.build()
+ wc_dir = sbox.wc_dir
+ os.chdir(wc_dir)
+
+ # turn iota into a modified binary file
+ svntest.main.file_append('iota', "\nSome more bytes.\n")
+ svntest.main.run_svn(None, 'propset', 'svn:mime-type',
+ 'application/octet-stream', 'iota')
+
+ # add dir
+ os.mkdir(os.path.join('A', 'T'))
+ svntest.main.run_svn(None, 'add', os.path.join('A', 'T'))
+
+ # copy file and modify
+ mu_path = os.path.join('A', 'mu')
+ mumu_path = os.path.join('A', 'mumu')
+ svntest.main.run_svn(None, 'cp', mu_path, mumu_path)
+ svntest.main.file_append(mumu_path, "\nSome more bytes.\n")
+
+ expected_output = [
+ "Index: A/mumu\n",
+ "===================================================================\n",
+ "--- A/mumu\t(revision 1)\n",
+ "+++ A/mumu\t(working copy)\n",
+ "@@ -1 +1,3 @@\n",
+ " This is the file 'mu'.\n",
+ "+\n",
+ "+Some more bytes.\n",
+ "Index: iota\n",
+ "===================================================================\n",
+ "Cannot display: file marked as a binary type.\n",
+ "svn:mime-type = application/octet-stream\n",
+ "\n",
+ "Property changes on: iota\n",
+ "___________________________________________________________________\n",
+ "Name: svn:mime-type\n",
+ " + application/octet-stream\n",
+ "\n",
+ "H4sICL/sikYAA291dACFkcFSgzAQhq3HvoG33NrOFGtIAiS3voCXdrynySIZgTCQOvadfEgDBcVW\n",
+ "6sCEkP12998/S2QrKIPaWoeW/lmhUOgn/1n5ny6kTe23WGzPEb/gjjsjUuueIGK72Z/DfglHjMpt\n",
+ "Az3VhX5SU5OD30Y+tzgWxyFdkbZg3J1OlcFjkX0dKox1chCq6FhEJstX6MCgqm3VFfEEJqJ5L0Vh\n",
+ "CgjcqWqrhFTIqsqNks7YcmOVAxc0rgZZTIkZHGvzToGDD6ch90qWwzBD3ncoUNmxfBsAKnYvz7Mr\n",
+ "Bko9EOO2/bQXpf/s3VpAQhFqnCgGLIaEKnZIJAMuI8AklYRTrW7ro1P6fjFM3D2s74PbUChmn/+0\n",
+ "YmK9z0yD/OsyQN2wi/ZeF4/z+c4WgApbAzqcHDT+ZNo0OmFa70mcJpRxnsaERqnGSmGuacpJRCX3\n",
+ "xrCLuwZtXO/2/AuhTZnRNgMAAA==\n",
+ ]
+
+ # 'clean' cleartext chunk translation (directory addition + property change +
+ # binary change):
+ #
+ # ( open-root ( ( ) 2:d0 ) )
+ # ( open-dir ( 1:A 2:d0 2:d1 ( ) ) )
+ # ( add-dir ( 3:A/T 2:d1 2:d2 ( ) ) )
+ # ( close-dir ( 2:d2 ) )
+ # ( add-file ( 6:A/mumu 2:d1 2:c3 ( 37:A/mu ) ) )
+ # ( close-dir ( 2:d1 ) )
+ # ( open-file ( 4:iota 2:d0 2:c4 ( ) ) )
+ # ( change-file-prop ( 2:c4 13:svn:mime-type (
24:application/octet-stream ) ) )
+ # ( close-dir ( 2:d0 ) )
+ # ( apply-textdelta ( 2:c3 ( ) ) )
+ # ( textdelta-chunk ( 2:c3 4:SVN^A ) )
+ # ( textdelta-end ( 2:c3 ) )
+ # ( close-file ( 2:c3 ( ) ) )
+ # ( apply-textdelta ( 2:c4 ( 32:2d18c5e57e84c5b8a5e9a6e13fa394dc ) ) )
+ # ( textdelta-chunk ( 2:c4 4:SVN^A ) )
+ # ( textdelta-chunk ( 2:c4 5:^@^Y,^B- ) )
+ # ( textdelta-chunk ( 2:c4 2:^A¬ ) )
+ # ( textdelta-chunk ( 2:c4 45:,This is the file 'iota'.
+ #
+ # Some more bytes.
+ #
+ # ) )
+ # ( textdelta-end ( 2:c4 ) )
+ # ( close-file ( 2:c4 ( 32:7f84599f7346fd1cc19d4f9364a913f5 ) ) )
+ # ( close-edit ( ) )
+
+ svntest.actions.run_and_verify_svn(None, expected_output, [],
+ 'diff', '--svnpatch')
+
 ########################################################################
 #Run the tests

@@ -2644,6 +2726,7 @@
               diff_ignore_whitespace,
               diff_ignore_eolstyle,
               diff_in_renamed_folder,
+ diff_svnpatch,
               ]

 if __name__ == '__main__':
Index: subversion/svn/cl.h
===================================================================
--- subversion/svn/cl.h (revision 25719)
+++ subversion/svn/cl.h (working copy)
@@ -66,7 +66,7 @@
   svn_cl__new_cmd_opt,
   svn_cl__no_auth_cache_opt,
   svn_cl__no_autoprops_opt,
- svn_cl__no_diff_deleted,
+ svn_cl__no_diff_deleted_opt,
   svn_cl__no_ignore_opt,
   svn_cl__no_unlock_opt,
   svn_cl__non_interactive_opt,
@@ -86,7 +86,8 @@
   svn_cl__keep_local_opt,
   svn_cl__with_revprop_opt,
   svn_cl__parents_opt,
- svn_cl__accept_opt
+ svn_cl__accept_opt,
+ svn_cl__svnpatch_format_opt
 } svn_cl__longopt_t;

@@ -132,6 +133,7 @@
   const char *extensions; /* subprocess extension args */ /* UTF-8! */
   apr_array_header_t *targets; /* target list from file */ /* UTF-8! */
   svn_boolean_t xml; /* output in xml, e.g., "svn log --xml" */
+ svn_boolean_t svnpatch; /* output in svnpatch format, e.g.,
"svn diff --svnpatch" */
   svn_boolean_t no_ignore; /* disregard default ignores & svn:ignore's */
   svn_boolean_t no_auth_cache; /* do not cache authentication information */
   svn_boolean_t no_diff_deleted; /* do not show diffs for deleted files */
Index: subversion/svn/diff-cmd.c
===================================================================
--- subversion/svn/diff-cmd.c (revision 25719)
+++ subversion/svn/diff-cmd.c (working copy)
@@ -301,6 +301,7 @@
                      opt_state->notice_ancestry ? FALSE : TRUE,
                      opt_state->no_diff_deleted,
                      opt_state->force,
+ opt_state->svnpatch,
                      svn_cmdline_output_encoding(pool),
                      outfile,
                      errfile,
@@ -344,6 +345,7 @@
                      opt_state->notice_ancestry ? FALSE : TRUE,
                      opt_state->no_diff_deleted,
                      opt_state->force,
+ opt_state->svnpatch,
                      svn_cmdline_output_encoding(pool),
                      outfile,
                      errfile,
Index: subversion/svn/main.c
===================================================================
--- subversion/svn/main.c (revision 25719)
+++ subversion/svn/main.c (working copy)
@@ -144,8 +144,10 @@
                     N_("do no interactive prompting")},
   {"dry-run", svn_cl__dry_run_opt, 0,
                     N_("try operation but make no changes")},
- {"no-diff-deleted", svn_cl__no_diff_deleted, 0,
+ {"no-diff-deleted", svn_cl__no_diff_deleted_opt, 0,
                     N_("do not print differences for deleted files")},
+ {"svnpatch", svn_cl__svnpatch_format_opt, 0,
+ N_("output in svnpatch format")},
   {"notice-ancestry", svn_cl__notice_ancestry_opt, 0,
                     N_("notice ancestry when calculating differences")},
   {"ignore-ancestry", svn_cl__ignore_ancestry_opt, 0,
@@ -399,10 +401,10 @@
      "\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__depth_opt, svn_cl__diff_cmd_opt, 'x', svn_cl__no_diff_deleted,
- svn_cl__notice_ancestry_opt, svn_cl__summarize, svn_cl__changelist_opt,
- svn_cl__force_opt, SVN_CL__AUTH_OPTIONS,
- svn_cl__config_dir_opt} },
+ svn_cl__depth_opt, svn_cl__diff_cmd_opt, 'x', svn_cl__no_diff_deleted_opt,
+ svn_cl__notice_ancestry_opt, svn_cl__summarize,
+ svn_cl__svnpatch_format_opt, svn_cl__changelist_opt, svn_cl__force_opt,
+ SVN_CL__AUTH_OPTIONS, svn_cl__config_dir_opt} },

   { "export", svn_cl__export, {0}, N_
     ("Create an unversioned copy of a tree.\n"
@@ -1279,7 +1281,7 @@
       case svn_cl__non_interactive_opt:
         opt_state.non_interactive = TRUE;
         break;
- case svn_cl__no_diff_deleted:
+ case svn_cl__no_diff_deleted_opt:
         opt_state.no_diff_deleted = TRUE;
         break;
       case svn_cl__notice_ancestry_opt:
@@ -1369,6 +1371,9 @@
       case svn_cl__summarize:
         opt_state.summarize = TRUE;
         break;
+ case svn_cl__svnpatch_format_opt:
+ opt_state.svnpatch = TRUE;
+ break;
       case svn_cl__remove_opt:
         opt_state.remove = TRUE;
         break;
]]]

Thanks for reading!

Cheers,
Charles

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org
Received on Thu Jul 12 21:21:34 2007

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.