svn_error_t * svn_client__export_externals(apr_hash_t *externals, const char *from_url, const char *to_abspath, const char *repos_root_url, svn_depth_t requested_depth, const char *native_eol, svn_boolean_t ignore_keywords, svn_client_ctx_t *ctx, apr_pool_t *scratch_pool) { apr_pool_t *iterpool = svn_pool_create(scratch_pool); apr_pool_t *sub_iterpool = svn_pool_create(scratch_pool); apr_hash_index_t *hi; SVN_ERR_ASSERT(svn_dirent_is_absolute(to_abspath)); for (hi = apr_hash_first(scratch_pool, externals); hi; hi = apr_hash_next(hi)) { const char *local_abspath = svn__apr_hash_index_key(hi); const char *desc_text = svn__apr_hash_index_val(hi); const char *local_relpath; const char *dir_url; apr_array_header_t *items; int i; svn_pool_clear(iterpool); SVN_ERR(svn_wc_parse_externals_description3(&items, local_abspath, desc_text, FALSE, iterpool)); if (! items->nelts) continue; local_relpath = svn_dirent_skip_ancestor(to_abspath, local_abspath); dir_url = svn_path_url_add_component2(from_url, local_relpath, scratch_pool); for (i = 0; i < items->nelts; i++) { const char *item_abspath; const char *new_url; svn_boolean_t under_root; svn_wc_external_item2_t *item = APR_ARRAY_IDX(items, i, svn_wc_external_item2_t *); svn_pool_clear(sub_iterpool); SVN_ERR(svn_dirent_is_under_root(&under_root, &item_abspath, local_abspath, item->target_dir, sub_iterpool)); if (! under_root) { return svn_error_createf( SVN_ERR_WC_OBSTRUCTED_UPDATE, NULL, _("Path '%s' is not in the working copy"), svn_dirent_local_style( svn_dirent_join(local_abspath, item->target_dir, sub_iterpool), sub_iterpool)); } SVN_ERR(svn_wc__resolve_relative_external_url(&new_url, item, repos_root_url, dir_url, sub_iterpool, sub_iterpool)); /* The target dir might have multiple components. Guarantee the path leading down to the last component. */ SVN_ERR(svn_io_make_dir_recursively(svn_dirent_dirname(item_abspath, sub_iterpool), sub_iterpool)); SVN_ERR(wrap_external_error( ctx, item_abspath, svn_client_export5(NULL, new_url, item_abspath, &item->peg_revision, &item->revision, TRUE, FALSE, ignore_keywords, svn_depth_infinity, native_eol, ctx, sub_iterpool), sub_iterpool)); } } svn_pool_destroy(sub_iterpool); svn_pool_destroy(iterpool); return SVN_NO_ERROR; }
/* This implements the `svn_opt_subcommand_t' interface. */ svn_error_t * svn_cl__export(apr_getopt_t *os, void *baton, apr_pool_t *pool) { svn_cl__opt_state_t *opt_state = ((svn_cl__cmd_baton_t *) baton)->opt_state; svn_client_ctx_t *ctx = ((svn_cl__cmd_baton_t *) baton)->ctx; const char *from, *to; apr_array_header_t *targets; svn_error_t *err; svn_opt_revision_t peg_revision; const char *truefrom; struct svn_cl__check_externals_failed_notify_baton nwb; SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os, opt_state->targets, ctx, FALSE, pool)); /* We want exactly 1 or 2 targets for this subcommand. */ if (targets->nelts < 1) return svn_error_create(SVN_ERR_CL_INSUFFICIENT_ARGS, 0, NULL); if (targets->nelts > 2) return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, 0, NULL); /* The first target is the `from' path. */ from = APR_ARRAY_IDX(targets, 0, const char *); /* Get the peg revision if present. */ SVN_ERR(svn_opt_parse_path(&peg_revision, &truefrom, from, pool)); /* If only one target was given, split off the basename to use as the `to' path. Else, a `to' path was supplied. */ if (targets->nelts == 1) { if (svn_path_is_url(truefrom)) to = svn_uri_basename(truefrom, pool); else to = svn_dirent_basename(truefrom, pool); } else { to = APR_ARRAY_IDX(targets, 1, const char *); if (strcmp("", to) != 0) /* svn_cl__eat_peg_revisions() but only on one target */ SVN_ERR(svn_opt__split_arg_at_peg_revision(&to, NULL, to, pool)); } SVN_ERR(svn_cl__check_target_is_local_path(to)); if (! opt_state->quiet) SVN_ERR(svn_cl__notifier_mark_export(ctx->notify_baton2)); if (opt_state->depth == svn_depth_unknown) opt_state->depth = svn_depth_infinity; nwb.wrapped_func = ctx->notify_func2; nwb.wrapped_baton = ctx->notify_baton2; nwb.had_externals_error = FALSE; ctx->notify_func2 = svn_cl__check_externals_failed_notify_wrapper; ctx->notify_baton2 = &nwb; /* Do the export. */ err = svn_client_export5(NULL, truefrom, to, &peg_revision, &(opt_state->start_revision), opt_state->force, opt_state->ignore_externals, opt_state->ignore_keywords, opt_state->depth, opt_state->native_eol, ctx, pool); if (err && err->apr_err == SVN_ERR_WC_OBSTRUCTED_UPDATE && !opt_state->force) SVN_ERR_W(err, _("Destination directory exists; please remove " "the directory or use --force to overwrite")); if (nwb.had_externals_error) { svn_error_t *externals_err; externals_err = svn_error_create(SVN_ERR_CL_ERROR_PROCESSING_EXTERNALS, NULL, _("Failure occurred processing one or " "more externals definitions")); return svn_error_compose_create(externals_err, err); } return svn_error_trace(err); }