builtin/apply: introduce 'struct apply_state' to start libifying

Currently commands that want to use the apply functionality have to launch a "git apply" process which can be bad for performance. Let's start libifying the apply functionality and to do that we first need to get rid of the global variables in "builtin/apply.c". This patch introduces "struct apply_state" into which all the previously global variables will be moved. A new parameter called "state" that is a pointer to the "apply_state" structure will come at the beginning of the helper functions that need it and will be passed around the call chain. To start let's move the "prefix" and "prefix_length" global variables into "struct apply_state". Reviewed-by: Stefan Beller <sbeller@google.com> Signed-off-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Christian Couder committed May 11, 2016 at 15:16 UTC 2fc0f1849bd0d6100719bb53f89f15fbd734157a
1 file changed +56 -38
builtin/apply.c
+56 -38
@@ -21,6 +21,11 @@
21 #include "ll-merge.h"
22 #include "rerere.h"
23
24 +struct apply_state {
25 + const char *prefix;
26 + int prefix_length;
27 +};
28 +
29 /*
30 * --check turns on checking that the working tree matches the
31 * files that are being modified, but doesn't apply the patch
@@ -30,8 +35,6 @@
35 * --index updates the cache as well.
36 * --cached updates only the cache without ever touching the working tree.
37 */
33 -static const char *prefix;
34 -static int prefix_length = -1;
38 static int newfd = -1;
39
40 static int unidiff_zero;
@@ -748,7 +751,7 @@ static int count_slashes(const char *cp)
751 * Given the string after "--- " or "+++ ", guess the appropriate
752 * p_value for the given patch.
753 */
751 -static int guess_p_value(const char *nameline)
754 +static int guess_p_value(struct apply_state *state, const char *nameline)
755 {
756 char *name, *cp;
757 int val = -1;
@@ -761,17 +764,17 @@ static int guess_p_value(const char *nameline)
764 cp = strchr(name, '/');
765 if (!cp)
766 val = 0;
764 - else if (prefix) {
767 + else if (state->prefix) {
768 /*
769 * Does it begin with "a/$our-prefix" and such? Then this is
770 * very likely to apply to our directory.
771 */
769 - if (!strncmp(name, prefix, prefix_length))
770 - val = count_slashes(prefix);
772 + if (!strncmp(name, state->prefix, state->prefix_length))
773 + val = count_slashes(state->prefix);
774 else {
775 cp++;
773 - if (!strncmp(cp, prefix, prefix_length))
774 - val = count_slashes(prefix) + 1;
776 + if (!strncmp(cp, state->prefix, state->prefix_length))
777 + val = count_slashes(state->prefix) + 1;
778 }
779 }
780 free(name);
@@ -858,7 +861,10 @@ static int has_epoch_timestamp(const char *nameline)
861 * files, we can happily check the index for a match, but for creating a
862 * new file we should try to match whatever "patch" does. I have no idea.
863 */
861 -static void parse_traditional_patch(const char *first, const char *second, struct patch *patch)
864 +static void parse_traditional_patch(struct apply_state *state,
865 + const char *first,
866 + const char *second,
867 + struct patch *patch)
868 {
869 char *name;
870
@@ -866,8 +872,8 @@ static void parse_traditional_patch(const char *first, const char *second, struc
872 second += 4; /* skip "+++ " */
873 if (!p_value_known) {
874 int p, q;
869 - p = guess_p_value(first);
870 - q = guess_p_value(second);
875 + p = guess_p_value(state, first);
876 + q = guess_p_value(state, second);
877 if (p < 0) p = q;
878 if (0 <= p && p == q) {
879 state_p_value = p;
@@ -1429,7 +1435,11 @@ static int parse_fragment_header(const char *line, int len, struct fragment *fra
1435 return offset;
1436 }
1437
1432 -static int find_header(const char *line, unsigned long size, int *hdrsize, struct patch *patch)
1438 +static int find_header(struct apply_state *state,
1439 + const char *line,
1440 + unsigned long size,
1441 + int *hdrsize,
1442 + struct patch *patch)
1443 {
1444 unsigned long offset, len;
1445
@@ -1506,7 +1516,7 @@ static int find_header(const char *line, unsigned long size, int *hdrsize, struc
1516 continue;
1517
1518 /* Ok, we'll consider it a patch */
1509 - parse_traditional_patch(line, line+len, patch);
1519 + parse_traditional_patch(state, line, line+len, patch);
1520 *hdrsize = len + nextlen;
1521 state_linenr += 2;
1522 return offset;
@@ -1913,21 +1923,21 @@ static int parse_binary(char *buffer, unsigned long size, struct patch *patch)
1923 return used;
1924 }
1925
1916 -static void prefix_one(char **name)
1926 +static void prefix_one(struct apply_state *state, char **name)
1927 {
1928 char *old_name = *name;
1929 if (!old_name)
1930 return;
1921 - *name = xstrdup(prefix_filename(prefix, prefix_length, *name));
1931 + *name = xstrdup(prefix_filename(state->prefix, state->prefix_length, *name));
1932 free(old_name);
1933 }
1934
1925 -static void prefix_patch(struct patch *p)
1935 +static void prefix_patch(struct apply_state *state, struct patch *p)
1936 {
1927 - if (!prefix || p->is_toplevel_relative)
1937 + if (!state->prefix || p->is_toplevel_relative)
1938 return;
1929 - prefix_one(&p->new_name);
1930 - prefix_one(&p->old_name);
1939 + prefix_one(state, &p->new_name);
1940 + prefix_one(state, &p->old_name);
1941 }
1942
1943 /*
@@ -1944,16 +1954,16 @@ static void add_name_limit(const char *name, int exclude)
1954 it->util = exclude ? NULL : (void *) 1;
1955 }
1956
1947 -static int use_patch(struct patch *p)
1957 +static int use_patch(struct apply_state *state, struct patch *p)
1958 {
1959 const char *pathname = p->new_name ? p->new_name : p->old_name;
1960 int i;
1961
1962 /* Paths outside are not touched regardless of "--include" */
1953 - if (0 < prefix_length) {
1963 + if (0 < state->prefix_length) {
1964 int pathlen = strlen(pathname);
1955 - if (pathlen <= prefix_length ||
1956 - memcmp(prefix, pathname, prefix_length))
1965 + if (pathlen <= state->prefix_length ||
1966 + memcmp(state->prefix, pathname, state->prefix_length))
1967 return 0;
1968 }
1969
@@ -1980,17 +1990,17 @@ static int use_patch(struct patch *p)
1990 * Return the number of bytes consumed, so that the caller can call us
1991 * again for the next patch.
1992 */
1983 -static int parse_chunk(char *buffer, unsigned long size, struct patch *patch)
1993 +static int parse_chunk(struct apply_state *state, char *buffer, unsigned long size, struct patch *patch)
1994 {
1995 int hdrsize, patchsize;
1986 - int offset = find_header(buffer, size, &hdrsize, patch);
1996 + int offset = find_header(state, buffer, size, &hdrsize, patch);
1997
1998 if (offset < 0)
1999 return offset;
2000
1991 - prefix_patch(patch);
2001 + prefix_patch(state, patch);
2002
1993 - if (!use_patch(patch))
2003 + if (!use_patch(state, patch))
2004 patch->ws_rule = 0;
2005 else
2006 patch->ws_rule = whitespace_rule(patch->new_name
@@ -4367,7 +4377,10 @@ static struct lock_file lock_file;
4377 #define INACCURATE_EOF (1<<0)
4378 #define RECOUNT (1<<1)
4379
4370 -static int apply_patch(int fd, const char *filename, int options)
4380 +static int apply_patch(struct apply_state *state,
4381 + int fd,
4382 + const char *filename,
4383 + int options)
4384 {
4385 size_t offset;
4386 struct strbuf buf = STRBUF_INIT; /* owns the patch text */
@@ -4384,14 +4397,14 @@ static int apply_patch(int fd, const char *filename, int options)
4397 patch = xcalloc(1, sizeof(*patch));
4398 patch->inaccurate_eof = !!(options & INACCURATE_EOF);
4399 patch->recount = !!(options & RECOUNT);
4387 - nr = parse_chunk(buf.buf + offset, buf.len - offset, patch);
4400 + nr = parse_chunk(state, buf.buf + offset, buf.len - offset, patch);
4401 if (nr < 0) {
4402 free_patch(patch);
4403 break;
4404 }
4405 if (apply_in_reverse)
4406 reverse_patches(patch);
4394 - if (use_patch(patch)) {
4407 + if (use_patch(state, patch)) {
4408 patch_stats(patch);
4409 *listp = patch;
4410 listp = &patch->next;
@@ -4517,6 +4530,7 @@ int cmd_apply(int argc, const char **argv, const char *prefix_)
4530 int force_apply = 0;
4531 int options = 0;
4532 int read_stdin = 1;
4533 + struct apply_state state;
4534
4535 const char *whitespace_option = NULL;
4536
@@ -4589,15 +4603,17 @@ int cmd_apply(int argc, const char **argv, const char *prefix_)
4603 OPT_END()
4604 };
4605
4592 - prefix = prefix_;
4593 - prefix_length = prefix ? strlen(prefix) : 0;
4606 + memset(&state, 0, sizeof(state));
4607 + state.prefix = prefix_;
4608 + state.prefix_length = state.prefix ? strlen(state.prefix) : 0;
4609 +
4610 git_apply_config();
4611 if (apply_default_whitespace)
4612 parse_whitespace_option(apply_default_whitespace);
4613 if (apply_default_ignorewhitespace)
4614 parse_ignorewhitespace_option(apply_default_ignorewhitespace);
4615
4600 - argc = parse_options(argc, argv, prefix, builtin_apply_options,
4616 + argc = parse_options(argc, argv, state.prefix, builtin_apply_options,
4617 apply_usage, 0);
4618
4619 if (apply_with_reject && threeway)
@@ -4628,23 +4644,25 @@ int cmd_apply(int argc, const char **argv, const char *prefix_)
4644 int fd;
4645
4646 if (!strcmp(arg, "-")) {
4631 - errs |= apply_patch(0, "<stdin>", options);
4647 + errs |= apply_patch(&state, 0, "<stdin>", options);
4648 read_stdin = 0;
4649 continue;
4634 - } else if (0 < prefix_length)
4635 - arg = prefix_filename(prefix, prefix_length, arg);
4650 + } else if (0 < state.prefix_length)
4651 + arg = prefix_filename(state.prefix,
4652 + state.prefix_length,
4653 + arg);
4654
4655 fd = open(arg, O_RDONLY);
4656 if (fd < 0)
4657 die_errno(_("can't open patch '%s'"), arg);
4658 read_stdin = 0;
4659 set_default_whitespace_mode(whitespace_option);
4642 - errs |= apply_patch(fd, arg, options);
4660 + errs |= apply_patch(&state, fd, arg, options);
4661 close(fd);
4662 }
4663 set_default_whitespace_mode(whitespace_option);
4664 if (read_stdin)
4647 - errs |= apply_patch(0, "<stdin>", options);
4665 + errs |= apply_patch(&state, 0, "<stdin>", options);
4666 if (whitespace_error) {
4667 if (squelch_whitespace_errors &&
4668 squelch_whitespace_errors < whitespace_error) {