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 /* ==================================================================== */
26 #include "svn_pools.h"
28 #include "svn_client.h"
30 #include "svn_types.h"
31 #include "svn_error.h"
38 #include "svn_private_config.h"
41 /*** Public Interfaces. ***/
45 svn_client__checkout_internal(svn_revnum_t
*result_rev
,
48 const svn_opt_revision_t
*peg_revision
,
49 const svn_opt_revision_t
*revision
,
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
,
57 svn_error_t
*err
= NULL
;
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. */
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
;
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
,
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
)
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
));
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
,
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
,
165 errmsg
= apr_psprintf
167 _("'%s' is already a working copy for a different URL"),
168 svn_path_local_style(path
, pool
));
169 if (entry
->incomplete
)
171 (pool
, errmsg
, _("; run 'svn update' to complete it"), NULL
);
173 return svn_error_create(SVN_ERR_WC_OBSTRUCTED_UPDATE
, NULL
,
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
));
188 /* Don't rely on the error handling to handle the sleep later, do
190 svn_sleep_for_timestamps();
197 svn_sleep_for_timestamps();
203 svn_client_checkout3(svn_revnum_t
*result_rev
,
206 const svn_opt_revision_t
*peg_revision
,
207 const svn_opt_revision_t
*revision
,
209 svn_boolean_t ignore_externals
,
210 svn_boolean_t allow_unver_obstructions
,
211 svn_client_ctx_t
*ctx
,
214 return svn_client__checkout_internal(result_rev
, URL
, path
, peg_revision
,
215 revision
, depth
, ignore_externals
,
216 allow_unver_obstructions
, NULL
, ctx
,
221 svn_client_checkout2(svn_revnum_t
*result_rev
,
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
,
231 return svn_client__checkout_internal(result_rev
, URL
, path
, peg_revision
,
233 SVN_DEPTH_INFINITY_OR_FILES(recurse
),
234 ignore_externals
, FALSE
, NULL
, ctx
,
239 svn_client_checkout(svn_revnum_t
*result_rev
,
242 const svn_opt_revision_t
*revision
,
243 svn_boolean_t recurse
,
244 svn_client_ctx_t
*ctx
,
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
,
253 SVN_DEPTH_INFINITY_OR_FILES(recurse
),
254 FALSE
, FALSE
, NULL
, ctx
, pool
);