checkout-cmd.c revision 299742
1/*
2 * checkout-cmd.c -- Subversion checkout command
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
28/*** Includes. ***/
29
30#include "svn_client.h"
31#include "svn_dirent_uri.h"
32#include "svn_path.h"
33#include "svn_error.h"
34#include "svn_pools.h"
35#include "cl.h"
36
37#include "svn_private_config.h"
38
39
40/*** Code. ***/
41
42/*
43  This is what it does
44
45  - case 1: one URL
46    $ svn co http://host/repos/module
47    checkout into ./module/
48
49  - case 2: one URL and explicit path
50    $ svn co http://host/repos/module path
51    checkout into ./path/
52
53  - case 3: multiple URLs
54    $ svn co http://host1/repos1/module1 http://host2/repos2/module2
55    checkout into ./module1/ and ./module2/
56
57  - case 4: multiple URLs and explicit path
58    $ svn co http://host1/repos1/module1 http://host2/repos2/module2 path
59    checkout into ./path/module1/ and ./path/module2/
60
61  Is this the same as CVS?  Does it matter if it is not?
62*/
63
64
65/* This implements the `svn_opt_subcommand_t' interface. */
66svn_error_t *
67svn_cl__checkout(apr_getopt_t *os,
68                 void *baton,
69                 apr_pool_t *pool)
70{
71  svn_cl__opt_state_t *opt_state = ((svn_cl__cmd_baton_t *) baton)->opt_state;
72  svn_client_ctx_t *ctx = ((svn_cl__cmd_baton_t *) baton)->ctx;
73  apr_pool_t *subpool;
74  apr_array_header_t *targets;
75  struct svn_cl__check_externals_failed_notify_baton nwb;
76  const char *last_target, *local_dir;
77  int i;
78
79  SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os,
80                                                      opt_state->targets,
81                                                      ctx, FALSE, pool));
82
83  if (! targets->nelts)
84    return svn_error_create(SVN_ERR_CL_INSUFFICIENT_ARGS, NULL, NULL);
85
86  /* Determine LOCAL_DIR (case 1: URL basename; 2,4: specified; 3: "")
87   * and leave TARGETS holding just the source URLs. */
88  last_target = APR_ARRAY_IDX(targets, targets->nelts - 1, const char *);
89  if (svn_path_is_url(last_target))
90    {
91      if (targets->nelts == 1)
92        {
93          svn_opt_revision_t pegrev;
94
95          /* Use the URL basename, discarding any peg revision. */
96          SVN_ERR(svn_opt_parse_path(&pegrev, &local_dir, last_target, pool));
97          local_dir = svn_uri_basename(local_dir, pool);
98        }
99      else
100        {
101          local_dir = "";
102        }
103    }
104  else
105    {
106      if (targets->nelts == 1)
107        /* What?  They gave us one target, and it wasn't a URL. */
108        return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL, NULL);
109
110      apr_array_pop(targets);
111      local_dir = last_target;
112    }
113
114  if (! opt_state->quiet)
115    SVN_ERR(svn_cl__notifier_mark_checkout(ctx->notify_baton2));
116
117  nwb.wrapped_func = ctx->notify_func2;
118  nwb.wrapped_baton = ctx->notify_baton2;
119  nwb.had_externals_error = FALSE;
120  ctx->notify_func2 = svn_cl__check_externals_failed_notify_wrapper;
121  ctx->notify_baton2 = &nwb;
122
123  subpool = svn_pool_create(pool);
124  for (i = 0; i < targets->nelts; ++i)
125    {
126      const char *repos_url = APR_ARRAY_IDX(targets, i, const char *);
127      const char *target_dir;
128      const char *true_url;
129      svn_opt_revision_t revision = opt_state->start_revision;
130      svn_opt_revision_t peg_revision;
131
132      svn_pool_clear(subpool);
133
134      SVN_ERR(svn_cl__check_cancel(ctx->cancel_baton));
135
136      /* Validate the REPOS_URL */
137      if (! svn_path_is_url(repos_url))
138        return svn_error_createf
139          (SVN_ERR_BAD_URL, NULL,
140           _("'%s' does not appear to be a URL"), repos_url);
141
142      /* Get a possible peg revision. */
143      SVN_ERR(svn_opt_parse_path(&peg_revision, &true_url, repos_url,
144                                 subpool));
145
146      /* Use sub-directory of destination if checking-out multiple URLs */
147      if (targets->nelts == 1)
148        {
149          target_dir = local_dir;
150        }
151      else
152        {
153          target_dir = svn_dirent_join(local_dir,
154                                       svn_uri_basename(true_url, subpool),
155                                       subpool);
156        }
157
158      /* Checkout doesn't accept an unspecified revision, so default to
159         the peg revision, or to HEAD if there wasn't a peg. */
160      if (revision.kind == svn_opt_revision_unspecified)
161      {
162        if (peg_revision.kind != svn_opt_revision_unspecified)
163          revision = peg_revision;
164        else
165          revision.kind = svn_opt_revision_head;
166      }
167
168      SVN_ERR(svn_client_checkout3
169              (NULL, true_url, target_dir,
170               &peg_revision,
171               &revision,
172               opt_state->depth,
173               opt_state->ignore_externals,
174               opt_state->force,
175               ctx, subpool));
176    }
177  svn_pool_destroy(subpool);
178
179  if (nwb.had_externals_error)
180    return svn_error_create(SVN_ERR_CL_ERROR_PROCESSING_EXTERNALS, NULL,
181                            _("Failure occurred processing one or "
182                              "more externals definitions"));
183
184  return SVN_NO_ERROR;
185}
186