📄 diff.c
字号:
return SVN_NO_ERROR;
}
/* The single-file, simplified version of do_merge. */
static svn_error_t *
do_single_file_merge (const char *initial_URL1,
const char *initial_path1,
const svn_opt_revision_t *initial_revision1,
const char *initial_URL2,
const char *initial_path2,
const svn_opt_revision_t *initial_revision2,
const svn_opt_revision_t *peg_revision,
const char *target_wcpath,
svn_wc_adm_access_t *adm_access,
struct merge_cmd_baton *merge_b,
apr_pool_t *pool)
{
apr_hash_t *props1, *props2;
const char *tmpfile1, *tmpfile2;
svn_revnum_t rev1, rev2;
const char *mimetype1, *mimetype2;
svn_string_t *pval;
apr_array_header_t *propchanges;
void *ra_baton;
svn_wc_notify_state_t prop_state = svn_wc_notify_state_unknown;
svn_wc_notify_state_t text_state = svn_wc_notify_state_unknown;
const char *URL1, *path1, *URL2, *path2;
svn_opt_revision_t *revision1, *revision2;
SVN_ERR (svn_ra_init_ra_libs (&ra_baton, pool));
/* If we are performing a pegged merge, we need to find out what our
actual URLs will be. */
if (peg_revision->kind != svn_opt_revision_unspecified)
{
svn_ra_plugin_t *ra_lib;
SVN_ERR (svn_ra_get_ra_library (&ra_lib, ra_baton, initial_URL2, pool));
SVN_ERR (svn_client__repos_locations (&URL1, &revision1,
&URL2, &revision2,
initial_path2 ? initial_path2
: initial_URL2,
peg_revision,
initial_revision1,
initial_revision2,
ra_lib, merge_b->ctx, pool));
merge_b->url = URL2;
merge_b->path = NULL;
path1 = NULL;
path2 = NULL;
}
else
{
URL1 = initial_URL1;
URL2 = initial_URL2;
path1 = initial_path1;
path2 = initial_path2;
revision1 = apr_pcalloc (pool, sizeof (*revision1));
*revision1 = *initial_revision1;
revision2 = apr_pcalloc (pool, sizeof (*revision2));
*revision2 = *initial_revision2;
}
/* ### heh, funny. we could be fetching two fulltexts from two
*totally* different repositories here. :-) */
SVN_ERR (single_file_merge_get_file (&tmpfile1, &props1, &rev1,
URL1, path1, revision1,
ra_baton, merge_b, pool));
SVN_ERR (single_file_merge_get_file (&tmpfile2, &props2, &rev2,
URL2, path2, revision2,
ra_baton, merge_b, pool));
/* Discover any svn:mime-type values in the proplists */
pval = apr_hash_get (props1, SVN_PROP_MIME_TYPE, strlen(SVN_PROP_MIME_TYPE));
mimetype1 = pval ? pval->data : NULL;
pval = apr_hash_get (props2, SVN_PROP_MIME_TYPE, strlen(SVN_PROP_MIME_TYPE));
mimetype2 = pval ? pval->data : NULL;
SVN_ERR (merge_file_changed (adm_access,
&text_state,
merge_b->target,
tmpfile1,
tmpfile2,
rev1,
rev2,
mimetype1, mimetype2,
merge_b));
SVN_ERR (svn_io_remove_file (tmpfile1, pool));
SVN_ERR (svn_io_remove_file (tmpfile2, pool));
/* Deduce property diffs, and merge those too. */
SVN_ERR (svn_prop_diffs (&propchanges, props2, props1, pool));
SVN_ERR (merge_props_changed (adm_access,
&prop_state,
merge_b->target,
propchanges,
NULL,
merge_b));
if (merge_b->ctx->notify_func)
{
(*merge_b->ctx->notify_func) (merge_b->ctx->notify_baton,
merge_b->target,
svn_wc_notify_update_update,
svn_node_file,
NULL,
text_state,
prop_state,
SVN_INVALID_REVNUM);
}
return SVN_NO_ERROR;
}
/* A Theoretical Note From Ben, regarding do_diff().
This function is really svn_client_diff(). If you read the public
API description for svn_client_diff, it sounds quite Grand. It
sounds really generalized and abstract and beautiful: that it will
diff any two paths, be they working-copy paths or URLs, at any two
revisions.
Now, the *reality* is that we have exactly three 'tools' for doing
diffing, and thus this routine is built around the use of the three
tools. Here they are, for clarity:
- svn_wc_diff: assumes both paths are the same wcpath.
compares wcpath@BASE vs. wcpath@WORKING
- svn_wc_get_diff_editor: compares some URL@REV vs. wcpath@WORKING
- svn_client__get_diff_editor: compares some URL1@REV1 vs. URL2@REV2
So the truth of the matter is, if the caller's arguments can't be
pigeonholed into one of these three use-cases, we currently bail
with a friendly apology.
Perhaps someday a brave soul will truly make svn_client_diff
perfectly general. For now, we live with the 90% case. Certainly,
the commandline client only calls this function in legal ways.
When there are other users of svn_client.h, maybe this will become
a more pressing issue.
*/
/* Return a "you can't do that" error, optionally wrapping another
error CHILD_ERR. */
static svn_error_t *
unsupported_diff_error (svn_error_t *child_err)
{
return svn_error_create (SVN_ERR_INCORRECT_PARAMS, child_err,
_("Sorry, svn_client_diff was called in a way "
"that is not yet supported"));
}
/* Perform a diff between two working-copy paths.
PATH1 and PATH2 are both working copy paths. REVISION1 and
REVISION2 are their respective revisions.
All other options are the same as those passed to svn_client_diff(). */
static svn_error_t *
diff_wc_wc (const apr_array_header_t *options,
const char *path1,
const svn_opt_revision_t *revision1,
const char *path2,
const svn_opt_revision_t *revision2,
svn_boolean_t recurse,
svn_boolean_t ignore_ancestry,
const svn_wc_diff_callbacks_t *callbacks,
struct diff_cmd_baton *callback_baton,
svn_client_ctx_t *ctx,
apr_pool_t *pool)
{
svn_wc_adm_access_t *adm_access;
const char *anchor, *target;
svn_node_kind_t kind;
/* Assert that we have valid input. */
assert (! svn_path_is_url (path1));
assert (! svn_path_is_url (path2));
/* Currently we support only the case where path1 and path2 are the
same path. */
if ((strcmp (path1, path2) != 0)
|| (! ((revision1->kind == svn_opt_revision_base)
&& (revision2->kind == svn_opt_revision_working))))
return unsupported_diff_error
(svn_error_create
(SVN_ERR_INCORRECT_PARAMS, NULL,
_("Only diffs between a path's text-base "
"and its working files are supported at this time")));
SVN_ERR (svn_wc_get_actual_target (path1, &anchor, &target, pool));
SVN_ERR (svn_io_check_path (path1, &kind, pool));
SVN_ERR (svn_wc_adm_open2 (&adm_access, NULL, anchor, FALSE,
(recurse && (! *target)) ? -1 : 0, pool));
if (*target && (kind == svn_node_dir))
{
/* Associate a potentially tree-locked access baton for the
target with the anchor's access baton. Note that we don't
actually use the target's baton here; it just floats around
in adm_access's set of associated batons, where the diff
editor can find it. */
svn_wc_adm_access_t *target_access;
SVN_ERR (svn_wc_adm_open2 (&target_access, adm_access, path1,
FALSE, recurse ? -1 : 0, pool));
}
/* Resolve named revisions to real numbers. */
SVN_ERR (svn_client__get_revision_number
(&callback_baton->revnum1, NULL, NULL, revision1, path1, pool));
callback_baton->revnum2 = SVN_INVALID_REVNUM; /* WC */
SVN_ERR (svn_wc_diff2 (adm_access, target, callbacks, callback_baton,
recurse, ignore_ancestry, pool));
SVN_ERR (svn_wc_adm_close (adm_access));
return SVN_NO_ERROR;
}
/* Perform a diff between two repository paths.
PATH1 and PATH2 may be either URLs or the working copy paths.
REVISION1 and REVISION2 are their respective revisions. If
PEG_REVISION is specified, PATH2 is the path at the peg revision,
and the actual two paths compared are determined by following copy
history from PATH2.
All other options are the same as those passed to svn_client_diff(). */
static svn_error_t *
diff_repos_repos (const apr_array_header_t *options,
const char *path1,
const svn_opt_revision_t *revision1,
const char *path2,
const svn_opt_revision_t *revision2,
const svn_opt_revision_t *peg_revision,
svn_boolean_t recurse,
svn_boolean_t ignore_ancestry,
const svn_wc_diff_callbacks_t *callbacks,
struct diff_cmd_baton *callback_baton,
svn_client_ctx_t *ctx,
apr_pool_t *pool)
{
const char *url1, *url2;
const char *anchor1, *target1, *anchor2, *target2, *base_path;
svn_node_kind_t kind1, kind2;
svn_revnum_t rev1, rev2;
void *ra_baton, *session1, *session2;
svn_ra_plugin_t *ra_lib;
const svn_ra_reporter_t *reporter;
void *report_baton;
const svn_delta_editor_t *diff_editor;
void *diff_edit_baton;
apr_pool_t *temppool = svn_pool_create (pool);
svn_boolean_t same_urls;
/* Figure out URL1 and URL2. */
SVN_ERR (convert_to_url (&url1, path1, pool));
SVN_ERR (convert_to_url (&url2, path2, pool));
same_urls = (strcmp (url1, url2) == 0);
/* We need exactly one BASE_PATH, so we'll let the BASE_PATH
calculated for PATH2 override the one for PATH1 (since the diff
will be "applied" to URL2 anyway). */
base_path = NULL;
if (url1 != path1)
base_path = path1;
if (url2 != path2)
base_path = path2;
/* Setup our RA libraries. */
SVN_ERR (svn_ra_init_ra_libs (&ra_baton, pool));
SVN_ERR (svn_ra_get_ra_library (&ra_lib, ra_baton, url1, pool));
/* If we are performing a pegged diff, we need to find out what our
actual URLs will be. */
if (peg_revision->kind != svn_opt_revision_unspecified)
{
svn_opt_revision_t *start_ignore, *end_ignore;
SVN_ERR (svn_client__repos_locations (&url1, &start_ignore,
&url2, &end_ignore,
path2,
peg_revision,
revision1, revision2,
ra_lib, ctx, pool));
callback_baton->orig_path_1 = url1;
callback_baton->orig_path_2 = url2;
}
/* Open temporary RA sessions to each URL. */
SVN_ERR (svn_client__open_ra_session (&session1, ra_lib, url1, NULL,
NULL, NULL, FALSE, TRUE,
ctx, temppool));
SVN_ERR (svn_client__open_ra_session (&session2, ra_lib, url2, NULL,
NULL, NULL, FALSE, TRUE,
ctx, temppool));
/* Resolve named revisions to real numbers. */
SVN_ERR (svn_client__get_revision_number
(&rev1, ra_lib, session1, revision1,
(path1 == url1) ? NULL : path1, pool));
callback_baton->revnum1 = rev1;
SVN_ERR (svn_client__get_revision_number
(&rev2, ra_lib, session2, revision2,
(path2 == url2) ? NULL : path2, pool));
callback_baton->revnum2 = rev2;
/* Choose useful anchors and targets for our two URLs, and verify
that both sides of the diff exist. */
anchor1 = url1;
anchor2 = url2;
target1 = "";
target2 = "";
SVN_ERR (ra_lib->check_path (session1, "", rev1, &kind1, temppool));
SVN_ERR (ra_lib->check_path (session2, "", rev2, &kind2, temppool));
if (kind1 == svn_node_none)
return svn_error_createf
(SVN_ERR_FS_NOT_FOUND, NULL,
_("'%s' was not found in the repository at revision %ld"),
url1, rev1);
if (kind2 == svn_node_none)
return svn_error_createf
(SVN_ERR_FS_NOT_FOUND, NULL,
_("'%s' was not found in the repository at revision %ld"),
url2, rev2);
if ((kind1 == svn_node_file) || (kind2 == svn_node_file))
{
svn_path_split (url1, &anchor1, &target1, pool);
target1 = svn_path_uri_decode (target1, pool);
svn_path_split (url2, &anchor2, &target2, pool);
target2 = svn_path_uri_decode (target2, pool);
if (base_path)
base_path = svn_path_dirname (base_path, pool);
}
/* Destroy the temporary pool, which closes our RA session. */
svn_pool_destroy (temppool);
/* Now, we reopen two RA session to the correct anchor/target
locations for our URLs. */
SVN_ERR (svn_client__open_ra_session (&session1, ra_lib, anchor1,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -