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