mirror of
https://git.proxmox.com/git/libgit2
synced 2025-06-19 22:44:42 +00:00
Introduce git_patch_options, handle prefixes
Handle prefixes (in terms of number of path components) for patch parsing.
This commit is contained in:
parent
19e46645af
commit
82175084e1
@ -267,18 +267,31 @@ GIT_EXTERN(int) git_patch_to_buf(
|
||||
git_buf *out,
|
||||
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.
|
||||
*
|
||||
* @param out The patch to be created
|
||||
* @param patchfile The contents of a patch file
|
||||
* @param patchfile_len The length of the patch file
|
||||
* @param opts The git_patch_options
|
||||
* @return 0 on success, <0 on failure.
|
||||
*/
|
||||
GIT_EXTERN(int) git_patch_from_patchfile(
|
||||
git_patch **out,
|
||||
const char *patchfile,
|
||||
size_t patchfile_len);
|
||||
size_t patchfile_len,
|
||||
git_patch_options *opts);
|
||||
|
||||
GIT_END_DECL
|
||||
|
||||
|
@ -5,9 +5,25 @@
|
||||
#define parse_err(...) \
|
||||
( giterr_set(GITERR_PATCH, __VA_ARGS__), -1 )
|
||||
|
||||
/* TODO: remove this, just use git_patch */
|
||||
typedef struct {
|
||||
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;
|
||||
|
||||
typedef struct {
|
||||
@ -19,10 +35,6 @@ typedef struct {
|
||||
size_t line_num;
|
||||
|
||||
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;
|
||||
|
||||
|
||||
@ -139,13 +151,13 @@ static int parse_header_path(char **out, patch_parse_ctx *ctx)
|
||||
static int parse_header_git_oldpath(
|
||||
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(
|
||||
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)
|
||||
@ -262,44 +274,17 @@ static int parse_header_git_newfilemode(
|
||||
|
||||
static int parse_header_rename(
|
||||
char **out,
|
||||
char **header_path,
|
||||
patch_parse_ctx *ctx)
|
||||
{
|
||||
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)
|
||||
return -1;
|
||||
|
||||
if (header_path_len < git_buf_len(&path))
|
||||
return parse_err("rename path is invalid at line %d", ctx->line_num);
|
||||
|
||||
/* This sanity check exists because git core uses the data in the
|
||||
* "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.
|
||||
/* Note: the `rename from` and `rename to` lines include the literal
|
||||
* filename. They do *not* include the prefix. (Who needs consistency?)
|
||||
*/
|
||||
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);
|
||||
|
||||
*out = git_buf_detach(&path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -307,22 +292,14 @@ static int parse_header_renamefrom(
|
||||
git_patch_parsed *patch, patch_parse_ctx *ctx)
|
||||
{
|
||||
patch->base.delta->status = GIT_DELTA_RENAMED;
|
||||
|
||||
return parse_header_rename(
|
||||
(char **)&patch->base.delta->old_file.path,
|
||||
&ctx->header_old_path,
|
||||
ctx);
|
||||
return parse_header_rename(&patch->rename_old_path, ctx);
|
||||
}
|
||||
|
||||
static int parse_header_renameto(
|
||||
git_patch_parsed *patch, patch_parse_ctx *ctx)
|
||||
{
|
||||
patch->base.delta->status = GIT_DELTA_RENAMED;
|
||||
|
||||
return parse_header_rename(
|
||||
(char **)&patch->base.delta->new_file.path,
|
||||
&ctx->header_new_path,
|
||||
ctx);
|
||||
return parse_header_rename(&patch->rename_new_path, ctx);
|
||||
}
|
||||
|
||||
static int parse_header_percent(uint16_t *out, patch_parse_ctx *ctx)
|
||||
@ -404,12 +381,12 @@ static int parse_header_git(
|
||||
if (parse_advance_expected(ctx, "diff --git ", 11) < 0)
|
||||
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",
|
||||
ctx->line_num);
|
||||
|
||||
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",
|
||||
ctx->line_num);
|
||||
|
||||
@ -628,49 +605,6 @@ done:
|
||||
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(
|
||||
git_patch_parsed *patch,
|
||||
patch_parse_ctx *ctx)
|
||||
@ -707,11 +641,7 @@ static int parsed_patch_header(
|
||||
|
||||
/* A proper git patch */
|
||||
if (ctx->line_len >= 11 && memcmp(ctx->line, "diff --git ", 11) == 0) {
|
||||
if ((error = parse_header_git(patch, ctx)) < 0)
|
||||
goto done;
|
||||
|
||||
error = check_filenames(patch, ctx);
|
||||
|
||||
error = parse_header_git(patch, ctx);
|
||||
goto done;
|
||||
}
|
||||
|
||||
@ -871,15 +801,114 @@ static int parsed_patch_body(
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 &&
|
||||
!patch->base.delta->new_file.path)
|
||||
return parse_err("git diff header lacks old / new paths");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int check_patch(git_patch_parsed *patch)
|
||||
{
|
||||
if (!patch->base.delta->old_file.path &&
|
||||
patch->base.delta->status != GIT_DELTA_ADDED)
|
||||
return parse_err("missing old file path");
|
||||
|
||||
if (!patch->base.delta->new_file.path &&
|
||||
patch->base.delta->status != GIT_DELTA_DELETED)
|
||||
return parse_err("missing new file path");
|
||||
if (check_filenames(patch) < 0)
|
||||
return -1;
|
||||
|
||||
if (patch->base.delta->old_file.path &&
|
||||
patch->base.delta->status != GIT_DELTA_DELETED &&
|
||||
@ -895,13 +924,32 @@ static int check_patch(git_patch_parsed *patch)
|
||||
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(
|
||||
git_patch **out,
|
||||
const char *content,
|
||||
size_t content_len)
|
||||
size_t content_len,
|
||||
git_patch_options *opts)
|
||||
{
|
||||
patch_parse_ctx ctx = { 0 };
|
||||
git_patch_parsed *patch;
|
||||
git_patch_options default_opts = GIT_PATCH_OPTIONS_INIT;
|
||||
int error = 0;
|
||||
|
||||
*out = NULL;
|
||||
@ -909,10 +957,12 @@ int git_patch_from_patchfile(
|
||||
patch = git__calloc(1, sizeof(git_patch_parsed));
|
||||
GITERR_CHECK_ALLOC(patch);
|
||||
|
||||
/* TODO: allow callers to specify prefix depth (eg, `-p2`) */
|
||||
patch->base.diff_opts.new_prefix = "";
|
||||
patch->base.diff_opts.old_prefix = "";
|
||||
patch->base.diff_opts.flags |= GIT_DIFF_SHOW_BINARY;
|
||||
if (opts)
|
||||
memcpy(&patch->opts, opts, sizeof(git_patch_options));
|
||||
else
|
||||
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->status = GIT_DELTA_MODIFIED;
|
||||
@ -927,12 +977,13 @@ int git_patch_from_patchfile(
|
||||
(error = check_patch(patch)) < 0)
|
||||
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);
|
||||
*out = &patch->base;
|
||||
|
||||
done:
|
||||
git__free(ctx.header_old_path);
|
||||
git__free(ctx.header_new_path);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ static int apply_patchfile(
|
||||
unsigned int mode;
|
||||
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);
|
||||
|
||||
@ -91,7 +91,7 @@ void test_apply_fromfile__change_middle(void)
|
||||
FILE_ORIGINAL, strlen(FILE_ORIGINAL),
|
||||
FILE_CHANGE_MIDDLE, strlen(FILE_CHANGE_MIDDLE),
|
||||
PATCH_ORIGINAL_TO_CHANGE_MIDDLE, NULL,
|
||||
"b/file.txt", 0100644));
|
||||
"file.txt", 0100644));
|
||||
}
|
||||
|
||||
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_CHANGE_MIDDLE, strlen(FILE_CHANGE_MIDDLE),
|
||||
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)
|
||||
FILE_ORIGINAL, strlen(FILE_ORIGINAL),
|
||||
FILE_CHANGE_FIRSTLINE, strlen(FILE_CHANGE_FIRSTLINE),
|
||||
PATCH_ORIGINAL_TO_CHANGE_FIRSTLINE, NULL,
|
||||
"b/file.txt", 0100644));
|
||||
"file.txt", 0100644));
|
||||
}
|
||||
|
||||
void test_apply_fromfile__lastline(void)
|
||||
@ -122,7 +122,7 @@ void test_apply_fromfile__lastline(void)
|
||||
FILE_ORIGINAL, strlen(FILE_ORIGINAL),
|
||||
FILE_CHANGE_LASTLINE, strlen(FILE_CHANGE_LASTLINE),
|
||||
PATCH_ORIGINAL_TO_CHANGE_LASTLINE, NULL,
|
||||
"b/file.txt", 0100644));
|
||||
"file.txt", 0100644));
|
||||
}
|
||||
|
||||
void test_apply_fromfile__prepend(void)
|
||||
@ -130,7 +130,7 @@ void test_apply_fromfile__prepend(void)
|
||||
cl_git_pass(validate_and_apply_patchfile(
|
||||
FILE_ORIGINAL, strlen(FILE_ORIGINAL),
|
||||
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)
|
||||
@ -142,7 +142,7 @@ void test_apply_fromfile__prepend_nocontext(void)
|
||||
FILE_ORIGINAL, strlen(FILE_ORIGINAL),
|
||||
FILE_PREPEND, strlen(FILE_PREPEND),
|
||||
PATCH_ORIGINAL_TO_PREPEND_NOCONTEXT, &diff_opts,
|
||||
"b/file.txt", 0100644));
|
||||
"file.txt", 0100644));
|
||||
}
|
||||
|
||||
void test_apply_fromfile__append(void)
|
||||
@ -150,7 +150,7 @@ void test_apply_fromfile__append(void)
|
||||
cl_git_pass(validate_and_apply_patchfile(
|
||||
FILE_ORIGINAL, strlen(FILE_ORIGINAL),
|
||||
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)
|
||||
@ -162,7 +162,7 @@ void test_apply_fromfile__append_nocontext(void)
|
||||
FILE_ORIGINAL, strlen(FILE_ORIGINAL),
|
||||
FILE_APPEND, strlen(FILE_APPEND),
|
||||
PATCH_ORIGINAL_TO_APPEND_NOCONTEXT, &diff_opts,
|
||||
"b/file.txt", 0100644));
|
||||
"file.txt", 0100644));
|
||||
}
|
||||
|
||||
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_PREPEND_AND_APPEND, strlen(FILE_PREPEND_AND_APPEND),
|
||||
PATCH_ORIGINAL_TO_PREPEND_AND_APPEND, NULL,
|
||||
"b/file.txt", 0100644));
|
||||
"file.txt", 0100644));
|
||||
}
|
||||
|
||||
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(
|
||||
FILE_ORIGINAL, strlen(FILE_ORIGINAL),
|
||||
"", 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)
|
||||
@ -187,7 +187,7 @@ void test_apply_fromfile__from_empty_file(void)
|
||||
cl_git_pass(validate_and_apply_patchfile(
|
||||
"", 0,
|
||||
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)
|
||||
@ -195,7 +195,7 @@ void test_apply_fromfile__add(void)
|
||||
cl_git_pass(validate_and_apply_patchfile(
|
||||
NULL, 0,
|
||||
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)
|
||||
@ -212,7 +212,7 @@ void test_apply_fromfile__rename_exact(void)
|
||||
cl_git_pass(apply_patchfile(
|
||||
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)
|
||||
@ -220,7 +220,7 @@ void test_apply_fromfile__rename_similar(void)
|
||||
cl_git_pass(apply_patchfile(
|
||||
FILE_ORIGINAL, strlen(FILE_ORIGINAL),
|
||||
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)
|
||||
@ -228,7 +228,7 @@ void test_apply_fromfile__rename_similar_quotedname(void)
|
||||
cl_git_pass(apply_patchfile(
|
||||
FILE_ORIGINAL, strlen(FILE_ORIGINAL),
|
||||
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)
|
||||
@ -236,7 +236,7 @@ void test_apply_fromfile__modechange(void)
|
||||
cl_git_pass(apply_patchfile(
|
||||
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)
|
||||
@ -244,7 +244,7 @@ void test_apply_fromfile__modechange_with_modification(void)
|
||||
cl_git_pass(apply_patchfile(
|
||||
FILE_ORIGINAL, strlen(FILE_ORIGINAL),
|
||||
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)
|
||||
@ -252,7 +252,7 @@ void test_apply_fromfile__noisy(void)
|
||||
cl_git_pass(apply_patchfile(
|
||||
FILE_ORIGINAL, strlen(FILE_ORIGINAL),
|
||||
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)
|
||||
@ -260,35 +260,35 @@ void test_apply_fromfile__noisy_nocontext(void)
|
||||
cl_git_pass(apply_patchfile(
|
||||
FILE_ORIGINAL, strlen(FILE_ORIGINAL),
|
||||
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)
|
||||
{
|
||||
git_patch *patch;
|
||||
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)
|
||||
{
|
||||
git_patch *patch;
|
||||
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)
|
||||
{
|
||||
git_patch *patch;
|
||||
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)
|
||||
{
|
||||
git_patch *patch;
|
||||
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)
|
||||
@ -297,7 +297,7 @@ void test_apply_fromfile__empty_context(void)
|
||||
FILE_EMPTY_CONTEXT_ORIGINAL, strlen(FILE_EMPTY_CONTEXT_ORIGINAL),
|
||||
FILE_EMPTY_CONTEXT_MODIFIED, strlen(FILE_EMPTY_CONTEXT_MODIFIED),
|
||||
PATCH_EMPTY_CONTEXT,
|
||||
"b/file.txt", 0100644));
|
||||
"file.txt", 0100644));
|
||||
}
|
||||
|
||||
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(
|
||||
FILE_ORIGINAL, strlen(FILE_ORIGINAL),
|
||||
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)
|
||||
@ -313,7 +313,7 @@ void test_apply_fromfile__fail_missing_new_file(void)
|
||||
git_patch *patch;
|
||||
cl_git_fail(git_patch_from_patchfile(&patch,
|
||||
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)
|
||||
@ -321,7 +321,7 @@ void test_apply_fromfile__fail_missing_old_file(void)
|
||||
git_patch *patch;
|
||||
cl_git_fail(git_patch_from_patchfile(&patch,
|
||||
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)
|
||||
@ -329,7 +329,7 @@ void test_apply_fromfile__fail_no_changes(void)
|
||||
git_patch *patch;
|
||||
cl_git_fail(git_patch_from_patchfile(&patch,
|
||||
PATCH_CORRUPT_NO_CHANGES,
|
||||
strlen(PATCH_CORRUPT_NO_CHANGES)));
|
||||
strlen(PATCH_CORRUPT_NO_CHANGES), NULL));
|
||||
}
|
||||
|
||||
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;
|
||||
cl_git_fail(git_patch_from_patchfile(&patch,
|
||||
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)
|
||||
{
|
||||
git_patch *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)
|
||||
@ -352,7 +352,7 @@ void test_apply_fromfile__binary_add(void)
|
||||
cl_git_pass(apply_patchfile(
|
||||
NULL, 0,
|
||||
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)
|
||||
@ -360,7 +360,7 @@ void test_apply_fromfile__binary_change_delta(void)
|
||||
cl_git_pass(apply_patchfile(
|
||||
FILE_BINARY_DELTA_ORIGINAL, FILE_BINARY_DELTA_ORIGINAL_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)
|
||||
@ -368,7 +368,7 @@ void test_apply_fromfile__binary_change_literal(void)
|
||||
cl_git_pass(apply_patchfile(
|
||||
FILE_BINARY_LITERAL_ORIGINAL, FILE_BINARY_LITERAL_ORIGINAL_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)
|
||||
@ -385,7 +385,7 @@ void test_apply_fromfile__binary_change_does_not_apply(void)
|
||||
cl_git_fail(apply_patchfile(
|
||||
FILE_BINARY_DELTA_MODIFIED, FILE_BINARY_DELTA_MODIFIED_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)
|
||||
@ -400,6 +400,6 @@ void test_apply_fromfile__empty_file_not_allowed(void)
|
||||
{
|
||||
git_patch *patch;
|
||||
|
||||
cl_git_fail(git_patch_from_patchfile(&patch, "", 0));
|
||||
cl_git_fail(git_patch_from_patchfile(&patch, NULL, 0));
|
||||
cl_git_fail(git_patch_from_patchfile(&patch, "", 0, NULL));
|
||||
cl_git_fail(git_patch_from_patchfile(&patch, NULL, 0, NULL));
|
||||
}
|
||||
|
@ -8,19 +8,21 @@ void test_patch_parse__original_to_change_middle(void)
|
||||
const git_diff_delta *delta;
|
||||
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_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_equal_i(7, delta->old_file.id_abbrev);
|
||||
git_oid_nfmt(idstr, delta->old_file.id_abbrev, &delta->old_file.id);
|
||||
cl_assert_equal_s(idstr, "9432026");
|
||||
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_equal_i(7, delta->new_file.id_abbrev);
|
||||
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)
|
||||
git_patch *patch;
|
||||
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_assert_equal_s(data, buf.ptr);
|
||||
|
Loading…
Reference in New Issue
Block a user