Commit 985f5cdf7c9ae8bc5111941b0f9b9ebbca2c4cb2

Patrick Steinhardt 2019-06-27T08:41:16

config_file: split out function that reads entries from a buffer The `config_read` function currently performs both reading the on-disk config file as well as parsing the retrieved buffer contents. To optimize how we refresh our config entries from an in-memory buffer, we need to be able to directly parse buffers, though, without involving any on-disk files at all. Extract a new function `config_read_buffer` that sets up the parsing logic and then parses config entries from a buffer, only. Have `config_read` use it to avoid duplicated logic.

diff --git a/src/config_file.c b/src/config_file.c
index 91fce1c..77edf13 100644
--- a/src/config_file.c
+++ b/src/config_file.c
@@ -62,6 +62,7 @@ typedef struct {
 } diskfile_parse_state;
 
 static int config_read(git_config_entries *entries, const git_repository *repo, git_config_file *file, git_config_level_t level, int depth);
+static int config_read_buffer(git_config_entries *entries, const git_repository *repo, git_config_file *file, git_config_level_t level, int depth, const char *buf, size_t buflen);
 static int config_write(diskfile_backend *cfg, const char *orig_key, const char *key, const p_regex_t *preg, const char *value);
 static char *escape_value(const char *ptr);
 
@@ -845,17 +846,17 @@ static int read_on_variable(
 	return result;
 }
 
-static int config_read(
+static int config_read_buffer(
 	git_config_entries *entries,
 	const git_repository *repo,
 	git_config_file *file,
 	git_config_level_t level,
-	int depth)
+	int depth,
+	const char *buf,
+	size_t buflen)
 {
 	diskfile_parse_state parse_data;
 	git_config_parser reader;
-	git_buf contents = GIT_BUF_INIT;
-	struct stat st;
 	int error;
 
 	if (depth >= MAX_INCLUDE_DEPTH) {
@@ -863,27 +864,15 @@ static int config_read(
 		return -1;
 	}
 
-	if (p_stat(file->path, &st) < 0) {
-		error = git_path_set_error(errno, file->path, "stat");
-		goto out;
-	}
-
-	if ((error = git_futils_readbuffer(&contents, file->path)) < 0)
-		goto out;
-
-	git_parse_ctx_init(&reader.ctx, contents.ptr, contents.size);
-
-	git_futils_filestamp_set_from_stat(&file->stamp, &st);
-	if ((error = git_hash_buf(&file->checksum, contents.ptr, contents.size)) < 0)
-		goto out;
-
 	/* Initialize the reading position */
 	reader.file = file;
-	git_parse_ctx_init(&reader.ctx, contents.ptr, contents.size);
+	git_parse_ctx_init(&reader.ctx, buf, buflen);
 
 	/* If the file is empty, there's nothing for us to do */
-	if (!reader.ctx.content || *reader.ctx.content == '\0')
+	if (!reader.ctx.content || *reader.ctx.content == '\0') {
+		error = 0;
 		goto out;
+	}
 
 	parse_data.repo = repo;
 	parse_data.file_path = file->path;
@@ -894,6 +883,37 @@ static int config_read(
 	error = git_config_parse(&reader, NULL, read_on_variable, NULL, NULL, &parse_data);
 
 out:
+	return error;
+}
+
+static int config_read(
+	git_config_entries *entries,
+	const git_repository *repo,
+	git_config_file *file,
+	git_config_level_t level,
+	int depth)
+{
+	git_buf contents = GIT_BUF_INIT;
+	struct stat st;
+	int error;
+
+	if (p_stat(file->path, &st) < 0) {
+		error = git_path_set_error(errno, file->path, "stat");
+		goto out;
+	}
+
+	if ((error = git_futils_readbuffer(&contents, file->path)) < 0)
+		goto out;
+
+	git_futils_filestamp_set_from_stat(&file->stamp, &st);
+	if ((error = git_hash_buf(&file->checksum, contents.ptr, contents.size)) < 0)
+		goto out;
+
+	if ((error = config_read_buffer(entries, repo, file, level, depth,
+					contents.ptr, contents.size)) < 0)
+		goto out;
+
+out:
 	git_buf_dispose(&contents);
 	return error;
 }