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