Author: gbg Date: Sat Oct 26 19:02:27 2013 New Revision: 1536020 URL: http://svn.apache.org/r1536020 Log: On the invoke-diff-cmd-feature branch: Add per file diff support which uses an arbitrary config file.
* BRANCH-README: Update to reflect the latest changes. * diff_cmd_config: Temporary file for demonstration/testing purposes. * subversion/include/svn_io.h (svn_io_parse_diff_cmd_file): New temporary function. * subversion/libsvn_subr/io.c (svn_io_run_external_diff): Add selection mechanism. (svn_io_parse_diff_cmd_file): New temporary function. * subversion/svn/svn.c (svn_cl__options[]): Update svn diff help to explain the new feature. Added: subversion/branches/invoke-diff-cmd-feature/diff_cmd_config Modified: subversion/branches/invoke-diff-cmd-feature/BRANCH-README subversion/branches/invoke-diff-cmd-feature/subversion/include/svn_io.h subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_subr/io.c subversion/branches/invoke-diff-cmd-feature/subversion/svn/svn.c Modified: subversion/branches/invoke-diff-cmd-feature/BRANCH-README URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/BRANCH-README?rev=1536020&r1=1536019&r2=1536020&view=diff ============================================================================== --- subversion/branches/invoke-diff-cmd-feature/BRANCH-README (original) +++ subversion/branches/invoke-diff-cmd-feature/BRANCH-README Sat Oct 26 19:02:27 2013 @@ -8,7 +8,7 @@ See: http://subversion.tigris.org/issues original motivation for this project. --invoke-diff-cmd allows command line selection of an external diff -program and will be extended to cover the existing diff3 option with a +program and will be extended to cover the existing diff3 option with similar --invoke-diff3-cmd option. Currently this capability is provided by user written shell scripts @@ -19,28 +19,28 @@ which are passed as the diff program via What --invoke-diff-cmd and --invoke-diff3-cmd provide -===================================================== +------------------------------------------------------ Users can type 'free-style' command lines for their selected diff/merge program, from 'svn help diff': --invoke-diff-cmd ARG: - use ARG as format string for external diff command - invocation. - - Substitutions: %svn_new% new file - %svn_old% old file - %svn_new_label% label of the new file - %svn_old_label% label of the old file - Examples: - --invoke-diff-cmd='diff -y %svn_new% %svn_old%' - --invoke-diff-cmd="kdiff3 -auto -o /home/u/log \ - %svn_new% %svn_old% --L1 %svn_new_label% \ - --L2 "Custom Label" ' - Other constructs possible are: - +%svn_new%, %svn_new%- and +++%svn_new_label%+++ - + use ARG as format string for external diff command + invocation. + + Substitutions: ;f1 original file + ;f2 changed file + ;l1 label of the original file + ;l2 label of the changed file + Examples: --invoke-diff-cmd="diff -y ;f1 ;f2" + --invoke-diff-cmd="kdiff3 -auto -o /home/u/log \ + +;f1 ;l2 --L1 ;l1 --L2 "Custom Label" " + + The delimiter ';' can be escaped by adding a ';', which will be + consumed in the process. The delimiter can appear anywhere in the + string, ie, file=;f1 will expand as expected and file=;;f1 will be + rendered as file=;f1. Structure of the feature: ========================= @@ -51,17 +51,18 @@ API components ./subversion/libsvn_subr/io.c:3030 __create_custom_diff_cmd() transforms the user input 'invoke-diff-cmd' into a command line - call by substitution the labels and file names(where defined), - whilst leaving everything else untouched. This is more of an - internal routine and probably not well placed in the public API. - It will be reused for the merge part of this project. + call by substitution the file names, whilst leaving everything else + untouched. This is more of an internal routine and probably not + well placed in the API. It will be reused for the merge part of + this project. + NOTE: ./subversion/libsvn_subr/io.c:3108 svn_io_run_external_diff() - calls __create_custom_diff_cmd() and does all the error checking - required, before routing the result to the actual call to the APR - routine that makes it. + calls svn_io_create_custom_diff_cmd() and does all the error + checking required, before routing the result to the actual call to + the APR routine that makes it. UI components @@ -82,32 +83,34 @@ UI components one of --invoke-diff-cmd, --diff-cmd or --internal-diff-cmd are invoked. - Changes to the existing code structure: ======================================= -The original --diff-cmd parsing and routing code has been refactored +the original --diff-cmd parsing and routing code has been deprecated and the call to --diff-cmd is now handled by the -__create_custom_diff_cmd() and svn_io_run_external_diff() routines. -All the original functionality and user syntax has been retained. - +svn_io_create_custom_diff_cmd() and svn_io_run_external_diff() +routines. All the original functionality and user syntax has been +retained. -Tests +TESTS ===== -The test for the 'invoke-diff-cmd' feature is +The test for this feature is + +/subversion/tests/cmdline/diff_tests.py diff_invoke_external_diffcmd - /subversion/tests/cmdline/diff_tests.py diff_invoke_external_diffcmd The test for the updated --diff-cmd is - /subversion/tests/cmdline/diff_tests.py diff_external_diffcmd +/subversion/tests/cmdline/diff_tests.py diff_external_diffcmd TODO: ==== - * add help info to log, svnlook + * add invoke-diff-cmd option to the blame section + + * add help info to log, svnlook, blame * Adding invoke-diff-cmd to merge: add --invoke-diff-3-cmd using the svn_io_create_custom_diff_cmd() @@ -122,170 +125,4 @@ TODO: http://subversion.tigris.org/issues/show_bug.cgi?id=3836 -Review tools -============ - -The entire code of the branch can be obtained thus: - -svn diff ^/subversion/trunk@1531612\ - ^/subversion/branches/invoke-diff-cmd-feature - -To obtain a visitable list of files with line numbers in the Emacs -compilation buffer: - -M-x cd /branches/invoke-diff-cmd-feature/ -M-x compile -svn diff ^/subversion/trunk@1531612\ - ^/subversion/branches/invoke-diff-cmd-feature |\ - perl -ne '/Index: (.*)$/ && ($name = $1); - /^@@.*\+(\d+),/ && print "./$name:$1:diff\n";' - - -Log messages of salient code changes -==================================== - -* subversion/include/svn_client.h - - (svn_client_diff7, svn_client_diff_peg7): Declare the new API. Like - svn_client_diff[_peg]6 but with invoke_diff_cmd parameter. - - (svn_client_diff6, svn_client_diff_peg_6): Deprecate. - - -* subversion/svn/log-cmd.c - - (svn_client_diff_peg7): Update call to svn_client_diff_peg6 to - svn_client_diff_peg7. - - (log_receiver_baton): New struct member invoke_diff_cmd. - - (display_diff): New parameter 'invoke_diff_cmd' . Pass - invoke_diff_cmd parameter into svn_client_diff_peg7(). - - (log_entry_receiver): Pass invoke_diff_cmd into display_diff(). - - (svn_cl__log): Ensure mutual exclusions between invoke_diff_cmd and - quiet and diff-cmd, require 'diff' option. Populate - log_receiver_baton member invoke_diff_cmd. - - (svn_cl__options): Expand help info for invoke-diff-cmd option. - - -* subversion/include/svn_config.h - - (SVN_CONFIG_OPTION_INVOKE_DIFF_CMD): New definition. - - -* subversion/include/svn_io.h - - (svn_io_create_custom_diff_cmd): New function. - - (svn_io_run_external_diff): New function. - - (svn_io_run_diff2): Deprecate function. - - -* subversion/libsvn_client/deprecated.c - - (svn_client_diff6, svn_client_diff_peg6): New deprecation wrappers. - - -* subversion/libsvn_client/diff.c - - (struct diff_cmd_baton): New member: 'invoke_diff_cmd'. - - (diff_content_changed): Call svn_io_run_external_diff if - --invoke-diff-cmd option was specified, otherwise retain previous - behaviour. - - (set_up_diff_cmd_and_options): Apply invoke-diff-cmd option - preferentially. Old behaviour unchanged. - - (svn_client_diff_peg_7): Rename and update from - svn_client_diff_peg_6. Add new parameter: invoke_diff_cmd. - - (svn_client_diff7): Rename and update from svn_client_diff6, add - new parameter 'invoke_diff_cmd'. - - (): Update all comments mentioning 'svn_client_diff6' to - 'svn_client_diff7'. - - (diff_content_changed): Raise an error if both diff_cmd and - invoke-diff-cmd are set. - - -* subversion/libsvn_subr/config_file.c - - (svn_config_ensure): New entry: invoke-diff-cmd. - - -* subversion/libsvn_subr/io.c - - (svn_io_create_custom_diff_cmd): New function. - - (svn_io_run_external_diff): New function. - - -* subversion/svn/cl.h - - (struct svn_cl__opt_state_t.diff): New member: 'invoke_diff_cmd'. - - -* subversion/svn/diff-cmd.c - - (svn_cl__diff): Update call to svn_client_diff6 to svn_client_diff7. - - -* subversion/svn/svn.c - - (svn_cl__options[]): Add help info and new variable: - 'opt_invoke_diff_cmd'. - - (svn_cl__cmd_table[]): New option: 'invoke-diff-cmd'. - - (sub_main): Prohibit simultaneous usage of --invoke-diff-cmd and - --internal-diff. Add new opt_state.diff.invoke-diff-cmd option - to the option selector. Add call to svn_config_set. - - (svn_cl__cmd_table): Add opt_invoke_diff_cmd to the list of valid - sub-commands. - - (sub_main): Add guard against concurrent usage of incompatible diff - options. Remove previous guard code. - - -* subversion/tests/cmdline/diff_tests.py - - (diff_invoke_external_diffcmd): New function. - - (test_list): Add new entry 'diff_invoke_external_diffcmd'. - - -* subversion/include/svn_error_codes.h - - (SVN_CLIENT_DIFF_CMD): New macro. - - -* subversion/svnlook/svnlook.c - - (enum): New variable svnlook__invoke_diff_cmd. - - (options_table[]): New entry 'invoke-diff-cmd'. - - (cmd_tablcmd[]): Add svnlook__invoke_diff_cmd to diff cmd table - entry. - - (svnlook_opt_state): New member variable "invoke_diff_cmd". - - (svnlook_ctxt_t): New member variable "invoke_diff_cmd". - - (print_diff_tree): Modify if condition to include new - invoke_diff_cmd. Add conditional call to - /include/svn_io.c:svn_io_run_external_diff(). - - (get_ctxt_baton): Assign invoke_diff_cmd data. - - (main): Assign opt_arg to opt_state.invoke_diff_cmd. Add - exclusiveness test for invoke_diff_cmd and diff_cmd. - Added: subversion/branches/invoke-diff-cmd-feature/diff_cmd_config URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/diff_cmd_config?rev=1536020&view=auto ============================================================================== --- subversion/branches/invoke-diff-cmd-feature/diff_cmd_config (added) +++ subversion/branches/invoke-diff-cmd-feature/diff_cmd_config Sat Oct 26 19:02:27 2013 @@ -0,0 +1,6 @@ +# this is to demonstrate the --svn-cfg-file feature. +subversion/svn/svn.c = diff -L "test1" %svn_old% %svn_new% +# +subversion/libsvn_subr/io.c = diff -L "test2" %svn_old% %svn_new% +# +subversion/include/svn_io.h = diff -u -L "test3" %svn_old% %svn_new% \ No newline at end of file Modified: subversion/branches/invoke-diff-cmd-feature/subversion/include/svn_io.h URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/include/svn_io.h?rev=1536020&r1=1536019&r2=1536020&view=diff ============================================================================== --- subversion/branches/invoke-diff-cmd-feature/subversion/include/svn_io.h (original) +++ subversion/branches/invoke-diff-cmd-feature/subversion/include/svn_io.h Sat Oct 26 19:02:27 2013 @@ -2426,6 +2426,17 @@ svn_io_run_external_diff(const char *dir const char *external_diff_cmd, apr_pool_t *scratch_pool); + +/** Open the diff_cmd file which contains custom diff commands + * pertaining to individual files. + * + * @since New in 1.9. + */ +svn_error_t * +svn_io_parse_diff_cmd_file(const char *diff_cmd_file, + apr_array_header_t *diff_file_data, + apr_pool_t *pool); + #ifdef __cplusplus } #endif /* __cplusplus */ Modified: subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_subr/io.c URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_subr/io.c?rev=1536020&r1=1536019&r2=1536020&view=diff ============================================================================== --- subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_subr/io.c (original) +++ subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_subr/io.c Sat Oct 26 19:02:27 2013 @@ -3089,13 +3089,71 @@ __create_custom_diff_cmd(const char *lab strlen(tokens_tab[i].replace)); i = delimiters; } - result[argv] = word->data; + result[argv] = apr_pstrdup(scratch_pool, word->data); } result[argv] = NULL; svn_pool_destroy(scratch_pool); return result; } +/* Copy pasta from svn_io_parse_mimetypes_file below. Should really +refactor this as a generalised wrap that calls any given file and just +hands back a stuffed array_header_t of the contents and lets the +caller deal with the result. (but that's for another patch) +*/ +svn_error_t * +svn_io_parse_diff_cmd_file(const char *diff_cmd_file, + apr_array_header_t *diff_file_data, + apr_pool_t *pool) +{ + svn_error_t *err = SVN_NO_ERROR; + svn_boolean_t eof = FALSE; + svn_stringbuf_t *buf; + apr_pool_t *subpool = svn_pool_create(pool); + apr_file_t *types_file; + svn_stream_t *mimetypes_stream; + + SVN_ERR(svn_io_file_open(&types_file, diff_cmd_file, + APR_READ, APR_OS_DEFAULT, pool)); + mimetypes_stream = svn_stream_from_aprfile2(types_file, FALSE, pool); + + while (1) + { + svn_pool_clear(subpool); + + /* Read a line. */ + if ((err = svn_stream_readline(mimetypes_stream, &buf, + APR_EOL_STR, &eof, subpool))) + break; + + /* Only pay attention to non-empty, non-comment lines. */ + if (buf->len) + { + if (buf->data[0] == '#') + continue; + + APR_ARRAY_PUSH(diff_file_data, char*) + = apr_pstrdup(pool, buf->data); + } + if (eof) + break; + } + svn_pool_destroy(subpool); + + /* If there was an error above, close the file (ignoring any error + from *that*) and return the originally error. */ + if (err) + { + svn_error_clear(svn_stream_close(mimetypes_stream)); + return err; + } + + /* Close the stream (which closes the underlying file, too). */ + SVN_ERR(svn_stream_close(mimetypes_stream)); + + return SVN_NO_ERROR; +} + svn_error_t * svn_io_run_external_diff(const char *dir, const char *label1, @@ -3108,17 +3166,88 @@ svn_io_run_external_diff(const char *dir const char *external_diff_cmd, apr_pool_t *pool) { - int exitcode; + int exitcode, file_in_list = 0, has_switch = 0; const char ** cmd; - + char *diff_cmd, *the_config; + apr_array_header_t *diff_file_data; + svn_stringbuf_t *the_cmd; + apr_array_header_t *words; apr_pool_t *scratch_pool = svn_pool_create(pool); if (0 == strlen(external_diff_cmd)) return svn_error_createf(SVN_ERR_INCORRECT_PARAMS, NULL, NULL); + diff_cmd = apr_palloc(pool, + ( (sizeof(external_diff_cmd)+1) *sizeof(char *) ) ); + + if (strstr(external_diff_cmd, "--svn-cfg-file-query") ) + has_switch = 2; + else if (strstr(external_diff_cmd, "--svn-cfg-file")) + has_switch = 1; + + the_cmd = svn_stringbuf_create_empty(scratch_pool); + + if (has_switch) + { + int i; + + diff_file_data = apr_array_make(scratch_pool, 0, sizeof(char*)); + + words = apr_array_make(scratch_pool, 0, sizeof(char **)); + words = svn_cstring_split(external_diff_cmd, " ", TRUE, scratch_pool); + + the_config = apr_palloc(pool, sizeof(APR_ARRAY_IDX(words, 1, char*)) ); + the_config = APR_ARRAY_IDX(words, 1, char*); + + SVN_ERR(svn_io_parse_diff_cmd_file(the_config, + diff_file_data, + scratch_pool)); + + for (i = 0; i < diff_file_data->nelts; i++) + { + apr_array_header_t *tokens; + + tokens = svn_cstring_split(APR_ARRAY_IDX(diff_file_data, + i, char *), + "=", TRUE, scratch_pool); + + if (strstr(label1, APR_ARRAY_IDX(tokens, 0, char *)) ) + { + diff_cmd = APR_ARRAY_IDX(tokens, 1, char *); + i = diff_file_data->nelts; /* found, so we're done here */ + file_in_list = 1; + } + } + + if (file_in_list) + { + + if (2 == has_switch) + { + /* here we'd show the user the two different cmds and + let them choose which one. Not built yet, b/c I've + not worked out yet how to make a hook for a client + here. + */ + ; + } + } + else + { /* build the command from what's in the external_diff_cmd */ + for (i = 2; i < words->nelts; i++) + { + svn_stringbuf_appendcstr(the_cmd, APR_ARRAY_IDX(words, i, char *)); + svn_stringbuf_appendcstr(the_cmd, " "); + } + diff_cmd = apr_pstrdup(scratch_pool, the_cmd->data); + } + } /* close has_switch */ + else /* no switch found, just a diff cmd */ + diff_cmd = apr_pstrdup(scratch_pool, external_diff_cmd); + cmd = __create_custom_diff_cmd(label1, label2, NULL, tmpfile1, tmpfile2, NULL, - external_diff_cmd, scratch_pool); + diff_cmd, scratch_pool); if (pexitcode == NULL) pexitcode = &exitcode; Modified: subversion/branches/invoke-diff-cmd-feature/subversion/svn/svn.c URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/svn/svn.c?rev=1536020&r1=1536019&r2=1536020&view=diff ============================================================================== --- subversion/branches/invoke-diff-cmd-feature/subversion/svn/svn.c (original) +++ subversion/branches/invoke-diff-cmd-feature/subversion/svn/svn.c Sat Oct 26 19:02:27 2013 @@ -371,6 +371,24 @@ const apr_getopt_option_t svn_cl__option "Other constructs possible are: \n" " " "+%svn_new%, %svn_new%- and +++%svn_new_label%+++ \n" + " " + "With optional switch given at the start of the command:\n" + " " + "--svn-cfg-file=/path/to/config-file (automatic) \n" + " " + "Read config file, apply the diff-cmds stored in there \n" + " " + "--query-cfg-file=/path/to/config-file (interactive) \n" + " " + "As above, but query interactively. \n" + " " + "Example: svn diff --invoke-diff-cmd=\'--svn-cfg-file\\ \n" + " " + " /home/user/diff_cmds diff -u %svn_new% %svn-old%\' \n" + " " + "Config file format: (accepts # comments) \n" + " " + "relative/path/to/file/ = diff %svn_new% ... \n" )}, {"internal-diff", opt_internal_diff, 0, N_("override diff-cmd specified in config file")},