зеркало из https://github.com/microsoft/git.git
Merge branch 'cc/apply-am'
"git am" has been taught to make an internal call to "git apply"'s innards without spawning the latter as a separate process. * cc/apply-am: (41 commits) builtin/am: use apply API in run_apply() apply: learn to use a different index file apply: pass apply state to build_fake_ancestor() apply: refactor `git apply` option parsing apply: change error_routine when silent usage: add get_error_routine() and get_warn_routine() usage: add set_warn_routine() apply: don't print on stdout in verbosity_silent mode apply: make it possible to silently apply apply: use error_errno() where possible apply: make some parsing functions static again apply: move libified code from builtin/apply.c to apply.{c,h} apply: rename and move opt constants to apply.h builtin/apply: rename option parsing functions builtin/apply: make create_one_file() return -1 on error builtin/apply: make try_create_file() return -1 on error builtin/apply: make write_out_results() return -1 on error builtin/apply: make write_out_one_result() return -1 on error builtin/apply: make create_file() return -1 on error builtin/apply: make add_index_file() return -1 on error ...
This commit is contained in:
Коммит
81358dc238
1
Makefile
1
Makefile
|
@ -696,6 +696,7 @@ LIB_OBJS += abspath.o
|
|||
LIB_OBJS += advice.o
|
||||
LIB_OBJS += alias.o
|
||||
LIB_OBJS += alloc.o
|
||||
LIB_OBJS += apply.o
|
||||
LIB_OBJS += archive.o
|
||||
LIB_OBJS += archive-tar.o
|
||||
LIB_OBJS += archive-zip.o
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,137 @@
|
|||
#ifndef APPLY_H
|
||||
#define APPLY_H
|
||||
|
||||
enum apply_ws_error_action {
|
||||
nowarn_ws_error,
|
||||
warn_on_ws_error,
|
||||
die_on_ws_error,
|
||||
correct_ws_error
|
||||
};
|
||||
|
||||
enum apply_ws_ignore {
|
||||
ignore_ws_none,
|
||||
ignore_ws_change
|
||||
};
|
||||
|
||||
enum apply_verbosity {
|
||||
verbosity_silent = -1,
|
||||
verbosity_normal = 0,
|
||||
verbosity_verbose = 1
|
||||
};
|
||||
|
||||
/*
|
||||
* We need to keep track of how symlinks in the preimage are
|
||||
* manipulated by the patches. A patch to add a/b/c where a/b
|
||||
* is a symlink should not be allowed to affect the directory
|
||||
* the symlink points at, but if the same patch removes a/b,
|
||||
* it is perfectly fine, as the patch removes a/b to make room
|
||||
* to create a directory a/b so that a/b/c can be created.
|
||||
*
|
||||
* See also "struct string_list symlink_changes" in "struct
|
||||
* apply_state".
|
||||
*/
|
||||
#define APPLY_SYMLINK_GOES_AWAY 01
|
||||
#define APPLY_SYMLINK_IN_RESULT 02
|
||||
|
||||
struct apply_state {
|
||||
const char *prefix;
|
||||
int prefix_length;
|
||||
|
||||
/* These are lock_file related */
|
||||
struct lock_file *lock_file;
|
||||
int newfd;
|
||||
|
||||
/* These control what gets looked at and modified */
|
||||
int apply; /* this is not a dry-run */
|
||||
int cached; /* apply to the index only */
|
||||
int check; /* preimage must match working tree, don't actually apply */
|
||||
int check_index; /* preimage must match the indexed version */
|
||||
int update_index; /* check_index && apply */
|
||||
|
||||
/* These control cosmetic aspect of the output */
|
||||
int diffstat; /* just show a diffstat, and don't actually apply */
|
||||
int numstat; /* just show a numeric diffstat, and don't actually apply */
|
||||
int summary; /* just report creation, deletion, etc, and don't actually apply */
|
||||
|
||||
/* These boolean parameters control how the apply is done */
|
||||
int allow_overlap;
|
||||
int apply_in_reverse;
|
||||
int apply_with_reject;
|
||||
int no_add;
|
||||
int threeway;
|
||||
int unidiff_zero;
|
||||
int unsafe_paths;
|
||||
|
||||
/* Other non boolean parameters */
|
||||
const char *index_file;
|
||||
enum apply_verbosity apply_verbosity;
|
||||
const char *fake_ancestor;
|
||||
const char *patch_input_file;
|
||||
int line_termination;
|
||||
struct strbuf root;
|
||||
int p_value;
|
||||
int p_value_known;
|
||||
unsigned int p_context;
|
||||
|
||||
/* Exclude and include path parameters */
|
||||
struct string_list limit_by_name;
|
||||
int has_include;
|
||||
|
||||
/* Various "current state" */
|
||||
int linenr; /* current line number */
|
||||
struct string_list symlink_changes; /* we have to track symlinks */
|
||||
|
||||
/*
|
||||
* For "diff-stat" like behaviour, we keep track of the biggest change
|
||||
* we've seen, and the longest filename. That allows us to do simple
|
||||
* scaling.
|
||||
*/
|
||||
int max_change;
|
||||
int max_len;
|
||||
|
||||
/*
|
||||
* Records filenames that have been touched, in order to handle
|
||||
* the case where more than one patches touch the same file.
|
||||
*/
|
||||
struct string_list fn_table;
|
||||
|
||||
/*
|
||||
* This is to save reporting routines before using
|
||||
* set_error_routine() or set_warn_routine() to install muting
|
||||
* routines when in verbosity_silent mode.
|
||||
*/
|
||||
void (*saved_error_routine)(const char *err, va_list params);
|
||||
void (*saved_warn_routine)(const char *warn, va_list params);
|
||||
|
||||
/* These control whitespace errors */
|
||||
enum apply_ws_error_action ws_error_action;
|
||||
enum apply_ws_ignore ws_ignore_action;
|
||||
const char *whitespace_option;
|
||||
int whitespace_error;
|
||||
int squelch_whitespace_errors;
|
||||
int applied_after_fixing_ws;
|
||||
};
|
||||
|
||||
extern int apply_parse_options(int argc, const char **argv,
|
||||
struct apply_state *state,
|
||||
int *force_apply, int *options,
|
||||
const char * const *apply_usage);
|
||||
extern int init_apply_state(struct apply_state *state,
|
||||
const char *prefix,
|
||||
struct lock_file *lock_file);
|
||||
extern void clear_apply_state(struct apply_state *state);
|
||||
extern int check_apply_state(struct apply_state *state, int force_apply);
|
||||
|
||||
/*
|
||||
* Some aspects of the apply behavior are controlled by the following
|
||||
* bits in the "options" parameter passed to apply_all_patches().
|
||||
*/
|
||||
#define APPLY_OPT_INACCURATE_EOF (1<<0) /* accept inaccurate eof */
|
||||
#define APPLY_OPT_RECOUNT (1<<1) /* accept inaccurate line count */
|
||||
|
||||
extern int apply_all_patches(struct apply_state *state,
|
||||
int argc,
|
||||
const char **argv,
|
||||
int options);
|
||||
|
||||
#endif
|
71
builtin/am.c
71
builtin/am.c
|
@ -28,6 +28,7 @@
|
|||
#include "rerere.h"
|
||||
#include "prompt.h"
|
||||
#include "mailinfo.h"
|
||||
#include "apply.h"
|
||||
#include "string-list.h"
|
||||
|
||||
/**
|
||||
|
@ -1509,40 +1510,60 @@ static int parse_mail_rebase(struct am_state *state, const char *mail)
|
|||
*/
|
||||
static int run_apply(const struct am_state *state, const char *index_file)
|
||||
{
|
||||
struct child_process cp = CHILD_PROCESS_INIT;
|
||||
struct argv_array apply_paths = ARGV_ARRAY_INIT;
|
||||
struct argv_array apply_opts = ARGV_ARRAY_INIT;
|
||||
struct apply_state apply_state;
|
||||
int res, opts_left;
|
||||
static struct lock_file lock_file;
|
||||
int force_apply = 0;
|
||||
int options = 0;
|
||||
|
||||
cp.git_cmd = 1;
|
||||
if (init_apply_state(&apply_state, NULL, &lock_file))
|
||||
die("BUG: init_apply_state() failed");
|
||||
|
||||
if (index_file)
|
||||
argv_array_pushf(&cp.env_array, "GIT_INDEX_FILE=%s", index_file);
|
||||
argv_array_push(&apply_opts, "apply");
|
||||
argv_array_pushv(&apply_opts, state->git_apply_opts.argv);
|
||||
|
||||
opts_left = apply_parse_options(apply_opts.argc, apply_opts.argv,
|
||||
&apply_state, &force_apply, &options,
|
||||
NULL);
|
||||
|
||||
if (opts_left != 0)
|
||||
die("unknown option passed through to git apply");
|
||||
|
||||
if (index_file) {
|
||||
apply_state.index_file = index_file;
|
||||
apply_state.cached = 1;
|
||||
} else
|
||||
apply_state.check_index = 1;
|
||||
|
||||
/*
|
||||
* If we are allowed to fall back on 3-way merge, don't give false
|
||||
* errors during the initial attempt.
|
||||
*/
|
||||
if (state->threeway && !index_file) {
|
||||
cp.no_stdout = 1;
|
||||
cp.no_stderr = 1;
|
||||
if (state->threeway && !index_file)
|
||||
apply_state.apply_verbosity = verbosity_silent;
|
||||
|
||||
if (check_apply_state(&apply_state, force_apply))
|
||||
die("BUG: check_apply_state() failed");
|
||||
|
||||
argv_array_push(&apply_paths, am_path(state, "patch"));
|
||||
|
||||
res = apply_all_patches(&apply_state, apply_paths.argc, apply_paths.argv, options);
|
||||
|
||||
argv_array_clear(&apply_paths);
|
||||
argv_array_clear(&apply_opts);
|
||||
clear_apply_state(&apply_state);
|
||||
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
if (index_file) {
|
||||
/* Reload index as apply_all_patches() will have modified it. */
|
||||
discard_cache();
|
||||
read_cache_from(index_file);
|
||||
}
|
||||
|
||||
argv_array_push(&cp.args, "apply");
|
||||
|
||||
argv_array_pushv(&cp.args, state->git_apply_opts.argv);
|
||||
|
||||
if (index_file)
|
||||
argv_array_push(&cp.args, "--cached");
|
||||
else
|
||||
argv_array_push(&cp.args, "--index");
|
||||
|
||||
argv_array_push(&cp.args, am_path(state, "patch"));
|
||||
|
||||
if (run_command(&cp))
|
||||
return -1;
|
||||
|
||||
/* Reload index as git-apply will have modified it. */
|
||||
discard_cache();
|
||||
read_cache_from(index_file ? index_file : get_index_file());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
4861
builtin/apply.c
4861
builtin/apply.c
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -441,6 +441,9 @@ static inline int const_error(void)
|
|||
|
||||
extern void set_die_routine(NORETURN_PTR void (*routine)(const char *err, va_list params));
|
||||
extern void set_error_routine(void (*routine)(const char *err, va_list params));
|
||||
extern void (*get_error_routine(void))(const char *err, va_list params);
|
||||
extern void set_warn_routine(void (*routine)(const char *warn, va_list params));
|
||||
extern void (*get_warn_routine(void))(const char *warn, va_list params);
|
||||
extern void set_die_is_recursing_routine(int (*routine)(void));
|
||||
extern void set_error_handle(FILE *);
|
||||
|
||||
|
|
|
@ -68,7 +68,7 @@ test_expect_success C_LOCALE_OUTPUT 'apply detecting corrupt patch correctly' '
|
|||
sed -e "s/-CIT/xCIT/" <output >broken &&
|
||||
test_must_fail git apply --stat --summary broken 2>detected &&
|
||||
detected=$(cat detected) &&
|
||||
detected=$(expr "$detected" : "fatal.*at line \\([0-9]*\\)\$") &&
|
||||
detected=$(expr "$detected" : "error.*at line \\([0-9]*\\)\$") &&
|
||||
detected=$(sed -ne "${detected}p" broken) &&
|
||||
test "$detected" = xCIT
|
||||
'
|
||||
|
@ -77,7 +77,7 @@ test_expect_success C_LOCALE_OUTPUT 'apply detecting corrupt patch correctly' '
|
|||
git diff --binary | sed -e "s/-CIT/xCIT/" >broken &&
|
||||
test_must_fail git apply --stat --summary broken 2>detected &&
|
||||
detected=$(cat detected) &&
|
||||
detected=$(expr "$detected" : "fatal.*at line \\([0-9]*\\)\$") &&
|
||||
detected=$(expr "$detected" : "error.*at line \\([0-9]*\\)\$") &&
|
||||
detected=$(sed -ne "${detected}p" broken) &&
|
||||
test "$detected" = xCIT
|
||||
'
|
||||
|
|
|
@ -29,7 +29,7 @@ test_expect_success 'try to apply corrupted patch' '
|
|||
'
|
||||
|
||||
test_expect_success 'compare diagnostic; ensure file is still here' '
|
||||
echo "fatal: git diff header lacks filename information (line 4)" >expected &&
|
||||
echo "error: git diff header lacks filename information (line 4)" >expected &&
|
||||
test_path_is_file f &&
|
||||
test_cmp expected actual
|
||||
'
|
||||
|
|
15
usage.c
15
usage.c
|
@ -70,6 +70,21 @@ void set_error_routine(void (*routine)(const char *err, va_list params))
|
|||
error_routine = routine;
|
||||
}
|
||||
|
||||
void (*get_error_routine(void))(const char *err, va_list params)
|
||||
{
|
||||
return error_routine;
|
||||
}
|
||||
|
||||
void set_warn_routine(void (*routine)(const char *warn, va_list params))
|
||||
{
|
||||
warn_routine = routine;
|
||||
}
|
||||
|
||||
void (*get_warn_routine(void))(const char *warn, va_list params)
|
||||
{
|
||||
return warn_routine;
|
||||
}
|
||||
|
||||
void set_die_is_recursing_routine(int (*routine)(void))
|
||||
{
|
||||
die_is_recursing = routine;
|
||||
|
|
Загрузка…
Ссылка в новой задаче