rugged 0.23.0b2 → 0.23.0b4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (124) hide show
  1. checksums.yaml +4 -4
  2. data/ext/rugged/rugged_blob.c +39 -0
  3. data/ext/rugged/rugged_diff.c +7 -3
  4. data/ext/rugged/rugged_index.c +2 -2
  5. data/ext/rugged/rugged_remote.c +27 -148
  6. data/ext/rugged/rugged_remote_collection.c +134 -12
  7. data/ext/rugged/rugged_repo.c +74 -5
  8. data/ext/rugged/rugged_submodule.c +18 -208
  9. data/ext/rugged/rugged_submodule_collection.c +148 -0
  10. data/lib/rugged/version.rb +1 -1
  11. data/vendor/libgit2/AUTHORS +1 -0
  12. data/vendor/libgit2/CMakeLists.txt +33 -25
  13. data/vendor/libgit2/deps/winhttp/winhttp.def +29 -29
  14. data/vendor/libgit2/include/git2.h +1 -1
  15. data/vendor/libgit2/include/git2/blob.h +4 -6
  16. data/vendor/libgit2/include/git2/checkout.h +10 -1
  17. data/vendor/libgit2/include/git2/clone.h +6 -7
  18. data/vendor/libgit2/include/git2/commit.h +11 -0
  19. data/vendor/libgit2/include/git2/cred_helpers.h +2 -2
  20. data/vendor/libgit2/include/git2/describe.h +1 -1
  21. data/vendor/libgit2/include/git2/diff.h +68 -11
  22. data/vendor/libgit2/include/git2/errors.h +4 -1
  23. data/vendor/libgit2/include/git2/filter.h +16 -0
  24. data/vendor/libgit2/include/git2/index.h +38 -11
  25. data/vendor/libgit2/include/git2/odb.h +1 -1
  26. data/vendor/libgit2/include/git2/odb_backend.h +2 -2
  27. data/vendor/libgit2/include/git2/remote.h +300 -207
  28. data/vendor/libgit2/include/git2/reset.h +1 -0
  29. data/vendor/libgit2/include/git2/stash.h +135 -4
  30. data/vendor/libgit2/include/git2/status.h +1 -0
  31. data/vendor/libgit2/include/git2/submodule.h +46 -75
  32. data/vendor/libgit2/include/git2/sys/odb_backend.h +1 -1
  33. data/vendor/libgit2/include/git2/sys/stream.h +2 -0
  34. data/vendor/libgit2/include/git2/sys/transport.h +1 -21
  35. data/vendor/libgit2/include/git2/transport.h +27 -0
  36. data/vendor/libgit2/include/git2/types.h +20 -10
  37. data/vendor/libgit2/include/git2/version.h +3 -3
  38. data/vendor/libgit2/libgit2.pc.in +4 -2
  39. data/vendor/libgit2/src/attr.c +2 -1
  40. data/vendor/libgit2/src/attr_file.c +18 -37
  41. data/vendor/libgit2/src/blame.c +2 -2
  42. data/vendor/libgit2/src/blob.c +4 -3
  43. data/vendor/libgit2/src/branch.c +6 -3
  44. data/vendor/libgit2/src/buf_text.c +4 -6
  45. data/vendor/libgit2/src/buf_text.h +1 -2
  46. data/vendor/libgit2/src/buffer.c +8 -6
  47. data/vendor/libgit2/src/buffer.h +1 -1
  48. data/vendor/libgit2/src/cache.c +1 -0
  49. data/vendor/libgit2/src/checkout.c +34 -20
  50. data/vendor/libgit2/src/clone.c +29 -29
  51. data/vendor/libgit2/src/commit.c +65 -0
  52. data/vendor/libgit2/src/common.h +5 -0
  53. data/vendor/libgit2/src/config.c +20 -0
  54. data/vendor/libgit2/src/config.h +6 -0
  55. data/vendor/libgit2/src/config_file.c +2 -2
  56. data/vendor/libgit2/src/crlf.c +39 -17
  57. data/vendor/libgit2/src/curl_stream.c +257 -0
  58. data/vendor/libgit2/src/curl_stream.h +14 -0
  59. data/vendor/libgit2/src/diff.c +223 -88
  60. data/vendor/libgit2/src/diff.h +21 -1
  61. data/vendor/libgit2/src/diff_file.c +23 -13
  62. data/vendor/libgit2/src/diff_file.h +4 -2
  63. data/vendor/libgit2/src/diff_patch.c +266 -71
  64. data/vendor/libgit2/src/diff_patch.h +36 -0
  65. data/vendor/libgit2/src/diff_print.c +156 -126
  66. data/vendor/libgit2/src/diff_tform.c +32 -54
  67. data/vendor/libgit2/src/fetch.c +27 -10
  68. data/vendor/libgit2/src/fetch.h +2 -2
  69. data/vendor/libgit2/src/filebuf.c +1 -1
  70. data/vendor/libgit2/src/fileops.c +6 -2
  71. data/vendor/libgit2/src/filter.c +28 -7
  72. data/vendor/libgit2/src/fnmatch.c +5 -5
  73. data/vendor/libgit2/src/global.c +16 -0
  74. data/vendor/libgit2/src/ident.c +2 -2
  75. data/vendor/libgit2/src/ignore.c +1 -0
  76. data/vendor/libgit2/src/index.c +338 -80
  77. data/vendor/libgit2/src/index.h +4 -1
  78. data/vendor/libgit2/src/indexer.c +19 -5
  79. data/vendor/libgit2/src/iterator.c +118 -11
  80. data/vendor/libgit2/src/iterator.h +25 -0
  81. data/vendor/libgit2/src/merge.c +96 -106
  82. data/vendor/libgit2/src/merge.h +14 -4
  83. data/vendor/libgit2/src/netops.c +3 -3
  84. data/vendor/libgit2/src/odb.c +17 -9
  85. data/vendor/libgit2/src/odb.h +1 -1
  86. data/vendor/libgit2/src/odb_loose.c +2 -2
  87. data/vendor/libgit2/src/odb_pack.c +1 -1
  88. data/vendor/libgit2/src/openssl_stream.c +118 -27
  89. data/vendor/libgit2/src/pack-objects.c +28 -0
  90. data/vendor/libgit2/src/pack-objects.h +1 -0
  91. data/vendor/libgit2/src/pack.c +18 -10
  92. data/vendor/libgit2/src/path.c +16 -11
  93. data/vendor/libgit2/src/path.h +1 -1
  94. data/vendor/libgit2/src/push.c +26 -42
  95. data/vendor/libgit2/src/push.h +2 -34
  96. data/vendor/libgit2/src/rebase.c +1 -1
  97. data/vendor/libgit2/src/refs.c +1 -1
  98. data/vendor/libgit2/src/refspec.c +6 -0
  99. data/vendor/libgit2/src/remote.c +381 -274
  100. data/vendor/libgit2/src/remote.h +0 -4
  101. data/vendor/libgit2/src/repository.c +33 -12
  102. data/vendor/libgit2/src/repository.h +0 -1
  103. data/vendor/libgit2/src/reset.c +1 -0
  104. data/vendor/libgit2/src/stash.c +439 -17
  105. data/vendor/libgit2/src/status.c +6 -0
  106. data/vendor/libgit2/src/stransport_stream.c +58 -21
  107. data/vendor/libgit2/src/stream.h +15 -0
  108. data/vendor/libgit2/src/submodule.c +410 -664
  109. data/vendor/libgit2/src/submodule.h +0 -24
  110. data/vendor/libgit2/src/transaction.c +1 -0
  111. data/vendor/libgit2/src/transports/cred.c +55 -1
  112. data/vendor/libgit2/src/transports/http.c +18 -2
  113. data/vendor/libgit2/src/transports/local.c +60 -59
  114. data/vendor/libgit2/src/transports/smart.h +1 -1
  115. data/vendor/libgit2/src/transports/smart_protocol.c +11 -11
  116. data/vendor/libgit2/src/transports/ssh.c +46 -7
  117. data/vendor/libgit2/src/unix/posix.h +4 -0
  118. data/vendor/libgit2/src/util.c +9 -9
  119. data/vendor/libgit2/src/util.h +9 -0
  120. data/vendor/libgit2/src/win32/posix.h +3 -0
  121. data/vendor/libgit2/src/win32/posix_w32.c +38 -0
  122. data/vendor/libgit2/src/win32/w32_util.h +10 -0
  123. metadata +4 -3
  124. data/vendor/libgit2/include/git2/push.h +0 -94
@@ -64,6 +64,7 @@ struct git_diff {
64
64
  git_iterator_type_t new_src;
65
65
  uint32_t diffcaps;
66
66
  git_diff_perfdata perf;
67
+ bool index_updated;
67
68
 
68
69
  int (*strcomp)(const char *, const char *);
69
70
  int (*strncomp)(const char *, const char *, size_t);
@@ -94,7 +95,7 @@ extern int git_diff_delta__format_file_header(
94
95
  extern int git_diff__oid_for_file(
95
96
  git_oid *out, git_diff *, const char *, uint16_t, git_off_t);
96
97
  extern int git_diff__oid_for_entry(
97
- git_oid *out, git_diff *, const git_index_entry *, const git_oid *update);
98
+ git_oid *out, git_diff *, const git_index_entry *, uint16_t, const git_oid *update);
98
99
 
99
100
  extern int git_diff__from_iterators(
100
101
  git_diff **diff_ptr,
@@ -123,6 +124,25 @@ extern int git_diff_find_similar__calc_similarity(
123
124
  extern int git_diff__commit(
124
125
  git_diff **diff, git_repository *repo, const git_commit *commit, const git_diff_options *opts);
125
126
 
127
+ /* Merge two `git_diff`s according to the callback given by `cb`. */
128
+
129
+ typedef git_diff_delta *(*git_diff__merge_cb)(
130
+ const git_diff_delta *left,
131
+ const git_diff_delta *right,
132
+ git_pool *pool);
133
+
134
+ extern int git_diff__merge(
135
+ git_diff *onto, const git_diff *from, git_diff__merge_cb cb);
136
+
137
+ extern git_diff_delta *git_diff__merge_like_cgit(
138
+ const git_diff_delta *a,
139
+ const git_diff_delta *b,
140
+ git_pool *pool);
141
+
142
+ /* Duplicate a `git_diff_delta` out of the `git_pool` */
143
+ extern git_diff_delta *git_diff__delta_dup(
144
+ const git_diff_delta *d, git_pool *pool);
145
+
126
146
  /*
127
147
  * Sometimes a git_diff_file will have a zero size; this attempts to
128
148
  * fill in the size without loading the blob if possible. If that is
@@ -89,10 +89,9 @@ static int diff_file_content_init_common(
89
89
  int git_diff_file_content__init_from_diff(
90
90
  git_diff_file_content *fc,
91
91
  git_diff *diff,
92
- size_t delta_index,
92
+ git_diff_delta *delta,
93
93
  bool use_old)
94
94
  {
95
- git_diff_delta *delta = git_vector_get(&diff->deltas, delta_index);
96
95
  bool has_data = true;
97
96
 
98
97
  memset(fc, 0, sizeof(*fc));
@@ -187,7 +186,7 @@ static int diff_file_content_commit_to_str(
187
186
  return error;
188
187
  }
189
188
 
190
- if ((error = git_submodule_status(&sm_status, sm)) < 0) {
189
+ if ((error = git_submodule_status(&sm_status, fc->repo, fc->file->path, GIT_SUBMODULE_IGNORE_UNSPECIFIED)) < 0) {
191
190
  git_submodule_free(sm);
192
191
  return error;
193
192
  }
@@ -218,7 +217,9 @@ static int diff_file_content_commit_to_str(
218
217
  return 0;
219
218
  }
220
219
 
221
- static int diff_file_content_load_blob(git_diff_file_content *fc)
220
+ static int diff_file_content_load_blob(
221
+ git_diff_file_content *fc,
222
+ git_diff_options *opts)
222
223
  {
223
224
  int error = 0;
224
225
  git_odb_object *odb_obj = NULL;
@@ -236,7 +237,8 @@ static int diff_file_content_load_blob(git_diff_file_content *fc)
236
237
  return error;
237
238
  }
238
239
 
239
- if (diff_file_content_binary_by_size(fc))
240
+ if ((opts->flags & GIT_DIFF_SHOW_BINARY) == 0 &&
241
+ diff_file_content_binary_by_size(fc))
240
242
  return 0;
241
243
 
242
244
  if (odb_obj != NULL) {
@@ -283,7 +285,9 @@ static int diff_file_content_load_workdir_symlink(
283
285
  }
284
286
 
285
287
  static int diff_file_content_load_workdir_file(
286
- git_diff_file_content *fc, git_buf *path)
288
+ git_diff_file_content *fc,
289
+ git_buf *path,
290
+ git_diff_options *diff_opts)
287
291
  {
288
292
  int error = 0;
289
293
  git_filter_list *fl = NULL;
@@ -297,7 +301,8 @@ static int diff_file_content_load_workdir_file(
297
301
  !(fc->file->size = git_futils_filesize(fd)))
298
302
  goto cleanup;
299
303
 
300
- if (diff_file_content_binary_by_size(fc))
304
+ if ((diff_opts->flags & GIT_DIFF_SHOW_BINARY) == 0 &&
305
+ diff_file_content_binary_by_size(fc))
301
306
  goto cleanup;
302
307
 
303
308
  if ((error = git_filter_list_load(
@@ -339,7 +344,9 @@ cleanup:
339
344
  return error;
340
345
  }
341
346
 
342
- static int diff_file_content_load_workdir(git_diff_file_content *fc)
347
+ static int diff_file_content_load_workdir(
348
+ git_diff_file_content *fc,
349
+ git_diff_options *diff_opts)
343
350
  {
344
351
  int error = 0;
345
352
  git_buf path = GIT_BUF_INIT;
@@ -357,7 +364,7 @@ static int diff_file_content_load_workdir(git_diff_file_content *fc)
357
364
  if (S_ISLNK(fc->file->mode))
358
365
  error = diff_file_content_load_workdir_symlink(fc, &path);
359
366
  else
360
- error = diff_file_content_load_workdir_file(fc, &path);
367
+ error = diff_file_content_load_workdir_file(fc, &path, diff_opts);
361
368
 
362
369
  /* once data is loaded, update OID if we didn't have it previously */
363
370
  if (!error && (fc->file->flags & GIT_DIFF_FLAG_VALID_ID) == 0) {
@@ -370,20 +377,23 @@ static int diff_file_content_load_workdir(git_diff_file_content *fc)
370
377
  return error;
371
378
  }
372
379
 
373
- int git_diff_file_content__load(git_diff_file_content *fc)
380
+ int git_diff_file_content__load(
381
+ git_diff_file_content *fc,
382
+ git_diff_options *diff_opts)
374
383
  {
375
384
  int error = 0;
376
385
 
377
386
  if ((fc->flags & GIT_DIFF_FLAG__LOADED) != 0)
378
387
  return 0;
379
388
 
380
- if ((fc->file->flags & GIT_DIFF_FLAG_BINARY) != 0)
389
+ if ((fc->file->flags & GIT_DIFF_FLAG_BINARY) != 0 &&
390
+ (diff_opts->flags & GIT_DIFF_SHOW_BINARY) == 0)
381
391
  return 0;
382
392
 
383
393
  if (fc->src == GIT_ITERATOR_TYPE_WORKDIR)
384
- error = diff_file_content_load_workdir(fc);
394
+ error = diff_file_content_load_workdir(fc, diff_opts);
385
395
  else
386
- error = diff_file_content_load_blob(fc);
396
+ error = diff_file_content_load_blob(fc, diff_opts);
387
397
  if (error)
388
398
  return error;
389
399
 
@@ -28,7 +28,7 @@ typedef struct {
28
28
  extern int git_diff_file_content__init_from_diff(
29
29
  git_diff_file_content *fc,
30
30
  git_diff *diff,
31
- size_t delta_index,
31
+ git_diff_delta *delta,
32
32
  bool use_old);
33
33
 
34
34
  typedef struct {
@@ -49,7 +49,9 @@ extern int git_diff_file_content__init_from_src(
49
49
  git_diff_file *as_file);
50
50
 
51
51
  /* this loads the blob/file-on-disk as needed */
52
- extern int git_diff_file_content__load(git_diff_file_content *fc);
52
+ extern int git_diff_file_content__load(
53
+ git_diff_file_content *fc,
54
+ git_diff_options *diff_opts);
53
55
 
54
56
  /* this releases the blob/file-in-memory */
55
57
  extern void git_diff_file_content__unload(git_diff_file_content *fc);
@@ -11,41 +11,13 @@
11
11
  #include "diff_driver.h"
12
12
  #include "diff_patch.h"
13
13
  #include "diff_xdiff.h"
14
+ #include "delta.h"
15
+ #include "zstream.h"
14
16
  #include "fileops.h"
15
17
 
16
- /* cached information about a hunk in a diff */
17
- typedef struct diff_patch_hunk {
18
- git_diff_hunk hunk;
19
- size_t line_start;
20
- size_t line_count;
21
- } diff_patch_hunk;
22
-
23
- struct git_patch {
24
- git_refcount rc;
25
- git_diff *diff; /* for refcount purposes, maybe NULL for blob diffs */
26
- git_diff_delta *delta;
27
- size_t delta_index;
28
- git_diff_file_content ofile;
29
- git_diff_file_content nfile;
30
- uint32_t flags;
31
- git_array_t(diff_patch_hunk) hunks;
32
- git_array_t(git_diff_line) lines;
33
- size_t content_size, context_size, header_size;
34
- git_pool flattened;
35
- };
36
-
37
- enum {
38
- GIT_DIFF_PATCH_ALLOCATED = (1 << 0),
39
- GIT_DIFF_PATCH_INITIALIZED = (1 << 1),
40
- GIT_DIFF_PATCH_LOADED = (1 << 2),
41
- GIT_DIFF_PATCH_DIFFABLE = (1 << 3),
42
- GIT_DIFF_PATCH_DIFFED = (1 << 4),
43
- GIT_DIFF_PATCH_FLATTENED = (1 << 5),
44
- };
45
-
46
18
  static void diff_output_init(
47
- git_diff_output*, const git_diff_options*,
48
- git_diff_file_cb, git_diff_hunk_cb, git_diff_line_cb, void*);
19
+ git_diff_output*, const git_diff_options*, git_diff_file_cb,
20
+ git_diff_binary_cb, git_diff_hunk_cb, git_diff_line_cb, void*);
49
21
 
50
22
  static void diff_output_to_patch(git_diff_output *, git_patch *);
51
23
 
@@ -67,15 +39,38 @@ static void diff_patch_init_common(git_patch *patch)
67
39
  {
68
40
  diff_patch_update_binary(patch);
69
41
 
70
- if ((patch->delta->flags & GIT_DIFF_FLAG_BINARY) != 0)
71
- patch->flags |= GIT_DIFF_PATCH_LOADED; /* LOADED but not DIFFABLE */
72
-
73
42
  patch->flags |= GIT_DIFF_PATCH_INITIALIZED;
74
43
 
75
44
  if (patch->diff)
76
45
  git_diff_addref(patch->diff);
77
46
  }
78
47
 
48
+ static int diff_patch_normalize_options(
49
+ git_diff_options *out,
50
+ const git_diff_options *opts)
51
+ {
52
+ if (opts) {
53
+ GITERR_CHECK_VERSION(opts, GIT_DIFF_OPTIONS_VERSION, "git_diff_options");
54
+ memcpy(out, opts, sizeof(git_diff_options));
55
+ } else {
56
+ git_diff_options default_opts = GIT_DIFF_OPTIONS_INIT;
57
+ memcpy(out, &default_opts, sizeof(git_diff_options));
58
+ }
59
+
60
+ out->old_prefix = opts && opts->old_prefix ?
61
+ git__strdup(opts->old_prefix) :
62
+ git__strdup(DIFF_OLD_PREFIX_DEFAULT);
63
+
64
+ out->new_prefix = opts && opts->new_prefix ?
65
+ git__strdup(opts->new_prefix) :
66
+ git__strdup(DIFF_NEW_PREFIX_DEFAULT);
67
+
68
+ GITERR_CHECK_ALLOC(out->old_prefix);
69
+ GITERR_CHECK_ALLOC(out->new_prefix);
70
+
71
+ return 0;
72
+ }
73
+
79
74
  static int diff_patch_init_from_diff(
80
75
  git_patch *patch, git_diff *diff, size_t delta_index)
81
76
  {
@@ -86,10 +81,12 @@ static int diff_patch_init_from_diff(
86
81
  patch->delta = git_vector_get(&diff->deltas, delta_index);
87
82
  patch->delta_index = delta_index;
88
83
 
89
- if ((error = git_diff_file_content__init_from_diff(
90
- &patch->ofile, diff, delta_index, true)) < 0 ||
84
+ if ((error = diff_patch_normalize_options(
85
+ &patch->diff_opts, &diff->opts)) < 0 ||
86
+ (error = git_diff_file_content__init_from_diff(
87
+ &patch->ofile, diff, patch->delta, true)) < 0 ||
91
88
  (error = git_diff_file_content__init_from_diff(
92
- &patch->nfile, diff, delta_index, false)) < 0)
89
+ &patch->nfile, diff, patch->delta, false)) < 0)
93
90
  return error;
94
91
 
95
92
  diff_patch_init_common(patch);
@@ -116,6 +113,43 @@ static int diff_patch_alloc_from_diff(
116
113
  return error;
117
114
  }
118
115
 
116
+ GIT_INLINE(bool) should_skip_binary(git_patch *patch, git_diff_file *file)
117
+ {
118
+ if ((patch->diff_opts.flags & GIT_DIFF_SHOW_BINARY) != 0)
119
+ return false;
120
+
121
+ return (file->flags & GIT_DIFF_FLAG_BINARY) != 0;
122
+ }
123
+
124
+ static bool diff_patch_diffable(git_patch *patch)
125
+ {
126
+ size_t olen, nlen;
127
+
128
+ if (patch->delta->status == GIT_DELTA_UNMODIFIED)
129
+ return false;
130
+
131
+ /* if we've determined this to be binary (and we are not showing binary
132
+ * data) then we have skipped loading the map data. instead, query the
133
+ * file data itself.
134
+ */
135
+ if ((patch->delta->flags & GIT_DIFF_FLAG_BINARY) != 0 &&
136
+ (patch->diff_opts.flags & GIT_DIFF_SHOW_BINARY) == 0) {
137
+ olen = (size_t)patch->ofile.file->size;
138
+ nlen = (size_t)patch->nfile.file->size;
139
+ } else {
140
+ olen = patch->ofile.map.len;
141
+ nlen = patch->nfile.map.len;
142
+ }
143
+
144
+ /* if both sides are empty, files are identical */
145
+ if (!olen && !nlen)
146
+ return false;
147
+
148
+ /* otherwise, check the file sizes and the oid */
149
+ return (olen != nlen ||
150
+ !git_oid_equal(&patch->ofile.file->id, &patch->nfile.file->id));
151
+ }
152
+
119
153
  static int diff_patch_load(git_patch *patch, git_diff_output *output)
120
154
  {
121
155
  int error = 0;
@@ -128,7 +162,7 @@ static int diff_patch_load(git_patch *patch, git_diff_output *output)
128
162
  * binary, then there is no need to actually load the data
129
163
  */
130
164
  if ((patch->ofile.opts_flags & GIT_DIFF_SKIP_BINARY_CHECK) != 0 &&
131
- output && !output->hunk_cb && !output->data_cb)
165
+ output && !output->binary_cb && !output->hunk_cb && !output->data_cb)
132
166
  return 0;
133
167
 
134
168
  incomplete_data =
@@ -141,25 +175,29 @@ static int diff_patch_load(git_patch *patch, git_diff_output *output)
141
175
  * need 2x data size and this minimizes peak memory footprint
142
176
  */
143
177
  if (patch->ofile.src == GIT_ITERATOR_TYPE_WORKDIR) {
144
- if ((error = git_diff_file_content__load(&patch->ofile)) < 0 ||
145
- (patch->ofile.file->flags & GIT_DIFF_FLAG_BINARY) != 0)
178
+ if ((error = git_diff_file_content__load(
179
+ &patch->ofile, &patch->diff_opts)) < 0 ||
180
+ should_skip_binary(patch, patch->ofile.file))
146
181
  goto cleanup;
147
182
  }
148
183
  if (patch->nfile.src == GIT_ITERATOR_TYPE_WORKDIR) {
149
- if ((error = git_diff_file_content__load(&patch->nfile)) < 0 ||
150
- (patch->nfile.file->flags & GIT_DIFF_FLAG_BINARY) != 0)
184
+ if ((error = git_diff_file_content__load(
185
+ &patch->nfile, &patch->diff_opts)) < 0 ||
186
+ should_skip_binary(patch, patch->nfile.file))
151
187
  goto cleanup;
152
188
  }
153
189
 
154
190
  /* once workdir has been tried, load other data as needed */
155
191
  if (patch->ofile.src != GIT_ITERATOR_TYPE_WORKDIR) {
156
- if ((error = git_diff_file_content__load(&patch->ofile)) < 0 ||
157
- (patch->ofile.file->flags & GIT_DIFF_FLAG_BINARY) != 0)
192
+ if ((error = git_diff_file_content__load(
193
+ &patch->ofile, &patch->diff_opts)) < 0 ||
194
+ should_skip_binary(patch, patch->ofile.file))
158
195
  goto cleanup;
159
196
  }
160
197
  if (patch->nfile.src != GIT_ITERATOR_TYPE_WORKDIR) {
161
- if ((error = git_diff_file_content__load(&patch->nfile)) < 0 ||
162
- (patch->nfile.file->flags & GIT_DIFF_FLAG_BINARY) != 0)
198
+ if ((error = git_diff_file_content__load(
199
+ &patch->nfile, &patch->diff_opts)) < 0 ||
200
+ should_skip_binary(patch, patch->nfile.file))
163
201
  goto cleanup;
164
202
  }
165
203
 
@@ -177,14 +215,7 @@ cleanup:
177
215
  diff_patch_update_binary(patch);
178
216
 
179
217
  if (!error) {
180
- /* patch is diffable only for non-binary, modified files where
181
- * at least one side has data and the data actually changed
182
- */
183
- if ((patch->delta->flags & GIT_DIFF_FLAG_BINARY) == 0 &&
184
- patch->delta->status != GIT_DELTA_UNMODIFIED &&
185
- (patch->ofile.map.len || patch->nfile.map.len) &&
186
- (patch->ofile.map.len != patch->nfile.map.len ||
187
- !git_oid_equal(&patch->ofile.file->id, &patch->nfile.file->id)))
218
+ if (diff_patch_diffable(patch))
188
219
  patch->flags |= GIT_DIFF_PATCH_DIFFABLE;
189
220
 
190
221
  patch->flags |= GIT_DIFF_PATCH_LOADED;
@@ -207,6 +238,103 @@ static int diff_patch_invoke_file_callback(
207
238
  "git_patch");
208
239
  }
209
240
 
241
+ static int create_binary(
242
+ git_diff_binary_t *out_type,
243
+ char **out_data,
244
+ size_t *out_datalen,
245
+ size_t *out_inflatedlen,
246
+ const char *a_data,
247
+ size_t a_datalen,
248
+ const char *b_data,
249
+ size_t b_datalen)
250
+ {
251
+ git_buf deflate = GIT_BUF_INIT, delta = GIT_BUF_INIT;
252
+ unsigned long delta_data_len;
253
+ int error;
254
+
255
+ /* The git_delta function accepts unsigned long only */
256
+ if (!git__is_ulong(a_datalen) || !git__is_ulong(b_datalen))
257
+ return GIT_EBUFS;
258
+
259
+ if ((error = git_zstream_deflatebuf(&deflate, b_data, b_datalen)) < 0)
260
+ goto done;
261
+
262
+ /* The git_delta function accepts unsigned long only */
263
+ if (!git__is_ulong(deflate.size)) {
264
+ error = GIT_EBUFS;
265
+ goto done;
266
+ }
267
+
268
+ if (a_datalen && b_datalen) {
269
+ void *delta_data = git_delta(
270
+ a_data, (unsigned long)a_datalen,
271
+ b_data, (unsigned long)b_datalen,
272
+ &delta_data_len, (unsigned long)deflate.size);
273
+
274
+ if (delta_data) {
275
+ error = git_zstream_deflatebuf(
276
+ &delta, delta_data, (size_t)delta_data_len);
277
+
278
+ git__free(delta_data);
279
+
280
+ if (error < 0)
281
+ goto done;
282
+ }
283
+ }
284
+
285
+ if (delta.size && delta.size < deflate.size) {
286
+ *out_type = GIT_DIFF_BINARY_DELTA;
287
+ *out_datalen = delta.size;
288
+ *out_data = git_buf_detach(&delta);
289
+ *out_inflatedlen = delta_data_len;
290
+ } else {
291
+ *out_type = GIT_DIFF_BINARY_LITERAL;
292
+ *out_datalen = deflate.size;
293
+ *out_data = git_buf_detach(&deflate);
294
+ *out_inflatedlen = b_datalen;
295
+ }
296
+
297
+ done:
298
+ git_buf_free(&deflate);
299
+ git_buf_free(&delta);
300
+
301
+ return error;
302
+ }
303
+
304
+ static int diff_binary(git_diff_output *output, git_patch *patch)
305
+ {
306
+ git_diff_binary binary = {{0}};
307
+ const char *old_data = patch->ofile.map.data;
308
+ const char *new_data = patch->nfile.map.data;
309
+ size_t old_len = patch->ofile.map.len,
310
+ new_len = patch->nfile.map.len;
311
+ int error;
312
+
313
+ /* Create the old->new delta (as the "new" side of the patch),
314
+ * and the new->old delta (as the "old" side)
315
+ */
316
+ if ((error = create_binary(&binary.old_file.type,
317
+ (char **)&binary.old_file.data,
318
+ &binary.old_file.datalen,
319
+ &binary.old_file.inflatedlen,
320
+ new_data, new_len, old_data, old_len)) < 0 ||
321
+ (error = create_binary(&binary.new_file.type,
322
+ (char **)&binary.new_file.data,
323
+ &binary.new_file.datalen,
324
+ &binary.new_file.inflatedlen,
325
+ old_data, old_len, new_data, new_len)) < 0)
326
+ return error;
327
+
328
+ error = giterr_set_after_callback_function(
329
+ output->binary_cb(patch->delta, &binary, output->payload),
330
+ "git_patch");
331
+
332
+ git__free((char *) binary.old_file.data);
333
+ git__free((char *) binary.new_file.data);
334
+
335
+ return error;
336
+ }
337
+
210
338
  static int diff_patch_generate(git_patch *patch, git_diff_output *output)
211
339
  {
212
340
  int error = 0;
@@ -214,8 +342,8 @@ static int diff_patch_generate(git_patch *patch, git_diff_output *output)
214
342
  if ((patch->flags & GIT_DIFF_PATCH_DIFFED) != 0)
215
343
  return 0;
216
344
 
217
- /* if we are not looking at the hunks and lines, don't do the diff */
218
- if (!output->hunk_cb && !output->data_cb)
345
+ /* if we are not looking at the binary or text data, don't do the diff */
346
+ if (!output->binary_cb && !output->hunk_cb && !output->data_cb)
219
347
  return 0;
220
348
 
221
349
  if ((patch->flags & GIT_DIFF_PATCH_LOADED) == 0 &&
@@ -225,10 +353,16 @@ static int diff_patch_generate(git_patch *patch, git_diff_output *output)
225
353
  if ((patch->flags & GIT_DIFF_PATCH_DIFFABLE) == 0)
226
354
  return 0;
227
355
 
228
- if (output->diff_cb != NULL &&
229
- (error = output->diff_cb(output, patch)) < 0)
230
- patch->flags |= GIT_DIFF_PATCH_DIFFED;
356
+ if ((patch->delta->flags & GIT_DIFF_FLAG_BINARY) != 0) {
357
+ if (output->binary_cb)
358
+ error = diff_binary(output, patch);
359
+ }
360
+ else {
361
+ if (output->diff_cb)
362
+ error = output->diff_cb(output, patch);
363
+ }
231
364
 
365
+ patch->flags |= GIT_DIFF_PATCH_DIFFED;
232
366
  return error;
233
367
  }
234
368
 
@@ -245,6 +379,12 @@ static void diff_patch_free(git_patch *patch)
245
379
 
246
380
  git_pool_clear(&patch->flattened);
247
381
 
382
+ git__free((char *)patch->diff_opts.old_prefix);
383
+ git__free((char *)patch->diff_opts.new_prefix);
384
+
385
+ git__free((char *)patch->binary.old_file.data);
386
+ git__free((char *)patch->binary.new_file.data);
387
+
248
388
  if (patch->flags & GIT_DIFF_PATCH_ALLOCATED)
249
389
  git__free(patch);
250
390
  }
@@ -260,6 +400,7 @@ static int diff_required(git_diff *diff, const char *action)
260
400
  int git_diff_foreach(
261
401
  git_diff *diff,
262
402
  git_diff_file_cb file_cb,
403
+ git_diff_binary_cb binary_cb,
263
404
  git_diff_hunk_cb hunk_cb,
264
405
  git_diff_line_cb data_cb,
265
406
  void *payload)
@@ -275,7 +416,7 @@ int git_diff_foreach(
275
416
  memset(&xo, 0, sizeof(xo));
276
417
  memset(&patch, 0, sizeof(patch));
277
418
  diff_output_init(
278
- &xo.output, &diff->opts, file_cb, hunk_cb, data_cb, payload);
419
+ &xo.output, &diff->opts, file_cb, binary_cb, hunk_cb, data_cb, payload);
279
420
  git_xdiff_init(&xo, &diff->opts);
280
421
 
281
422
  git_vector_foreach(&diff->deltas, idx, patch.delta) {
@@ -284,11 +425,15 @@ int git_diff_foreach(
284
425
  if (git_diff_delta__should_skip(&diff->opts, patch.delta))
285
426
  continue;
286
427
 
428
+ if (binary_cb || hunk_cb || data_cb) {
429
+ if ((error = diff_patch_init_from_diff(&patch, diff, idx)) != 0 ||
430
+ (error = diff_patch_load(&patch, &xo.output)) != 0)
431
+ return error;
432
+ }
433
+
287
434
  if ((error = diff_patch_invoke_file_callback(&patch, &xo.output)) == 0) {
288
- if (hunk_cb || data_cb) {
289
- if ((error = diff_patch_init_from_diff(&patch, diff, idx)) == 0)
435
+ if (binary_cb || hunk_cb || data_cb)
290
436
  error = diff_patch_generate(&patch, &xo.output);
291
- }
292
437
  }
293
438
 
294
439
  git_patch_free(&patch);
@@ -350,7 +495,8 @@ static int diff_patch_from_sources(
350
495
  git_diff_file *lfile = &pd->delta.old_file, *rfile = &pd->delta.new_file;
351
496
  git_diff_file_content *ldata = &pd->patch.ofile, *rdata = &pd->patch.nfile;
352
497
 
353
- GITERR_CHECK_VERSION(opts, GIT_DIFF_OPTIONS_VERSION, "git_diff_options");
498
+ if ((error = diff_patch_normalize_options(&pd->patch.diff_opts, opts)) < 0)
499
+ return error;
354
500
 
355
501
  if (opts && (opts->flags & GIT_DIFF_REVERSE) != 0) {
356
502
  void *tmp = lfile; lfile = rfile; rfile = tmp;
@@ -419,6 +565,7 @@ static int diff_from_sources(
419
565
  git_diff_file_content_src *newsrc,
420
566
  const git_diff_options *opts,
421
567
  git_diff_file_cb file_cb,
568
+ git_diff_binary_cb binary_cb,
422
569
  git_diff_hunk_cb hunk_cb,
423
570
  git_diff_line_cb data_cb,
424
571
  void *payload)
@@ -429,7 +576,7 @@ static int diff_from_sources(
429
576
 
430
577
  memset(&xo, 0, sizeof(xo));
431
578
  diff_output_init(
432
- &xo.output, opts, file_cb, hunk_cb, data_cb, payload);
579
+ &xo.output, opts, file_cb, binary_cb, hunk_cb, data_cb, payload);
433
580
  git_xdiff_init(&xo, opts);
434
581
 
435
582
  memset(&pd, 0, sizeof(pd));
@@ -477,6 +624,7 @@ int git_diff_blobs(
477
624
  const char *new_path,
478
625
  const git_diff_options *opts,
479
626
  git_diff_file_cb file_cb,
627
+ git_diff_binary_cb binary_cb,
480
628
  git_diff_hunk_cb hunk_cb,
481
629
  git_diff_line_cb data_cb,
482
630
  void *payload)
@@ -486,7 +634,7 @@ int git_diff_blobs(
486
634
  git_diff_file_content_src nsrc =
487
635
  GIT_DIFF_FILE_CONTENT_SRC__BLOB(new_blob, new_path);
488
636
  return diff_from_sources(
489
- &osrc, &nsrc, opts, file_cb, hunk_cb, data_cb, payload);
637
+ &osrc, &nsrc, opts, file_cb, binary_cb, hunk_cb, data_cb, payload);
490
638
  }
491
639
 
492
640
  int git_patch_from_blobs(
@@ -512,6 +660,7 @@ int git_diff_blob_to_buffer(
512
660
  const char *buf_path,
513
661
  const git_diff_options *opts,
514
662
  git_diff_file_cb file_cb,
663
+ git_diff_binary_cb binary_cb,
515
664
  git_diff_hunk_cb hunk_cb,
516
665
  git_diff_line_cb data_cb,
517
666
  void *payload)
@@ -521,7 +670,7 @@ int git_diff_blob_to_buffer(
521
670
  git_diff_file_content_src nsrc =
522
671
  GIT_DIFF_FILE_CONTENT_SRC__BUF(buf, buflen, buf_path);
523
672
  return diff_from_sources(
524
- &osrc, &nsrc, opts, file_cb, hunk_cb, data_cb, payload);
673
+ &osrc, &nsrc, opts, file_cb, binary_cb, hunk_cb, data_cb, payload);
525
674
  }
526
675
 
527
676
  int git_patch_from_blob_and_buffer(
@@ -549,6 +698,7 @@ int git_diff_buffers(
549
698
  const char *new_path,
550
699
  const git_diff_options *opts,
551
700
  git_diff_file_cb file_cb,
701
+ git_diff_binary_cb binary_cb,
552
702
  git_diff_hunk_cb hunk_cb,
553
703
  git_diff_line_cb data_cb,
554
704
  void *payload)
@@ -558,7 +708,7 @@ int git_diff_buffers(
558
708
  git_diff_file_content_src nsrc =
559
709
  GIT_DIFF_FILE_CONTENT_SRC__BUF(new_buf, new_len, new_path);
560
710
  return diff_from_sources(
561
- &osrc, &nsrc, opts, file_cb, hunk_cb, data_cb, payload);
711
+ &osrc, &nsrc, opts, file_cb, binary_cb, hunk_cb, data_cb, payload);
562
712
  }
563
713
 
564
714
  int git_patch_from_buffers(
@@ -812,6 +962,7 @@ void git_patch__new_data(
812
962
  int git_patch__invoke_callbacks(
813
963
  git_patch *patch,
814
964
  git_diff_file_cb file_cb,
965
+ git_diff_binary_cb binary_cb,
815
966
  git_diff_hunk_cb hunk_cb,
816
967
  git_diff_line_cb line_cb,
817
968
  void *payload)
@@ -822,6 +973,13 @@ int git_patch__invoke_callbacks(
822
973
  if (file_cb)
823
974
  error = file_cb(patch->delta, 0, payload);
824
975
 
976
+ if ((patch->delta->flags & GIT_DIFF_FLAG_BINARY) != 0) {
977
+ if (binary_cb)
978
+ error = binary_cb(patch->delta, &patch->binary, payload);
979
+
980
+ return error;
981
+ }
982
+
825
983
  if (!hunk_cb && !line_cb)
826
984
  return error;
827
985
 
@@ -855,6 +1013,36 @@ static int diff_patch_file_cb(
855
1013
  return 0;
856
1014
  }
857
1015
 
1016
+ static int diff_patch_binary_cb(
1017
+ const git_diff_delta *delta,
1018
+ const git_diff_binary *binary,
1019
+ void *payload)
1020
+ {
1021
+ git_patch *patch = payload;
1022
+
1023
+ GIT_UNUSED(delta);
1024
+
1025
+ memcpy(&patch->binary, binary, sizeof(git_diff_binary));
1026
+
1027
+ if (binary->old_file.data) {
1028
+ patch->binary.old_file.data = git__malloc(binary->old_file.datalen);
1029
+ GITERR_CHECK_ALLOC(patch->binary.old_file.data);
1030
+
1031
+ memcpy((char *)patch->binary.old_file.data,
1032
+ binary->old_file.data, binary->old_file.datalen);
1033
+ }
1034
+
1035
+ if (binary->new_file.data) {
1036
+ patch->binary.new_file.data = git__malloc(binary->new_file.datalen);
1037
+ GITERR_CHECK_ALLOC(patch->binary.new_file.data);
1038
+
1039
+ memcpy((char *)patch->binary.new_file.data,
1040
+ binary->new_file.data, binary->new_file.datalen);
1041
+ }
1042
+
1043
+ return 0;
1044
+ }
1045
+
858
1046
  static int diff_patch_hunk_cb(
859
1047
  const git_diff_delta *delta,
860
1048
  const git_diff_hunk *hunk_,
@@ -921,6 +1109,7 @@ static void diff_output_init(
921
1109
  git_diff_output *out,
922
1110
  const git_diff_options *opts,
923
1111
  git_diff_file_cb file_cb,
1112
+ git_diff_binary_cb binary_cb,
924
1113
  git_diff_hunk_cb hunk_cb,
925
1114
  git_diff_line_cb data_cb,
926
1115
  void *payload)
@@ -930,6 +1119,7 @@ static void diff_output_init(
930
1119
  memset(out, 0, sizeof(*out));
931
1120
 
932
1121
  out->file_cb = file_cb;
1122
+ out->binary_cb = binary_cb;
933
1123
  out->hunk_cb = hunk_cb;
934
1124
  out->data_cb = data_cb;
935
1125
  out->payload = payload;
@@ -938,6 +1128,11 @@ static void diff_output_init(
938
1128
  static void diff_output_to_patch(git_diff_output *out, git_patch *patch)
939
1129
  {
940
1130
  diff_output_init(
941
- out, NULL,
942
- diff_patch_file_cb, diff_patch_hunk_cb, diff_patch_line_cb, patch);
1131
+ out,
1132
+ NULL,
1133
+ diff_patch_file_cb,
1134
+ diff_patch_binary_cb,
1135
+ diff_patch_hunk_cb,
1136
+ diff_patch_line_cb,
1137
+ patch);
943
1138
  }