| /* |
| * layout.c: code to list and update the working copy layout |
| * |
| * ==================================================================== |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * ==================================================================== |
| */ |
| |
| /* ==================================================================== */ |
| |
| |
| |
| /*** Includes. ***/ |
| |
| #include "svn_hash.h" |
| #include "svn_dirent_uri.h" |
| #include "svn_path.h" |
| #include "svn_wc.h" |
| #include "svn_client.h" |
| #include "svn_error.h" |
| #include "svn_pools.h" |
| #include "client.h" |
| |
| #include "svn_private_config.h" |
| #include "private/svn_wc_private.h" |
| |
| struct layout_item_t |
| { |
| const char *local_abspath; |
| const char *url; |
| svn_revnum_t revision; |
| svn_depth_t depth; |
| struct layout_item_t *ancestor; |
| apr_pool_t *pool; |
| }; |
| |
| struct client_layout_baton_t |
| { |
| const char *root_abspath; |
| svn_wc_context_t *wc_ctx; |
| const char *repos_root_url; |
| |
| struct layout_item_t *stack; |
| apr_pool_t *root_pool; |
| |
| svn_client__layout_func_t layout; |
| void *layout_baton; |
| }; |
| |
| |
| static svn_error_t * |
| layout_set_path(void *report_baton, |
| const char *path, |
| svn_revnum_t revision, |
| svn_depth_t depth, |
| svn_boolean_t start_empty, |
| const char *lock_token, |
| apr_pool_t *pool) |
| { |
| struct client_layout_baton_t *lb = report_baton; |
| const char *local_abspath = svn_dirent_join(lb->root_abspath, path, pool); |
| struct layout_item_t *it; |
| apr_pool_t *item_pool; |
| svn_depth_t expected_depth; |
| |
| while (lb->stack |
| && !svn_dirent_is_ancestor(lb->stack->local_abspath, local_abspath)) |
| { |
| it = lb->stack; |
| lb->stack = it->ancestor; |
| svn_pool_destroy(it->pool); |
| } |
| |
| item_pool = svn_pool_create(lb->stack ? lb->stack->pool |
| : lb->root_pool); |
| |
| it = apr_pcalloc(item_pool, sizeof(*it)); |
| it->pool = item_pool; |
| it->local_abspath = apr_pstrdup(item_pool, local_abspath); |
| it->depth = depth; |
| it->revision = revision; |
| if (lb->stack) |
| { |
| it->url = svn_path_url_add_component2( |
| lb->stack->url, |
| svn_dirent_skip_ancestor(lb->stack->local_abspath, |
| local_abspath), |
| item_pool); |
| } |
| else |
| { |
| const char *repos_relpath, *repos_root_url; |
| |
| SVN_ERR(svn_wc__node_get_base(NULL, NULL, &repos_relpath, |
| &repos_root_url, NULL, NULL, |
| lb->wc_ctx, local_abspath, |
| FALSE /* ignore_enoent */, |
| pool, pool)); |
| |
| lb->repos_root_url = apr_pstrdup(lb->root_pool, repos_root_url); |
| it->url = svn_path_url_add_component2(repos_root_url, repos_relpath, |
| item_pool); |
| } |
| it->ancestor = lb->stack; |
| lb->stack = it; |
| |
| if (!it->ancestor) |
| expected_depth = depth; |
| else if (it->ancestor->depth == svn_depth_infinity) |
| expected_depth = svn_depth_infinity; |
| else |
| expected_depth = svn_depth_empty; |
| |
| return svn_error_trace(lb->layout(lb->layout_baton, |
| it->local_abspath, |
| lb->repos_root_url, |
| FALSE /* not-present */, |
| FALSE /* url changed */, |
| it->url, |
| it->ancestor |
| ? it->ancestor->revision != it->revision |
| : FALSE, |
| it->revision, |
| (depth != expected_depth), |
| it->depth, |
| pool)); |
| } |
| |
| static svn_error_t * |
| layout_link_path(void *report_baton, |
| const char *path, |
| const char *url, |
| svn_revnum_t revision, |
| svn_depth_t depth, |
| svn_boolean_t start_empty, |
| const char *lock_token, |
| apr_pool_t *pool) |
| { |
| struct client_layout_baton_t *lb = report_baton; |
| const char *local_abspath = svn_dirent_join(lb->root_abspath, path, pool); |
| struct layout_item_t *it; |
| apr_pool_t *item_pool; |
| svn_depth_t expected_depth; |
| |
| SVN_ERR_ASSERT(lb->stack); /* Always below root entry */ |
| |
| while (!svn_dirent_is_ancestor(lb->stack->local_abspath, local_abspath)) |
| { |
| it = lb->stack; |
| lb->stack = it->ancestor; |
| svn_pool_destroy(it->pool); |
| } |
| |
| item_pool = svn_pool_create(lb->stack ? lb->stack->pool |
| : lb->root_pool); |
| |
| it = apr_pcalloc(item_pool, sizeof(*it)); |
| it->pool = item_pool; |
| it->local_abspath = apr_pstrdup(item_pool, local_abspath); |
| it->depth = depth; |
| it->revision = revision; |
| it->url = apr_pstrdup(item_pool, url); |
| |
| it->ancestor = lb->stack; |
| lb->stack = it; |
| |
| if (it->ancestor->depth == svn_depth_infinity) |
| expected_depth = svn_depth_infinity; |
| else |
| expected_depth = svn_depth_empty; |
| |
| return svn_error_trace(lb->layout(lb->layout_baton, |
| it->local_abspath, |
| lb->repos_root_url, |
| FALSE /* not-present */, |
| TRUE /* url changed */, |
| it->url, |
| it->ancestor |
| ? it->ancestor->revision != it->revision |
| : FALSE, |
| it->revision, |
| (depth != expected_depth), |
| it->depth, |
| pool)); |
| } |
| |
| static svn_error_t * |
| layout_delete_path(void *report_baton, |
| const char *path, |
| apr_pool_t *pool) |
| { |
| struct client_layout_baton_t *lb = report_baton; |
| const char *local_abspath = svn_dirent_join(lb->root_abspath, path, pool); |
| struct layout_item_t *it; |
| |
| SVN_ERR_ASSERT(lb->stack); /* Always below root entry */ |
| |
| while (!svn_dirent_is_ancestor(lb->stack->local_abspath, local_abspath)) |
| { |
| it = lb->stack; |
| lb->stack = it->ancestor; |
| svn_pool_destroy(it->pool); |
| } |
| |
| return svn_error_trace(lb->layout(lb->layout_baton, |
| local_abspath, |
| lb->repos_root_url, |
| TRUE /* not-present */, |
| FALSE /* url changed */, |
| NULL /* no-url */, |
| FALSE /* revision changed */, |
| SVN_INVALID_REVNUM, |
| FALSE /* depth changed */, |
| svn_depth_unknown, |
| pool)); |
| } |
| |
| static svn_error_t * |
| layout_finish_report(void *report_baton, |
| apr_pool_t *pool) |
| { |
| /*struct client_layout_baton_t *lb = report_baton;*/ |
| return SVN_NO_ERROR; |
| } |
| |
| static svn_error_t * |
| layout_abort_report(void *report_baton, |
| apr_pool_t *pool) |
| { |
| /*struct client_layout_baton_t *lb = report_baton;*/ |
| return SVN_NO_ERROR; |
| } |
| |
| static const svn_ra_reporter3_t layout_reporter = |
| { |
| layout_set_path, |
| layout_delete_path, |
| layout_link_path, |
| layout_finish_report, |
| layout_abort_report |
| }; |
| |
| svn_error_t * |
| svn_client__layout_list(const char *local_abspath, |
| svn_client__layout_func_t layout, |
| void *layout_baton, |
| svn_client_ctx_t *ctx, |
| apr_pool_t *scratch_pool) |
| { |
| struct client_layout_baton_t lb; |
| |
| lb.root_abspath = local_abspath; |
| lb.root_pool = scratch_pool; |
| lb.wc_ctx = ctx->wc_ctx; |
| lb.repos_root_url = NULL; /* Filled in later */ |
| lb.stack = NULL; |
| |
| lb.layout = layout; |
| lb.layout_baton = layout_baton; |
| |
| /* Drive the reporter structure, describing the revisions within |
| LOCAL_ABSPATH. */ |
| SVN_ERR(svn_wc_crawl_revisions5(ctx->wc_ctx, local_abspath, |
| &layout_reporter, &lb, |
| FALSE /* restore_files */, |
| svn_depth_infinity, |
| TRUE /* honor_depth_exclude */, |
| FALSE /* depth_compatibility_trick */, |
| FALSE /* use_commit_times */, |
| ctx->cancel_func, ctx->cancel_baton, |
| ctx->notify_func2, ctx->notify_baton2, |
| scratch_pool)); |
| return SVN_NO_ERROR; |
| } |