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