]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/subversion/subversion/libsvn_wc/crop.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / contrib / subversion / subversion / libsvn_wc / crop.c
1 /*
2  * crop.c: Cropping the WC
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 #include "svn_wc.h"
27 #include "svn_pools.h"
28 #include "svn_error.h"
29 #include "svn_error_codes.h"
30 #include "svn_dirent_uri.h"
31 #include "svn_path.h"
32
33 #include "wc.h"
34 #include "workqueue.h"
35
36 #include "svn_private_config.h"
37
38 /* Helper function that crops the children of the LOCAL_ABSPATH, under the
39  * constraint of NEW_DEPTH. The DIR_PATH itself will never be cropped. The
40  * whole subtree should have been locked.
41  *
42  * DIR_DEPTH is the current depth of LOCAL_ABSPATH as stored in DB.
43  *
44  * If NOTIFY_FUNC is not null, each file and ROOT of subtree will be reported
45  * upon remove.
46  */
47 static svn_error_t *
48 crop_children(svn_wc__db_t *db,
49               const char *local_abspath,
50               svn_depth_t dir_depth,
51               svn_depth_t new_depth,
52               svn_wc_notify_func2_t notify_func,
53               void *notify_baton,
54               svn_cancel_func_t cancel_func,
55               void *cancel_baton,
56               apr_pool_t *pool)
57 {
58   const apr_array_header_t *children;
59   apr_pool_t *iterpool;
60   int i;
61
62   SVN_ERR_ASSERT(new_depth >= svn_depth_empty
63                  && new_depth <= svn_depth_infinity);
64
65   if (cancel_func)
66     SVN_ERR(cancel_func(cancel_baton));
67
68   iterpool = svn_pool_create(pool);
69
70   if (dir_depth == svn_depth_unknown)
71     dir_depth = svn_depth_infinity;
72
73   /* Update the depth of target first, if needed. */
74   if (dir_depth > new_depth)
75     SVN_ERR(svn_wc__db_op_set_base_depth(db, local_abspath, new_depth,
76                                          iterpool));
77
78   /* Looping over current directory's SVN entries: */
79   SVN_ERR(svn_wc__db_read_children(&children, db, local_abspath, pool,
80                                    iterpool));
81
82   for (i = 0; i < children->nelts; i++)
83     {
84       const char *child_name = APR_ARRAY_IDX(children, i, const char *);
85       const char *child_abspath;
86       svn_wc__db_status_t child_status;
87       svn_node_kind_t kind;
88       svn_depth_t child_depth;
89
90       svn_pool_clear(iterpool);
91
92       /* Get the next node */
93       child_abspath = svn_dirent_join(local_abspath, child_name, iterpool);
94
95       SVN_ERR(svn_wc__db_read_info(&child_status, &kind, NULL, NULL, NULL,
96                                    NULL,NULL, NULL, NULL, &child_depth,
97                                    NULL, NULL, NULL, NULL, NULL, NULL,
98                                    NULL, NULL, NULL, NULL, NULL, NULL,
99                                    NULL, NULL, NULL, NULL, NULL,
100                                    db, child_abspath, iterpool, iterpool));
101
102       if (child_status == svn_wc__db_status_server_excluded ||
103           child_status == svn_wc__db_status_excluded ||
104           child_status == svn_wc__db_status_not_present)
105         {
106           svn_depth_t remove_below = (kind == svn_node_dir)
107                                             ? svn_depth_immediates
108                                             : svn_depth_files;
109           if (new_depth < remove_below)
110             SVN_ERR(svn_wc__db_base_remove(db, child_abspath,
111                                            FALSE /* keep_as_working */,
112                                            FALSE /* queue_deletes */,
113                                            FALSE /* remove_locks */,
114                                            SVN_INVALID_REVNUM,
115                                            NULL, NULL, iterpool));
116
117           continue;
118         }
119       else if (kind == svn_node_file)
120         {
121           if (new_depth == svn_depth_empty)
122             SVN_ERR(svn_wc__db_op_remove_node(NULL,
123                                               db, child_abspath,
124                                               TRUE /* destroy */,
125                                               FALSE /* destroy_changes */,
126                                               SVN_INVALID_REVNUM,
127                                               svn_wc__db_status_not_present,
128                                               svn_node_none,
129                                               NULL, NULL,
130                                               cancel_func, cancel_baton,
131                                               iterpool));
132           else
133             continue;
134
135         }
136       else if (kind == svn_node_dir)
137         {
138           if (new_depth < svn_depth_immediates)
139             {
140               SVN_ERR(svn_wc__db_op_remove_node(NULL,
141                                                 db, child_abspath,
142                                                 TRUE /* destroy */,
143                                                 FALSE /* destroy_changes */,
144                                                 SVN_INVALID_REVNUM,
145                                                 svn_wc__db_status_not_present,
146                                                 svn_node_none,
147                                                 NULL, NULL,
148                                                 cancel_func, cancel_baton,
149                                                 iterpool));
150             }
151           else
152             {
153               SVN_ERR(crop_children(db,
154                                     child_abspath,
155                                     child_depth,
156                                     svn_depth_empty,
157                                     notify_func,
158                                     notify_baton,
159                                     cancel_func,
160                                     cancel_baton,
161                                     iterpool));
162               continue;
163             }
164         }
165       else
166         {
167           return svn_error_createf
168             (SVN_ERR_NODE_UNKNOWN_KIND, NULL, _("Unknown node kind for '%s'"),
169              svn_dirent_local_style(child_abspath, iterpool));
170         }
171
172       if (notify_func)
173         {
174           svn_wc_notify_t *notify;
175           notify = svn_wc_create_notify(child_abspath,
176                                         svn_wc_notify_delete,
177                                         iterpool);
178           (*notify_func)(notify_baton, notify, iterpool);
179         }
180     }
181
182   svn_pool_destroy(iterpool);
183
184   return SVN_NO_ERROR;
185 }
186
187 svn_error_t *
188 svn_wc_exclude(svn_wc_context_t *wc_ctx,
189                const char *local_abspath,
190                svn_cancel_func_t cancel_func,
191                void *cancel_baton,
192                svn_wc_notify_func2_t notify_func,
193                void *notify_baton,
194                apr_pool_t *scratch_pool)
195 {
196   svn_boolean_t is_root, is_switched;
197   svn_wc__db_status_t status;
198   svn_node_kind_t kind;
199   svn_revnum_t revision;
200   const char *repos_relpath, *repos_root, *repos_uuid;
201
202   SVN_ERR(svn_wc__db_is_switched(&is_root, &is_switched, NULL,
203                                  wc_ctx->db, local_abspath, scratch_pool));
204
205   if (is_root)
206     {
207        return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
208                                 _("Cannot exclude '%s': "
209                                   "it is a working copy root"),
210                                 svn_dirent_local_style(local_abspath,
211                                                        scratch_pool));
212     }
213   if (is_switched)
214     {
215       return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
216                                _("Cannot exclude '%s': "
217                                  "it is a switched path"),
218                                svn_dirent_local_style(local_abspath,
219                                                       scratch_pool));
220     }
221
222   SVN_ERR(svn_wc__db_read_info(&status, &kind, &revision, &repos_relpath,
223                                &repos_root, &repos_uuid, NULL, NULL, NULL,
224                                NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
225                                NULL, NULL, NULL, NULL, NULL, NULL, NULL,
226                                NULL, NULL, NULL,
227                                wc_ctx->db, local_abspath,
228                                scratch_pool, scratch_pool));
229
230   switch (status)
231     {
232       case svn_wc__db_status_server_excluded:
233       case svn_wc__db_status_excluded:
234       case svn_wc__db_status_not_present:
235         return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
236                                  _("The node '%s' was not found."),
237                                  svn_dirent_local_style(local_abspath,
238                                                         scratch_pool));
239
240       case svn_wc__db_status_added:
241         /* Would have to check parents if we want to allow this */
242         return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
243                                  _("Cannot exclude '%s': it is to be added "
244                                    "to the repository. Try commit instead"),
245                                  svn_dirent_local_style(local_abspath,
246                                                         scratch_pool));
247       case svn_wc__db_status_deleted:
248         /* Would have to check parents if we want to allow this */
249         return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
250                                  _("Cannot exclude '%s': it is to be deleted "
251                                    "from the repository. Try commit instead"),
252                                  svn_dirent_local_style(local_abspath,
253                                                         scratch_pool));
254
255       case svn_wc__db_status_normal:
256       case svn_wc__db_status_incomplete:
257       default:
258         break; /* Ok to exclude */
259     }
260
261   /* Remove all working copy data below local_abspath */
262   SVN_ERR(svn_wc__db_op_remove_node(NULL,
263                                     wc_ctx->db, local_abspath,
264                                     TRUE /* destroy */,
265                                     FALSE /* destroy_changes */,
266                                     revision,
267                                     svn_wc__db_status_excluded,
268                                     kind,
269                                     NULL, NULL,
270                                     cancel_func, cancel_baton,
271                                     scratch_pool));
272
273   SVN_ERR(svn_wc__wq_run(wc_ctx->db, local_abspath,
274                          cancel_func, cancel_baton,
275                          scratch_pool));
276
277   if (notify_func)
278     {
279       svn_wc_notify_t *notify;
280       notify = svn_wc_create_notify(local_abspath,
281                                     svn_wc_notify_exclude,
282                                     scratch_pool);
283       notify_func(notify_baton, notify, scratch_pool);
284     }
285
286   return SVN_NO_ERROR;
287 }
288
289 svn_error_t *
290 svn_wc_crop_tree2(svn_wc_context_t *wc_ctx,
291                   const char *local_abspath,
292                   svn_depth_t depth,
293                   svn_cancel_func_t cancel_func,
294                   void *cancel_baton,
295                   svn_wc_notify_func2_t notify_func,
296                   void *notify_baton,
297                   apr_pool_t *scratch_pool)
298 {
299   svn_wc__db_t *db = wc_ctx->db;
300   svn_wc__db_status_t status;
301   svn_node_kind_t kind;
302   svn_depth_t dir_depth;
303
304   /* Only makes sense when the depth is restrictive. */
305   if (depth == svn_depth_infinity)
306     return SVN_NO_ERROR; /* Nothing to crop */
307   if (!(depth >= svn_depth_empty && depth < svn_depth_infinity))
308     return svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
309       _("Can only crop a working copy with a restrictive depth"));
310
311   SVN_ERR(svn_wc__db_read_info(&status, &kind, NULL, NULL, NULL, NULL, NULL,
312                                NULL, NULL, &dir_depth, NULL, NULL, NULL, NULL,
313                                NULL, NULL, NULL, NULL, NULL, NULL, NULL,
314                                NULL, NULL, NULL, NULL, NULL, NULL,
315                                db, local_abspath,
316                                scratch_pool, scratch_pool));
317
318   if (kind != svn_node_dir)
319     return svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
320       _("Can only crop directories"));
321
322   switch (status)
323     {
324       case svn_wc__db_status_not_present:
325       case svn_wc__db_status_server_excluded:
326         return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
327                                  _("The node '%s' was not found."),
328                                  svn_dirent_local_style(local_abspath,
329                                                         scratch_pool));
330
331       case svn_wc__db_status_deleted:
332         return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
333                                _("Cannot crop '%s': it is going to be removed "
334                                  "from repository. Try commit instead"),
335                                svn_dirent_local_style(local_abspath,
336                                                       scratch_pool));
337
338       case svn_wc__db_status_added:
339         return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
340                                  _("Cannot crop '%s': it is to be added "
341                                    "to the repository. Try commit instead"),
342                                  svn_dirent_local_style(local_abspath,
343                                                         scratch_pool));
344       case svn_wc__db_status_excluded:
345         return SVN_NO_ERROR; /* Nothing to do */
346
347       case svn_wc__db_status_normal:
348       case svn_wc__db_status_incomplete:
349         break;
350
351       default:
352         SVN_ERR_MALFUNCTION();
353     }
354
355   SVN_ERR(crop_children(db, local_abspath, dir_depth, depth,
356                         notify_func, notify_baton,
357                         cancel_func, cancel_baton, scratch_pool));
358
359   return svn_error_trace(svn_wc__wq_run(db, local_abspath,
360                                         cancel_func, cancel_baton,
361                                         scratch_pool));
362 }