1/* 2 * commit-cmd.c -- Check changes into the repository. 3 * 4 * ==================================================================== 5 * Licensed to the Apache Software Foundation (ASF) under one 6 * or more contributor license agreements. See the NOTICE file 7 * distributed with this work for additional information 8 * regarding copyright ownership. The ASF licenses this file 9 * to you under the Apache License, Version 2.0 (the 10 * "License"); you may not use this file except in compliance 11 * with the License. You may obtain a copy of the License at 12 * 13 * http://www.apache.org/licenses/LICENSE-2.0 14 * 15 * Unless required by applicable law or agreed to in writing, 16 * software distributed under the License is distributed on an 17 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 18 * KIND, either express or implied. See the License for the 19 * specific language governing permissions and limitations 20 * under the License. 21 * ==================================================================== 22 */ 23 24/* ==================================================================== */ 25 26 27 28/*** Includes. ***/ 29 30#include <apr_general.h> 31 32#include "svn_hash.h" 33#include "svn_error.h" 34#include "svn_error_codes.h" 35#include "svn_wc.h" 36#include "svn_client.h" 37#include "svn_path.h" 38#include "svn_dirent_uri.h" 39#include "svn_error.h" 40#include "svn_config.h" 41#include "cl.h" 42 43#include "svn_private_config.h" 44 45 46 47/* Wrapper notify_func2 function and baton for warning about 48 reduced-depth commits of copied directories. */ 49struct copy_warning_notify_baton 50{ 51 svn_wc_notify_func2_t wrapped_func; 52 void *wrapped_baton; 53 svn_depth_t depth; 54 svn_boolean_t warned; 55}; 56 57static void 58copy_warning_notify_func(void *baton, 59 const svn_wc_notify_t *notify, 60 apr_pool_t *pool) 61{ 62 struct copy_warning_notify_baton *b = baton; 63 64 /* Call the wrapped notification system (if any). */ 65 if (b->wrapped_func) 66 b->wrapped_func(b->wrapped_baton, notify, pool); 67 68 /* If we're being notified about a copy of a directory when our 69 commit depth is less-than-infinite, and we've not already warned 70 about this situation, then warn about it (and remember that we 71 now have.) */ 72 if ((! b->warned) 73 && (b->depth < svn_depth_infinity) 74 && (notify->kind == svn_node_dir) 75 && ((notify->action == svn_wc_notify_commit_copied) || 76 (notify->action == svn_wc_notify_commit_copied_replaced))) 77 { 78 svn_error_t *err; 79 err = svn_cmdline_printf(pool, 80 _("svn: The depth of this commit is '%s', " 81 "but copies are always performed " 82 "recursively in the repository.\n"), 83 svn_depth_to_word(b->depth)); 84 /* ### FIXME: Try to return this error showhow? */ 85 svn_error_clear(err); 86 87 /* We'll only warn once. */ 88 b->warned = TRUE; 89 } 90} 91 92 93 94 95/* This implements the `svn_opt_subcommand_t' interface. */ 96svn_error_t * 97svn_cl__commit(apr_getopt_t *os, 98 void *baton, 99 apr_pool_t *pool) 100{ 101 svn_error_t *err; 102 svn_cl__opt_state_t *opt_state = ((svn_cl__cmd_baton_t *) baton)->opt_state; 103 svn_client_ctx_t *ctx = ((svn_cl__cmd_baton_t *) baton)->ctx; 104 apr_array_header_t *targets; 105 apr_array_header_t *condensed_targets; 106 const char *base_dir; 107 svn_config_t *cfg; 108 svn_boolean_t no_unlock = FALSE; 109 struct copy_warning_notify_baton cwnb; 110 111 SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os, 112 opt_state->targets, 113 ctx, FALSE, pool)); 114 115 SVN_ERR_W(svn_cl__check_targets_are_local_paths(targets), 116 _("Commit targets must be local paths")); 117 118 /* Add "." if user passed 0 arguments. */ 119 svn_opt_push_implicit_dot_target(targets, pool); 120 121 SVN_ERR(svn_cl__eat_peg_revisions(&targets, targets, pool)); 122 123 /* Condense the targets (like commit does)... */ 124 SVN_ERR(svn_dirent_condense_targets(&base_dir, &condensed_targets, targets, 125 TRUE, pool, pool)); 126 127 if ((! condensed_targets) || (! condensed_targets->nelts)) 128 { 129 const char *parent_dir, *base_name; 130 131 SVN_ERR(svn_wc_get_actual_target2(&parent_dir, &base_name, ctx->wc_ctx, 132 base_dir, pool, pool)); 133 if (*base_name) 134 base_dir = apr_pstrdup(pool, parent_dir); 135 } 136 137 if (opt_state->depth == svn_depth_unknown) 138 opt_state->depth = svn_depth_infinity; 139 140 cfg = svn_hash_gets(ctx->config, SVN_CONFIG_CATEGORY_CONFIG); 141 if (cfg) 142 SVN_ERR(svn_config_get_bool(cfg, &no_unlock, 143 SVN_CONFIG_SECTION_MISCELLANY, 144 SVN_CONFIG_OPTION_NO_UNLOCK, FALSE)); 145 146 /* We're creating a new log message baton because we can use our base_dir 147 to store the temp file, instead of the current working directory. The 148 client might not have write access to their working directory, but they 149 better have write access to the directory they're committing. */ 150 SVN_ERR(svn_cl__make_log_msg_baton(&(ctx->log_msg_baton3), 151 opt_state, base_dir, 152 ctx->config, pool)); 153 154 /* Copies are done server-side, and cheaply, which means they're 155 effectively always done with infinite depth. This is a potential 156 cause of confusion for users trying to commit copied subtrees in 157 part by restricting the commit's depth. See issues #3699 and #3752. */ 158 if (opt_state->depth < svn_depth_infinity) 159 { 160 cwnb.wrapped_func = ctx->notify_func2; 161 cwnb.wrapped_baton = ctx->notify_baton2; 162 cwnb.depth = opt_state->depth; 163 cwnb.warned = FALSE; 164 ctx->notify_func2 = copy_warning_notify_func; 165 ctx->notify_baton2 = &cwnb; 166 } 167 168 /* Commit. */ 169 err = svn_client_commit6(targets, 170 opt_state->depth, 171 no_unlock, 172 opt_state->keep_changelists, 173 TRUE /* commit_as_operations */, 174 opt_state->include_externals, /* file externals */ 175 opt_state->include_externals, /* dir externals */ 176 opt_state->changelists, 177 opt_state->revprop_table, 178 (opt_state->quiet 179 ? NULL : svn_cl__print_commit_info), 180 NULL, 181 ctx, 182 pool); 183 SVN_ERR(svn_cl__cleanup_log_msg(ctx->log_msg_baton3, err, pool)); 184 185 return SVN_NO_ERROR; 186} 187