1/* 2 * repos_diff_summarize.c -- The diff callbacks for summarizing 3 * the differences of two repository versions 4 * 5 * ==================================================================== 6 * Licensed to the Apache Software Foundation (ASF) under one 7 * or more contributor license agreements. See the NOTICE file 8 * distributed with this work for additional information 9 * regarding copyright ownership. The ASF licenses this file 10 * to you under the Apache License, Version 2.0 (the 11 * "License"); you may not use this file except in compliance 12 * with the License. You may obtain a copy of the License at 13 * 14 * http://www.apache.org/licenses/LICENSE-2.0 15 * 16 * Unless required by applicable law or agreed to in writing, 17 * software distributed under the License is distributed on an 18 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 19 * KIND, either express or implied. See the License for the 20 * specific language governing permissions and limitations 21 * under the License. 22 * ==================================================================== 23 */ 24 25 26#include "svn_dirent_uri.h" 27#include "svn_hash.h" 28#include "svn_props.h" 29#include "svn_pools.h" 30 31#include "client.h" 32 33 34/* Diff callbacks baton. */ 35struct summarize_baton_t { 36 /* The target path of the diff, relative to the anchor; "" if target == anchor. */ 37 const char *target; 38 39 /* The summarize callback passed down from the API */ 40 svn_client_diff_summarize_func_t summarize_func; 41 42 /* Is the diff handling reversed? (add<->delete) */ 43 svn_boolean_t reversed; 44 45 /* The summarize callback baton */ 46 void *summarize_func_baton; 47 48 /* Which paths have a prop change. Key is a (const char *) path; the value 49 * is any non-null pointer to indicate that this path has a prop change. */ 50 apr_hash_t *prop_changes; 51}; 52 53 54/* Call B->summarize_func with B->summarize_func_baton, passing it a 55 * summary object composed from PATH (but made to be relative to the target 56 * of the diff), SUMMARIZE_KIND, PROP_CHANGED (or FALSE if the action is an 57 * add or delete) and NODE_KIND. */ 58static svn_error_t * 59send_summary(struct summarize_baton_t *b, 60 const char *path, 61 svn_client_diff_summarize_kind_t summarize_kind, 62 svn_boolean_t prop_changed, 63 svn_node_kind_t node_kind, 64 apr_pool_t *scratch_pool) 65{ 66 svn_client_diff_summarize_t *sum = apr_pcalloc(scratch_pool, sizeof(*sum)); 67 68 SVN_ERR_ASSERT(summarize_kind != svn_client_diff_summarize_kind_normal 69 || prop_changed); 70 71 if (b->reversed) 72 { 73 switch(summarize_kind) 74 { 75 case svn_client_diff_summarize_kind_added: 76 summarize_kind = svn_client_diff_summarize_kind_deleted; 77 break; 78 case svn_client_diff_summarize_kind_deleted: 79 summarize_kind = svn_client_diff_summarize_kind_added; 80 break; 81 default: 82 break; 83 } 84 } 85 86 /* PATH is relative to the anchor of the diff, but SUM->path needs to be 87 relative to the target of the diff. */ 88 sum->path = svn_relpath_skip_ancestor(b->target, path); 89 sum->summarize_kind = summarize_kind; 90 if (summarize_kind == svn_client_diff_summarize_kind_modified 91 || summarize_kind == svn_client_diff_summarize_kind_normal) 92 sum->prop_changed = prop_changed; 93 sum->node_kind = node_kind; 94 95 SVN_ERR(b->summarize_func(sum, b->summarize_func_baton, scratch_pool)); 96 return SVN_NO_ERROR; 97} 98 99/* Are there any changes to relevant (normal) props in PROPCHANGES? */ 100static svn_boolean_t 101props_changed(const apr_array_header_t *propchanges, 102 apr_pool_t *scratch_pool) 103{ 104 apr_array_header_t *props; 105 106 svn_error_clear(svn_categorize_props(propchanges, NULL, NULL, &props, 107 scratch_pool)); 108 return (props->nelts != 0); 109} 110 111 112static svn_error_t * 113cb_dir_deleted(svn_wc_notify_state_t *state, 114 svn_boolean_t *tree_conflicted, 115 const char *path, 116 void *diff_baton, 117 apr_pool_t *scratch_pool) 118{ 119 struct summarize_baton_t *b = diff_baton; 120 121 SVN_ERR(send_summary(b, path, svn_client_diff_summarize_kind_deleted, 122 FALSE, svn_node_dir, scratch_pool)); 123 124 return SVN_NO_ERROR; 125} 126 127static svn_error_t * 128cb_file_deleted(svn_wc_notify_state_t *state, 129 svn_boolean_t *tree_conflicted, 130 const char *path, 131 const char *tmpfile1, 132 const char *tmpfile2, 133 const char *mimetype1, 134 const char *mimetype2, 135 apr_hash_t *originalprops, 136 void *diff_baton, 137 apr_pool_t *scratch_pool) 138{ 139 struct summarize_baton_t *b = diff_baton; 140 141 SVN_ERR(send_summary(b, path, svn_client_diff_summarize_kind_deleted, 142 FALSE, svn_node_file, scratch_pool)); 143 144 return SVN_NO_ERROR; 145} 146 147static svn_error_t * 148cb_dir_added(svn_wc_notify_state_t *state, 149 svn_boolean_t *tree_conflicted, 150 svn_boolean_t *skip, 151 svn_boolean_t *skip_children, 152 const char *path, 153 svn_revnum_t rev, 154 const char *copyfrom_path, 155 svn_revnum_t copyfrom_revision, 156 void *diff_baton, 157 apr_pool_t *scratch_pool) 158{ 159 return SVN_NO_ERROR; 160} 161 162static svn_error_t * 163cb_dir_opened(svn_boolean_t *tree_conflicted, 164 svn_boolean_t *skip, 165 svn_boolean_t *skip_children, 166 const char *path, 167 svn_revnum_t rev, 168 void *diff_baton, 169 apr_pool_t *scratch_pool) 170{ 171 return SVN_NO_ERROR; 172} 173 174static svn_error_t * 175cb_dir_closed(svn_wc_notify_state_t *contentstate, 176 svn_wc_notify_state_t *propstate, 177 svn_boolean_t *tree_conflicted, 178 const char *path, 179 svn_boolean_t dir_was_added, 180 void *diff_baton, 181 apr_pool_t *scratch_pool) 182{ 183 struct summarize_baton_t *b = diff_baton; 184 svn_boolean_t prop_change; 185 186 if (! svn_relpath_skip_ancestor(b->target, path)) 187 return SVN_NO_ERROR; 188 189 prop_change = svn_hash_gets(b->prop_changes, path) != NULL; 190 if (dir_was_added || prop_change) 191 SVN_ERR(send_summary(b, path, 192 dir_was_added ? svn_client_diff_summarize_kind_added 193 : svn_client_diff_summarize_kind_normal, 194 prop_change, svn_node_dir, scratch_pool)); 195 196 return SVN_NO_ERROR; 197} 198 199static svn_error_t * 200cb_file_added(svn_wc_notify_state_t *contentstate, 201 svn_wc_notify_state_t *propstate, 202 svn_boolean_t *tree_conflicted, 203 const char *path, 204 const char *tmpfile1, 205 const char *tmpfile2, 206 svn_revnum_t rev1, 207 svn_revnum_t rev2, 208 const char *mimetype1, 209 const char *mimetype2, 210 const char *copyfrom_path, 211 svn_revnum_t copyfrom_revision, 212 const apr_array_header_t *propchanges, 213 apr_hash_t *originalprops, 214 void *diff_baton, 215 apr_pool_t *scratch_pool) 216{ 217 struct summarize_baton_t *b = diff_baton; 218 219 SVN_ERR(send_summary(b, path, svn_client_diff_summarize_kind_added, 220 props_changed(propchanges, scratch_pool), 221 svn_node_file, scratch_pool)); 222 223 return SVN_NO_ERROR; 224} 225 226static svn_error_t * 227cb_file_opened(svn_boolean_t *tree_conflicted, 228 svn_boolean_t *skip, 229 const char *path, 230 svn_revnum_t rev, 231 void *diff_baton, 232 apr_pool_t *scratch_pool) 233{ 234 return SVN_NO_ERROR; 235} 236 237static svn_error_t * 238cb_file_changed(svn_wc_notify_state_t *contentstate, 239 svn_wc_notify_state_t *propstate, 240 svn_boolean_t *tree_conflicted, 241 const char *path, 242 const char *tmpfile1, 243 const char *tmpfile2, 244 svn_revnum_t rev1, 245 svn_revnum_t rev2, 246 const char *mimetype1, 247 const char *mimetype2, 248 const apr_array_header_t *propchanges, 249 apr_hash_t *originalprops, 250 void *diff_baton, 251 apr_pool_t *scratch_pool) 252{ 253 struct summarize_baton_t *b = diff_baton; 254 svn_boolean_t text_change = (tmpfile2 != NULL); 255 svn_boolean_t prop_change = props_changed(propchanges, scratch_pool); 256 257 if (text_change || prop_change) 258 SVN_ERR(send_summary(b, path, 259 text_change ? svn_client_diff_summarize_kind_modified 260 : svn_client_diff_summarize_kind_normal, 261 prop_change, svn_node_file, scratch_pool)); 262 263 return SVN_NO_ERROR; 264} 265 266static svn_error_t * 267cb_dir_props_changed(svn_wc_notify_state_t *propstate, 268 svn_boolean_t *tree_conflicted, 269 const char *path, 270 svn_boolean_t dir_was_added, 271 const apr_array_header_t *propchanges, 272 apr_hash_t *original_props, 273 void *diff_baton, 274 apr_pool_t *scratch_pool) 275{ 276 struct summarize_baton_t *b = diff_baton; 277 278 if (props_changed(propchanges, scratch_pool)) 279 svn_hash_sets(b->prop_changes, path, path); 280 281 return SVN_NO_ERROR; 282} 283 284svn_error_t * 285svn_client__get_diff_summarize_callbacks( 286 svn_wc_diff_callbacks4_t **callbacks, 287 void **callback_baton, 288 const char *target, 289 svn_boolean_t reversed, 290 svn_client_diff_summarize_func_t summarize_func, 291 void *summarize_baton, 292 apr_pool_t *pool) 293{ 294 svn_wc_diff_callbacks4_t *cb = apr_palloc(pool, sizeof(*cb)); 295 struct summarize_baton_t *b = apr_palloc(pool, sizeof(*b)); 296 297 b->target = target; 298 b->summarize_func = summarize_func; 299 b->summarize_func_baton = summarize_baton; 300 b->prop_changes = apr_hash_make(pool); 301 b->reversed = reversed; 302 303 cb->file_opened = cb_file_opened; 304 cb->file_changed = cb_file_changed; 305 cb->file_added = cb_file_added; 306 cb->file_deleted = cb_file_deleted; 307 cb->dir_deleted = cb_dir_deleted; 308 cb->dir_opened = cb_dir_opened; 309 cb->dir_added = cb_dir_added; 310 cb->dir_props_changed = cb_dir_props_changed; 311 cb->dir_closed = cb_dir_closed; 312 313 *callbacks = cb; 314 *callback_baton = b; 315 316 return SVN_NO_ERROR; 317} 318