You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by ju...@apache.org on 2018/07/09 09:53:37 UTC
svn commit: r1835398 - in /subversion/trunk/subversion:
include/private/svn_client_private.h include/svn_client.h
libsvn_client/diff.c libsvn_client/shelf.c svn/shelf-cmd.c
tests/cmdline/shelf_tests.py
Author: julianfoad
Date: Mon Jul 9 09:53:37 2018
New Revision: 1835398
URL: http://svn.apache.org/viewvc?rev=1835398&view=rev
Log:
Shelving: Implement 'svn shelf-diff', issue SVN-4745.
This is a first pass. It drives only the file methods in the diff processor
API, not the open- and close-directory methods, and not reporting changes on
directories.
* subversion/include/svn_client.h
(svn_client_shelf_export_patch): Deprecate.
* subversion/include/private/svn_client_private.h
(svn_client__get_diff_writer_unidiff): New.
(svn_client__shelf_diff): New.
* subversion/libsvn_client/diff.c
(svn_client__get_diff_writer_unidiff): New.
* subversion/libsvn_client/shelf.c
(file_changed, file_deleted, file_added): New.
(diff_baton_t, diff_visitor): Drive a diff-processor from shelved changes.
(svn_client__shelf_diff): New.
(svn_client_shelf_export_patch): Delete the body; it is deprecated and did
nothing before.
* subversion/svn/shelf-cmd.c
(shelf_diff): First obtain a diff writer. Then call the shelf-diff API,
driving that writer.
* subversion/tests/cmdline/shelf_tests.py
(shelf_diff_simple): New test.
(test_list): Run it.
Modified:
subversion/trunk/subversion/include/private/svn_client_private.h
subversion/trunk/subversion/include/svn_client.h
subversion/trunk/subversion/libsvn_client/diff.c
subversion/trunk/subversion/libsvn_client/shelf.c
subversion/trunk/subversion/svn/shelf-cmd.c
subversion/trunk/subversion/tests/cmdline/shelf_tests.py
Modified: subversion/trunk/subversion/include/private/svn_client_private.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/include/private/svn_client_private.h?rev=1835398&r1=1835397&r2=1835398&view=diff
==============================================================================
--- subversion/trunk/subversion/include/private/svn_client_private.h (original)
+++ subversion/trunk/subversion/include/private/svn_client_private.h Mon Jul 9 09:53:37 2018
@@ -341,6 +341,51 @@ svn_client__mergeinfo_log(svn_boolean_t
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
+/** Return a diff processor that will print a Subversion-style
+ * (not git-style) diff.
+ *
+ * @a anchor is optional (may be null), and is the 'anchor' path to prefix
+ * to the diff-processor paths before displaying.
+ *
+ * @a orig_path_1 and @a orig_path_2 are the two main root paths to be
+ * diffed; each may be a URL, a local WC path or a local unversioned path.
+ *
+ * Other arguments are as for svn_client_diff7() etc.
+ */
+svn_error_t *
+svn_client__get_diff_writer_svn(
+ svn_diff_tree_processor_t **diff_processor,
+ const char *anchor,
+ const char *orig_path_1,
+ const char *orig_path_2,
+ const apr_array_header_t *options,
+ const char *relative_to_dir,
+ svn_boolean_t no_diff_added,
+ svn_boolean_t no_diff_deleted,
+ svn_boolean_t show_copies_as_adds,
+ svn_boolean_t ignore_content_type,
+ svn_boolean_t ignore_properties,
+ svn_boolean_t properties_only,
+ svn_boolean_t pretty_print_mergeinfo,
+ const char *header_encoding,
+ svn_stream_t *outstream,
+ svn_stream_t *errstream,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *pool);
+
+/** Output the subtree of @a shelf_version rooted at @a shelf_relpath
+ * as a diff to @a diff_processor.
+ *
+ * @since New in 1.X.
+ * @warning EXPERIMENTAL.
+ */
+SVN_EXPERIMENTAL
+svn_error_t *
+svn_client__shelf_diff(svn_client_shelf_version_t *shelf_version,
+ const char *shelf_relpath,
+ svn_diff_tree_processor_t *diff_processor,
+ apr_pool_t *scratch_pool);
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
Modified: subversion/trunk/subversion/include/svn_client.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/include/svn_client.h?rev=1835398&r1=1835397&r2=1835398&view=diff
==============================================================================
--- subversion/trunk/subversion/include/svn_client.h (original)
+++ subversion/trunk/subversion/include/svn_client.h Mon Jul 9 09:53:37 2018
@@ -7152,12 +7152,10 @@ svn_client_shelf_unapply(svn_client_shel
svn_boolean_t dry_run,
apr_pool_t *scratch_pool);
-/** Output @a shelf_version as a patch to @a outstream.
- *
- * @since New in 1.X.
+/** @deprecated Use svn_client__shelf_diff() instead.
* @warning EXPERIMENTAL.
*/
-SVN_EXPERIMENTAL
+SVN_DEPRECATED
svn_error_t *
svn_client_shelf_export_patch(svn_client_shelf_version_t *shelf_version,
svn_stream_t *outstream,
Modified: subversion/trunk/subversion/libsvn_client/diff.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/diff.c?rev=1835398&r1=1835397&r2=1835398&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/diff.c (original)
+++ subversion/trunk/subversion/libsvn_client/diff.c Mon Jul 9 09:53:37 2018
@@ -2580,6 +2580,49 @@ get_diff_processor(svn_diff_tree_process
return SVN_NO_ERROR;
}
+svn_error_t *
+svn_client__get_diff_writer_svn(
+ svn_diff_tree_processor_t **diff_processor,
+ const char *anchor,
+ const char *orig_path_1,
+ const char *orig_path_2,
+ const apr_array_header_t *options,
+ const char *relative_to_dir,
+ svn_boolean_t no_diff_added,
+ svn_boolean_t no_diff_deleted,
+ svn_boolean_t show_copies_as_adds,
+ svn_boolean_t ignore_content_type,
+ svn_boolean_t ignore_properties,
+ svn_boolean_t properties_only,
+ svn_boolean_t pretty_print_mergeinfo,
+ const char *header_encoding,
+ svn_stream_t *outstream,
+ svn_stream_t *errstream,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *pool)
+{
+ struct diff_driver_info_t *ddi;
+
+ SVN_ERR(get_diff_processor(diff_processor, &ddi,
+ options,
+ relative_to_dir,
+ no_diff_added,
+ no_diff_deleted,
+ show_copies_as_adds,
+ ignore_content_type,
+ ignore_properties,
+ properties_only,
+ FALSE /*use_git_diff_format*/,
+ pretty_print_mergeinfo,
+ header_encoding,
+ outstream, errstream,
+ ctx, pool));
+ ddi->anchor = anchor;
+ ddi->orig_path_1 = orig_path_1;
+ ddi->orig_path_2 = orig_path_2;
+ return SVN_NO_ERROR;
+}
+
/*----------------------------------------------------------------------- */
/*** Public Interfaces. ***/
Modified: subversion/trunk/subversion/libsvn_client/shelf.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/shelf.c?rev=1835398&r1=1835397&r2=1835398&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/shelf.c (original)
+++ subversion/trunk/subversion/libsvn_client/shelf.c Mon Jul 9 09:53:37 2018
@@ -413,6 +413,9 @@ shelf_write_current(svn_client_shelf_t *
return SVN_NO_ERROR;
}
+/*-------------------------------------------------------------------------*/
+/* Status Reporting */
+
/* Create a status struct with all fields initialized to valid values
* representing 'uninteresting' or 'unknown' status.
*/
@@ -728,6 +731,9 @@ svn_client_shelf_version_status_walk(svn
return SVN_NO_ERROR;
}
+/*-------------------------------------------------------------------------*/
+/* Shelf Storage */
+
/* A baton for use with write_changes_visitor(). */
typedef struct write_changes_baton_t {
const char *wc_root_abspath;
@@ -1609,23 +1615,204 @@ apply_file_visitor(void *baton,
return SVN_NO_ERROR;
}
+/*-------------------------------------------------------------------------*/
+/* Diff */
+
+/* */
+static svn_error_t *
+file_changed(svn_client_shelf_version_t *shelf_version,
+ const char *relpath,
+ svn_wc_status3_t *s,
+ svn_diff_tree_processor_t *diff_processor,
+ svn_diff_source_t *left_source,
+ svn_diff_source_t *right_source,
+ const char *left_stored_abspath,
+ const char *right_stored_abspath,
+ void *dir_baton,
+ apr_pool_t *scratch_pool)
+{
+ void *fb;
+ svn_boolean_t skip = FALSE;
+
+ SVN_ERR(diff_processor->file_opened(&fb, &skip, relpath,
+ left_source, right_source,
+ NULL /*copyfrom*/,
+ dir_baton, diff_processor,
+ scratch_pool, scratch_pool));
+ if (!skip)
+ {
+ apr_hash_t *left_props, *right_props;
+ apr_array_header_t *prop_changes;
+
+ SVN_ERR(read_props_from_shelf(&left_props, &right_props,
+ s->node_status, shelf_version, relpath,
+ scratch_pool, scratch_pool));
+ SVN_ERR(svn_prop_diffs(&prop_changes, right_props, left_props,
+ scratch_pool));
+ SVN_ERR(diff_processor->file_changed(
+ relpath,
+ left_source, right_source,
+ left_stored_abspath, right_stored_abspath,
+ left_props, right_props,
+ TRUE /*file_modified*/, prop_changes,
+ fb, diff_processor, scratch_pool));
+ }
+
+ return SVN_NO_ERROR;
+}
+
+/* */
+static svn_error_t *
+file_deleted(svn_client_shelf_version_t *shelf_version,
+ const char *relpath,
+ svn_wc_status3_t *s,
+ svn_diff_tree_processor_t *diff_processor,
+ svn_diff_source_t *left_source,
+ const char *left_stored_abspath,
+ void *dir_baton,
+ apr_pool_t *scratch_pool)
+{
+ void *fb;
+ svn_boolean_t skip = FALSE;
+
+ SVN_ERR(diff_processor->file_opened(&fb, &skip, relpath,
+ left_source, NULL, NULL /*copyfrom*/,
+ dir_baton, diff_processor,
+ scratch_pool, scratch_pool));
+ if (!skip)
+ {
+ apr_hash_t *left_props, *right_props;
+
+ SVN_ERR(read_props_from_shelf(&left_props, &right_props,
+ s->node_status, shelf_version, relpath,
+ scratch_pool, scratch_pool));
+ SVN_ERR(diff_processor->file_deleted(relpath,
+ left_source,
+ left_stored_abspath,
+ left_props,
+ fb, diff_processor,
+ scratch_pool));
+ }
+
+ return SVN_NO_ERROR;
+}
+
+/* */
+static svn_error_t *
+file_added(svn_client_shelf_version_t *shelf_version,
+ const char *relpath,
+ svn_wc_status3_t *s,
+ svn_diff_tree_processor_t *diff_processor,
+ svn_diff_source_t *right_source,
+ const char *right_stored_abspath,
+ void *dir_baton,
+ apr_pool_t *scratch_pool)
+{
+ void *fb;
+ svn_boolean_t skip = FALSE;
+
+ SVN_ERR(diff_processor->file_opened(&fb, &skip, relpath,
+ NULL, right_source, NULL /*copyfrom*/,
+ dir_baton, diff_processor,
+ scratch_pool, scratch_pool));
+ if (!skip)
+ {
+ apr_hash_t *left_props, *right_props;
+
+ SVN_ERR(read_props_from_shelf(&left_props, &right_props,
+ s->node_status, shelf_version, relpath,
+ scratch_pool, scratch_pool));
+ SVN_ERR(diff_processor->file_added(
+ relpath,
+ NULL /*copyfrom_source*/, right_source,
+ NULL /*copyfrom_abspath*/, right_stored_abspath,
+ NULL /*copyfrom_props*/, right_props,
+ fb, diff_processor, scratch_pool));
+ }
+
+ return SVN_NO_ERROR;
+}
+
/* Baton for diff_visitor(). */
struct diff_baton_t
{
svn_client_shelf_version_t *shelf_version;
- svn_stream_t *outstream;
+ const char *top_relpath; /* top of diff, relative to shelf */
+ const char *walk_root_abspath;
+ svn_diff_tree_processor_t *diff_processor;
};
-/* Write a diff to BATON->outstream.
- * Implements shelved_files_walk_func_t. */
+/* Drive BATON->diff_processor.
+ * Implements svn_io_walk_func_t. */
static svn_error_t *
diff_visitor(void *baton,
- const char *relpath,
- svn_wc_status3_t *s,
+ const char *abspath,
+ const apr_finfo_t *finfo,
apr_pool_t *scratch_pool)
{
- /* ### TODO */
+ struct diff_baton_t *b = baton;
+ const char *relpath;
+ relpath = svn_dirent_skip_ancestor(b->walk_root_abspath, abspath);
+ if (finfo->filetype == APR_REG
+ && (strlen(relpath) >= 5 && strcmp(relpath+strlen(relpath)-5, ".meta") == 0))
+ {
+ svn_wc_status3_t *s;
+ void *db = NULL;
+ svn_diff_source_t *left_source;
+ svn_diff_source_t *right_source;
+ char *left_stored_abspath, *right_stored_abspath;
+
+ relpath = apr_pstrndup(scratch_pool, relpath, strlen(relpath) - 5);
+ if (!svn_relpath_skip_ancestor(b->top_relpath, relpath))
+ return SVN_NO_ERROR;
+
+ SVN_ERR(status_read(&s, b->shelf_version, relpath,
+ scratch_pool, scratch_pool));
+
+ left_source = svn_diff__source_create(s->revision, scratch_pool);
+ right_source = svn_diff__source_create(SVN_INVALID_REVNUM, scratch_pool);
+ SVN_ERR(get_base_file_abspath(&left_stored_abspath,
+ b->shelf_version, relpath,
+ scratch_pool, scratch_pool));
+ SVN_ERR(get_working_file_abspath(&right_stored_abspath,
+ b->shelf_version, relpath,
+ scratch_pool, scratch_pool));
+
+ switch (s->node_status)
+ {
+ case svn_wc_status_modified:
+ SVN_ERR(file_changed(b->shelf_version, relpath, s,
+ b->diff_processor,
+ left_source, right_source,
+ left_stored_abspath, right_stored_abspath,
+ db, scratch_pool));
+ break;
+ case svn_wc_status_added:
+ SVN_ERR(file_added(b->shelf_version, relpath, s,
+ b->diff_processor,
+ right_source, right_stored_abspath,
+ db, scratch_pool));
+ break;
+ case svn_wc_status_deleted:
+ SVN_ERR(file_deleted(b->shelf_version, relpath, s,
+ b->diff_processor,
+ left_source, left_stored_abspath,
+ db, scratch_pool));
+ break;
+ case svn_wc_status_replaced:
+ SVN_ERR(file_deleted(b->shelf_version, relpath, s,
+ b->diff_processor,
+ left_source, left_stored_abspath,
+ db, scratch_pool));
+ SVN_ERR(file_added(b->shelf_version, relpath, s,
+ b->diff_processor,
+ right_source, right_stored_abspath,
+ db, scratch_pool));
+ default:
+ break;
+ }
+ }
return SVN_NO_ERROR;
}
@@ -1726,17 +1913,34 @@ svn_client_shelf_delete_newer_versions(s
}
svn_error_t *
+svn_client__shelf_diff(svn_client_shelf_version_t *shelf_version,
+ const char *shelf_relpath,
+ svn_diff_tree_processor_t *diff_processor,
+ apr_pool_t *scratch_pool)
+{
+ struct diff_baton_t baton;
+ svn_error_t *err;
+
+ baton.shelf_version = shelf_version;
+ baton.top_relpath = shelf_relpath;
+ baton.walk_root_abspath = shelf_version->files_dir_abspath;
+ baton.diff_processor = diff_processor;
+ err = svn_io_dir_walk2(baton.walk_root_abspath, 0 /*wanted*/,
+ diff_visitor, &baton,
+ scratch_pool);
+ if (err && APR_STATUS_IS_ENOENT(err->apr_err))
+ svn_error_clear(err);
+ else
+ SVN_ERR(err);
+
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
svn_client_shelf_export_patch(svn_client_shelf_version_t *shelf_version,
svn_stream_t *outstream,
apr_pool_t *scratch_pool)
{
- struct diff_baton_t baton = {0};
-
- baton.shelf_version = shelf_version;
- baton.outstream = outstream;
- SVN_ERR(shelf_status_walk(shelf_version, "",
- diff_visitor, &baton,
- scratch_pool));
return SVN_NO_ERROR;
}
Modified: subversion/trunk/subversion/svn/shelf-cmd.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svn/shelf-cmd.c?rev=1835398&r1=1835397&r2=1835398&view=diff
==============================================================================
--- subversion/trunk/subversion/svn/shelf-cmd.c (original)
+++ subversion/trunk/subversion/svn/shelf-cmd.c Mon Jul 9 09:53:37 2018
@@ -38,6 +38,7 @@
#include "svn_private_config.h"
#include "private/svn_sorts_private.h"
+#include "private/svn_client_private.h"
/* Open the newest version of SHELF; error if no versions found. */
@@ -709,7 +710,8 @@ shelf_diff(const char *name,
{
svn_client_shelf_t *shelf;
svn_client_shelf_version_t *shelf_version;
- svn_stream_t *stream;
+ svn_stream_t *stream, *errstream;
+ svn_diff_tree_processor_t *diff_processor;
SVN_ERR(svn_client_shelf_open_existing(&shelf, name, local_abspath,
ctx, scratch_pool));
@@ -730,8 +732,27 @@ shelf_diff(const char *name,
}
SVN_ERR(svn_stream_for_stdout(&stream, scratch_pool));
- SVN_ERR(svn_client_shelf_export_patch(shelf_version, stream,
- scratch_pool));
+ errstream = svn_stream_empty(scratch_pool);
+
+ SVN_ERR(svn_client__get_diff_writer_svn(
+ &diff_processor,
+ NULL /*anchor*/,
+ "", "", /*orig_path_1, orig_path_2,*/
+ NULL /*options*/,
+ "" /*relative_to_dir*/,
+ FALSE /*no_diff_added*/,
+ FALSE /*no_diff_deleted*/,
+ FALSE /*show_copies_as_adds*/,
+ FALSE /*ignore_content_type*/,
+ FALSE /*ignore_properties*/,
+ FALSE /*properties_only*/,
+ TRUE /*pretty_print_mergeinfo*/,
+ svn_cmdline_output_encoding(scratch_pool),
+ stream, errstream,
+ ctx, scratch_pool));
+
+ SVN_ERR(svn_client__shelf_diff(shelf_version, "", diff_processor,
+ scratch_pool));
SVN_ERR(svn_stream_close(stream));
SVN_ERR(svn_client_shelf_close(shelf, scratch_pool));
Modified: subversion/trunk/subversion/tests/cmdline/shelf_tests.py
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/shelf_tests.py?rev=1835398&r1=1835397&r2=1835398&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/shelf_tests.py (original)
+++ subversion/trunk/subversion/tests/cmdline/shelf_tests.py Mon Jul 9 09:53:37 2018
@@ -32,6 +32,10 @@ logger = logging.getLogger()
# Our testing module
import svntest
from svntest import wc
+from svntest.verify import make_diff_header, make_no_diff_deleted_header, \
+ make_git_diff_header, make_diff_prop_header, \
+ make_diff_prop_val, make_diff_prop_deleted, \
+ make_diff_prop_added, make_diff_prop_modified
# (abbreviation)
Skip = svntest.testcase.Skip_deco
@@ -874,6 +878,46 @@ B>>>>>>> (incoming 'changed to' value)
unshelve_with_merge(sbox, setup, modifier1, modifier2, tweak_expected_state)
+#----------------------------------------------------------------------
+
+# Exercise a very basic case of shelf-diff.
+def shelf_diff_simple(sbox):
+ "shelf diff simple"
+
+ sbox.build()
+ was_cwd = os.getcwd()
+ os.chdir(sbox.wc_dir)
+ sbox.wc_dir = ''
+ wc_dir = sbox.wc_dir
+
+ def setup(sbox):
+ sbox.simple_propset('p1', 'v', 'A/mu')
+ sbox.simple_propset('p2', 'v', 'A/mu')
+
+ def modifier1(sbox):
+ sbox.simple_append('A/mu', 'New line.\n')
+ sbox.simple_propset('p1', 'changed', 'A/mu')
+
+ setup(sbox)
+ sbox.simple_commit()
+ initial_state = get_wc_state(wc_dir)
+
+ # Make some changes to the working copy
+ modifier1(sbox)
+ modified_state = get_wc_state(wc_dir)
+
+ svntest.actions.run_and_verify_svn(None, [],
+ 'shelf-save', 'foo')
+
+ expected_output = make_diff_header('A/mu', 'revision 2', 'working copy') + [
+ "@@ -1 +1,2 @@\n",
+ " This is the file 'mu'.\n",
+ "+New line.\n",
+ ] + make_diff_prop_header('A/mu') \
+ + make_diff_prop_modified('p1', 'v', 'changed')
+ svntest.actions.run_and_verify_svn(expected_output, [],
+ 'shelf-diff', 'foo')
+
########################################################################
# Run the tests
@@ -910,6 +954,7 @@ test_list = [ None,
unshelve_binary_mod_conflict,
unshelve_text_prop_merge,
unshelve_text_prop_conflict,
+ shelf_diff_simple,
]
if __name__ == '__main__':