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. */
38 struct 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. */
55 static svn_error_t *
send_summary(struct summarize_baton_t * b,const char * path,svn_client_diff_summarize_kind_t summarize_kind,svn_boolean_t prop_changed,svn_node_kind_t node_kind,apr_pool_t * scratch_pool)56 send_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? */
82 static svn_boolean_t
props_changed_hash(apr_hash_t * props,apr_pool_t * scratch_pool)83 props_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? */
105 static svn_boolean_t
props_changed(const apr_array_header_t * propchanges,apr_pool_t * scratch_pool)106 props_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 */
117 static svn_error_t *
diff_dir_opened(void ** new_dir_baton,svn_boolean_t * skip,svn_boolean_t * skip_children,const char * relpath,const svn_diff_source_t * left_source,const svn_diff_source_t * right_source,const svn_diff_source_t * copyfrom_source,void * parent_dir_baton,const struct svn_diff_tree_processor_t * processor,apr_pool_t * result_pool,apr_pool_t * scratch_pool)118 diff_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 */
143 static svn_error_t *
diff_dir_changed(const char * relpath,const svn_diff_source_t * left_source,const svn_diff_source_t * right_source,apr_hash_t * left_props,apr_hash_t * right_props,const apr_array_header_t * prop_changes,void * dir_baton,const struct svn_diff_tree_processor_t * processor,apr_pool_t * scratch_pool)144 diff_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 */
163 static svn_error_t *
diff_dir_added(const char * relpath,const svn_diff_source_t * copyfrom_source,const svn_diff_source_t * right_source,apr_hash_t * copyfrom_props,apr_hash_t * right_props,void * dir_baton,const struct svn_diff_tree_processor_t * processor,apr_pool_t * scratch_pool)164 diff_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 */
184 static svn_error_t *
diff_dir_deleted(const char * relpath,const svn_diff_source_t * left_source,apr_hash_t * left_props,void * dir_baton,const struct svn_diff_tree_processor_t * processor,apr_pool_t * scratch_pool)185 diff_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 */
201 static svn_error_t *
diff_file_added(const char * relpath,const svn_diff_source_t * copyfrom_source,const svn_diff_source_t * right_source,const char * copyfrom_file,const char * right_file,apr_hash_t * copyfrom_props,apr_hash_t * right_props,void * file_baton,const struct svn_diff_tree_processor_t * processor,apr_pool_t * scratch_pool)202 diff_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 */
223 static svn_error_t *
diff_file_changed(const char * relpath,const svn_diff_source_t * left_source,const svn_diff_source_t * right_source,const char * left_file,const char * right_file,apr_hash_t * left_props,apr_hash_t * right_props,svn_boolean_t file_modified,const apr_array_header_t * prop_changes,void * file_baton,const struct svn_diff_tree_processor_t * processor,apr_pool_t * scratch_pool)224 diff_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 */
249 static svn_error_t *
diff_file_deleted(const char * relpath,const svn_diff_source_t * left_source,const char * left_file,apr_hash_t * left_props,void * file_baton,const struct svn_diff_tree_processor_t * processor,apr_pool_t * scratch_pool)250 diff_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
266 svn_error_t *
svn_client__get_diff_summarize_callbacks(const svn_diff_tree_processor_t ** diff_processor,const char *** p_root_relpath,svn_client_diff_summarize_func_t summarize_func,void * summarize_baton,const char * original_target,apr_pool_t * result_pool,apr_pool_t * scratch_pool)267 svn_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
301 svn_client_diff_summarize_t *
svn_client_diff_summarize_dup(const svn_client_diff_summarize_t * diff,apr_pool_t * pool)302 svn_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