commit-graph: don't early exit(1) on e.g. "git status"
authorÆvar Arnfjörð Bjarmason <avarab@gmail.com>
Mon, 25 Mar 2019 12:08:30 +0000 (13:08 +0100)
committerJunio C Hamano <gitster@pobox.com>
Mon, 1 Apr 2019 03:14:50 +0000 (12:14 +0900)
Make the commit-graph loading code work as a library that returns an
error code instead of calling exit(1) when the commit-graph is
corrupt. This means that e.g. "status" will now report commit-graph
corruption as an "error: [...]" at the top of its output, but then
proceed to work normally.

This required splitting up the load_commit_graph_one() function so
that the code that deals with open()-ing and stat()-ing the graph can
now be called independently as open_commit_graph().

This is needed because "commit-graph verify" where the graph doesn't
exist isn't an error. See the third paragraph in
283e68c72f ("commit-graph: add 'verify' subcommand",
2018-06-27). There's a bug in that logic where we conflate the
intended ENOENT with other errno values (e.g. EACCES), but this change
doesn't address that. That'll be addressed in a follow-up change.

I'm then splitting most of the logic out of load_commit_graph_one()
into load_commit_graph_one_fd_st(), which allows for providing an
existing file descriptor and stat information to the loading
code. This isn't strictly needed, but it would be redundant and
confusing to open() and stat() the file twice for some of the
codepaths, this allows for calling open_commit_graph() followed by
load_commit_graph_one_fd_st(). The "graph_file" still needs to be
passed to that function for the the "graph file %s is too small" error
message.

This leaves load_commit_graph_one() unused by everything except the
internal prepare_commit_graph_one() function, so let's mark it as
"static". If someone needs it in the future we can remove the "static"
attribute. I could also rewrite its sole remaining
user ("prepare_commit_graph_one()") to use
load_commit_graph_one_fd_st() instead, but let's leave it at this.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Ramsay Jones <ramsay@ramsayjones.plus.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
builtin/commit-graph.c
commit-graph.c
commit-graph.h
t/t5318-commit-graph.sh
index 4ae502754c292d0e743ed8fbfdf9d5dda00d1dba..32bcc63427e6c449a436b1fef62a00d920b6355f 100644 (file)
@@ -42,6 +42,9 @@ static int graph_verify(int argc, const char **argv)
 {
        struct commit_graph *graph = NULL;
        char *graph_name;
+       int open_ok;
+       int fd;
+       struct stat st;
 
        static struct option builtin_commit_graph_verify_options[] = {
                OPT_STRING(0, "object-dir", &opts.obj_dir,
@@ -58,11 +61,14 @@ static int graph_verify(int argc, const char **argv)
                opts.obj_dir = get_object_directory();
 
        graph_name = get_commit_graph_filename(opts.obj_dir);
-       graph = load_commit_graph_one(graph_name);
+       open_ok = open_commit_graph(graph_name, &fd, &st);
+       if (!open_ok)
+               return 0;
+       graph = load_commit_graph_one_fd_st(graph_name, fd, &st);
        FREE_AND_NULL(graph_name);
 
        if (!graph)
-               return 0;
+               return 1;
 
        UNLEAK(graph);
        return verify_commit_graph(the_repository, graph);
@@ -72,6 +78,9 @@ static int graph_read(int argc, const char **argv)
 {
        struct commit_graph *graph = NULL;
        char *graph_name;
+       int open_ok;
+       int fd;
+       struct stat st;
 
        static struct option builtin_commit_graph_read_options[] = {
                OPT_STRING(0, "object-dir", &opts.obj_dir,
@@ -88,10 +97,14 @@ static int graph_read(int argc, const char **argv)
                opts.obj_dir = get_object_directory();
 
        graph_name = get_commit_graph_filename(opts.obj_dir);
-       graph = load_commit_graph_one(graph_name);
 
+       open_ok = open_commit_graph(graph_name, &fd, &st);
+       if (!open_ok)
+               die_errno(_("Could not open commit-graph '%s'"), graph_name);
+
+       graph = load_commit_graph_one_fd_st(graph_name, fd, &st);
        if (!graph)
-               die("graph file %s does not exist", graph_name);
+               return 1;
 
        FREE_AND_NULL(graph_name);
 
index f8201d888b9a26299b3c7b0eb7cc48ad546dd7f2..3acc032c1b59d0b35a9422319458613320ca60a5 100644 (file)
@@ -80,25 +80,31 @@ static int commit_graph_compatible(struct repository *r)
        return 1;
 }
 
-struct commit_graph *load_commit_graph_one(const char *graph_file)
+int open_commit_graph(const char *graph_file, int *fd, struct stat *st)
+{
+       *fd = git_open(graph_file);
+       if (*fd < 0)
+               return 0;
+       if (fstat(*fd, st)) {
+               close(*fd);
+               return 0;
+       }
+       return 1;
+}
+
+struct commit_graph *load_commit_graph_one_fd_st(const char *graph_file,
+                                                int fd, struct stat *st)
 {
        void *graph_map;
        size_t graph_size;
-       struct stat st;
        struct commit_graph *ret;
-       int fd = git_open(graph_file);
 
-       if (fd < 0)
-               return NULL;
-       if (fstat(fd, &st)) {
-               close(fd);
-               return NULL;
-       }
-       graph_size = xsize_t(st.st_size);
+       graph_size = xsize_t(st->st_size);
 
        if (graph_size < GRAPH_MIN_SIZE) {
                close(fd);
-               die(_("graph file %s is too small"), graph_file);
+               error(_("graph file %s is too small"), graph_file);
+               return NULL;
        }
        graph_map = xmmap(NULL, graph_size, PROT_READ, MAP_PRIVATE, fd, 0);
        ret = parse_commit_graph(graph_map, fd, graph_size);
@@ -106,7 +112,6 @@ struct commit_graph *load_commit_graph_one(const char *graph_file)
        if (!ret) {
                munmap(graph_map, graph_size);
                close(fd);
-               exit(1);
        }
 
        return ret;
@@ -269,6 +274,19 @@ struct commit_graph *parse_commit_graph(void *graph_map, int fd,
        return graph;
 }
 
+static struct commit_graph *load_commit_graph_one(const char *graph_file)
+{
+
+       struct stat st;
+       int fd;
+       int open_ok = open_commit_graph(graph_file, &fd, &st);
+
+       if (!open_ok)
+               return NULL;
+
+       return load_commit_graph_one_fd_st(graph_file, fd, &st);
+}
+
 static void prepare_commit_graph_one(struct repository *r, const char *obj_dir)
 {
        char *graph_name;
index 096d8bac340514916c852268ef37c7b97190799a..77cc739bc020a6dfd5425b39313ae7d6299b660c 100644 (file)
@@ -11,6 +11,7 @@
 struct commit;
 
 char *get_commit_graph_filename(const char *obj_dir);
+int open_commit_graph(const char *graph_file, int *fd, struct stat *st);
 
 /*
  * Given a commit struct, try to fill the commit struct info, including:
@@ -52,7 +53,8 @@ struct commit_graph {
        const unsigned char *chunk_extra_edges;
 };
 
-struct commit_graph *load_commit_graph_one(const char *graph_file);
+struct commit_graph *load_commit_graph_one_fd_st(const char *graph_file,
+                                                int fd, struct stat *st);
 
 struct commit_graph *parse_commit_graph(void *graph_map, int fd,
                                        size_t graph_size);
index b3f3e515fc011cdc5c3582f7fae38682570b7068..0d012f55e559e83823ff27235f60a83b1ba4c5fd 100755 (executable)
@@ -377,7 +377,7 @@ corrupt_graph_verify() {
        test_must_fail git commit-graph verify 2>test_err &&
        grep -v "^+" test_err >err &&
        test_i18ngrep "$grepstr" err &&
-       test_might_fail git status --short
+       git status --short
 }
 
 # usage: corrupt_graph_and_verify <position> <data> <string> [<zero_pos>]