Skip to content

Commit db2a794

Browse files
committed
diff: parse patches with sha256
1 parent 7f70484 commit db2a794

File tree

24 files changed

+307
-139
lines changed

24 files changed

+307
-139
lines changed

examples/diff.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,9 +188,17 @@ static void compute_diff_no_index(git_diff **diff, struct diff_options *o) {
188188
check_lg2(
189189
git_patch_to_buf(&buf, patch),
190190
"patch to buf", NULL);
191+
192+
#ifdef GIT_EXPERIMENTAL_SHA256
193+
check_lg2(
194+
git_diff_from_buffer(diff, buf.ptr, buf.size, NULL),
195+
"diff from patch", NULL);
196+
#else
191197
check_lg2(
192198
git_diff_from_buffer(diff, buf.ptr, buf.size),
193199
"diff from patch", NULL);
200+
#endif
201+
194202
git_patch_free(patch);
195203
git_buf_dispose(&buf);
196204
free(file1_str);

include/git2/diff.h

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,22 @@ typedef struct {
421421
*/
422422
uint32_t interhunk_lines;
423423

424+
/**
425+
* The object ID type to emit in diffs; this is used by functions
426+
* that operate without a repository - namely `git_diff_buffers`,
427+
* or `git_diff_blobs` and `git_diff_blob_to_buffer` when one blob
428+
* is `NULL`.
429+
*
430+
* This may be omitted (set to `0`). If a repository is available,
431+
* the object ID format of the repository will be used. If no
432+
* repository is available then the default is `GIT_OID_SHA`.
433+
*
434+
* If this is specified and a repository is available, then the
435+
* specified `oid_type` must match the repository's object ID
436+
* format.
437+
*/
438+
git_oid_t oid_type;
439+
424440
/**
425441
* The abbreviation length to use when formatting object ids.
426442
* Defaults to the value of 'core.abbrev' from the config, or 7 if unset.
@@ -1153,9 +1169,8 @@ GIT_EXTERN(int) git_diff_to_buf(
11531169

11541170
/**@}*/
11551171

1156-
11571172
/*
1158-
* Misc
1173+
* Low-level file comparison, invoking callbacks per difference.
11591174
*/
11601175

11611176
/**
@@ -1271,6 +1286,25 @@ GIT_EXTERN(int) git_diff_buffers(
12711286
git_diff_line_cb line_cb,
12721287
void *payload);
12731288

1289+
/* Patch file parsing. */
1290+
1291+
/**
1292+
* Options for parsing a diff / patch file.
1293+
*/
1294+
typedef struct {
1295+
unsigned int version;
1296+
git_oid_t oid_type;
1297+
} git_diff_parse_options;
1298+
1299+
/* The current version of the diff parse options structure */
1300+
#define GIT_DIFF_PARSE_OPTIONS_VERSION 1
1301+
1302+
/* Stack initializer for diff parse options. Alternatively use
1303+
* `git_diff_parse_options_init` programmatic initialization.
1304+
*/
1305+
#define GIT_DIFF_PARSE_OPTIONS_INIT \
1306+
{ GIT_DIFF_PARSE_OPTIONS_VERSION, GIT_OID_DEFAULT }
1307+
12741308
/**
12751309
* Read the contents of a git patch file into a `git_diff` object.
12761310
*
@@ -1293,7 +1327,11 @@ GIT_EXTERN(int) git_diff_buffers(
12931327
GIT_EXTERN(int) git_diff_from_buffer(
12941328
git_diff **out,
12951329
const char *content,
1296-
size_t content_len);
1330+
size_t content_len
1331+
#ifdef GIT_EXPERIMENTAL_SHA256
1332+
, git_diff_parse_options *opts
1333+
#endif
1334+
);
12971335

12981336
/**
12991337
* This is an opaque structure which is allocated by `git_diff_get_stats`.

src/libgit2/diff.c

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,10 @@
1919
#include "git2/email.h"
2020

2121
struct patch_id_args {
22+
git_diff *diff;
2223
git_hash_ctx ctx;
2324
git_oid result;
25+
git_oid_t oid_type;
2426
int first_file;
2527
};
2628

@@ -280,17 +282,19 @@ int git_diff_find_options_init(
280282
return 0;
281283
}
282284

283-
static int flush_hunk(git_oid *result, git_hash_ctx *ctx)
285+
static int flush_hunk(git_oid *result, struct patch_id_args *args)
284286
{
287+
git_hash_ctx *ctx = &args->ctx;
285288
git_oid hash;
286289
unsigned short carry = 0;
287-
int error, i;
290+
size_t i;
291+
int error;
288292

289293
if ((error = git_hash_final(hash.id, ctx)) < 0 ||
290294
(error = git_hash_init(ctx)) < 0)
291295
return error;
292296

293-
for (i = 0; i < GIT_OID_SHA1_SIZE; i++) {
297+
for (i = 0; i < git_oid_size(args->oid_type); i++) {
294298
carry += result->id[i] + hash.id[i];
295299
result->id[i] = (unsigned char)carry;
296300
carry >>= 8;
@@ -338,7 +342,7 @@ static int diff_patchid_print_callback_to_buf(
338342

339343
if (line->origin == GIT_DIFF_LINE_FILE_HDR &&
340344
!args->first_file &&
341-
(error = flush_hunk(&args->result, &args->ctx) < 0))
345+
(error = flush_hunk(&args->result, args) < 0))
342346
goto out;
343347

344348
if ((error = git_hash_update(&args->ctx, buf.ptr, buf.size)) < 0)
@@ -362,14 +366,19 @@ int git_diff_patchid_options_init(git_diff_patchid_options *opts, unsigned int v
362366
int git_diff_patchid(git_oid *out, git_diff *diff, git_diff_patchid_options *opts)
363367
{
364368
struct patch_id_args args;
369+
git_hash_algorithm_t algorithm;
365370
int error;
366371

367372
GIT_ERROR_CHECK_VERSION(
368373
opts, GIT_DIFF_PATCHID_OPTIONS_VERSION, "git_diff_patchid_options");
369374

375+
algorithm = git_oid_algorithm(diff->opts.oid_type);
376+
370377
memset(&args, 0, sizeof(args));
378+
args.diff = diff;
371379
args.first_file = 1;
372-
if ((error = git_hash_ctx_init(&args.ctx, GIT_HASH_ALGORITHM_SHA1)) < 0)
380+
args.oid_type = diff->opts.oid_type;
381+
if ((error = git_hash_ctx_init(&args.ctx, algorithm)) < 0)
373382
goto out;
374383

375384
if ((error = git_diff_print(diff,
@@ -378,11 +387,11 @@ int git_diff_patchid(git_oid *out, git_diff *diff, git_diff_patchid_options *opt
378387
&args)) < 0)
379388
goto out;
380389

381-
if ((error = (flush_hunk(&args.result, &args.ctx))) < 0)
390+
if ((error = (flush_hunk(&args.result, &args))) < 0)
382391
goto out;
383392

384393
#ifdef GIT_EXPERIMENTAL_SHA256
385-
args.result.type = GIT_OID_SHA1;
394+
args.result.type = diff->opts.oid_type;
386395
#endif
387396

388397
git_oid_cpy(out, &args.result);

src/libgit2/diff.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,15 @@ typedef enum {
3030
} git_diff_origin_t;
3131

3232
struct git_diff {
33-
git_refcount rc;
33+
git_refcount rc;
3434
git_repository *repo;
35-
git_attr_session attrsession;
35+
git_attr_session attrsession;
3636
git_diff_origin_t type;
37-
git_diff_options opts;
38-
git_vector deltas; /* vector of git_diff_delta */
37+
git_diff_options opts;
38+
git_vector deltas; /* vector of git_diff_delta */
3939
git_pool pool;
40-
git_iterator_t old_src;
41-
git_iterator_t new_src;
40+
git_iterator_t old_src;
41+
git_iterator_t new_src;
4242
git_diff_perfdata perf;
4343

4444
int (*strcomp)(const char *, const char *);

src/libgit2/diff_file.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ int git_diff_file_content__init_from_src(
144144

145145
if (!src->blob && !src->buf) {
146146
fc->flags |= GIT_DIFF_FLAG__NO_DATA;
147-
git_oid_clear(&fc->file->id, GIT_OID_SHA1);
147+
git_oid_clear(&fc->file->id, opts->oid_type);
148148
} else {
149149
fc->flags |= GIT_DIFF_FLAG__LOADED;
150150
fc->file->flags |= GIT_DIFF_FLAG_VALID_ID;
@@ -154,18 +154,18 @@ int git_diff_file_content__init_from_src(
154154
git_blob_dup((git_blob **)&fc->blob, (git_blob *) src->blob);
155155
fc->file->size = git_blob_rawsize(src->blob);
156156
git_oid_cpy(&fc->file->id, git_blob_id(src->blob));
157-
fc->file->id_abbrev = GIT_OID_SHA1_HEXSIZE;
157+
fc->file->id_abbrev = (uint16_t)git_oid_hexsize(repo->oid_type);
158158

159159
fc->map.len = (size_t)fc->file->size;
160160
fc->map.data = (char *)git_blob_rawcontent(src->blob);
161161

162162
fc->flags |= GIT_DIFF_FLAG__FREE_BLOB;
163163
} else {
164164
int error;
165-
if ((error = git_odb__hash(&fc->file->id, src->buf, src->buflen, GIT_OBJECT_BLOB, GIT_OID_SHA1)) < 0)
165+
if ((error = git_odb__hash(&fc->file->id, src->buf, src->buflen, GIT_OBJECT_BLOB, opts->oid_type)) < 0)
166166
return error;
167167
fc->file->size = src->buflen;
168-
fc->file->id_abbrev = GIT_OID_SHA1_HEXSIZE;
168+
fc->file->id_abbrev = (uint16_t)git_oid_hexsize(opts->oid_type);
169169

170170
fc->map.len = src->buflen;
171171
fc->map.data = (char *)src->buf;
@@ -178,7 +178,7 @@ int git_diff_file_content__init_from_src(
178178
static int diff_file_content_commit_to_str(
179179
git_diff_file_content *fc, bool check_status)
180180
{
181-
char oid[GIT_OID_SHA1_HEXSIZE+1];
181+
char oid[GIT_OID_MAX_HEXSIZE+1];
182182
git_str content = GIT_STR_INIT;
183183
const char *status = "";
184184

@@ -420,7 +420,7 @@ static int diff_file_content_load_workdir(
420420
if (!error && (fc->file->flags & GIT_DIFF_FLAG_VALID_ID) == 0) {
421421
error = git_odb__hash(
422422
&fc->file->id, fc->map.data, fc->map.len,
423-
GIT_OBJECT_BLOB, GIT_OID_SHA1);
423+
GIT_OBJECT_BLOB, diff_opts->oid_type);
424424
fc->file->flags |= GIT_DIFF_FLAG_VALID_ID;
425425
}
426426

0 commit comments

Comments
 (0)