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  const char *last_target, *local_dir;
76  int i;
77
78  SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os,
79                                                      opt_state->targets,
80                                                      ctx, FALSE, pool));
81
82  if (! targets->nelts)
83    return svn_error_create(SVN_ERR_CL_INSUFFICIENT_ARGS, NULL, NULL);
84
85  /* Determine LOCAL_DIR (case 1: URL basename; 2,4: specified; 3: "")
86   * and leave TARGETS holding just the source URLs. */
87  last_target = APR_ARRAY_IDX(targets, targets->nelts - 1, const char *);
88  if (svn_path_is_url(last_target))
89    {
90      if (targets->nelts == 1)
91        {
92          svn_opt_revision_t pegrev;
93
94          /* Use the URL basename, discarding any peg revision. */
95          SVN_ERR(svn_opt_parse_path(&pegrev, &local_dir, last_target, pool));
96          local_dir = svn_uri_basename(local_dir, pool);
97        }
98      else
99        {
100          local_dir = "";
101        }
102    }
103  else
104    {
105      if (targets->nelts == 1)
106        /* What?  They gave us one target, and it wasn't a URL. */
107        return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL, NULL);
108
109      apr_array_pop(targets);
110      local_dir = last_target;
111    }
112
113  if (! opt_state->quiet)
114    SVN_ERR(svn_cl__notifier_mark_checkout(ctx->notify_baton2));
115
116  subpool = svn_pool_create(pool);
117  for (i = 0; i < targets->nelts; ++i)
118    {
119      const char *repos_url = APR_ARRAY_IDX(targets, i, const char *);
120      const char *target_dir;
121      const char *true_url;
122      svn_opt_revision_t revision = opt_state->start_revision;
123      svn_opt_revision_t peg_revision;
124
125      svn_pool_clear(subpool);
126
127      SVN_ERR(svn_cl__check_cancel(ctx->cancel_baton));
128
129      /* Validate the REPOS_URL */
130      if (! svn_path_is_url(repos_url))
131        return svn_error_createf
132          (SVN_ERR_BAD_URL, NULL,
133           _("'%s' does not appear to be a URL"), repos_url);
134
135      /* Get a possible peg revision. */
136      SVN_ERR(svn_opt_parse_path(&peg_revision, &true_url, repos_url,
137                                 subpool));
138
139      /* Use sub-directory of destination if checking-out multiple URLs */
140      if (targets->nelts == 1)
141        {
142          target_dir = local_dir;
143        }
144      else
145        {
146          target_dir = svn_dirent_join(local_dir,
147                                       svn_uri_basename(true_url, subpool),
148                                       subpool);
149        }
150
151      /* Checkout doesn't accept an unspecified revision, so default to
152         the peg revision, or to HEAD if there wasn't a peg. */
153      if (revision.kind == svn_opt_revision_unspecified)
154      {
155        if (peg_revision.kind != svn_opt_revision_unspecified)
156          revision = peg_revision;
157        else
158          revision.kind = svn_opt_revision_head;
159      }
160
161      SVN_ERR(svn_client_checkout3
162              (NULL, true_url, target_dir,
163               &peg_revision,
164               &revision,
165               opt_state->depth,
166               opt_state->ignore_externals,
167               opt_state->force,
168               ctx, subpool));
169    }
170  svn_pool_destroy(subpool);
171
172  return SVN_NO_ERROR;
173}
174