1251881Speter/*
2251881Speter * commit-cmd.c -- Check changes into the repository.
3251881Speter *
4251881Speter * ====================================================================
5251881Speter *    Licensed to the Apache Software Foundation (ASF) under one
6251881Speter *    or more contributor license agreements.  See the NOTICE file
7251881Speter *    distributed with this work for additional information
8251881Speter *    regarding copyright ownership.  The ASF licenses this file
9251881Speter *    to you under the Apache License, Version 2.0 (the
10251881Speter *    "License"); you may not use this file except in compliance
11251881Speter *    with the License.  You may obtain a copy of the License at
12251881Speter *
13251881Speter *      http://www.apache.org/licenses/LICENSE-2.0
14251881Speter *
15251881Speter *    Unless required by applicable law or agreed to in writing,
16251881Speter *    software distributed under the License is distributed on an
17251881Speter *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18251881Speter *    KIND, either express or implied.  See the License for the
19251881Speter *    specific language governing permissions and limitations
20251881Speter *    under the License.
21251881Speter * ====================================================================
22251881Speter */
23251881Speter
24251881Speter/* ==================================================================== */
25251881Speter
26251881Speter
27251881Speter
28251881Speter/*** Includes. ***/
29251881Speter
30251881Speter#include <apr_general.h>
31251881Speter
32251881Speter#include "svn_hash.h"
33251881Speter#include "svn_error.h"
34251881Speter#include "svn_error_codes.h"
35251881Speter#include "svn_wc.h"
36251881Speter#include "svn_client.h"
37251881Speter#include "svn_path.h"
38251881Speter#include "svn_dirent_uri.h"
39251881Speter#include "svn_error.h"
40251881Speter#include "svn_config.h"
41251881Speter#include "cl.h"
42251881Speter
43251881Speter#include "svn_private_config.h"
44251881Speter
45251881Speter
46251881Speter
47251881Speter/* Wrapper notify_func2 function and baton for warning about
48251881Speter   reduced-depth commits of copied directories.  */
49251881Speterstruct copy_warning_notify_baton
50251881Speter{
51251881Speter  svn_wc_notify_func2_t wrapped_func;
52251881Speter  void *wrapped_baton;
53251881Speter  svn_depth_t depth;
54251881Speter  svn_boolean_t warned;
55251881Speter};
56251881Speter
57251881Speterstatic void
58251881Spetercopy_warning_notify_func(void *baton,
59251881Speter                         const svn_wc_notify_t *notify,
60251881Speter                         apr_pool_t *pool)
61251881Speter{
62251881Speter  struct copy_warning_notify_baton *b = baton;
63251881Speter
64251881Speter  /* Call the wrapped notification system (if any). */
65251881Speter  if (b->wrapped_func)
66251881Speter    b->wrapped_func(b->wrapped_baton, notify, pool);
67251881Speter
68251881Speter  /* If we're being notified about a copy of a directory when our
69251881Speter     commit depth is less-than-infinite, and we've not already warned
70251881Speter     about this situation, then warn about it (and remember that we
71251881Speter     now have.)  */
72251881Speter  if ((! b->warned)
73251881Speter      && (b->depth < svn_depth_infinity)
74251881Speter      && (notify->kind == svn_node_dir)
75251881Speter      && ((notify->action == svn_wc_notify_commit_copied) ||
76251881Speter          (notify->action == svn_wc_notify_commit_copied_replaced)))
77251881Speter    {
78251881Speter      svn_error_t *err;
79251881Speter      err = svn_cmdline_printf(pool,
80251881Speter                               _("svn: The depth of this commit is '%s', "
81251881Speter                                 "but copies are always performed "
82251881Speter                                 "recursively in the repository.\n"),
83251881Speter                               svn_depth_to_word(b->depth));
84251881Speter      /* ### FIXME: Try to return this error showhow? */
85251881Speter      svn_error_clear(err);
86251881Speter
87251881Speter      /* We'll only warn once. */
88251881Speter      b->warned = TRUE;
89251881Speter    }
90251881Speter}
91251881Speter
92251881Speter
93251881Speter
94251881Speter
95251881Speter/* This implements the `svn_opt_subcommand_t' interface. */
96251881Spetersvn_error_t *
97251881Spetersvn_cl__commit(apr_getopt_t *os,
98251881Speter               void *baton,
99251881Speter               apr_pool_t *pool)
100251881Speter{
101251881Speter  svn_error_t *err;
102251881Speter  svn_cl__opt_state_t *opt_state = ((svn_cl__cmd_baton_t *) baton)->opt_state;
103251881Speter  svn_client_ctx_t *ctx = ((svn_cl__cmd_baton_t *) baton)->ctx;
104251881Speter  apr_array_header_t *targets;
105251881Speter  apr_array_header_t *condensed_targets;
106251881Speter  const char *base_dir;
107251881Speter  svn_config_t *cfg;
108251881Speter  svn_boolean_t no_unlock = FALSE;
109251881Speter  struct copy_warning_notify_baton cwnb;
110251881Speter
111251881Speter  SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os,
112251881Speter                                                      opt_state->targets,
113251881Speter                                                      ctx, FALSE, pool));
114251881Speter
115251881Speter  SVN_ERR_W(svn_cl__check_targets_are_local_paths(targets),
116251881Speter            _("Commit targets must be local paths"));
117251881Speter
118251881Speter  /* Add "." if user passed 0 arguments. */
119251881Speter  svn_opt_push_implicit_dot_target(targets, pool);
120251881Speter
121251881Speter  SVN_ERR(svn_cl__eat_peg_revisions(&targets, targets, pool));
122251881Speter
123251881Speter  /* Condense the targets (like commit does)... */
124251881Speter  SVN_ERR(svn_dirent_condense_targets(&base_dir, &condensed_targets, targets,
125251881Speter                                      TRUE, pool, pool));
126251881Speter
127251881Speter  if ((! condensed_targets) || (! condensed_targets->nelts))
128251881Speter    {
129251881Speter      const char *parent_dir, *base_name;
130251881Speter
131251881Speter      SVN_ERR(svn_wc_get_actual_target2(&parent_dir, &base_name, ctx->wc_ctx,
132251881Speter                                        base_dir, pool, pool));
133251881Speter      if (*base_name)
134251881Speter        base_dir = apr_pstrdup(pool, parent_dir);
135251881Speter    }
136251881Speter
137251881Speter  if (opt_state->depth == svn_depth_unknown)
138251881Speter    opt_state->depth = svn_depth_infinity;
139251881Speter
140251881Speter  cfg = svn_hash_gets(ctx->config, SVN_CONFIG_CATEGORY_CONFIG);
141251881Speter  if (cfg)
142251881Speter    SVN_ERR(svn_config_get_bool(cfg, &no_unlock,
143251881Speter                                SVN_CONFIG_SECTION_MISCELLANY,
144251881Speter                                SVN_CONFIG_OPTION_NO_UNLOCK, FALSE));
145251881Speter
146251881Speter  /* We're creating a new log message baton because we can use our base_dir
147251881Speter     to store the temp file, instead of the current working directory.  The
148251881Speter     client might not have write access to their working directory, but they
149251881Speter     better have write access to the directory they're committing.  */
150251881Speter  SVN_ERR(svn_cl__make_log_msg_baton(&(ctx->log_msg_baton3),
151251881Speter                                     opt_state, base_dir,
152251881Speter                                     ctx->config, pool));
153251881Speter
154251881Speter  /* Copies are done server-side, and cheaply, which means they're
155251881Speter     effectively always done with infinite depth.  This is a potential
156251881Speter     cause of confusion for users trying to commit copied subtrees in
157251881Speter     part by restricting the commit's depth.  See issues #3699 and #3752. */
158251881Speter  if (opt_state->depth < svn_depth_infinity)
159251881Speter    {
160251881Speter      cwnb.wrapped_func = ctx->notify_func2;
161251881Speter      cwnb.wrapped_baton = ctx->notify_baton2;
162251881Speter      cwnb.depth = opt_state->depth;
163251881Speter      cwnb.warned = FALSE;
164251881Speter      ctx->notify_func2 = copy_warning_notify_func;
165251881Speter      ctx->notify_baton2 = &cwnb;
166251881Speter    }
167251881Speter
168251881Speter  /* Commit. */
169251881Speter  err = svn_client_commit6(targets,
170251881Speter                           opt_state->depth,
171251881Speter                           no_unlock,
172251881Speter                           opt_state->keep_changelists,
173251881Speter                           TRUE /* commit_as_operations */,
174251881Speter                           opt_state->include_externals, /* file externals */
175251881Speter                           opt_state->include_externals, /* dir externals */
176251881Speter                           opt_state->changelists,
177251881Speter                           opt_state->revprop_table,
178251881Speter                           (opt_state->quiet
179251881Speter                            ? NULL : svn_cl__print_commit_info),
180251881Speter                           NULL,
181251881Speter                           ctx,
182251881Speter                           pool);
183251881Speter  SVN_ERR(svn_cl__cleanup_log_msg(ctx->log_msg_baton3, err, pool));
184251881Speter
185251881Speter  return SVN_NO_ERROR;
186251881Speter}
187