#include "cache.h"
#include "config.h"
+#include "convert.h"
#include "attr.h"
#include "xdiff-interface.h"
#include "run-command.h"
#include "ll-merge.h"
#include "quote.h"
+#include "wrapper.h"
struct ll_merge_driver;
-typedef int (*ll_merge_fn)(const struct ll_merge_driver *,
+typedef enum ll_merge_result (*ll_merge_fn)(const struct ll_merge_driver *,
mmbuffer_t *result,
const char *path,
mmfile_t *orig, const char *orig_name,
/*
* Built-in low-levels
*/
-static int ll_binary_merge(const struct ll_merge_driver *drv_unused,
+static enum ll_merge_result ll_binary_merge(const struct ll_merge_driver *drv UNUSED,
mmbuffer_t *result,
- const char *path,
- mmfile_t *orig, const char *orig_name,
- mmfile_t *src1, const char *name1,
- mmfile_t *src2, const char *name2,
+ const char *path UNUSED,
+ mmfile_t *orig, const char *orig_name UNUSED,
+ mmfile_t *src1, const char *name1 UNUSED,
+ mmfile_t *src2, const char *name2 UNUSED,
const struct ll_merge_options *opts,
- int marker_size)
+ int marker_size UNUSED)
{
+ enum ll_merge_result ret;
mmfile_t *stolen;
assert(opts);
*/
if (opts->virtual_ancestor) {
stolen = orig;
+ ret = LL_MERGE_OK;
} else {
switch (opts->variant) {
default:
- warning("Cannot merge binary files: %s (%s vs. %s)",
- path, name1, name2);
- /* fallthru */
+ ret = LL_MERGE_BINARY_CONFLICT;
+ stolen = src1;
+ break;
case XDL_MERGE_FAVOR_OURS:
+ ret = LL_MERGE_OK;
stolen = src1;
break;
case XDL_MERGE_FAVOR_THEIRS:
+ ret = LL_MERGE_OK;
stolen = src2;
break;
}
result->size = stolen->size;
stolen->ptr = NULL;
- /*
- * With -Xtheirs or -Xours, we have cleanly merged;
- * otherwise we got a conflict.
- */
- return (opts->variant ? 0 : 1);
+ return ret;
}
-static int ll_xdl_merge(const struct ll_merge_driver *drv_unused,
+static enum ll_merge_result ll_xdl_merge(const struct ll_merge_driver *drv_unused,
mmbuffer_t *result,
const char *path,
mmfile_t *orig, const char *orig_name,
const struct ll_merge_options *opts,
int marker_size)
{
+ enum ll_merge_result ret;
xmparam_t xmp;
+ int status;
assert(opts);
if (orig->size > MAX_XDIFF_SIZE ||
xmp.ancestor = orig_name;
xmp.file1 = name1;
xmp.file2 = name2;
- return xdl_merge(orig, src1, src2, &xmp, result);
+ status = xdl_merge(orig, src1, src2, &xmp, result);
+ ret = (status > 0) ? LL_MERGE_CONFLICT : status;
+ return ret;
}
-static int ll_union_merge(const struct ll_merge_driver *drv_unused,
+static enum ll_merge_result ll_union_merge(const struct ll_merge_driver *drv_unused,
mmbuffer_t *result,
- const char *path_unused,
+ const char *path,
mmfile_t *orig, const char *orig_name,
mmfile_t *src1, const char *name1,
mmfile_t *src2, const char *name2,
assert(opts);
o = *opts;
o.variant = XDL_MERGE_FAVOR_UNION;
- return ll_xdl_merge(drv_unused, result, path_unused,
- orig, NULL, src1, NULL, src2, NULL,
+ return ll_xdl_merge(drv_unused, result, path,
+ orig, orig_name, src1, name1, src2, name2,
&o, marker_size);
}
/*
* User defined low-level merge driver support.
*/
-static int ll_ext_merge(const struct ll_merge_driver *fn,
+static enum ll_merge_result ll_ext_merge(const struct ll_merge_driver *fn,
mmbuffer_t *result,
const char *path,
- mmfile_t *orig, const char *orig_name,
- mmfile_t *src1, const char *name1,
- mmfile_t *src2, const char *name2,
+ mmfile_t *orig, const char *orig_name UNUSED,
+ mmfile_t *src1, const char *name1 UNUSED,
+ mmfile_t *src2, const char *name2 UNUSED,
const struct ll_merge_options *opts,
int marker_size)
{
struct strbuf cmd = STRBUF_INIT;
struct strbuf_expand_dict_entry dict[6];
struct strbuf path_sq = STRBUF_INIT;
- const char *args[] = { NULL, NULL };
+ struct child_process child = CHILD_PROCESS_INIT;
int status, fd, i;
struct stat st;
+ enum ll_merge_result ret;
assert(opts);
sq_quote_buf(&path_sq, path);
dict[4].placeholder = "P"; dict[4].value = path_sq.buf;
dict[5].placeholder = NULL; dict[5].value = NULL;
- if (fn->cmdline == NULL)
+ if (!fn->cmdline)
die("custom merge driver %s lacks command line.", fn->name);
result->ptr = NULL;
strbuf_expand(&cmd, fn->cmdline, strbuf_expand_dict_cb, &dict);
- args[0] = cmd.buf;
- status = run_command_v_opt(args, RUN_USING_SHELL);
+ child.use_shell = 1;
+ strvec_push(&child.args, cmd.buf);
+ status = run_command(&child);
fd = open(temp[1], O_RDONLY);
if (fd < 0)
goto bad;
unlink_or_warn(temp[i]);
strbuf_release(&cmd);
strbuf_release(&path_sq);
- return status;
+ ret = (status > 0) ? LL_MERGE_CONFLICT : status;
+ return ret;
}
/*
static struct ll_merge_driver *ll_user_merge, **ll_user_merge_tail;
static const char *default_ll_merge;
-static int read_merge_config(const char *var, const char *value, void *cb)
+static int read_merge_config(const char *var, const char *value,
+ void *cb UNUSED)
{
struct ll_merge_driver *fn;
const char *key, *name;
}
}
-int ll_merge(mmbuffer_t *result_buf,
+enum ll_merge_result ll_merge(mmbuffer_t *result_buf,
const char *path,
mmfile_t *ancestor, const char *ancestor_label,
mmfile_t *ours, const char *our_label,
normalize_file(theirs, path, istate);
}
- git_check_attr(istate, path, check);
+ git_check_attr(istate, NULL, path, check);
ll_driver_name = check->items[0].value;
if (check->items[1].value) {
marker_size = atoi(check->items[1].value);
if (!check)
check = attr_check_initl("conflict-marker-size", NULL);
- git_check_attr(istate, path, check);
+ git_check_attr(istate, NULL, path, check);
if (check->items[0].value) {
marker_size = atoi(check->items[0].value);
if (marker_size <= 0)