diff_summarize.c revision 299742
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_path.h" 29#include "svn_props.h" 30#include "svn_pools.h" 31 32#include "private/svn_wc_private.h" 33 34#include "client.h" 35 36 37/* Diff callbacks baton. */ 38struct summarize_baton_t { 39 apr_pool_t *baton_pool; /* For allocating skip_path */ 40 41 /* The target path of the diff, relative to the anchor; "" if target == anchor. */ 42 const char *skip_relpath; 43 44 /* The summarize callback passed down from the API */ 45 svn_client_diff_summarize_func_t summarize_func; 46 47 /* The summarize callback baton */ 48 void *summarize_func_baton; 49}; 50 51/* Call B->summarize_func with B->summarize_func_baton, passing it a 52 * summary object composed from PATH (but made to be relative to the target 53 * of the diff), SUMMARIZE_KIND, PROP_CHANGED (or FALSE if the action is an 54 * add or delete) and NODE_KIND. */ 55static svn_error_t * 56send_summary(struct summarize_baton_t *b, 57 const char *path, 58 svn_client_diff_summarize_kind_t summarize_kind, 59 svn_boolean_t prop_changed, 60 svn_node_kind_t node_kind, 61 apr_pool_t *scratch_pool) 62{ 63 svn_client_diff_summarize_t *sum = apr_pcalloc(scratch_pool, sizeof(*sum)); 64 65 SVN_ERR_ASSERT(summarize_kind != svn_client_diff_summarize_kind_normal 66 || prop_changed); 67 68 /* PATH is relative to the anchor of the diff, but SUM->path needs to be 69 relative to the target of the diff. */ 70 sum->path = svn_relpath_skip_ancestor(b->skip_relpath, path); 71 sum->summarize_kind = summarize_kind; 72 if (summarize_kind == svn_client_diff_summarize_kind_modified 73 || summarize_kind == svn_client_diff_summarize_kind_normal) 74 sum->prop_changed = prop_changed; 75 sum->node_kind = node_kind; 76 77 SVN_ERR(b->summarize_func(sum, b->summarize_func_baton, scratch_pool)); 78 return SVN_NO_ERROR; 79} 80 81/* Are there any changes to relevant (normal) props in PROPS? */ 82static svn_boolean_t 83props_changed_hash(apr_hash_t *props, 84 apr_pool_t *scratch_pool) 85{ 86 apr_hash_index_t *hi; 87 88 if (!props) 89 return FALSE; 90 91 for (hi = apr_hash_first(scratch_pool, props); hi; hi = apr_hash_next(hi)) 92 { 93 const char *name = apr_hash_this_key(hi); 94 95 if (svn_property_kind2(name) == svn_prop_regular_kind) 96 { 97 return TRUE; 98 } 99 } 100 101 return FALSE; 102} 103 104/* Are there any changes to relevant (normal) props in PROPCHANGES? */ 105static svn_boolean_t 106props_changed(const apr_array_header_t *propchanges, 107 apr_pool_t *scratch_pool) 108{ 109 apr_array_header_t *props; 110 111 svn_error_clear(svn_categorize_props(propchanges, NULL, NULL, &props, 112 scratch_pool)); 113 return (props->nelts != 0); 114} 115 116/* svn_diff_tree_processor_t callback */ 117static svn_error_t * 118diff_dir_opened(void **new_dir_baton, 119 svn_boolean_t *skip, 120 svn_boolean_t *skip_children, 121 const char *relpath, 122 const svn_diff_source_t *left_source, 123 const svn_diff_source_t *right_source, 124 const svn_diff_source_t *copyfrom_source, 125 void *parent_dir_baton, 126 const struct svn_diff_tree_processor_t *processor, 127 apr_pool_t *result_pool, 128 apr_pool_t *scratch_pool) 129{ 130 /* struct summarize_baton_t *b = processor->baton; */ 131 132 /* ### Send here instead of from dir_added() ? */ 133 /*if (!left_source) 134 { 135 SVN_ERR(send_summary(b, relpath, svn_client_diff_summarize_kind_added, 136 FALSE, svn_node_dir, scratch_pool)); 137 }*/ 138 139 return SVN_NO_ERROR; 140} 141 142/* svn_diff_tree_processor_t callback */ 143static svn_error_t * 144diff_dir_changed(const char *relpath, 145 const svn_diff_source_t *left_source, 146 const svn_diff_source_t *right_source, 147 /*const*/ apr_hash_t *left_props, 148 /*const*/ apr_hash_t *right_props, 149 const apr_array_header_t *prop_changes, 150 void *dir_baton, 151 const struct svn_diff_tree_processor_t *processor, 152 apr_pool_t *scratch_pool) 153{ 154 struct summarize_baton_t *b = processor->baton; 155 156 SVN_ERR(send_summary(b, relpath, svn_client_diff_summarize_kind_normal, 157 TRUE, svn_node_dir, scratch_pool)); 158 159 return SVN_NO_ERROR; 160} 161 162/* svn_diff_tree_processor_t callback */ 163static svn_error_t * 164diff_dir_added(const char *relpath, 165 const svn_diff_source_t *copyfrom_source, 166 const svn_diff_source_t *right_source, 167 /*const*/ apr_hash_t *copyfrom_props, 168 /*const*/ apr_hash_t *right_props, 169 void *dir_baton, 170 const struct svn_diff_tree_processor_t *processor, 171 apr_pool_t *scratch_pool) 172{ 173 struct summarize_baton_t *b = processor->baton; 174 175 /* ### Send from dir_opened without prop info? */ 176 SVN_ERR(send_summary(b, relpath, svn_client_diff_summarize_kind_added, 177 props_changed_hash(right_props, scratch_pool), 178 svn_node_dir, scratch_pool)); 179 180 return SVN_NO_ERROR; 181} 182 183/* svn_diff_tree_processor_t callback */ 184static svn_error_t * 185diff_dir_deleted(const char *relpath, 186 const svn_diff_source_t *left_source, 187 /*const*/ apr_hash_t *left_props, 188 void *dir_baton, 189 const struct svn_diff_tree_processor_t *processor, 190 apr_pool_t *scratch_pool) 191{ 192 struct summarize_baton_t *b = processor->baton; 193 194 SVN_ERR(send_summary(b, relpath, svn_client_diff_summarize_kind_deleted, 195 FALSE, svn_node_dir, scratch_pool)); 196 197 return SVN_NO_ERROR; 198} 199 200/* svn_diff_tree_processor_t callback */ 201static svn_error_t * 202diff_file_added(const char *relpath, 203 const svn_diff_source_t *copyfrom_source, 204 const svn_diff_source_t *right_source, 205 const char *copyfrom_file, 206 const char *right_file, 207 /*const*/ apr_hash_t *copyfrom_props, 208 /*const*/ apr_hash_t *right_props, 209 void *file_baton, 210 const struct svn_diff_tree_processor_t *processor, 211 apr_pool_t *scratch_pool) 212{ 213 struct summarize_baton_t *b = processor->baton; 214 215 SVN_ERR(send_summary(b, relpath, svn_client_diff_summarize_kind_added, 216 props_changed_hash(right_props, scratch_pool), 217 svn_node_file, scratch_pool)); 218 219 return SVN_NO_ERROR; 220} 221 222/* svn_diff_tree_processor_t callback */ 223static svn_error_t * 224diff_file_changed(const char *relpath, 225 const svn_diff_source_t *left_source, 226 const svn_diff_source_t *right_source, 227 const char *left_file, 228 const char *right_file, 229 /*const*/ apr_hash_t *left_props, 230 /*const*/ apr_hash_t *right_props, 231 svn_boolean_t file_modified, 232 const apr_array_header_t *prop_changes, 233 void *file_baton, 234 const struct svn_diff_tree_processor_t *processor, 235 apr_pool_t *scratch_pool) 236{ 237 struct summarize_baton_t *b = processor->baton; 238 239 SVN_ERR(send_summary(b, relpath, 240 file_modified ? svn_client_diff_summarize_kind_modified 241 : svn_client_diff_summarize_kind_normal, 242 props_changed(prop_changes, scratch_pool), 243 svn_node_file, scratch_pool)); 244 245 return SVN_NO_ERROR; 246} 247 248/* svn_diff_tree_processor_t callback */ 249static svn_error_t * 250diff_file_deleted(const char *relpath, 251 const svn_diff_source_t *left_source, 252 const char *left_file, 253 /*const*/ apr_hash_t *left_props, 254 void *file_baton, 255 const struct svn_diff_tree_processor_t *processor, 256 apr_pool_t *scratch_pool) 257{ 258 struct summarize_baton_t *b = processor->baton; 259 260 SVN_ERR(send_summary(b, relpath, svn_client_diff_summarize_kind_deleted, 261 FALSE, svn_node_file, scratch_pool)); 262 263 return SVN_NO_ERROR; 264} 265 266svn_error_t * 267svn_client__get_diff_summarize_callbacks( 268 const svn_diff_tree_processor_t **diff_processor, 269 const char ***p_root_relpath, 270 svn_client_diff_summarize_func_t summarize_func, 271 void *summarize_baton, 272 const char *original_target, 273 apr_pool_t *result_pool, 274 apr_pool_t *scratch_pool) 275{ 276 svn_diff_tree_processor_t *dp; 277 struct summarize_baton_t *b = apr_pcalloc(result_pool, sizeof(*b)); 278 279 b->baton_pool = result_pool; 280 b->summarize_func = summarize_func; 281 b->summarize_func_baton = summarize_baton; 282 283 dp = svn_diff__tree_processor_create(b, result_pool); 284 285 /*dp->file_opened = diff_file_opened;*/ 286 dp->file_added = diff_file_added; 287 dp->file_deleted = diff_file_deleted; 288 dp->file_changed = diff_file_changed; 289 290 dp->dir_opened = diff_dir_opened; 291 dp->dir_changed = diff_dir_changed; 292 dp->dir_deleted = diff_dir_deleted; 293 dp->dir_added = diff_dir_added; 294 295 *diff_processor = dp; 296 *p_root_relpath = &b->skip_relpath; 297 298 return SVN_NO_ERROR; 299} 300 301svn_client_diff_summarize_t * 302svn_client_diff_summarize_dup(const svn_client_diff_summarize_t *diff, 303 apr_pool_t *pool) 304{ 305 svn_client_diff_summarize_t *dup_diff = apr_palloc(pool, sizeof(*dup_diff)); 306 307 *dup_diff = *diff; 308 309 if (diff->path) 310 dup_diff->path = apr_pstrdup(pool, diff->path); 311 312 return dup_diff; 313} 314