~ubuntu-branches/debian/sid/subversion/sid

« back to all changes in this revision

Viewing changes to subversion/libsvn_wc/diff_local.c

  • Committer: Package Import Robot
  • Author(s): James McCoy, Peter Samuelson, James McCoy
  • Date: 2014-01-12 19:48:33 UTC
  • mfrom: (0.2.10)
  • Revision ID: package-import@ubuntu.com-20140112194833-w3axfwksn296jn5x
Tags: 1.8.5-1
[ Peter Samuelson ]
* New upstream release.  (Closes: #725787) Rediff patches:
  - Remove apr-abi1 (applied upstream), rename apr-abi2 to apr-abi
  - Remove loosen-sqlite-version-check (shouldn't be needed)
  - Remove java-osgi-metadata (applied upstream)
  - svnmucc prompts for a changelog if none is provided. (Closes: #507430)
  - Remove fix-bdb-version-detection, upstream uses "apu-config --dbm-libs"
  - Remove ruby-test-wc (applied upstream)
  - Fix “svn diff -r N file” when file has svn:mime-type set.
    (Closes: #734163)
  - Support specifying an encoding for mod_dav_svn's environment in which
    hooks are run.  (Closes: #601544)
  - Fix ordering of “svnadmin dump” paths with certain APR versions.
    (Closes: #687291)
  - Provide a better error message when authentication fails with an
    svn+ssh:// URL.  (Closes: #273874)
  - Updated Polish translations.  (Closes: #690815)

[ James McCoy ]
* Remove all traces of libneon, replaced by libserf.
* patches/sqlite_3.8.x_workaround: Upstream fix for wc-queries-test test
  failurse.
* Run configure with --with-apache-libexecdir, which allows removing part of
  patches/rpath.
* Re-enable auth-test as upstream has fixed the problem of picking up
  libraries from the environment rather than the build tree.
  (Closes: #654172)
* Point LD_LIBRARY_PATH at the built auth libraries when running the svn
  command during the build.  (Closes: #678224)
* Add a NEWS entry describing how to configure mod_dav_svn to understand
  UTF-8.  (Closes: #566148)
* Remove ancient transitional package, libsvn-ruby.
* Enable compatibility with Sqlite3 versions back to Wheezy.
* Enable hardening flags.  (Closes: #734918)
* patches/build-fixes: Enable verbose build logs.
* Build against the default ruby version.  (Closes: #722393)

Show diffs side-by-side

added added

removed removed

Lines of Context:
38
38
#include "svn_hash.h"
39
39
 
40
40
#include "private/svn_wc_private.h"
 
41
#include "private/svn_diff_tree.h"
41
42
 
42
43
#include "wc.h"
43
44
#include "props.h"
44
45
#include "translate.h"
 
46
#include "diff.h"
45
47
 
46
48
#include "svn_private_config.h"
47
49
 
48
50
/*-------------------------------------------------------------------------*/
49
51
 
 
52
/* Baton containing the state of a directory
 
53
   reported open via a diff processor */
 
54
struct node_state_t
 
55
{
 
56
  struct node_state_t *parent;
 
57
 
 
58
  apr_pool_t *pool;
 
59
 
 
60
  const char *local_abspath;
 
61
  const char *relpath;
 
62
  void *baton;
 
63
 
 
64
  svn_diff_source_t *left_src;
 
65
  svn_diff_source_t *right_src;
 
66
  svn_diff_source_t *copy_src;
 
67
 
 
68
  svn_boolean_t skip;
 
69
  svn_boolean_t skip_children;
 
70
 
 
71
  apr_hash_t *left_props;
 
72
  apr_hash_t *right_props;
 
73
  const apr_array_header_t *propchanges;
 
74
};
50
75
 
51
76
/* The diff baton */
52
77
struct diff_baton
57
82
  /* Report editor paths relative from this directory */
58
83
  const char *anchor_abspath;
59
84
 
60
 
  /* The callbacks and callback argument that implement the file comparison
61
 
     functions */
62
 
  const svn_wc_diff_callbacks4_t *callbacks;
63
 
  void *callback_baton;
 
85
  struct node_state_t *cur;
 
86
 
 
87
  const svn_diff_tree_processor_t *processor;
64
88
 
65
89
  /* Should this diff ignore node ancestry? */
66
90
  svn_boolean_t ignore_ancestry;
68
92
  /* Should this diff not compare copied files with their source? */
69
93
  svn_boolean_t show_copies_as_adds;
70
94
 
71
 
  /* Are we producing a git-style diff? */
72
 
  svn_boolean_t use_git_diff_format;
73
 
 
74
 
  /* Empty file used to diff adds / deletes */
75
 
  const char *empty_file;
76
 
 
77
95
  /* Hash whose keys are const char * changelist names. */
78
96
  apr_hash_t *changelist_hash;
79
97
 
84
102
  apr_pool_t *pool;
85
103
};
86
104
 
87
 
/* Get the empty file associated with the edit baton. This is cached so
88
 
 * that it can be reused, all empty files are the same.
89
 
 */
90
 
static svn_error_t *
91
 
get_empty_file(struct diff_baton *eb,
92
 
               const char **empty_file,
93
 
               apr_pool_t *scratch_pool)
94
 
{
95
 
  /* Create the file if it does not exist */
96
 
  /* Note that we tried to use /dev/null in r857294, but
97
 
     that won't work on Windows: it's impossible to stat NUL */
98
 
  if (!eb->empty_file)
99
 
    {
100
 
      SVN_ERR(svn_io_open_unique_file3(NULL, &eb->empty_file, NULL,
101
 
                                       svn_io_file_del_on_pool_cleanup,
102
 
                                       eb->pool, scratch_pool));
103
 
    }
104
 
 
105
 
  *empty_file = eb->empty_file;
106
 
 
107
 
  return SVN_NO_ERROR;
108
 
}
109
 
 
110
 
 
111
 
/* Return the value of the svn:mime-type property held in PROPS, or NULL
112
 
   if no such property exists. */
113
 
static const char *
114
 
get_prop_mimetype(apr_hash_t *props)
115
 
{
116
 
  return svn_prop_get_value(props, SVN_PROP_MIME_TYPE);
117
 
}
118
 
 
119
 
 
120
 
/* Diff the file PATH against its text base.  At this
121
 
 * stage we are dealing with a file that does exist in the working copy.
122
 
 *
123
 
 * DIR_BATON is the parent directory baton, PATH is the path to the file to
124
 
 * be compared.
125
 
 *
126
 
 * Do all allocation in POOL.
127
 
 *
128
 
 * ### TODO: Need to work on replace if the new filename used to be a
129
 
 * directory.
130
 
 */
131
 
static svn_error_t *
132
 
file_diff(struct diff_baton *eb,
133
 
          const char *local_abspath,
134
 
          const char *path,
135
 
          apr_pool_t *scratch_pool)
136
 
{
137
 
  svn_wc__db_t *db = eb->db;
138
 
  const char *empty_file;
139
 
  const char *original_repos_relpath;
140
 
  svn_wc__db_status_t status;
141
 
  svn_wc__db_kind_t kind;
142
 
  svn_revnum_t revision;
143
 
  const svn_checksum_t *checksum;
144
 
  svn_boolean_t op_root;
145
 
  svn_boolean_t had_props, props_mod;
146
 
  svn_boolean_t have_base, have_more_work;
147
 
  svn_boolean_t replaced = FALSE;
148
 
  svn_boolean_t base_replace = FALSE;
149
 
  svn_wc__db_status_t base_status;
150
 
  svn_revnum_t base_revision = SVN_INVALID_REVNUM;
151
 
  const svn_checksum_t *base_checksum;
152
 
  const char *pristine_abspath;
153
 
 
154
 
  SVN_ERR(svn_wc__db_read_info(&status, &kind, &revision, NULL, NULL, NULL,
155
 
                               NULL, NULL, NULL, NULL, &checksum, NULL,
156
 
                               &original_repos_relpath, NULL, NULL, NULL,
157
 
                               NULL, NULL, NULL, NULL, NULL,
158
 
                               &op_root, &had_props, &props_mod,
159
 
                               &have_base, &have_more_work, NULL,
160
 
                               db, local_abspath, scratch_pool, scratch_pool));
161
 
 
162
 
  if ((status == svn_wc__db_status_added) && (have_base || have_more_work))
163
 
    {
164
 
      SVN_ERR(svn_wc__db_node_check_replace(&replaced, &base_replace,
165
 
                                            NULL, db, local_abspath,
166
 
                                            scratch_pool));
167
 
 
168
 
      if (replaced && base_replace /* && !have_more_work */)
169
 
        {
170
 
          svn_wc__db_kind_t base_kind;
171
 
          SVN_ERR(svn_wc__db_base_get_info(&base_status, &base_kind,
172
 
                                           &base_revision,
173
 
                                           NULL, NULL, NULL, NULL, NULL, NULL,
174
 
                                           NULL, &base_checksum, NULL,
175
 
                                           NULL, NULL, NULL,
176
 
                                           db, local_abspath,
177
 
                                           scratch_pool, scratch_pool));
178
 
 
179
 
          if (base_status != svn_wc__db_status_normal
180
 
              || base_kind != kind)
181
 
            {
182
 
              /* We can't show a replacement here */
183
 
              replaced = FALSE;
184
 
              base_replace = FALSE;
185
 
            }
186
 
        }
187
 
      else
188
 
        {
189
 
          /* We can't look in this middle working layer (yet).
190
 
             We just report the change itself.
191
 
 
192
 
             And if we could look at it, how would we report the addition
193
 
             of this middle layer (and maybe different layers below that)?
194
 
 
195
 
             For 1.7 we just do what we did before: Ignore this layering
196
 
             problem and just show how the current file got in your wc.
197
 
           */
198
 
          replaced = FALSE;
199
 
          base_replace = FALSE;
200
 
        }
201
 
    }
202
 
 
203
 
  /* Now refine ADDED to one of: ADDED, COPIED, MOVED_HERE. Note that only
204
 
     the latter two have corresponding pristine info to diff against.  */
205
 
  if (status == svn_wc__db_status_added)
206
 
    SVN_ERR(svn_wc__db_scan_addition(&status, NULL, NULL, NULL, NULL,
207
 
                                     NULL, NULL, NULL,
208
 
                                     NULL, db, local_abspath,
209
 
                                     scratch_pool, scratch_pool));
210
 
 
211
 
  SVN_ERR(get_empty_file(eb, &empty_file, scratch_pool));
212
 
 
213
 
  /* When we show a delete, we show a diff of the original pristine against
214
 
   * an empty file.
215
 
   * A base-replace is treated like a delete plus an add.
216
 
   *
217
 
   * For this kind of diff we prefer to show the deletion of what was checked
218
 
   * out over showing what was actually deleted (if that was defined by
219
 
   * a higher layer). */
220
 
  if (status == svn_wc__db_status_deleted ||
221
 
      (base_replace && ! eb->ignore_ancestry))
222
 
    {
223
 
      apr_hash_t *del_props;
224
 
      const svn_checksum_t *del_checksum;
225
 
      const char *del_text_abspath;
226
 
      const char *del_mimetype;
227
 
 
228
 
      if (base_replace && ! eb->ignore_ancestry)
229
 
        {
230
 
          /* We show a deletion of the information in the BASE layer */
231
 
          SVN_ERR(svn_wc__db_base_get_props(&del_props, db, local_abspath,
232
 
                                            scratch_pool, scratch_pool));
233
 
 
234
 
          del_checksum = base_checksum;
235
 
        }
236
 
      else
237
 
        {
238
 
          /* We show a deletion of what was actually deleted */
239
 
          SVN_ERR_ASSERT(status == svn_wc__db_status_deleted);
240
 
 
241
 
          SVN_ERR(svn_wc__get_pristine_props(&del_props, db, local_abspath,
242
 
                                             scratch_pool, scratch_pool));
243
 
 
244
 
          SVN_ERR(svn_wc__db_read_pristine_info(NULL, NULL, NULL, NULL, NULL,
245
 
                                                NULL, &del_checksum, NULL,
246
 
                                                NULL, db, local_abspath,
247
 
                                                scratch_pool, scratch_pool));
248
 
        }
249
 
 
250
 
      SVN_ERR_ASSERT(del_checksum != NULL);
251
 
 
252
 
      SVN_ERR(svn_wc__db_pristine_get_path(&del_text_abspath, db,
253
 
                                           local_abspath, del_checksum,
254
 
                                           scratch_pool, scratch_pool));
255
 
 
256
 
      if (del_props == NULL)
257
 
        del_props = apr_hash_make(scratch_pool);
258
 
 
259
 
      del_mimetype = get_prop_mimetype(del_props);
260
 
 
261
 
      SVN_ERR(eb->callbacks->file_deleted(NULL, NULL, path,
262
 
                                          del_text_abspath,
263
 
                                          empty_file,
264
 
                                          del_mimetype,
265
 
                                          NULL,
266
 
                                          del_props,
267
 
                                          eb->callback_baton,
268
 
                                          scratch_pool));
269
 
 
270
 
      if (status == svn_wc__db_status_deleted)
271
 
        {
272
 
          /* We're here only for showing a delete, so we're done. */
273
 
          return SVN_NO_ERROR;
274
 
        }
275
 
    }
276
 
 
277
 
  if (checksum != NULL)
278
 
    SVN_ERR(svn_wc__db_pristine_get_path(&pristine_abspath, db, local_abspath,
279
 
                                         checksum,
280
 
                                         scratch_pool, scratch_pool));
281
 
  else if (base_replace && eb->ignore_ancestry)
282
 
    SVN_ERR(svn_wc__db_pristine_get_path(&pristine_abspath, db, local_abspath,
283
 
                                         base_checksum,
284
 
                                         scratch_pool, scratch_pool));
285
 
  else
286
 
    pristine_abspath = empty_file;
287
 
 
288
 
 /* Now deal with showing additions, or the add-half of replacements.
289
 
  * If the item is schedule-add *with history*, then we usually want
290
 
  * to see the usual working vs. text-base comparison, which will show changes
291
 
  * made since the file was copied.  But in case we're showing copies as adds,
292
 
  * we need to compare the copied file to the empty file. If we're doing a git
293
 
  * diff, and the file was copied, we need to report the file as added and
294
 
  * diff it against the text base, so that a "copied" git diff header, and
295
 
  * possibly a diff against the copy source, will be generated for it. */
296
 
  if ((! base_replace && status == svn_wc__db_status_added) ||
297
 
     (base_replace && ! eb->ignore_ancestry) ||
298
 
     ((status == svn_wc__db_status_copied ||
299
 
       status == svn_wc__db_status_moved_here) &&
300
 
         (eb->show_copies_as_adds || eb->use_git_diff_format)))
301
 
    {
302
 
      const char *translated = NULL;
303
 
      apr_hash_t *pristine_props;
304
 
      apr_hash_t *actual_props;
305
 
      const char *actual_mimetype;
306
 
      apr_array_header_t *propchanges;
307
 
 
308
 
 
309
 
      /* Get svn:mime-type from ACTUAL props of PATH. */
310
 
      SVN_ERR(svn_wc__get_actual_props(&actual_props, db, local_abspath,
311
 
                                       scratch_pool, scratch_pool));
312
 
      actual_mimetype = get_prop_mimetype(actual_props);
313
 
 
314
 
      /* Set the original properties to empty, then compute "changes" from
315
 
         that. Essentially, all ACTUAL props will be "added".  */
316
 
      pristine_props = apr_hash_make(scratch_pool);
317
 
      SVN_ERR(svn_prop_diffs(&propchanges, actual_props, pristine_props,
318
 
                             scratch_pool));
319
 
 
320
 
      SVN_ERR(svn_wc__internal_translated_file(
321
 
              &translated, local_abspath, db, local_abspath,
322
 
              SVN_WC_TRANSLATE_TO_NF | SVN_WC_TRANSLATE_USE_GLOBAL_TMP,
323
 
              eb->cancel_func, eb->cancel_baton,
324
 
              scratch_pool, scratch_pool));
325
 
 
326
 
      SVN_ERR(eb->callbacks->file_added(NULL, NULL, NULL, path,
327
 
                                        (! eb->show_copies_as_adds &&
328
 
                                         eb->use_git_diff_format &&
329
 
                                         status != svn_wc__db_status_added) ?
330
 
                                          pristine_abspath : empty_file,
331
 
                                        translated,
332
 
                                        0, revision,
333
 
                                        NULL,
334
 
                                        actual_mimetype,
335
 
                                        original_repos_relpath,
336
 
                                        SVN_INVALID_REVNUM, propchanges,
337
 
                                        pristine_props, eb->callback_baton,
338
 
                                        scratch_pool));
339
 
    }
340
 
  else
341
 
    {
342
 
      const char *translated = NULL;
343
 
      apr_hash_t *pristine_props;
344
 
      const char *pristine_mimetype;
345
 
      const char *actual_mimetype;
346
 
      apr_hash_t *actual_props;
347
 
      apr_array_header_t *propchanges;
348
 
      svn_boolean_t modified;
349
 
 
350
 
      /* Here we deal with showing pure modifications. */
351
 
      SVN_ERR(svn_wc__internal_file_modified_p(&modified, db, local_abspath,
352
 
                                               FALSE, scratch_pool));
353
 
      if (modified)
354
 
        {
355
 
          /* Note that this might be the _second_ time we translate
356
 
             the file, as svn_wc__text_modified_internal_p() might have used a
357
 
             tmp translated copy too.  But what the heck, diff is
358
 
             already expensive, translating twice for the sake of code
359
 
             modularity is liveable. */
360
 
          SVN_ERR(svn_wc__internal_translated_file(
361
 
                    &translated, local_abspath, db, local_abspath,
362
 
                    SVN_WC_TRANSLATE_TO_NF | SVN_WC_TRANSLATE_USE_GLOBAL_TMP,
363
 
                    eb->cancel_func, eb->cancel_baton,
364
 
                    scratch_pool, scratch_pool));
365
 
        }
366
 
 
367
 
      /* Get the properties, the svn:mime-type values, and compute the
368
 
         differences between the two.  */
369
 
      if (base_replace
370
 
          && eb->ignore_ancestry)
371
 
        {
372
 
          /* We don't want the normal pristine properties (which are
373
 
             from the WORKING tree). We want the pristines associated
374
 
             with the BASE tree, which are saved as "revert" props.  */
375
 
          SVN_ERR(svn_wc__db_base_get_props(&pristine_props,
376
 
                                            db, local_abspath,
377
 
                                            scratch_pool, scratch_pool));
378
 
        }
379
 
      else
380
 
        {
381
 
          /* We can only fetch the pristine props (from BASE or WORKING) if
382
 
             the node has not been replaced, or it was copied/moved here.  */
383
 
          SVN_ERR_ASSERT(!replaced
384
 
                         || status == svn_wc__db_status_copied
385
 
                         || status == svn_wc__db_status_moved_here);
386
 
 
387
 
          SVN_ERR(svn_wc__db_read_pristine_props(&pristine_props, db,
388
 
                                                 local_abspath,
389
 
                                                 scratch_pool, scratch_pool));
390
 
 
391
 
          /* baseprops will be NULL for added nodes */
392
 
          if (!pristine_props)
393
 
            pristine_props = apr_hash_make(scratch_pool);
394
 
        }
395
 
      pristine_mimetype = get_prop_mimetype(pristine_props);
396
 
 
397
 
      SVN_ERR(svn_wc__db_read_props(&actual_props, db, local_abspath,
398
 
                                    scratch_pool, scratch_pool));
399
 
      actual_mimetype = get_prop_mimetype(actual_props);
400
 
 
401
 
      SVN_ERR(svn_prop_diffs(&propchanges, actual_props, pristine_props,
402
 
                             scratch_pool));
403
 
 
404
 
      if (modified || propchanges->nelts > 0)
405
 
        {
406
 
          SVN_ERR(eb->callbacks->file_changed(NULL, NULL, NULL,
407
 
                                              path,
408
 
                                              modified ? pristine_abspath
409
 
                                                       : NULL,
410
 
                                              translated,
411
 
                                              revision,
412
 
                                              SVN_INVALID_REVNUM,
413
 
                                              pristine_mimetype,
414
 
                                              actual_mimetype,
415
 
                                              propchanges,
416
 
                                              pristine_props,
417
 
                                              eb->callback_baton,
418
 
                                              scratch_pool));
419
 
        }
420
 
    }
 
105
/* Recursively opens directories on the stack in EB, until LOCAL_ABSPATH
 
106
   is reached. If RECURSIVE_SKIP is TRUE, don't open LOCAL_ABSPATH itself,
 
107
   but create it marked with skip+skip_children.
 
108
 */
 
109
static svn_error_t *
 
110
ensure_state(struct diff_baton *eb,
 
111
             const char *local_abspath,
 
112
             svn_boolean_t recursive_skip,
 
113
             apr_pool_t *scratch_pool)
 
114
{
 
115
  struct node_state_t *ns;
 
116
  apr_pool_t *ns_pool;
 
117
  if (!eb->cur)
 
118
    {
 
119
      if (!svn_dirent_is_ancestor(eb->anchor_abspath, local_abspath))
 
120
        return SVN_NO_ERROR;
 
121
 
 
122
      SVN_ERR(ensure_state(eb,
 
123
                           svn_dirent_dirname(local_abspath,scratch_pool),
 
124
                           FALSE,
 
125
                           scratch_pool));
 
126
    }
 
127
  else if (svn_dirent_is_child(eb->cur->local_abspath, local_abspath, NULL))
 
128
    SVN_ERR(ensure_state(eb, svn_dirent_dirname(local_abspath,scratch_pool),
 
129
                         FALSE,
 
130
                         scratch_pool));
 
131
  else
 
132
    return SVN_NO_ERROR;
 
133
 
 
134
  if (eb->cur && eb->cur->skip_children)
 
135
    return SVN_NO_ERROR;
 
136
 
 
137
  ns_pool = svn_pool_create(eb->cur ? eb->cur->pool : eb->pool);
 
138
  ns = apr_pcalloc(ns_pool, sizeof(*ns));
 
139
 
 
140
  ns->pool = ns_pool;
 
141
  ns->local_abspath = apr_pstrdup(ns_pool, local_abspath);
 
142
  ns->relpath = svn_dirent_skip_ancestor(eb->anchor_abspath, ns->local_abspath);
 
143
  ns->parent = eb->cur;
 
144
  eb->cur = ns;
 
145
 
 
146
  if (recursive_skip)
 
147
    {
 
148
      ns->skip = TRUE;
 
149
      ns->skip_children = TRUE;
 
150
      return SVN_NO_ERROR;
 
151
    }
 
152
 
 
153
  {
 
154
    svn_revnum_t revision;
 
155
    svn_error_t *err;
 
156
 
 
157
    err = svn_wc__db_base_get_info(NULL, NULL, &revision, NULL, NULL, NULL,
 
158
                                   NULL, NULL, NULL, NULL, NULL, NULL, NULL,
 
159
                                   NULL, NULL, NULL,
 
160
                                   eb->db, local_abspath,
 
161
                                   scratch_pool, scratch_pool);
 
162
 
 
163
    if (err)
 
164
      {
 
165
        if (err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND)
 
166
          return svn_error_trace(err);
 
167
        svn_error_clear(err);
 
168
 
 
169
        revision = 0; /* Use original revision? */
 
170
      }
 
171
    ns->left_src = svn_diff__source_create(revision, ns->pool);
 
172
    ns->right_src = svn_diff__source_create(SVN_INVALID_REVNUM, ns->pool);
 
173
 
 
174
    SVN_ERR(eb->processor->dir_opened(&ns->baton, &ns->skip,
 
175
                                      &ns->skip_children,
 
176
                                      ns->relpath,
 
177
                                      ns->left_src,
 
178
                                      ns->right_src,
 
179
                                      NULL /* copyfrom_source */,
 
180
                                      ns->parent ? ns->parent->baton : NULL,
 
181
                                      eb->processor,
 
182
                                      ns->pool, scratch_pool));
 
183
  }
421
184
 
422
185
  return SVN_NO_ERROR;
423
186
}
430
193
                     apr_pool_t *scratch_pool)
431
194
{
432
195
  struct diff_baton *eb = baton;
433
 
  switch (status->node_status)
434
 
    {
435
 
      case svn_wc_status_unversioned:
436
 
      case svn_wc_status_ignored:
437
 
        return SVN_NO_ERROR; /* No diff */
438
 
 
439
 
      case svn_wc_status_obstructed:
440
 
      case svn_wc_status_missing:
441
 
        return SVN_NO_ERROR; /* ### What should we do here? */
442
 
 
443
 
      default:
444
 
        break; /* Go check other conditions */
445
 
    }
 
196
  svn_wc__db_t *db = eb->db;
 
197
 
 
198
  if (! status->versioned)
 
199
    return SVN_NO_ERROR; /* unversioned (includes dir externals) */
 
200
 
 
201
  if (status->node_status == svn_wc_status_conflicted
 
202
      && status->text_status == svn_wc_status_none
 
203
      && status->prop_status == svn_wc_status_none)
 
204
    {
 
205
      /* Node is an actual only node describing a tree conflict */
 
206
      return SVN_NO_ERROR;
 
207
    }
 
208
 
 
209
  /* Not text/prop modified, not copied. Easy out */
 
210
  if (status->node_status == svn_wc_status_normal && !status->copied)
 
211
    return SVN_NO_ERROR;
 
212
 
 
213
  /* Mark all directories where we are no longer inside as closed */
 
214
  while (eb->cur
 
215
         && !svn_dirent_is_ancestor(eb->cur->local_abspath, local_abspath))
 
216
    {
 
217
      struct node_state_t *ns = eb->cur;
 
218
 
 
219
      if (!ns->skip)
 
220
        {
 
221
          if (ns->propchanges)
 
222
            SVN_ERR(eb->processor->dir_changed(ns->relpath,
 
223
                                               ns->left_src,
 
224
                                               ns->right_src,
 
225
                                               ns->left_props,
 
226
                                               ns->right_props,
 
227
                                               ns->propchanges,
 
228
                                               ns->baton,
 
229
                                               eb->processor,
 
230
                                               ns->pool));
 
231
          else
 
232
            SVN_ERR(eb->processor->dir_closed(ns->relpath,
 
233
                                              ns->left_src,
 
234
                                              ns->right_src,
 
235
                                              ns->baton,
 
236
                                              eb->processor,
 
237
                                              ns->pool));
 
238
        }
 
239
      eb->cur = ns->parent;
 
240
      svn_pool_clear(ns->pool);
 
241
    }
 
242
  SVN_ERR(ensure_state(eb, svn_dirent_dirname(local_abspath, scratch_pool),
 
243
                       FALSE, scratch_pool));
 
244
 
 
245
  if (eb->cur && eb->cur->skip_children)
 
246
    return SVN_NO_ERROR;
446
247
 
447
248
  if (eb->changelist_hash != NULL
448
249
      && (!status->changelist
449
 
          || ! apr_hash_get(eb->changelist_hash, status->changelist,
450
 
                            APR_HASH_KEY_STRING)))
 
250
          || ! svn_hash_gets(eb->changelist_hash, status->changelist)))
451
251
    return SVN_NO_ERROR; /* Filtered via changelist */
452
252
 
453
 
  /* ### The following checks should probably be reversed as it should decide
454
 
         when *not* to show a diff, because generally all changed nodes should
455
 
         have a diff. */
456
 
  if (status->kind == svn_node_file)
457
 
    {
458
 
      /* Show a diff when
459
 
       *   - The text is modified
460
 
       *   - Or the properties are modified
461
 
       *   - Or when the node has been replaced
462
 
       *   - Or (if in copies as adds or git mode) when a node is copied */
463
 
      if (status->text_status == svn_wc_status_modified
464
 
          || status->prop_status == svn_wc_status_modified
465
 
          || status->node_status == svn_wc_status_deleted
466
 
          || status->node_status == svn_wc_status_replaced
467
 
          || ((eb->show_copies_as_adds || eb->use_git_diff_format)
468
 
              && status->copied))
469
 
        {
470
 
          const char *path = svn_dirent_skip_ancestor(eb->anchor_abspath,
471
 
                                                      local_abspath);
472
 
 
473
 
          SVN_ERR(file_diff(eb, local_abspath, path, scratch_pool));
474
 
        }
475
 
    }
476
 
  else
477
 
    {
478
 
      /* ### This case should probably be extended for git-diff, but this
479
 
             is what the old diff code provided */
480
 
      if (status->node_status == svn_wc_status_deleted
481
 
          || status->node_status == svn_wc_status_replaced
482
 
          || status->prop_status == svn_wc_status_modified)
483
 
        {
484
 
          apr_array_header_t *propchanges;
485
 
          apr_hash_t *baseprops;
486
 
          const char *path = svn_dirent_skip_ancestor(eb->anchor_abspath,
487
 
                                                      local_abspath);
488
 
 
489
 
 
490
 
          SVN_ERR(svn_wc__internal_propdiff(&propchanges, &baseprops,
491
 
                                            eb->db, local_abspath,
492
 
                                            scratch_pool, scratch_pool));
493
 
 
494
 
          SVN_ERR(eb->callbacks->dir_props_changed(NULL, NULL,
495
 
                                                   path, FALSE /* ### ? */,
496
 
                                                   propchanges, baseprops,
497
 
                                                   eb->callback_baton,
 
253
  /* This code does about the same thing as the inner body of
 
254
     walk_local_nodes_diff() in diff_editor.c, except that
 
255
     it is already filtered by the status walker, doesn't have to
 
256
     account for remote changes (and many tiny other details) */
 
257
 
 
258
  {
 
259
    svn_boolean_t repos_only;
 
260
    svn_boolean_t local_only;
 
261
    svn_wc__db_status_t db_status;
 
262
    svn_boolean_t have_base;
 
263
    svn_node_kind_t base_kind;
 
264
    svn_node_kind_t db_kind = status->kind;
 
265
    svn_depth_t depth_below_here = svn_depth_unknown;
 
266
 
 
267
    const char *child_abspath = local_abspath;
 
268
    const char *child_relpath = svn_dirent_skip_ancestor(eb->anchor_abspath,
 
269
                                                         local_abspath);
 
270
 
 
271
 
 
272
    repos_only = FALSE;
 
273
    local_only = FALSE;
 
274
 
 
275
    /* ### optimize away this call using status info. Should
 
276
           be possible in almost every case (except conflict, missing, obst.)*/
 
277
    SVN_ERR(svn_wc__db_read_info(&db_status, NULL, NULL, NULL, NULL, NULL,
 
278
                                 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
 
279
                                 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
 
280
                                 NULL, NULL, NULL, NULL,
 
281
                                 &have_base, NULL, NULL,
 
282
                                 eb->db, local_abspath,
 
283
                                 scratch_pool, scratch_pool));
 
284
    if (!have_base)
 
285
      {
 
286
        local_only = TRUE; /* Only report additions */
 
287
      }
 
288
    else if (db_status == svn_wc__db_status_normal)
 
289
      {
 
290
        /* Simple diff */
 
291
        base_kind = db_kind;
 
292
      }
 
293
    else if (db_status == svn_wc__db_status_deleted)
 
294
      {
 
295
        svn_wc__db_status_t base_status;
 
296
        repos_only = TRUE;
 
297
        SVN_ERR(svn_wc__db_base_get_info(&base_status, &base_kind, NULL,
 
298
                                         NULL, NULL, NULL, NULL, NULL,
 
299
                                         NULL, NULL, NULL, NULL, NULL,
 
300
                                         NULL, NULL, NULL,
 
301
                                         eb->db, local_abspath,
 
302
                                         scratch_pool, scratch_pool));
 
303
 
 
304
        if (base_status != svn_wc__db_status_normal)
 
305
          return SVN_NO_ERROR;
 
306
      }
 
307
    else
 
308
      {
 
309
        /* working status is either added or deleted */
 
310
        svn_wc__db_status_t base_status;
 
311
 
 
312
        SVN_ERR(svn_wc__db_base_get_info(&base_status, &base_kind, NULL,
 
313
                                         NULL, NULL, NULL, NULL, NULL,
 
314
                                         NULL, NULL, NULL, NULL, NULL,
 
315
                                         NULL, NULL, NULL,
 
316
                                         eb->db, local_abspath,
 
317
                                         scratch_pool, scratch_pool));
 
318
 
 
319
        if (base_status != svn_wc__db_status_normal)
 
320
          local_only = TRUE;
 
321
        else if (base_kind != db_kind || !eb->ignore_ancestry)
 
322
          {
 
323
            repos_only = TRUE;
 
324
            local_only = TRUE;
 
325
          }
 
326
      }
 
327
 
 
328
    if (repos_only)
 
329
      {
 
330
        /* Report repository form deleted */
 
331
        if (base_kind == svn_node_file)
 
332
          SVN_ERR(svn_wc__diff_base_only_file(db, child_abspath,
 
333
                                              child_relpath,
 
334
                                              SVN_INVALID_REVNUM,
 
335
                                              eb->processor,
 
336
                                              eb->cur ? eb->cur->baton : NULL,
 
337
                                              scratch_pool));
 
338
        else if (base_kind == svn_node_dir)
 
339
          SVN_ERR(svn_wc__diff_base_only_dir(db, child_abspath,
 
340
                                             child_relpath,
 
341
                                             SVN_INVALID_REVNUM,
 
342
                                             depth_below_here,
 
343
                                             eb->processor,
 
344
                                             eb->cur ? eb->cur->baton : NULL,
 
345
                                             eb->cancel_func,
 
346
                                             eb->cancel_baton,
 
347
                                             scratch_pool));
 
348
      }
 
349
    else if (!local_only)
 
350
      {
 
351
        /* Diff base against actual */
 
352
        if (db_kind == svn_node_file)
 
353
          {
 
354
            SVN_ERR(svn_wc__diff_base_working_diff(db, child_abspath,
 
355
                                                   child_relpath,
 
356
                                                   SVN_INVALID_REVNUM,
 
357
                                                   eb->changelist_hash,
 
358
                                                   eb->processor,
 
359
                                                   eb->cur
 
360
                                                        ? eb->cur->baton
 
361
                                                        : NULL,
 
362
                                                   FALSE,
 
363
                                                   eb->cancel_func,
 
364
                                                   eb->cancel_baton,
498
365
                                                   scratch_pool));
499
 
        }
500
 
    }
 
366
          }
 
367
        else if (db_kind == svn_node_dir)
 
368
          {
 
369
            SVN_ERR(ensure_state(eb, local_abspath, FALSE, scratch_pool));
 
370
 
 
371
            if (status->prop_status != svn_wc_status_none
 
372
                && status->prop_status != svn_wc_status_normal)
 
373
              {
 
374
                apr_array_header_t *propchanges;
 
375
                SVN_ERR(svn_wc__db_base_get_props(&eb->cur->left_props,
 
376
                                                  eb->db, local_abspath,
 
377
                                                  eb->cur->pool,
 
378
                                                  scratch_pool));
 
379
                SVN_ERR(svn_wc__db_read_props(&eb->cur->right_props,
 
380
                                              eb->db, local_abspath,
 
381
                                              eb->cur->pool,
 
382
                                              scratch_pool));
 
383
 
 
384
                SVN_ERR(svn_prop_diffs(&propchanges,
 
385
                                       eb->cur->right_props,
 
386
                                       eb->cur->left_props,
 
387
                                       eb->cur->pool));
 
388
 
 
389
                eb->cur->propchanges = propchanges;
 
390
              }
 
391
          }
 
392
      }
 
393
 
 
394
    if (local_only && (db_status != svn_wc__db_status_deleted))
 
395
      {
 
396
        if (db_kind == svn_node_file)
 
397
          SVN_ERR(svn_wc__diff_local_only_file(db, child_abspath,
 
398
                                               child_relpath,
 
399
                                               eb->processor,
 
400
                                               eb->cur ? eb->cur->baton : NULL,
 
401
                                               eb->changelist_hash,
 
402
                                               FALSE,
 
403
                                               eb->cancel_func,
 
404
                                               eb->cancel_baton,
 
405
                                               scratch_pool));
 
406
        else if (db_kind == svn_node_dir)
 
407
          SVN_ERR(svn_wc__diff_local_only_dir(db, child_abspath,
 
408
                                              child_relpath, depth_below_here,
 
409
                                              eb->processor,
 
410
                                              eb->cur ? eb->cur->baton : NULL,
 
411
                                              eb->changelist_hash,
 
412
                                              FALSE,
 
413
                                              eb->cancel_func,
 
414
                                              eb->cancel_baton,
 
415
                                              scratch_pool));
 
416
      }
 
417
 
 
418
    if (db_kind == svn_node_dir && (local_only || repos_only))
 
419
      SVN_ERR(ensure_state(eb, local_abspath, TRUE /* skip */, scratch_pool));
 
420
  }
 
421
 
501
422
  return SVN_NO_ERROR;
502
423
}
503
424
 
518
439
             apr_pool_t *scratch_pool)
519
440
{
520
441
  struct diff_baton eb = { 0 };
521
 
  svn_wc__db_kind_t kind;
 
442
  svn_node_kind_t kind;
522
443
  svn_boolean_t get_all;
 
444
  const svn_diff_tree_processor_t *processor;
523
445
 
524
446
  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
525
 
  SVN_ERR(svn_wc__db_read_kind(&kind, wc_ctx->db, local_abspath, FALSE,
 
447
  SVN_ERR(svn_wc__db_read_kind(&kind, wc_ctx->db, local_abspath,
 
448
                               FALSE /* allow_missing */,
 
449
                               TRUE /* show_deleted */,
 
450
                               FALSE /* show_hidden */,
526
451
                               scratch_pool));
527
452
 
528
 
  if (kind == svn_wc__db_kind_dir)
529
 
      eb.anchor_abspath = local_abspath;
 
453
  if (kind == svn_node_dir)
 
454
    eb.anchor_abspath = local_abspath;
530
455
  else
531
456
    eb.anchor_abspath = svn_dirent_dirname(local_abspath, scratch_pool);
532
457
 
 
458
  SVN_ERR(svn_wc__wrap_diff_callbacks(&processor,
 
459
                                      callbacks, callback_baton, TRUE,
 
460
                                      scratch_pool, scratch_pool));
 
461
 
 
462
  if (use_git_diff_format)
 
463
    show_copies_as_adds = TRUE;
 
464
  if (show_copies_as_adds)
 
465
    ignore_ancestry = FALSE;
 
466
 
 
467
 
 
468
 
 
469
  /*
 
470
  if (reverse_order)
 
471
    processor = svn_diff__tree_processor_reverse_create(processor, NULL, pool);
 
472
   */
 
473
 
 
474
  if (! show_copies_as_adds && !use_git_diff_format)
 
475
    processor = svn_diff__tree_processor_copy_as_changed_create(processor,
 
476
                                                                scratch_pool);
 
477
 
533
478
  eb.db = wc_ctx->db;
534
 
  eb.callbacks = callbacks;
535
 
  eb.callback_baton = callback_baton;
 
479
  eb.processor = processor;
536
480
  eb.ignore_ancestry = ignore_ancestry;
537
481
  eb.show_copies_as_adds = show_copies_as_adds;
538
 
  eb.use_git_diff_format = use_git_diff_format;
539
 
  eb.empty_file = NULL;
540
482
  eb.pool = scratch_pool;
541
483
 
542
484
  if (changelist_filter && changelist_filter->nelts)
543
485
    SVN_ERR(svn_hash_from_cstring_keys(&eb.changelist_hash, changelist_filter,
544
486
                                       scratch_pool));
545
487
 
546
 
  if (show_copies_as_adds || use_git_diff_format)
 
488
  if (show_copies_as_adds || use_git_diff_format || !ignore_ancestry)
547
489
    get_all = TRUE; /* We need unmodified descendants of copies */
548
490
  else
549
491
    get_all = FALSE;
558
500
                                       cancel_func, cancel_baton,
559
501
                                       scratch_pool));
560
502
 
 
503
  /* Close the remaining open directories */
 
504
  while (eb.cur)
 
505
    {
 
506
      struct node_state_t *ns = eb.cur;
 
507
 
 
508
      if (!ns->skip)
 
509
        {
 
510
          if (ns->propchanges)
 
511
            SVN_ERR(processor->dir_changed(ns->relpath,
 
512
                                           ns->left_src,
 
513
                                           ns->right_src,
 
514
                                           ns->left_props,
 
515
                                           ns->right_props,
 
516
                                           ns->propchanges,
 
517
                                           ns->baton,
 
518
                                           processor,
 
519
                                           ns->pool));
 
520
          else
 
521
            SVN_ERR(processor->dir_closed(ns->relpath,
 
522
                                          ns->left_src,
 
523
                                          ns->right_src,
 
524
                                          ns->baton,
 
525
                                          processor,
 
526
                                          ns->pool));
 
527
        }
 
528
      eb.cur = ns->parent;
 
529
      svn_pool_clear(ns->pool);
 
530
    }
 
531
 
561
532
  return SVN_NO_ERROR;
562
533
}