rugged 0.25.0b5 → 0.25.0b6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. checksums.yaml +4 -4
  2. data/ext/rugged/rugged_patch.c +77 -17
  3. data/lib/rugged/version.rb +1 -1
  4. data/vendor/libgit2/CMakeLists.txt +8 -6
  5. data/vendor/libgit2/include/git2/checkout.h +7 -0
  6. data/vendor/libgit2/include/git2/common.h +1 -0
  7. data/vendor/libgit2/include/git2/diff.h +54 -7
  8. data/vendor/libgit2/include/git2/errors.h +2 -1
  9. data/vendor/libgit2/include/git2/index.h +25 -0
  10. data/vendor/libgit2/include/git2/pack.h +4 -4
  11. data/vendor/libgit2/include/git2/repository.h +20 -1
  12. data/vendor/libgit2/include/git2/submodule.h +11 -3
  13. data/vendor/libgit2/include/git2/sys/odb_backend.h +11 -0
  14. data/vendor/libgit2/src/apply.c +369 -0
  15. data/vendor/libgit2/src/apply.h +21 -0
  16. data/vendor/libgit2/src/array.h +0 -1
  17. data/vendor/libgit2/src/blame_git.c +18 -8
  18. data/vendor/libgit2/src/buffer.c +252 -20
  19. data/vendor/libgit2/src/buffer.h +8 -0
  20. data/vendor/libgit2/src/checkout.c +7 -1
  21. data/vendor/libgit2/src/clone.c +0 -8
  22. data/vendor/libgit2/src/common.h +1 -1
  23. data/vendor/libgit2/src/crlf.c +1 -0
  24. data/vendor/libgit2/src/delta.c +238 -62
  25. data/vendor/libgit2/src/delta.h +79 -58
  26. data/vendor/libgit2/src/diff.c +32 -1547
  27. data/vendor/libgit2/src/diff.h +12 -122
  28. data/vendor/libgit2/src/diff_driver.c +1 -2
  29. data/vendor/libgit2/src/diff_file.c +3 -0
  30. data/vendor/libgit2/src/diff_generate.c +1611 -0
  31. data/vendor/libgit2/src/diff_generate.h +123 -0
  32. data/vendor/libgit2/src/diff_parse.c +105 -0
  33. data/vendor/libgit2/src/diff_print.c +259 -142
  34. data/vendor/libgit2/src/diff_stats.c +3 -2
  35. data/vendor/libgit2/src/diff_tform.c +1 -0
  36. data/vendor/libgit2/src/diff_tform.h +22 -0
  37. data/vendor/libgit2/src/diff_xdiff.c +9 -9
  38. data/vendor/libgit2/src/diff_xdiff.h +5 -5
  39. data/vendor/libgit2/src/fileops.c +13 -0
  40. data/vendor/libgit2/src/fileops.h +6 -0
  41. data/vendor/libgit2/src/global.c +9 -8
  42. data/vendor/libgit2/src/ignore.c +45 -16
  43. data/vendor/libgit2/src/index.c +161 -47
  44. data/vendor/libgit2/src/index.h +2 -0
  45. data/vendor/libgit2/src/merge.c +2 -0
  46. data/vendor/libgit2/src/mwindow.c +8 -19
  47. data/vendor/libgit2/src/mwindow.h +1 -2
  48. data/vendor/libgit2/src/odb.c +46 -10
  49. data/vendor/libgit2/src/odb_loose.c +19 -1
  50. data/vendor/libgit2/src/odb_pack.c +27 -4
  51. data/vendor/libgit2/src/pack-objects.c +106 -77
  52. data/vendor/libgit2/src/pack-objects.h +13 -12
  53. data/vendor/libgit2/src/pack.c +4 -3
  54. data/vendor/libgit2/src/pack.h +2 -0
  55. data/vendor/libgit2/src/patch.c +207 -0
  56. data/vendor/libgit2/src/patch.h +66 -0
  57. data/vendor/libgit2/src/{diff_patch.c → patch_generate.c} +171 -359
  58. data/vendor/libgit2/src/patch_generate.h +66 -0
  59. data/vendor/libgit2/src/patch_parse.c +1121 -0
  60. data/vendor/libgit2/src/patch_parse.h +54 -0
  61. data/vendor/libgit2/src/path.c +19 -0
  62. data/vendor/libgit2/src/path.h +6 -0
  63. data/vendor/libgit2/src/pool.h +5 -0
  64. data/vendor/libgit2/src/remote.c +15 -80
  65. data/vendor/libgit2/src/repository.c +227 -39
  66. data/vendor/libgit2/src/settings.c +11 -5
  67. data/vendor/libgit2/src/stash.c +1 -0
  68. data/vendor/libgit2/src/status.c +1 -0
  69. data/vendor/libgit2/src/stransport_stream.c +14 -9
  70. data/vendor/libgit2/src/submodule.c +16 -4
  71. data/vendor/libgit2/src/sysdir.c +41 -47
  72. data/vendor/libgit2/src/sysdir.h +0 -5
  73. data/vendor/libgit2/src/thread-utils.h +5 -51
  74. data/vendor/libgit2/src/transport.c +3 -5
  75. data/vendor/libgit2/src/transports/http.c +2 -3
  76. data/vendor/libgit2/src/transports/smart_pkt.c +1 -0
  77. data/vendor/libgit2/src/transports/smart_protocol.c +11 -0
  78. data/vendor/libgit2/src/transports/winhttp.c +16 -2
  79. data/vendor/libgit2/src/unix/pthread.h +54 -0
  80. data/vendor/libgit2/src/util.c +23 -5
  81. data/vendor/libgit2/src/util.h +10 -0
  82. data/vendor/libgit2/src/varint.c +44 -0
  83. data/vendor/libgit2/src/varint.h +15 -0
  84. data/vendor/libgit2/src/vector.c +42 -0
  85. data/vendor/libgit2/src/vector.h +3 -0
  86. data/vendor/libgit2/src/win32/precompiled.h +1 -1
  87. data/vendor/libgit2/src/win32/{pthread.c → thread.c} +50 -80
  88. data/vendor/libgit2/src/win32/thread.h +62 -0
  89. data/vendor/libgit2/src/zstream.c +36 -7
  90. data/vendor/libgit2/src/zstream.h +8 -1
  91. metadata +20 -9
  92. data/vendor/libgit2/src/delta-apply.c +0 -166
  93. data/vendor/libgit2/src/delta-apply.h +0 -62
  94. data/vendor/libgit2/src/diff_patch.h +0 -83
  95. data/vendor/libgit2/src/win32/pthread.h +0 -92
@@ -0,0 +1,123 @@
1
+ /*
2
+ * Copyright (C) the libgit2 contributors. All rights reserved.
3
+ *
4
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
5
+ * a Linking Exception. For full terms see the included COPYING file.
6
+ */
7
+ #ifndef INCLUDE_diff_generate_h__
8
+ #define INCLUDE_diff_generate_h__
9
+
10
+ enum {
11
+ GIT_DIFFCAPS_HAS_SYMLINKS = (1 << 0), /* symlinks on platform? */
12
+ GIT_DIFFCAPS_IGNORE_STAT = (1 << 1), /* use stat? */
13
+ GIT_DIFFCAPS_TRUST_MODE_BITS = (1 << 2), /* use st_mode? */
14
+ GIT_DIFFCAPS_TRUST_CTIME = (1 << 3), /* use st_ctime? */
15
+ GIT_DIFFCAPS_USE_DEV = (1 << 4), /* use st_dev? */
16
+ };
17
+
18
+ #define DIFF_FLAGS_KNOWN_BINARY (GIT_DIFF_FLAG_BINARY|GIT_DIFF_FLAG_NOT_BINARY)
19
+ #define DIFF_FLAGS_NOT_BINARY (GIT_DIFF_FLAG_NOT_BINARY|GIT_DIFF_FLAG__NO_DATA)
20
+
21
+ enum {
22
+ GIT_DIFF_FLAG__FREE_PATH = (1 << 7), /* `path` is allocated memory */
23
+ GIT_DIFF_FLAG__FREE_DATA = (1 << 8), /* internal file data is allocated */
24
+ GIT_DIFF_FLAG__UNMAP_DATA = (1 << 9), /* internal file data is mmap'ed */
25
+ GIT_DIFF_FLAG__NO_DATA = (1 << 10), /* file data should not be loaded */
26
+ GIT_DIFF_FLAG__FREE_BLOB = (1 << 11), /* release the blob when done */
27
+ GIT_DIFF_FLAG__LOADED = (1 << 12), /* file data has been loaded */
28
+
29
+ GIT_DIFF_FLAG__TO_DELETE = (1 << 16), /* delete entry during rename det. */
30
+ GIT_DIFF_FLAG__TO_SPLIT = (1 << 17), /* split entry during rename det. */
31
+ GIT_DIFF_FLAG__IS_RENAME_TARGET = (1 << 18),
32
+ GIT_DIFF_FLAG__IS_RENAME_SOURCE = (1 << 19),
33
+ GIT_DIFF_FLAG__HAS_SELF_SIMILARITY = (1 << 20),
34
+ };
35
+
36
+ #define GIT_DIFF_FLAG__CLEAR_INTERNAL(F) (F) = ((F) & 0x00FFFF)
37
+
38
+ #define GIT_DIFF__VERBOSE (1 << 30)
39
+
40
+ extern void git_diff_addref(git_diff *diff);
41
+
42
+ extern bool git_diff_delta__should_skip(
43
+ const git_diff_options *opts, const git_diff_delta *delta);
44
+
45
+ extern int git_diff__from_iterators(
46
+ git_diff **diff_ptr,
47
+ git_repository *repo,
48
+ git_iterator *old_iter,
49
+ git_iterator *new_iter,
50
+ const git_diff_options *opts);
51
+
52
+ extern int git_diff__commit(
53
+ git_diff **diff, git_repository *repo, const git_commit *commit, const git_diff_options *opts);
54
+
55
+ extern int git_diff__paired_foreach(
56
+ git_diff *idx2head,
57
+ git_diff *wd2idx,
58
+ int (*cb)(git_diff_delta *i2h, git_diff_delta *w2i, void *payload),
59
+ void *payload);
60
+
61
+ /* Merge two `git_diff`s according to the callback given by `cb`. */
62
+
63
+ typedef git_diff_delta *(*git_diff__merge_cb)(
64
+ const git_diff_delta *left,
65
+ const git_diff_delta *right,
66
+ git_pool *pool);
67
+
68
+ extern int git_diff__merge(
69
+ git_diff *onto, const git_diff *from, git_diff__merge_cb cb);
70
+
71
+ extern git_diff_delta *git_diff__merge_like_cgit(
72
+ const git_diff_delta *a,
73
+ const git_diff_delta *b,
74
+ git_pool *pool);
75
+
76
+ /* Duplicate a `git_diff_delta` out of the `git_pool` */
77
+ extern git_diff_delta *git_diff__delta_dup(
78
+ const git_diff_delta *d, git_pool *pool);
79
+
80
+ extern int git_diff__oid_for_file(
81
+ git_oid *out,
82
+ git_diff *diff,
83
+ const char *path,
84
+ uint16_t mode,
85
+ git_off_t size);
86
+
87
+ extern int git_diff__oid_for_entry(
88
+ git_oid *out,
89
+ git_diff *diff,
90
+ const git_index_entry *src,
91
+ uint16_t mode,
92
+ const git_oid *update_match);
93
+
94
+ /*
95
+ * Sometimes a git_diff_file will have a zero size; this attempts to
96
+ * fill in the size without loading the blob if possible. If that is
97
+ * not possible, then it will return the git_odb_object that had to be
98
+ * loaded and the caller can use it or dispose of it as needed.
99
+ */
100
+ GIT_INLINE(int) git_diff_file__resolve_zero_size(
101
+ git_diff_file *file, git_odb_object **odb_obj, git_repository *repo)
102
+ {
103
+ int error;
104
+ git_odb *odb;
105
+ size_t len;
106
+ git_otype type;
107
+
108
+ if ((error = git_repository_odb(&odb, repo)) < 0)
109
+ return error;
110
+
111
+ error = git_odb__read_header_or_object(
112
+ odb_obj, &len, &type, odb, &file->id);
113
+
114
+ git_odb_free(odb);
115
+
116
+ if (!error)
117
+ file->size = (git_off_t)len;
118
+
119
+ return error;
120
+ }
121
+
122
+ #endif
123
+
@@ -0,0 +1,105 @@
1
+ /*
2
+ * Copyright (C) the libgit2 contributors. All rights reserved.
3
+ *
4
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
5
+ * a Linking Exception. For full terms see the included COPYING file.
6
+ */
7
+ #include "common.h"
8
+ #include "diff.h"
9
+ #include "patch.h"
10
+ #include "patch_parse.h"
11
+
12
+ typedef struct {
13
+ struct git_diff base;
14
+
15
+ git_vector patches;
16
+ } git_diff_parsed;
17
+
18
+ static void diff_parsed_free(git_diff *d)
19
+ {
20
+ git_diff_parsed *diff = (git_diff_parsed *)d;
21
+ git_patch *patch;
22
+ size_t i;
23
+
24
+ git_vector_foreach(&diff->patches, i, patch)
25
+ git_patch_free(patch);
26
+
27
+ git_vector_free(&diff->patches);
28
+
29
+ git_vector_free(&diff->base.deltas);
30
+ git_pool_clear(&diff->base.pool);
31
+
32
+ git__memzero(diff, sizeof(*diff));
33
+ git__free(diff);
34
+ }
35
+
36
+ static git_diff_parsed *diff_parsed_alloc(void)
37
+ {
38
+ git_diff_parsed *diff;
39
+
40
+ if ((diff = git__calloc(1, sizeof(git_diff_parsed))) == NULL)
41
+ return NULL;
42
+
43
+ GIT_REFCOUNT_INC(diff);
44
+ diff->base.type = GIT_DIFF_TYPE_PARSED;
45
+ diff->base.opts.flags &= ~GIT_DIFF_IGNORE_CASE;
46
+ diff->base.strcomp = git__strcmp;
47
+ diff->base.strncomp = git__strncmp;
48
+ diff->base.pfxcomp = git__prefixcmp;
49
+ diff->base.entrycomp = git_diff__entry_cmp;
50
+ diff->base.free_fn = diff_parsed_free;
51
+
52
+ git_pool_init(&diff->base.pool, 1);
53
+
54
+ if (git_vector_init(&diff->patches, 0, NULL) < 0 ||
55
+ git_vector_init(&diff->base.deltas, 0, git_diff_delta__cmp) < 0) {
56
+ git_diff_free(&diff->base);
57
+ return NULL;
58
+ }
59
+
60
+ git_vector_set_cmp(&diff->base.deltas, git_diff_delta__cmp);
61
+
62
+ return diff;
63
+ }
64
+
65
+ int git_diff_from_buffer(
66
+ git_diff **out,
67
+ const char *content,
68
+ size_t content_len)
69
+ {
70
+ git_diff_parsed *diff;
71
+ git_patch *patch;
72
+ git_patch_parse_ctx *ctx = NULL;
73
+ int error = 0;
74
+
75
+ *out = NULL;
76
+
77
+ diff = diff_parsed_alloc();
78
+ GITERR_CHECK_ALLOC(diff);
79
+
80
+ ctx = git_patch_parse_ctx_init(content, content_len, NULL);
81
+ GITERR_CHECK_ALLOC(ctx);
82
+
83
+ while (ctx->remain_len) {
84
+ if ((error = git_patch_parse(&patch, ctx)) < 0)
85
+ break;
86
+
87
+ git_vector_insert(&diff->patches, patch);
88
+ git_vector_insert(&diff->base.deltas, patch->delta);
89
+ }
90
+
91
+ if (error == GIT_ENOTFOUND && git_vector_length(&diff->patches) > 0) {
92
+ giterr_clear();
93
+ error = 0;
94
+ }
95
+
96
+ git_patch_parse_ctx_free(ctx);
97
+
98
+ if (error < 0)
99
+ git_diff_free(&diff->base);
100
+ else
101
+ *out = &diff->base;
102
+
103
+ return error;
104
+ }
105
+
@@ -6,7 +6,8 @@
6
6
  */
7
7
  #include "common.h"
8
8
  #include "diff.h"
9
- #include "diff_patch.h"
9
+ #include "diff_file.h"
10
+ #include "patch_generate.h"
10
11
  #include "fileops.h"
11
12
  #include "zstream.h"
12
13
  #include "blob.h"
@@ -14,19 +15,19 @@
14
15
  #include "git2/sys/diff.h"
15
16
 
16
17
  typedef struct {
17
- git_diff *diff;
18
18
  git_diff_format_t format;
19
19
  git_diff_line_cb print_cb;
20
20
  void *payload;
21
+
21
22
  git_buf *buf;
22
- uint32_t flags;
23
- int oid_strlen;
24
23
  git_diff_line line;
25
- unsigned int
26
- content_loaded : 1,
27
- content_allocated : 1;
28
- git_diff_file_content *ofile;
29
- git_diff_file_content *nfile;
24
+
25
+ const char *old_prefix;
26
+ const char *new_prefix;
27
+ uint32_t flags;
28
+ int id_strlen;
29
+
30
+ int (*strcomp)(const char *, const char *);
30
31
  } diff_print_info;
31
32
 
32
33
  static int diff_print_info_init__common(
@@ -42,17 +43,15 @@ static int diff_print_info_init__common(
42
43
  pi->payload = payload;
43
44
  pi->buf = out;
44
45
 
45
- if (!pi->oid_strlen) {
46
+ if (!pi->id_strlen) {
46
47
  if (!repo)
47
- pi->oid_strlen = GIT_ABBREV_DEFAULT;
48
- else if (git_repository__cvar(&pi->oid_strlen, repo, GIT_CVAR_ABBREV) < 0)
48
+ pi->id_strlen = GIT_ABBREV_DEFAULT;
49
+ else if (git_repository__cvar(&pi->id_strlen, repo, GIT_CVAR_ABBREV) < 0)
49
50
  return -1;
50
51
  }
51
52
 
52
- pi->oid_strlen += 1; /* for NUL byte */
53
-
54
- if (pi->oid_strlen > GIT_OID_HEXSZ + 1)
55
- pi->oid_strlen = GIT_OID_HEXSZ + 1;
53
+ if (pi->id_strlen > GIT_OID_HEXSZ)
54
+ pi->id_strlen = GIT_OID_HEXSZ;
56
55
 
57
56
  memset(&pi->line, 0, sizeof(pi->line));
58
57
  pi->line.old_lineno = -1;
@@ -74,11 +73,13 @@ static int diff_print_info_init_fromdiff(
74
73
 
75
74
  memset(pi, 0, sizeof(diff_print_info));
76
75
 
77
- pi->diff = diff;
78
-
79
76
  if (diff) {
80
77
  pi->flags = diff->opts.flags;
81
- pi->oid_strlen = diff->opts.id_abbrev;
78
+ pi->id_strlen = diff->opts.id_abbrev;
79
+ pi->old_prefix = diff->opts.old_prefix;
80
+ pi->new_prefix = diff->opts.new_prefix;
81
+
82
+ pi->strcomp = diff->strcomp;
82
83
  }
83
84
 
84
85
  return diff_print_info_init__common(pi, out, repo, format, cb, payload);
@@ -92,24 +93,16 @@ static int diff_print_info_init_frompatch(
92
93
  git_diff_line_cb cb,
93
94
  void *payload)
94
95
  {
95
- git_repository *repo;
96
-
97
96
  assert(patch);
98
97
 
99
- repo = patch->diff ? patch->diff->repo : NULL;
100
-
101
98
  memset(pi, 0, sizeof(diff_print_info));
102
99
 
103
- pi->diff = patch->diff;
104
-
105
100
  pi->flags = patch->diff_opts.flags;
106
- pi->oid_strlen = patch->diff_opts.id_abbrev;
107
-
108
- pi->content_loaded = 1;
109
- pi->ofile = &patch->ofile;
110
- pi->nfile = &patch->nfile;
101
+ pi->id_strlen = patch->diff_opts.id_abbrev;
102
+ pi->old_prefix = patch->diff_opts.old_prefix;
103
+ pi->new_prefix = patch->diff_opts.new_prefix;
111
104
 
112
- return diff_print_info_init__common(pi, out, repo, format, cb, payload);
105
+ return diff_print_info_init__common(pi, out, patch->repo, format, cb, payload);
113
106
  }
114
107
 
115
108
  static char diff_pick_suffix(int mode)
@@ -173,8 +166,8 @@ static int diff_print_one_name_status(
173
166
  diff_print_info *pi = data;
174
167
  git_buf *out = pi->buf;
175
168
  char old_suffix, new_suffix, code = git_diff_status_char(delta->status);
176
- int (*strcomp)(const char *, const char *) =
177
- pi->diff ? pi->diff->strcomp : git__strcmp;
169
+ int(*strcomp)(const char *, const char *) = pi->strcomp ?
170
+ pi->strcomp : git__strcmp;
178
171
 
179
172
  GIT_UNUSED(progress);
180
173
 
@@ -213,6 +206,7 @@ static int diff_print_one_raw(
213
206
  {
214
207
  diff_print_info *pi = data;
215
208
  git_buf *out = pi->buf;
209
+ int id_abbrev;
216
210
  char code = git_diff_status_char(delta->status);
217
211
  char start_oid[GIT_OID_HEXSZ+1], end_oid[GIT_OID_HEXSZ+1];
218
212
 
@@ -223,11 +217,21 @@ static int diff_print_one_raw(
223
217
 
224
218
  git_buf_clear(out);
225
219
 
226
- git_oid_tostr(start_oid, pi->oid_strlen, &delta->old_file.id);
227
- git_oid_tostr(end_oid, pi->oid_strlen, &delta->new_file.id);
220
+ id_abbrev = delta->old_file.mode ? delta->old_file.id_abbrev :
221
+ delta->new_file.id_abbrev;
222
+
223
+ if (pi->id_strlen > id_abbrev) {
224
+ giterr_set(GITERR_PATCH,
225
+ "The patch input contains %d id characters (cannot print %d)",
226
+ id_abbrev, pi->id_strlen);
227
+ return -1;
228
+ }
229
+
230
+ git_oid_tostr(start_oid, pi->id_strlen + 1, &delta->old_file.id);
231
+ git_oid_tostr(end_oid, pi->id_strlen + 1, &delta->new_file.id);
228
232
 
229
233
  git_buf_printf(
230
- out, (pi->oid_strlen <= GIT_OID_HEXSZ) ?
234
+ out, (pi->id_strlen <= GIT_OID_HEXSZ) ?
231
235
  ":%06o %06o %s... %s... %c" : ":%06o %06o %s %s %c",
232
236
  delta->old_file.mode, delta->new_file.mode, start_oid, end_oid, code);
233
237
 
@@ -252,53 +256,140 @@ static int diff_print_one_raw(
252
256
  return pi->print_cb(delta, NULL, &pi->line, pi->payload);
253
257
  }
254
258
 
259
+ static int diff_print_modes(
260
+ git_buf *out, const git_diff_delta *delta)
261
+ {
262
+ git_buf_printf(out, "old mode %o\n", delta->old_file.mode);
263
+ git_buf_printf(out, "new mode %o\n", delta->new_file.mode);
264
+
265
+ return git_buf_oom(out) ? -1 : 0;
266
+ }
267
+
255
268
  static int diff_print_oid_range(
256
- git_buf *out, const git_diff_delta *delta, int oid_strlen)
269
+ git_buf *out, const git_diff_delta *delta, int id_strlen)
257
270
  {
258
271
  char start_oid[GIT_OID_HEXSZ+1], end_oid[GIT_OID_HEXSZ+1];
259
272
 
260
- git_oid_tostr(start_oid, oid_strlen, &delta->old_file.id);
261
- git_oid_tostr(end_oid, oid_strlen, &delta->new_file.id);
273
+ if (delta->old_file.mode &&
274
+ id_strlen > delta->old_file.id_abbrev) {
275
+ giterr_set(GITERR_PATCH,
276
+ "The patch input contains %d id characters (cannot print %d)",
277
+ delta->old_file.id_abbrev, id_strlen);
278
+ return -1;
279
+ }
280
+
281
+ if ((delta->new_file.mode &&
282
+ id_strlen > delta->new_file.id_abbrev)) {
283
+ giterr_set(GITERR_PATCH,
284
+ "The patch input contains %d id characters (cannot print %d)",
285
+ delta->new_file.id_abbrev, id_strlen);
286
+ return -1;
287
+ }
288
+
289
+ git_oid_tostr(start_oid, id_strlen + 1, &delta->old_file.id);
290
+ git_oid_tostr(end_oid, id_strlen + 1, &delta->new_file.id);
262
291
 
263
- /* TODO: Match git diff more closely */
264
292
  if (delta->old_file.mode == delta->new_file.mode) {
265
293
  git_buf_printf(out, "index %s..%s %o\n",
266
294
  start_oid, end_oid, delta->old_file.mode);
267
295
  } else {
268
- if (delta->old_file.mode == 0) {
296
+ if (delta->old_file.mode == 0)
269
297
  git_buf_printf(out, "new file mode %o\n", delta->new_file.mode);
270
- } else if (delta->new_file.mode == 0) {
298
+ else if (delta->new_file.mode == 0)
271
299
  git_buf_printf(out, "deleted file mode %o\n", delta->old_file.mode);
272
- } else {
273
- git_buf_printf(out, "old mode %o\n", delta->old_file.mode);
274
- git_buf_printf(out, "new mode %o\n", delta->new_file.mode);
275
- }
300
+ else
301
+ diff_print_modes(out, delta);
302
+
276
303
  git_buf_printf(out, "index %s..%s\n", start_oid, end_oid);
277
304
  }
278
305
 
279
306
  return git_buf_oom(out) ? -1 : 0;
280
307
  }
281
308
 
309
+ static int diff_delta_format_path(
310
+ git_buf *out, const char *prefix, const char *filename)
311
+ {
312
+ if (git_buf_joinpath(out, prefix, filename) < 0)
313
+ return -1;
314
+
315
+ return git_buf_quote(out);
316
+ }
317
+
282
318
  static int diff_delta_format_with_paths(
283
319
  git_buf *out,
284
320
  const git_diff_delta *delta,
285
- const char *oldpfx,
286
- const char *newpfx,
287
- const char *template)
321
+ const char *template,
322
+ const char *oldpath,
323
+ const char *newpath)
288
324
  {
289
- const char *oldpath = delta->old_file.path;
290
- const char *newpath = delta->new_file.path;
291
-
292
- if (git_oid_iszero(&delta->old_file.id)) {
293
- oldpfx = "";
325
+ if (git_oid_iszero(&delta->old_file.id))
294
326
  oldpath = "/dev/null";
295
- }
296
- if (git_oid_iszero(&delta->new_file.id)) {
297
- newpfx = "";
327
+
328
+ if (git_oid_iszero(&delta->new_file.id))
298
329
  newpath = "/dev/null";
330
+
331
+ return git_buf_printf(out, template, oldpath, newpath);
332
+ }
333
+
334
+ int diff_delta_format_similarity_header(
335
+ git_buf *out,
336
+ const git_diff_delta *delta)
337
+ {
338
+ git_buf old_path = GIT_BUF_INIT, new_path = GIT_BUF_INIT;
339
+ const char *type;
340
+ int error = 0;
341
+
342
+ if (delta->similarity > 100) {
343
+ giterr_set(GITERR_PATCH, "invalid similarity %d", delta->similarity);
344
+ error = -1;
345
+ goto done;
299
346
  }
300
347
 
301
- return git_buf_printf(out, template, oldpfx, oldpath, newpfx, newpath);
348
+ if (delta->status == GIT_DELTA_RENAMED)
349
+ type = "rename";
350
+ else if (delta->status == GIT_DELTA_COPIED)
351
+ type = "copy";
352
+ else
353
+ abort();
354
+
355
+ if ((error = git_buf_puts(&old_path, delta->old_file.path)) < 0 ||
356
+ (error = git_buf_puts(&new_path, delta->new_file.path)) < 0 ||
357
+ (error = git_buf_quote(&old_path)) < 0 ||
358
+ (error = git_buf_quote(&new_path)) < 0)
359
+ goto done;
360
+
361
+ git_buf_printf(out,
362
+ "similarity index %d%%\n"
363
+ "%s from %s\n"
364
+ "%s to %s\n",
365
+ delta->similarity,
366
+ type, old_path.ptr,
367
+ type, new_path.ptr);
368
+
369
+ if (git_buf_oom(out))
370
+ error = -1;
371
+
372
+ done:
373
+ git_buf_free(&old_path);
374
+ git_buf_free(&new_path);
375
+
376
+ return error;
377
+ }
378
+
379
+ static bool delta_is_unchanged(const git_diff_delta *delta)
380
+ {
381
+ if (git_oid_iszero(&delta->old_file.id) &&
382
+ git_oid_iszero(&delta->new_file.id))
383
+ return true;
384
+
385
+ if (delta->old_file.mode == GIT_FILEMODE_COMMIT ||
386
+ delta->new_file.mode == GIT_FILEMODE_COMMIT)
387
+ return false;
388
+
389
+ if (git_oid_equal(&delta->old_file.id, &delta->new_file.id))
390
+ return true;
391
+
392
+ return false;
302
393
  }
303
394
 
304
395
  int git_diff_delta__format_file_header(
@@ -306,27 +397,56 @@ int git_diff_delta__format_file_header(
306
397
  const git_diff_delta *delta,
307
398
  const char *oldpfx,
308
399
  const char *newpfx,
309
- int oid_strlen)
400
+ int id_strlen)
310
401
  {
402
+ git_buf old_path = GIT_BUF_INIT, new_path = GIT_BUF_INIT;
403
+ bool unchanged = delta_is_unchanged(delta);
404
+ int error = 0;
405
+
311
406
  if (!oldpfx)
312
407
  oldpfx = DIFF_OLD_PREFIX_DEFAULT;
313
408
  if (!newpfx)
314
409
  newpfx = DIFF_NEW_PREFIX_DEFAULT;
315
- if (!oid_strlen)
316
- oid_strlen = GIT_ABBREV_DEFAULT + 1;
410
+ if (!id_strlen)
411
+ id_strlen = GIT_ABBREV_DEFAULT;
412
+
413
+ if ((error = diff_delta_format_path(
414
+ &old_path, oldpfx, delta->old_file.path)) < 0 ||
415
+ (error = diff_delta_format_path(
416
+ &new_path, newpfx, delta->new_file.path)) < 0)
417
+ goto done;
317
418
 
318
419
  git_buf_clear(out);
319
420
 
320
- git_buf_printf(out, "diff --git %s%s %s%s\n",
321
- oldpfx, delta->old_file.path, newpfx, delta->new_file.path);
421
+ git_buf_printf(out, "diff --git %s %s\n",
422
+ old_path.ptr, new_path.ptr);
322
423
 
323
- GITERR_CHECK_ERROR(diff_print_oid_range(out, delta, oid_strlen));
424
+ if (delta->status == GIT_DELTA_RENAMED ||
425
+ (delta->status == GIT_DELTA_COPIED && unchanged)) {
426
+ if ((error = diff_delta_format_similarity_header(out, delta)) < 0)
427
+ goto done;
428
+ }
324
429
 
325
- if ((delta->flags & GIT_DIFF_FLAG_BINARY) == 0)
326
- diff_delta_format_with_paths(
327
- out, delta, oldpfx, newpfx, "--- %s%s\n+++ %s%s\n");
430
+ if (!unchanged) {
431
+ if ((error = diff_print_oid_range(out, delta, id_strlen)) < 0)
432
+ goto done;
328
433
 
329
- return git_buf_oom(out) ? -1 : 0;
434
+ if ((delta->flags & GIT_DIFF_FLAG_BINARY) == 0)
435
+ diff_delta_format_with_paths(out, delta,
436
+ "--- %s\n+++ %s\n", old_path.ptr, new_path.ptr);
437
+ }
438
+
439
+ if (unchanged && delta->old_file.mode != delta->new_file.mode)
440
+ diff_print_modes(out, delta);
441
+
442
+ if (git_buf_oom(out))
443
+ error = -1;
444
+
445
+ done:
446
+ git_buf_free(&old_path);
447
+ git_buf_free(&new_path);
448
+
449
+ return error;
330
450
  }
331
451
 
332
452
  static int format_binary(
@@ -367,37 +487,30 @@ static int format_binary(
367
487
  return 0;
368
488
  }
369
489
 
370
- static int diff_print_load_content(
371
- diff_print_info *pi,
372
- git_diff_delta *delta)
490
+ static int diff_print_patch_file_binary_noshow(
491
+ diff_print_info *pi, git_diff_delta *delta,
492
+ const char *old_pfx, const char *new_pfx)
373
493
  {
374
- git_diff_file_content *ofile, *nfile;
494
+ git_buf old_path = GIT_BUF_INIT, new_path = GIT_BUF_INIT;
375
495
  int error;
376
496
 
377
- assert(pi->diff);
378
-
379
- ofile = git__calloc(1, sizeof(git_diff_file_content));
380
- nfile = git__calloc(1, sizeof(git_diff_file_content));
497
+ if ((error = diff_delta_format_path(
498
+ &old_path, old_pfx, delta->old_file.path)) < 0 ||
499
+ (error = diff_delta_format_path(
500
+ &new_path, new_pfx, delta->new_file.path)) < 0)
501
+ goto done;
381
502
 
382
- GITERR_CHECK_ALLOC(ofile);
383
- GITERR_CHECK_ALLOC(nfile);
384
503
 
385
- if ((error = git_diff_file_content__init_from_diff(
386
- ofile, pi->diff, delta, true)) < 0 ||
387
- (error = git_diff_file_content__init_from_diff(
388
- nfile, pi->diff, delta, true)) < 0) {
389
-
390
- git__free(ofile);
391
- git__free(nfile);
392
- return error;
393
- }
504
+ pi->line.num_lines = 1;
505
+ error = diff_delta_format_with_paths(
506
+ pi->buf, delta, "Binary files %s and %s differ\n",
507
+ old_path.ptr, new_path.ptr);
394
508
 
395
- pi->content_loaded = 1;
396
- pi->content_allocated = 1;
397
- pi->ofile = ofile;
398
- pi->nfile = nfile;
509
+ done:
510
+ git_buf_free(&old_path);
511
+ git_buf_free(&new_path);
399
512
 
400
- return 0;
513
+ return error;
401
514
  }
402
515
 
403
516
  static int diff_print_patch_file_binary(
@@ -409,11 +522,11 @@ static int diff_print_patch_file_binary(
409
522
  int error;
410
523
 
411
524
  if ((pi->flags & GIT_DIFF_SHOW_BINARY) == 0)
412
- goto noshow;
525
+ return diff_print_patch_file_binary_noshow(
526
+ pi, delta, old_pfx, new_pfx);
413
527
 
414
- if (!pi->content_loaded &&
415
- (error = diff_print_load_content(pi, delta)) < 0)
416
- return error;
528
+ if (binary->new_file.datalen == 0 && binary->old_file.datalen == 0)
529
+ return 0;
417
530
 
418
531
  pre_binary_size = pi->buf->size;
419
532
  git_buf_printf(pi->buf, "GIT binary patch\n");
@@ -427,18 +540,14 @@ static int diff_print_patch_file_binary(
427
540
  if (error == GIT_EBUFS) {
428
541
  giterr_clear();
429
542
  git_buf_truncate(pi->buf, pre_binary_size);
430
- goto noshow;
543
+
544
+ return diff_print_patch_file_binary_noshow(
545
+ pi, delta, old_pfx, new_pfx);
431
546
  }
432
547
  }
433
548
 
434
549
  pi->line.num_lines++;
435
550
  return error;
436
-
437
- noshow:
438
- pi->line.num_lines = 1;
439
- return diff_delta_format_with_paths(
440
- pi->buf, delta, old_pfx, new_pfx,
441
- "Binary files %s%s and %s%s differ\n");
442
551
  }
443
552
 
444
553
  static int diff_print_patch_file(
@@ -447,15 +556,15 @@ static int diff_print_patch_file(
447
556
  int error;
448
557
  diff_print_info *pi = data;
449
558
  const char *oldpfx =
450
- pi->diff ? pi->diff->opts.old_prefix : DIFF_OLD_PREFIX_DEFAULT;
559
+ pi->old_prefix ? pi->old_prefix : DIFF_OLD_PREFIX_DEFAULT;
451
560
  const char *newpfx =
452
- pi->diff ? pi->diff->opts.new_prefix : DIFF_NEW_PREFIX_DEFAULT;
561
+ pi->new_prefix ? pi->new_prefix : DIFF_NEW_PREFIX_DEFAULT;
453
562
 
454
563
  bool binary = (delta->flags & GIT_DIFF_FLAG_BINARY) ||
455
564
  (pi->flags & GIT_DIFF_FORCE_BINARY);
456
565
  bool show_binary = !!(pi->flags & GIT_DIFF_SHOW_BINARY);
457
- int oid_strlen = binary && show_binary ?
458
- GIT_OID_HEXSZ + 1 : pi->oid_strlen;
566
+ int id_strlen = binary && show_binary ?
567
+ GIT_OID_HEXSZ : pi->id_strlen;
459
568
 
460
569
  GIT_UNUSED(progress);
461
570
 
@@ -468,7 +577,7 @@ static int diff_print_patch_file(
468
577
  return 0;
469
578
 
470
579
  if ((error = git_diff_delta__format_file_header(
471
- pi->buf, delta, oldpfx, newpfx, oid_strlen)) < 0)
580
+ pi->buf, delta, oldpfx, newpfx, id_strlen)) < 0)
472
581
  return error;
473
582
 
474
583
  pi->line.origin = GIT_DIFF_LINE_FILE_HDR;
@@ -485,9 +594,9 @@ static int diff_print_patch_binary(
485
594
  {
486
595
  diff_print_info *pi = data;
487
596
  const char *old_pfx =
488
- pi->diff ? pi->diff->opts.old_prefix : DIFF_OLD_PREFIX_DEFAULT;
597
+ pi->old_prefix ? pi->old_prefix : DIFF_OLD_PREFIX_DEFAULT;
489
598
  const char *new_pfx =
490
- pi->diff ? pi->diff->opts.new_prefix : DIFF_NEW_PREFIX_DEFAULT;
599
+ pi->new_prefix ? pi->new_prefix : DIFF_NEW_PREFIX_DEFAULT;
491
600
  int error;
492
601
 
493
602
  git_buf_clear(pi->buf);
@@ -582,43 +691,11 @@ int git_diff_print(
582
691
  giterr_set_after_callback_function(error, "git_diff_print");
583
692
  }
584
693
 
585
- git__free(pi.nfile);
586
- git__free(pi.ofile);
587
-
588
694
  git_buf_free(&buf);
589
695
 
590
696
  return error;
591
697
  }
592
698
 
593
- /* print a git_patch to an output callback */
594
- int git_patch_print(
595
- git_patch *patch,
596
- git_diff_line_cb print_cb,
597
- void *payload)
598
- {
599
- int error;
600
- git_buf temp = GIT_BUF_INIT;
601
- diff_print_info pi;
602
-
603
- assert(patch && print_cb);
604
-
605
- if (!(error = diff_print_info_init_frompatch(
606
- &pi, &temp, patch,
607
- GIT_DIFF_FORMAT_PATCH, print_cb, payload)))
608
- {
609
- error = git_patch__invoke_callbacks(
610
- patch, diff_print_patch_file, diff_print_patch_binary,
611
- diff_print_patch_hunk, diff_print_patch_line, &pi);
612
-
613
- if (error) /* make sure error message is set */
614
- giterr_set_after_callback_function(error, "git_patch_print");
615
- }
616
-
617
- git_buf_free(&temp);
618
-
619
- return error;
620
- }
621
-
622
699
  int git_diff_print_callback__to_buf(
623
700
  const git_diff_delta *delta,
624
701
  const git_diff_hunk *hunk,
@@ -659,6 +736,46 @@ int git_diff_print_callback__to_file_handle(
659
736
  return 0;
660
737
  }
661
738
 
739
+ /* print a git_diff to a git_buf */
740
+ int git_diff_to_buf(git_buf *out, git_diff *diff, git_diff_format_t format)
741
+ {
742
+ assert(out && diff);
743
+ git_buf_sanitize(out);
744
+ return git_diff_print(
745
+ diff, format, git_diff_print_callback__to_buf, out);
746
+ }
747
+
748
+ /* print a git_patch to an output callback */
749
+ int git_patch_print(
750
+ git_patch *patch,
751
+ git_diff_line_cb print_cb,
752
+ void *payload)
753
+ {
754
+ int error;
755
+ git_buf temp = GIT_BUF_INIT;
756
+ diff_print_info pi;
757
+
758
+ assert(patch && print_cb);
759
+
760
+ if (!(error = diff_print_info_init_frompatch(
761
+ &pi, &temp, patch,
762
+ GIT_DIFF_FORMAT_PATCH, print_cb, payload)))
763
+ {
764
+ error = git_patch__invoke_callbacks(
765
+ patch,
766
+ diff_print_patch_file, diff_print_patch_binary,
767
+ diff_print_patch_hunk, diff_print_patch_line,
768
+ &pi);
769
+
770
+ if (error) /* make sure error message is set */
771
+ giterr_set_after_callback_function(error, "git_patch_print");
772
+ }
773
+
774
+ git_buf_free(&temp);
775
+
776
+ return error;
777
+ }
778
+
662
779
  /* print a git_patch to a git_buf */
663
780
  int git_patch_to_buf(git_buf *out, git_patch *patch)
664
781
  {