blob: bfa7ec1039f1eab87e9be0ca9f0921cb76ac4933 [file] [log] [blame]
/*
* 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;
}