Reorganize the output to "svnserve --help".
[svn.git] / subversion / libsvn_client / checkout.c
blob8a670c1510423438c36a25c9ccb43516bf9118ce
1 /*
2 * checkout.c: wrappers around wc checkout functionality
4 * ====================================================================
5 * Copyright (c) 2000-2006 CollabNet. All rights reserved.
7 * This software is licensed as described in the file COPYING, which
8 * you should have received as part of this distribution. The terms
9 * are also available at http://subversion.tigris.org/license-1.html.
10 * If newer versions of this license are posted there, you may use a
11 * newer version instead, at your option.
13 * This software consists of voluntary contributions made by many
14 * individuals. For exact contribution history, see the revision
15 * history and logs, available at http://subversion.tigris.org/.
16 * ====================================================================
19 /* ==================================================================== */
23 /*** Includes. ***/
25 #include <assert.h>
26 #include "svn_pools.h"
27 #include "svn_wc.h"
28 #include "svn_client.h"
29 #include "svn_ra.h"
30 #include "svn_types.h"
31 #include "svn_error.h"
32 #include "svn_path.h"
33 #include "svn_io.h"
34 #include "svn_opt.h"
35 #include "svn_time.h"
36 #include "client.h"
38 #include "svn_private_config.h"
41 /*** Public Interfaces. ***/
44 svn_error_t *
45 svn_client__checkout_internal(svn_revnum_t *result_rev,
46 const char *url,
47 const char *path,
48 const svn_opt_revision_t *peg_revision,
49 const svn_opt_revision_t *revision,
50 svn_depth_t depth,
51 svn_boolean_t ignore_externals,
52 svn_boolean_t allow_unver_obstructions,
53 svn_boolean_t *timestamp_sleep,
54 svn_client_ctx_t *ctx,
55 apr_pool_t *pool)
57 svn_error_t *err = NULL;
58 svn_revnum_t revnum;
59 svn_boolean_t sleep_here = FALSE;
60 svn_boolean_t *use_sleep = timestamp_sleep ? timestamp_sleep : &sleep_here;
61 const char *session_url;
63 /* Sanity check. Without these, the checkout is meaningless. */
64 assert(path != NULL);
65 assert(url != NULL);
67 /* Fulfill the docstring promise of svn_client_checkout: */
68 if ((revision->kind != svn_opt_revision_number)
69 && (revision->kind != svn_opt_revision_date)
70 && (revision->kind != svn_opt_revision_head))
71 return svn_error_create(SVN_ERR_CLIENT_BAD_REVISION, NULL, NULL);
73 /* Canonicalize the URL. */
74 url = svn_path_canonicalize(url, pool);
77 svn_ra_session_t *ra_session;
78 svn_node_kind_t kind;
79 const char *uuid, *repos;
80 apr_pool_t *session_pool = svn_pool_create(pool);
82 /* Get the RA connection. */
83 SVN_ERR(svn_client__ra_session_from_path(&ra_session, &revnum,
84 &session_url, url, NULL,
85 peg_revision, revision, ctx,
86 session_pool));
88 SVN_ERR(svn_ra_check_path(ra_session, "", revnum, &kind, pool));
89 if (kind == svn_node_none)
90 return svn_error_createf(SVN_ERR_RA_ILLEGAL_URL, NULL,
91 _("URL '%s' doesn't exist"), session_url);
92 else if (kind == svn_node_file)
93 return svn_error_createf
94 (SVN_ERR_UNSUPPORTED_FEATURE , NULL,
95 _("URL '%s' refers to a file, not a directory"), session_url);
97 /* Get the repos UUID and root URL. */
98 SVN_ERR(svn_ra_get_uuid2(ra_session, &uuid, session_pool));
99 SVN_ERR(svn_ra_get_repos_root2(ra_session, &repos, session_pool));
101 SVN_ERR(svn_io_check_path(path, &kind, pool));
103 /* Finished with the RA session -- close up, but not without
104 copying out useful information that needs to survive. */
105 session_url = apr_pstrdup(pool, session_url);
106 uuid = (uuid ? apr_pstrdup(pool, uuid) : NULL);
107 repos = (repos ? apr_pstrdup(pool, repos) : NULL);
108 svn_pool_destroy(session_pool);
110 if (kind == svn_node_none)
112 /* Bootstrap: create an incomplete working-copy root dir. Its
113 entries file should only have an entry for THIS_DIR with a
114 URL, revnum, and an 'incomplete' flag. */
115 SVN_ERR(svn_io_make_dir_recursively(path, pool));
116 goto initialize_area;
118 else if (kind == svn_node_dir)
120 int wc_format;
121 const svn_wc_entry_t *entry;
122 svn_wc_adm_access_t *adm_access;
124 SVN_ERR(svn_wc_check_wc(path, &wc_format, pool));
125 if (! wc_format)
127 initialize_area:
129 if (depth == svn_depth_unknown)
130 depth = svn_depth_infinity;
132 /* Make the unversioned directory into a versioned one. */
133 SVN_ERR(svn_wc_ensure_adm3(path, uuid, session_url,
134 repos, revnum, depth, pool));
135 /* Have update fix the incompleteness. */
136 err = svn_client__update_internal(result_rev, path, revision,
137 depth, TRUE, ignore_externals,
138 allow_unver_obstructions,
139 use_sleep, FALSE,
140 ctx, pool);
141 goto done;
144 /* Get PATH's entry. */
145 SVN_ERR(svn_wc_adm_open3(&adm_access, NULL, path,
146 FALSE, 0, ctx->cancel_func,
147 ctx->cancel_baton, pool));
148 SVN_ERR(svn_wc_entry(&entry, path, adm_access, FALSE, pool));
149 SVN_ERR(svn_wc_adm_close(adm_access));
151 /* If PATH's existing URL matches the incoming one, then
152 just update. This allows 'svn co' to restart an
153 interrupted checkout. */
154 if (entry->url && (strcmp(entry->url, session_url) == 0))
156 err = svn_client__update_internal(result_rev, path, revision,
157 depth, TRUE, ignore_externals,
158 allow_unver_obstructions,
159 use_sleep, FALSE,
160 ctx, pool);
162 else
164 const char *errmsg;
165 errmsg = apr_psprintf
166 (pool,
167 _("'%s' is already a working copy for a different URL"),
168 svn_path_local_style(path, pool));
169 if (entry->incomplete)
170 errmsg = apr_pstrcat
171 (pool, errmsg, _("; run 'svn update' to complete it"), NULL);
173 return svn_error_create(SVN_ERR_WC_OBSTRUCTED_UPDATE, NULL,
174 errmsg);
177 else
179 return svn_error_createf
180 (SVN_ERR_WC_NODE_KIND_CHANGE, NULL,
181 _("'%s' already exists and is not a directory"),
182 svn_path_local_style(path, pool));
185 done:
186 if (err)
188 /* Don't rely on the error handling to handle the sleep later, do
189 it now */
190 svn_sleep_for_timestamps();
191 return err;
193 *use_sleep = TRUE;
196 if (sleep_here)
197 svn_sleep_for_timestamps();
199 return SVN_NO_ERROR;
202 svn_error_t *
203 svn_client_checkout3(svn_revnum_t *result_rev,
204 const char *URL,
205 const char *path,
206 const svn_opt_revision_t *peg_revision,
207 const svn_opt_revision_t *revision,
208 svn_depth_t depth,
209 svn_boolean_t ignore_externals,
210 svn_boolean_t allow_unver_obstructions,
211 svn_client_ctx_t *ctx,
212 apr_pool_t *pool)
214 return svn_client__checkout_internal(result_rev, URL, path, peg_revision,
215 revision, depth, ignore_externals,
216 allow_unver_obstructions, NULL, ctx,
217 pool);
220 svn_error_t *
221 svn_client_checkout2(svn_revnum_t *result_rev,
222 const char *URL,
223 const char *path,
224 const svn_opt_revision_t *peg_revision,
225 const svn_opt_revision_t *revision,
226 svn_boolean_t recurse,
227 svn_boolean_t ignore_externals,
228 svn_client_ctx_t *ctx,
229 apr_pool_t *pool)
231 return svn_client__checkout_internal(result_rev, URL, path, peg_revision,
232 revision,
233 SVN_DEPTH_INFINITY_OR_FILES(recurse),
234 ignore_externals, FALSE, NULL, ctx,
235 pool);
238 svn_error_t *
239 svn_client_checkout(svn_revnum_t *result_rev,
240 const char *URL,
241 const char *path,
242 const svn_opt_revision_t *revision,
243 svn_boolean_t recurse,
244 svn_client_ctx_t *ctx,
245 apr_pool_t *pool)
247 svn_opt_revision_t peg_revision;
249 peg_revision.kind = svn_opt_revision_unspecified;
251 return svn_client__checkout_internal(result_rev, URL, path, &peg_revision,
252 revision,
253 SVN_DEPTH_INFINITY_OR_FILES(recurse),
254 FALSE, FALSE, NULL, ctx, pool);