📄 diff.c
字号:
/* First input path */ const char *path1; /* Revision of first input path */ const svn_opt_revision_t *revision1; /* Second input path */ const char *path2; /* Revision of second input path */ const svn_opt_revision_t *revision2; /* Peg revision */ const svn_opt_revision_t *peg_revision; /* Recurse */ svn_boolean_t recurse; /* Ignore acestry */ svn_boolean_t ignore_ancestry; /* Ignore deleted */ svn_boolean_t no_diff_deleted;};/** Helper structure: filled by check_paths() */struct diff_paths{ /* path1 can only be found in the repository? */ svn_boolean_t is_repos1; /* path2 can only be found in the repository? */ svn_boolean_t is_repos2;};/** Check if paths are urls and if the revisions are local, and, for pegged revisions, ensure that at least one revision is non-local. Fills the PATHS structure. */static svn_error_t *check_paths(const struct diff_parameters *params, struct diff_paths *paths){ svn_boolean_t is_local_rev1, is_local_rev2; /* Verify our revision arguments in light of the paths. */ if ((params->revision1->kind == svn_opt_revision_unspecified) || (params->revision2->kind == svn_opt_revision_unspecified)) return svn_error_create(SVN_ERR_CLIENT_BAD_REVISION, NULL, _("Not all required revisions are specified")); /* Revisions can be said to be local or remote. BASE and WORKING, for example, are local. */ is_local_rev1 = ((params->revision1->kind == svn_opt_revision_base) || (params->revision1->kind == svn_opt_revision_working)); is_local_rev2 = ((params->revision2->kind == svn_opt_revision_base) || (params->revision2->kind == svn_opt_revision_working)); if (params->peg_revision->kind != svn_opt_revision_unspecified) { if (is_local_rev1 && is_local_rev2) return svn_error_create(SVN_ERR_CLIENT_BAD_REVISION, NULL, _("At least one revision must be non-local " "for a pegged diff")); paths->is_repos1 = ! is_local_rev1; paths->is_repos2 = ! is_local_rev2; } else { /* Working copy paths with non-local revisions get turned into URLs. We don't do that here, though. We simply record that it needs to be done, which is information that helps us choose our diff helper function. */ paths->is_repos1 = ! is_local_rev1 || svn_path_is_url(params->path1); paths->is_repos2 = ! is_local_rev2 || svn_path_is_url(params->path2); } return SVN_NO_ERROR;}/** Helper structure filled by diff_prepare_repos_repos */struct diff_repos_repos_t{ /* URL created from path1 */ const char *url1; /* URL created from path2 */ const char *url2; /* The BASE_PATH for the diff */ const char *base_path; /* url1 and url2 are the same */ svn_boolean_t same_urls; /* Revision of url1 */ svn_revnum_t rev1; /* Revision of url2 */ svn_revnum_t rev2; /* Anchor based on url1 */ const char *anchor1; /* Anchor based on url2 */ const char *anchor2; /* Target based on url1 */ const char *target1; /* Target based on url2 */ const char *target2; /* RA session pointing at anchor1. */ svn_ra_session_t *ra_session;};/** Helper function: prepare a repos repos diff. Fills DRR * structure. */static svn_error_t *diff_prepare_repos_repos(const struct diff_parameters *params, struct diff_repos_repos_t *drr, svn_client_ctx_t *ctx, apr_pool_t *pool){ svn_ra_session_t *ra_session; svn_node_kind_t kind1, kind2; /* Figure out URL1 and URL2. */ SVN_ERR(convert_to_url(&drr->url1, params->path1, pool)); SVN_ERR(convert_to_url(&drr->url2, params->path2, pool)); drr->same_urls = (strcmp(drr->url1, drr->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). */ drr->base_path = NULL; if (drr->url1 != params->path1) drr->base_path = params->path1; if (drr->url2 != params->path2) drr->base_path = params->path2; SVN_ERR(svn_client__open_ra_session_internal(&ra_session, drr->url2, NULL, NULL, NULL, FALSE, TRUE, ctx, pool)); /* If we are performing a pegged diff, we need to find out what our actual URLs will be. */ if (params->peg_revision->kind != svn_opt_revision_unspecified) { svn_opt_revision_t *start_ignore, *end_ignore; SVN_ERR(svn_client__repos_locations(&drr->url1, &start_ignore, &drr->url2, &end_ignore, ra_session, params->path2, params->peg_revision, params->revision1, params->revision2, ctx, pool)); /* Reparent the session, since drr->url2 might have changed as a result the above call. */ SVN_ERR(svn_ra_reparent(ra_session, drr->url2, pool)); } /* Resolve revision and get path kind for the second target. */ SVN_ERR(svn_client__get_revision_number (&drr->rev2, ra_session, params->revision2, (params->path2 == drr->url2) ? NULL : params->path2, pool)); SVN_ERR(svn_ra_check_path(ra_session, "", drr->rev2, &kind2, pool)); 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"), drr->url2, drr->rev2); /* Do the same for the first target. */ SVN_ERR(svn_ra_reparent(ra_session, drr->url1, pool)); SVN_ERR(svn_client__get_revision_number (&drr->rev1, ra_session, params->revision1, (params->path1 == drr->url1) ? NULL : params->path1, pool)); SVN_ERR(svn_ra_check_path(ra_session, "", drr->rev1, &kind1, pool)); 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"), drr->url1, drr->rev1); /* Choose useful anchors and targets for our two URLs. */ drr->anchor1 = drr->url1; drr->anchor2 = drr->url2; drr->target1 = ""; drr->target2 = ""; if ((kind1 == svn_node_file) || (kind2 == svn_node_file)) { svn_path_split(drr->url1, &drr->anchor1, &drr->target1, pool); drr->target1 = svn_path_uri_decode(drr->target1, pool); svn_path_split(drr->url2, &drr->anchor2, &drr->target2, pool); drr->target2 = svn_path_uri_decode(drr->target2, pool); if (drr->base_path) drr->base_path = svn_path_dirname(drr->base_path, pool); SVN_ERR(svn_ra_reparent(ra_session, drr->anchor1, pool)); } drr->ra_session = ra_session; return SVN_NO_ERROR;}/* URL1/PATH1, URL2/PATH2, and TARGET_WCPATH all better be directories. For the single file case, the caller does the merging manually. PATH1 and PATH2 can be NULL. If PEG_REVISION is specified, then INITIAL_PATH2 is the path to peg off of, unless it is NULL, in which case INITIAL_URL2 is the peg path. The actual two paths to compare are then found by tracing copy history from this peg path to INITIAL_REVISION2 and INITIAL_REVISION1.*/static svn_error_t *do_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, svn_boolean_t recurse, svn_boolean_t ignore_ancestry, svn_boolean_t dry_run, const svn_wc_diff_callbacks2_t *callbacks, void *callback_baton, svn_client_ctx_t *ctx, apr_pool_t *pool){ svn_revnum_t start_revnum, end_revnum; svn_ra_session_t *ra_session, *ra_session2; const svn_ra_reporter2_t *reporter; void *report_baton; const svn_delta_editor_t *diff_editor; void *diff_edit_baton; struct merge_cmd_baton *merge_b = callback_baton; const char *URL1, *URL2, *path1, *path2; svn_opt_revision_t *revision1, *revision2; /* Sanity check -- ensure that we have valid revisions to look at. */ if ((initial_revision1->kind == svn_opt_revision_unspecified) || (initial_revision2->kind == svn_opt_revision_unspecified)) { return svn_error_create (SVN_ERR_CLIENT_BAD_REVISION, NULL, _("Not all required revisions are specified")); } /* 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_ERR(svn_client__repos_locations(&URL1, &revision1, &URL2, &revision2, NULL, initial_path2 ? initial_path2 : initial_URL2, peg_revision, initial_revision1, initial_revision2, ctx, pool)); merge_b->url = URL2; path1 = NULL; path2 = NULL; merge_b->path = 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; } /* Establish first RA session to URL1. */ SVN_ERR(svn_client__open_ra_session_internal(&ra_session, URL1, NULL, NULL, NULL, FALSE, TRUE, ctx, pool)); /* Resolve the revision numbers. */ SVN_ERR(svn_client__get_revision_number (&start_revnum, ra_session, revision1, path1, pool)); SVN_ERR(svn_client__get_revision_number (&end_revnum, ra_session, revision2, path2, pool)); /* Open a second session used to request individual file contents. Although a session can be used for multiple requests, it appears that they must be sequential. Since the first request, for the diff, is still being processed the first session cannot be reused. This applies to ra_dav, ra_local does not appears to have this limitation. */ SVN_ERR(svn_client__open_ra_session_internal(&ra_session2, URL1, NULL, NULL, NULL, FALSE, TRUE, ctx, pool)); SVN_ERR(svn_client__get_diff_editor(target_wcpath, adm_access, callbacks, callback_baton, recurse, dry_run, ra_session2, start_revnum, ctx->notify_func2, ctx->notify_baton2, ctx->cancel_func, ctx->cancel_baton, &diff_editor, &diff_edit_baton, pool)); SVN_ERR(svn_ra_do_diff2(ra_session, &reporter, &report_baton, end_revnum, "", recurse, ignore_ancestry, TRUE, /* text_deltas */ URL2, diff_editor, diff_edit_baton, pool)); SVN_ERR(reporter->set_path(report_baton, "", start_revnum, FALSE, NULL, pool)); SVN_ERR(reporter->finish_report(report_baton, pool)); /* Sleep to ensure timestamp integrity. */ svn_sleep_for_timestamps(); return SVN_NO_ERROR;}/* Get REVISION of the file at URL. SOURCE is a path that refers to that file's entry in the working copy, or NULL if we don't have one. Return in *FILENAME the name of a file containing the file contents, in *PROPS a hash containing the properties and in *REV the revision. All allocation occurs in POOL. */static svn_error_t *single_file_merge_get_file(const char **filename, apr_hash_t **props, svn_revnum_t *rev, const char *url, const char *path, const svn_opt_revision_t *revision, struct merge_cmd_baton *merge_b, apr_pool_t *pool){ svn_ra_session_t *ra_session; apr_file_t *fp; svn_stream_t *stream; SVN_ERR(svn_client__open_ra_session_internal(&ra_session, url, NULL,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -