2 * crop.c: Cropping the WC
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
13 * http://www.apache.org/licenses/LICENSE-2.0
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
21 * ====================================================================
24 /* ==================================================================== */
27 #include "svn_pools.h"
28 #include "svn_error.h"
29 #include "svn_error_codes.h"
30 #include "svn_dirent_uri.h"
34 #include "workqueue.h"
36 #include "svn_private_config.h"
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.
42 * DIR_DEPTH is the current depth of LOCAL_ABSPATH as stored in DB.
44 * If NOTIFY_FUNC is not null, each file and ROOT of subtree will be reported
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,
54 svn_cancel_func_t cancel_func,
58 const apr_array_header_t *children;
62 SVN_ERR_ASSERT(new_depth >= svn_depth_empty
63 && new_depth <= svn_depth_infinity);
66 SVN_ERR(cancel_func(cancel_baton));
68 iterpool = svn_pool_create(pool);
70 if (dir_depth == svn_depth_unknown)
71 dir_depth = svn_depth_infinity;
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,
78 /* Looping over current directory's SVN entries: */
79 SVN_ERR(svn_wc__db_read_children(&children, db, local_abspath, pool,
82 for (i = 0; i < children->nelts; i++)
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;
88 svn_depth_t child_depth;
90 svn_pool_clear(iterpool);
92 /* Get the next node */
93 child_abspath = svn_dirent_join(local_abspath, child_name, iterpool);
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));
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)
106 svn_depth_t remove_below = (kind == svn_node_dir)
107 ? svn_depth_immediates
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 */,
115 NULL, NULL, iterpool));
119 else if (kind == svn_node_file)
121 if (new_depth == svn_depth_empty)
122 SVN_ERR(svn_wc__db_op_remove_node(NULL,
125 FALSE /* destroy_changes */,
127 svn_wc__db_status_not_present,
130 cancel_func, cancel_baton,
136 else if (kind == svn_node_dir)
138 if (new_depth < svn_depth_immediates)
140 SVN_ERR(svn_wc__db_op_remove_node(NULL,
143 FALSE /* destroy_changes */,
145 svn_wc__db_status_not_present,
148 cancel_func, cancel_baton,
153 SVN_ERR(crop_children(db,
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));
174 svn_wc_notify_t *notify;
175 notify = svn_wc_create_notify(child_abspath,
176 svn_wc_notify_delete,
178 (*notify_func)(notify_baton, notify, iterpool);
182 svn_pool_destroy(iterpool);
188 svn_wc_exclude(svn_wc_context_t *wc_ctx,
189 const char *local_abspath,
190 svn_cancel_func_t cancel_func,
192 svn_wc_notify_func2_t notify_func,
194 apr_pool_t *scratch_pool)
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;
202 SVN_ERR(svn_wc__db_is_switched(&is_root, &is_switched, NULL,
203 wc_ctx->db, local_abspath, scratch_pool));
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,
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,
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,
227 wc_ctx->db, local_abspath,
228 scratch_pool, scratch_pool));
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,
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,
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,
255 case svn_wc__db_status_normal:
256 case svn_wc__db_status_incomplete:
258 break; /* Ok to exclude */
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,
265 FALSE /* destroy_changes */,
267 svn_wc__db_status_excluded,
270 cancel_func, cancel_baton,
273 SVN_ERR(svn_wc__wq_run(wc_ctx->db, local_abspath,
274 cancel_func, cancel_baton,
279 svn_wc_notify_t *notify;
280 notify = svn_wc_create_notify(local_abspath,
281 svn_wc_notify_exclude,
283 notify_func(notify_baton, notify, scratch_pool);
290 svn_wc_crop_tree2(svn_wc_context_t *wc_ctx,
291 const char *local_abspath,
293 svn_cancel_func_t cancel_func,
295 svn_wc_notify_func2_t notify_func,
297 apr_pool_t *scratch_pool)
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;
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"));
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,
316 scratch_pool, scratch_pool));
318 if (kind != svn_node_dir)
319 return svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
320 _("Can only crop directories"));
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,
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,
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,
344 case svn_wc__db_status_excluded:
345 return SVN_NO_ERROR; /* Nothing to do */
347 case svn_wc__db_status_normal:
348 case svn_wc__db_status_incomplete:
352 SVN_ERR_MALFUNCTION();
355 SVN_ERR(crop_children(db, local_abspath, dir_depth, depth,
356 notify_func, notify_baton,
357 cancel_func, cancel_baton, scratch_pool));
359 return svn_error_trace(svn_wc__wq_run(db, local_abspath,
360 cancel_func, cancel_baton,