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 2015/11/16 16:19:21 UTC
svn commit: r1714604 - in /subversion/branches/move-tracking-2:
subversion/include/private/svn_client_private.h
subversion/libsvn_client/update.c tools/dev/svnmover/scanlog.c
tools/dev/svnmover/svnmover.h
Author: julianfoad
Date: Mon Nov 16 15:19:21 2015
New Revision: 1714604
URL: http://svn.apache.org/viewvc?rev=1714604&view=rev
Log:
On the 'move-tracking-2' branch: Move log-scanning code out of libsvn_client
and into svnmover, to localize the experimental source code as much as
possible.
* subversion/include/private/svn_client_private.h
(svn_repos_move_info_t,
svn_repos_move_info_create,
svn_client__format_move_chain_for_display,
svn_client__get_repos_moves): Move to svnmover.h.
* subversion/libsvn_client/update.c
(svn_repos_move_info_create,
svn_client__format_move_chain_for_display,
scan_moves_log_receiver_baton,
copy_info,
check_ancestry,
scan_moves_log_receiver,
svn_client__get_repos_moves): Move to scanlog.c.
(update_internal): Tweak commented-out code such that it could be compiled.
* tools/dev/svnmover/scanlog.c
New file, with contents moved from update.c.
* tools/dev/svnmover/svnmover.h
(svn_repos_move_info_t,
svn_repos_move_info_create,
svn_client__format_move_chain_for_display,
svn_client__get_repos_moves): Move from svn_client_private.h..
Added:
subversion/branches/move-tracking-2/tools/dev/svnmover/scanlog.c
- copied, changed from r1714534, subversion/branches/move-tracking-2/subversion/libsvn_client/update.c
Modified:
subversion/branches/move-tracking-2/subversion/include/private/svn_client_private.h
subversion/branches/move-tracking-2/subversion/libsvn_client/update.c
subversion/branches/move-tracking-2/tools/dev/svnmover/svnmover.h
Modified: subversion/branches/move-tracking-2/subversion/include/private/svn_client_private.h
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/include/private/svn_client_private.h?rev=1714604&r1=1714603&r2=1714604&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/include/private/svn_client_private.h (original)
+++ subversion/branches/move-tracking-2/subversion/include/private/svn_client_private.h Mon Nov 16 15:19:21 2015
@@ -341,63 +341,6 @@ svn_client__mergeinfo_log(svn_boolean_t
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
-/** Describes a server-side move (really a copy+delete within the same
- * revision) which has been identified by scanning the revision log.
- */
-typedef struct svn_repos_move_info_t {
- /* The repository relpath the node was moved from. */
- const char *moved_from_repos_relpath;
-
- /* The repository relpath the node was moved to. */
- const char *moved_to_repos_relpath;
-
- /* The revision in which the move happened. */
- svn_revnum_t revision;
-
- /* The copyfrom revision of the moved-to path. */
- svn_revnum_t copyfrom_rev;
-
- /* Pointers to previous or subsequent moves of the same node
- * within interesting history. */
- struct svn_repos_move_info_t *prev;
- struct svn_repos_move_info_t *next;
-
- /* @note Fields may be added to the end of this structure in future
- * versions. Therefore, to preserve binary compatibility, users
- * should not directly allocate structures of this type but should use
- * svn_wc_create_repos_move_info(). */
-} svn_repos_move_info_t;
-
-/** Create a svn_wc_repos_move_info_t structure.
- * @see svn_wc_repos_move_info_t
- */
-svn_repos_move_info_t *
-svn_repos_move_info_create(const char *moved_from_repos_relpath,
- const char *moved_to_repos_relpath,
- svn_revnum_t revision,
- svn_revnum_t copyfrom_rev,
- svn_repos_move_info_t *prev,
- svn_repos_move_info_t *next,
- apr_pool_t *result_pool);
-
-/* ...
- */
-const char *
-svn_client__format_move_chain_for_display(svn_repos_move_info_t *first_move,
- const char *indent,
- apr_pool_t *result_pool);
-/* ...
- */
-svn_error_t *
-svn_client__get_repos_moves(apr_hash_t **moves,
- const char *anchor_abspath,
- svn_ra_session_t *ra_session,
- svn_revnum_t start,
- svn_revnum_t end,
- svn_client_ctx_t *ctx,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool);
-
#ifdef __cplusplus
}
#endif /* __cplusplus */
Modified: subversion/branches/move-tracking-2/subversion/libsvn_client/update.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_client/update.c?rev=1714604&r1=1714603&r2=1714604&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_client/update.c (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_client/update.c Mon Nov 16 15:19:21 2015
@@ -183,477 +183,6 @@ record_conflict(svn_wc_conflict_result_t
return SVN_NO_ERROR;
}
-
-/* From moves-scan-log branch */
-
-svn_repos_move_info_t *
-svn_repos_move_info_create(const char *moved_from_repos_relpath,
- const char *moved_to_repos_relpath,
- svn_revnum_t revision,
- svn_revnum_t copyfrom_rev,
- svn_repos_move_info_t *prev,
- svn_repos_move_info_t *next,
- apr_pool_t *result_pool)
-{
- svn_repos_move_info_t *move = apr_palloc(result_pool, sizeof(*move));
-
- move->moved_from_repos_relpath = moved_from_repos_relpath;
- move->moved_to_repos_relpath = moved_to_repos_relpath;
- move->revision = revision;
- move->copyfrom_rev = copyfrom_rev;
- move->prev = prev;
- move->next = next;
-
- return move;
-}
-
-const char *
-svn_client__format_move_chain_for_display(svn_repos_move_info_t *first_move,
- const char *indent,
- apr_pool_t *result_pool)
-{
- const char *s;
- svn_repos_move_info_t *last_move;
-
- last_move = first_move;
- while (last_move->next)
- last_move = last_move->next;
-
- if (last_move != first_move)
- {
- svn_repos_move_info_t *this_move;
-
- s = apr_psprintf(result_pool,
- _("Combined move:\n%s %s@%ld -> %s\n"
- "%sIndividual moves:\n"),
- indent, first_move->moved_from_repos_relpath,
- first_move->copyfrom_rev,
- last_move->moved_to_repos_relpath, indent);
-
- this_move = first_move;
- do
- {
- s = apr_pstrcat(result_pool, s,
- apr_psprintf(
- result_pool, _("%s [r%ld] %s@%ld -> %s\n"),
- indent,
- this_move->revision,
- this_move->moved_from_repos_relpath,
- this_move->copyfrom_rev,
- this_move->moved_to_repos_relpath),
- (char *)NULL);
- this_move = this_move->next;
- }
- while (this_move);
- }
- else
- s = apr_psprintf(result_pool, _(" [r%ld] %s@%ld -> %s\n"),
- first_move->revision,
- first_move->moved_from_repos_relpath,
- first_move->copyfrom_rev,
- first_move->moved_to_repos_relpath);
-
- return s;
-}
-
-struct scan_moves_log_receiver_baton {
- /*const char *anchor_abspath;*/
- svn_client_ctx_t *ctx;
- svn_revnum_t start;
- svn_revnum_t end;
- svn_ra_session_t *ra_session;
-
- /* The moved nodes hash to be populated.
- * Maps a revision number to an array of svn_repos_move_info_t
- * objects describing moves which happened in the revision.
- *
- * Given a sequence of moves which happened in given revisions, such as:
- * rA: mv x->z
- * rA: mv a->b
- * rB: mv b->c
- * rC: mv c->d
- * we map each revision number to all moves which happened in the
- * revision, which looks as follows:
- * rA : [(rA, x->z), (rA, a->b)]
- * rB : [(rB, b->c)]
- * rC : [(rC, c->d)]
- * This allows an update to find relevant moves based on the base
- * revision of a node (during updates the base revision of each node
- * in the working copy is arbitrary so we might not know the nodes 'a'
- * and 'x' under these names).
- * Additionally, all moves pertaining to the same node are chained into a
- * doubly-linked list via 'next' and 'prev' pointers (see definition of
- * svn_repos_move_info_t).
- * This way, an update can look up all moves relevant to a node, forwards
- * or backwards in history, once it has located a relevant move in the chain.
- * This can be visualized as follows:
- * rA : [(rA, x->z, prev=>NULL, next=>NULL),
- * (rA, a->b, prev=>NULL, next=>(rB, b->c))]
- * rB : [(rB, b->c), prev=>(rA, a->b), next=>(rC, c->d)]
- * rC : [(rC, c->d), prev=>(rB, c->d), next=>NULL]
- */
- apr_hash_t *moves;
-
- /* Temporary map of move-target paths to repos_move_info_t.
- * Used to link multiple moves of the same node across revisions. */
- apr_hash_t *moves_by_target_path;
-} scan_moves_log_receiver_baton;
-
-struct copy_info {
- const char *copyto_path;
- const char *copyfrom_path;
- svn_revnum_t copyfrom_rev;
-} copy_info;
-
-
-/* Set *RELATED to true if the deleted node at repository relpath
- * DELETED_PATH@DELETED_REV is ancestrally related to the node at
- * repository relpath COPYFROM_PATH@COPYFROM_REV, else set it to false.
- *
- * ### JAF: In practice this attempts to trace back, starting from
- * DELETED_PATH@(DELETED_REV-1). What if that does not exist?
- */
-static svn_error_t *
-check_ancestry(svn_boolean_t *related,
- const char *session_url,
- const char *repos_root_url,
- const char *deleted_path,
- svn_revnum_t deleted_rev,
- const char *copyfrom_path,
- svn_revnum_t copyfrom_rev,
- svn_client_ctx_t *ctx,
- apr_pool_t *scratch_pool)
-{
- apr_hash_t *locations;
- const char *old_url;
- const char *old_location;
- const char *relpath;
- svn_ra_session_t *ra_session2;
- apr_array_header_t *location_revisions;
-
- *related = FALSE;
-
- location_revisions = apr_array_make(scratch_pool, 1, sizeof(svn_revnum_t));
- APR_ARRAY_PUSH(location_revisions, svn_revnum_t) = copyfrom_rev;
- old_url = svn_uri_canonicalize(apr_pstrcat(scratch_pool,
- repos_root_url, "/",
- deleted_path, NULL),
- scratch_pool);
- relpath = svn_uri_skip_ancestor(session_url, old_url, scratch_pool);
- SVN_ERR(svn_client__open_ra_session_internal(&ra_session2, NULL,
- session_url, NULL,
- NULL, FALSE, FALSE,
- ctx, scratch_pool, scratch_pool));
- if (relpath == NULL)
- {
- svn_error_t *err;
-
- /* The deleted path is outside of the baton's RA session URL.
- * Try to open the new RA session to the repository root. */
- SVN_ERR(svn_ra_reparent(ra_session2, repos_root_url, scratch_pool));
- relpath = svn_uri_skip_ancestor(repos_root_url, old_url, scratch_pool);
- if (relpath == NULL)
- return SVN_NO_ERROR;
- err = svn_ra_get_locations(ra_session2, &locations, relpath,
- deleted_rev - 1, location_revisions,
- scratch_pool);
- if (err)
- {
- if (err->apr_err == SVN_ERR_RA_NOT_AUTHORIZED ||
- err->apr_err == SVN_ERR_RA_DAV_FORBIDDEN)
- {
- svn_error_clear(err);
- return SVN_NO_ERROR;
- }
- else
- return svn_error_trace(err);
- }
- }
- else
- SVN_ERR(svn_ra_get_locations(ra_session2, &locations, relpath,
- deleted_rev - 1, location_revisions,
- scratch_pool));
-
- old_location = apr_hash_get(locations, ©from_rev, sizeof(svn_revnum_t));
- *related = (old_location &&
- strcmp(old_location[0] == '/' ? old_location + 1 : old_location,
- copyfrom_path) == 0);
-
- return SVN_NO_ERROR;
-}
-
-static svn_error_t *
-scan_moves_log_receiver(void *baton,
- svn_log_entry_t *log_entry,
- apr_pool_t *scratch_pool)
-{
- apr_hash_index_t *hi;
- apr_hash_t *copies;
- apr_array_header_t *deleted_paths;
- struct scan_moves_log_receiver_baton *b = baton;
- apr_pool_t *result_pool = apr_hash_pool_get(b->moves);
- apr_pool_t *iterpool;
- int i;
- const char *session_url;
- const char *repos_root_url;
- apr_array_header_t *moves;
-
- if (b->ctx->notify_func2)
- {
-#if 0
- svn_wc_notify_t *notify;
- notify = svn_wc_create_notify(b->anchor_abspath,
- svn_wc_notify_moves_scan_log_in_progress,
- scratch_pool);
- notify->moves_scan_log_start_rev = b->start;
- notify->moves_scan_log_end_rev = b->end;
- notify->moves_scan_log_current_rev = log_entry->revision;
- b->ctx->notify_func2(b->ctx->notify_baton2, notify, scratch_pool);
-#endif
- }
-
- if (log_entry->changed_paths2 == NULL)
- return SVN_NO_ERROR;
-
- copies = apr_hash_make(scratch_pool);
- deleted_paths = apr_array_make(scratch_pool, 0, sizeof(const char *));
-
- /* Scan for copied and deleted nodes in this revision. */
- for (hi = apr_hash_first(scratch_pool, log_entry->changed_paths2);
- hi; hi = apr_hash_next(hi))
- {
- const char *path = apr_hash_this_key(hi);
- svn_log_changed_path2_t *data = apr_hash_this_val(hi);
-
- if ((data->action == 'A' || data->action == 'R') && data->copyfrom_path)
- {
- struct copy_info *copy;
- apr_array_header_t *copies_with_same_source_path;
-
- SVN_ERR_ASSERT(path[0] == '/');
-
- if (data->copyfrom_path[0] == '/')
- data->copyfrom_path++;
-
- copy = apr_palloc(scratch_pool, sizeof(*copy));
- copy->copyto_path = path + 1; /* Strip leading '/' */
- copy->copyfrom_path = data->copyfrom_path;
- copy->copyfrom_rev = data->copyfrom_rev;
- copies_with_same_source_path = apr_hash_get(copies,
- data->copyfrom_path,
- APR_HASH_KEY_STRING);
- if (copies_with_same_source_path == NULL)
- {
- copies_with_same_source_path = apr_array_make(
- result_pool, 1,
- sizeof(struct copy_info *));
- apr_hash_set(copies, copy->copyfrom_path, APR_HASH_KEY_STRING,
- copies_with_same_source_path);
- }
- APR_ARRAY_PUSH(copies_with_same_source_path,
- struct copy_info *) = copy;
- }
-
- if (data->action == 'D' || data->action == 'R')
- {
- const char *parent_path;
-
- /* ### Is this true? What does the API guarantee? Is it
- ### true that copyfrom_path is a relpath? */
- SVN_ERR_ASSERT(path[0] == '/');
-
- /* When a delete is within a copy the deleted path in the
- changed_paths2 hash is the copied path, but for the purposes
- of move detection we want the pre-copy path.
-
- ### Not sure if this is the correct thing to do. Yes, it
- ### allows us to detect moves in copies/moves but will it
- ### lead to false positives? Does it matter that the
- ### adjusted path may not have been committed? Does it
- ### matter that the adjusted path may be the same as
- ### another committed path? */
- parent_path = svn_dirent_dirname(path, scratch_pool);
- while(strcmp(parent_path, "/"))
- {
- svn_log_changed_path2_t *data2
- = apr_hash_get(log_entry->changed_paths2, parent_path,
- APR_HASH_KEY_STRING);
-
- if (data2 && data2->action == 'A')
- {
- const char *relpath = svn_dirent_skip_ancestor(parent_path,
- path);
- path = svn_dirent_join_many(scratch_pool, "/",
- data2->copyfrom_path, relpath,
- NULL);
- break;
- }
- else
- parent_path = svn_dirent_dirname(parent_path, scratch_pool);
- }
- APR_ARRAY_PUSH(deleted_paths, const char *) = path + 1;
- }
- }
-
- /* If a node was deleted at one location and copied from the deleted
- * location to a new location within the same revision, put the node
- * on the moved-nodes list. */
- SVN_ERR(svn_ra_get_session_url(b->ra_session, &session_url, scratch_pool));
- SVN_ERR(svn_ra_get_repos_root2(b->ra_session, &repos_root_url, scratch_pool));
- iterpool = svn_pool_create(scratch_pool);
- for (i = 0; i < deleted_paths->nelts; i++)
- {
- const char *deleted_path;
- apr_array_header_t *copies_with_same_source_path;
- svn_repos_move_info_t *new_move;
- svn_repos_move_info_t *prior_move;
- svn_boolean_t related;
- int j;
-
- deleted_path = APR_ARRAY_IDX(deleted_paths, i, const char *);
- copies_with_same_source_path = apr_hash_get(copies, deleted_path,
- APR_HASH_KEY_STRING);
- if (copies_with_same_source_path == NULL)
- continue;
-
- svn_pool_clear(iterpool);
-
- for (j = 0; j < copies_with_same_source_path->nelts; j++)
- {
- struct copy_info *copy;
-
- copy = APR_ARRAY_IDX(copies_with_same_source_path, j,
- struct copy_info *);
-
- /* We found a deleted node which matches the copyfrom path of
- * a copied node. Verify that the deleted node is an ancestor
- * of the copied node. Tracing back history of the deleted node
- * from revision log_entry->revision-1 to the copyfrom-revision
- * we must end up at the copyfrom-path. */
- SVN_ERR(check_ancestry(&related, session_url, repos_root_url,
- deleted_path, log_entry->revision,
- copy->copyfrom_path,
- copy->copyfrom_rev,
- b->ctx, iterpool));
- if (!related)
- continue;
-
- /* ### TODO:
- * If the node was not copied from the most recent last-changed
- * revision of the deleted node, this is not a move but a
- * "copy from the past + delete". */
-
- /* Remember details of this move. */
- new_move = svn_repos_move_info_create(
- apr_pstrdup(result_pool, deleted_path),
- apr_pstrdup(result_pool, copy->copyto_path),
- log_entry->revision, copy->copyfrom_rev,
- NULL, NULL, result_pool);
-
- /* Link together multiple moves of the same node. */
- prior_move = apr_hash_get(b->moves_by_target_path,
- new_move->moved_from_repos_relpath,
- APR_HASH_KEY_STRING);
- if (prior_move)
- {
- /* Tracing back history of the delete-half of the new move
- * to the copyfrom-revision of the prior move we must end up
- * at the delete-half of the prior move. */
- SVN_ERR(check_ancestry(&related, session_url, repos_root_url,
- new_move->moved_from_repos_relpath,
- new_move->revision,
- prior_move->moved_from_repos_relpath,
- prior_move->copyfrom_rev,
- b->ctx, iterpool));
- if (related)
- {
- prior_move->next = new_move;
- new_move->prev = prior_move;
- }
- }
- apr_hash_set(b->moves_by_target_path,
- new_move->moved_to_repos_relpath,
- APR_HASH_KEY_STRING, new_move);
-
- /* Add this move to the list of moves in this revision. */
- moves = apr_hash_get(b->moves, &new_move->revision,
- sizeof(svn_revnum_t));
- if (moves == NULL)
- {
- moves = apr_array_make(result_pool, 1,
- sizeof(svn_repos_move_info_t *));
- APR_ARRAY_PUSH(moves, svn_repos_move_info_t *) = new_move;
- apr_hash_set(b->moves, &new_move->revision, sizeof(svn_revnum_t),
- moves);
- }
- else
- APR_ARRAY_PUSH(moves, svn_repos_move_info_t *) = new_move;
- }
- }
- svn_pool_destroy(iterpool);
-
- return SVN_NO_ERROR;
-}
-
-svn_error_t *
-svn_client__get_repos_moves(apr_hash_t **moves,
- const char *anchor_abspath,
- svn_ra_session_t *ra_session,
- svn_revnum_t start,
- svn_revnum_t end,
- svn_client_ctx_t *ctx,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
-{
- struct scan_moves_log_receiver_baton lrb;
-
- /*lrb.anchor_abspath = anchor_abspath;*/
- lrb.ctx = ctx;
- lrb.moves = apr_hash_make(result_pool);
- lrb.start = start;
- lrb.end = end;
- lrb.ra_session = ra_session;
- lrb.moves_by_target_path = apr_hash_make(scratch_pool);
-
- if (ctx->notify_func2)
- {
-#if 0
- svn_wc_notify_t *notify;
- notify = svn_wc_create_notify(b->anchor_abspath,
- svn_wc_notify_moves_scan_log_start,
- scratch_pool);
- notify->moves_scan_log_start_rev = start;
- notify->moves_scan_log_end_rev = end;
- notify->moves_scan_log_current_rev = start;
- ctx->notify_func2(b->ctx->notify_baton2, notify, scratch_pool);
-#endif
- }
-
- SVN_ERR(svn_ra_get_log2(ra_session, NULL, start, end, 0, TRUE, FALSE,
- FALSE, apr_array_make(scratch_pool, 0,
- sizeof(const char *)),
- scan_moves_log_receiver, &lrb, scratch_pool));
-
- if (ctx->notify_func2)
- {
-#if 0
- svn_wc_notify_t *notify;
- notify = svn_wc_create_notify(b->anchor_abspath,
- svn_wc_notify_moves_scan_log_done,
- scratch_pool);
- notify->moves_scan_log_start_rev = start;
- notify->moves_scan_log_end_rev = end;
- notify->moves_scan_log_current_rev = end;
- b->ctx->notify_func2(b->ctx->notify_baton2, notify, scratch_pool);
-#endif
- }
-
- if (moves)
- *moves = lrb.moves;
-
- return SVN_NO_ERROR;
-}
-
/* This is a helper for svn_client__update_internal(), which see for
an explanation of most of these parameters. Some stuff that's
unique is as follows:
@@ -954,10 +483,10 @@ update_internal(svn_revnum_t *result_rev
NULL, NULL,
ctx->cancel_func, ctx->cancel_baton,
ctx->notify_func2, ctx->notify_baton2,
- pool, pool));
- SVN_ERR(svn_editor3__get_debug_editor(&update_editor->editor,
+ scratch_pool, scratch_pool));
+ /*SVN_ERR(svn_editor3__get_debug_editor(&update_editor->editor,
update_editor->editor,
- pool));
+ scratch_pool));*/
/* Tell RA to do an update of URL+TARGET to REVISION; if we pass an
invalid revnum, that means RA will use the latest revision. */
@@ -968,7 +497,7 @@ update_internal(svn_revnum_t *result_rev
: svn_depth_unknown),
FALSE /* send_copyfrom_args */,
FALSE /* ignore_ancestry */,
- update_editor, pool, pool));
+ update_editor, scratch_pool, scratch_pool));
#else
/* Fetch the update editor. If REVISION is invalid, that's okay;
the RA driver will call editor->set_target_revision later on. */
Copied: subversion/branches/move-tracking-2/tools/dev/svnmover/scanlog.c (from r1714534, subversion/branches/move-tracking-2/subversion/libsvn_client/update.c)
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/tools/dev/svnmover/scanlog.c?p2=subversion/branches/move-tracking-2/tools/dev/svnmover/scanlog.c&p1=subversion/branches/move-tracking-2/subversion/libsvn_client/update.c&r1=1714534&r2=1714604&rev=1714604&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_client/update.c (original)
+++ subversion/branches/move-tracking-2/tools/dev/svnmover/scanlog.c Mon Nov 16 15:19:21 2015
@@ -1,5 +1,5 @@
/*
- * update.c: wrappers around wc update functionality
+ * scanlog.c: scanning the log for moves
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
@@ -37,151 +37,14 @@
#include "svn_path.h"
#include "svn_pools.h"
#include "svn_io.h"
-#include "client.h"
-#include "svn_private_config.h"
+#include "private/svn_client_private.h"
#include "private/svn_wc_private.h"
#include "private/svn_ra_private.h"
-/* Implements svn_wc_dirents_func_t for update and switch handling. Assumes
- a struct svn_client__dirent_fetcher_baton_t * baton */
-svn_error_t *
-svn_client__dirent_fetcher(void *baton,
- apr_hash_t **dirents,
- const char *repos_root_url,
- const char *repos_relpath,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
-{
- struct svn_client__dirent_fetcher_baton_t *dfb = baton;
- const char *old_url = NULL;
- const char *session_relpath;
- svn_node_kind_t kind;
- const char *url;
-
- url = svn_path_url_add_component2(repos_root_url, repos_relpath,
- scratch_pool);
-
- if (!svn_uri__is_ancestor(dfb->anchor_url, url))
- {
- SVN_ERR(svn_client__ensure_ra_session_url(&old_url, dfb->ra_session,
- url, scratch_pool));
- session_relpath = "";
- }
- else
- SVN_ERR(svn_ra_get_path_relative_to_session(dfb->ra_session,
- &session_relpath, url,
- scratch_pool));
-
- /* Is session_relpath still a directory? */
- SVN_ERR(svn_ra_check_path(dfb->ra_session, session_relpath,
- dfb->target_revision, &kind, scratch_pool));
-
- if (kind == svn_node_dir)
- SVN_ERR(svn_ra_get_dir2(dfb->ra_session, dirents, NULL, NULL,
- session_relpath, dfb->target_revision,
- SVN_DIRENT_KIND, result_pool));
- else
- *dirents = NULL;
-
- if (old_url)
- SVN_ERR(svn_ra_reparent(dfb->ra_session, old_url, scratch_pool));
-
- return SVN_NO_ERROR;
-}
-
-
-/*** Code. ***/
-
-/* Set *CLEAN_CHECKOUT to FALSE only if LOCAL_ABSPATH is a non-empty
- folder. ANCHOR_ABSPATH is the w/c root and LOCAL_ABSPATH will still
- be considered empty, if it is equal to ANCHOR_ABSPATH and only
- contains the admin sub-folder.
- If the w/c folder already exists but cannot be openend, we return
- "unclean" - just in case. Most likely, the caller will have to bail
- out later due to the same error we got here.
- */
-static svn_error_t *
-is_empty_wc(svn_boolean_t *clean_checkout,
- const char *local_abspath,
- const char *anchor_abspath,
- apr_pool_t *pool)
-{
- apr_dir_t *dir;
- apr_finfo_t finfo;
- svn_error_t *err;
-
- /* "clean" until found dirty */
- *clean_checkout = TRUE;
-
- /* open directory. If it does not exist, yet, a clean one will
- be created by the caller. */
- err = svn_io_dir_open(&dir, local_abspath, pool);
- if (err)
- {
- if (! APR_STATUS_IS_ENOENT(err->apr_err))
- *clean_checkout = FALSE;
+#include "svnmover.h"
- svn_error_clear(err);
- return SVN_NO_ERROR;
- }
-
- for (err = svn_io_dir_read(&finfo, APR_FINFO_NAME, dir, pool);
- err == SVN_NO_ERROR;
- err = svn_io_dir_read(&finfo, APR_FINFO_NAME, dir, pool))
- {
- /* Ignore entries for this dir and its parent, robustly.
- (APR promises that they'll come first, so technically
- this guard could be moved outside the loop. But Ryan Bloom
- says he doesn't believe it, and I believe him. */
- if (! (finfo.name[0] == '.'
- && (finfo.name[1] == '\0'
- || (finfo.name[1] == '.' && finfo.name[2] == '\0'))))
- {
- if ( ! svn_wc_is_adm_dir(finfo.name, pool)
- || strcmp(local_abspath, anchor_abspath) != 0)
- {
- *clean_checkout = FALSE;
- break;
- }
- }
- }
-
- if (err)
- {
- if (! APR_STATUS_IS_ENOENT(err->apr_err))
- {
- /* There was some issue reading the folder content.
- * We better disable optimizations in that case. */
- *clean_checkout = FALSE;
- }
-
- svn_error_clear(err);
- }
-
- return svn_io_dir_close(dir);
-}
-
-/* A conflict callback that simply records the conflicted path in BATON.
-
- Implements svn_wc_conflict_resolver_func2_t.
-*/
-static svn_error_t *
-record_conflict(svn_wc_conflict_result_t **result,
- const svn_wc_conflict_description2_t *description,
- void *baton,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
-{
- apr_hash_t *conflicted_paths = baton;
-
- svn_hash_sets(conflicted_paths,
- apr_pstrdup(apr_hash_pool_get(conflicted_paths),
- description->local_abspath), "");
- *result = svn_wc_create_conflict_result(svn_wc_conflict_choose_postpone,
- NULL, result_pool);
- return SVN_NO_ERROR;
-}
+#include "svn_private_config.h"
/* From moves-scan-log branch */
@@ -340,10 +203,8 @@ check_ancestry(svn_boolean_t *related,
deleted_path, NULL),
scratch_pool);
relpath = svn_uri_skip_ancestor(session_url, old_url, scratch_pool);
- SVN_ERR(svn_client__open_ra_session_internal(&ra_session2, NULL,
- session_url, NULL,
- NULL, FALSE, FALSE,
- ctx, scratch_pool, scratch_pool));
+ SVN_ERR(svn_client_open_ra_session2(&ra_session2, session_url, NULL,
+ ctx, scratch_pool, scratch_pool));
if (relpath == NULL)
{
svn_error_t *err;
@@ -654,641 +515,3 @@ svn_client__get_repos_moves(apr_hash_t *
return SVN_NO_ERROR;
}
-/* This is a helper for svn_client__update_internal(), which see for
- an explanation of most of these parameters. Some stuff that's
- unique is as follows:
-
- ANCHOR_ABSPATH is the local absolute path of the update anchor.
- This is typically either the same as LOCAL_ABSPATH, or the
- immediate parent of LOCAL_ABSPATH.
-
- If NOTIFY_SUMMARY is set (and there's a notification handler in
- CTX), transmit the final update summary upon successful
- completion of the update.
-
- Add the paths of any conflict victims to CONFLICTED_PATHS, if that
- is not null.
-
- Use RA_SESSION_P to run the update if it is not NULL. If it is then
- open a new ra session and place it in RA_SESSION_P. This allows
- repeated calls to update_internal to reuse the same session.
-*/
-static svn_error_t *
-update_internal(svn_revnum_t *result_rev,
- svn_boolean_t *timestamp_sleep,
- apr_hash_t *conflicted_paths,
- svn_ra_session_t **ra_session_p,
- const char *local_abspath,
- const char *anchor_abspath,
- const svn_opt_revision_t *revision,
- svn_depth_t depth,
- svn_boolean_t depth_is_sticky,
- svn_boolean_t ignore_externals,
- svn_boolean_t allow_unver_obstructions,
- svn_boolean_t adds_as_modification,
- svn_boolean_t notify_summary,
- svn_client_ctx_t *ctx,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
-{
-#if 0
- svn_branch__compat_update_editor3_t *update_editor;
-#else
- const svn_delta_editor_t *update_editor;
- void *update_edit_baton;
-#endif
- const svn_ra_reporter3_t *reporter;
- void *report_baton;
- const char *corrected_url;
- const char *target;
- const char *repos_root_url;
- const char *repos_relpath;
- const char *repos_uuid;
- const char *anchor_url;
- svn_revnum_t revnum;
- svn_boolean_t use_commit_times;
- svn_boolean_t clean_checkout = FALSE;
- const char *diff3_cmd;
- apr_hash_t *wcroot_iprops;
- svn_opt_revision_t opt_rev;
- svn_ra_session_t *ra_session = *ra_session_p;
- const char *preserved_exts_str;
- apr_array_header_t *preserved_exts;
- struct svn_client__dirent_fetcher_baton_t dfb;
- svn_boolean_t server_supports_depth;
- svn_boolean_t cropping_target;
- svn_boolean_t target_conflicted = FALSE;
- svn_config_t *cfg = ctx->config
- ? svn_hash_gets(ctx->config, SVN_CONFIG_CATEGORY_CONFIG)
- : NULL;
-
- if (result_rev)
- *result_rev = SVN_INVALID_REVNUM;
-
- /* An unknown depth can't be sticky. */
- if (depth == svn_depth_unknown)
- depth_is_sticky = FALSE;
-
- if (strcmp(local_abspath, anchor_abspath))
- target = svn_dirent_basename(local_abspath, scratch_pool);
- else
- target = "";
-
- /* Check if our anchor exists in BASE. If it doesn't we can't update. */
- SVN_ERR(svn_wc__node_get_base(NULL, NULL, &repos_relpath, &repos_root_url,
- &repos_uuid, NULL,
- ctx->wc_ctx, anchor_abspath,
- TRUE /* ignore_enoent */,
- scratch_pool, scratch_pool));
-
- /* It does not make sense to update conflict victims. */
- if (repos_relpath)
- {
- svn_error_t *err;
- svn_boolean_t text_conflicted, prop_conflicted;
-
- anchor_url = svn_path_url_add_component2(repos_root_url, repos_relpath,
- scratch_pool);
-
- err = svn_wc_conflicted_p3(&text_conflicted, &prop_conflicted,
- NULL,
- ctx->wc_ctx, local_abspath, scratch_pool);
-
- if (err && err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND)
- return svn_error_trace(err);
- svn_error_clear(err);
-
- /* tree-conflicts are handled by the update editor */
- if (!err && (text_conflicted || prop_conflicted))
- target_conflicted = TRUE;
- }
- else
- anchor_url = NULL;
-
- if (! anchor_url || target_conflicted)
- {
- if (ctx->notify_func2)
- {
- svn_wc_notify_t *nt;
-
- nt = svn_wc_create_notify(local_abspath,
- target_conflicted
- ? svn_wc_notify_skip_conflicted
- : svn_wc_notify_update_skip_working_only,
- scratch_pool);
-
- ctx->notify_func2(ctx->notify_baton2, nt, scratch_pool);
- }
- return SVN_NO_ERROR;
- }
-
- /* We may need to crop the tree if the depth is sticky */
- cropping_target = (depth_is_sticky && depth < svn_depth_infinity);
- if (cropping_target)
- {
- svn_node_kind_t target_kind;
-
- if (depth == svn_depth_exclude)
- {
- SVN_ERR(svn_wc_exclude(ctx->wc_ctx,
- local_abspath,
- ctx->cancel_func, ctx->cancel_baton,
- ctx->notify_func2, ctx->notify_baton2,
- scratch_pool));
-
- /* Target excluded, we are done now */
- return SVN_NO_ERROR;
- }
-
- SVN_ERR(svn_wc_read_kind2(&target_kind, ctx->wc_ctx, local_abspath,
- TRUE, TRUE, scratch_pool));
- if (target_kind == svn_node_dir)
- {
- SVN_ERR(svn_wc_crop_tree2(ctx->wc_ctx, local_abspath, depth,
- ctx->cancel_func, ctx->cancel_baton,
- ctx->notify_func2, ctx->notify_baton2,
- scratch_pool));
- }
- }
-
- /* check whether the "clean c/o" optimization is applicable */
- SVN_ERR(is_empty_wc(&clean_checkout, local_abspath, anchor_abspath,
- scratch_pool));
-
- /* Get the external diff3, if any. */
- svn_config_get(cfg, &diff3_cmd, SVN_CONFIG_SECTION_HELPERS,
- SVN_CONFIG_OPTION_DIFF3_CMD, NULL);
-
- if (diff3_cmd != NULL)
- SVN_ERR(svn_path_cstring_to_utf8(&diff3_cmd, diff3_cmd, scratch_pool));
-
- /* See if the user wants last-commit timestamps instead of current ones. */
- SVN_ERR(svn_config_get_bool(cfg, &use_commit_times,
- SVN_CONFIG_SECTION_MISCELLANY,
- SVN_CONFIG_OPTION_USE_COMMIT_TIMES, FALSE));
-
- /* See which files the user wants to preserve the extension of when
- conflict files are made. */
- svn_config_get(cfg, &preserved_exts_str, SVN_CONFIG_SECTION_MISCELLANY,
- SVN_CONFIG_OPTION_PRESERVED_CF_EXTS, "");
- preserved_exts = *preserved_exts_str
- ? svn_cstring_split(preserved_exts_str, "\n\r\t\v ", FALSE, scratch_pool)
- : NULL;
-
- /* Let everyone know we're starting a real update (unless we're
- asked not to). */
- if (ctx->notify_func2 && notify_summary)
- {
- svn_wc_notify_t *notify
- = svn_wc_create_notify(local_abspath, svn_wc_notify_update_started,
- scratch_pool);
- notify->kind = svn_node_none;
- notify->content_state = notify->prop_state
- = svn_wc_notify_state_inapplicable;
- notify->lock_state = svn_wc_notify_lock_state_inapplicable;
- ctx->notify_func2(ctx->notify_baton2, notify, scratch_pool);
- }
-
- /* Try to reuse the RA session by reparenting it to the anchor_url.
- * This code is probably overly cautious since we only use this
- * currently when parents are missing and so all the anchor_urls
- * have to be in the same repo. */
- if (ra_session)
- {
- svn_error_t *err = svn_ra_reparent(ra_session, anchor_url, scratch_pool);
- if (err)
- {
- if (err->apr_err == SVN_ERR_RA_ILLEGAL_URL)
- {
- /* session changed repos, can't reuse it */
- svn_error_clear(err);
- ra_session = NULL;
- }
- else
- {
- return svn_error_trace(err);
- }
- }
- else
- {
- corrected_url = NULL;
- }
- }
-
- /* Open an RA session for the URL if one isn't already available */
- if (!ra_session)
- {
- SVN_ERR(svn_client__open_ra_session_internal(&ra_session, &corrected_url,
- anchor_url,
- anchor_abspath, NULL,
- TRUE /* write_dav_props */,
- TRUE /* read_dav_props */,
- ctx,
- result_pool, scratch_pool));
- *ra_session_p = ra_session;
- }
-
- /* If we got a corrected URL from the RA subsystem, we'll need to
- relocate our working copy first. */
- if (corrected_url)
- {
- const char *new_repos_root_url;
-
- /* To relocate everything inside our repository we need the old and new
- repos root. */
- SVN_ERR(svn_ra_get_repos_root2(ra_session, &new_repos_root_url,
- scratch_pool));
-
- /* svn_client_relocate2() will check the uuid */
- SVN_ERR(svn_client_relocate2(anchor_abspath, repos_root_url,
- new_repos_root_url, ignore_externals,
- ctx, scratch_pool));
-
- /* Store updated repository root for externals */
- repos_root_url = new_repos_root_url;
- /* ### We should update anchor_loc->repos_uuid too, although currently
- * we don't use it. */
- anchor_url = corrected_url;
- }
-
- /* Resolve unspecified REVISION now, because we need to retrieve the
- correct inherited props prior to the editor drive and we need to
- use the same value of HEAD for both. */
- opt_rev.kind = revision->kind;
- opt_rev.value = revision->value;
- if (opt_rev.kind == svn_opt_revision_unspecified)
- opt_rev.kind = svn_opt_revision_head;
-
- /* ### todo: shouldn't svn_client__get_revision_number be able
- to take a URL as easily as a local path? */
- SVN_ERR(svn_client__get_revision_number(&revnum, NULL, ctx->wc_ctx,
- local_abspath, ra_session, &opt_rev,
- scratch_pool));
-
- SVN_ERR(svn_ra_has_capability(ra_session, &server_supports_depth,
- SVN_RA_CAPABILITY_DEPTH, scratch_pool));
-
- dfb.ra_session = ra_session;
- dfb.target_revision = revnum;
- dfb.anchor_url = anchor_url;
-
- SVN_ERR(svn_client__get_inheritable_props(&wcroot_iprops, local_abspath,
- revnum, depth, ra_session,
- ctx, scratch_pool, scratch_pool));
-
-#if 0
- /* Fetch the update editor. If REVISION is invalid, that's okay;
- the RA driver will call editor->set_target_revision later on. */
- SVN_ERR(svn_wc__get_update_editor_ev3(&update_editor,
- &revnum, ctx->wc_ctx, anchor_abspath,
- target, wcroot_iprops, use_commit_times,
- depth, depth_is_sticky,
- allow_unver_obstructions,
- adds_as_modification,
- server_supports_depth,
- clean_checkout,
- diff3_cmd, preserved_exts,
- svn_client__dirent_fetcher, &dfb,
- conflicted_paths ? record_conflict : NULL,
- conflicted_paths,
- NULL, NULL,
- ctx->cancel_func, ctx->cancel_baton,
- ctx->notify_func2, ctx->notify_baton2,
- pool, pool));
- SVN_ERR(svn_editor3__get_debug_editor(&update_editor->editor,
- update_editor->editor,
- pool));
-
- /* Tell RA to do an update of URL+TARGET to REVISION; if we pass an
- invalid revnum, that means RA will use the latest revision. */
- SVN_ERR(svn_ra_do_update4(ra_session, &reporter, &report_baton,
- revnum, target,
- (!server_supports_depth || depth_is_sticky
- ? depth
- : svn_depth_unknown),
- FALSE /* send_copyfrom_args */,
- FALSE /* ignore_ancestry */,
- update_editor, pool, pool));
-#else
- /* Fetch the update editor. If REVISION is invalid, that's okay;
- the RA driver will call editor->set_target_revision later on. */
- SVN_ERR(svn_wc__get_update_editor(&update_editor, &update_edit_baton,
- &revnum, ctx->wc_ctx, anchor_abspath,
- target, wcroot_iprops, use_commit_times,
- depth, depth_is_sticky,
- allow_unver_obstructions,
- adds_as_modification,
- server_supports_depth,
- clean_checkout,
- diff3_cmd, preserved_exts,
- svn_client__dirent_fetcher, &dfb,
- conflicted_paths ? record_conflict : NULL,
- conflicted_paths,
- NULL, NULL,
- ctx->cancel_func, ctx->cancel_baton,
- ctx->notify_func2, ctx->notify_baton2,
- scratch_pool, scratch_pool));
-
- /* Tell RA to do an update of URL+TARGET to REVISION; if we pass an
- invalid revnum, that means RA will use the latest revision. */
- SVN_ERR(svn_ra_do_update3(ra_session, &reporter, &report_baton,
- revnum, target,
- (!server_supports_depth || depth_is_sticky
- ? depth
- : svn_depth_unknown),
- FALSE /* send_copyfrom_args */,
- FALSE /* ignore_ancestry */,
- update_editor, update_edit_baton,
- scratch_pool, scratch_pool));
-#endif
-
- /* Past this point, we assume the WC is going to be modified so we will
- * need to sleep for timestamps. */
- *timestamp_sleep = TRUE;
-
- /* Drive the reporter structure, describing the revisions within
- LOCAL_ABSPATH. When this calls reporter->finish_report, the
- reporter will drive the update_editor. */
- SVN_ERR(svn_wc_crawl_revisions5(ctx->wc_ctx, local_abspath, reporter,
- report_baton, TRUE,
- depth, (! depth_is_sticky),
- (! server_supports_depth),
- use_commit_times,
- ctx->cancel_func, ctx->cancel_baton,
- ctx->notify_func2, ctx->notify_baton2,
- scratch_pool));
-
- /* We handle externals after the update is complete, so that
- handling external items (and any errors therefrom) doesn't delay
- the primary operation. */
- if ((SVN_DEPTH_IS_RECURSIVE(depth) || cropping_target)
- && (! ignore_externals))
- {
- apr_hash_t *new_externals;
- apr_hash_t *new_depths;
- SVN_ERR(svn_wc__externals_gather_definitions(&new_externals,
- &new_depths,
- ctx->wc_ctx, local_abspath,
- depth,
- scratch_pool, scratch_pool));
-
- SVN_ERR(svn_client__handle_externals(new_externals,
- new_depths,
- repos_root_url, local_abspath,
- depth, timestamp_sleep, ra_session,
- ctx, scratch_pool));
- }
-
- /* Let everyone know we're finished here (unless we're asked not to). */
- if (ctx->notify_func2 && notify_summary)
- {
- svn_wc_notify_t *notify
- = svn_wc_create_notify(local_abspath, svn_wc_notify_update_completed,
- scratch_pool);
- notify->kind = svn_node_none;
- notify->content_state = notify->prop_state
- = svn_wc_notify_state_inapplicable;
- notify->lock_state = svn_wc_notify_lock_state_inapplicable;
- notify->revision = revnum;
- ctx->notify_func2(ctx->notify_baton2, notify, scratch_pool);
- }
-
- /* If the caller wants the result revision, give it to them. */
- if (result_rev)
- *result_rev = revnum;
-
- return SVN_NO_ERROR;
-}
-
-svn_error_t *
-svn_client__update_internal(svn_revnum_t *result_rev,
- svn_boolean_t *timestamp_sleep,
- const char *local_abspath,
- const svn_opt_revision_t *revision,
- svn_depth_t depth,
- svn_boolean_t depth_is_sticky,
- svn_boolean_t ignore_externals,
- svn_boolean_t allow_unver_obstructions,
- svn_boolean_t adds_as_modification,
- svn_boolean_t make_parents,
- svn_boolean_t innerupdate,
- svn_ra_session_t *ra_session,
- svn_client_ctx_t *ctx,
- apr_pool_t *pool)
-{
- const char *anchor_abspath, *lockroot_abspath;
- svn_error_t *err;
- svn_opt_revision_t peg_revision = *revision;
- apr_hash_t *conflicted_paths
- = ctx->conflict_func2 ? apr_hash_make(pool) : NULL;
-
- SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
- SVN_ERR_ASSERT(! (innerupdate && make_parents));
-
- if (make_parents)
- {
- int i;
- const char *parent_abspath = local_abspath;
- apr_array_header_t *missing_parents =
- apr_array_make(pool, 4, sizeof(const char *));
- apr_pool_t *iterpool;
-
- iterpool = svn_pool_create(pool);
-
- while (1)
- {
- svn_pool_clear(iterpool);
-
- /* Try to lock. If we can't lock because our target (or its
- parent) isn't a working copy, we'll try to walk up the
- tree to find a working copy, remembering this path's
- parent as one we need to flesh out. */
- err = svn_wc__acquire_write_lock(&lockroot_abspath, ctx->wc_ctx,
- parent_abspath, !innerupdate,
- pool, iterpool);
- if (!err)
- break;
- if ((err->apr_err != SVN_ERR_WC_NOT_WORKING_COPY)
- || svn_dirent_is_root(parent_abspath, strlen(parent_abspath)))
- return err;
- svn_error_clear(err);
-
- /* Remember the parent of our update target as a missing
- parent. */
- parent_abspath = svn_dirent_dirname(parent_abspath, pool);
- APR_ARRAY_PUSH(missing_parents, const char *) = parent_abspath;
- }
-
- /* Run 'svn up --depth=empty' (effectively) on the missing
- parents, if any. */
- anchor_abspath = lockroot_abspath;
- for (i = missing_parents->nelts - 1; i >= 0; i--)
- {
- const char *missing_parent =
- APR_ARRAY_IDX(missing_parents, i, const char *);
-
- svn_pool_clear(iterpool);
-
- err = update_internal(result_rev, timestamp_sleep, conflicted_paths,
- &ra_session, missing_parent,
- anchor_abspath, &peg_revision, svn_depth_empty,
- FALSE, ignore_externals,
- allow_unver_obstructions, adds_as_modification,
- FALSE, ctx, pool, iterpool);
- if (err)
- goto cleanup;
- anchor_abspath = missing_parent;
-
- /* If we successfully updated a missing parent, let's re-use
- the returned revision number for future updates for the
- sake of consistency. */
- peg_revision.kind = svn_opt_revision_number;
- peg_revision.value.number = *result_rev;
- }
-
- svn_pool_destroy(iterpool);
- }
- else
- {
- SVN_ERR(svn_wc__acquire_write_lock(&lockroot_abspath, ctx->wc_ctx,
- local_abspath, !innerupdate,
- pool, pool));
- anchor_abspath = lockroot_abspath;
- }
-
- err = update_internal(result_rev, timestamp_sleep, conflicted_paths,
- &ra_session,
- local_abspath, anchor_abspath,
- &peg_revision, depth, depth_is_sticky,
- ignore_externals, allow_unver_obstructions,
- adds_as_modification,
- TRUE, ctx, pool, pool);
-
- /* Give the conflict resolver callback the opportunity to
- * resolve any conflicts that were raised. */
- if (! err && ctx->conflict_func2 && apr_hash_count(conflicted_paths))
- {
- err = svn_client__resolve_conflicts(NULL, conflicted_paths, ctx, pool);
- }
-
- cleanup:
- err = svn_error_compose_create(
- err,
- svn_wc__release_write_lock(ctx->wc_ctx, lockroot_abspath, pool));
-
- return svn_error_trace(err);
-}
-
-
-svn_error_t *
-svn_client_update4(apr_array_header_t **result_revs,
- const apr_array_header_t *paths,
- const svn_opt_revision_t *revision,
- svn_depth_t depth,
- svn_boolean_t depth_is_sticky,
- svn_boolean_t ignore_externals,
- svn_boolean_t allow_unver_obstructions,
- svn_boolean_t adds_as_modification,
- svn_boolean_t make_parents,
- svn_client_ctx_t *ctx,
- apr_pool_t *pool)
-{
- int i;
- apr_pool_t *iterpool = svn_pool_create(pool);
- const char *path = NULL;
- svn_boolean_t sleep = FALSE;
- svn_error_t *err = SVN_NO_ERROR;
- svn_boolean_t found_valid_target = FALSE;
-
- if (result_revs)
- *result_revs = apr_array_make(pool, paths->nelts, sizeof(svn_revnum_t));
-
- for (i = 0; i < paths->nelts; ++i)
- {
- path = APR_ARRAY_IDX(paths, i, const char *);
-
- if (svn_path_is_url(path))
- return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
- _("'%s' is not a local path"), path);
- }
-
- for (i = 0; i < paths->nelts; ++i)
- {
- svn_revnum_t result_rev;
- const char *local_abspath;
- path = APR_ARRAY_IDX(paths, i, const char *);
-
- svn_pool_clear(iterpool);
-
- if (ctx->cancel_func)
- {
- err = ctx->cancel_func(ctx->cancel_baton);
- if (err)
- goto cleanup;
- }
-
- err = svn_dirent_get_absolute(&local_abspath, path, iterpool);
- if (err)
- goto cleanup;
- err = svn_client__update_internal(&result_rev, &sleep, local_abspath,
- revision, depth, depth_is_sticky,
- ignore_externals,
- allow_unver_obstructions,
- adds_as_modification,
- make_parents,
- FALSE, NULL, ctx,
- iterpool);
-
- if (err)
- {
- if (err->apr_err != SVN_ERR_WC_NOT_WORKING_COPY)
- goto cleanup;
-
- svn_error_clear(err);
- err = SVN_NO_ERROR;
-
- /* SVN_ERR_WC_NOT_WORKING_COPY: it's not versioned */
-
- result_rev = SVN_INVALID_REVNUM;
- if (ctx->notify_func2)
- {
- svn_wc_notify_t *notify;
- notify = svn_wc_create_notify(path,
- svn_wc_notify_skip,
- iterpool);
- ctx->notify_func2(ctx->notify_baton2, notify, iterpool);
- }
- }
- else
- found_valid_target = TRUE;
-
- if (result_revs)
- APR_ARRAY_PUSH(*result_revs, svn_revnum_t) = result_rev;
- }
- svn_pool_destroy(iterpool);
-
- cleanup:
- if (!err && !found_valid_target)
- return svn_error_create(SVN_ERR_WC_NOT_WORKING_COPY, NULL,
- _("None of the targets are working copies"));
- if (sleep)
- {
- const char *wcroot_abspath;
-
- if (paths->nelts == 1)
- {
- const char *abspath;
-
- /* PATH iteslf may have been removed by the update. */
- SVN_ERR(svn_dirent_get_absolute(&abspath, path, pool));
- SVN_ERR(svn_wc__get_wcroot(&wcroot_abspath, ctx->wc_ctx, abspath,
- pool, pool));
- }
- else
- wcroot_abspath = NULL;
-
- svn_io_sleep_for_timestamps(wcroot_abspath, pool);
- }
-
- return svn_error_trace(err);
-}
Modified: subversion/branches/move-tracking-2/tools/dev/svnmover/svnmover.h
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/tools/dev/svnmover/svnmover.h?rev=1714604&r1=1714603&r2=1714604&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/tools/dev/svnmover/svnmover.h (original)
+++ subversion/branches/move-tracking-2/tools/dev/svnmover/svnmover.h Mon Nov 16 15:19:21 2015
@@ -210,6 +210,63 @@ svn_ra_get_commit_txn(svn_ra_session_t *
const char *branch_info_dir,
apr_pool_t *pool);
+/** Describes a server-side move (really a copy+delete within the same
+ * revision) which has been identified by scanning the revision log.
+ */
+typedef struct svn_repos_move_info_t {
+ /* The repository relpath the node was moved from. */
+ const char *moved_from_repos_relpath;
+
+ /* The repository relpath the node was moved to. */
+ const char *moved_to_repos_relpath;
+
+ /* The revision in which the move happened. */
+ svn_revnum_t revision;
+
+ /* The copyfrom revision of the moved-to path. */
+ svn_revnum_t copyfrom_rev;
+
+ /* Pointers to previous or subsequent moves of the same node
+ * within interesting history. */
+ struct svn_repos_move_info_t *prev;
+ struct svn_repos_move_info_t *next;
+
+ /* @note Fields may be added to the end of this structure in future
+ * versions. Therefore, to preserve binary compatibility, users
+ * should not directly allocate structures of this type but should use
+ * svn_wc_create_repos_move_info(). */
+} svn_repos_move_info_t;
+
+/** Create a svn_wc_repos_move_info_t structure.
+ * @see svn_wc_repos_move_info_t
+ */
+svn_repos_move_info_t *
+svn_repos_move_info_create(const char *moved_from_repos_relpath,
+ const char *moved_to_repos_relpath,
+ svn_revnum_t revision,
+ svn_revnum_t copyfrom_rev,
+ svn_repos_move_info_t *prev,
+ svn_repos_move_info_t *next,
+ apr_pool_t *result_pool);
+
+/* ...
+ */
+const char *
+svn_client__format_move_chain_for_display(svn_repos_move_info_t *first_move,
+ const char *indent,
+ apr_pool_t *result_pool);
+/* ...
+ */
+svn_error_t *
+svn_client__get_repos_moves(apr_hash_t **moves,
+ const char *anchor_abspath,
+ svn_ra_session_t *ra_session,
+ svn_revnum_t start,
+ svn_revnum_t end,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool);
+
#ifdef __cplusplus
}