Index: subversion/include/svn_wc.h =================================================================== --- subversion/include/svn_wc.h (revision 6604) +++ subversion/include/svn_wc.h (working copy) @@ -1563,7 +1563,24 @@ const char *diff3_cmd, apr_pool_t *pool); +typedef svn_error_t * (*svn_wc_put_repos_file_in_wc_helper)(svn_stream_t *fstream, apr_hash_t **props, void *baton); +/* + * Copies a single file from the repository in the working copy. + * @a dst_path is the destination path. + * @a adm_access is the adm_access. + * @a helper is a callback that accepts a file stream, a pointer to + * a property hash, and @a helper_baton, and actually retrieves the + * file from the back end. + * @a pool is the memory pool associated with the calling context. + * */ +svn_error_t * +svn_wc_put_repos_file_in_wc (const char *dst_path, + svn_wc_adm_access_t *adm_access, + svn_wc_put_repos_file_in_wc_helper helper, + void *helper_baton, + apr_pool_t *pool); + /* A word about the implementation of working copy property storage: * Index: subversion/libsvn_wc/update_editor.c =================================================================== --- subversion/libsvn_wc/update_editor.c (revision 6604) +++ subversion/libsvn_wc/update_editor.c (working copy) @@ -2330,3 +2330,128 @@ return SVN_NO_ERROR; } + +svn_error_t * +svn_wc_put_repos_file_in_wc (const char *dst_path, + svn_wc_adm_access_t *adm_access, + svn_wc_put_repos_file_in_wc_helper helper, + void *helper_baton, + apr_pool_t *pool + ) +{ + const char *text_base_path; + svn_stream_t *fstream; + apr_file_t *fp; + apr_hash_t *props; + const char *prop_base_path, *prop_path; + svn_stringbuf_t *log_accum; + apr_file_t *log_fp = NULL; + const char *parent_dir; + const char *base_name; + apr_status_t status; + const char * tmptext; + apr_hash_index_t *hi; + svn_node_kind_t kind; + apr_hash_t *regular_props; + + text_base_path = svn_wc__text_base_path(dst_path, FALSE, pool); + + SVN_ERR_W (svn_io_file_open (&fp, text_base_path, + (APR_CREATE | APR_WRITE), + APR_OS_DEFAULT, pool), + "failed to open file for writing."); + + /* Create a generic stream that operates on this file. */ + fstream = svn_stream_from_aprfile (fp, pool); + + SVN_ERR (helper (fstream, &props, helper_baton)); + + /* Close the file. */ + status = apr_file_close (fp); + if (status) + return svn_error_createf (status, NULL, + "failed to close file '%s'.", + dst_path); + + /* TODO: change the permissions of the text_base file to read-only */ + + /* Write the props and prop-base file for this file */ + + regular_props = apr_hash_make (pool); + if (props) + { + for (hi = apr_hash_first(pool, props); hi; hi = apr_hash_next(hi)) + { + const void *key; + void *val; + enum svn_prop_kind prop_kind; + + apr_hash_this (hi, &key, NULL, &val); + + /* We only want to set 'normal' props. For now, we're + ignoring any wc props (they're not needed when we commit + an addition), and we're ignoring entry props (they're + written to the entries file as part of the post-commit + processing). */ + prop_kind = svn_property_kind (NULL, key); + if (prop_kind == svn_prop_regular_kind) + { + apr_hash_set (regular_props, key, APR_HASH_KEY_STRING, val); + } + } + } + + SVN_ERR (svn_wc__prop_path (&prop_path, dst_path, adm_access, FALSE, pool)); + + SVN_ERR (svn_wc__prop_base_path (&prop_base_path, dst_path, adm_access, + FALSE, pool)); + + svn_wc__save_prop_file(prop_path, regular_props, pool); + svn_wc__save_prop_file(prop_base_path, regular_props, pool); + + /* Now copy the text-base to the main file while applying the end-of-line + * and keywords policies */ + + /* Split FILE_PATH. */ + svn_path_split (dst_path, &parent_dir, &base_name, pool); + + + /* Open a log file. This is safe because the adm area is locked + right now. */ + SVN_ERR (svn_wc__open_adm_file (&log_fp, + parent_dir, + SVN_WC__ADM_LOG, + (APR_WRITE | APR_CREATE), /* not excl */ + pool)); + + log_accum = svn_stringbuf_create ("", pool); + + tmptext = svn_wc__text_base_path(base_name, FALSE, pool); + + svn_xml_make_open_tag (&log_accum, pool, + svn_xml_self_closing, + SVN_WC__LOG_CP_AND_TRANSLATE, + SVN_WC__LOG_ATTR_NAME, tmptext, + SVN_WC__LOG_ATTR_DEST, base_name, + NULL); + + /* Write our accumulation of log entries into a log file */ + status = apr_file_write_full (log_fp, log_accum->data, + log_accum->len, NULL); + if (status) + { + apr_file_close (log_fp); + return svn_error_createf (status, NULL, + "error writing log for '%s'.", + dst_path); + } + + /* The log is ready to run. Close it and run it! */ + SVN_ERR (svn_wc__close_adm_file (log_fp, parent_dir, SVN_WC__ADM_LOG, + TRUE, /* sync */ pool)); + SVN_ERR (svn_wc__run_log (adm_access, NULL, pool)); + + return SVN_NO_ERROR; +} + + Index: subversion/libsvn_client/copy.c =================================================================== --- subversion/libsvn_client/copy.c (revision 6604) +++ subversion/libsvn_client/copy.c (working copy) @@ -672,7 +672,30 @@ return reconcile_errors (cmt_err, unlock_err, cleanup_err, pool); } +typedef struct +{ + svn_ra_plugin_t *ra_lib; + void *sess; + svn_revnum_t src_revnum; + svn_revnum_t *fetched_rev; + apr_hash_t **props; + apr_pool_t *pool; +}put_file_in_repos_baton; +static svn_error_t * +put_file_helper(svn_stream_t *fstream, apr_hash_t **props, void *void_baton) +{ + put_file_in_repos_baton *baton=void_baton; + + SVN_ERR (baton->ra_lib->get_file (baton->sess, "", baton->src_revnum, + fstream, baton->fetched_rev, + baton->props, baton->pool)); + + *props = *(baton->props); + + return SVN_NO_ERROR; +} + /* ### 838 OPTIONAL_ADM_ACCESS is an access baton with a write lock for the ### parent of DST_PATH. This parameter should be removed when issue 838 @@ -692,7 +715,6 @@ svn_revnum_t src_revnum; svn_wc_adm_access_t *adm_access; apr_hash_t *props = NULL; - apr_hash_index_t *hi; const char *src_uuid = NULL, *dst_uuid = NULL; svn_boolean_t same_repositories; const char *auth_dir; @@ -878,33 +900,20 @@ else if (src_kind == svn_node_file) { - apr_status_t status; - svn_stream_t *fstream; - apr_file_t *fp; - svn_revnum_t fetched_rev = 0; - - /* Open DST_PATH for writing. */ - SVN_ERR_W (svn_io_file_open (&fp, dst_path, - (APR_CREATE | APR_WRITE), - APR_OS_DEFAULT, pool), - "failed to open file for writing."); + svn_revnum_t fetched_rev; + put_file_in_repos_baton put_file_baton; + put_file_baton.ra_lib = ra_lib; + put_file_baton.sess = sess; + put_file_baton.src_revnum = src_revnum; + put_file_baton.fetched_rev = &fetched_rev; + put_file_baton.props = &props; + put_file_baton.pool = pool; + + SVN_ERR (svn_wc_put_repos_file_in_wc (dst_path, adm_access, + put_file_helper, + &put_file_baton, + pool)); - /* Create a generic stream that operates on this file. */ - fstream = svn_stream_from_aprfile (fp, pool); - - /* Have the RA layer 'push' data at this stream. We pass a - relative path of "", because we opened SRC_URL, which is - already the full URL to the file. */ - SVN_ERR (ra_lib->get_file (sess, "", src_revnum, fstream, - &fetched_rev, &props, pool)); - - /* Close the file. */ - status = apr_file_close (fp); - if (status) - return svn_error_createf (status, NULL, - "failed to close file '%s'.", - dst_path); - /* Also, if SRC_REVNUM is invalid ('head'), then FETCHED_REV is now equal to the revision that was actually retrieved. This is the value we want to use as 'copyfrom_rev' in the call to @@ -950,29 +959,6 @@ adm_access, ctx, pool)); } - /* If any properties were fetched (in the file case), apply those - changes now. */ - if (props) - { - for (hi = apr_hash_first(pool, props); hi; hi = apr_hash_next(hi)) - { - const void *key; - void *val; - enum svn_prop_kind kind; - - apr_hash_this (hi, &key, NULL, &val); - - /* We only want to set 'normal' props. For now, we're - ignoring any wc props (they're not needed when we commit - an addition), and we're ignoring entry props (they're - written to the entries file as part of the post-commit - processing). */ - kind = svn_property_kind (NULL, key); - if (kind == svn_prop_regular_kind) - SVN_ERR (svn_wc_prop_set (key, val, dst_path, adm_access, pool)); - } - } - if (! optional_adm_access) SVN_ERR (svn_wc_adm_close (adm_access)); Index: subversion/tests/clients/cmdline/copy_tests.py =================================================================== --- subversion/tests/clients/cmdline/copy_tests.py (revision 6613) +++ subversion/tests/clients/cmdline/copy_tests.py (working copy) @@ -1105,8 +1105,26 @@ }) svntest.actions.run_and_verify_status (wc_dir, expected_status) +#------------------------------------------------------------- +# Issue #1297: +# svn diff failed after a repository to WC copy of a single file +# This test checks just that. +def repos_to_wc_copy_a_file_and_diff(sbox): + "Repos->WC Copy a file and Diff" + sbox.build() + wc_dir = sbox.wc_dir + + iota_repos_path = svntest.main.current_repo_url + '/iota' + target_wc_path = os.path.join(wc_dir, 'new_file'); + + svntest.actions.run_and_verify_svn(None, None, [], 'cp', + iota_repos_path, target_wc_path) + + svntest.actions.run_and_verify_svn(None, None, [], 'diff', wc_dir) + + ######################################################################## # Run the tests @@ -1130,6 +1148,7 @@ url_copy_parent_into_child, wc_copy_parent_into_child, resurrect_deleted_file, + repos_to_wc_copy_a_file_and_diff, ] if __name__ == '__main__': Index: subversion/tests/clients/cmdline/merge_tests.py =================================================================== --- subversion/tests/clients/cmdline/merge_tests.py (revision 6655) +++ subversion/tests/clients/cmdline/merge_tests.py (working copy) @@ -1247,7 +1247,50 @@ None, None, None, None, None, 1) +#---------------------------------------------------------------------- +# Issue #1297: +# A merge that creates a new file followed by an immediate diff +# The diff should succeed. +def merge_that_creates_a_new_file_and_diff(sbox): + "Merge that creates a new file followed by a diff" + + sbox.build() + + wc_dir = sbox.wc_dir + + trunk_url = svntest.main.current_repo_url + '/A/B/E'; + + # Create a branch + svntest.actions.run_and_verify_svn(None, None, [], 'cp', + trunk_url, + svntest.main.current_repo_url + '/branch', + '-m', "Creating the Branch" + ) + + # Now we're at revision No. 2 + + svntest.actions.run_and_verify_svn(None, None, [], 'update', wc_dir) + + new_file_path = os.path.join(wc_dir, 'A', 'B', 'E', 'newfile'); + fp = open(new_file_path, 'w') + fp.write("newfile") + fp.close() + + svntest.actions.run_and_verify_svn(None, None, [], "add", new_file_path); + + svntest.actions.run_and_verify_svn(None, None, [], 'ci', '-m', "Changing the trunk.", wc_dir) + + # Now we're at revision No. 3 + branch_path = os.path.join(wc_dir, "branch") + svntest.actions.run_and_verify_svn(None, None, [], 'merge', '-r', '1:HEAD', + trunk_url, branch_path) + + svntest.actions.run_and_verify_svn(None, None, [], 'diff', branch_path) + + + + ######################################################################## # Run the tests @@ -1265,6 +1308,7 @@ merge_with_prev, merge_binary_file, merge_one_file, + merge_that_creates_a_new_file_and_diff, # property_merges_galore, # Would be nice to have this. # tree_merges_galore, # Would be nice to have this. # various_merges_galore, # Would be nice to have this.