I'd like to get the "is this WC mixed revision?" and "is this WC switched?" bits without stat()-ing every single file in the worktree.
Patch enclosed. It still prints 'M' when there's a tree mod or a prop mod. In my use-case I actually throw that out: I use it as «svnversion --no-stat | sed s/M//». Cheers, Daniel [[[ svnversion: Grow a new option to not stat() the WORKING tree. * subversion/include/svn_wc.h (svn_wc_revision_status2): Deprecate. (svn_wc_revision_status3): New. * subversion/libsvn_wc/revision_status.c (svn_wc_revision_status2): Deprecate. (svn_wc_revision_status3): New. * subversion/svnversion/svnversion.c (SVNVERSION_OPT_VERSION): Changed from macro to enumerator. (SVNVERSION_OPT_NO_STAT): New enumerator. (sub_main): Declare and parse a new option, --no-stat. * subversion/tests/cmdline/svnversion_tests.py (no_stat): New test. (test_list): Run it. ]]] [[[ Index: subversion/include/svn_wc.h =================================================================== --- subversion/include/svn_wc.h (revision 1870656) +++ subversion/include/svn_wc.h (working copy) @@ -8176,7 +8176,8 @@ typedef struct svn_wc_revision_status_t * status. * * Set @a (*result_p)->modified to indicate whether any item is locally - * modified. + * modified. If @a may_stat is @c TRUE, do a full check; otherwise, check the + * working copy database only, but don't look for text modifications on-disk. * * If @a cancel_func is non-NULL, call it with @a cancel_baton to determine * if the client has canceled the operation. @@ -8186,6 +8187,24 @@ typedef struct svn_wc_revision_status_t * * @a wc_ctx should be a valid working copy context. * + * @since New in 1.14 + */ +svn_error_t * +svn_wc_revision_status3(svn_wc_revision_status_t **result_p, + svn_wc_context_t *wc_ctx, + const char *local_abspath, + const char *trail_url, + svn_boolean_t committed, + svn_boolean_t may_stat, + svn_cancel_func_t cancel_func, + void *cancel_baton, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool); + +/** Similar to svn_wc_revision_status2(), but with @a may_stat + * set to @c TRUE. + * + * @deprecated Provided for backward compatibility with the 1.13 API. * @since New in 1.7 */ svn_error_t * Index: subversion/libsvn_wc/revision_status.c =================================================================== --- subversion/libsvn_wc/revision_status.c (revision 1870656) +++ subversion/libsvn_wc/revision_status.c (working copy) @@ -32,11 +32,12 @@ #include "svn_private_config.h" svn_error_t * -svn_wc_revision_status2(svn_wc_revision_status_t **result_p, +svn_wc_revision_status3(svn_wc_revision_status_t **result_p, svn_wc_context_t *wc_ctx, const char *local_abspath, const char *trail_url, svn_boolean_t committed, + svn_boolean_t may_stat, svn_cancel_func_t cancel_func, void *cancel_baton, apr_pool_t *result_pool, @@ -63,11 +64,28 @@ svn_error_t * committed, scratch_pool)); - if (!result->modified) + if (!result->modified && may_stat) SVN_ERR(svn_wc__node_has_local_mods(&result->modified, NULL, wc_ctx->db, local_abspath, TRUE, cancel_func, cancel_baton, scratch_pool)); + return SVN_NO_ERROR; +} + +svn_error_t * +svn_wc_revision_status2(svn_wc_revision_status_t **result_p, + svn_wc_context_t *wc_ctx, + const char *local_abspath, + const char *trail_url, + svn_boolean_t committed, + svn_cancel_func_t cancel_func, + void *cancel_baton, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + SVN_ERR(svn_wc_revision_status3(result_p, wc_ctx, local_abspath, trail_url, + committed, TRUE, cancel_func, cancel_baton, + result_pool, scratch_pool)); return SVN_NO_ERROR; } Index: subversion/svnversion/svnversion.c =================================================================== --- subversion/svnversion/svnversion.c (revision 1870656) +++ subversion/svnversion/svnversion.c (working copy) @@ -32,7 +32,10 @@ #include "svn_private_config.h" -#define SVNVERSION_OPT_VERSION SVN_OPT_FIRST_LONGOPT_ID +enum { + SVNVERSION_OPT_VERSION = SVN_OPT_FIRST_LONGOPT_ID, + SVNVERSION_OPT_NO_STAT +}; static svn_error_t * @@ -135,10 +138,13 @@ sub_main(int *exit_code, int argc, const char *arg svn_wc_context_t *wc_ctx; svn_boolean_t quiet = FALSE; svn_boolean_t is_version = FALSE; + svn_boolean_t may_stat = TRUE; const apr_getopt_option_t options[] = { {"no-newline", 'n', 0, N_("do not output the trailing newline")}, {"committed", 'c', 0, N_("last changed rather than current revisions")}, + {"no-stat", SVNVERSION_OPT_NO_STAT, 0, + N_("don't check the working files for modifications")}, {"help", 'h', 0, N_("display this help")}, {"version", SVNVERSION_OPT_VERSION, 0, N_("show program version information")}, @@ -192,6 +198,9 @@ sub_main(int *exit_code, int argc, const char *arg case SVNVERSION_OPT_VERSION: is_version = TRUE; break; + case SVNVERSION_OPT_NO_STAT: + may_stat = FALSE; + break; default: *exit_code = EXIT_FAILURE; usage(pool); @@ -224,8 +233,8 @@ sub_main(int *exit_code, int argc, const char *arg else trail_url = NULL; - err = svn_wc_revision_status2(&res, wc_ctx, local_abspath, trail_url, - committed, NULL, NULL, pool, pool); + err = svn_wc_revision_status3(&res, wc_ctx, local_abspath, trail_url, + committed, may_stat, NULL, NULL, pool, pool); if (err && (err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND || err->apr_err == SVN_ERR_WC_NOT_WORKING_COPY)) Index: subversion/tests/cmdline/svnversion_tests.py =================================================================== --- subversion/tests/cmdline/svnversion_tests.py (revision 1870656) +++ subversion/tests/cmdline/svnversion_tests.py (working copy) @@ -377,6 +377,33 @@ def child_switched(sbox): svntest.actions.run_and_verify_svnversion(os.path.join(wc_dir, 'D', 'H'), None, [ "2\n" ], []) +def no_stat(sbox): + "test '--no-stat'" + sbox.build(read_only = True) + wc_dir = sbox.wc_dir + + verify = lambda expected_output: \ + svntest.actions.run_and_verify_svnversion(wc_dir, None, expected_output, + [], '--no-stat', '--no-newline') + + # Baseline: + verify(['1']) + + # Property change gets reported + sbox.simple_propset('k', 'v', 'iota') + verify(['1M']) + sbox.simple_revert('iota') + + # Tree changes get reported + sbox.simple_rm('iota') + verify(['1M']) + sbox.simple_revert('iota') + + # Text mods do NOT get reported: the output shall not include 'M'. + sbox.simple_append('iota', b'This file is locally modified.\n') + verify(['1']) + sbox.simple_revert('iota') + ######################################################################## # Run the tests @@ -390,6 +417,7 @@ test_list = [ None, committed_revisions, non_reposroot_wc, child_switched, + no_stat, ] if __name__ == '__main__': ]]]