]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - contrib/subversion/subversion/libsvn_client/checkout.c
MFC r275385 (by bapt):
[FreeBSD/stable/10.git] / contrib / subversion / subversion / libsvn_client / checkout.c
1 /*
2  * checkout.c:  wrappers around wc checkout functionality
3  *
4  * ====================================================================
5  *    Licensed to the Apache Software Foundation (ASF) under one
6  *    or more contributor license agreements.  See the NOTICE file
7  *    distributed with this work for additional information
8  *    regarding copyright ownership.  The ASF licenses this file
9  *    to you under the Apache License, Version 2.0 (the
10  *    "License"); you may not use this file except in compliance
11  *    with the License.  You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  *    Unless required by applicable law or agreed to in writing,
16  *    software distributed under the License is distributed on an
17  *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18  *    KIND, either express or implied.  See the License for the
19  *    specific language governing permissions and limitations
20  *    under the License.
21  * ====================================================================
22  */
23
24 /* ==================================================================== */
25
26
27 \f
28 /*** Includes. ***/
29
30 #include "svn_pools.h"
31 #include "svn_wc.h"
32 #include "svn_client.h"
33 #include "svn_ra.h"
34 #include "svn_types.h"
35 #include "svn_error.h"
36 #include "svn_dirent_uri.h"
37 #include "svn_path.h"
38 #include "svn_io.h"
39 #include "svn_opt.h"
40 #include "svn_time.h"
41 #include "client.h"
42
43 #include "private/svn_wc_private.h"
44
45 #include "svn_private_config.h"
46
47 \f
48 /*** Public Interfaces. ***/
49
50 static svn_error_t *
51 initialize_area(const char *local_abspath,
52                 const svn_client__pathrev_t *pathrev,
53                 svn_depth_t depth,
54                 svn_client_ctx_t *ctx,
55                 apr_pool_t *pool)
56 {
57   if (depth == svn_depth_unknown)
58     depth = svn_depth_infinity;
59
60   /* Make the unversioned directory into a versioned one.  */
61   SVN_ERR(svn_wc_ensure_adm4(ctx->wc_ctx, local_abspath, pathrev->url,
62                              pathrev->repos_root_url, pathrev->repos_uuid,
63                              pathrev->rev, depth, pool));
64   return SVN_NO_ERROR;
65 }
66
67
68 svn_error_t *
69 svn_client__checkout_internal(svn_revnum_t *result_rev,
70                               svn_boolean_t *timestamp_sleep,
71                               const char *url,
72                               const char *local_abspath,
73                               const svn_opt_revision_t *peg_revision,
74                               const svn_opt_revision_t *revision,
75                               svn_depth_t depth,
76                               svn_boolean_t ignore_externals,
77                               svn_boolean_t allow_unver_obstructions,
78                               svn_ra_session_t *ra_session,
79                               svn_client_ctx_t *ctx,
80                               apr_pool_t *scratch_pool)
81 {
82   svn_node_kind_t kind;
83   svn_client__pathrev_t *pathrev;
84
85   /* Sanity check.  Without these, the checkout is meaningless. */
86   SVN_ERR_ASSERT(local_abspath != NULL);
87   SVN_ERR_ASSERT(svn_uri_is_canonical(url, scratch_pool));
88   SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
89
90   /* Fulfill the docstring promise of svn_client_checkout: */
91   if ((revision->kind != svn_opt_revision_number)
92       && (revision->kind != svn_opt_revision_date)
93       && (revision->kind != svn_opt_revision_head))
94     return svn_error_create(SVN_ERR_CLIENT_BAD_REVISION, NULL, NULL);
95
96   /* Get the RA connection, if needed. */
97   if (ra_session)
98     {
99       svn_error_t *err = svn_ra_reparent(ra_session, url, scratch_pool);
100
101       if (err)
102         {
103           if (err->apr_err == SVN_ERR_RA_ILLEGAL_URL)
104             {
105               svn_error_clear(err);
106               ra_session = NULL;
107             }
108           else
109             return svn_error_trace(err);
110         }
111       else
112         {
113           SVN_ERR(svn_client__resolve_rev_and_url(&pathrev,
114                                                   ra_session, url,
115                                                   peg_revision, revision,
116                                                   ctx, scratch_pool));
117         }
118     }
119
120   if (!ra_session)
121     {
122       SVN_ERR(svn_client__ra_session_from_path2(&ra_session, &pathrev,
123                                                 url, NULL, peg_revision,
124                                                 revision, ctx, scratch_pool));
125     }
126
127   SVN_ERR(svn_ra_check_path(ra_session, "", pathrev->rev, &kind, scratch_pool));
128
129   if (kind == svn_node_none)
130     return svn_error_createf(SVN_ERR_RA_ILLEGAL_URL, NULL,
131                              _("URL '%s' doesn't exist"), pathrev->url);
132   else if (kind == svn_node_file)
133     return svn_error_createf
134       (SVN_ERR_UNSUPPORTED_FEATURE , NULL,
135        _("URL '%s' refers to a file, not a directory"), pathrev->url);
136
137   SVN_ERR(svn_io_check_path(local_abspath, &kind, scratch_pool));
138
139   if (kind == svn_node_none)
140     {
141       /* Bootstrap: create an incomplete working-copy root dir.  Its
142          entries file should only have an entry for THIS_DIR with a
143          URL, revnum, and an 'incomplete' flag.  */
144       SVN_ERR(svn_io_make_dir_recursively(local_abspath, scratch_pool));
145       SVN_ERR(initialize_area(local_abspath, pathrev, depth, ctx,
146                               scratch_pool));
147     }
148   else if (kind == svn_node_dir)
149     {
150       int wc_format;
151       const char *entry_url;
152
153       SVN_ERR(svn_wc_check_wc2(&wc_format, ctx->wc_ctx, local_abspath,
154                                scratch_pool));
155
156       if (! wc_format)
157         {
158           SVN_ERR(initialize_area(local_abspath, pathrev, depth, ctx,
159                                   scratch_pool));
160         }
161       else
162         {
163           /* Get PATH's URL. */
164           SVN_ERR(svn_wc__node_get_url(&entry_url, ctx->wc_ctx, local_abspath,
165                                        scratch_pool, scratch_pool));
166
167           /* If PATH's existing URL matches the incoming one, then
168              just update.  This allows 'svn co' to restart an
169              interrupted checkout.  Otherwise bail out. */
170           if (strcmp(entry_url, pathrev->url) != 0)
171             return svn_error_createf(
172                           SVN_ERR_WC_OBSTRUCTED_UPDATE, NULL,
173                           _("'%s' is already a working copy for a"
174                             " different URL"),
175                           svn_dirent_local_style(local_abspath, scratch_pool));
176         }
177     }
178   else
179     {
180       return svn_error_createf(SVN_ERR_WC_NODE_KIND_CHANGE, NULL,
181                                _("'%s' already exists and is not a directory"),
182                                svn_dirent_local_style(local_abspath,
183                                                       scratch_pool));
184     }
185
186   /* Have update fix the incompleteness. */
187   SVN_ERR(svn_client__update_internal(result_rev, timestamp_sleep,
188                                       local_abspath, revision, depth, TRUE,
189                                       ignore_externals,
190                                       allow_unver_obstructions,
191                                       TRUE /* adds_as_modification */,
192                                       FALSE, FALSE, ra_session,
193                                       ctx, scratch_pool));
194
195   return SVN_NO_ERROR;
196 }
197
198 svn_error_t *
199 svn_client_checkout3(svn_revnum_t *result_rev,
200                      const char *URL,
201                      const char *path,
202                      const svn_opt_revision_t *peg_revision,
203                      const svn_opt_revision_t *revision,
204                      svn_depth_t depth,
205                      svn_boolean_t ignore_externals,
206                      svn_boolean_t allow_unver_obstructions,
207                      svn_client_ctx_t *ctx,
208                      apr_pool_t *pool)
209 {
210   const char *local_abspath;
211   svn_error_t *err;
212   svn_boolean_t sleep_here = FALSE;
213
214   SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, pool));
215
216   err = svn_client__checkout_internal(result_rev, &sleep_here,
217                                       URL, local_abspath,
218                                       peg_revision, revision, depth,
219                                       ignore_externals,
220                                       allow_unver_obstructions,
221                                       NULL /* ra_session */,
222                                       ctx, pool);
223   if (sleep_here)
224     svn_io_sleep_for_timestamps(local_abspath, pool);
225
226   return svn_error_trace(err);
227 }