📄 externals.c
字号:
(*ib->ctx->notify_func) (ib->ctx->notify_baton,
path,
svn_wc_notify_update_external,
svn_node_unknown,
NULL,
svn_wc_notify_state_unknown,
svn_wc_notify_state_unknown,
SVN_INVALID_REVNUM);
/* Next, verify that the external working copy matches
(URL-wise) what is supposed to be on disk. */
SVN_ERR (svn_io_check_path (path, &kind, ib->pool));
if (kind == svn_node_dir)
{
SVN_ERR (svn_wc_adm_open2 (&adm_access, NULL, path, TRUE, -1,
ib->pool));
SVN_ERR (svn_wc_entry (&ext_entry, path, adm_access,
FALSE, ib->pool));
SVN_ERR (svn_wc_adm_close (adm_access));
/* If we have what appears to be a version controlled
subdir, and its top-level URL matches that of our
externals definition, perform an update. */
if (ext_entry && (strcmp (ext_entry->url, new_item->url) == 0))
{
SVN_ERR (svn_client__update_internal (NULL, path,
&(new_item->revision),
TRUE, /* recurse */
ib->timestamp_sleep,
ib->ctx, ib->pool));
}
/* If, however, the URLs don't match, we need to relegate
the one subdir, and then checkout a new one. */
else
{
/* Buh-bye, old and busted ... */
SVN_ERR (relegate_external (path,
ib->ctx->cancel_func,
ib->ctx->cancel_baton,
ib->pool));
/* ... Hello, new hotness. */
SVN_ERR (svn_client__checkout_internal (NULL, new_item->url,
path,
&(new_item->revision),
TRUE, /* recurse */
ib->timestamp_sleep,
ib->ctx, ib->pool));
}
}
else /* Not a directory at all -- just try the checkout. */
{
/* The target dir might have multiple components. Guarantee
the path leading down to the last component. */
svn_path_split (path, &parent, NULL, ib->pool);
SVN_ERR (svn_io_make_dir_recursively (parent, ib->pool));
/* Checking out... */
SVN_ERR (svn_client__checkout_internal (NULL, new_item->url, path,
&(new_item->revision),
TRUE, /* recurse */
ib->timestamp_sleep,
ib->ctx, ib->pool));
}
}
/* Clear IB->pool -- we only use it for scratchwork (and this will
close any RA sessions still open in this pool). */
svn_pool_clear (ib->pool);
return SVN_NO_ERROR;
}
/* Closure for handle_externals_change. */
struct handle_externals_desc_change_baton
{
/* As returned by svn_wc_edited_externals(). */
apr_hash_t *externals_new;
apr_hash_t *externals_old;
/* Passed through to handle_external_item_change_baton. */
svn_client_ctx_t *ctx;
svn_boolean_t update_unchanged;
svn_boolean_t *timestamp_sleep;
svn_boolean_t is_export;
apr_pool_t *pool;
};
/* This implements the 'svn_hash_diff_func_t' interface.
BATON is of type 'struct handle_externals_desc_change_baton *'.
*/
static svn_error_t *
handle_externals_desc_change (const void *key, apr_ssize_t klen,
enum svn_hash_diff_key_status status,
void *baton)
{
struct handle_externals_desc_change_baton *cb = baton;
struct handle_external_item_change_baton ib;
const char *old_desc_text, *new_desc_text;
apr_array_header_t *old_desc, *new_desc;
apr_hash_t *old_desc_hash, *new_desc_hash;
int i;
svn_wc_external_item_t *item;
if ((old_desc_text = apr_hash_get (cb->externals_old, key, klen)))
SVN_ERR (svn_wc_parse_externals_description2 (&old_desc, (const char *) key,
old_desc_text, cb->pool));
else
old_desc = NULL;
if ((new_desc_text = apr_hash_get (cb->externals_new, key, klen)))
SVN_ERR (svn_wc_parse_externals_description2 (&new_desc, (const char *) key,
new_desc_text, cb->pool));
else
new_desc = NULL;
old_desc_hash = apr_hash_make (cb->pool);
new_desc_hash = apr_hash_make (cb->pool);
/* Create hashes of our two externals arrays so that we can
efficiently generate a diff for them. */
for (i = 0; old_desc && (i < old_desc->nelts); i++)
{
item = APR_ARRAY_IDX (old_desc, i, svn_wc_external_item_t *);
apr_hash_set (old_desc_hash, item->target_dir,
APR_HASH_KEY_STRING, item);
}
for (i = 0; new_desc && (i < new_desc->nelts); i++)
{
item = APR_ARRAY_IDX (new_desc, i, svn_wc_external_item_t *);
apr_hash_set (new_desc_hash, item->target_dir,
APR_HASH_KEY_STRING, item);
}
ib.old_desc = old_desc_hash;
ib.new_desc = new_desc_hash;
ib.parent_dir = (const char *) key;
ib.ctx = cb->ctx;
ib.update_unchanged = cb->update_unchanged;
ib.is_export = cb->is_export;
ib.timestamp_sleep = cb->timestamp_sleep;
ib.pool = svn_pool_create (cb->pool);
/* We must use a custom version of svn_hash_diff so that the diff
entries are processed in the order they were originally specified
in the svn:external properties. */
for (i = 0; old_desc && (i < old_desc->nelts); i++)
{
item = APR_ARRAY_IDX (old_desc, i, svn_wc_external_item_t *);
if (apr_hash_get (new_desc_hash, item->target_dir, APR_HASH_KEY_STRING))
SVN_ERR (handle_external_item_change (item->target_dir,
APR_HASH_KEY_STRING,
svn_hash_diff_key_both, &ib));
else
SVN_ERR (handle_external_item_change (item->target_dir,
APR_HASH_KEY_STRING,
svn_hash_diff_key_a, &ib));
}
for (i = 0; new_desc && (i < new_desc->nelts); i++)
{
item = APR_ARRAY_IDX (new_desc, i, svn_wc_external_item_t *);
if (! apr_hash_get (old_desc_hash, item->target_dir, APR_HASH_KEY_STRING))
SVN_ERR (handle_external_item_change (item->target_dir,
APR_HASH_KEY_STRING,
svn_hash_diff_key_b, &ib));
}
/* Now destroy the subpool we pass to the hash differ. This will
close any remaining RA sessions used by the hash diff callback. */
svn_pool_destroy (ib.pool);
return SVN_NO_ERROR;
}
svn_error_t *
svn_client__handle_externals (svn_wc_traversal_info_t *traversal_info,
svn_boolean_t update_unchanged,
svn_boolean_t *timestamp_sleep,
svn_client_ctx_t *ctx,
apr_pool_t *pool)
{
apr_hash_t *externals_old, *externals_new;
struct handle_externals_desc_change_baton cb;
svn_wc_edited_externals (&externals_old, &externals_new, traversal_info);
cb.externals_new = externals_new;
cb.externals_old = externals_old;
cb.ctx = ctx;
cb.update_unchanged = update_unchanged;
cb.timestamp_sleep = timestamp_sleep;
cb.is_export = FALSE;
cb.pool = pool;
SVN_ERR (svn_hash_diff (cb.externals_old, cb.externals_new,
handle_externals_desc_change, &cb, pool));
return SVN_NO_ERROR;
}
svn_error_t *
svn_client__fetch_externals (apr_hash_t *externals,
svn_boolean_t is_export,
svn_boolean_t *timestamp_sleep,
svn_client_ctx_t *ctx,
apr_pool_t *pool)
{
struct handle_externals_desc_change_baton cb;
cb.externals_new = externals;
cb.externals_old = apr_hash_make (pool);
cb.ctx = ctx;
cb.update_unchanged = TRUE;
cb.timestamp_sleep = timestamp_sleep;
cb.is_export = is_export;
cb.pool = pool;
SVN_ERR (svn_hash_diff (cb.externals_old, cb.externals_new,
handle_externals_desc_change, &cb, pool));
return SVN_NO_ERROR;
}
svn_error_t *
svn_client__do_external_status (svn_wc_traversal_info_t *traversal_info,
svn_wc_status_func_t status_func,
void *status_baton,
svn_boolean_t get_all,
svn_boolean_t update,
svn_boolean_t no_ignore,
svn_client_ctx_t *ctx,
apr_pool_t *pool)
{
apr_hash_t *externals_old, *externals_new;
apr_hash_index_t *hi;
apr_pool_t *subpool = svn_pool_create (pool);
/* Get the values of the svn:externals properties. */
svn_wc_edited_externals (&externals_old, &externals_new, traversal_info);
/* Loop over the hash of new values (we don't care about the old
ones). This is a mapping of versioned directories to property
values. */
for (hi = apr_hash_first (pool, externals_new);
hi;
hi = apr_hash_next (hi))
{
apr_array_header_t *exts;
const void *key;
void *val;
const char *path;
const char *propval;
apr_pool_t *iterpool;
int i;
/* Clear the subpool. */
svn_pool_clear (subpool);
apr_hash_this (hi, &key, NULL, &val);
path = key;
propval = val;
/* Parse the svn:externals property value. This results in a
hash mapping subdirectories to externals structures. */
SVN_ERR (svn_wc_parse_externals_description2 (&exts, path,
propval, subpool));
/* Make a sub-pool of SUBPOOL. */
iterpool = svn_pool_create (subpool);
/* Loop over the subdir array. */
for (i = 0; exts && (i < exts->nelts); i++)
{
const char *fullpath;
svn_wc_external_item_t *external;
svn_node_kind_t kind;
svn_pool_clear (iterpool);
external = APR_ARRAY_IDX (exts, i, svn_wc_external_item_t *);
fullpath = svn_path_join (path, external->target_dir, iterpool);
/* If the external target directory doesn't exist on disk,
just skip it. */
SVN_ERR (svn_io_check_path (fullpath, &kind, iterpool));
if (kind != svn_node_dir)
continue;
/* Tell the client we're staring an external status set. */
if (ctx->notify_func)
(ctx->notify_func) (ctx->notify_baton,
fullpath,
svn_wc_notify_status_external,
svn_node_unknown,
NULL,
svn_wc_notify_state_unknown,
svn_wc_notify_state_unknown,
SVN_INVALID_REVNUM);
/* And then do the status. */
SVN_ERR (svn_client_status (NULL, fullpath,
&(external->revision),
status_func, status_baton,
TRUE, get_all, update, no_ignore,
ctx, iterpool));
}
}
/* Destroy SUBPOOL and (implicitly) ITERPOOL. */
apr_pool_destroy (subpool);
return SVN_NO_ERROR;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -