1251881Speter/*
2251881Speter * update-cmd.c -- Bring work tree in sync with repository
3251881Speter *
4251881Speter * ====================================================================
5251881Speter *    Licensed to the Apache Software Foundation (ASF) under one
6251881Speter *    or more contributor license agreements.  See the NOTICE file
7251881Speter *    distributed with this work for additional information
8251881Speter *    regarding copyright ownership.  The ASF licenses this file
9251881Speter *    to you under the Apache License, Version 2.0 (the
10251881Speter *    "License"); you may not use this file except in compliance
11251881Speter *    with the License.  You may obtain a copy of the License at
12251881Speter *
13251881Speter *      http://www.apache.org/licenses/LICENSE-2.0
14251881Speter *
15251881Speter *    Unless required by applicable law or agreed to in writing,
16251881Speter *    software distributed under the License is distributed on an
17251881Speter *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18251881Speter *    KIND, either express or implied.  See the License for the
19251881Speter *    specific language governing permissions and limitations
20251881Speter *    under the License.
21251881Speter * ====================================================================
22251881Speter */
23251881Speter
24251881Speter/* ==================================================================== */
25251881Speter
26251881Speter
27251881Speter
28251881Speter/*** Includes. ***/
29251881Speter
30251881Speter#include "svn_pools.h"
31251881Speter#include "svn_client.h"
32251881Speter#include "svn_path.h"
33251881Speter#include "svn_error_codes.h"
34251881Speter#include "svn_error.h"
35251881Speter#include "cl.h"
36251881Speter
37251881Speter#include "svn_private_config.h"
38251881Speter
39251881Speter
40251881Speter/*** Code. ***/
41251881Speter
42251881Speter/* Print an update summary when there's more than one target to report
43251881Speter   about.  Each (const char *) path in TARGETS is an absolute or relative
44251881Speter   dirent, and each (svn_revnum_t) entry in RESULT_REVS is the corresponding
45251881Speter   updated revision, or SVN_INVALID_REVNUM if not a valid target. */
46251881Speterstatic svn_error_t *
47251881Speterprint_update_summary(apr_array_header_t *targets,
48251881Speter                     apr_array_header_t *result_revs,
49251881Speter                     apr_pool_t *scratch_pool)
50251881Speter{
51251881Speter  int i;
52251881Speter  const char *path_prefix;
53251881Speter  apr_pool_t *iterpool;
54251881Speter  svn_boolean_t printed_header = FALSE;
55251881Speter
56251881Speter  if (targets->nelts < 2)
57251881Speter    return SVN_NO_ERROR;
58251881Speter
59251881Speter  SVN_ERR(svn_dirent_get_absolute(&path_prefix, "", scratch_pool));
60251881Speter
61251881Speter  iterpool = svn_pool_create(scratch_pool);
62251881Speter
63251881Speter  for (i = 0; i < targets->nelts; i++)
64251881Speter    {
65251881Speter      const char *path = APR_ARRAY_IDX(targets, i, const char *);
66251881Speter      svn_revnum_t rev = SVN_INVALID_REVNUM;
67251881Speter
68251881Speter      svn_pool_clear(iterpool);
69251881Speter
70251881Speter      /* PATH shouldn't be a URL. */
71251881Speter      SVN_ERR_ASSERT(! svn_path_is_url(path));
72251881Speter
73251881Speter      /* Grab the result revision from the corresponding slot in our
74251881Speter         RESULT_REVS array. */
75251881Speter      if (i < result_revs->nelts)
76251881Speter        rev = APR_ARRAY_IDX(result_revs, i, svn_revnum_t);
77251881Speter
78251881Speter      /* No result rev?  We must have skipped this path.  At any rate,
79251881Speter         nothing to report here. */
80251881Speter      if (! SVN_IS_VALID_REVNUM(rev))
81251881Speter        continue;
82251881Speter
83251881Speter      /* Convert to an absolute path if it's not already. */
84251881Speter      if (! svn_dirent_is_absolute(path))
85251881Speter        SVN_ERR(svn_dirent_get_absolute(&path, path, iterpool));
86251881Speter
87251881Speter      /* Print an update summary for this target, removing the current
88251881Speter         working directory prefix from PATH (if PATH is at or under
89251881Speter         $CWD), and converting the path to local style for display. */
90251881Speter      if (! printed_header)
91251881Speter        {
92251881Speter          SVN_ERR(svn_cmdline_printf(scratch_pool,
93251881Speter                                     _("Summary of updates:\n")));
94251881Speter          printed_header = TRUE;
95251881Speter        }
96251881Speter
97251881Speter      SVN_ERR(svn_cmdline_printf(iterpool, _("  Updated '%s' to r%ld.\n"),
98251881Speter                                 svn_cl__local_style_skip_ancestor(
99251881Speter                                   path_prefix, path, iterpool),
100251881Speter                                 rev));
101251881Speter    }
102251881Speter
103251881Speter  svn_pool_destroy(iterpool);
104251881Speter  return SVN_NO_ERROR;
105251881Speter}
106251881Speter
107251881Speter/* This implements the `svn_opt_subcommand_t' interface. */
108251881Spetersvn_error_t *
109251881Spetersvn_cl__update(apr_getopt_t *os,
110251881Speter               void *baton,
111251881Speter               apr_pool_t *scratch_pool)
112251881Speter{
113251881Speter  svn_cl__opt_state_t *opt_state = ((svn_cl__cmd_baton_t *) baton)->opt_state;
114251881Speter  svn_client_ctx_t *ctx = ((svn_cl__cmd_baton_t *) baton)->ctx;
115251881Speter  apr_array_header_t *targets;
116251881Speter  svn_depth_t depth;
117251881Speter  svn_boolean_t depth_is_sticky;
118251881Speter  struct svn_cl__check_externals_failed_notify_baton nwb;
119251881Speter  apr_array_header_t *result_revs;
120251881Speter  svn_error_t *err = SVN_NO_ERROR;
121251881Speter  svn_error_t *externals_err = SVN_NO_ERROR;
122251881Speter
123251881Speter  SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os,
124251881Speter                                                      opt_state->targets,
125251881Speter                                                      ctx, FALSE,
126251881Speter                                                      scratch_pool));
127251881Speter
128251881Speter  /* Add "." if user passed 0 arguments */
129251881Speter  svn_opt_push_implicit_dot_target(targets, scratch_pool);
130251881Speter
131251881Speter  SVN_ERR(svn_cl__eat_peg_revisions(&targets, targets, scratch_pool));
132251881Speter
133251881Speter  SVN_ERR(svn_cl__check_targets_are_local_paths(targets));
134251881Speter
135251881Speter  /* If using changelists, convert targets into a set of paths that
136251881Speter     match the specified changelist(s). */
137251881Speter  if (opt_state->changelists)
138251881Speter    {
139251881Speter      svn_depth_t cl_depth = opt_state->depth;
140251881Speter      if (cl_depth == svn_depth_unknown)
141251881Speter        cl_depth = svn_depth_infinity;
142251881Speter      SVN_ERR(svn_cl__changelist_paths(&targets,
143251881Speter                                       opt_state->changelists, targets,
144251881Speter                                       cl_depth, ctx, scratch_pool,
145251881Speter                                       scratch_pool));
146251881Speter    }
147251881Speter
148251881Speter  /* Deal with depthstuffs. */
149251881Speter  if (opt_state->set_depth != svn_depth_unknown)
150251881Speter    {
151251881Speter      depth = opt_state->set_depth;
152251881Speter      depth_is_sticky = TRUE;
153251881Speter    }
154251881Speter  else
155251881Speter    {
156251881Speter      depth = opt_state->depth;
157251881Speter      depth_is_sticky = FALSE;
158251881Speter    }
159251881Speter
160251881Speter  nwb.wrapped_func = ctx->notify_func2;
161251881Speter  nwb.wrapped_baton = ctx->notify_baton2;
162251881Speter  nwb.had_externals_error = FALSE;
163251881Speter  ctx->notify_func2 = svn_cl__check_externals_failed_notify_wrapper;
164251881Speter  ctx->notify_baton2 = &nwb;
165251881Speter
166251881Speter  SVN_ERR(svn_client_update4(&result_revs, targets,
167251881Speter                             &(opt_state->start_revision),
168251881Speter                             depth, depth_is_sticky,
169251881Speter                             opt_state->ignore_externals,
170251881Speter                             opt_state->force, TRUE /* adds_as_modification */,
171251881Speter                             opt_state->parents,
172251881Speter                             ctx, scratch_pool));
173251881Speter
174251881Speter  if (nwb.had_externals_error)
175251881Speter    externals_err = svn_error_create(SVN_ERR_CL_ERROR_PROCESSING_EXTERNALS,
176251881Speter                                     NULL,
177251881Speter                                     _("Failure occurred processing one or "
178251881Speter                                       "more externals definitions"));
179251881Speter
180251881Speter  if (! opt_state->quiet)
181251881Speter    {
182251881Speter      err = print_update_summary(targets, result_revs, scratch_pool);
183251881Speter      if (err)
184251881Speter        return svn_error_compose_create(externals_err, err);
185251881Speter
186251881Speter      /* ### Layering problem: This call assumes that the baton we're
187251881Speter       * passing is the one that was originally provided by
188251881Speter       * svn_cl__get_notifier(), but that isn't promised. */
189251881Speter      err = svn_cl__notifier_print_conflict_stats(nwb.wrapped_baton,
190251881Speter                                                  scratch_pool);
191251881Speter      if (err)
192251881Speter        return svn_error_compose_create(externals_err, err);
193251881Speter    }
194251881Speter
195251881Speter  return svn_error_compose_create(externals_err, err);
196251881Speter}
197