git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v3 08/49] builtin/apply: introduce 'struct apply_state' to start libifying

From
Christian Couder <christian.couder@gmail.com>
Date
May 24, 2016, 08:10 UTC
Message-ID
<20160524081126.16973-9-chriscool@tuxfamily.org>
In-Reply-To
<20160524081126.16973-1-chriscool@tuxfamily.org>

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>
---
 builtin/apply.c | 94 ++++++++++++++++++++++++++++++++++-----------------------
 1 file changed, 56 insertions(+), 38 deletions(-)
diff --git a/builtin/apply.c b/builtin/apply.c
index c911e4e..ae068e7 100644
--- a/builtin/apply.c
+++ b/builtin/apply.c
@@ -21,6 +21,11 @@
 #include "ll-merge.h"
 #include "rerere.h"
 
+struct apply_state {
+	const char *prefix;
+	int prefix_length;
+};
+
 /*
  *  --check turns on checking that the working tree matches the
  *    files that are being modified, but doesn't apply the patch
@@ -30,8 +35,6 @@
  *  --index updates the cache as well.
  *  --cached updates only the cache without ever touching the working tree.
  */
-static const char *prefix;
-static int prefix_length = -1;
 static int newfd = -1;
 
 static int unidiff_zero;
@@ -748,7 +751,7 @@ static int count_slashes(const char *cp)
  * Given the string after "--- " or "+++ ", guess the appropriate
  * p_value for the given patch.
  */
-static int guess_p_value(const char *nameline)
+static int guess_p_value(struct apply_state *state, const char *nameline)
 {
 	char *name, *cp;
 	int val = -1;
@@ -761,17 +764,17 @@ static int guess_p_value(const char *nameline)
 	cp = strchr(name, '/');
 	if (!cp)
 		val = 0;
-	else if (prefix) {
+	else if (state->prefix) {
 		/*
 		 * Does it begin with "a/$our-prefix" and such?  Then this is
 		 * very likely to apply to our directory.
 		 */
-		if (!strncmp(name, prefix, prefix_length))
-			val = count_slashes(prefix);
+		if (!strncmp(name, state->prefix, state->prefix_length))
+			val = count_slashes(state->prefix);
 		else {
 			cp++;
-			if (!strncmp(cp, prefix, prefix_length))
-				val = count_slashes(prefix) + 1;
+			if (!strncmp(cp, state->prefix, state->prefix_length))
+				val = count_slashes(state->prefix) + 1;
 		}
 	}
 	free(name);
@@ -858,7 +861,10 @@ static int has_epoch_timestamp(const char *nameline)
  * files, we can happily check the index for a match, but for creating a
  * new file we should try to match whatever "patch" does. I have no idea.
  */
-static void parse_traditional_patch(const char *first, const char *second, struct patch *patch)
+static void parse_traditional_patch(struct apply_state *state,
+				    const char *first,
+				    const char *second,
+				    struct patch *patch)
 {
 	char *name;
 
@@ -866,8 +872,8 @@ static void parse_traditional_patch(const char *first, const char *second, struc
 	second += 4;	/* skip "+++ " */
 	if (!p_value_known) {
 		int p, q;
-		p = guess_p_value(first);
-		q = guess_p_value(second);
+		p = guess_p_value(state, first);
+		q = guess_p_value(state, second);
 		if (p < 0) p = q;
 		if (0 <= p && p == q) {
 			state_p_value = p;
@@ -1429,7 +1435,11 @@ static int parse_fragment_header(const char *line, int len, struct fragment *fra
 	return offset;
 }
 
-static int find_header(const char *line, unsigned long size, int *hdrsize, struct patch *patch)
+static int find_header(struct apply_state *state,
+		       const char *line,
+		       unsigned long size,
+		       int *hdrsize,
+		       struct patch *patch)
 {
 	unsigned long offset, len;
 
@@ -1506,7 +1516,7 @@ static int find_header(const char *line, unsigned long size, int *hdrsize, struc
 			continue;
 
 		/* Ok, we'll consider it a patch */
-		parse_traditional_patch(line, line+len, patch);
+		parse_traditional_patch(state, line, line+len, patch);
 		*hdrsize = len + nextlen;
 		state_linenr += 2;
 		return offset;
@@ -1913,21 +1923,21 @@ static int parse_binary(char *buffer, unsigned long size, struct patch *patch)
 	return used;
 }
 
-static void prefix_one(char **name)
+static void prefix_one(struct apply_state *state, char **name)
 {
 	char *old_name = *name;
 	if (!old_name)
 		return;
-	*name = xstrdup(prefix_filename(prefix, prefix_length, *name));
+	*name = xstrdup(prefix_filename(state->prefix, state->prefix_length, *name));
 	free(old_name);
 }
 
-static void prefix_patch(struct patch *p)
+static void prefix_patch(struct apply_state *state, struct patch *p)
 {
-	if (!prefix || p->is_toplevel_relative)
+	if (!state->prefix || p->is_toplevel_relative)
 		return;
-	prefix_one(&p->new_name);
-	prefix_one(&p->old_name);
+	prefix_one(state, &p->new_name);
+	prefix_one(state, &p->old_name);
 }
 
 /*
@@ -1944,16 +1954,16 @@ static void add_name_limit(const char *name, int exclude)
 	it->util = exclude ? NULL : (void *) 1;
 }
 
-static int use_patch(struct patch *p)
+static int use_patch(struct apply_state *state, struct patch *p)
 {
 	const char *pathname = p->new_name ? p->new_name : p->old_name;
 	int i;
 
 	/* Paths outside are not touched regardless of "--include" */
-	if (0 < prefix_length) {
+	if (0 < state->prefix_length) {
 		int pathlen = strlen(pathname);
-		if (pathlen <= prefix_length ||
-		    memcmp(prefix, pathname, prefix_length))
+		if (pathlen <= state->prefix_length ||
+		    memcmp(state->prefix, pathname, state->prefix_length))
 			return 0;
 	}
 
@@ -1980,17 +1990,17 @@ static int use_patch(struct patch *p)
  * Return the number of bytes consumed, so that the caller can call us
  * again for the next patch.
  */
-static int parse_chunk(char *buffer, unsigned long size, struct patch *patch)
+static int parse_chunk(struct apply_state *state, char *buffer, unsigned long size, struct patch *patch)
 {
 	int hdrsize, patchsize;
-	int offset = find_header(buffer, size, &hdrsize, patch);
+	int offset = find_header(state, buffer, size, &hdrsize, patch);
 
 	if (offset < 0)
 		return offset;
 
-	prefix_patch(patch);
+	prefix_patch(state, patch);
 
-	if (!use_patch(patch))
+	if (!use_patch(state, patch))
 		patch->ws_rule = 0;
 	else
 		patch->ws_rule = whitespace_rule(patch->new_name
@@ -4367,7 +4377,10 @@ static struct lock_file lock_file;
 #define INACCURATE_EOF	(1<<0)
 #define RECOUNT		(1<<1)
 
-static int apply_patch(int fd, const char *filename, int options)
+static int apply_patch(struct apply_state *state,
+		       int fd,
+		       const char *filename,
+		       int options)
 {
 	size_t offset;
 	struct strbuf buf = STRBUF_INIT; /* owns the patch text */
@@ -4384,14 +4397,14 @@ static int apply_patch(int fd, const char *filename, int options)
 		patch = xcalloc(1, sizeof(*patch));
 		patch->inaccurate_eof = !!(options & INACCURATE_EOF);
 		patch->recount =  !!(options & RECOUNT);
-		nr = parse_chunk(buf.buf + offset, buf.len - offset, patch);
+		nr = parse_chunk(state, buf.buf + offset, buf.len - offset, patch);
 		if (nr < 0) {
 			free_patch(patch);
 			break;
 		}
 		if (apply_in_reverse)
 			reverse_patches(patch);
-		if (use_patch(patch)) {
+		if (use_patch(state, patch)) {
 			patch_stats(patch);
 			*listp = patch;
 			listp = &patch->next;
@@ -4517,6 +4530,7 @@ int cmd_apply(int argc, const char **argv, const char *prefix_)
 	int force_apply = 0;
 	int options = 0;
 	int read_stdin = 1;
+	struct apply_state state;
 
 	const char *whitespace_option = NULL;
 
@@ -4589,15 +4603,17 @@ int cmd_apply(int argc, const char **argv, const char *prefix_)
 		OPT_END()
 	};
 
-	prefix = prefix_;
-	prefix_length = prefix ? strlen(prefix) : 0;
+	memset(&state, 0, sizeof(state));
+	state.prefix = prefix_;
+	state.prefix_length = state.prefix ? strlen(state.prefix) : 0;
+
 	git_apply_config();
 	if (apply_default_whitespace)
 		parse_whitespace_option(apply_default_whitespace);
 	if (apply_default_ignorewhitespace)
 		parse_ignorewhitespace_option(apply_default_ignorewhitespace);
 
-	argc = parse_options(argc, argv, prefix, builtin_apply_options,
+	argc = parse_options(argc, argv, state.prefix, builtin_apply_options,
 			apply_usage, 0);
 
 	if (apply_with_reject && threeway)
@@ -4628,23 +4644,25 @@ int cmd_apply(int argc, const char **argv, const char *prefix_)
 		int fd;
 
 		if (!strcmp(arg, "-")) {
-			errs |= apply_patch(0, "<stdin>", options);
+			errs |= apply_patch(&state, 0, "<stdin>", options);
 			read_stdin = 0;
 			continue;
-		} else if (0 < prefix_length)
-			arg = prefix_filename(prefix, prefix_length, arg);
+		} else if (0 < state.prefix_length)
+			arg = prefix_filename(state.prefix,
+					      state.prefix_length,
+					      arg);
 
 		fd = open(arg, O_RDONLY);
 		if (fd < 0)
 			die_errno(_("can't open patch '%s'"), arg);
 		read_stdin = 0;
 		set_default_whitespace_mode(whitespace_option);
-		errs |= apply_patch(fd, arg, options);
+		errs |= apply_patch(&state, fd, arg, options);
 		close(fd);
 	}
 	set_default_whitespace_mode(whitespace_option);
 	if (read_stdin)
-		errs |= apply_patch(0, "<stdin>", options);
+		errs |= apply_patch(&state, 0, "<stdin>", options);
 	if (whitespace_error) {
 		if (squelch_whitespace_errors &&
 		    squelch_whitespace_errors < whitespace_error) {
-- 
2.8.3.443.gaeee61e
Previous: Christian CouderNext: Christian Couder
Message 9 of 53 in “libify apply and use lib in am, part 1”
  1. 00/49 libify apply and use lib in am, part 1Christian Couder, May 24, 2016
  2. 01/49 builtin/apply: make gitdiff_verify_name() return voidChristian Couder, May 24, 2016
  3. 02/49 builtin/apply: avoid parameter shadowing 'p_value' globalChristian Couder, May 24, 2016
  4. 03/49 builtin/apply: avoid parameter shadowing 'linenr' globalChristian Couder, May 24, 2016
  5. 04/49 builtin/apply: avoid local variable shadowing 'len' parameterChristian Couder, May 24, 2016
  6. 05/49 builtin/apply: extract line_by_line_fuzzy_match() from match_fragment()Christian Couder, May 24, 2016
  7. 06/49 builtin/apply: move 'options' variable into cmd_apply()Christian Couder, May 24, 2016
  8. 07/49 builtin/apply: move 'read_stdin' global into cmd_apply()Christian Couder, May 24, 2016
  9. 08/49 builtin/apply: introduce 'struct apply_state' to start libifyingChristian Couder, May 24, 2016
  10. 09/49 builtin/apply: move 'state' init into init_apply_state()Christian Couder, May 24, 2016
  11. 10/49 builtin/apply: move 'unidiff_zero' global into 'struct apply_state'Christian Couder, May 24, 2016
  12. 11/49 builtin/apply: move 'check' global into 'struct apply_state'Christian Couder, May 24, 2016
  13. 12/49 builtin/apply: move 'check_index' global into 'struct apply_state'Christian Couder, May 24, 2016
  14. 13/49 builtin/apply: move 'apply_in_reverse' global into 'struct apply_state'Christian Couder, May 24, 2016
  15. 14/49 builtin/apply: move 'apply_with_reject' global into 'struct apply_state'Christian Couder, May 24, 2016
  16. 15/49 builtin/apply: move 'apply_verbosely' global into 'struct apply_state'Christian Couder, May 24, 2016
  17. 16/49 builtin/apply: move 'update_index' global into 'struct apply_state'Christian Couder, May 24, 2016
  18. 17/49 builtin/apply: move 'allow_overlap' global into 'struct apply_state'Christian Couder, May 24, 2016
  19. 18/49 builtin/apply: move 'cached' global into 'struct apply_state'Christian Couder, May 24, 2016
  20. 19/49 builtin/apply: move 'diffstat' global into 'struct apply_state'Christian Couder, May 24, 2016
  21. 20/49 builtin/apply: move 'numstat' global into 'struct apply_state'Christian Couder, May 24, 2016
  22. 21/49 builtin/apply: move 'summary' global into 'struct apply_state'Christian Couder, May 24, 2016
  23. 22/49 builtin/apply: move 'threeway' global into 'struct apply_state'Christian Couder, May 24, 2016
  24. 23/49 builtin/apply: move 'no_add' global into 'struct apply_state'Christian Couder, May 24, 2016
  25. 24/49 builtin/apply: move 'unsafe_paths' global into 'struct apply_state'Christian Couder, May 24, 2016
  26. 25/49 builtin/apply: move 'line_termination' global into 'struct apply_state'Christian Couder, May 24, 2016
  27. 26/49 builtin/apply: move 'fake_ancestor' global into 'struct apply_state'Christian Couder, May 24, 2016
  28. 27/49 builtin/apply: move 'p_context' global into 'struct apply_state'Christian Couder, May 24, 2016
  29. 28/49 builtin/apply: move 'apply' global into 'struct apply_state'Christian Couder, May 24, 2016
  30. 29/49 builtin/apply: move 'patch_input_file' global into 'struct apply_state'Christian Couder, May 24, 2016
  31. 30/49 builtin/apply: move 'limit_by_name' global into 'struct apply_state'Christian Couder, May 24, 2016
  32. 31/49 builtin/apply: move 'has_include' global into 'struct apply_state'Christian Couder, May 24, 2016
  33. 32/49 builtin/apply: move 'p_value' global into 'struct apply_state'Christian Couder, May 24, 2016
  34. 33/49 builtin/apply: move 'p_value_known' global into 'struct apply_state'Christian Couder, May 24, 2016
  35. 34/49 builtin/apply: move 'root' global into 'struct apply_state'Christian Couder, May 24, 2016
  36. 35/49 builtin/apply: move 'whitespace_error' global into 'struct apply_state'Christian Couder, May 24, 2016
  37. 36/49 builtin/apply: move 'whitespace_option' into 'struct apply_state'Christian Couder, May 24, 2016
  38. 37/49 builtin/apply: remove whitespace_option arg from set_default_whitespace_mode()Christian Couder, May 24, 2016
  39. 38/49 builtin/apply: move 'squelch_whitespace_errors' into 'struct apply_state'Christian Couder, May 24, 2016
  40. 39/49 builtin/apply: move 'applied_after_fixing_ws' into 'struct apply_state'Christian Couder, May 24, 2016
  41. 40/49 builtin/apply: move 'ws_error_action' into 'struct apply_state'Christian Couder, May 24, 2016
  42. 41/49 builtin/apply: move 'ws_ignore_action' into 'struct apply_state'Christian Couder, May 24, 2016
  43. 42/49 builtin/apply: move 'max_change' and 'max_len' into 'struct apply_state'Christian Couder, May 24, 2016
  44. 43/49 builtin/apply: move 'state_linenr' global into 'struct apply_state'Christian Couder, May 24, 2016
  45. 44/49 builtin/apply: move 'fn_table' global into 'struct apply_state'Christian Couder, May 24, 2016
  46. 45/49 builtin/apply: move 'symlink_changes' global into 'struct apply_state'Christian Couder, May 24, 2016
  47. 46/49 builtin/apply: move 'state' check into check_apply_state()Christian Couder, May 24, 2016
  48. 47/49 builtin/apply: move applying patches into apply_all_patches()Christian Couder, May 24, 2016
  49. 48/49 builtin/apply: move 'lock_file' global into 'struct apply_state'Christian Couder, May 24, 2016
  50. Junio C HamanoJun 1, 2016
  51. Christian CouderJun 3, 2016
  52. 49/49 builtin/apply: move 'newfd' global into 'struct apply_state'Christian Couder, May 24, 2016
  53. Christian CouderMay 24, 2016

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.