/* This implements the `svn_opt_subcommand_t' interface. */ svn_error_t * svn_cl__lock(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; apr_array_header_t *targets; const char *comment; SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os, opt_state->targets, pool)); /* We only support locking files, so '.' is not valid. */ if (! targets->nelts) return svn_error_create(SVN_ERR_CL_INSUFFICIENT_ARGS, 0, NULL); /* Get comment. */ SVN_ERR(get_comment(&comment, ctx, opt_state, pool)); svn_cl__get_notifier(&ctx->notify_func2, &ctx->notify_baton2, FALSE, FALSE, FALSE, pool); SVN_ERR(svn_client_lock(targets, comment, opt_state->force, ctx, pool)); return SVN_NO_ERROR; }
/* This implements the `svn_opt_subcommand_t' interface. */ svn_error_t * svn_cl__propdel(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 *pname; apr_array_header_t *args, *targets; /* Get the property's name (and a UTF-8 version of that name). */ SVN_ERR(svn_opt_parse_num_args(&args, os, 1, pool)); pname = APR_ARRAY_IDX(args, 0, const char *); SVN_ERR(svn_utf_cstring_to_utf8(&pname, pname, pool)); /* No need to check svn_prop_name_is_valid for *deleting* properties, and it may even be useful to allow, in case invalid properties sneaked through somehow. */ SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os, opt_state->targets, ctx, FALSE, pool)); /* Add "." if user passed 0 file arguments */ svn_opt_push_implicit_dot_target(targets, pool); SVN_ERR(svn_cl__eat_peg_revisions(&targets, targets, pool)); if (opt_state->revprop) /* operate on a revprop */ { svn_revnum_t rev; const char *URL; SVN_ERR(svn_cl__revprop_prepare(&opt_state->start_revision, targets, &URL, ctx, pool)); /* Let libsvn_client do the real work. */ SVN_ERR(svn_client_revprop_set2(pname, NULL, NULL, URL, &(opt_state->start_revision), &rev, FALSE, ctx, pool)); } else if (opt_state->start_revision.kind != svn_opt_revision_unspecified) { return svn_error_createf(SVN_ERR_CLIENT_PROPERTY_NAME, NULL, _("Cannot specify revision for deleting versioned property '%s'"), pname); } else /* operate on a normal, versioned property (not a revprop) */ { if (opt_state->depth == svn_depth_unknown) opt_state->depth = svn_depth_empty; /* For each target, remove the property PNAME. */ SVN_ERR(svn_client_propset_local(pname, NULL, targets, opt_state->depth, FALSE, opt_state->changelists, ctx, pool)); } return SVN_NO_ERROR; }
/* This implements the `svn_opt_subcommand_t' interface. */ svn_error_t * svn_cl__cat(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; apr_array_header_t *targets; int i; svn_stream_t *out; apr_pool_t *subpool = svn_pool_create(pool); svn_boolean_t seen_nonexistent_target = FALSE; SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os, opt_state->targets, ctx, FALSE, pool)); /* Cat cannot operate on an implicit '.' so a filename is required */ if (! targets->nelts) return svn_error_create(SVN_ERR_CL_INSUFFICIENT_ARGS, 0, NULL); SVN_ERR(svn_stream_for_stdout(&out, pool)); for (i = 0; i < targets->nelts; i++) { const char *target = APR_ARRAY_IDX(targets, i, const char *); const char *truepath; svn_opt_revision_t peg_revision; svn_boolean_t success; svn_pool_clear(subpool); SVN_ERR(svn_cl__check_cancel(ctx->cancel_baton)); /* Get peg revisions. */ SVN_ERR(svn_opt_parse_path(&peg_revision, &truepath, target, subpool)); SVN_ERR(svn_cl__try(svn_client_cat2(out, truepath, &peg_revision, &(opt_state->start_revision), ctx, subpool), &success, opt_state->quiet, SVN_ERR_UNVERSIONED_RESOURCE, SVN_ERR_ENTRY_NOT_FOUND, SVN_ERR_CLIENT_IS_DIRECTORY, SVN_ERR_FS_NOT_FOUND, SVN_NO_ERROR)); if (! success) seen_nonexistent_target = TRUE; } svn_pool_destroy(subpool); if (seen_nonexistent_target) return svn_error_create( SVN_ERR_ILLEGAL_TARGET, NULL, _("Could not cat all targets because some targets don't exist")); else return SVN_NO_ERROR; }
/* This implements the `svn_opt_subcommand_t' interface. */ svn_error_t * svn_cl__import(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; apr_array_header_t *targets; const char *path; const char *url; /* Import takes two arguments, for example * * $ svn import projects/test file:///home/jrandom/repos/trunk * ^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ * (source) (repository) * * or * * $ svn import file:///home/jrandom/repos/some/subdir * * What is the nicest behavior for import, from the user's point of * view? This is a subtle question. Seemingly intuitive answers * can lead to weird situations, such never being able to create * non-directories in the top-level of the repository. * * If 'source' is a file then the basename of 'url' is used as the * filename in the repository. If 'source' is a directory then the * import happens directly in the repository target dir, creating * however many new entries are necessary. If some part of 'url' * does not exist in the repository then parent directories are created * as necessary. * * In the case where no 'source' is given '.' (the current directory) * is implied. * * ### kff todo: review above behaviors. */ SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os, opt_state->targets, ctx, FALSE, pool)); if (targets->nelts < 1) return svn_error_create (SVN_ERR_CL_INSUFFICIENT_ARGS, NULL, _("Repository URL required when importing")); else if (targets->nelts > 2) return svn_error_create (SVN_ERR_CL_ARG_PARSING_ERROR, NULL, _("Too many arguments to import command")); else if (targets->nelts == 1) { url = APR_ARRAY_IDX(targets, 0, const char *); path = ""; }
/* This implements the `svn_opt_subcommand_t' interface. */ svn_error_t * svn_cl__null_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; apr_array_header_t *targets; svn_error_t *err; svn_opt_revision_t peg_revision; const char *truefrom; edit_baton_t eb = { 0 }; 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 (opt_state->depth == svn_depth_unknown) opt_state->depth = svn_depth_infinity; /* Do the export. */ err = bench_null_export(NULL, truefrom, &peg_revision, &(opt_state->start_revision), opt_state->depth, &eb, ctx, opt_state->quiet, pool); if (!opt_state->quiet) SVN_ERR(svn_cmdline_printf(pool, _("%15s directories\n" "%15s files\n" "%15s bytes in files\n" "%15s properties\n" "%15s bytes in properties\n"), svn__ui64toa_sep(eb.dir_count, ',', pool), svn__ui64toa_sep(eb.file_count, ',', pool), svn__ui64toa_sep(eb.byte_count, ',', pool), svn__ui64toa_sep(eb.prop_count, ',', pool), svn__ui64toa_sep(eb.prop_byte_count, ',', pool))); return svn_error_trace(err); }
/* This implements the `svn_opt_subcommand_t' interface. */ svn_error_t * svn_cl__add(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; apr_array_header_t *targets; int i; apr_pool_t *subpool; SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os, opt_state->targets, pool)); if (! targets->nelts) return svn_error_create(SVN_ERR_CL_INSUFFICIENT_ARGS, 0, NULL); if (! opt_state->quiet) svn_cl__get_notifier(&ctx->notify_func2, &ctx->notify_baton2, FALSE, FALSE, FALSE, pool); if (opt_state->depth == svn_depth_unknown) opt_state->depth = svn_depth_infinity; subpool = svn_pool_create(pool); for (i = 0; i < targets->nelts; i++) { const char *target = APR_ARRAY_IDX(targets, i, const char *); svn_pool_clear(subpool); SVN_ERR(svn_cl__check_cancel(ctx->cancel_baton)); SVN_ERR(svn_cl__try (svn_client_add4(target, opt_state->depth, opt_state->force, opt_state->no_ignore, opt_state->parents, ctx, subpool), NULL, opt_state->quiet, SVN_ERR_ENTRY_EXISTS, SVN_ERR_WC_PATH_NOT_FOUND, SVN_NO_ERROR)); } svn_pool_destroy(subpool); return SVN_NO_ERROR; }
/* This implements the `svn_opt_subcommand_t' interface. */ svn_error_t * svn_cl__revert(apr_getopt_t *os, void *baton, apr_pool_t *scratch_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; apr_array_header_t *targets = NULL; svn_error_t *err; SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os, opt_state->targets, ctx, FALSE, scratch_pool)); /* Revert has no implicit dot-target `.', so don't you put that code here! */ if (! targets->nelts) return svn_error_create(SVN_ERR_CL_INSUFFICIENT_ARGS, 0, NULL); /* Revert is especially conservative, by default it is as nonrecursive as possible. */ if (opt_state->depth == svn_depth_unknown) opt_state->depth = svn_depth_empty; SVN_ERR(svn_cl__eat_peg_revisions(&targets, targets, scratch_pool)); SVN_ERR(svn_cl__check_targets_are_local_paths(targets)); err = svn_client_revert2(targets, opt_state->depth, opt_state->changelists, ctx, scratch_pool); if (err && (err->apr_err == SVN_ERR_WC_INVALID_OPERATION_DEPTH) && (! SVN_DEPTH_IS_RECURSIVE(opt_state->depth))) { err = svn_error_quick_wrap (err, _("Try 'svn revert --depth infinity' instead?")); } return svn_error_trace(err); }
/* This implements the `svn_opt_subcommand_t' interface. */ svn_error_t * svn_cl__upgrade(apr_getopt_t *os, void *baton, apr_pool_t *scratch_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; apr_array_header_t *targets; apr_pool_t *iterpool; int i; SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os, opt_state->targets, ctx, FALSE, scratch_pool)); /* Add "." if user passed 0 arguments */ svn_opt_push_implicit_dot_target(targets, scratch_pool); SVN_ERR(svn_cl__eat_peg_revisions(&targets, targets, scratch_pool)); SVN_ERR(svn_cl__check_targets_are_local_paths(targets)); iterpool = svn_pool_create(scratch_pool); for (i = 0; i < targets->nelts; i++) { const char *target = APR_ARRAY_IDX(targets, i, const char *); svn_pool_clear(iterpool); SVN_ERR(svn_cl__check_cancel(ctx->cancel_baton)); SVN_ERR(svn_client_upgrade(target, ctx, scratch_pool)); } svn_pool_destroy(iterpool); return SVN_NO_ERROR; }
/* This implements the `svn_opt_subcommand_t' interface. */ svn_error_t * svn_cl__copy(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; apr_array_header_t *targets, *sources; const char *src_path, *dst_path; svn_boolean_t srcs_are_urls, dst_is_url; svn_error_t *err; int i; SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os, opt_state->targets, ctx, FALSE, pool)); if (targets->nelts < 2) return svn_error_create(SVN_ERR_CL_INSUFFICIENT_ARGS, 0, NULL); /* Get the src list and associated peg revs */ sources = apr_array_make(pool, targets->nelts - 1, sizeof(svn_client_copy_source_t *)); for (i = 0; i < (targets->nelts - 1); i++) { const char *target = APR_ARRAY_IDX(targets, i, const char *); svn_client_copy_source_t *source = apr_palloc(pool, sizeof(*source)); const char *src; svn_opt_revision_t *peg_revision = apr_palloc(pool, sizeof(*peg_revision)); err = svn_opt_parse_path(peg_revision, &src, target, pool); if (err) { /* Issue #3606: 'svn cp .@HEAD target' gives svn: '@HEAD' is just a peg revision. Maybe try '@HEAD@' instead? This is caused by a first round of canonicalization in svn_cl__args_to_target_array_print_reserved(). Undo that in an attempt to fix this issue without revving many apis. */ if (*target == '@' && err->apr_err == SVN_ERR_BAD_FILENAME) { svn_error_t *err2; err2 = svn_opt_parse_path(peg_revision, &src, apr_pstrcat(pool, ".", target, (const char *)NULL), pool); if (err2) { /* Fix attempt failed; return original error */ svn_error_clear(err2); } else { /* Error resolved. Use path */ svn_error_clear(err); err = NULL; } } if (err) return svn_error_trace(err); } source->path = src; source->revision = &(opt_state->start_revision); source->peg_revision = peg_revision; APR_ARRAY_PUSH(sources, svn_client_copy_source_t *) = source; } /* Get DST_PATH (the target path or URL) and check that no peg revision is * specified for it. */ { const char *tgt = APR_ARRAY_IDX(targets, targets->nelts - 1, const char *); svn_opt_revision_t peg; SVN_ERR(svn_opt_parse_path(&peg, &dst_path, tgt, pool)); if (peg.kind != svn_opt_revision_unspecified) return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL, _("'%s': a peg revision is not allowed here"), tgt); } /* Figure out which type of notification to use. (There is no need to check that the src paths are homogeneous; svn_client_copy6() through its subroutine try_copy() will return an error if they are not.) */ src_path = APR_ARRAY_IDX(targets, 0, const char *); srcs_are_urls = svn_path_is_url(src_path); dst_is_url = svn_path_is_url(dst_path); if ((! srcs_are_urls) && (! dst_is_url)) { /* WC->WC */ } else if ((! srcs_are_urls) && (dst_is_url)) { /* WC->URL : Use notification. */ if (! opt_state->quiet) SVN_ERR(svn_cl__notifier_mark_wc_to_repos_copy(ctx->notify_baton2)); } else if ((srcs_are_urls) && (! dst_is_url)) { /* URL->WC : Use checkout-style notification. */ if (! opt_state->quiet) SVN_ERR(svn_cl__notifier_mark_checkout(ctx->notify_baton2)); } else { /* URL -> URL, meaning that no notification is needed. */ ctx->notify_func2 = NULL; } if (! dst_is_url) { ctx->log_msg_func3 = NULL; if (opt_state->message || opt_state->filedata || opt_state->revprop_table) return svn_error_create (SVN_ERR_CL_UNNECESSARY_LOG_MESSAGE, NULL, _("Local, non-commit operations do not take a log message " "or revision properties")); } if (ctx->log_msg_func3) SVN_ERR(svn_cl__make_log_msg_baton(&(ctx->log_msg_baton3), opt_state, NULL, ctx->config, pool)); err = svn_client_copy6(sources, dst_path, TRUE, opt_state->parents, opt_state->ignore_externals, opt_state->revprop_table, (opt_state->quiet ? NULL : svn_cl__print_commit_info), NULL, ctx, pool); if (ctx->log_msg_func3) SVN_ERR(svn_cl__cleanup_log_msg(ctx->log_msg_baton3, err, pool)); else if (err) return svn_error_trace(err); return SVN_NO_ERROR; }
/* This implements the `svn_opt_subcommand_t' interface. */ svn_error_t * svn_cl__move(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; apr_array_header_t *targets; const char *dst_path; svn_commit_info_t *commit_info = NULL; svn_error_t *err; SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os, opt_state->targets, ctx, pool)); if (targets->nelts < 2) return svn_error_create(SVN_ERR_CL_INSUFFICIENT_ARGS, 0, NULL); if (opt_state->start_revision.kind != svn_opt_revision_unspecified && opt_state->start_revision.kind != svn_opt_revision_head) { return svn_error_create (SVN_ERR_UNSUPPORTED_FEATURE, NULL, _("Cannot specify revisions (except HEAD) with move operations")); } if (! opt_state->quiet) svn_cl__get_notifier(&ctx->notify_func2, &ctx->notify_baton2, FALSE, FALSE, FALSE, pool); dst_path = APR_ARRAY_IDX(targets, targets->nelts - 1, const char *); apr_array_pop(targets); if (! svn_path_is_url(dst_path)) { ctx->log_msg_func3 = NULL; if (opt_state->message || opt_state->filedata || opt_state->revprop_table) return svn_error_create (SVN_ERR_CL_UNNECESSARY_LOG_MESSAGE, NULL, _("Local, non-commit operations do not take a log message " "or revision properties")); } if (ctx->log_msg_func3) SVN_ERR(svn_cl__make_log_msg_baton(&(ctx->log_msg_baton3), opt_state, NULL, ctx->config, pool)); SVN_ERR(svn_opt__eat_peg_revisions(&targets, targets, pool)); err = svn_client_move5(&commit_info, targets, dst_path, opt_state->force, TRUE, opt_state->parents, opt_state->revprop_table, ctx, pool); if (err) err = svn_cl__may_need_force(err); if (ctx->log_msg_func3) SVN_ERR(svn_cl__cleanup_log_msg(ctx->log_msg_baton3, err, pool)); else if (err) return err; if (commit_info && ! opt_state->quiet) SVN_ERR(svn_cl__print_commit_info(commit_info, pool)); return SVN_NO_ERROR; }
/* If we're not removing changelists, then our first argument should be the name of a changelist. */ if (! opt_state->remove) { apr_array_header_t *args; SVN_ERR(svn_opt_parse_num_args(&args, os, 1, pool)); changelist_name = APR_ARRAY_IDX(args, 0, const char *); SVN_ERR(svn_utf_cstring_to_utf8(&changelist_name, changelist_name, pool)); } /* Parse the remaining arguments as paths. */ SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os, opt_state->targets, pool)); /* Changelist has no implicit dot-target `.', so don't you put that code here! */ if (! targets->nelts) return svn_error_create(SVN_ERR_CL_INSUFFICIENT_ARGS, 0, NULL); if (! opt_state->quiet) svn_cl__get_notifier(&ctx->notify_func2, &ctx->notify_baton2, FALSE, FALSE, FALSE, pool); else /* FIXME: This is required because svn_client_create_context() always initializes ctx->notify_func2 to a wrapper function which calls ctx->notify_func() if it isn't NULL. In other words, typically, ctx->notify_func2 is never NULL. This isn't
/* This implements the `svn_opt_subcommand_t' interface. */ svn_error_t * svn_cl__commit(apr_getopt_t *os, void *baton, apr_pool_t *pool) { svn_error_t *err; 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; apr_array_header_t *targets; apr_array_header_t *condensed_targets; const char *base_dir; svn_config_t *cfg; svn_boolean_t no_unlock = FALSE; struct copy_warning_notify_baton cwnb; SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os, opt_state->targets, ctx, FALSE, pool)); SVN_ERR_W(svn_cl__check_targets_are_local_paths(targets), _("Commit targets must be local paths")); /* Add "." if user passed 0 arguments. */ svn_opt_push_implicit_dot_target(targets, pool); SVN_ERR(svn_cl__eat_peg_revisions(&targets, targets, pool)); /* Condense the targets (like commit does)... */ SVN_ERR(svn_dirent_condense_targets(&base_dir, &condensed_targets, targets, TRUE, pool, pool)); if ((! condensed_targets) || (! condensed_targets->nelts)) { const char *parent_dir, *base_name; SVN_ERR(svn_wc_get_actual_target2(&parent_dir, &base_name, ctx->wc_ctx, base_dir, pool, pool)); if (*base_name) base_dir = apr_pstrdup(pool, parent_dir); } if (opt_state->depth == svn_depth_unknown) opt_state->depth = svn_depth_infinity; cfg = apr_hash_get(ctx->config, SVN_CONFIG_CATEGORY_CONFIG, APR_HASH_KEY_STRING); if (cfg) SVN_ERR(svn_config_get_bool(cfg, &no_unlock, SVN_CONFIG_SECTION_MISCELLANY, SVN_CONFIG_OPTION_NO_UNLOCK, FALSE)); /* We're creating a new log message baton because we can use our base_dir to store the temp file, instead of the current working directory. The client might not have write access to their working directory, but they better have write access to the directory they're committing. */ SVN_ERR(svn_cl__make_log_msg_baton(&(ctx->log_msg_baton3), opt_state, base_dir, ctx->config, pool)); /* Copies are done server-side, and cheaply, which means they're effectively always done with infinite depth. This is a potential cause of confusion for users trying to commit copied subtrees in part by restricting the commit's depth. See issues #3699 and #3752. */ if (opt_state->depth < svn_depth_infinity) { cwnb.wrapped_func = ctx->notify_func2; cwnb.wrapped_baton = ctx->notify_baton2; cwnb.depth = opt_state->depth; cwnb.warned = FALSE; ctx->notify_func2 = copy_warning_notify_func; ctx->notify_baton2 = &cwnb; } /* Commit. */ err = svn_client_commit5(targets, opt_state->depth, no_unlock, opt_state->keep_changelists, TRUE /* commit_as_operations */, opt_state->changelists, opt_state->revprop_table, (opt_state->quiet ? NULL : svn_cl__print_commit_info), NULL, ctx, pool); SVN_ERR(svn_cl__cleanup_log_msg(ctx->log_msg_baton3, err, pool)); return SVN_NO_ERROR; }
/* This implements the `svn_opt_subcommand_t' interface. */ svn_error_t * svn_cl__add(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; apr_array_header_t *targets; int i; apr_pool_t *iterpool; apr_array_header_t *errors = apr_array_make(pool, 0, sizeof(apr_status_t)); SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os, opt_state->targets, ctx, FALSE, pool)); if (! targets->nelts) return svn_error_create(SVN_ERR_CL_INSUFFICIENT_ARGS, 0, NULL); if (opt_state->depth == svn_depth_unknown) opt_state->depth = svn_depth_infinity; SVN_ERR(svn_cl__eat_peg_revisions(&targets, targets, pool)); SVN_ERR(svn_cl__check_targets_are_local_paths(targets)); iterpool = svn_pool_create(pool); for (i = 0; i < targets->nelts; i++) { const char *target = APR_ARRAY_IDX(targets, i, const char *); svn_pool_clear(iterpool); SVN_ERR(svn_cl__check_cancel(ctx->cancel_baton)); SVN_ERR(svn_cl__try (svn_client_add5(target, opt_state->depth, opt_state->force, opt_state->no_ignore, opt_state->no_autoprops, opt_state->parents, ctx, iterpool), errors, opt_state->quiet, SVN_ERR_ENTRY_EXISTS, SVN_ERR_WC_PATH_NOT_FOUND, 0)); } svn_pool_destroy(iterpool); if (errors->nelts > 0) { svn_error_t *err; err = svn_error_create(SVN_ERR_ILLEGAL_TARGET, NULL, NULL); for (i = 0; i < errors->nelts; i++) { apr_status_t status = APR_ARRAY_IDX(errors, i, apr_status_t); if (status == SVN_ERR_WC_PATH_NOT_FOUND) err = svn_error_quick_wrap(err, _("Could not add all targets because " "some targets don't exist")); else if (status == SVN_ERR_ENTRY_EXISTS) err = svn_error_quick_wrap(err, _("Could not add all targets because " "some targets are already versioned")); } return svn_error_trace(err); } return SVN_NO_ERROR; }
/* This implements the `svn_opt_subcommand_t' interface. */ svn_error_t * svn_cl__null_list(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; apr_array_header_t *targets; int i; apr_pool_t *subpool = svn_pool_create(pool); apr_uint32_t dirent_fields; struct print_baton pb = { FALSE }; svn_boolean_t seen_nonexistent_target = FALSE; svn_error_t *err; SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os, opt_state->targets, ctx, FALSE, pool)); /* Add "." if user passed 0 arguments */ svn_opt_push_implicit_dot_target(targets, pool); if (opt_state->verbose) dirent_fields = SVN_DIRENT_ALL; else dirent_fields = SVN_DIRENT_KIND; /* the only thing we actually need... */ pb.ctx = ctx; pb.verbose = opt_state->verbose; if (opt_state->depth == svn_depth_unknown) opt_state->depth = svn_depth_immediates; /* For each target, try to list it. */ for (i = 0; i < targets->nelts; i++) { const char *target = APR_ARRAY_IDX(targets, i, const char *); const char *truepath; svn_opt_revision_t peg_revision; svn_pool_clear(subpool); SVN_ERR(svn_cl__check_cancel(ctx->cancel_baton)); /* Get peg revisions. */ SVN_ERR(svn_opt_parse_path(&peg_revision, &truepath, target, subpool)); err = svn_client_list3(truepath, &peg_revision, &(opt_state->start_revision), opt_state->depth, dirent_fields, opt_state->verbose, FALSE, /* include externals */ print_dirent, &pb, ctx, subpool); if (err) { /* If one of the targets is a non-existent URL or wc-entry, don't bail out. Just warn and move on to the next target. */ if (err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND || err->apr_err == SVN_ERR_FS_NOT_FOUND) svn_handle_warning2(stderr, err, "svnbench: "); else return svn_error_trace(err); svn_error_clear(err); err = NULL; seen_nonexistent_target = TRUE; } else if (!opt_state->quiet) SVN_ERR(svn_cmdline_printf(pool, _("%15s directories\n" "%15s files\n" "%15s locks\n"), svn__ui64toa_sep(pb.directories, ',', pool), svn__ui64toa_sep(pb.files, ',', pool), svn__ui64toa_sep(pb.locks, ',', pool))); } svn_pool_destroy(subpool); if (seen_nonexistent_target) return svn_error_create( SVN_ERR_ILLEGAL_TARGET, NULL, _("Could not list all targets because some targets don't exist")); else return SVN_NO_ERROR; }
/* This implements the `svn_opt_subcommand_t' interface. */ svn_error_t * svn_cl__propget(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 *pname, *pname_utf8; apr_array_header_t *args, *targets; svn_stream_t *out; if (opt_state->verbose && (opt_state->revprop || opt_state->strict || opt_state->xml)) return svn_error_create(SVN_ERR_CL_MUTUALLY_EXCLUSIVE_ARGS, NULL, _("--verbose cannot be used with --revprop or " "--strict or --xml")); /* PNAME is first argument (and PNAME_UTF8 will be a UTF-8 version thereof) */ SVN_ERR(svn_opt_parse_num_args(&args, os, 1, pool)); pname = APR_ARRAY_IDX(args, 0, const char *); SVN_ERR(svn_utf_cstring_to_utf8(&pname_utf8, pname, pool)); if (! svn_prop_name_is_valid(pname_utf8)) return svn_error_createf(SVN_ERR_CLIENT_PROPERTY_NAME, NULL, _("'%s' is not a valid Subversion property name"), pname_utf8); SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os, opt_state->targets, ctx, FALSE, pool)); /* Add "." if user passed 0 file arguments */ svn_opt_push_implicit_dot_target(targets, pool); /* Open a stream to stdout. */ SVN_ERR(svn_stream_for_stdout(&out, pool)); if (opt_state->revprop) /* operate on a revprop */ { svn_revnum_t rev; const char *URL; svn_string_t *propval; SVN_ERR(svn_cl__revprop_prepare(&opt_state->start_revision, targets, &URL, ctx, pool)); /* Let libsvn_client do the real work. */ SVN_ERR(svn_client_revprop_get(pname_utf8, &propval, URL, &(opt_state->start_revision), &rev, ctx, pool)); if (propval != NULL) { if (opt_state->xml) { svn_stringbuf_t *sb = NULL; char *revstr = apr_psprintf(pool, "%ld", rev); SVN_ERR(svn_cl__xml_print_header("properties", pool)); svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "revprops", "rev", revstr, NULL); svn_cmdline__print_xml_prop(&sb, pname_utf8, propval, pool); svn_xml_make_close_tag(&sb, pool, "revprops"); SVN_ERR(svn_cl__error_checked_fputs(sb->data, stdout)); SVN_ERR(svn_cl__xml_print_footer("properties", pool)); } else { svn_string_t *printable_val = propval; /* If this is a special Subversion property, it is stored as UTF8 and LF, so convert to the native locale and eol-style. */ if (svn_prop_needs_translation(pname_utf8)) SVN_ERR(svn_subst_detranslate_string(&printable_val, propval, TRUE, pool)); SVN_ERR(stream_write(out, printable_val->data, printable_val->len)); if (! opt_state->strict) SVN_ERR(stream_write(out, APR_EOL_STR, strlen(APR_EOL_STR))); } } } else /* operate on a normal, versioned property (not a revprop) */ { apr_pool_t *subpool = svn_pool_create(pool); int i; if (opt_state->xml) SVN_ERR(svn_cl__xml_print_header("properties", subpool)); if (opt_state->depth == svn_depth_unknown) opt_state->depth = svn_depth_empty; /* Strict mode only makes sense for a single target. So make sure we have only a single target, and that we're not being asked to recurse on that target. */ if (opt_state->strict && ((targets->nelts > 1) || (opt_state->depth != svn_depth_empty))) return svn_error_create (SVN_ERR_CL_ARG_PARSING_ERROR, NULL, _("Strict output of property values only available for single-" "target, non-recursive propget operations")); for (i = 0; i < targets->nelts; i++) { const char *target = APR_ARRAY_IDX(targets, i, const char *); apr_hash_t *props; svn_boolean_t print_filenames; svn_boolean_t omit_newline; svn_boolean_t like_proplist; const char *truepath; svn_opt_revision_t peg_revision; svn_pool_clear(subpool); SVN_ERR(svn_cl__check_cancel(ctx->cancel_baton)); /* Check for a peg revision. */ SVN_ERR(svn_opt_parse_path(&peg_revision, &truepath, target, subpool)); if (!svn_path_is_url(truepath)) SVN_ERR(svn_dirent_get_absolute(&truepath, truepath, subpool)); SVN_ERR(svn_client_propget4(&props, pname_utf8, truepath, &peg_revision, &(opt_state->start_revision), NULL, opt_state->depth, opt_state->changelists, ctx, subpool, subpool)); /* Any time there is more than one thing to print, or where the path associated with a printed thing is not obvious, we'll print filenames. That is, unless we've been told not to do so with the --strict option. */ print_filenames = ((opt_state->depth > svn_depth_empty || targets->nelts > 1 || apr_hash_count(props) > 1 || opt_state->verbose) && (! opt_state->strict)); omit_newline = opt_state->strict; like_proplist = opt_state->verbose && !opt_state->strict; if (opt_state->xml) SVN_ERR(print_properties_xml(pname_utf8, props, subpool)); else SVN_ERR(print_properties(out, svn_path_is_url(target), pname_utf8, props, print_filenames, omit_newline, like_proplist, subpool)); } if (opt_state->xml) SVN_ERR(svn_cl__xml_print_footer("properties", subpool)); svn_pool_destroy(subpool); } 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); }
/* This implements the `svn_opt_subcommand_t' interface. */ svn_error_t * svn_cl__proplist(apr_getopt_t *os, void *baton, apr_pool_t *scratch_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; apr_array_header_t *targets; SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os, opt_state->targets, ctx, FALSE, scratch_pool)); /* Add "." if user passed 0 file arguments */ svn_opt_push_implicit_dot_target(targets, scratch_pool); if (opt_state->revprop) /* operate on revprops */ { svn_revnum_t rev; const char *URL; apr_hash_t *proplist; SVN_ERR(svn_cl__revprop_prepare(&opt_state->start_revision, targets, &URL, ctx, scratch_pool)); /* Let libsvn_client do the real work. */ SVN_ERR(svn_client_revprop_list(&proplist, URL, &(opt_state->start_revision), &rev, ctx, scratch_pool)); if (opt_state->xml) { svn_stringbuf_t *sb = NULL; char *revstr = apr_psprintf(scratch_pool, "%ld", rev); SVN_ERR(svn_cl__xml_print_header("properties", scratch_pool)); svn_xml_make_open_tag(&sb, scratch_pool, svn_xml_normal, "revprops", "rev", revstr, NULL); SVN_ERR(svn_cl__print_xml_prop_hash (&sb, proplist, (! opt_state->verbose), scratch_pool)); svn_xml_make_close_tag(&sb, scratch_pool, "revprops"); SVN_ERR(svn_cl__error_checked_fputs(sb->data, stdout)); SVN_ERR(svn_cl__xml_print_footer("properties", scratch_pool)); } else { SVN_ERR (svn_cmdline_printf(scratch_pool, _("Unversioned properties on revision %ld:\n"), rev)); SVN_ERR(svn_cl__print_prop_hash (NULL, proplist, (! opt_state->verbose), scratch_pool)); } } else /* operate on normal, versioned properties (not revprops) */ { int i; apr_pool_t *iterpool; svn_proplist_receiver_t pl_receiver; svn_boolean_t had_errors = FALSE; if (opt_state->xml) { SVN_ERR(svn_cl__xml_print_header("properties", scratch_pool)); pl_receiver = proplist_receiver_xml; } else { pl_receiver = proplist_receiver; } if (opt_state->depth == svn_depth_unknown) opt_state->depth = svn_depth_empty; iterpool = svn_pool_create(scratch_pool); for (i = 0; i < targets->nelts; i++) { const char *target = APR_ARRAY_IDX(targets, i, const char *); proplist_baton_t pl_baton; const char *truepath; svn_opt_revision_t peg_revision; svn_boolean_t success; svn_pool_clear(iterpool); SVN_ERR(svn_cl__check_cancel(ctx->cancel_baton)); pl_baton.is_url = svn_path_is_url(target); pl_baton.opt_state = opt_state; /* Check for a peg revision. */ SVN_ERR(svn_opt_parse_path(&peg_revision, &truepath, target, iterpool)); SVN_ERR(svn_cl__try( svn_client_proplist3(truepath, &peg_revision, &(opt_state->start_revision), opt_state->depth, opt_state->changelists, pl_receiver, &pl_baton, ctx, iterpool), &success, opt_state->quiet, SVN_ERR_UNVERSIONED_RESOURCE, SVN_ERR_ENTRY_NOT_FOUND, SVN_NO_ERROR)); if (!success) had_errors = TRUE; } svn_pool_destroy(iterpool); if (opt_state->xml) SVN_ERR(svn_cl__xml_print_footer("properties", scratch_pool)); /* Error out *after* we closed the XML element */ if (had_errors) return svn_error_create(SVN_ERR_ILLEGAL_TARGET, NULL, _("Could not display info for all targets " "because some targets don't exist")); } return SVN_NO_ERROR; }
/* This implements the `svn_opt_subcommand_t' interface. */ svn_error_t * svn_cl__blame(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; apr_pool_t *subpool; apr_array_header_t *targets; blame_baton_t bl; int i; svn_boolean_t end_revision_unspecified = FALSE; svn_diff_file_options_t *diff_options = svn_diff_file_options_create(pool); svn_boolean_t seen_nonexistent_target = FALSE; SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os, opt_state->targets, ctx, FALSE, pool)); /* Blame needs a file on which to operate. */ if (! targets->nelts) return svn_error_create(SVN_ERR_CL_INSUFFICIENT_ARGS, 0, NULL); if (opt_state->end_revision.kind == svn_opt_revision_unspecified) { if (opt_state->start_revision.kind != svn_opt_revision_unspecified) { /* In the case that -rX was specified, we actually want to set the range to be -r1:X. */ opt_state->end_revision = opt_state->start_revision; opt_state->start_revision.kind = svn_opt_revision_number; opt_state->start_revision.value.number = 1; } else end_revision_unspecified = TRUE; } if (opt_state->start_revision.kind == svn_opt_revision_unspecified) { opt_state->start_revision.kind = svn_opt_revision_number; opt_state->start_revision.value.number = 1; } /* The final conclusion from issue #2431 is that blame info is client output (unlike 'svn cat' which plainly cats the file), so the EOL style should be the platform local one. */ if (! opt_state->xml) SVN_ERR(svn_stream_for_stdout(&bl.out, pool)); else bl.sbuf = svn_stringbuf_create("", pool); bl.opt_state = opt_state; subpool = svn_pool_create(pool); if (opt_state->extensions) { apr_array_header_t *opts; opts = svn_cstring_split(opt_state->extensions, " \t\n\r", TRUE, pool); SVN_ERR(svn_diff_file_options_parse(diff_options, opts, pool)); } if (opt_state->xml) { if (opt_state->verbose) return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL, _("'verbose' option invalid in XML mode")); /* If output is not incremental, output the XML header and wrap everything in a top-level element. This makes the output in its entirety a well-formed XML document. */ if (! opt_state->incremental) SVN_ERR(svn_cl__xml_print_header("blame", pool)); } else { if (opt_state->incremental) return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL, _("'incremental' option only valid in XML " "mode")); } for (i = 0; i < targets->nelts; i++) { svn_error_t *err; const char *target = APR_ARRAY_IDX(targets, i, const char *); const char *truepath; svn_opt_revision_t peg_revision; svn_client_blame_receiver3_t receiver; svn_pool_clear(subpool); SVN_ERR(svn_cl__check_cancel(ctx->cancel_baton)); /* Check for a peg revision. */ SVN_ERR(svn_opt_parse_path(&peg_revision, &truepath, target, subpool)); if (end_revision_unspecified) { if (peg_revision.kind != svn_opt_revision_unspecified) opt_state->end_revision = peg_revision; else if (svn_path_is_url(target)) opt_state->end_revision.kind = svn_opt_revision_head; else opt_state->end_revision.kind = svn_opt_revision_working; } if (opt_state->xml) { /* "<target ...>" */ /* We don't output this tag immediately, which avoids creating a target element if this path is skipped. */ const char *outpath = truepath; if (! svn_path_is_url(target)) outpath = svn_dirent_local_style(truepath, subpool); svn_xml_make_open_tag(&bl.sbuf, pool, svn_xml_normal, "target", "path", outpath, NULL); receiver = blame_receiver_xml; } else receiver = blame_receiver; err = svn_client_blame5(truepath, &peg_revision, &opt_state->start_revision, &opt_state->end_revision, diff_options, opt_state->force, opt_state->use_merge_history, receiver, &bl, ctx, subpool); if (err) { if (err->apr_err == SVN_ERR_CLIENT_IS_BINARY_FILE) { svn_error_clear(err); SVN_ERR(svn_cmdline_fprintf(stderr, subpool, _("Skipping binary file: '%s'\n"), target)); } else if (err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND || err->apr_err == SVN_ERR_FS_NOT_FILE || err->apr_err == SVN_ERR_FS_NOT_FOUND) { svn_handle_warning2(stderr, err, "svn: "); svn_error_clear(err); err = NULL; seen_nonexistent_target = TRUE; } else { return svn_error_trace(err); } } else if (opt_state->xml) { /* "</target>" */ svn_xml_make_close_tag(&(bl.sbuf), pool, "target"); SVN_ERR(svn_cl__error_checked_fputs(bl.sbuf->data, stdout)); } if (opt_state->xml) svn_stringbuf_setempty(bl.sbuf); } svn_pool_destroy(subpool); if (opt_state->xml && ! opt_state->incremental) SVN_ERR(svn_cl__xml_print_footer("blame", pool)); if (seen_nonexistent_target) return svn_error_create( SVN_ERR_ILLEGAL_TARGET, NULL, _("Could not perform blame on all targets because some " "targets don't exist")); else return SVN_NO_ERROR; }
/* This implements the `svn_opt_subcommand_t' interface. */ svn_error_t * svn_cl__copy(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; apr_array_header_t *targets, *sources; const char *src_path, *dst_path; svn_boolean_t srcs_are_urls, dst_is_url; svn_commit_info_t *commit_info = NULL; svn_error_t *err; int i; SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os, opt_state->targets, ctx, pool)); if (targets->nelts < 2) return svn_error_create(SVN_ERR_CL_INSUFFICIENT_ARGS, 0, NULL); /* Get the src list and associated peg revs */ sources = apr_array_make(pool, targets->nelts - 1, sizeof(svn_client_copy_source_t *)); for (i = 0; i < (targets->nelts - 1); i++) { const char *target = APR_ARRAY_IDX(targets, i, const char *); svn_client_copy_source_t *source = apr_palloc(pool, sizeof(*source)); const char *src; svn_opt_revision_t *peg_revision = apr_palloc(pool, sizeof(*peg_revision)); SVN_ERR(svn_opt_parse_path(peg_revision, &src, target, pool)); source->path = src; source->revision = &(opt_state->start_revision); source->peg_revision = peg_revision; APR_ARRAY_PUSH(sources, svn_client_copy_source_t *) = source; } SVN_ERR(svn_opt__eat_peg_revisions(&targets, targets, pool)); /* Figure out which type of trace editor to use. If the src_paths are not homogeneous, setup_copy will return an error. */ src_path = APR_ARRAY_IDX(targets, 0, const char *); srcs_are_urls = svn_path_is_url(src_path); dst_path = APR_ARRAY_IDX(targets, targets->nelts - 1, const char *); apr_array_pop(targets); dst_is_url = svn_path_is_url(dst_path); if ((! srcs_are_urls) && (! dst_is_url)) { /* WC->WC */ if (! opt_state->quiet) svn_cl__get_notifier(&ctx->notify_func2, &ctx->notify_baton2, FALSE, FALSE, FALSE, pool); } else if ((! srcs_are_urls) && (dst_is_url)) { /* WC->URL : Use notification. */ /* ### todo: We'd like to use the notifier, but we MAY have a couple of problems with that, the same problems that used to apply to the old trace_editor: 1) We don't know where the commit editor for this case will be anchored with respect to the repository, so we can't use the DST_URL. 2) While we do know where the commit editor will be driven from with respect to our working copy, we don't know what basenames will be chosen for our committed things. So a copy of dir1/foo.c to http://.../dir2/foo-copy-c would display like: "Adding dir1/foo-copy.c", which could be a bogus path. */ } else if ((srcs_are_urls) && (! dst_is_url)) { /* URL->WC : Use checkout-style notification. */ if (! opt_state->quiet) svn_cl__get_notifier(&ctx->notify_func2, &ctx->notify_baton2, TRUE, FALSE, FALSE, pool); } /* else URL -> URL, meaning that no notification is needed. */ if (! dst_is_url) { ctx->log_msg_func3 = NULL; if (opt_state->message || opt_state->filedata || opt_state->revprop_table) return svn_error_create (SVN_ERR_CL_UNNECESSARY_LOG_MESSAGE, NULL, _("Local, non-commit operations do not take a log message " "or revision properties")); } if (ctx->log_msg_func3) SVN_ERR(svn_cl__make_log_msg_baton(&(ctx->log_msg_baton3), opt_state, NULL, ctx->config, pool)); err = svn_client_copy5(&commit_info, sources, dst_path, TRUE, opt_state->parents, opt_state->ignore_externals, opt_state->revprop_table, ctx, pool); if (ctx->log_msg_func3) SVN_ERR(svn_cl__cleanup_log_msg(ctx->log_msg_baton3, err, pool)); else if (err) return err; if (commit_info && ! opt_state->quiet) SVN_ERR(svn_cl__print_commit_info(commit_info, pool)); return SVN_NO_ERROR; }
/* This implements the `svn_opt_subcommand_t' interface. */ svn_error_t * svn_cl__copy(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; apr_array_header_t *targets, *sources; const char *src_path, *dst_path; svn_boolean_t srcs_are_urls, dst_is_url; svn_error_t *err; int i; SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os, opt_state->targets, ctx, FALSE, pool)); if (targets->nelts < 2) return svn_error_create(SVN_ERR_CL_INSUFFICIENT_ARGS, 0, NULL); /* Get the src list and associated peg revs */ sources = apr_array_make(pool, targets->nelts - 1, sizeof(svn_client_copy_source_t *)); for (i = 0; i < (targets->nelts - 1); i++) { const char *target = APR_ARRAY_IDX(targets, i, const char *); svn_client_copy_source_t *source = apr_palloc(pool, sizeof(*source)); const char *src; svn_opt_revision_t *peg_revision = apr_palloc(pool, sizeof(*peg_revision)); SVN_ERR(svn_opt_parse_path(peg_revision, &src, target, pool)); source->path = src; source->revision = &(opt_state->start_revision); source->peg_revision = peg_revision; APR_ARRAY_PUSH(sources, svn_client_copy_source_t *) = source; } SVN_ERR(svn_cl__eat_peg_revisions(&targets, targets, pool)); /* Figure out which type of notification to use. (There is no need to check that the src paths are homogeneous; svn_client_copy6() through its subroutine try_copy() will return an error if they are not.) */ src_path = APR_ARRAY_IDX(targets, 0, const char *); srcs_are_urls = svn_path_is_url(src_path); dst_path = APR_ARRAY_IDX(targets, targets->nelts - 1, const char *); apr_array_pop(targets); dst_is_url = svn_path_is_url(dst_path); if ((! srcs_are_urls) && (! dst_is_url)) { /* WC->WC */ } else if ((! srcs_are_urls) && (dst_is_url)) { /* WC->URL : Use notification. */ if (! opt_state->quiet) SVN_ERR(svn_cl__notifier_mark_wc_to_repos_copy(ctx->notify_baton2)); } else if ((srcs_are_urls) && (! dst_is_url)) { /* URL->WC : Use checkout-style notification. */ if (! opt_state->quiet) SVN_ERR(svn_cl__notifier_mark_checkout(ctx->notify_baton2)); } else { /* URL -> URL, meaning that no notification is needed. */ ctx->notify_func2 = NULL; } if (! dst_is_url) { ctx->log_msg_func3 = NULL; if (opt_state->message || opt_state->filedata || opt_state->revprop_table) return svn_error_create (SVN_ERR_CL_UNNECESSARY_LOG_MESSAGE, NULL, _("Local, non-commit operations do not take a log message " "or revision properties")); } if (ctx->log_msg_func3) SVN_ERR(svn_cl__make_log_msg_baton(&(ctx->log_msg_baton3), opt_state, NULL, ctx->config, pool)); err = svn_client_copy6(sources, dst_path, TRUE, opt_state->parents, opt_state->ignore_externals, opt_state->revprop_table, svn_cl__print_commit_info, NULL, ctx, pool); if (ctx->log_msg_func3) SVN_ERR(svn_cl__cleanup_log_msg(ctx->log_msg_baton3, err, pool)); else if (err) return svn_error_trace(err); return SVN_NO_ERROR; }
/* This implements the `svn_opt_subcommand_t' interface. */ svn_error_t * svn_cl__propdel(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 *pname, *pname_utf8; apr_array_header_t *args, *targets; int i; /* Get the property's name (and a UTF-8 version of that name). */ SVN_ERR(svn_opt_parse_num_args(&args, os, 1, pool)); pname = APR_ARRAY_IDX(args, 0, const char *); SVN_ERR(svn_utf_cstring_to_utf8(&pname_utf8, pname, pool)); /* No need to check svn_prop_name_is_valid for *deleting* properties, and it may even be useful to allow, in case invalid properties sneaked through somehow. */ SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os, opt_state->targets, pool)); /* Add "." if user passed 0 file arguments */ svn_opt_push_implicit_dot_target(targets, pool); if (opt_state->revprop) /* operate on a revprop */ { svn_revnum_t rev; const char *URL; SVN_ERR(svn_cl__revprop_prepare(&opt_state->start_revision, targets, &URL, pool)); /* Let libsvn_client do the real work. */ SVN_ERR(svn_client_revprop_set(pname_utf8, NULL, URL, &(opt_state->start_revision), &rev, FALSE, ctx, pool)); if (! opt_state->quiet) { SVN_ERR(svn_cmdline_printf(pool, _("property '%s' deleted from" " repository revision %ld\n"), pname_utf8, rev)); } } else if (opt_state->start_revision.kind != svn_opt_revision_unspecified) { return svn_error_createf (SVN_ERR_CL_ARG_PARSING_ERROR, NULL, _("Cannot specify revision for deleting versioned property '%s'"), pname); } else /* operate on a normal, versioned property (not a revprop) */ { apr_pool_t *subpool = svn_pool_create(pool); if (opt_state->depth == svn_depth_unknown) opt_state->depth = svn_depth_empty; /* For each target, remove the property PNAME. */ for (i = 0; i < targets->nelts; i++) { const char *target = APR_ARRAY_IDX(targets, i, const char *); svn_commit_info_t *commit_info; svn_boolean_t success; svn_pool_clear(subpool); SVN_ERR(svn_cl__check_cancel(ctx->cancel_baton)); /* Pass FALSE for 'skip_checks' because it doesn't matter here, and opt_state->force doesn't apply to this command anyway. */ SVN_ERR(svn_cl__try(svn_client_propset3 (&commit_info, pname_utf8, NULL, target, opt_state->depth, FALSE, SVN_INVALID_REVNUM, opt_state->changelists, NULL, ctx, subpool), &success, opt_state->quiet, SVN_ERR_UNVERSIONED_RESOURCE, SVN_ERR_ENTRY_NOT_FOUND, SVN_NO_ERROR)); if (success && (! opt_state->quiet)) { SVN_ERR(svn_cmdline_printf (subpool, SVN_DEPTH_IS_RECURSIVE(opt_state->depth) ? _("property '%s' deleted (recursively) from '%s'.\n") : _("property '%s' deleted from '%s'.\n"), pname_utf8, svn_path_local_style(target, subpool))); } } svn_pool_destroy(subpool); } return SVN_NO_ERROR; }
/* This implements the `svn_opt_subcommand_t' interface. */ svn_error_t * svn_cl__null_blame(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; apr_pool_t *iterpool; apr_array_header_t *targets; int i; svn_boolean_t end_revision_unspecified = FALSE; svn_boolean_t seen_nonexistent_target = FALSE; SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os, opt_state->targets, ctx, FALSE, pool)); /* Blame needs a file on which to operate. */ if (! targets->nelts) return svn_error_create(SVN_ERR_CL_INSUFFICIENT_ARGS, 0, NULL); if (opt_state->end_revision.kind == svn_opt_revision_unspecified) { if (opt_state->start_revision.kind != svn_opt_revision_unspecified) { /* In the case that -rX was specified, we actually want to set the range to be -r1:X. */ opt_state->end_revision = opt_state->start_revision; opt_state->start_revision.kind = svn_opt_revision_number; opt_state->start_revision.value.number = 1; } else end_revision_unspecified = TRUE; } if (opt_state->start_revision.kind == svn_opt_revision_unspecified) { opt_state->start_revision.kind = svn_opt_revision_number; opt_state->start_revision.value.number = 1; } /* The final conclusion from issue #2431 is that blame info is client output (unlike 'svn cat' which plainly cats the file), so the EOL style should be the platform local one. */ iterpool = svn_pool_create(pool); for (i = 0; i < targets->nelts; i++) { svn_error_t *err; const char *target = APR_ARRAY_IDX(targets, i, const char *); const char *parsed_path; svn_opt_revision_t peg_revision; svn_pool_clear(iterpool); SVN_ERR(svn_cl__check_cancel(ctx->cancel_baton)); /* Check for a peg revision. */ SVN_ERR(svn_opt_parse_path(&peg_revision, &parsed_path, target, iterpool)); if (end_revision_unspecified) { if (peg_revision.kind != svn_opt_revision_unspecified) opt_state->end_revision = peg_revision; else if (svn_path_is_url(target)) opt_state->end_revision.kind = svn_opt_revision_head; else opt_state->end_revision.kind = svn_opt_revision_working; } err = bench_null_blame(parsed_path, &peg_revision, &opt_state->start_revision, &opt_state->end_revision, opt_state->use_merge_history, opt_state->quiet, ctx, iterpool); if (err) { if (err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND || err->apr_err == SVN_ERR_ENTRY_NOT_FOUND || err->apr_err == SVN_ERR_FS_NOT_FILE || err->apr_err == SVN_ERR_FS_NOT_FOUND) { svn_handle_warning2(stderr, err, "svn: "); svn_error_clear(err); err = NULL; seen_nonexistent_target = TRUE; } else { return svn_error_trace(err); } } } svn_pool_destroy(iterpool); if (seen_nonexistent_target) return svn_error_create( SVN_ERR_ILLEGAL_TARGET, NULL, _("Could not perform blame on all targets because some " "targets don't exist")); else return SVN_NO_ERROR; }
/* This implements the `svn_opt_subcommand_t' interface. */ svn_error_t * svn_cl__resolve(apr_getopt_t *os, void *baton, apr_pool_t *scratch_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; svn_wc_conflict_choice_t conflict_choice; svn_error_t *err; apr_array_header_t *targets; int i; apr_pool_t *iterpool; svn_boolean_t had_error = FALSE; switch (opt_state->accept_which) { case svn_cl__accept_working: conflict_choice = svn_wc_conflict_choose_merged; break; case svn_cl__accept_base: conflict_choice = svn_wc_conflict_choose_base; break; case svn_cl__accept_theirs_conflict: conflict_choice = svn_wc_conflict_choose_theirs_conflict; break; case svn_cl__accept_mine_conflict: conflict_choice = svn_wc_conflict_choose_mine_conflict; break; case svn_cl__accept_theirs_full: conflict_choice = svn_wc_conflict_choose_theirs_full; break; case svn_cl__accept_mine_full: conflict_choice = svn_wc_conflict_choose_mine_full; break; case svn_cl__accept_unspecified: if (opt_state->non_interactive) return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL, _("missing --accept option")); conflict_choice = svn_wc_conflict_choose_unspecified; break; default: return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL, _("invalid 'accept' ARG")); } SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os, opt_state->targets, ctx, FALSE, scratch_pool)); if (! targets->nelts) svn_opt_push_implicit_dot_target(targets, scratch_pool); if (opt_state->depth == svn_depth_unknown) { if (opt_state->accept_which == svn_cl__accept_unspecified) opt_state->depth = svn_depth_infinity; else opt_state->depth = svn_depth_empty; } SVN_ERR(svn_cl__eat_peg_revisions(&targets, targets, scratch_pool)); SVN_ERR(svn_cl__check_targets_are_local_paths(targets)); iterpool = svn_pool_create(scratch_pool); for (i = 0; i < targets->nelts; i++) { const char *target = APR_ARRAY_IDX(targets, i, const char *); svn_pool_clear(iterpool); SVN_ERR(svn_cl__check_cancel(ctx->cancel_baton)); err = svn_client_resolve(target, opt_state->depth, conflict_choice, ctx, iterpool); if (err) { svn_handle_warning2(stderr, err, "svn: "); svn_error_clear(err); had_error = TRUE; } } svn_pool_destroy(iterpool); if (had_error) return svn_error_create(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL, _("Failure occurred resolving one or more " "conflicts")); 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; SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os, opt_state->targets, ctx, 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) to = svn_path_uri_decode(svn_path_basename(truefrom, pool), pool); else to = APR_ARRAY_IDX(targets, 1, const char *); SVN_ERR(svn_opt__split_arg_at_peg_revision(&to, NULL, to, pool)); if (! opt_state->quiet) svn_cl__get_notifier(&ctx->notify_func2, &ctx->notify_baton2, FALSE, TRUE, FALSE, pool); if (opt_state->depth == svn_depth_unknown) opt_state->depth = svn_depth_infinity; /* Decode the partially encoded URL and escape all URL unsafe characters. */ if (svn_path_is_url(truefrom)) truefrom = svn_path_uri_encode(svn_path_uri_decode(truefrom, pool), pool); /* Do the export. */ err = svn_client_export4(NULL, truefrom, to, &peg_revision, &(opt_state->start_revision), opt_state->force, opt_state->ignore_externals, 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")); return err; }
/* This implements the `svn_opt_subcommand_t' interface. */ svn_error_t * svn_cl__resolve(apr_getopt_t *os, void *baton, apr_pool_t *scratch_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; svn_wc_conflict_choice_t conflict_choice; svn_error_t *err; apr_array_header_t *targets; int i; apr_pool_t *iterpool; switch (opt_state->accept_which) { case svn_cl__accept_working: conflict_choice = svn_wc_conflict_choose_merged; break; case svn_cl__accept_base: conflict_choice = svn_wc_conflict_choose_base; break; case svn_cl__accept_theirs_conflict: conflict_choice = svn_wc_conflict_choose_theirs_conflict; break; case svn_cl__accept_mine_conflict: conflict_choice = svn_wc_conflict_choose_mine_conflict; break; case svn_cl__accept_theirs_full: conflict_choice = svn_wc_conflict_choose_theirs_full; break; case svn_cl__accept_mine_full: conflict_choice = svn_wc_conflict_choose_mine_full; break; case svn_cl__accept_unspecified: return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL, _("missing --accept option")); default: return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL, _("invalid 'accept' ARG")); } SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os, opt_state->targets, ctx, FALSE, scratch_pool)); if (! targets->nelts) return svn_error_create(SVN_ERR_CL_INSUFFICIENT_ARGS, 0, NULL); if (opt_state->depth == svn_depth_unknown) opt_state->depth = svn_depth_empty; SVN_ERR(svn_cl__eat_peg_revisions(&targets, targets, scratch_pool)); SVN_ERR(svn_cl__check_targets_are_local_paths(targets)); iterpool = svn_pool_create(scratch_pool); for (i = 0; i < targets->nelts; i++) { const char *target = APR_ARRAY_IDX(targets, i, const char *); svn_pool_clear(iterpool); SVN_ERR(svn_cl__check_cancel(ctx->cancel_baton)); err = svn_client_resolve(target, opt_state->depth, conflict_choice, ctx, iterpool); if (err) { svn_handle_warning2(stderr, err, "svn: "); svn_error_clear(err); } } svn_pool_destroy(iterpool); return SVN_NO_ERROR; }
/* This implements the `svn_opt_subcommand_t' interface. */ svn_error_t * svn_cl__list(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; apr_array_header_t *targets; int i; apr_pool_t *subpool = svn_pool_create(pool); apr_uint32_t dirent_fields; struct print_baton pb; svn_boolean_t seen_nonexistent_target = FALSE; svn_error_t *err; SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os, opt_state->targets, ctx, FALSE, pool)); /* Add "." if user passed 0 arguments */ svn_opt_push_implicit_dot_target(targets, pool); if (opt_state->xml) { /* The XML output contains all the information, so "--verbose" does not apply. */ if (opt_state->verbose) return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL, _("'verbose' option invalid in XML mode")); /* If output is not incremental, output the XML header and wrap everything in a top-level element. This makes the output in its entirety a well-formed XML document. */ if (! opt_state->incremental) SVN_ERR(svn_cl__xml_print_header("lists", pool)); } else { if (opt_state->incremental) return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL, _("'incremental' option only valid in XML " "mode")); } if (opt_state->verbose || opt_state->xml) dirent_fields = SVN_DIRENT_ALL; else dirent_fields = SVN_DIRENT_KIND; /* the only thing we actually need... */ pb.ctx = ctx; pb.verbose = opt_state->verbose; if (opt_state->depth == svn_depth_unknown) opt_state->depth = svn_depth_immediates; /* For each target, try to list it. */ for (i = 0; i < targets->nelts; i++) { const char *target = APR_ARRAY_IDX(targets, i, const char *); const char *truepath; svn_opt_revision_t peg_revision; svn_pool_clear(subpool); SVN_ERR(svn_cl__check_cancel(ctx->cancel_baton)); /* Get peg revisions. */ SVN_ERR(svn_opt_parse_path(&peg_revision, &truepath, target, subpool)); if (opt_state->xml) { svn_stringbuf_t *sb = svn_stringbuf_create("", pool); svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "list", "path", truepath[0] == '\0' ? "." : truepath, NULL); SVN_ERR(svn_cl__error_checked_fputs(sb->data, stdout)); } err = svn_client_list2(truepath, &peg_revision, &(opt_state->start_revision), opt_state->depth, dirent_fields, (opt_state->xml || opt_state->verbose), opt_state->xml ? print_dirent_xml : print_dirent, &pb, ctx, subpool); if (err) { /* If one of the targets is a non-existent URL or wc-entry, don't bail out. Just warn and move on to the next target. */ if (err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND || err->apr_err == SVN_ERR_FS_NOT_FOUND) svn_handle_warning2(stderr, err, "svn: "); else return svn_error_trace(err); svn_error_clear(err); err = NULL; seen_nonexistent_target = TRUE; } if (opt_state->xml) { svn_stringbuf_t *sb = svn_stringbuf_create("", pool); svn_xml_make_close_tag(&sb, pool, "list"); SVN_ERR(svn_cl__error_checked_fputs(sb->data, stdout)); } } svn_pool_destroy(subpool); if (opt_state->xml && ! opt_state->incremental) SVN_ERR(svn_cl__xml_print_footer("lists", pool)); if (seen_nonexistent_target) return svn_error_create( SVN_ERR_ILLEGAL_TARGET, NULL, _("Could not list all targets because some targets don't exist")); else return SVN_NO_ERROR; }
/* This implements the `svn_opt_subcommand_t' interface. */ svn_error_t * svn_cl__status(apr_getopt_t *os, void *baton, apr_pool_t *scratch_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; apr_array_header_t *targets; apr_pool_t *iterpool; apr_hash_t *master_cl_hash = apr_hash_make(scratch_pool); int i; svn_opt_revision_t rev; struct status_baton sb; SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os, opt_state->targets, ctx, FALSE, scratch_pool)); /* Add "." if user passed 0 arguments */ svn_opt_push_implicit_dot_target(targets, scratch_pool); SVN_ERR(svn_cl__check_targets_are_local_paths(targets)); /* We want our -u statuses to be against HEAD by default. */ if (opt_state->start_revision.kind == svn_opt_revision_unspecified) rev.kind = svn_opt_revision_head; else if (! opt_state->update) return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL, _("--revision (-r) option valid only with " "--show-updates (-u) option")); else rev = opt_state->start_revision; sb.had_print_error = FALSE; if (opt_state->xml) { /* If output is not incremental, output the XML header and wrap everything in a top-level element. This makes the output in its entirety a well-formed XML document. */ if (! opt_state->incremental) SVN_ERR(svn_cl__xml_print_header("status", scratch_pool)); } else { if (opt_state->incremental) return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL, _("'incremental' option only valid in XML " "mode")); } sb.suppress_externals_placeholders = (opt_state->quiet && (! opt_state->verbose)); sb.detailed = (opt_state->verbose || opt_state->update); sb.show_last_committed = opt_state->verbose; sb.skip_unrecognized = opt_state->quiet; sb.repos_locks = opt_state->update; sb.xml_mode = opt_state->xml; sb.cached_changelists = master_cl_hash; sb.cl_pool = scratch_pool; sb.text_conflicts = 0; sb.prop_conflicts = 0; sb.tree_conflicts = 0; sb.ctx = ctx; SVN_ERR(svn_cl__eat_peg_revisions(&targets, targets, scratch_pool)); iterpool = svn_pool_create(scratch_pool); for (i = 0; i < targets->nelts; i++) { const char *target = APR_ARRAY_IDX(targets, i, const char *); svn_revnum_t repos_rev = SVN_INVALID_REVNUM; svn_pool_clear(iterpool); SVN_ERR(svn_dirent_get_absolute(&(sb.target_abspath), target, scratch_pool)); sb.target_path = target; SVN_ERR(svn_cl__check_cancel(ctx->cancel_baton)); if (opt_state->xml) SVN_ERR(print_start_target_xml(svn_dirent_local_style(target, iterpool), iterpool)); /* Retrieve a hash of status structures with the information requested by the user. */ SVN_ERR(svn_cl__try(svn_client_status6(&repos_rev, ctx, target, &rev, opt_state->depth, opt_state->verbose, opt_state->update, TRUE /* check_working_copy */, opt_state->no_ignore, opt_state->ignore_externals, FALSE /* depth_as_sticky */, opt_state->changelists, print_status, &sb, iterpool), NULL, opt_state->quiet, /* not versioned: */ SVN_ERR_WC_NOT_WORKING_COPY, SVN_ERR_WC_PATH_NOT_FOUND, 0)); if (opt_state->xml) SVN_ERR(print_finish_target_xml(repos_rev, iterpool)); } /* If any paths were cached because they were associated with changelists, we can now display them as grouped changelists. */ if (apr_hash_count(master_cl_hash) > 0) { apr_hash_index_t *hi; svn_stringbuf_t *buf; if (opt_state->xml) buf = svn_stringbuf_create_empty(scratch_pool); for (hi = apr_hash_first(scratch_pool, master_cl_hash); hi; hi = apr_hash_next(hi)) { const char *changelist_name = apr_hash_this_key(hi); apr_array_header_t *path_array = apr_hash_this_val(hi); int j; /* ### TODO: For non-XML output, we shouldn't print the ### leading \n on the first changelist if there were no ### non-changelist entries. */ if (opt_state->xml) { svn_stringbuf_setempty(buf); svn_xml_make_open_tag(&buf, scratch_pool, svn_xml_normal, "changelist", "name", changelist_name, SVN_VA_NULL); SVN_ERR(svn_cl__error_checked_fputs(buf->data, stdout)); } else SVN_ERR(svn_cmdline_printf(scratch_pool, _("\n--- Changelist '%s':\n"), changelist_name)); for (j = 0; j < path_array->nelts; j++) { struct status_cache *scache = APR_ARRAY_IDX(path_array, j, struct status_cache *); sb.target_abspath = scache->target_abspath; sb.target_path = scache->target_path; SVN_ERR(print_status_normal_or_xml(&sb, scache->path, scache->status, scratch_pool)); } if (opt_state->xml) { svn_stringbuf_setempty(buf); svn_xml_make_close_tag(&buf, scratch_pool, "changelist"); SVN_ERR(svn_cl__error_checked_fputs(buf->data, stdout)); } } }
/* This implements the `svn_opt_subcommand_t' interface. */ svn_error_t * svn_cl__log(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; apr_array_header_t *targets; struct log_receiver_baton lb; const char *target; int i; svn_opt_revision_t peg_revision; const char *true_path; apr_array_header_t *revprops; if (!opt_state->xml) { if (opt_state->all_revprops) return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL, _("'with-all-revprops' option only valid in" " XML mode")); if (opt_state->revprop_table != NULL) return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL, _("'with-revprop' option only valid in" " XML mode")); } SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os, opt_state->targets, pool)); /* Add "." if user passed 0 arguments */ svn_opt_push_implicit_dot_target(targets, pool); target = APR_ARRAY_IDX(targets, 0, const char *); /* Determine if they really want a two-revision range. */ if (opt_state->used_change_arg) { if (opt_state->start_revision.value.number < opt_state->end_revision.value.number) opt_state->start_revision = opt_state->end_revision; else opt_state->end_revision = opt_state->start_revision; } /* Strip peg revision if targets contains an URI. */ SVN_ERR(svn_opt_parse_path(&peg_revision, &true_path, target, pool)); APR_ARRAY_IDX(targets, 0, const char *) = true_path; if ((opt_state->start_revision.kind != svn_opt_revision_unspecified) && (opt_state->end_revision.kind == svn_opt_revision_unspecified)) { /* If the user specified exactly one revision, then start rev is set but end is not. We show the log message for just that revision by making end equal to start. Note that if the user requested a single dated revision, then this will cause the same date to be resolved twice. The extra code complexity to get around this slight inefficiency doesn't seem worth it, however. */ opt_state->end_revision = opt_state->start_revision; } else if (opt_state->start_revision.kind == svn_opt_revision_unspecified) { /* Default to any specified peg revision. Otherwise, if the first target is an URL, then we default to HEAD:0. Lastly, the default is BASE:0 since WC@HEAD may not exist. */ if (peg_revision.kind == svn_opt_revision_unspecified) { if (svn_path_is_url(target)) opt_state->start_revision.kind = svn_opt_revision_head; else opt_state->start_revision.kind = svn_opt_revision_base; } else opt_state->start_revision = peg_revision; if (opt_state->end_revision.kind == svn_opt_revision_unspecified) { opt_state->end_revision.kind = svn_opt_revision_number; opt_state->end_revision.value.number = 0; } } if (svn_path_is_url(target)) { for (i = 1; i < targets->nelts; i++) { target = APR_ARRAY_IDX(targets, i, const char *); if (svn_path_is_url(target)) return svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL, _("Only relative paths can be specified " "after a URL")); } } lb.cancel_func = ctx->cancel_func; lb.cancel_baton = ctx->cancel_baton; lb.omit_log_message = opt_state->quiet; lb.merge_stack = apr_array_make(pool, 0, sizeof(svn_revnum_t)); lb.pool = pool; if (! opt_state->quiet) svn_cl__get_notifier(&ctx->notify_func2, &ctx->notify_baton2, FALSE, FALSE, FALSE, pool); if (opt_state->xml) { /* If output is not incremental, output the XML header and wrap everything in a top-level element. This makes the output in its entirety a well-formed XML document. */ if (! opt_state->incremental) SVN_ERR(svn_cl__xml_print_header("log", pool)); if (opt_state->all_revprops) revprops = NULL; else if (opt_state->revprop_table != NULL) { apr_hash_index_t *hi; revprops = apr_array_make(pool, apr_hash_count(opt_state->revprop_table), sizeof(char *)); for (hi = apr_hash_first(pool, opt_state->revprop_table); hi != NULL; hi = apr_hash_next(hi)) { char *property; svn_string_t *value; apr_hash_this(hi, (void *)&property, NULL, (void *)&value); if (value && value->data[0] != '\0') return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL, _("cannot assign with 'with-revprop'" " option (drop the '=')")); APR_ARRAY_PUSH(revprops, char *) = property; } } else { revprops = apr_array_make(pool, 3, sizeof(char *)); APR_ARRAY_PUSH(revprops, const char *) = SVN_PROP_REVISION_AUTHOR; APR_ARRAY_PUSH(revprops, const char *) = SVN_PROP_REVISION_DATE; if (!opt_state->quiet) APR_ARRAY_PUSH(revprops, const char *) = SVN_PROP_REVISION_LOG; } SVN_ERR(svn_client_log4(targets, &peg_revision, &(opt_state->start_revision), &(opt_state->end_revision), opt_state->limit, opt_state->verbose, opt_state->stop_on_copy, opt_state->use_merge_history, revprops, log_entry_receiver_xml, &lb, ctx, pool)); if (! opt_state->incremental) SVN_ERR(svn_cl__xml_print_footer("log", pool)); } else /* default output format */ { revprops = apr_array_make(pool, 3, sizeof(char *)); APR_ARRAY_PUSH(revprops, const char *) = SVN_PROP_REVISION_AUTHOR; APR_ARRAY_PUSH(revprops, const char *) = SVN_PROP_REVISION_DATE; if (!opt_state->quiet) APR_ARRAY_PUSH(revprops, const char *) = SVN_PROP_REVISION_LOG; SVN_ERR(svn_client_log4(targets, &peg_revision, &(opt_state->start_revision), &(opt_state->end_revision), opt_state->limit, opt_state->verbose, opt_state->stop_on_copy, opt_state->use_merge_history, revprops, log_entry_receiver, &lb, ctx, pool)); if (! opt_state->incremental) SVN_ERR(svn_cmdline_printf(pool, SEP_STRING)); } return SVN_NO_ERROR; }
/* This implements the `svn_opt_subcommand_t' interface. */ svn_error_t * svn_cl__status(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; apr_array_header_t *targets; apr_pool_t *subpool; apr_hash_t *master_cl_hash = apr_hash_make(pool); int i; svn_opt_revision_t rev; struct status_baton sb; SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os, opt_state->targets, ctx, pool)); /* Add "." if user passed 0 arguments */ svn_opt_push_implicit_dot_target(targets, pool); /* We want our -u statuses to be against HEAD. */ rev.kind = svn_opt_revision_head; /* The notification callback, leave the notifier as NULL in XML mode */ if (! opt_state->xml) svn_cl__get_notifier(&ctx->notify_func2, &ctx->notify_baton2, FALSE, FALSE, FALSE, pool); subpool = svn_pool_create(pool); sb.had_print_error = FALSE; if (opt_state->xml) { /* If output is not incremental, output the XML header and wrap everything in a top-level element. This makes the output in its entirety a well-formed XML document. */ if (! opt_state->incremental) SVN_ERR(svn_cl__xml_print_header("status", pool)); } else { if (opt_state->incremental) return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL, _("'incremental' option only valid in XML " "mode")); } sb.detailed = (opt_state->verbose || opt_state->update); sb.show_last_committed = opt_state->verbose; sb.skip_unrecognized = opt_state->quiet; sb.repos_locks = opt_state->update; sb.xml_mode = opt_state->xml; sb.cached_changelists = master_cl_hash; sb.cl_pool = pool; SVN_ERR(svn_opt__eat_peg_revisions(&targets, targets, pool)); for (i = 0; i < targets->nelts; i++) { const char *target = APR_ARRAY_IDX(targets, i, const char *); svn_revnum_t repos_rev = SVN_INVALID_REVNUM; svn_pool_clear(subpool); SVN_ERR(svn_cl__check_cancel(ctx->cancel_baton)); if (opt_state->xml) SVN_ERR(print_start_target_xml(svn_path_local_style(target, subpool), subpool)); /* Retrieve a hash of status structures with the information requested by the user. */ SVN_ERR(svn_cl__try(svn_client_status4(&repos_rev, target, &rev, print_status, &sb, opt_state->depth, opt_state->verbose, opt_state->update, opt_state->no_ignore, opt_state->ignore_externals, opt_state->changelists, ctx, subpool), NULL, opt_state->quiet, /* not versioned: */ SVN_ERR_WC_NOT_DIRECTORY, SVN_NO_ERROR)); if (opt_state->xml) SVN_ERR(print_finish_target_xml(repos_rev, subpool)); } /* If any paths were cached because they were associatied with changelists, we can now display them as grouped changelists. */ if (apr_hash_count(master_cl_hash) > 0) { apr_hash_index_t *hi; svn_stringbuf_t *buf; if (opt_state->xml) buf = svn_stringbuf_create("", pool); for (hi = apr_hash_first(pool, master_cl_hash); hi; hi = apr_hash_next(hi)) { const char *changelist_name; apr_array_header_t *path_array; const void *key; void *val; int j; apr_hash_this(hi, &key, NULL, &val); changelist_name = key; path_array = val; /* ### TODO: For non-XML output, we shouldn't print the ### leading \n on the first changelist if there were no ### non-changelist entries. */ if (opt_state->xml) { svn_stringbuf_set(buf, ""); svn_xml_make_open_tag(&buf, pool, svn_xml_normal, "changelist", "name", changelist_name, NULL); SVN_ERR(svn_cl__error_checked_fputs(buf->data, stdout)); } else SVN_ERR(svn_cmdline_printf(pool, _("\n--- Changelist '%s':\n"), changelist_name)); for (j = 0; j < path_array->nelts; j++) { struct status_cache *scache = APR_ARRAY_IDX(path_array, j, struct status_cache *); SVN_ERR(print_status_normal_or_xml(&sb, scache->path, scache->status, pool)); } if (opt_state->xml) { svn_stringbuf_set(buf, ""); svn_xml_make_close_tag(&buf, pool, "changelist"); SVN_ERR(svn_cl__error_checked_fputs(buf->data, stdout)); } } }
/* This implements the `svn_opt_subcommand_t' interface. */ svn_error_t * svn_cl__propset(apr_getopt_t *os, void *baton, apr_pool_t *scratch_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 *pname; svn_string_t *propval = NULL; svn_boolean_t propval_came_from_cmdline; apr_array_header_t *args, *targets; /* PNAME and PROPVAL expected as first 2 arguments if filedata was NULL, else PNAME alone will precede the targets. Get a UTF-8 version of the name, too. */ SVN_ERR(svn_opt_parse_num_args(&args, os, opt_state->filedata ? 1 : 2, scratch_pool)); pname = APR_ARRAY_IDX(args, 0, const char *); SVN_ERR(svn_utf_cstring_to_utf8(&pname, pname, scratch_pool)); if (! svn_prop_name_is_valid(pname)) return svn_error_createf(SVN_ERR_CLIENT_PROPERTY_NAME, NULL, _("'%s' is not a valid Subversion property name"), pname); if (!opt_state->force) SVN_ERR(svn_cl__check_svn_prop_name(pname, opt_state->revprop, svn_cl__prop_use_set, scratch_pool)); /* Get the PROPVAL from either an external file, or from the command line. */ if (opt_state->filedata) { propval = svn_string_create_from_buf(opt_state->filedata, scratch_pool); propval_came_from_cmdline = FALSE; } else { propval = svn_string_create(APR_ARRAY_IDX(args, 1, const char *), scratch_pool); propval_came_from_cmdline = TRUE; } /* We only want special Subversion property values to be in UTF-8 and LF line endings. All other propvals are taken literally. */ if (svn_prop_needs_translation(pname)) SVN_ERR(svn_subst_translate_string2(&propval, NULL, NULL, propval, opt_state->encoding, FALSE, scratch_pool, scratch_pool)); else if (opt_state->encoding) return svn_error_create (SVN_ERR_UNSUPPORTED_FEATURE, NULL, _("--encoding option applies only to textual" " Subversion-controlled properties")); /* Suck up all the remaining arguments into a targets array */ SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os, opt_state->targets, ctx, FALSE, scratch_pool)); /* Implicit "." is okay for revision properties; it just helps us find the right repository. */ if (opt_state->revprop) svn_opt_push_implicit_dot_target(targets, scratch_pool); SVN_ERR(svn_cl__eat_peg_revisions(&targets, targets, scratch_pool)); if (opt_state->revprop) /* operate on a revprop */ { svn_revnum_t rev; const char *URL; SVN_ERR(svn_cl__revprop_prepare(&opt_state->start_revision, targets, &URL, ctx, scratch_pool)); /* Let libsvn_client do the real work. */ SVN_ERR(svn_client_revprop_set2(pname, propval, NULL, URL, &(opt_state->start_revision), &rev, opt_state->force, ctx, scratch_pool)); } else if (opt_state->start_revision.kind != svn_opt_revision_unspecified) { return svn_error_createf (SVN_ERR_CL_ARG_PARSING_ERROR, NULL, _("Cannot specify revision for setting versioned property '%s'"), pname); } else /* operate on a normal, versioned property (not a revprop) */ { if (opt_state->depth == svn_depth_unknown) opt_state->depth = svn_depth_empty; /* The customary implicit dot rule has been prone to user error * here. People would do intuitive things like * * $ svn propset svn:executable script * * and then be surprised to get an error like: * * svn: Illegal target for the requested operation * svn: Cannot set svn:executable on a directory () * * So we don't do the implicit dot thing anymore. A * target * must always be explicitly provided when setting a versioned * property. See * * http://subversion.tigris.org/issues/show_bug.cgi?id=924 * * for more details. */ if (targets->nelts == 0) { if (propval_came_from_cmdline) { return svn_error_createf (SVN_ERR_CL_INSUFFICIENT_ARGS, NULL, _("Explicit target required ('%s' interpreted as prop value)"), propval->data); } else { return svn_error_create (SVN_ERR_CL_INSUFFICIENT_ARGS, NULL, _("Explicit target argument required")); } } SVN_ERR(svn_cl__propset_print_binary_mime_type_warning(targets, pname, propval, scratch_pool)); SVN_ERR(svn_client_propset_local(pname, propval, targets, opt_state->depth, opt_state->force, opt_state->changelists, ctx, scratch_pool)); if (! opt_state->quiet) svn_cl__check_boolean_prop_val(pname, propval->data, scratch_pool); } return SVN_NO_ERROR; }