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