/*
* checkout.c: wrappers around wc checkout functionality
*
* ====================================================================
* Copyright (c) 2000-2004 CollabNet. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://subversion.tigris.org/license-1.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
*
* This software consists of voluntary contributions made by many
* individuals. For exact contribution history, see the revision
* history and logs, available at http://subversion.tigris.org/.
* ====================================================================
*/
/* ==================================================================== */
/*** Includes. ***/
#include <assert.h>
#include "svn_pools.h"
#include "svn_wc.h"
#include "svn_client.h"
#include "svn_ra.h"
#include "svn_types.h"
#include "svn_error.h"
#include "svn_path.h"
#include "svn_io.h"
#include "svn_opt.h"
#include "svn_time.h"
#include "client.h"
#include "svn_private_config.h"
/*** Public Interfaces. ***/
svn_error_t *
svn_client__checkout_internal(svn_revnum_t *result_rev,
const char *url,
const char *path,
const svn_opt_revision_t *peg_revision,
const svn_opt_revision_t *revision,
svn_boolean_t recurse,
svn_boolean_t ignore_externals,
svn_boolean_t *timestamp_sleep,
svn_client_ctx_t *ctx,
apr_pool_t *pool)
{
svn_wc_traversal_info_t *traversal_info = svn_wc_init_traversal_info(pool);
svn_error_t *err = NULL;
svn_revnum_t revnum;
svn_boolean_t sleep_here = FALSE;
svn_boolean_t *use_sleep = timestamp_sleep ? timestamp_sleep : &sleep_here;
const char *session_url;
/* Sanity check. Without these, the checkout is meaningless. */
assert(path != NULL);
assert(url != NULL);
/* Fulfill the docstring promise of svn_client_checkout: */
if ((revision->kind != svn_opt_revision_number)
&& (revision->kind != svn_opt_revision_date)
&& (revision->kind != svn_opt_revision_head))
return svn_error_create(SVN_ERR_CLIENT_BAD_REVISION, NULL, NULL);
/* Canonicalize the URL. */
url = svn_path_canonicalize(url, pool);
{
svn_ra_session_t *ra_session;
svn_node_kind_t kind;
const char *uuid, *repos;
apr_pool_t *session_pool = svn_pool_create(pool);
/* Get the RA connection. */
SVN_ERR(svn_client__ra_session_from_path(&ra_session, &revnum,
&session_url, url,
peg_revision, revision, ctx,
session_pool));
SVN_ERR(svn_ra_check_path(ra_session, "", revnum, &kind, pool));
if (kind == svn_node_none)
return svn_error_createf(SVN_ERR_RA_ILLEGAL_URL, NULL,
_("URL '%s' doesn't exist"), session_url);
else if (kind == svn_node_file)
return svn_error_createf
(SVN_ERR_UNSUPPORTED_FEATURE , NULL,
_("URL '%s' refers to a file, not a directory"), session_url);
/* Get the repos UUID and root URL. */
SVN_ERR(svn_ra_get_uuid(ra_session, &uuid, pool));
SVN_ERR(svn_ra_get_repos_root(ra_session, &repos, pool));
SVN_ERR(svn_io_check_path(path, &kind, pool));
/* Finished with the RA session -- close up, but not without
copying out useful information that needs to survive. */
session_url = apr_pstrdup(pool, session_url);
uuid = (uuid ? apr_pstrdup(pool, uuid) : NULL);
repos = (repos ? apr_pstrdup(pool, repos) : NULL);
svn_pool_destroy(session_pool);
if (kind == svn_node_none)
{
/* Bootstrap: create an incomplete working-copy root dir. Its
entries file should only have an entry for THIS_DIR with a
URL, revnum, and an 'incomplete' flag. */
SVN_ERR(svn_io_make_dir_recursively(path, pool));
SVN_ERR(svn_wc_ensure_adm2(path, uuid, session_url,
repos, revnum, pool));
/* Have update fix the incompleteness. */
err = svn_client__update_internal(result_rev, path, revision,
recurse, ignore_externals,
use_sleep, ctx, pool);
}
else if (kind == svn_node_dir)
{
int wc_format;
const svn_wc_entry_t *entry;
svn_wc_adm_access_t *adm_access;
SVN_ERR(svn_wc_check_wc(path, &wc_format, pool));
if (! wc_format)
{
/* Make the unversioned directory into a versioned one. */
SVN_ERR(svn_wc_ensure_adm2(path, uuid, session_url,
repos, revnum, pool));
err = svn_client__update_internal(result_rev, path, revision,
recurse, ignore_externals,
use_sleep, ctx, pool);
goto done;
}
/* Get PATH's entry. */
SVN_ERR(svn_wc_adm_open3(&adm_access, NULL, path,
FALSE, 0, ctx->cancel_func,
ctx->cancel_baton, pool));
SVN_ERR(svn_wc_entry(&entry, path, adm_access, FALSE, pool));
SVN_ERR(svn_wc_adm_close(adm_access));
/* If PATH's existing URL matches the incoming one, then
just update. This allows 'svn co' to restart an
interrupted checkout. */
if (entry->url && (strcmp(entry->url, session_url) == 0))
{
err = svn_client__update_internal(result_rev, path, revision,
recurse, ignore_externals,
use_sleep, ctx, pool);
}
else
{
const char *errmsg;
errmsg = apr_psprintf
(pool,
_("'%s' is already a working copy for a different URL"),
svn_path_local_style(path, pool));
if (entry->incomplete)
errmsg = apr_pstrcat
(pool, errmsg, _("; run 'svn update' to complete it"), NULL);
return svn_error_create(SVN_ERR_WC_OBSTRUCTED_UPDATE, NULL,
errmsg);
}
}
else
{
return svn_error_createf
(SVN_ERR_WC_NODE_KIND_CHANGE, NULL,
_("'%s' already exists and is not a directory"),
svn_path_local_style(path, pool));
}
done:
if (err)
{
/* Don't rely on the error handling to handle the sleep later, do
it now */
svn_sleep_for_timestamps();
return err;
}
*use_sleep = TRUE;
}
/* We handle externals after the initial checkout is complete, so
that fetching external items (and any errors therefrom) doesn't
delay the primary checkout.
### Should we really do externals if recurse is false?
*/
SVN_ERR(svn_client__handle_externals(traversal_info, FALSE, use_sleep,
ctx, pool));
if (sleep_here)
svn_sleep_for_timestamps();
return SVN_NO_ERROR;
}
svn_error_t *
svn_client_checkout2(svn_revnum_t *result_rev,
const char *URL,
const char *path,
const svn_opt_revision_t *peg_revision,
const svn_opt_revision_t *revision,
svn_boolean_t recurse,
svn_boolean_t ignore_externals,
svn_client_ctx_t *ctx,
apr_pool_t *pool)
{
return svn_client__checkout_internal(result_rev, URL, path, peg_revision,
revision, recurse, ignore_externals,
NULL, ctx, pool);
}
svn_error_t *
svn_client_checkout(svn_revnum_t *result_rev,
const char *URL,
const char *path,
const svn_opt_revision_t *revision,
svn_boolean_t recurse,
svn_client_ctx_t *ctx,
apr_pool_t *pool)
{
svn_opt_revision_t peg_revision;
peg_revision.kind = svn_opt_revision_unspecified;
return svn_client__checkout_internal(result_rev, URL, path, &peg_revision,
revision, recurse, FALSE, NULL,
ctx, pool);
}
syntax highlighted by Code2HTML, v. 0.9.1