crop.c revision 251881
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 */ 47static svn_error_t * 48crop_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 SVN_INVALID_REVNUM, 114 NULL, NULL, iterpool)); 115 116 continue; 117 } 118 else if (kind == svn_node_file) 119 { 120 if (new_depth == svn_depth_empty) 121 SVN_ERR(svn_wc__db_op_remove_node(NULL, 122 db, child_abspath, 123 TRUE /* destroy */, 124 FALSE /* destroy_changes */, 125 SVN_INVALID_REVNUM, 126 svn_wc__db_status_not_present, 127 svn_node_none, 128 NULL, NULL, 129 cancel_func, cancel_baton, 130 iterpool)); 131 else 132 continue; 133 134 } 135 else if (kind == svn_node_dir) 136 { 137 if (new_depth < svn_depth_immediates) 138 { 139 SVN_ERR(svn_wc__db_op_remove_node(NULL, 140 db, child_abspath, 141 TRUE /* destroy */, 142 FALSE /* destroy_changes */, 143 SVN_INVALID_REVNUM, 144 svn_wc__db_status_not_present, 145 svn_node_none, 146 NULL, NULL, 147 cancel_func, cancel_baton, 148 iterpool)); 149 } 150 else 151 { 152 SVN_ERR(crop_children(db, 153 child_abspath, 154 child_depth, 155 svn_depth_empty, 156 notify_func, 157 notify_baton, 158 cancel_func, 159 cancel_baton, 160 iterpool)); 161 continue; 162 } 163 } 164 else 165 { 166 return svn_error_createf 167 (SVN_ERR_NODE_UNKNOWN_KIND, NULL, _("Unknown node kind for '%s'"), 168 svn_dirent_local_style(child_abspath, iterpool)); 169 } 170 171 if (notify_func) 172 { 173 svn_wc_notify_t *notify; 174 notify = svn_wc_create_notify(child_abspath, 175 svn_wc_notify_delete, 176 iterpool); 177 (*notify_func)(notify_baton, notify, iterpool); 178 } 179 } 180 181 svn_pool_destroy(iterpool); 182 183 return SVN_NO_ERROR; 184} 185 186svn_error_t * 187svn_wc_exclude(svn_wc_context_t *wc_ctx, 188 const char *local_abspath, 189 svn_cancel_func_t cancel_func, 190 void *cancel_baton, 191 svn_wc_notify_func2_t notify_func, 192 void *notify_baton, 193 apr_pool_t *scratch_pool) 194{ 195 svn_boolean_t is_root, is_switched; 196 svn_wc__db_status_t status; 197 svn_node_kind_t kind; 198 svn_revnum_t revision; 199 const char *repos_relpath, *repos_root, *repos_uuid; 200 201 SVN_ERR(svn_wc__db_is_switched(&is_root, &is_switched, NULL, 202 wc_ctx->db, local_abspath, scratch_pool)); 203 204 if (is_root) 205 { 206 return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL, 207 _("Cannot exclude '%s': " 208 "it is a working copy root"), 209 svn_dirent_local_style(local_abspath, 210 scratch_pool)); 211 } 212 if (is_switched) 213 { 214 return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL, 215 _("Cannot exclude '%s': " 216 "it is a switched path"), 217 svn_dirent_local_style(local_abspath, 218 scratch_pool)); 219 } 220 221 SVN_ERR(svn_wc__db_read_info(&status, &kind, &revision, &repos_relpath, 222 &repos_root, &repos_uuid, NULL, NULL, NULL, 223 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 224 NULL, NULL, NULL, NULL, NULL, NULL, NULL, 225 NULL, NULL, NULL, 226 wc_ctx->db, local_abspath, 227 scratch_pool, scratch_pool)); 228 229 switch (status) 230 { 231 case svn_wc__db_status_server_excluded: 232 case svn_wc__db_status_excluded: 233 case svn_wc__db_status_not_present: 234 return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL, 235 _("The node '%s' was not found."), 236 svn_dirent_local_style(local_abspath, 237 scratch_pool)); 238 239 case svn_wc__db_status_added: 240 /* Would have to check parents if we want to allow this */ 241 return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL, 242 _("Cannot exclude '%s': it is to be added " 243 "to the repository. Try commit instead"), 244 svn_dirent_local_style(local_abspath, 245 scratch_pool)); 246 case svn_wc__db_status_deleted: 247 /* Would have to check parents if we want to allow this */ 248 return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL, 249 _("Cannot exclude '%s': it is to be deleted " 250 "from the repository. Try commit instead"), 251 svn_dirent_local_style(local_abspath, 252 scratch_pool)); 253 254 case svn_wc__db_status_normal: 255 case svn_wc__db_status_incomplete: 256 default: 257 break; /* Ok to exclude */ 258 } 259 260 /* Remove all working copy data below local_abspath */ 261 SVN_ERR(svn_wc__db_op_remove_node(NULL, 262 wc_ctx->db, local_abspath, 263 TRUE /* destroy */, 264 FALSE /* destroy_changes */, 265 revision, 266 svn_wc__db_status_excluded, 267 kind, 268 NULL, NULL, 269 cancel_func, cancel_baton, 270 scratch_pool)); 271 272 SVN_ERR(svn_wc__wq_run(wc_ctx->db, local_abspath, 273 cancel_func, cancel_baton, 274 scratch_pool)); 275 276 if (notify_func) 277 { 278 svn_wc_notify_t *notify; 279 notify = svn_wc_create_notify(local_abspath, 280 svn_wc_notify_exclude, 281 scratch_pool); 282 notify_func(notify_baton, notify, scratch_pool); 283 } 284 285 return SVN_NO_ERROR; 286} 287 288svn_error_t * 289svn_wc_crop_tree2(svn_wc_context_t *wc_ctx, 290 const char *local_abspath, 291 svn_depth_t depth, 292 svn_cancel_func_t cancel_func, 293 void *cancel_baton, 294 svn_wc_notify_func2_t notify_func, 295 void *notify_baton, 296 apr_pool_t *scratch_pool) 297{ 298 svn_wc__db_t *db = wc_ctx->db; 299 svn_wc__db_status_t status; 300 svn_node_kind_t kind; 301 svn_depth_t dir_depth; 302 303 /* Only makes sense when the depth is restrictive. */ 304 if (depth == svn_depth_infinity) 305 return SVN_NO_ERROR; /* Nothing to crop */ 306 if (!(depth >= svn_depth_empty && depth < svn_depth_infinity)) 307 return svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL, 308 _("Can only crop a working copy with a restrictive depth")); 309 310 SVN_ERR(svn_wc__db_read_info(&status, &kind, NULL, NULL, NULL, NULL, NULL, 311 NULL, NULL, &dir_depth, NULL, NULL, NULL, NULL, 312 NULL, NULL, NULL, NULL, NULL, NULL, NULL, 313 NULL, NULL, NULL, NULL, NULL, NULL, 314 db, local_abspath, 315 scratch_pool, scratch_pool)); 316 317 if (kind != svn_node_dir) 318 return svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL, 319 _("Can only crop directories")); 320 321 switch (status) 322 { 323 case svn_wc__db_status_not_present: 324 case svn_wc__db_status_server_excluded: 325 return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL, 326 _("The node '%s' was not found."), 327 svn_dirent_local_style(local_abspath, 328 scratch_pool)); 329 330 case svn_wc__db_status_deleted: 331 return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL, 332 _("Cannot crop '%s': it is going to be removed " 333 "from repository. Try commit instead"), 334 svn_dirent_local_style(local_abspath, 335 scratch_pool)); 336 337 case svn_wc__db_status_added: 338 return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL, 339 _("Cannot crop '%s': it is to be added " 340 "to the repository. Try commit instead"), 341 svn_dirent_local_style(local_abspath, 342 scratch_pool)); 343 case svn_wc__db_status_excluded: 344 return SVN_NO_ERROR; /* Nothing to do */ 345 346 case svn_wc__db_status_normal: 347 case svn_wc__db_status_incomplete: 348 break; 349 350 default: 351 SVN_ERR_MALFUNCTION(); 352 } 353 354 SVN_ERR(crop_children(db, local_abspath, dir_depth, depth, 355 notify_func, notify_baton, 356 cancel_func, cancel_baton, scratch_pool)); 357 358 return svn_error_trace(svn_wc__wq_run(db, local_abspath, 359 cancel_func, cancel_baton, 360 scratch_pool)); 361} 362