update-cmd.c revision 362181
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_cl__conflict_stats_t *conflict_stats = 115 ((svn_cl__cmd_baton_t *) baton)->conflict_stats; 116 svn_client_ctx_t *ctx = ((svn_cl__cmd_baton_t *) baton)->ctx; 117 apr_array_header_t *targets; 118 svn_depth_t depth; 119 svn_boolean_t depth_is_sticky; 120 struct svn_cl__check_externals_failed_notify_baton nwb; 121 apr_array_header_t *result_revs; 122 apr_array_header_t *conflicted_paths; 123 svn_error_t *err = SVN_NO_ERROR; 124 svn_error_t *externals_err = SVN_NO_ERROR; 125 126 SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os, 127 opt_state->targets, 128 ctx, FALSE, 129 scratch_pool)); 130 131 /* Add "." if user passed 0 arguments */ 132 svn_opt_push_implicit_dot_target(targets, scratch_pool); 133 134 SVN_ERR(svn_cl__eat_peg_revisions(&targets, targets, scratch_pool)); 135 136 SVN_ERR(svn_cl__check_targets_are_local_paths(targets)); 137 138 /* If using changelists, convert targets into a set of paths that 139 match the specified changelist(s). */ 140 if (opt_state->changelists) 141 { 142 svn_depth_t cl_depth = opt_state->depth; 143 if (cl_depth == svn_depth_unknown) 144 cl_depth = svn_depth_infinity; 145 SVN_ERR(svn_cl__changelist_paths(&targets, 146 opt_state->changelists, targets, 147 cl_depth, ctx, scratch_pool, 148 scratch_pool)); 149 } 150 151 /* Deal with depthstuffs. */ 152 if (opt_state->set_depth != svn_depth_unknown) 153 { 154 depth = opt_state->set_depth; 155 depth_is_sticky = TRUE; 156 } 157 else 158 { 159 depth = opt_state->depth; 160 depth_is_sticky = FALSE; 161 } 162 163 nwb.wrapped_func = ctx->notify_func2; 164 nwb.wrapped_baton = ctx->notify_baton2; 165 nwb.had_externals_error = FALSE; 166 ctx->notify_func2 = svn_cl__check_externals_failed_notify_wrapper; 167 ctx->notify_baton2 = &nwb; 168 169 SVN_ERR(svn_client_update4(&result_revs, targets, 170 &(opt_state->start_revision), 171 depth, depth_is_sticky, 172 opt_state->ignore_externals, 173 opt_state->force, 174 opt_state->adds_as_modification, 175 opt_state->parents, 176 ctx, scratch_pool)); 177 178 if (nwb.had_externals_error) 179 externals_err = svn_error_create(SVN_ERR_CL_ERROR_PROCESSING_EXTERNALS, 180 NULL, 181 _("Failure occurred processing one or " 182 "more externals definitions")); 183 184 /* Run the interactive resolver if conflicts were raised. */ 185 SVN_ERR(svn_cl__conflict_stats_get_paths(&conflicted_paths, conflict_stats, 186 scratch_pool, scratch_pool)); 187 if (conflicted_paths) 188 SVN_ERR(svn_cl__walk_conflicts(conflicted_paths, conflict_stats, 189 opt_state, ctx, scratch_pool)); 190 191 if (! opt_state->quiet) 192 { 193 err = print_update_summary(targets, result_revs, scratch_pool); 194 if (err) 195 return svn_error_compose_create(externals_err, err); 196 197 /* ### Layering problem: This call assumes that the baton we're 198 * passing is the one that was originally provided by 199 * svn_cl__get_notifier(), but that isn't promised. */ 200 err = svn_cl__notifier_print_conflict_stats(nwb.wrapped_baton, 201 scratch_pool); 202 if (err) 203 return svn_error_compose_create(externals_err, err); 204 } 205 206 return svn_error_compose_create(externals_err, err); 207} 208