Commit 804d5fe9 by Edward Thomson Committed by Edward Thomson

patch: abstract patches into diff'ed and parsed

Patches can now come from a variety of sources - either internally
generated (from diffing two commits) or as the results of parsing
some external data.
parent 8d2eef27
......@@ -10,7 +10,7 @@
#include "git2/patch.h"
#include "git2/filter.h"
#include "array.h"
#include "diff_patch.h"
#include "patch.h"
#include "fileops.h"
#include "apply.h"
#include "delta.h"
......@@ -163,7 +163,7 @@ static int update_hunk(
static int apply_hunk(
patch_image *image,
git_patch *patch,
diff_patch_hunk *hunk)
git_patch_hunk *hunk)
{
patch_image preimage, postimage;
size_t line_num, i;
......@@ -218,7 +218,7 @@ static int apply_hunks(
size_t source_len,
git_patch *patch)
{
diff_patch_hunk *hunk;
git_patch_hunk *hunk;
git_diff_line *line;
patch_image image;
size_t i;
......@@ -340,9 +340,11 @@ int git_apply__patch(
*mode_out = 0;
if (patch->delta->status != GIT_DELTA_DELETED) {
filename = git__strdup(patch->nfile.file->path);
mode = patch->nfile.file->mode ?
patch->nfile.file->mode : GIT_FILEMODE_BLOB;
const git_diff_file *newfile = patch->newfile(patch);
filename = git__strdup(newfile->path);
mode = newfile->mode ?
newfile->mode : GIT_FILEMODE_BLOB;
}
if (patch->delta->flags & GIT_DIFF_FLAG_BINARY)
......
......@@ -9,7 +9,6 @@
#include "git2/attr.h"
#include "diff.h"
#include "diff_patch.h"
#include "diff_driver.h"
#include "strmap.h"
#include "map.h"
......
......@@ -6,7 +6,8 @@
*/
#include "common.h"
#include "diff.h"
#include "diff_patch.h"
#include "diff_file.h"
#include "patch_diff.h"
#include "fileops.h"
#include "zstream.h"
#include "blob.h"
......@@ -14,19 +15,19 @@
#include "git2/sys/diff.h"
typedef struct {
git_diff *diff;
git_diff_format_t format;
git_diff_line_cb print_cb;
void *payload;
git_buf *buf;
git_diff_line line;
const char *old_prefix;
const char *new_prefix;
uint32_t flags;
int oid_strlen;
git_diff_line line;
unsigned int
content_loaded : 1,
content_allocated : 1;
git_diff_file_content *ofile;
git_diff_file_content *nfile;
int (*strcomp)(const char *, const char *);
} diff_print_info;
static int diff_print_info_init__common(
......@@ -74,11 +75,13 @@ static int diff_print_info_init_fromdiff(
memset(pi, 0, sizeof(diff_print_info));
pi->diff = diff;
if (diff) {
pi->flags = diff->opts.flags;
pi->oid_strlen = diff->opts.id_abbrev;
pi->old_prefix = diff->opts.old_prefix;
pi->new_prefix = diff->opts.new_prefix;
pi->strcomp = diff->strcomp;
}
return diff_print_info_init__common(pi, out, repo, format, cb, payload);
......@@ -92,24 +95,16 @@ static int diff_print_info_init_frompatch(
git_diff_line_cb cb,
void *payload)
{
git_repository *repo;
assert(patch);
repo = patch->diff ? patch->diff->repo : NULL;
memset(pi, 0, sizeof(diff_print_info));
pi->diff = patch->diff;
pi->flags = patch->diff_opts.flags;
pi->oid_strlen = patch->diff_opts.id_abbrev;
pi->old_prefix = patch->diff_opts.old_prefix;
pi->new_prefix = patch->diff_opts.new_prefix;
pi->content_loaded = 1;
pi->ofile = &patch->ofile;
pi->nfile = &patch->nfile;
return diff_print_info_init__common(pi, out, repo, format, cb, payload);
return diff_print_info_init__common(pi, out, patch->repo, format, cb, payload);
}
static char diff_pick_suffix(int mode)
......@@ -173,8 +168,8 @@ static int diff_print_one_name_status(
diff_print_info *pi = data;
git_buf *out = pi->buf;
char old_suffix, new_suffix, code = git_diff_status_char(delta->status);
int (*strcomp)(const char *, const char *) =
pi->diff ? pi->diff->strcomp : git__strcmp;
int(*strcomp)(const char *, const char *) = pi->strcomp ?
pi->strcomp : git__strcmp;
GIT_UNUSED(progress);
......@@ -367,39 +362,6 @@ static int format_binary(
return 0;
}
static int diff_print_load_content(
diff_print_info *pi,
git_diff_delta *delta)
{
git_diff_file_content *ofile, *nfile;
int error;
assert(pi->diff);
ofile = git__calloc(1, sizeof(git_diff_file_content));
nfile = git__calloc(1, sizeof(git_diff_file_content));
GITERR_CHECK_ALLOC(ofile);
GITERR_CHECK_ALLOC(nfile);
if ((error = git_diff_file_content__init_from_diff(
ofile, pi->diff, delta, true)) < 0 ||
(error = git_diff_file_content__init_from_diff(
nfile, pi->diff, delta, true)) < 0) {
git__free(ofile);
git__free(nfile);
return error;
}
pi->content_loaded = 1;
pi->content_allocated = 1;
pi->ofile = ofile;
pi->nfile = nfile;
return 0;
}
static int diff_print_patch_file_binary(
diff_print_info *pi, git_diff_delta *delta,
const char *old_pfx, const char *new_pfx,
......@@ -411,10 +373,6 @@ static int diff_print_patch_file_binary(
if ((pi->flags & GIT_DIFF_SHOW_BINARY) == 0)
goto noshow;
if (!pi->content_loaded &&
(error = diff_print_load_content(pi, delta)) < 0)
return error;
if (binary->new_file.datalen == 0 && binary->old_file.datalen == 0)
return 0;
......@@ -450,9 +408,9 @@ static int diff_print_patch_file(
int error;
diff_print_info *pi = data;
const char *oldpfx =
pi->diff ? pi->diff->opts.old_prefix : DIFF_OLD_PREFIX_DEFAULT;
pi->old_prefix ? pi->old_prefix : DIFF_OLD_PREFIX_DEFAULT;
const char *newpfx =
pi->diff ? pi->diff->opts.new_prefix : DIFF_NEW_PREFIX_DEFAULT;
pi->new_prefix ? pi->new_prefix : DIFF_NEW_PREFIX_DEFAULT;
bool binary = (delta->flags & GIT_DIFF_FLAG_BINARY) ||
(pi->flags & GIT_DIFF_FORCE_BINARY);
......@@ -488,9 +446,9 @@ static int diff_print_patch_binary(
{
diff_print_info *pi = data;
const char *old_pfx =
pi->diff ? pi->diff->opts.old_prefix : DIFF_OLD_PREFIX_DEFAULT;
pi->old_prefix ? pi->old_prefix : DIFF_OLD_PREFIX_DEFAULT;
const char *new_pfx =
pi->diff ? pi->diff->opts.new_prefix : DIFF_NEW_PREFIX_DEFAULT;
pi->new_prefix ? pi->new_prefix : DIFF_NEW_PREFIX_DEFAULT;
int error;
git_buf_clear(pi->buf);
......@@ -585,43 +543,11 @@ int git_diff_print(
giterr_set_after_callback_function(error, "git_diff_print");
}
git__free(pi.nfile);
git__free(pi.ofile);
git_buf_free(&buf);
return error;
}
/* print a git_patch to an output callback */
int git_patch_print(
git_patch *patch,
git_diff_line_cb print_cb,
void *payload)
{
int error;
git_buf temp = GIT_BUF_INIT;
diff_print_info pi;
assert(patch && print_cb);
if (!(error = diff_print_info_init_frompatch(
&pi, &temp, patch,
GIT_DIFF_FORMAT_PATCH, print_cb, payload)))
{
error = git_patch__invoke_callbacks(
patch, diff_print_patch_file, diff_print_patch_binary,
diff_print_patch_hunk, diff_print_patch_line, &pi);
if (error) /* make sure error message is set */
giterr_set_after_callback_function(error, "git_patch_print");
}
git_buf_free(&temp);
return error;
}
int git_diff_print_callback__to_buf(
const git_diff_delta *delta,
const git_diff_hunk *hunk,
......@@ -662,6 +588,37 @@ int git_diff_print_callback__to_file_handle(
return 0;
}
/* print a git_patch to an output callback */
int git_patch_print(
git_patch *patch,
git_diff_line_cb print_cb,
void *payload)
{
int error;
git_buf temp = GIT_BUF_INIT;
diff_print_info pi;
assert(patch && print_cb);
if (!(error = diff_print_info_init_frompatch(
&pi, &temp, patch,
GIT_DIFF_FORMAT_PATCH, print_cb, payload)))
{
error = git_patch__invoke_callbacks(
patch,
diff_print_patch_file, diff_print_patch_binary,
diff_print_patch_hunk, diff_print_patch_line,
&pi);
if (error) /* make sure error message is set */
giterr_set_after_callback_function(error, "git_patch_print");
}
git_buf_free(&temp);
return error;
}
/* print a git_patch to a git_buf */
int git_patch_to_buf(git_buf *out, git_patch *patch)
{
......
......@@ -7,7 +7,7 @@
#include "common.h"
#include "vector.h"
#include "diff.h"
#include "diff_patch.h"
#include "patch_diff.h"
#define DIFF_RENAME_FILE_SEPARATOR " => "
#define STATS_FULL_MIN_SCALE 7
......@@ -190,8 +190,9 @@ int git_diff_get_stats(
break;
/* keep a count of renames because it will affect formatting */
delta = git_patch_get_delta(patch);
delta = patch->delta;
/* TODO ugh */
namelen = strlen(delta->new_file.path);
if (strcmp(delta->old_file.path, delta->new_file.path) != 0) {
namelen += strlen(delta->old_file.path);
......
......@@ -8,8 +8,8 @@
#include "common.h"
#include "diff.h"
#include "diff_driver.h"
#include "diff_patch.h"
#include "diff_xdiff.h"
#include "patch_diff.h"
static int git_xdiff_scan_int(const char **str, int *value)
{
......@@ -56,7 +56,7 @@ fail:
typedef struct {
git_xdiff_output *xo;
git_patch *patch;
git_patch_diff *patch;
git_diff_hunk hunk;
int old_lineno, new_lineno;
mmfile_t xd_old_data, xd_new_data;
......@@ -110,9 +110,9 @@ static int diff_update_lines(
static int git_xdiff_cb(void *priv, mmbuffer_t *bufs, int len)
{
git_xdiff_info *info = priv;
git_patch *patch = info->patch;
const git_diff_delta *delta = git_patch_get_delta(patch);
git_diff_output *output = &info->xo->output;
git_patch_diff *patch = info->patch;
const git_diff_delta *delta = patch->base.delta;
git_patch_diff_output *output = &info->xo->output;
git_diff_line line;
if (len == 1) {
......@@ -181,7 +181,7 @@ static int git_xdiff_cb(void *priv, mmbuffer_t *bufs, int len)
return output->error;
}
static int git_xdiff(git_diff_output *output, git_patch *patch)
static int git_xdiff(git_patch_diff_output *output, git_patch_diff *patch)
{
git_xdiff_output *xo = (git_xdiff_output *)output;
git_xdiff_info info;
......@@ -194,7 +194,7 @@ static int git_xdiff(git_diff_output *output, git_patch *patch)
xo->callback.priv = &info;
git_diff_find_context_init(
&xo->config.find_func, &findctxt, git_patch__driver(patch));
&xo->config.find_func, &findctxt, git_patch_diff_driver(patch));
xo->config.find_func_priv = &findctxt;
if (xo->config.find_func != NULL)
......@@ -206,8 +206,8 @@ static int git_xdiff(git_diff_output *output, git_patch *patch)
* updates are needed to xo->params.flags
*/
git_patch__old_data(&info.xd_old_data.ptr, &info.xd_old_data.size, patch);
git_patch__new_data(&info.xd_new_data.ptr, &info.xd_new_data.size, patch);
git_patch_diff_old_data(&info.xd_old_data.ptr, &info.xd_old_data.size, patch);
git_patch_diff_new_data(&info.xd_new_data.ptr, &info.xd_new_data.size, patch);
if (info.xd_old_data.size > GIT_XDIFF_MAX_SIZE ||
info.xd_new_data.size > GIT_XDIFF_MAX_SIZE) {
......
......@@ -8,20 +8,20 @@
#define INCLUDE_diff_xdiff_h__
#include "diff.h"
#include "diff_patch.h"
#include "xdiff/xdiff.h"
#include "patch_diff.h"
/* xdiff cannot cope with large files. these files should not be passed to
* xdiff. callers should treat these large files as binary.
*/
#define GIT_XDIFF_MAX_SIZE (1024LL * 1024 * 1023)
/* A git_xdiff_output is a git_diff_output with extra fields necessary
/* A git_xdiff_output is a git_patch_diff_output with extra fields necessary
* to use libxdiff. Calling git_xdiff_init() will set the diff_cb field
* of the output to use xdiff to generate the diffs.
*/
typedef struct {
git_diff_output output;
git_patch_diff_output output;
xdemitconf_t config;
xpparam_t params;
......
/*
* Copyright (C) the libgit2 contributors. All rights reserved.
*
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
#ifndef INCLUDE_patch_h__
#define INCLUDE_patch_h__
#include "git2/patch.h"
#include "array.h"
/* cached information about a hunk in a patch */
typedef struct git_patch_hunk {
git_diff_hunk hunk;
size_t line_start;
size_t line_count;
} git_patch_hunk;
struct git_patch {
git_refcount rc;
git_repository *repo; /* may be null */
git_diff_options diff_opts;
git_diff_delta *delta;
git_diff_binary binary;
git_array_t(git_patch_hunk) hunks;
git_array_t(git_diff_line) lines;
size_t header_size;
size_t content_size;
size_t context_size;
const git_diff_file *(*newfile)(git_patch *patch);
const git_diff_file *(*oldfile)(git_patch *patch);
void (*free_fn)(git_patch *patch);
};
extern int git_patch__invoke_callbacks(
git_patch *patch,
git_diff_file_cb file_cb,
git_diff_binary_cb binary_cb,
git_diff_hunk_cb hunk_cb,
git_diff_line_cb line_cb,
void *payload);
extern int git_patch_line_stats(
size_t *total_ctxt,
size_t *total_adds,
size_t *total_dels,
const git_patch *patch);
extern void git_patch_free(git_patch *patch);
#endif
......@@ -10,60 +10,40 @@
#include "common.h"
#include "diff.h"
#include "diff_file.h"
#include "array.h"
#include "git2/patch.h"
/* cached information about a hunk in a diff */
typedef struct diff_patch_hunk {
git_diff_hunk hunk;
size_t line_start;
size_t line_count;
} diff_patch_hunk;
#include "patch.h"
enum {
GIT_DIFF_PATCH_ALLOCATED = (1 << 0),
GIT_DIFF_PATCH_INITIALIZED = (1 << 1),
GIT_DIFF_PATCH_LOADED = (1 << 2),
GIT_PATCH_DIFF_ALLOCATED = (1 << 0),
GIT_PATCH_DIFF_INITIALIZED = (1 << 1),
GIT_PATCH_DIFF_LOADED = (1 << 2),
/* the two sides are different */
GIT_DIFF_PATCH_DIFFABLE = (1 << 3),
GIT_PATCH_DIFF_DIFFABLE = (1 << 3),
/* the difference between the two sides has been computed */
GIT_DIFF_PATCH_DIFFED = (1 << 4),
GIT_DIFF_PATCH_FLATTENED = (1 << 5),
GIT_PATCH_DIFF_DIFFED = (1 << 4),
GIT_PATCH_DIFF_FLATTENED = (1 << 5),
};
struct git_patch {
git_refcount rc;
struct git_patch_diff {
struct git_patch base;
git_diff *diff; /* for refcount purposes, maybe NULL for blob diffs */
git_diff_options diff_opts;
git_diff_delta *delta;
size_t delta_index;
git_diff_file_content ofile;
git_diff_file_content nfile;
uint32_t flags;
git_diff_binary binary;
git_array_t(diff_patch_hunk) hunks;
git_array_t(git_diff_line) lines;
size_t content_size, context_size, header_size;
git_pool flattened;
};
extern git_diff *git_patch__diff(git_patch *);
typedef struct git_patch_diff git_patch_diff;
extern git_diff_driver *git_patch__driver(git_patch *);
extern git_diff_driver *git_patch_diff_driver(git_patch_diff *);
extern void git_patch__old_data(char **, size_t *, git_patch *);
extern void git_patch__new_data(char **, size_t *, git_patch *);
extern void git_patch_diff_old_data(char **, size_t *, git_patch_diff *);
extern void git_patch_diff_new_data(char **, size_t *, git_patch_diff *);
extern int git_patch__invoke_callbacks(
git_patch *patch,
git_diff_file_cb file_cb,
git_diff_binary_cb binary_cb,
git_diff_hunk_cb hunk_cb,
git_diff_line_cb line_cb,
void *payload);
typedef struct git_patch_diff_output git_patch_diff_output;
typedef struct git_diff_output git_diff_output;
struct git_diff_output {
struct git_patch_diff_output {
/* these callbacks are issued with the diff data */
git_diff_file_cb file_cb;
git_diff_binary_cb binary_cb;
......@@ -77,7 +57,7 @@ struct git_diff_output {
/* this callback is used to do the diff and drive the other callbacks.
* see diff_xdiff.h for how to use this in practice for now.
*/
int (*diff_cb)(git_diff_output *output, git_patch *patch);
int (*diff_cb)(git_patch_diff_output *output, git_patch_diff *patch);
};
#endif
......@@ -106,6 +106,7 @@ void test_apply_fromfile__change_middle_nocontext(void)
&diff_opts, "b/file.txt", 0100644));
}
void test_apply_fromfile__change_firstline(void)
{
cl_git_pass(validate_and_apply_patchfile(
......
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