revert.c revision 362181
1/*
2 * revert.c:  wrapper around wc revert functionality.
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_path.h"
31#include "svn_wc.h"
32#include "svn_client.h"
33#include "svn_dirent_uri.h"
34#include "svn_hash.h"
35#include "svn_pools.h"
36#include "svn_error.h"
37#include "svn_time.h"
38#include "svn_config.h"
39#include "client.h"
40#include "private/svn_wc_private.h"
41
42#include "svn_private_config.h"
43
44
45/*** Code. ***/
46
47struct revert_with_write_lock_baton {
48  const char *local_abspath;
49  svn_depth_t depth;
50  svn_boolean_t use_commit_times;
51  const apr_array_header_t *changelists;
52  svn_boolean_t clear_changelists;
53  svn_boolean_t metadata_only;
54  svn_boolean_t added_keep_local;
55  svn_client_ctx_t *ctx;
56};
57
58/* (Note: All arguments are in the baton above.)
59
60   Attempt to revert LOCAL_ABSPATH by calling svn_wc_revert6(), which
61   see for further details.
62
63   If the target isn't versioned, send a 'skip' notification and return
64   no error.
65 */
66static svn_error_t *
67revert(void *baton, apr_pool_t *result_pool, apr_pool_t *scratch_pool)
68{
69  struct revert_with_write_lock_baton *b = baton;
70  svn_error_t *err;
71
72  err = svn_wc_revert6(b->ctx->wc_ctx,
73                       b->local_abspath,
74                       b->depth,
75                       b->use_commit_times,
76                       b->changelists,
77                       b->clear_changelists,
78                       b->metadata_only,
79                       b->added_keep_local,
80                       b->ctx->cancel_func, b->ctx->cancel_baton,
81                       b->ctx->notify_func2, b->ctx->notify_baton2,
82                       scratch_pool);
83
84  if (err)
85    {
86      /* If target isn't versioned, just send a 'skip'
87         notification and move on. */
88      if (err->apr_err == SVN_ERR_ENTRY_NOT_FOUND
89          || err->apr_err == SVN_ERR_UNVERSIONED_RESOURCE
90          || err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
91        {
92          if (b->ctx->notify_func2)
93            {
94              svn_wc_notify_t *notify;
95
96              notify = svn_wc_create_notify(b->local_abspath,
97                                            svn_wc_notify_skip,
98                                            scratch_pool);
99
100              notify->err = err;
101
102              b->ctx->notify_func2(b->ctx->notify_baton2,
103                                   notify, scratch_pool);
104            }
105          svn_error_clear(err);
106        }
107      else
108        return svn_error_trace(err);
109    }
110
111  return SVN_NO_ERROR;
112}
113
114
115svn_error_t *
116svn_client_revert4(const apr_array_header_t *paths,
117                   svn_depth_t depth,
118                   const apr_array_header_t *changelists,
119                   svn_boolean_t clear_changelists,
120                   svn_boolean_t metadata_only,
121                   svn_boolean_t added_keep_local,
122                   svn_client_ctx_t *ctx,
123                   apr_pool_t *pool)
124{
125  apr_pool_t *iterpool;
126  svn_error_t *err = SVN_NO_ERROR;
127  int i;
128  svn_config_t *cfg;
129  svn_boolean_t use_commit_times;
130  struct revert_with_write_lock_baton baton;
131
132  /* Don't even attempt to modify the working copy if any of the
133   * targets look like URLs. URLs are invalid input. */
134  for (i = 0; i < paths->nelts; i++)
135    {
136      const char *path = APR_ARRAY_IDX(paths, i, const char *);
137
138      if (svn_path_is_url(path))
139        return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
140                                 _("'%s' is not a local path"), path);
141    }
142
143  cfg = ctx->config
144        ? svn_hash_gets(ctx->config, SVN_CONFIG_CATEGORY_CONFIG)
145        : NULL;
146
147  SVN_ERR(svn_config_get_bool(cfg, &use_commit_times,
148                              SVN_CONFIG_SECTION_MISCELLANY,
149                              SVN_CONFIG_OPTION_USE_COMMIT_TIMES,
150                              FALSE));
151
152  iterpool = svn_pool_create(pool);
153
154  for (i = 0; i < paths->nelts; i++)
155    {
156      const char *path = APR_ARRAY_IDX(paths, i, const char *);
157      const char *local_abspath, *lock_target;
158      svn_boolean_t wc_root;
159
160      svn_pool_clear(iterpool);
161
162      /* See if we've been asked to cancel this operation. */
163      if ((ctx->cancel_func)
164          && ((err = ctx->cancel_func(ctx->cancel_baton))))
165        goto errorful;
166
167      err = svn_dirent_get_absolute(&local_abspath, path, iterpool);
168      if (err)
169        goto errorful;
170
171      baton.local_abspath = local_abspath;
172      baton.depth = depth;
173      baton.use_commit_times = use_commit_times;
174      baton.changelists = changelists;
175      baton.clear_changelists = clear_changelists;
176      baton.metadata_only = metadata_only;
177      baton.added_keep_local = added_keep_local;
178      baton.ctx = ctx;
179
180      err = svn_wc__is_wcroot(&wc_root, ctx->wc_ctx, local_abspath, iterpool);
181      if (err)
182        goto errorful;
183      lock_target = wc_root ? local_abspath
184                            : svn_dirent_dirname(local_abspath, pool);
185      err = svn_wc__call_with_write_lock(revert, &baton, ctx->wc_ctx,
186                                         lock_target, FALSE,
187                                         iterpool, iterpool);
188      if (err)
189        goto errorful;
190    }
191
192 errorful:
193
194  {
195    /* Sleep to ensure timestamp integrity. */
196    const char *sleep_path = NULL;
197
198    /* Only specify a path if we are certain all paths are on the
199       same filesystem */
200    if (paths->nelts == 1)
201      sleep_path = APR_ARRAY_IDX(paths, 0, const char *);
202
203    svn_io_sleep_for_timestamps(sleep_path, iterpool);
204  }
205
206  svn_pool_destroy(iterpool);
207
208  return svn_error_trace(err);
209}
210