1/* 2 * update-cmd.c -- Bring work tree in sync with repository 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_pools.h" 31#include "svn_client.h" 32#include "svn_path.h" 33#include "svn_error_codes.h" 34#include "svn_error.h" 35#include "cl.h" 36 37#include "svn_private_config.h" 38 39 40/*** Code. ***/ 41 42/* Print an update summary when there's more than one target to report 43 about. Each (const char *) path in TARGETS is an absolute or relative 44 dirent, and each (svn_revnum_t) entry in RESULT_REVS is the corresponding 45 updated revision, or SVN_INVALID_REVNUM if not a valid target. */ 46static svn_error_t * 47print_update_summary(apr_array_header_t *targets, 48 apr_array_header_t *result_revs, 49 apr_pool_t *scratch_pool) 50{ 51 int i; 52 const char *path_prefix; 53 apr_pool_t *iterpool; 54 svn_boolean_t printed_header = FALSE; 55 56 if (targets->nelts < 2) 57 return SVN_NO_ERROR; 58 59 SVN_ERR(svn_dirent_get_absolute(&path_prefix, "", scratch_pool)); 60 61 iterpool = svn_pool_create(scratch_pool); 62 63 for (i = 0; i < targets->nelts; i++) 64 { 65 const char *path = APR_ARRAY_IDX(targets, i, const char *); 66 svn_revnum_t rev = SVN_INVALID_REVNUM; 67 68 svn_pool_clear(iterpool); 69 70 /* PATH shouldn't be a URL. */ 71 SVN_ERR_ASSERT(! svn_path_is_url(path)); 72 73 /* Grab the result revision from the corresponding slot in our 74 RESULT_REVS array. */ 75 if (i < result_revs->nelts) 76 rev = APR_ARRAY_IDX(result_revs, i, svn_revnum_t); 77 78 /* No result rev? We must have skipped this path. At any rate, 79 nothing to report here. */ 80 if (! SVN_IS_VALID_REVNUM(rev)) 81 continue; 82 83 /* Convert to an absolute path if it's not already. */ 84 if (! svn_dirent_is_absolute(path)) 85 SVN_ERR(svn_dirent_get_absolute(&path, path, iterpool)); 86 87 /* Print an update summary for this target, removing the current 88 working directory prefix from PATH (if PATH is at or under 89 $CWD), and converting the path to local style for display. */ 90 if (! printed_header) 91 { 92 SVN_ERR(svn_cmdline_printf(scratch_pool, 93 _("Summary of updates:\n"))); 94 printed_header = TRUE; 95 } 96 97 SVN_ERR(svn_cmdline_printf(iterpool, _(" Updated '%s' to r%ld.\n"), 98 svn_cl__local_style_skip_ancestor( 99 path_prefix, path, iterpool), 100 rev)); 101 } 102 103 svn_pool_destroy(iterpool); 104 return SVN_NO_ERROR; 105} 106 107/* This implements the `svn_opt_subcommand_t' interface. */ 108svn_error_t * 109svn_cl__update(apr_getopt_t *os, 110 void *baton, 111 apr_pool_t *scratch_pool) 112{ 113 svn_cl__opt_state_t *opt_state = ((svn_cl__cmd_baton_t *) baton)->opt_state; 114 svn_client_ctx_t *ctx = ((svn_cl__cmd_baton_t *) baton)->ctx; 115 apr_array_header_t *targets; 116 svn_depth_t depth; 117 svn_boolean_t depth_is_sticky; 118 struct svn_cl__check_externals_failed_notify_baton nwb; 119 apr_array_header_t *result_revs; 120 svn_error_t *err = SVN_NO_ERROR; 121 svn_error_t *externals_err = SVN_NO_ERROR; 122 123 SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os, 124 opt_state->targets, 125 ctx, FALSE, 126 scratch_pool)); 127 128 /* Add "." if user passed 0 arguments */ 129 svn_opt_push_implicit_dot_target(targets, scratch_pool); 130 131 SVN_ERR(svn_cl__eat_peg_revisions(&targets, targets, scratch_pool)); 132 133 SVN_ERR(svn_cl__check_targets_are_local_paths(targets)); 134 135 /* If using changelists, convert targets into a set of paths that 136 match the specified changelist(s). */ 137 if (opt_state->changelists) 138 { 139 svn_depth_t cl_depth = opt_state->depth; 140 if (cl_depth == svn_depth_unknown) 141 cl_depth = svn_depth_infinity; 142 SVN_ERR(svn_cl__changelist_paths(&targets, 143 opt_state->changelists, targets, 144 cl_depth, ctx, scratch_pool, 145 scratch_pool)); 146 } 147 148 /* Deal with depthstuffs. */ 149 if (opt_state->set_depth != svn_depth_unknown) 150 { 151 depth = opt_state->set_depth; 152 depth_is_sticky = TRUE; 153 } 154 else 155 { 156 depth = opt_state->depth; 157 depth_is_sticky = FALSE; 158 } 159 160 nwb.wrapped_func = ctx->notify_func2; 161 nwb.wrapped_baton = ctx->notify_baton2; 162 nwb.had_externals_error = FALSE; 163 ctx->notify_func2 = svn_cl__check_externals_failed_notify_wrapper; 164 ctx->notify_baton2 = &nwb; 165 166 SVN_ERR(svn_client_update4(&result_revs, targets, 167 &(opt_state->start_revision), 168 depth, depth_is_sticky, 169 opt_state->ignore_externals, 170 opt_state->force, TRUE /* adds_as_modification */, 171 opt_state->parents, 172 ctx, scratch_pool)); 173 174 if (nwb.had_externals_error) 175 externals_err = svn_error_create(SVN_ERR_CL_ERROR_PROCESSING_EXTERNALS, 176 NULL, 177 _("Failure occurred processing one or " 178 "more externals definitions")); 179 180 if (! opt_state->quiet) 181 { 182 err = print_update_summary(targets, result_revs, scratch_pool); 183 if (err) 184 return svn_error_compose_create(externals_err, err); 185 186 /* ### Layering problem: This call assumes that the baton we're 187 * passing is the one that was originally provided by 188 * svn_cl__get_notifier(), but that isn't promised. */ 189 err = svn_cl__notifier_print_conflict_stats(nwb.wrapped_baton, 190 scratch_pool); 191 if (err) 192 return svn_error_compose_create(externals_err, err); 193 } 194 195 return svn_error_compose_create(externals_err, err); 196} 197