1251881Speter/* 2251881Speter * checkout.c: wrappers around wc checkout functionality 3251881Speter * 4251881Speter * ==================================================================== 5251881Speter * Licensed to the Apache Software Foundation (ASF) under one 6251881Speter * or more contributor license agreements. See the NOTICE file 7251881Speter * distributed with this work for additional information 8251881Speter * regarding copyright ownership. The ASF licenses this file 9251881Speter * to you under the Apache License, Version 2.0 (the 10251881Speter * "License"); you may not use this file except in compliance 11251881Speter * with the License. You may obtain a copy of the License at 12251881Speter * 13251881Speter * http://www.apache.org/licenses/LICENSE-2.0 14251881Speter * 15251881Speter * Unless required by applicable law or agreed to in writing, 16251881Speter * software distributed under the License is distributed on an 17251881Speter * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 18251881Speter * KIND, either express or implied. See the License for the 19251881Speter * specific language governing permissions and limitations 20251881Speter * under the License. 21251881Speter * ==================================================================== 22251881Speter */ 23251881Speter 24251881Speter/* ==================================================================== */ 25251881Speter 26251881Speter 27251881Speter 28251881Speter/*** Includes. ***/ 29251881Speter 30251881Speter#include "svn_pools.h" 31251881Speter#include "svn_wc.h" 32251881Speter#include "svn_client.h" 33251881Speter#include "svn_ra.h" 34251881Speter#include "svn_types.h" 35251881Speter#include "svn_error.h" 36251881Speter#include "svn_dirent_uri.h" 37251881Speter#include "svn_path.h" 38251881Speter#include "svn_io.h" 39251881Speter#include "svn_opt.h" 40251881Speter#include "svn_time.h" 41251881Speter#include "client.h" 42251881Speter 43251881Speter#include "private/svn_wc_private.h" 44251881Speter 45251881Speter#include "svn_private_config.h" 46251881Speter 47251881Speter 48251881Speter/*** Public Interfaces. ***/ 49251881Speter 50251881Speterstatic svn_error_t * 51251881Speterinitialize_area(const char *local_abspath, 52251881Speter const svn_client__pathrev_t *pathrev, 53251881Speter svn_depth_t depth, 54251881Speter svn_client_ctx_t *ctx, 55251881Speter apr_pool_t *pool) 56251881Speter{ 57251881Speter if (depth == svn_depth_unknown) 58251881Speter depth = svn_depth_infinity; 59251881Speter 60251881Speter /* Make the unversioned directory into a versioned one. */ 61251881Speter SVN_ERR(svn_wc_ensure_adm4(ctx->wc_ctx, local_abspath, pathrev->url, 62251881Speter pathrev->repos_root_url, pathrev->repos_uuid, 63251881Speter pathrev->rev, depth, pool)); 64251881Speter return SVN_NO_ERROR; 65251881Speter} 66251881Speter 67251881Speter 68251881Spetersvn_error_t * 69251881Spetersvn_client__checkout_internal(svn_revnum_t *result_rev, 70289180Speter svn_boolean_t *timestamp_sleep, 71251881Speter const char *url, 72251881Speter const char *local_abspath, 73251881Speter const svn_opt_revision_t *peg_revision, 74251881Speter const svn_opt_revision_t *revision, 75251881Speter svn_depth_t depth, 76251881Speter svn_boolean_t ignore_externals, 77251881Speter svn_boolean_t allow_unver_obstructions, 78289180Speter svn_ra_session_t *ra_session, 79251881Speter svn_client_ctx_t *ctx, 80289180Speter apr_pool_t *scratch_pool) 81251881Speter{ 82251881Speter svn_node_kind_t kind; 83251881Speter svn_client__pathrev_t *pathrev; 84362181Sdim svn_opt_revision_t resolved_rev = { svn_opt_revision_number }; 85251881Speter 86251881Speter /* Sanity check. Without these, the checkout is meaningless. */ 87251881Speter SVN_ERR_ASSERT(local_abspath != NULL); 88289180Speter SVN_ERR_ASSERT(svn_uri_is_canonical(url, scratch_pool)); 89251881Speter SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath)); 90251881Speter 91251881Speter /* Fulfill the docstring promise of svn_client_checkout: */ 92251881Speter if ((revision->kind != svn_opt_revision_number) 93251881Speter && (revision->kind != svn_opt_revision_date) 94251881Speter && (revision->kind != svn_opt_revision_head)) 95251881Speter return svn_error_create(SVN_ERR_CLIENT_BAD_REVISION, NULL, NULL); 96251881Speter 97289180Speter /* Get the RA connection, if needed. */ 98289180Speter if (ra_session) 99289180Speter { 100289180Speter svn_error_t *err = svn_ra_reparent(ra_session, url, scratch_pool); 101251881Speter 102289180Speter if (err) 103289180Speter { 104289180Speter if (err->apr_err == SVN_ERR_RA_ILLEGAL_URL) 105289180Speter { 106289180Speter svn_error_clear(err); 107289180Speter ra_session = NULL; 108289180Speter } 109289180Speter else 110289180Speter return svn_error_trace(err); 111289180Speter } 112289180Speter else 113289180Speter { 114289180Speter SVN_ERR(svn_client__resolve_rev_and_url(&pathrev, 115289180Speter ra_session, url, 116289180Speter peg_revision, revision, 117289180Speter ctx, scratch_pool)); 118289180Speter } 119289180Speter } 120251881Speter 121289180Speter if (!ra_session) 122289180Speter { 123289180Speter SVN_ERR(svn_client__ra_session_from_path2(&ra_session, &pathrev, 124289180Speter url, NULL, peg_revision, 125289180Speter revision, ctx, scratch_pool)); 126289180Speter } 127251881Speter 128289180Speter SVN_ERR(svn_ra_check_path(ra_session, "", pathrev->rev, &kind, scratch_pool)); 129362181Sdim resolved_rev.value.number = pathrev->rev; 130289180Speter 131251881Speter if (kind == svn_node_none) 132251881Speter return svn_error_createf(SVN_ERR_RA_ILLEGAL_URL, NULL, 133251881Speter _("URL '%s' doesn't exist"), pathrev->url); 134251881Speter else if (kind == svn_node_file) 135251881Speter return svn_error_createf 136251881Speter (SVN_ERR_UNSUPPORTED_FEATURE , NULL, 137251881Speter _("URL '%s' refers to a file, not a directory"), pathrev->url); 138251881Speter 139289180Speter SVN_ERR(svn_io_check_path(local_abspath, &kind, scratch_pool)); 140251881Speter 141251881Speter if (kind == svn_node_none) 142251881Speter { 143251881Speter /* Bootstrap: create an incomplete working-copy root dir. Its 144251881Speter entries file should only have an entry for THIS_DIR with a 145251881Speter URL, revnum, and an 'incomplete' flag. */ 146289180Speter SVN_ERR(svn_io_make_dir_recursively(local_abspath, scratch_pool)); 147289180Speter SVN_ERR(initialize_area(local_abspath, pathrev, depth, ctx, 148289180Speter scratch_pool)); 149251881Speter } 150251881Speter else if (kind == svn_node_dir) 151251881Speter { 152251881Speter int wc_format; 153251881Speter const char *entry_url; 154251881Speter 155289180Speter SVN_ERR(svn_wc_check_wc2(&wc_format, ctx->wc_ctx, local_abspath, 156289180Speter scratch_pool)); 157289180Speter 158251881Speter if (! wc_format) 159251881Speter { 160289180Speter SVN_ERR(initialize_area(local_abspath, pathrev, depth, ctx, 161289180Speter scratch_pool)); 162251881Speter } 163251881Speter else 164251881Speter { 165251881Speter /* Get PATH's URL. */ 166251881Speter SVN_ERR(svn_wc__node_get_url(&entry_url, ctx->wc_ctx, local_abspath, 167289180Speter scratch_pool, scratch_pool)); 168251881Speter 169251881Speter /* If PATH's existing URL matches the incoming one, then 170251881Speter just update. This allows 'svn co' to restart an 171251881Speter interrupted checkout. Otherwise bail out. */ 172251881Speter if (strcmp(entry_url, pathrev->url) != 0) 173251881Speter return svn_error_createf( 174251881Speter SVN_ERR_WC_OBSTRUCTED_UPDATE, NULL, 175251881Speter _("'%s' is already a working copy for a" 176251881Speter " different URL"), 177289180Speter svn_dirent_local_style(local_abspath, scratch_pool)); 178251881Speter } 179251881Speter } 180251881Speter else 181251881Speter { 182251881Speter return svn_error_createf(SVN_ERR_WC_NODE_KIND_CHANGE, NULL, 183251881Speter _("'%s' already exists and is not a directory"), 184289180Speter svn_dirent_local_style(local_abspath, 185289180Speter scratch_pool)); 186251881Speter } 187251881Speter 188251881Speter /* Have update fix the incompleteness. */ 189289180Speter SVN_ERR(svn_client__update_internal(result_rev, timestamp_sleep, 190362181Sdim local_abspath, &resolved_rev, depth, 191362181Sdim TRUE, ignore_externals, 192251881Speter allow_unver_obstructions, 193251881Speter TRUE /* adds_as_modification */, 194289180Speter FALSE, FALSE, ra_session, 195289180Speter ctx, scratch_pool)); 196251881Speter 197251881Speter return SVN_NO_ERROR; 198251881Speter} 199251881Speter 200251881Spetersvn_error_t * 201251881Spetersvn_client_checkout3(svn_revnum_t *result_rev, 202251881Speter const char *URL, 203251881Speter const char *path, 204251881Speter const svn_opt_revision_t *peg_revision, 205251881Speter const svn_opt_revision_t *revision, 206251881Speter svn_depth_t depth, 207251881Speter svn_boolean_t ignore_externals, 208251881Speter svn_boolean_t allow_unver_obstructions, 209251881Speter svn_client_ctx_t *ctx, 210251881Speter apr_pool_t *pool) 211251881Speter{ 212251881Speter const char *local_abspath; 213251881Speter svn_error_t *err; 214251881Speter svn_boolean_t sleep_here = FALSE; 215251881Speter 216251881Speter SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, pool)); 217251881Speter 218289180Speter err = svn_client__checkout_internal(result_rev, &sleep_here, 219289180Speter URL, local_abspath, 220251881Speter peg_revision, revision, depth, 221251881Speter ignore_externals, 222289180Speter allow_unver_obstructions, 223289180Speter NULL /* ra_session */, 224251881Speter ctx, pool); 225251881Speter if (sleep_here) 226251881Speter svn_io_sleep_for_timestamps(local_abspath, pool); 227251881Speter 228251881Speter return svn_error_trace(err); 229251881Speter} 230