propset-cmd.c revision 362181
1/*
2 * propset-cmd.c -- Set property values on files/dirs
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 "svn_cmdline.h"
31#include "svn_pools.h"
32#include "svn_client.h"
33#include "svn_string.h"
34#include "svn_error.h"
35#include "svn_utf.h"
36#include "svn_subst.h"
37#include "svn_path.h"
38#include "svn_props.h"
39#include "cl.h"
40
41#include "svn_private_config.h"
42
43
44/*** Code. ***/
45
46/* This implements the `svn_opt_subcommand_t' interface. */
47svn_error_t *
48svn_cl__propset(apr_getopt_t *os,
49                void *baton,
50                apr_pool_t *scratch_pool)
51{
52  svn_cl__opt_state_t *opt_state = ((svn_cl__cmd_baton_t *) baton)->opt_state;
53  svn_client_ctx_t *ctx = ((svn_cl__cmd_baton_t *) baton)->ctx;
54  const char *pname;
55  svn_string_t *propval = NULL;
56  svn_boolean_t propval_came_from_cmdline;
57  apr_array_header_t *args, *targets;
58
59  /* PNAME and PROPVAL expected as first 2 arguments if filedata was
60     NULL, else PNAME alone will precede the targets.  Get a UTF-8
61     version of the name, too. */
62  SVN_ERR(svn_opt_parse_num_args(&args, os,
63                                 opt_state->filedata ? 1 : 2, scratch_pool));
64  pname = APR_ARRAY_IDX(args, 0, const char *);
65  SVN_ERR(svn_utf_cstring_to_utf8(&pname, pname, scratch_pool));
66  if (! svn_prop_name_is_valid(pname))
67    return svn_error_createf(SVN_ERR_CLIENT_PROPERTY_NAME, NULL,
68                             _("'%s' is not a valid Subversion property name"),
69                             pname);
70  if (!opt_state->force)
71    SVN_ERR(svn_cl__check_svn_prop_name(pname, opt_state->revprop,
72                                        svn_cl__prop_use_set, scratch_pool));
73
74  /* Get the PROPVAL from either an external file, or from the command
75     line. */
76  if (opt_state->filedata)
77    {
78      propval = svn_string_create_from_buf(opt_state->filedata, scratch_pool);
79      propval_came_from_cmdline = FALSE;
80    }
81  else
82    {
83      propval = svn_string_create(APR_ARRAY_IDX(args, 1, const char *),
84                                  scratch_pool);
85      propval_came_from_cmdline = TRUE;
86    }
87
88  /* We only want special Subversion property values to be in UTF-8
89     and LF line endings.  All other propvals are taken literally. */
90  if (svn_prop_needs_translation(pname))
91    SVN_ERR(svn_subst_translate_string2(&propval, NULL, NULL, propval,
92                                        opt_state->encoding, FALSE,
93                                        scratch_pool, scratch_pool));
94  else if (opt_state->encoding)
95    return svn_error_create
96      (SVN_ERR_UNSUPPORTED_FEATURE, NULL,
97       _("--encoding option applies only to textual"
98         " Subversion-controlled properties"));
99
100  /* Suck up all the remaining arguments into a targets array */
101
102  SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os,
103                                                      opt_state->targets,
104                                                      ctx, FALSE,
105                                                      scratch_pool));
106
107  /* Implicit "." is okay for revision properties; it just helps
108     us find the right repository. */
109  if (opt_state->revprop)
110    svn_opt_push_implicit_dot_target(targets, scratch_pool);
111
112  SVN_ERR(svn_cl__eat_peg_revisions(&targets, targets, scratch_pool));
113
114  if (opt_state->revprop)  /* operate on a revprop */
115    {
116      svn_revnum_t rev;
117      const char *URL;
118
119      SVN_ERR(svn_cl__revprop_prepare(&opt_state->start_revision, targets,
120                                      &URL, ctx, scratch_pool));
121
122      /* Let libsvn_client do the real work. */
123      SVN_ERR(svn_client_revprop_set2(pname, propval, NULL,
124                                      URL, &(opt_state->start_revision),
125                                      &rev, opt_state->force, ctx,
126                                      scratch_pool));
127    }
128  else if (opt_state->start_revision.kind != svn_opt_revision_unspecified)
129    {
130      return svn_error_createf
131        (SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
132         _("Cannot specify revision for setting versioned property '%s'"),
133         pname);
134    }
135  else  /* operate on a normal, versioned property (not a revprop) */
136    {
137      if (opt_state->depth == svn_depth_unknown)
138        opt_state->depth = svn_depth_empty;
139
140      /* The customary implicit dot rule has been prone to user error
141       * here.  People would do intuitive things like
142       *
143       *    $ svn propset svn:executable script
144       *
145       * and then be surprised to get an error like:
146       *
147       *    svn: Illegal target for the requested operation
148       *    svn: Cannot set svn:executable on a directory ()
149       *
150       * So we don't do the implicit dot thing anymore.  A * target
151       * must always be explicitly provided when setting a versioned
152       * property.  See
153       *
154       *    https://issues.apache.org/jira/browse/SVN-924
155       *
156       * for more details.
157       */
158
159      if (targets->nelts == 0)
160        {
161          if (propval_came_from_cmdline)
162            {
163              return svn_error_createf
164                (SVN_ERR_CL_INSUFFICIENT_ARGS, NULL,
165                 _("Explicit target required ('%s' interpreted as prop value)"),
166                 propval->data);
167            }
168          else
169            {
170              return svn_error_create
171                (SVN_ERR_CL_INSUFFICIENT_ARGS, NULL,
172                 _("Explicit target argument required"));
173            }
174        }
175
176      SVN_ERR(svn_cl__propset_print_binary_mime_type_warning(targets,
177                                                             pname,
178                                                             propval,
179                                                             scratch_pool));
180
181      SVN_ERR(svn_client_propset_local(pname, propval, targets,
182                                       opt_state->depth, opt_state->force,
183                                       opt_state->changelists, ctx,
184                                       scratch_pool));
185
186      if (! opt_state->quiet)
187        svn_cl__check_boolean_prop_val(pname, propval->data, scratch_pool);
188    }
189
190  return SVN_NO_ERROR;
191}
192