Hi! I need to have a diff header even if there's only property changes for the sake of parsing.
And I want only one diff header per file. Makes it easier to apply the patch. For each found diff header we create one svn_patch_t object. Simple and clean. What to do? I could add a flag to the diff_cmd_baton and reset it between each call but, as Greg pointed out, that's like using a global variable. I could collect all the paths with affected files and create the diff in something like close_edit() but there's no such call for svn_wc_diff_callbacks4_t. One other approach: [[[ Make 'svn diff' always write out a diff header if there are changes to a path, no matter if it's property or text changes. * subversion/libsvn_client/diff.c (diff_cmd_baton): New field 'visited_paths' to hold all the paths for which a diff header has already been written. (display_prop_diff): Add parameter 'show_diff_header'. (diff_props_changed): Call display_prop_diffs() with show_diff_header set to TRUE if the path has not yet been processed. (diff_content_changed): Add the path to 'visited_paths'. (svn_client_diff5, svn_client_diff_peg5): Initialize diff_cmd_baton->visited_paths. ]]] Feels kinda ugly. Some obvious way to do it that I'm missing? The alternatives I can come up with would involve revamping the callback chain to make property changes and text changes end up in one function. [[[ Index: subversion/libsvn_client/diff.c =================================================================== --- subversion/libsvn_client/diff.c (revision 955844) +++ subversion/libsvn_client/diff.c (arbetskopia) @@ -200,6 +200,7 @@ display_prop_diffs(const apr_array_header_t *propc const char *encoding, apr_file_t *file, const char *relative_to_dir, + svn_boolean_t show_diff_header, apr_pool_t *pool) { int i; @@ -294,7 +295,8 @@ display_prop_diffs(const apr_array_header_t *propc * UNIX patch could apply the property diff to, so we use "##" * instead of "@@" as the default hunk delimiter for property diffs. * We also supress the diff header. */ - SVN_ERR(svn_diff_mem_string_output_unified2(os, diff, FALSE, "##", + SVN_ERR(svn_diff_mem_string_output_unified2(os, diff, show_diff_header, + "##", svn_dirent_local_style(path, pool), svn_dirent_local_style(path, pool), encoding, orig, val, pool)); @@ -451,6 +453,8 @@ struct diff_cmd_baton { /* The directory that diff target paths should be considered as relative to for output generation (see issue #2723). */ const char *relative_to_dir; + + apr_hash_t *visited_paths; }; /* Generate a label for the diff output for file PATH at revision REVNUM. @@ -485,15 +489,22 @@ diff_props_changed(const char *local_dir_abspath, { struct diff_cmd_baton *diff_cmd_baton = diff_baton; apr_array_header_t *props; + svn_boolean_t show_diff_header; apr_pool_t *subpool = svn_pool_create(diff_cmd_baton->pool); SVN_ERR(svn_categorize_props(propchanges, NULL, NULL, &props, subpool)); + if (apr_hash_get(diff_cmd_baton->visited_paths, path, APR_HASH_KEY_STRING)) + show_diff_header = FALSE; + else + show_diff_header = TRUE; + if (props->nelts > 0) SVN_ERR(display_prop_diffs(props, original_props, path, diff_cmd_baton->header_encoding, diff_cmd_baton->outfile, diff_cmd_baton->relative_to_dir, + show_diff_header, subpool)); if (state) @@ -750,6 +761,8 @@ diff_content_changed(const char *path, /* Destroy the subpool. */ svn_pool_destroy(subpool); + apr_hash_set(diff_cmd_baton->visited_paths, path, APR_HASH_KEY_STRING, path); + return SVN_NO_ERROR; } @@ -1908,6 +1921,7 @@ svn_client_diff5(const apr_array_header_t *options diff_cmd_baton.force_empty = FALSE; diff_cmd_baton.force_binary = ignore_content_type; diff_cmd_baton.relative_to_dir = relative_to_dir; + diff_cmd_baton.visited_paths = apr_hash_make(pool); return do_diff(&diff_params, &diff_callbacks, &diff_cmd_baton, ctx, pool); } @@ -1974,6 +1988,7 @@ svn_client_diff_peg5(const apr_array_header_t *opt diff_cmd_baton.force_empty = FALSE; diff_cmd_baton.force_binary = ignore_content_type; diff_cmd_baton.relative_to_dir = relative_to_dir; + diff_cmd_baton.visited_paths = apr_hash_make(pool); return do_diff(&diff_params, &diff_callbacks, &diff_cmd_baton, ctx, pool); } ]]] Daniel