Commit 82175084 by Edward Thomson Committed by Edward Thomson

Introduce git_patch_options, handle prefixes

Handle prefixes (in terms of number of path components) for patch
parsing.
parent 19e46645
...@@ -267,18 +267,31 @@ GIT_EXTERN(int) git_patch_to_buf( ...@@ -267,18 +267,31 @@ GIT_EXTERN(int) git_patch_to_buf(
git_buf *out, git_buf *out,
git_patch *patch); git_patch *patch);
/** Options for parsing patch files. */
typedef struct {
/**
* The length of the prefix (in path segments) for the filenames.
* This prefix will be removed when looking for files. The default is 1.
*/
uint32_t prefix_len;
} git_patch_options;
#define GIT_PATCH_OPTIONS_INIT { 1 }
/** /**
* Create a patch from the contents of a patch file. * Create a patch from the contents of a patch file.
* *
* @param out The patch to be created * @param out The patch to be created
* @param patchfile The contents of a patch file * @param patchfile The contents of a patch file
* @param patchfile_len The length of the patch file * @param patchfile_len The length of the patch file
* @param opts The git_patch_options
* @return 0 on success, <0 on failure. * @return 0 on success, <0 on failure.
*/ */
GIT_EXTERN(int) git_patch_from_patchfile( GIT_EXTERN(int) git_patch_from_patchfile(
git_patch **out, git_patch **out,
const char *patchfile, const char *patchfile,
size_t patchfile_len); size_t patchfile_len,
git_patch_options *opts);
GIT_END_DECL GIT_END_DECL
......
...@@ -5,9 +5,25 @@ ...@@ -5,9 +5,25 @@
#define parse_err(...) \ #define parse_err(...) \
( giterr_set(GITERR_PATCH, __VA_ARGS__), -1 ) ( giterr_set(GITERR_PATCH, __VA_ARGS__), -1 )
/* TODO: remove this, just use git_patch */
typedef struct { typedef struct {
git_patch base; git_patch base;
git_patch_options opts;
/* the paths from the `diff --git` header, these will be used if this is not
* a rename (and rename paths are specified) or if no `+++`/`---` line specify
* the paths.
*/
char *header_old_path, *header_new_path;
/* renamed paths are precise and are not prefixed */
char *rename_old_path, *rename_new_path;
/* the paths given in `---` and `+++` lines */
char *old_path, *new_path;
/* the prefixes from the old/new paths */
char *old_prefix, *new_prefix;
} git_patch_parsed; } git_patch_parsed;
typedef struct { typedef struct {
...@@ -19,10 +35,6 @@ typedef struct { ...@@ -19,10 +35,6 @@ typedef struct {
size_t line_num; size_t line_num;
size_t remain; size_t remain;
/* TODO: move this into the parse struct? its lifecycle is odd... */
char *header_new_path;
char *header_old_path;
} patch_parse_ctx; } patch_parse_ctx;
...@@ -139,13 +151,13 @@ static int parse_header_path(char **out, patch_parse_ctx *ctx) ...@@ -139,13 +151,13 @@ static int parse_header_path(char **out, patch_parse_ctx *ctx)
static int parse_header_git_oldpath( static int parse_header_git_oldpath(
git_patch_parsed *patch, patch_parse_ctx *ctx) git_patch_parsed *patch, patch_parse_ctx *ctx)
{ {
return parse_header_path((char **)&patch->base.delta->old_file.path, ctx); return parse_header_path(&patch->old_path, ctx);
} }
static int parse_header_git_newpath( static int parse_header_git_newpath(
git_patch_parsed *patch, patch_parse_ctx *ctx) git_patch_parsed *patch, patch_parse_ctx *ctx)
{ {
return parse_header_path((char **)&patch->base.delta->new_file.path, ctx); return parse_header_path(&patch->new_path, ctx);
} }
static int parse_header_mode(uint16_t *mode, patch_parse_ctx *ctx) static int parse_header_mode(uint16_t *mode, patch_parse_ctx *ctx)
...@@ -262,44 +274,17 @@ static int parse_header_git_newfilemode( ...@@ -262,44 +274,17 @@ static int parse_header_git_newfilemode(
static int parse_header_rename( static int parse_header_rename(
char **out, char **out,
char **header_path,
patch_parse_ctx *ctx) patch_parse_ctx *ctx)
{ {
git_buf path = GIT_BUF_INIT; git_buf path = GIT_BUF_INIT;
size_t header_path_len, prefix_len;
if (*header_path == NULL)
return parse_err("rename without proper git diff header at line %d",
ctx->line_num);
header_path_len = strlen(*header_path);
if (parse_header_path_buf(&path, ctx) < 0) if (parse_header_path_buf(&path, ctx) < 0)
return -1; return -1;
if (header_path_len < git_buf_len(&path)) /* Note: the `rename from` and `rename to` lines include the literal
return parse_err("rename path is invalid at line %d", ctx->line_num); * filename. They do *not* include the prefix. (Who needs consistency?)
*/
/* This sanity check exists because git core uses the data in the *out = git_buf_detach(&path);
* "rename from" / "rename to" lines, but it's formatted differently
* than the other paths and lacks the normal prefix. This irregularity
* causes us to ignore these paths (we always store the prefixed paths)
* but instead validate that they match the suffix of the paths we parsed
* since we would behave differently from git core if they ever differed.
* Instead, we raise an error, rather than parsing differently.
*/
prefix_len = header_path_len - path.size;
if (strncmp(*header_path + prefix_len, path.ptr, path.size) != 0 ||
(prefix_len > 0 && (*header_path)[prefix_len - 1] != '/'))
return parse_err("rename path does not match header at line %d",
ctx->line_num);
*out = *header_path;
*header_path = NULL;
git_buf_free(&path);
return 0; return 0;
} }
...@@ -307,22 +292,14 @@ static int parse_header_renamefrom( ...@@ -307,22 +292,14 @@ static int parse_header_renamefrom(
git_patch_parsed *patch, patch_parse_ctx *ctx) git_patch_parsed *patch, patch_parse_ctx *ctx)
{ {
patch->base.delta->status = GIT_DELTA_RENAMED; patch->base.delta->status = GIT_DELTA_RENAMED;
return parse_header_rename(&patch->rename_old_path, ctx);
return parse_header_rename(
(char **)&patch->base.delta->old_file.path,
&ctx->header_old_path,
ctx);
} }
static int parse_header_renameto( static int parse_header_renameto(
git_patch_parsed *patch, patch_parse_ctx *ctx) git_patch_parsed *patch, patch_parse_ctx *ctx)
{ {
patch->base.delta->status = GIT_DELTA_RENAMED; patch->base.delta->status = GIT_DELTA_RENAMED;
return parse_header_rename(&patch->rename_new_path, ctx);
return parse_header_rename(
(char **)&patch->base.delta->new_file.path,
&ctx->header_new_path,
ctx);
} }
static int parse_header_percent(uint16_t *out, patch_parse_ctx *ctx) static int parse_header_percent(uint16_t *out, patch_parse_ctx *ctx)
...@@ -404,12 +381,12 @@ static int parse_header_git( ...@@ -404,12 +381,12 @@ static int parse_header_git(
if (parse_advance_expected(ctx, "diff --git ", 11) < 0) if (parse_advance_expected(ctx, "diff --git ", 11) < 0)
return parse_err("corrupt git diff header at line %d", ctx->line_num); return parse_err("corrupt git diff header at line %d", ctx->line_num);
if (parse_header_path(&ctx->header_old_path, ctx) < 0) if (parse_header_path(&patch->header_old_path, ctx) < 0)
return parse_err("corrupt old path in git diff header at line %d", return parse_err("corrupt old path in git diff header at line %d",
ctx->line_num); ctx->line_num);
if (parse_advance_ws(ctx) < 0 || if (parse_advance_ws(ctx) < 0 ||
parse_header_path(&ctx->header_new_path, ctx) < 0) parse_header_path(&patch->header_new_path, ctx) < 0)
return parse_err("corrupt new path in git diff header at line %d", return parse_err("corrupt new path in git diff header at line %d",
ctx->line_num); ctx->line_num);
...@@ -628,49 +605,6 @@ done: ...@@ -628,49 +605,6 @@ done:
return error; return error;
} }
static int check_filenames(
git_patch_parsed *patch,
patch_parse_ctx *ctx)
{
/* For modechange only patches, it does not include filenames;
* instead we need to use the paths in the diff --git header.
*/
if (!patch->base.delta->old_file.path &&
!patch->base.delta->new_file.path) {
if (!ctx->header_old_path || !ctx->header_new_path)
return parse_err("git diff header lacks old / new paths");
patch->base.delta->old_file.path = ctx->header_old_path;
ctx->header_old_path = NULL;
patch->base.delta->new_file.path = ctx->header_new_path;
ctx->header_new_path = NULL;
}
/* For additions that have a `diff --git` header, set the old path
* to the path from the header, not `/dev/null`.
*/
if (patch->base.delta->status == GIT_DELTA_ADDED &&
ctx->header_old_path) {
git__free((char *)patch->base.delta->old_file.path);
patch->base.delta->old_file.path = ctx->header_old_path;
ctx->header_old_path = NULL;
}
/* For deletes, set the new path to the path from the
* `diff --git` header, not `/dev/null`.
*/
if (patch->base.delta->status == GIT_DELTA_DELETED &&
ctx->header_new_path) {
git__free((char *)patch->base.delta->new_file.path);
patch->base.delta->new_file.path = ctx->header_new_path;
ctx->header_new_path = NULL;
}
return 0;
}
static int parsed_patch_header( static int parsed_patch_header(
git_patch_parsed *patch, git_patch_parsed *patch,
patch_parse_ctx *ctx) patch_parse_ctx *ctx)
...@@ -707,11 +641,7 @@ static int parsed_patch_header( ...@@ -707,11 +641,7 @@ static int parsed_patch_header(
/* A proper git patch */ /* A proper git patch */
if (ctx->line_len >= 11 && memcmp(ctx->line, "diff --git ", 11) == 0) { if (ctx->line_len >= 11 && memcmp(ctx->line, "diff --git ", 11) == 0) {
if ((error = parse_header_git(patch, ctx)) < 0) error = parse_header_git(patch, ctx);
goto done;
error = check_filenames(patch, ctx);
goto done; goto done;
} }
...@@ -871,15 +801,114 @@ static int parsed_patch_body( ...@@ -871,15 +801,114 @@ static int parsed_patch_body(
return 0; return 0;
} }
static int check_patch(git_patch_parsed *patch) int check_header_names(
const char *one,
const char *two,
const char *old_or_new,
bool two_null)
{
if (!one || !two)
return 0;
if (two_null && strcmp(two, "/dev/null") != 0)
return parse_err("expected %s path of '/dev/null'", old_or_new);
else if (!two_null && strcmp(one, two) != 0)
return parse_err("mismatched %s path names", old_or_new);
return 0;
}
static int check_prefix(
char **out,
size_t *out_len,
git_patch_parsed *patch,
const char *path_start)
{
const char *path = path_start;
uint32_t remain = patch->opts.prefix_len;
*out = NULL;
*out_len = 0;
if (patch->opts.prefix_len == 0)
goto done;
/* leading slashes do not count as part of the prefix in git apply */
while (*path == '/')
path++;
while (*path && remain) {
if (*path == '/')
remain--;
path++;
}
if (remain || !*path)
return parse_err("header filename does not contain %d path components",
patch->opts.prefix_len);
done:
*out_len = (path - path_start);
*out = git__strndup(path_start, *out_len);
return (out == NULL) ? -1 : 0;
}
static int check_filenames(git_patch_parsed *patch)
{ {
const char *prefixed_new, *prefixed_old;
size_t old_prefixlen = 0, new_prefixlen = 0;
bool added = (patch->base.delta->status == GIT_DELTA_ADDED);
bool deleted = (patch->base.delta->status == GIT_DELTA_DELETED);
if (patch->old_path && !patch->new_path)
return parse_err("missing new path");
if (!patch->old_path && patch->new_path)
return parse_err("missing old path");
/* Ensure (non-renamed) paths match */
if (check_header_names(
patch->header_old_path, patch->old_path, "old", added) < 0 ||
check_header_names(
patch->header_new_path, patch->new_path, "new", deleted) < 0)
return -1;
prefixed_old = (!added && patch->old_path) ? patch->old_path :
patch->header_old_path;
prefixed_new = (!deleted && patch->new_path) ? patch->new_path :
patch->header_new_path;
if (check_prefix(
&patch->old_prefix, &old_prefixlen, patch, prefixed_old) < 0 ||
check_prefix(
&patch->new_prefix, &new_prefixlen, patch, prefixed_new) < 0)
return -1;
/* Prefer the rename filenames as they are unambiguous and unprefixed */
if (patch->rename_old_path)
patch->base.delta->old_file.path = patch->rename_old_path;
else
patch->base.delta->old_file.path = prefixed_old + old_prefixlen;
if (patch->rename_new_path)
patch->base.delta->new_file.path = patch->rename_new_path;
else
patch->base.delta->new_file.path = prefixed_new + new_prefixlen;
if (!patch->base.delta->old_file.path && if (!patch->base.delta->old_file.path &&
patch->base.delta->status != GIT_DELTA_ADDED) !patch->base.delta->new_file.path)
return parse_err("missing old file path"); return parse_err("git diff header lacks old / new paths");
if (!patch->base.delta->new_file.path && return 0;
patch->base.delta->status != GIT_DELTA_DELETED) }
return parse_err("missing new file path");
static int check_patch(git_patch_parsed *patch)
{
if (check_filenames(patch) < 0)
return -1;
if (patch->base.delta->old_file.path && if (patch->base.delta->old_file.path &&
patch->base.delta->status != GIT_DELTA_DELETED && patch->base.delta->status != GIT_DELTA_DELETED &&
...@@ -895,13 +924,32 @@ static int check_patch(git_patch_parsed *patch) ...@@ -895,13 +924,32 @@ static int check_patch(git_patch_parsed *patch)
return 0; return 0;
} }
static void patch_parsed__free(git_patch *p)
{
git_patch_parsed *patch = (git_patch_parsed *)p;
if (!patch)
return;
git__free(patch->old_prefix);
git__free(patch->new_prefix);
git__free(patch->header_old_path);
git__free(patch->header_new_path);
git__free(patch->rename_old_path);
git__free(patch->rename_new_path);
git__free(patch->old_path);
git__free(patch->new_path);
}
int git_patch_from_patchfile( int git_patch_from_patchfile(
git_patch **out, git_patch **out,
const char *content, const char *content,
size_t content_len) size_t content_len,
git_patch_options *opts)
{ {
patch_parse_ctx ctx = { 0 }; patch_parse_ctx ctx = { 0 };
git_patch_parsed *patch; git_patch_parsed *patch;
git_patch_options default_opts = GIT_PATCH_OPTIONS_INIT;
int error = 0; int error = 0;
*out = NULL; *out = NULL;
...@@ -909,10 +957,12 @@ int git_patch_from_patchfile( ...@@ -909,10 +957,12 @@ int git_patch_from_patchfile(
patch = git__calloc(1, sizeof(git_patch_parsed)); patch = git__calloc(1, sizeof(git_patch_parsed));
GITERR_CHECK_ALLOC(patch); GITERR_CHECK_ALLOC(patch);
/* TODO: allow callers to specify prefix depth (eg, `-p2`) */ if (opts)
patch->base.diff_opts.new_prefix = ""; memcpy(&patch->opts, opts, sizeof(git_patch_options));
patch->base.diff_opts.old_prefix = ""; else
patch->base.diff_opts.flags |= GIT_DIFF_SHOW_BINARY; memcpy(&patch->opts, &default_opts, sizeof(git_patch_options));
patch->base.free_fn = patch_parsed__free;
patch->base.delta = git__calloc(1, sizeof(git_diff_delta)); patch->base.delta = git__calloc(1, sizeof(git_diff_delta));
patch->base.delta->status = GIT_DELTA_MODIFIED; patch->base.delta->status = GIT_DELTA_MODIFIED;
...@@ -927,12 +977,13 @@ int git_patch_from_patchfile( ...@@ -927,12 +977,13 @@ int git_patch_from_patchfile(
(error = check_patch(patch)) < 0) (error = check_patch(patch)) < 0)
goto done; goto done;
patch->base.diff_opts.old_prefix = patch->old_prefix;
patch->base.diff_opts.new_prefix = patch->new_prefix;
patch->base.diff_opts.flags |= GIT_DIFF_SHOW_BINARY;
GIT_REFCOUNT_INC(patch); GIT_REFCOUNT_INC(patch);
*out = &patch->base; *out = &patch->base;
done: done:
git__free(ctx.header_old_path);
git__free(ctx.header_new_path);
return error; return error;
} }
...@@ -35,7 +35,7 @@ static int apply_patchfile( ...@@ -35,7 +35,7 @@ static int apply_patchfile(
unsigned int mode; unsigned int mode;
int error; int error;
cl_git_pass(git_patch_from_patchfile(&patch, patchfile, strlen(patchfile))); cl_git_pass(git_patch_from_patchfile(&patch, patchfile, strlen(patchfile), NULL));
error = git_apply__patch(&result, &filename, &mode, old, old_len, patch); error = git_apply__patch(&result, &filename, &mode, old, old_len, patch);
...@@ -91,7 +91,7 @@ void test_apply_fromfile__change_middle(void) ...@@ -91,7 +91,7 @@ void test_apply_fromfile__change_middle(void)
FILE_ORIGINAL, strlen(FILE_ORIGINAL), FILE_ORIGINAL, strlen(FILE_ORIGINAL),
FILE_CHANGE_MIDDLE, strlen(FILE_CHANGE_MIDDLE), FILE_CHANGE_MIDDLE, strlen(FILE_CHANGE_MIDDLE),
PATCH_ORIGINAL_TO_CHANGE_MIDDLE, NULL, PATCH_ORIGINAL_TO_CHANGE_MIDDLE, NULL,
"b/file.txt", 0100644)); "file.txt", 0100644));
} }
void test_apply_fromfile__change_middle_nocontext(void) void test_apply_fromfile__change_middle_nocontext(void)
...@@ -103,7 +103,7 @@ void test_apply_fromfile__change_middle_nocontext(void) ...@@ -103,7 +103,7 @@ void test_apply_fromfile__change_middle_nocontext(void)
FILE_ORIGINAL, strlen(FILE_ORIGINAL), FILE_ORIGINAL, strlen(FILE_ORIGINAL),
FILE_CHANGE_MIDDLE, strlen(FILE_CHANGE_MIDDLE), FILE_CHANGE_MIDDLE, strlen(FILE_CHANGE_MIDDLE),
PATCH_ORIGINAL_TO_CHANGE_MIDDLE_NOCONTEXT, PATCH_ORIGINAL_TO_CHANGE_MIDDLE_NOCONTEXT,
&diff_opts, "b/file.txt", 0100644)); &diff_opts, "file.txt", 0100644));
} }
...@@ -113,7 +113,7 @@ void test_apply_fromfile__change_firstline(void) ...@@ -113,7 +113,7 @@ void test_apply_fromfile__change_firstline(void)
FILE_ORIGINAL, strlen(FILE_ORIGINAL), FILE_ORIGINAL, strlen(FILE_ORIGINAL),
FILE_CHANGE_FIRSTLINE, strlen(FILE_CHANGE_FIRSTLINE), FILE_CHANGE_FIRSTLINE, strlen(FILE_CHANGE_FIRSTLINE),
PATCH_ORIGINAL_TO_CHANGE_FIRSTLINE, NULL, PATCH_ORIGINAL_TO_CHANGE_FIRSTLINE, NULL,
"b/file.txt", 0100644)); "file.txt", 0100644));
} }
void test_apply_fromfile__lastline(void) void test_apply_fromfile__lastline(void)
...@@ -122,7 +122,7 @@ void test_apply_fromfile__lastline(void) ...@@ -122,7 +122,7 @@ void test_apply_fromfile__lastline(void)
FILE_ORIGINAL, strlen(FILE_ORIGINAL), FILE_ORIGINAL, strlen(FILE_ORIGINAL),
FILE_CHANGE_LASTLINE, strlen(FILE_CHANGE_LASTLINE), FILE_CHANGE_LASTLINE, strlen(FILE_CHANGE_LASTLINE),
PATCH_ORIGINAL_TO_CHANGE_LASTLINE, NULL, PATCH_ORIGINAL_TO_CHANGE_LASTLINE, NULL,
"b/file.txt", 0100644)); "file.txt", 0100644));
} }
void test_apply_fromfile__prepend(void) void test_apply_fromfile__prepend(void)
...@@ -130,7 +130,7 @@ void test_apply_fromfile__prepend(void) ...@@ -130,7 +130,7 @@ void test_apply_fromfile__prepend(void)
cl_git_pass(validate_and_apply_patchfile( cl_git_pass(validate_and_apply_patchfile(
FILE_ORIGINAL, strlen(FILE_ORIGINAL), FILE_ORIGINAL, strlen(FILE_ORIGINAL),
FILE_PREPEND, strlen(FILE_PREPEND), FILE_PREPEND, strlen(FILE_PREPEND),
PATCH_ORIGINAL_TO_PREPEND, NULL, "b/file.txt", 0100644)); PATCH_ORIGINAL_TO_PREPEND, NULL, "file.txt", 0100644));
} }
void test_apply_fromfile__prepend_nocontext(void) void test_apply_fromfile__prepend_nocontext(void)
...@@ -142,7 +142,7 @@ void test_apply_fromfile__prepend_nocontext(void) ...@@ -142,7 +142,7 @@ void test_apply_fromfile__prepend_nocontext(void)
FILE_ORIGINAL, strlen(FILE_ORIGINAL), FILE_ORIGINAL, strlen(FILE_ORIGINAL),
FILE_PREPEND, strlen(FILE_PREPEND), FILE_PREPEND, strlen(FILE_PREPEND),
PATCH_ORIGINAL_TO_PREPEND_NOCONTEXT, &diff_opts, PATCH_ORIGINAL_TO_PREPEND_NOCONTEXT, &diff_opts,
"b/file.txt", 0100644)); "file.txt", 0100644));
} }
void test_apply_fromfile__append(void) void test_apply_fromfile__append(void)
...@@ -150,7 +150,7 @@ void test_apply_fromfile__append(void) ...@@ -150,7 +150,7 @@ void test_apply_fromfile__append(void)
cl_git_pass(validate_and_apply_patchfile( cl_git_pass(validate_and_apply_patchfile(
FILE_ORIGINAL, strlen(FILE_ORIGINAL), FILE_ORIGINAL, strlen(FILE_ORIGINAL),
FILE_APPEND, strlen(FILE_APPEND), FILE_APPEND, strlen(FILE_APPEND),
PATCH_ORIGINAL_TO_APPEND, NULL, "b/file.txt", 0100644)); PATCH_ORIGINAL_TO_APPEND, NULL, "file.txt", 0100644));
} }
void test_apply_fromfile__append_nocontext(void) void test_apply_fromfile__append_nocontext(void)
...@@ -162,7 +162,7 @@ void test_apply_fromfile__append_nocontext(void) ...@@ -162,7 +162,7 @@ void test_apply_fromfile__append_nocontext(void)
FILE_ORIGINAL, strlen(FILE_ORIGINAL), FILE_ORIGINAL, strlen(FILE_ORIGINAL),
FILE_APPEND, strlen(FILE_APPEND), FILE_APPEND, strlen(FILE_APPEND),
PATCH_ORIGINAL_TO_APPEND_NOCONTEXT, &diff_opts, PATCH_ORIGINAL_TO_APPEND_NOCONTEXT, &diff_opts,
"b/file.txt", 0100644)); "file.txt", 0100644));
} }
void test_apply_fromfile__prepend_and_append(void) void test_apply_fromfile__prepend_and_append(void)
...@@ -171,7 +171,7 @@ void test_apply_fromfile__prepend_and_append(void) ...@@ -171,7 +171,7 @@ void test_apply_fromfile__prepend_and_append(void)
FILE_ORIGINAL, strlen(FILE_ORIGINAL), FILE_ORIGINAL, strlen(FILE_ORIGINAL),
FILE_PREPEND_AND_APPEND, strlen(FILE_PREPEND_AND_APPEND), FILE_PREPEND_AND_APPEND, strlen(FILE_PREPEND_AND_APPEND),
PATCH_ORIGINAL_TO_PREPEND_AND_APPEND, NULL, PATCH_ORIGINAL_TO_PREPEND_AND_APPEND, NULL,
"b/file.txt", 0100644)); "file.txt", 0100644));
} }
void test_apply_fromfile__to_empty_file(void) void test_apply_fromfile__to_empty_file(void)
...@@ -179,7 +179,7 @@ void test_apply_fromfile__to_empty_file(void) ...@@ -179,7 +179,7 @@ void test_apply_fromfile__to_empty_file(void)
cl_git_pass(validate_and_apply_patchfile( cl_git_pass(validate_and_apply_patchfile(
FILE_ORIGINAL, strlen(FILE_ORIGINAL), FILE_ORIGINAL, strlen(FILE_ORIGINAL),
"", 0, "", 0,
PATCH_ORIGINAL_TO_EMPTY_FILE, NULL, "b/file.txt", 0100644)); PATCH_ORIGINAL_TO_EMPTY_FILE, NULL, "file.txt", 0100644));
} }
void test_apply_fromfile__from_empty_file(void) void test_apply_fromfile__from_empty_file(void)
...@@ -187,7 +187,7 @@ void test_apply_fromfile__from_empty_file(void) ...@@ -187,7 +187,7 @@ void test_apply_fromfile__from_empty_file(void)
cl_git_pass(validate_and_apply_patchfile( cl_git_pass(validate_and_apply_patchfile(
"", 0, "", 0,
FILE_ORIGINAL, strlen(FILE_ORIGINAL), FILE_ORIGINAL, strlen(FILE_ORIGINAL),
PATCH_EMPTY_FILE_TO_ORIGINAL, NULL, "b/file.txt", 0100644)); PATCH_EMPTY_FILE_TO_ORIGINAL, NULL, "file.txt", 0100644));
} }
void test_apply_fromfile__add(void) void test_apply_fromfile__add(void)
...@@ -195,7 +195,7 @@ void test_apply_fromfile__add(void) ...@@ -195,7 +195,7 @@ void test_apply_fromfile__add(void)
cl_git_pass(validate_and_apply_patchfile( cl_git_pass(validate_and_apply_patchfile(
NULL, 0, NULL, 0,
FILE_ORIGINAL, strlen(FILE_ORIGINAL), FILE_ORIGINAL, strlen(FILE_ORIGINAL),
PATCH_ADD_ORIGINAL, NULL, "b/file.txt", 0100644)); PATCH_ADD_ORIGINAL, NULL, "file.txt", 0100644));
} }
void test_apply_fromfile__delete(void) void test_apply_fromfile__delete(void)
...@@ -212,7 +212,7 @@ void test_apply_fromfile__rename_exact(void) ...@@ -212,7 +212,7 @@ void test_apply_fromfile__rename_exact(void)
cl_git_pass(apply_patchfile( cl_git_pass(apply_patchfile(
FILE_ORIGINAL, strlen(FILE_ORIGINAL), FILE_ORIGINAL, strlen(FILE_ORIGINAL),
FILE_ORIGINAL, strlen(FILE_ORIGINAL), FILE_ORIGINAL, strlen(FILE_ORIGINAL),
PATCH_RENAME_EXACT, "b/newfile.txt", 0100644)); PATCH_RENAME_EXACT, "newfile.txt", 0100644));
} }
void test_apply_fromfile__rename_similar(void) void test_apply_fromfile__rename_similar(void)
...@@ -220,7 +220,7 @@ void test_apply_fromfile__rename_similar(void) ...@@ -220,7 +220,7 @@ void test_apply_fromfile__rename_similar(void)
cl_git_pass(apply_patchfile( cl_git_pass(apply_patchfile(
FILE_ORIGINAL, strlen(FILE_ORIGINAL), FILE_ORIGINAL, strlen(FILE_ORIGINAL),
FILE_CHANGE_MIDDLE, strlen(FILE_CHANGE_MIDDLE), FILE_CHANGE_MIDDLE, strlen(FILE_CHANGE_MIDDLE),
PATCH_RENAME_SIMILAR, "b/newfile.txt", 0100644)); PATCH_RENAME_SIMILAR, "newfile.txt", 0100644));
} }
void test_apply_fromfile__rename_similar_quotedname(void) void test_apply_fromfile__rename_similar_quotedname(void)
...@@ -228,7 +228,7 @@ void test_apply_fromfile__rename_similar_quotedname(void) ...@@ -228,7 +228,7 @@ void test_apply_fromfile__rename_similar_quotedname(void)
cl_git_pass(apply_patchfile( cl_git_pass(apply_patchfile(
FILE_ORIGINAL, strlen(FILE_ORIGINAL), FILE_ORIGINAL, strlen(FILE_ORIGINAL),
FILE_CHANGE_MIDDLE, strlen(FILE_CHANGE_MIDDLE), FILE_CHANGE_MIDDLE, strlen(FILE_CHANGE_MIDDLE),
PATCH_RENAME_SIMILAR_QUOTEDNAME, "b/foo\"bar.txt", 0100644)); PATCH_RENAME_SIMILAR_QUOTEDNAME, "foo\"bar.txt", 0100644));
} }
void test_apply_fromfile__modechange(void) void test_apply_fromfile__modechange(void)
...@@ -236,7 +236,7 @@ void test_apply_fromfile__modechange(void) ...@@ -236,7 +236,7 @@ void test_apply_fromfile__modechange(void)
cl_git_pass(apply_patchfile( cl_git_pass(apply_patchfile(
FILE_ORIGINAL, strlen(FILE_ORIGINAL), FILE_ORIGINAL, strlen(FILE_ORIGINAL),
FILE_ORIGINAL, strlen(FILE_ORIGINAL), FILE_ORIGINAL, strlen(FILE_ORIGINAL),
PATCH_MODECHANGE_UNCHANGED, "b/file.txt", 0100755)); PATCH_MODECHANGE_UNCHANGED, "file.txt", 0100755));
} }
void test_apply_fromfile__modechange_with_modification(void) void test_apply_fromfile__modechange_with_modification(void)
...@@ -244,7 +244,7 @@ void test_apply_fromfile__modechange_with_modification(void) ...@@ -244,7 +244,7 @@ void test_apply_fromfile__modechange_with_modification(void)
cl_git_pass(apply_patchfile( cl_git_pass(apply_patchfile(
FILE_ORIGINAL, strlen(FILE_ORIGINAL), FILE_ORIGINAL, strlen(FILE_ORIGINAL),
FILE_CHANGE_MIDDLE, strlen(FILE_CHANGE_MIDDLE), FILE_CHANGE_MIDDLE, strlen(FILE_CHANGE_MIDDLE),
PATCH_MODECHANGE_MODIFIED, "b/file.txt", 0100755)); PATCH_MODECHANGE_MODIFIED, "file.txt", 0100755));
} }
void test_apply_fromfile__noisy(void) void test_apply_fromfile__noisy(void)
...@@ -252,7 +252,7 @@ void test_apply_fromfile__noisy(void) ...@@ -252,7 +252,7 @@ void test_apply_fromfile__noisy(void)
cl_git_pass(apply_patchfile( cl_git_pass(apply_patchfile(
FILE_ORIGINAL, strlen(FILE_ORIGINAL), FILE_ORIGINAL, strlen(FILE_ORIGINAL),
FILE_CHANGE_MIDDLE, strlen(FILE_CHANGE_MIDDLE), FILE_CHANGE_MIDDLE, strlen(FILE_CHANGE_MIDDLE),
PATCH_NOISY, "b/file.txt", 0100644)); PATCH_NOISY, "file.txt", 0100644));
} }
void test_apply_fromfile__noisy_nocontext(void) void test_apply_fromfile__noisy_nocontext(void)
...@@ -260,35 +260,35 @@ void test_apply_fromfile__noisy_nocontext(void) ...@@ -260,35 +260,35 @@ void test_apply_fromfile__noisy_nocontext(void)
cl_git_pass(apply_patchfile( cl_git_pass(apply_patchfile(
FILE_ORIGINAL, strlen(FILE_ORIGINAL), FILE_ORIGINAL, strlen(FILE_ORIGINAL),
FILE_CHANGE_MIDDLE, strlen(FILE_CHANGE_MIDDLE), FILE_CHANGE_MIDDLE, strlen(FILE_CHANGE_MIDDLE),
PATCH_NOISY_NOCONTEXT, "b/file.txt", 0100644)); PATCH_NOISY_NOCONTEXT, "file.txt", 0100644));
} }
void test_apply_fromfile__fail_truncated_1(void) void test_apply_fromfile__fail_truncated_1(void)
{ {
git_patch *patch; git_patch *patch;
cl_git_fail(git_patch_from_patchfile(&patch, PATCH_TRUNCATED_1, cl_git_fail(git_patch_from_patchfile(&patch, PATCH_TRUNCATED_1,
strlen(PATCH_TRUNCATED_1))); strlen(PATCH_TRUNCATED_1), NULL));
} }
void test_apply_fromfile__fail_truncated_2(void) void test_apply_fromfile__fail_truncated_2(void)
{ {
git_patch *patch; git_patch *patch;
cl_git_fail(git_patch_from_patchfile(&patch, PATCH_TRUNCATED_2, cl_git_fail(git_patch_from_patchfile(&patch, PATCH_TRUNCATED_2,
strlen(PATCH_TRUNCATED_2))); strlen(PATCH_TRUNCATED_2), NULL));
} }
void test_apply_fromfile__fail_truncated_3(void) void test_apply_fromfile__fail_truncated_3(void)
{ {
git_patch *patch; git_patch *patch;
cl_git_fail(git_patch_from_patchfile(&patch, PATCH_TRUNCATED_3, cl_git_fail(git_patch_from_patchfile(&patch, PATCH_TRUNCATED_3,
strlen(PATCH_TRUNCATED_3))); strlen(PATCH_TRUNCATED_3), NULL));
} }
void test_apply_fromfile__fail_corrupt_githeader(void) void test_apply_fromfile__fail_corrupt_githeader(void)
{ {
git_patch *patch; git_patch *patch;
cl_git_fail(git_patch_from_patchfile(&patch, PATCH_CORRUPT_GIT_HEADER, cl_git_fail(git_patch_from_patchfile(&patch, PATCH_CORRUPT_GIT_HEADER,
strlen(PATCH_CORRUPT_GIT_HEADER))); strlen(PATCH_CORRUPT_GIT_HEADER), NULL));
} }
void test_apply_fromfile__empty_context(void) void test_apply_fromfile__empty_context(void)
...@@ -297,7 +297,7 @@ void test_apply_fromfile__empty_context(void) ...@@ -297,7 +297,7 @@ void test_apply_fromfile__empty_context(void)
FILE_EMPTY_CONTEXT_ORIGINAL, strlen(FILE_EMPTY_CONTEXT_ORIGINAL), FILE_EMPTY_CONTEXT_ORIGINAL, strlen(FILE_EMPTY_CONTEXT_ORIGINAL),
FILE_EMPTY_CONTEXT_MODIFIED, strlen(FILE_EMPTY_CONTEXT_MODIFIED), FILE_EMPTY_CONTEXT_MODIFIED, strlen(FILE_EMPTY_CONTEXT_MODIFIED),
PATCH_EMPTY_CONTEXT, PATCH_EMPTY_CONTEXT,
"b/file.txt", 0100644)); "file.txt", 0100644));
} }
void test_apply_fromfile__append_no_nl(void) void test_apply_fromfile__append_no_nl(void)
...@@ -305,7 +305,7 @@ void test_apply_fromfile__append_no_nl(void) ...@@ -305,7 +305,7 @@ void test_apply_fromfile__append_no_nl(void)
cl_git_pass(validate_and_apply_patchfile( cl_git_pass(validate_and_apply_patchfile(
FILE_ORIGINAL, strlen(FILE_ORIGINAL), FILE_ORIGINAL, strlen(FILE_ORIGINAL),
FILE_APPEND_NO_NL, strlen(FILE_APPEND_NO_NL), FILE_APPEND_NO_NL, strlen(FILE_APPEND_NO_NL),
PATCH_APPEND_NO_NL, NULL, "b/file.txt", 0100644)); PATCH_APPEND_NO_NL, NULL, "file.txt", 0100644));
} }
void test_apply_fromfile__fail_missing_new_file(void) void test_apply_fromfile__fail_missing_new_file(void)
...@@ -313,7 +313,7 @@ void test_apply_fromfile__fail_missing_new_file(void) ...@@ -313,7 +313,7 @@ void test_apply_fromfile__fail_missing_new_file(void)
git_patch *patch; git_patch *patch;
cl_git_fail(git_patch_from_patchfile(&patch, cl_git_fail(git_patch_from_patchfile(&patch,
PATCH_CORRUPT_MISSING_NEW_FILE, PATCH_CORRUPT_MISSING_NEW_FILE,
strlen(PATCH_CORRUPT_MISSING_NEW_FILE))); strlen(PATCH_CORRUPT_MISSING_NEW_FILE), NULL));
} }
void test_apply_fromfile__fail_missing_old_file(void) void test_apply_fromfile__fail_missing_old_file(void)
...@@ -321,7 +321,7 @@ void test_apply_fromfile__fail_missing_old_file(void) ...@@ -321,7 +321,7 @@ void test_apply_fromfile__fail_missing_old_file(void)
git_patch *patch; git_patch *patch;
cl_git_fail(git_patch_from_patchfile(&patch, cl_git_fail(git_patch_from_patchfile(&patch,
PATCH_CORRUPT_MISSING_OLD_FILE, PATCH_CORRUPT_MISSING_OLD_FILE,
strlen(PATCH_CORRUPT_MISSING_OLD_FILE))); strlen(PATCH_CORRUPT_MISSING_OLD_FILE), NULL));
} }
void test_apply_fromfile__fail_no_changes(void) void test_apply_fromfile__fail_no_changes(void)
...@@ -329,7 +329,7 @@ void test_apply_fromfile__fail_no_changes(void) ...@@ -329,7 +329,7 @@ void test_apply_fromfile__fail_no_changes(void)
git_patch *patch; git_patch *patch;
cl_git_fail(git_patch_from_patchfile(&patch, cl_git_fail(git_patch_from_patchfile(&patch,
PATCH_CORRUPT_NO_CHANGES, PATCH_CORRUPT_NO_CHANGES,
strlen(PATCH_CORRUPT_NO_CHANGES))); strlen(PATCH_CORRUPT_NO_CHANGES), NULL));
} }
void test_apply_fromfile__fail_missing_hunk_header(void) void test_apply_fromfile__fail_missing_hunk_header(void)
...@@ -337,14 +337,14 @@ void test_apply_fromfile__fail_missing_hunk_header(void) ...@@ -337,14 +337,14 @@ void test_apply_fromfile__fail_missing_hunk_header(void)
git_patch *patch; git_patch *patch;
cl_git_fail(git_patch_from_patchfile(&patch, cl_git_fail(git_patch_from_patchfile(&patch,
PATCH_CORRUPT_MISSING_HUNK_HEADER, PATCH_CORRUPT_MISSING_HUNK_HEADER,
strlen(PATCH_CORRUPT_MISSING_HUNK_HEADER))); strlen(PATCH_CORRUPT_MISSING_HUNK_HEADER), NULL));
} }
void test_apply_fromfile__fail_not_a_patch(void) void test_apply_fromfile__fail_not_a_patch(void)
{ {
git_patch *patch; git_patch *patch;
cl_git_fail(git_patch_from_patchfile(&patch, PATCH_NOT_A_PATCH, cl_git_fail(git_patch_from_patchfile(&patch, PATCH_NOT_A_PATCH,
strlen(PATCH_NOT_A_PATCH))); strlen(PATCH_NOT_A_PATCH), NULL));
} }
void test_apply_fromfile__binary_add(void) void test_apply_fromfile__binary_add(void)
...@@ -352,7 +352,7 @@ void test_apply_fromfile__binary_add(void) ...@@ -352,7 +352,7 @@ void test_apply_fromfile__binary_add(void)
cl_git_pass(apply_patchfile( cl_git_pass(apply_patchfile(
NULL, 0, NULL, 0,
FILE_BINARY_DELTA_MODIFIED, FILE_BINARY_DELTA_MODIFIED_LEN, FILE_BINARY_DELTA_MODIFIED, FILE_BINARY_DELTA_MODIFIED_LEN,
PATCH_BINARY_ADD, "b/binary.bin", 0100644)); PATCH_BINARY_ADD, "binary.bin", 0100644));
} }
void test_apply_fromfile__binary_change_delta(void) void test_apply_fromfile__binary_change_delta(void)
...@@ -360,7 +360,7 @@ void test_apply_fromfile__binary_change_delta(void) ...@@ -360,7 +360,7 @@ void test_apply_fromfile__binary_change_delta(void)
cl_git_pass(apply_patchfile( cl_git_pass(apply_patchfile(
FILE_BINARY_DELTA_ORIGINAL, FILE_BINARY_DELTA_ORIGINAL_LEN, FILE_BINARY_DELTA_ORIGINAL, FILE_BINARY_DELTA_ORIGINAL_LEN,
FILE_BINARY_DELTA_MODIFIED, FILE_BINARY_DELTA_MODIFIED_LEN, FILE_BINARY_DELTA_MODIFIED, FILE_BINARY_DELTA_MODIFIED_LEN,
PATCH_BINARY_DELTA, "b/binary.bin", 0100644)); PATCH_BINARY_DELTA, "binary.bin", 0100644));
} }
void test_apply_fromfile__binary_change_literal(void) void test_apply_fromfile__binary_change_literal(void)
...@@ -368,7 +368,7 @@ void test_apply_fromfile__binary_change_literal(void) ...@@ -368,7 +368,7 @@ void test_apply_fromfile__binary_change_literal(void)
cl_git_pass(apply_patchfile( cl_git_pass(apply_patchfile(
FILE_BINARY_LITERAL_ORIGINAL, FILE_BINARY_LITERAL_ORIGINAL_LEN, FILE_BINARY_LITERAL_ORIGINAL, FILE_BINARY_LITERAL_ORIGINAL_LEN,
FILE_BINARY_LITERAL_MODIFIED, FILE_BINARY_LITERAL_MODIFIED_LEN, FILE_BINARY_LITERAL_MODIFIED, FILE_BINARY_LITERAL_MODIFIED_LEN,
PATCH_BINARY_LITERAL, "b/binary.bin", 0100644)); PATCH_BINARY_LITERAL, "binary.bin", 0100644));
} }
void test_apply_fromfile__binary_delete(void) void test_apply_fromfile__binary_delete(void)
...@@ -385,7 +385,7 @@ void test_apply_fromfile__binary_change_does_not_apply(void) ...@@ -385,7 +385,7 @@ void test_apply_fromfile__binary_change_does_not_apply(void)
cl_git_fail(apply_patchfile( cl_git_fail(apply_patchfile(
FILE_BINARY_DELTA_MODIFIED, FILE_BINARY_DELTA_MODIFIED_LEN, FILE_BINARY_DELTA_MODIFIED, FILE_BINARY_DELTA_MODIFIED_LEN,
FILE_BINARY_DELTA_ORIGINAL, FILE_BINARY_DELTA_ORIGINAL_LEN, FILE_BINARY_DELTA_ORIGINAL, FILE_BINARY_DELTA_ORIGINAL_LEN,
PATCH_BINARY_DELTA, "b/binary.bin", 0100644)); PATCH_BINARY_DELTA, "binary.bin", 0100644));
} }
void test_apply_fromfile__binary_change_must_be_reversible(void) void test_apply_fromfile__binary_change_must_be_reversible(void)
...@@ -400,6 +400,6 @@ void test_apply_fromfile__empty_file_not_allowed(void) ...@@ -400,6 +400,6 @@ void test_apply_fromfile__empty_file_not_allowed(void)
{ {
git_patch *patch; git_patch *patch;
cl_git_fail(git_patch_from_patchfile(&patch, "", 0)); cl_git_fail(git_patch_from_patchfile(&patch, "", 0, NULL));
cl_git_fail(git_patch_from_patchfile(&patch, NULL, 0)); cl_git_fail(git_patch_from_patchfile(&patch, NULL, 0, NULL));
} }
...@@ -8,19 +8,21 @@ void test_patch_parse__original_to_change_middle(void) ...@@ -8,19 +8,21 @@ void test_patch_parse__original_to_change_middle(void)
const git_diff_delta *delta; const git_diff_delta *delta;
char idstr[GIT_OID_HEXSZ+1] = {0}; char idstr[GIT_OID_HEXSZ+1] = {0};
cl_git_pass(git_patch_from_patchfile(&patch, PATCH_ORIGINAL_TO_CHANGE_MIDDLE, strlen(PATCH_ORIGINAL_TO_CHANGE_MIDDLE))); cl_git_pass(git_patch_from_patchfile(
&patch, PATCH_ORIGINAL_TO_CHANGE_MIDDLE,
strlen(PATCH_ORIGINAL_TO_CHANGE_MIDDLE), NULL));
cl_assert((delta = git_patch_get_delta(patch)) != NULL); cl_assert((delta = git_patch_get_delta(patch)) != NULL);
cl_assert_equal_i(2, delta->nfiles); cl_assert_equal_i(2, delta->nfiles);
cl_assert_equal_s(delta->old_file.path, "a/file.txt"); cl_assert_equal_s(delta->old_file.path, "file.txt");
cl_assert(delta->old_file.mode == GIT_FILEMODE_BLOB); cl_assert(delta->old_file.mode == GIT_FILEMODE_BLOB);
cl_assert_equal_i(7, delta->old_file.id_abbrev); cl_assert_equal_i(7, delta->old_file.id_abbrev);
git_oid_nfmt(idstr, delta->old_file.id_abbrev, &delta->old_file.id); git_oid_nfmt(idstr, delta->old_file.id_abbrev, &delta->old_file.id);
cl_assert_equal_s(idstr, "9432026"); cl_assert_equal_s(idstr, "9432026");
cl_assert_equal_i(0, delta->old_file.size); cl_assert_equal_i(0, delta->old_file.size);
cl_assert_equal_s(delta->new_file.path, "b/file.txt"); cl_assert_equal_s(delta->new_file.path, "file.txt");
cl_assert(delta->new_file.mode == GIT_FILEMODE_BLOB); cl_assert(delta->new_file.mode == GIT_FILEMODE_BLOB);
cl_assert_equal_i(7, delta->new_file.id_abbrev); cl_assert_equal_i(7, delta->new_file.id_abbrev);
git_oid_nfmt(idstr, delta->new_file.id_abbrev, &delta->new_file.id); git_oid_nfmt(idstr, delta->new_file.id_abbrev, &delta->new_file.id);
......
...@@ -12,7 +12,7 @@ void patch_print_from_patchfile(const char *data, size_t len) ...@@ -12,7 +12,7 @@ void patch_print_from_patchfile(const char *data, size_t len)
git_patch *patch; git_patch *patch;
git_buf buf = GIT_BUF_INIT; git_buf buf = GIT_BUF_INIT;
cl_git_pass(git_patch_from_patchfile(&patch, data, len)); cl_git_pass(git_patch_from_patchfile(&patch, data, len, NULL));
cl_git_pass(git_patch_to_buf(&buf, patch)); cl_git_pass(git_patch_to_buf(&buf, patch));
cl_assert_equal_s(data, buf.ptr); cl_assert_equal_s(data, buf.ptr);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment