{"thread":{"id":"56335","subject":"[PATCH v5 1/6] t6030-bisect-porcelain: add tests to control bisect run exit cases","startedAt":"2021-08-20T17:23:04Z","lastAt":"2021-08-26T16:46:30Z","messageCount":10,"participants":["Miriam Rubio","Johannes Schindelin","Miriam R."],"isPatch":true,"patchVersion":5,"patchTotal":6},"messages":[{"id":"433249","messageId":"20210820172148.2249-2-mirucam@gmail.com","threadId":"56335","inReplyTo":"20210820172148.2249-1-mirucam@gmail.com","subject":"[PATCH v5 1/6] t6030-bisect-porcelain: add tests to control bisect run exit cases","fromName":"Miriam Rubio","fromEmail":"mirucam@gmail.com","sentAt":"2021-08-20T17:21:43Z","receivedAt":"2021-08-20T17:23:04Z","isPatch":true,"sender":{"key":"mirucam@gmail.com","avatar":"https://avatars.githubusercontent.com/u/56339109?v=4"},"body":"There is a gap on bisect run test coverage related with error exits.\nAdd two tests to control these error cases.\n\nSigned-off-by: Miriam Rubio <mirucam@gmail.com>\n---\n t/t6030-bisect-porcelain.sh | 11 +++++++++++\n 1 file changed, 11 insertions(+)\n\ndiff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh\nindex a1baf4e451..e61b8143fd 100755\n--- a/t/t6030-bisect-porcelain.sh\n+++ b/t/t6030-bisect-porcelain.sh\n@@ -962,4 +962,15 @@ test_expect_success 'bisect handles annotated tags' '\n \tgrep \"$bad is the first bad commit\" output\n '\n \n+test_expect_success 'bisect run fails with exit code equals or greater than 128' '\n+\twrite_script test_script.sh <<-\\EOF &&\n+\texit 128 >/dev/null\n+\tEOF\n+\ttest_must_fail git bisect run ./test_script.sh > my_bisect_log.txt &&\n+\twrite_script test_script.sh <<-\\EOF &&\n+\texit 255 >/dev/null\n+\tEOF\n+\ttest_must_fail git bisect run ./test_script.sh >> my_bisect_log.txt\n+'\n+\n test_done\n-- \n2.29.2\n\n"},{"id":"433250","messageId":"20210820172148.2249-1-mirucam@gmail.com","threadId":"56335","inReplyTo":null,"subject":"[PATCH v5 0/6] Finish converting git bisect to C part 4","fromName":"Miriam Rubio","fromEmail":"mirucam@gmail.com","sentAt":"2021-08-20T17:21:42Z","receivedAt":"2021-08-20T17:23:05Z","isPatch":true,"sender":{"key":"mirucam@gmail.com","avatar":"https://avatars.githubusercontent.com/u/56339109?v=4"},"body":"These patches correspond to a fourth part of patch series \nof Outreachy project \"Finish converting `git bisect` from shell to C\" \nstarted by Pranit Bauva and Tanushree Tumane\n(https://public-inbox.org/git/pull.117.git.gitgitgadget@gmail.com) and\ncontinued by me.\n\nThis fourth part is formed by reimplementations of some `git bisect` \nsubcommands, addition of tests and removal of some temporary subcommands.\n\nThese patch series emails were generated from:\nhttps://gitlab.com/mirucam/git/commits/git-bisect-work-part4-v5.\n\nI would like to thank Johannes Schindelin, Bagas Sanjaya and \nChristian Couder for reviewing this patch series.\n\nSpecific changes\n----------------\n[1/6] t6030-bisect-porcelain: add tests to control bisect run exit cases\n* Add evaluation of error code 255 in test 'bisect run fails with exit \ncode equals or greater than 128'.\n* Remove test with error code smaller than 0.\n---\n\n[4/6] bisect--helper: reimplement `bisect_visualize()`shell function in C\n* Use strvec_push() instead of strvec_pushl().\n---\n\n[5/6] bisect--helper: reimplement `bisect_run` shell function in C\n* Add error message.\n* Remove exit variable.\n* Write contents of bisect_state() in BISECT_RUN file and show to user.\n---\n\nMiriam Rubio (3):\n  t6030-bisect-porcelain: add tests to control bisect run exit cases\n  t6030-bisect-porcelain: add test for bisect visualize\n  bisect--helper: retire `--bisect-next-check` subcommand\n\nPranit Bauva (2):\n  run-command: make `exists_in_PATH()` non-static\n  bisect--helper: reimplement `bisect_visualize()`shell function in C\n\nTanushree Tumane (1):\n  bisect--helper: reimplement `bisect_run` shell function in C\n\n builtin/bisect--helper.c    | 157 ++++++++++++++++++++++++++++++++++--\n git-bisect.sh               |  87 +-------------------\n run-command.c               |   2 +-\n run-command.h               |  12 +++\n t/t6030-bisect-porcelain.sh |  18 +++++\n 5 files changed, 182 insertions(+), 94 deletions(-)\n\n-- \n2.29.2\n\n"},{"id":"433251","messageId":"20210820172148.2249-3-mirucam@gmail.com","threadId":"56335","inReplyTo":"20210820172148.2249-1-mirucam@gmail.com","subject":"[PATCH v5 2/6] t6030-bisect-porcelain: add test for bisect visualize","fromName":"Miriam Rubio","fromEmail":"mirucam@gmail.com","sentAt":"2021-08-20T17:21:44Z","receivedAt":"2021-08-20T17:23:05Z","isPatch":true,"sender":{"key":"mirucam@gmail.com","avatar":"https://avatars.githubusercontent.com/u/56339109?v=4"},"body":"Add a test to control breakages in bisect visualize command.\n\nSigned-off-by: Miriam Rubio <mirucam@gmail.com>\n---\n t/t6030-bisect-porcelain.sh | 7 +++++++\n 1 file changed, 7 insertions(+)\n\ndiff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh\nindex e61b8143fd..f13eeac9ce 100755\n--- a/t/t6030-bisect-porcelain.sh\n+++ b/t/t6030-bisect-porcelain.sh\n@@ -973,4 +973,11 @@ test_expect_success 'bisect run fails with exit code equals or greater than 128'\n \ttest_must_fail git bisect run ./test_script.sh >> my_bisect_log.txt\n '\n \n+test_expect_success 'bisect visualize with a filename with dash and space' '\n+\techo \"My test line\" >> -hello\\ 2 &&\n+\tgit add -- -hello\\ 2 &&\n+\tgit commit --quiet -m \"Add test line\" -- -hello\\ 2 &&\n+\tgit bisect visualize -p -- -hello\\ 2 > my_bisect_log.txt\n+'\n+\n test_done\n-- \n2.29.2\n\n"},{"id":"433252","messageId":"20210820172148.2249-4-mirucam@gmail.com","threadId":"56335","inReplyTo":"20210820172148.2249-1-mirucam@gmail.com","subject":"[PATCH v5 3/6] run-command: make `exists_in_PATH()` non-static","fromName":"Miriam Rubio","fromEmail":"mirucam@gmail.com","sentAt":"2021-08-20T17:21:45Z","receivedAt":"2021-08-20T17:23:07Z","isPatch":true,"sender":{"key":"mirucam@gmail.com","avatar":"https://avatars.githubusercontent.com/u/56339109?v=4"},"body":"From: Pranit Bauva <pranit.bauva@gmail.com>\n\nRemoves the `static` keyword from `exists_in_PATH()` function\nand declares the function in `run-command.h` file.\nThe function will be used in bisect_visualize() in a later\ncommit.\n\nMentored by: Christian Couder <chriscool@tuxfamily.org>\nMentored by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\nSigned-off-by: Tanushree Tumane <tanushreetumane@gmail.com>\nSigned-off-by: Miriam Rubio <mirucam@gmail.com>\n---\n run-command.c |  2 +-\n run-command.h | 12 ++++++++++++\n 2 files changed, 13 insertions(+), 1 deletion(-)\n\ndiff --git a/run-command.c b/run-command.c\nindex f72e72cce7..390f46819f 100644\n--- a/run-command.c\n+++ b/run-command.c\n@@ -210,7 +210,7 @@ static char *locate_in_PATH(const char *file)\n \treturn NULL;\n }\n \n-static int exists_in_PATH(const char *file)\n+int exists_in_PATH(const char *file)\n {\n \tchar *r = locate_in_PATH(file);\n \tint found = r != NULL;\ndiff --git a/run-command.h b/run-command.h\nindex af1296769f..54d74b706f 100644\n--- a/run-command.h\n+++ b/run-command.h\n@@ -182,6 +182,18 @@ void child_process_clear(struct child_process *);\n \n int is_executable(const char *name);\n \n+/**\n+ * Search if a $PATH for a command exists.  This emulates the path search that\n+ * execvp would perform, without actually executing the command so it\n+ * can be used before fork() to prepare to run a command using\n+ * execve() or after execvp() to diagnose why it failed.\n+ *\n+ * The caller should ensure that file contains no directory separators.\n+ *\n+ * Returns 1 if it is found in $PATH or 0 if the command could not be found.\n+ */\n+int exists_in_PATH(const char *file);\n+\n /**\n  * Start a sub-process. Takes a pointer to a `struct child_process`\n  * that specifies the details and returns pipe FDs (if requested).\n-- \n2.29.2\n\n"},{"id":"433253","messageId":"20210820172148.2249-5-mirucam@gmail.com","threadId":"56335","inReplyTo":"20210820172148.2249-1-mirucam@gmail.com","subject":"[PATCH v5 4/6] bisect--helper: reimplement `bisect_visualize()`shell function in C","fromName":"Miriam Rubio","fromEmail":"mirucam@gmail.com","sentAt":"2021-08-20T17:21:46Z","receivedAt":"2021-08-20T17:23:10Z","isPatch":true,"sender":{"key":"mirucam@gmail.com","avatar":"https://avatars.githubusercontent.com/u/56339109?v=4"},"body":"From: Pranit Bauva <pranit.bauva@gmail.com>\n\nReimplement the `bisect_visualize()` shell function\nin C and also add `--bisect-visualize` subcommand to\n`git bisect--helper` to call it from git-bisect.sh.\n\nMentored-by: Christian Couder <chriscool@tuxfamily.org>\nMentored-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\nSigned-off-by: Tanushree Tumane <tanushreetumane@gmail.com>\nSigned-off-by: Miriam Rubio <mirucam@gmail.com>\n---\n builtin/bisect--helper.c | 48 +++++++++++++++++++++++++++++++++++++++-\n git-bisect.sh            | 25 +--------------------\n 2 files changed, 48 insertions(+), 25 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex f184eaeac6..1e118a966a 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -30,6 +30,7 @@ static const char * const git_bisect_helper_usage[] = {\n \tN_(\"git bisect--helper --bisect-state (good|old) [<rev>...]\"),\n \tN_(\"git bisect--helper --bisect-replay <filename>\"),\n \tN_(\"git bisect--helper --bisect-skip [(<rev>|<range>)...]\"),\n+\tN_(\"git bisect--helper --bisect-visualize\"),\n \tNULL\n };\n \n@@ -1036,6 +1037,44 @@ static enum bisect_error bisect_skip(struct bisect_terms *terms, const char **ar\n \treturn res;\n }\n \n+static int bisect_visualize(struct bisect_terms *terms, const char **argv, int argc)\n+{\n+\tstruct strvec args = STRVEC_INIT;\n+\tint flags = RUN_COMMAND_NO_STDIN, res = 0;\n+\tstruct strbuf sb = STRBUF_INIT;\n+\n+\tif (bisect_next_check(terms, NULL) != 0)\n+\t\treturn BISECT_FAILED;\n+\n+\tif (!argc) {\n+\t\tif ((getenv(\"DISPLAY\") || getenv(\"SESSIONNAME\") || getenv(\"MSYSTEM\") ||\n+\t\t     getenv(\"SECURITYSESSIONID\")) && exists_in_PATH(\"gitk\"))\n+\t\t\tstrvec_push(&args, \"gitk\");\n+\t\telse {\n+\t\t\tstrvec_push(&args, \"log\");\n+\t\t\tflags |= RUN_GIT_CMD;\n+\t\t}\n+\t} else {\n+\t\tif (argv[0][0] == '-') {\n+\t\t\tstrvec_push(&args, \"log\");\n+\t\t\tflags |= RUN_GIT_CMD;\n+\t\t} else if (strcmp(argv[0], \"tig\") && !starts_with(argv[0], \"git\"))\n+\t\t\tflags |= RUN_GIT_CMD;\n+\n+\t\tstrvec_pushv(&args, argv);\n+\t}\n+\n+\tstrvec_pushl(&args, \"--bisect\", \"--\", NULL);\n+\n+\tstrbuf_read_file(&sb, git_path_bisect_names(), 0);\n+\tsq_dequote_to_strvec(sb.buf, &args);\n+\tstrbuf_release(&sb);\n+\n+\tres = run_command_v_opt(args.v, flags);\n+\tstrvec_clear(&args);\n+\treturn res;\n+}\n+\n int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n {\n \tenum {\n@@ -1048,7 +1087,8 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tBISECT_STATE,\n \t\tBISECT_LOG,\n \t\tBISECT_REPLAY,\n-\t\tBISECT_SKIP\n+\t\tBISECT_SKIP,\n+\t\tBISECT_VISUALIZE,\n \t} cmdmode = 0;\n \tint res = 0, nolog = 0;\n \tstruct option options[] = {\n@@ -1070,6 +1110,8 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\t\t N_(\"replay the bisection process from the given file\"), BISECT_REPLAY),\n \t\tOPT_CMDMODE(0, \"bisect-skip\", &cmdmode,\n \t\t\t N_(\"skip some commits for checkout\"), BISECT_SKIP),\n+\t\tOPT_CMDMODE(0, \"bisect-visualize\", &cmdmode,\n+\t\t\t N_(\"visualize the bisection\"), BISECT_VISUALIZE),\n \t\tOPT_BOOL(0, \"no-log\", &nolog,\n \t\t\t N_(\"no log for BISECT_WRITE\")),\n \t\tOPT_END()\n@@ -1131,6 +1173,10 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tget_terms(&terms);\n \t\tres = bisect_skip(&terms, argv, argc);\n \t\tbreak;\n+\tcase BISECT_VISUALIZE:\n+\t\tget_terms(&terms);\n+\t\tres = bisect_visualize(&terms, argv, argc);\n+\t\tbreak;\n \tdefault:\n \t\tBUG(\"unknown subcommand %d\", cmdmode);\n \t}\ndiff --git a/git-bisect.sh b/git-bisect.sh\nindex 6a7afaea8d..95f7f3fb8c 100755\n--- a/git-bisect.sh\n+++ b/git-bisect.sh\n@@ -39,29 +39,6 @@ _x40=\"$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40\"\n TERM_BAD=bad\n TERM_GOOD=good\n \n-bisect_visualize() {\n-\tgit bisect--helper --bisect-next-check $TERM_GOOD $TERM_BAD fail || exit\n-\n-\tif test $# = 0\n-\tthen\n-\t\tif test -n \"${DISPLAY+set}${SESSIONNAME+set}${MSYSTEM+set}${SECURITYSESSIONID+set}\" &&\n-\t\t\ttype gitk >/dev/null 2>&1\n-\t\tthen\n-\t\t\tset gitk\n-\t\telse\n-\t\t\tset git log\n-\t\tfi\n-\telse\n-\t\tcase \"$1\" in\n-\t\tgit*|tig) ;;\n-\t\t-*)\tset git log \"$@\" ;;\n-\t\t*)\tset git \"$@\" ;;\n-\t\tesac\n-\tfi\n-\n-\teval '\"$@\"' --bisect -- $(cat \"$GIT_DIR/BISECT_NAMES\")\n-}\n-\n bisect_run () {\n \tgit bisect--helper --bisect-next-check $TERM_GOOD $TERM_BAD fail || exit\n \n@@ -152,7 +129,7 @@ case \"$#\" in\n \t\t# Not sure we want \"next\" at the UI level anymore.\n \t\tgit bisect--helper --bisect-next \"$@\" || exit ;;\n \tvisualize|view)\n-\t\tbisect_visualize \"$@\" ;;\n+\t\tgit bisect--helper --bisect-visualize \"$@\" || exit;;\n \treset)\n \t\tgit bisect--helper --bisect-reset \"$@\" ;;\n \treplay)\n-- \n2.29.2\n\n"},{"id":"433254","messageId":"20210820172148.2249-6-mirucam@gmail.com","threadId":"56335","inReplyTo":"20210820172148.2249-1-mirucam@gmail.com","subject":"[PATCH v5 5/6] bisect--helper: reimplement `bisect_run` shell function in C","fromName":"Miriam Rubio","fromEmail":"mirucam@gmail.com","sentAt":"2021-08-20T17:21:47Z","receivedAt":"2021-08-20T17:23:14Z","isPatch":true,"sender":{"key":"mirucam@gmail.com","avatar":"https://avatars.githubusercontent.com/u/56339109?v=4"},"body":"From: Tanushree Tumane <tanushreetumane@gmail.com>\n\nReimplement the `bisect_run()` shell function\nin C and also add `--bisect-run` subcommand to\n`git bisect--helper` to call it from git-bisect.sh.\n\nMentored-by: Christian Couder <chriscool@tuxfamily.org>\nSigned-off-by: Tanushree Tumane <tanushreetumane@gmail.com>\nSigned-off-by: Miriam Rubio <mirucam@gmail.com>\n---\n builtin/bisect--helper.c | 102 +++++++++++++++++++++++++++++++++++++++\n git-bisect.sh            |  62 +-----------------------\n 2 files changed, 103 insertions(+), 61 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 1e118a966a..8d33c809aa 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -18,6 +18,7 @@ static GIT_PATH_FUNC(git_path_bisect_log, \"BISECT_LOG\")\n static GIT_PATH_FUNC(git_path_head_name, \"head-name\")\n static GIT_PATH_FUNC(git_path_bisect_names, \"BISECT_NAMES\")\n static GIT_PATH_FUNC(git_path_bisect_first_parent, \"BISECT_FIRST_PARENT\")\n+static GIT_PATH_FUNC(git_path_bisect_run, \"BISECT_RUN\")\n \n static const char * const git_bisect_helper_usage[] = {\n \tN_(\"git bisect--helper --bisect-reset [<commit>]\"),\n@@ -31,6 +32,7 @@ static const char * const git_bisect_helper_usage[] = {\n \tN_(\"git bisect--helper --bisect-replay <filename>\"),\n \tN_(\"git bisect--helper --bisect-skip [(<rev>|<range>)...]\"),\n \tN_(\"git bisect--helper --bisect-visualize\"),\n+\tN_(\"git bisect--helper --bisect-run <cmd>...\"),\n \tNULL\n };\n \n@@ -144,6 +146,25 @@ static int append_to_file(const char *path, const char *format, ...)\n \treturn res;\n }\n \n+static int print_file_to_stdout(const char *path)\n+{\n+\tFILE *fp;\n+\tchar c;\n+\n+\tfp = fopen(path, \"r\");\n+\tif (!fp)\n+\t\treturn error_errno(_(\"cannot open file '%s' in read mode\"), path);\n+\n+\tc = fgetc(fp);\n+\twhile (c != EOF) {\n+\t\tprintf (\"%c\", c);\n+\t\tc = fgetc(fp);\n+\t}\n+\n+\tfclose(fp);\n+\treturn 0;\n+}\n+\n static int check_term_format(const char *term, const char *orig_term)\n {\n \tint res;\n@@ -1075,6 +1096,78 @@ static int bisect_visualize(struct bisect_terms *terms, const char **argv, int a\n \treturn res;\n }\n \n+static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n+{\n+\tint res = BISECT_OK;\n+\tstruct strbuf command = STRBUF_INIT;\n+\tstruct strvec args = STRVEC_INIT;\n+\tstruct strvec run_args = STRVEC_INIT;\n+\tconst char *new_state;\n+\tint temporary_stdout_fd, saved_stdout;\n+\n+\tif (bisect_next_check(terms, NULL))\n+\t\treturn BISECT_FAILED;\n+\n+\tif (argc)\n+\t\tsq_quote_argv(&command, argv);\n+\telse {\n+\t\terror(_(\"bisect run failed: no command provided.\"));\n+\t\treturn BISECT_FAILED;\n+\t}\n+\n+\tstrvec_push(&run_args, command.buf);\n+\n+\twhile (1) {\n+\t\tstrvec_clear(&args);\n+\n+\t\tprintf(_(\"running %s\\n\"), command.buf);\n+\t\tres = run_command_v_opt(run_args.v, RUN_USING_SHELL);\n+\n+\t\tif (res < 0 || 128 <= res) {\n+\t\t\terror(_(\"bisect run failed: exit code %d from\"\n+\t\t\t\t\" '%s' is < 0 or >= 128\"), res, command.buf);\n+\t\t\tstrbuf_release(&command);\n+\t\t\treturn res;\n+\t\t}\n+\n+\t\tif (res == 125)\n+\t\t\tnew_state = \"skip\";\n+\t\telse new_state = res > 0 ? terms->term_bad : terms->term_good;\n+\n+\t\ttemporary_stdout_fd = open(git_path_bisect_run(), O_CREAT | O_WRONLY | O_TRUNC, 0666);\n+\t\tsaved_stdout = dup(1);\n+\t\tdup2(temporary_stdout_fd, 1);\n+\n+\t\tres = bisect_state(terms, &new_state, 1);\n+\n+\t\tdup2(saved_stdout, 1);\n+\t\tclose(saved_stdout);\n+\t\tclose(temporary_stdout_fd);\n+\n+\t\tprint_file_to_stdout(git_path_bisect_run());\n+\n+\t\tif (res == BISECT_ONLY_SKIPPED_LEFT)\n+\t\t\terror(_(\"bisect run cannot continue any more\"));\n+\t\telse if (res == BISECT_INTERNAL_SUCCESS_MERGE_BASE) {\n+\t\t\tprintf(_(\"bisect run success\"));\n+\t\t\tres = BISECT_OK;\n+\t\t} else if (res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND) {\n+\t\t\tprintf(_(\"bisect found first bad commit\"));\n+\t\t\tres = BISECT_OK;\n+\t\t} else if (res) {\n+\t\t\terror(_(\"bisect run failed:'git bisect--helper --bisect-state\"\n+\t\t\t\" %s' exited with error code %d\"), args.v[0], res);\n+\t\t} else {\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tstrbuf_release(&command);\n+\t\tstrvec_clear(&args);\n+\t\tstrvec_clear(&run_args);\n+\t\treturn res;\n+\t}\n+}\n+\n int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n {\n \tenum {\n@@ -1089,6 +1182,7 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tBISECT_REPLAY,\n \t\tBISECT_SKIP,\n \t\tBISECT_VISUALIZE,\n+\t\tBISECT_RUN,\n \t} cmdmode = 0;\n \tint res = 0, nolog = 0;\n \tstruct option options[] = {\n@@ -1112,6 +1206,8 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\t\t N_(\"skip some commits for checkout\"), BISECT_SKIP),\n \t\tOPT_CMDMODE(0, \"bisect-visualize\", &cmdmode,\n \t\t\t N_(\"visualize the bisection\"), BISECT_VISUALIZE),\n+\t\tOPT_CMDMODE(0, \"bisect-run\", &cmdmode,\n+\t\t\t N_(\"use <cmd>... to automatically bisect.\"), BISECT_RUN),\n \t\tOPT_BOOL(0, \"no-log\", &nolog,\n \t\t\t N_(\"no log for BISECT_WRITE\")),\n \t\tOPT_END()\n@@ -1177,6 +1273,12 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tget_terms(&terms);\n \t\tres = bisect_visualize(&terms, argv, argc);\n \t\tbreak;\n+\tcase BISECT_RUN:\n+\t\tif (!argc)\n+\t\t\treturn error(_(\"bisect run failed: no command provided.\"));\n+\t\tget_terms(&terms);\n+\t\tres = bisect_run(&terms, argv, argc);\n+\t\tbreak;\n \tdefault:\n \t\tBUG(\"unknown subcommand %d\", cmdmode);\n \t}\ndiff --git a/git-bisect.sh b/git-bisect.sh\nindex 95f7f3fb8c..e83d011e17 100755\n--- a/git-bisect.sh\n+++ b/git-bisect.sh\n@@ -39,66 +39,6 @@ _x40=\"$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40\"\n TERM_BAD=bad\n TERM_GOOD=good\n \n-bisect_run () {\n-\tgit bisect--helper --bisect-next-check $TERM_GOOD $TERM_BAD fail || exit\n-\n-\ttest -n \"$*\" || die \"$(gettext \"bisect run failed: no command provided.\")\"\n-\n-\twhile true\n-\tdo\n-\t\tcommand=\"$@\"\n-\t\teval_gettextln \"running \\$command\"\n-\t\t\"$@\"\n-\t\tres=$?\n-\n-\t\t# Check for really bad run error.\n-\t\tif [ $res -lt 0 -o $res -ge 128 ]\n-\t\tthen\n-\t\t\teval_gettextln \"bisect run failed:\n-exit code \\$res from '\\$command' is < 0 or >= 128\" >&2\n-\t\t\texit $res\n-\t\tfi\n-\n-\t\t# Find current state depending on run success or failure.\n-\t\t# A special exit code of 125 means cannot test.\n-\t\tif [ $res -eq 125 ]\n-\t\tthen\n-\t\t\tstate='skip'\n-\t\telif [ $res -gt 0 ]\n-\t\tthen\n-\t\t\tstate=\"$TERM_BAD\"\n-\t\telse\n-\t\t\tstate=\"$TERM_GOOD\"\n-\t\tfi\n-\n-\t\tgit bisect--helper --bisect-state $state >\"$GIT_DIR/BISECT_RUN\"\n-\t\tres=$?\n-\n-\t\tcat \"$GIT_DIR/BISECT_RUN\"\n-\n-\t\tif sane_grep \"first $TERM_BAD commit could be any of\" \"$GIT_DIR/BISECT_RUN\" \\\n-\t\t\t>/dev/null\n-\t\tthen\n-\t\t\tgettextln \"bisect run cannot continue any more\" >&2\n-\t\t\texit $res\n-\t\tfi\n-\n-\t\tif [ $res -ne 0 ]\n-\t\tthen\n-\t\t\teval_gettextln \"bisect run failed:\n-'bisect-state \\$state' exited with error code \\$res\" >&2\n-\t\t\texit $res\n-\t\tfi\n-\n-\t\tif sane_grep \"is the first $TERM_BAD commit\" \"$GIT_DIR/BISECT_RUN\" >/dev/null\n-\t\tthen\n-\t\t\tgettextln \"bisect run success\"\n-\t\t\texit 0;\n-\t\tfi\n-\n-\tdone\n-}\n-\n get_terms () {\n \tif test -s \"$GIT_DIR/BISECT_TERMS\"\n \tthen\n@@ -137,7 +77,7 @@ case \"$#\" in\n \tlog)\n \t\tgit bisect--helper --bisect-log || exit ;;\n \trun)\n-\t\tbisect_run \"$@\" ;;\n+\t\tgit bisect--helper --bisect-run \"$@\" || exit;;\n \tterms)\n \t\tgit bisect--helper --bisect-terms \"$@\" || exit;;\n \t*)\n-- \n2.29.2\n\n"},{"id":"433255","messageId":"20210820172148.2249-7-mirucam@gmail.com","threadId":"56335","inReplyTo":"20210820172148.2249-1-mirucam@gmail.com","subject":"[PATCH v5 6/6] bisect--helper: retire `--bisect-next-check` subcommand","fromName":"Miriam Rubio","fromEmail":"mirucam@gmail.com","sentAt":"2021-08-20T17:21:48Z","receivedAt":"2021-08-20T17:23:15Z","isPatch":true,"sender":{"key":"mirucam@gmail.com","avatar":"https://avatars.githubusercontent.com/u/56339109?v=4"},"body":"After reimplementation of `git bisect run` in C,\n`--bisect-next-check` subcommand is not needed anymore.\n\nLet's remove it from options list and code.\n\nMentored by: Christian Couder <chriscool@tuxfamily.org>\nSigned-off-by: Miriam Rubio <mirucam@gmail.com>\n---\n builtin/bisect--helper.c | 7 -------\n 1 file changed, 7 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 8d33c809aa..6e1e7c243d 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -22,7 +22,6 @@ static GIT_PATH_FUNC(git_path_bisect_run, \"BISECT_RUN\")\n \n static const char * const git_bisect_helper_usage[] = {\n \tN_(\"git bisect--helper --bisect-reset [<commit>]\"),\n-\tN_(\"git bisect--helper --bisect-next-check <good_term> <bad_term> [<term>]\"),\n \tN_(\"git bisect--helper --bisect-terms [--term-good | --term-old | --term-bad | --term-new]\"),\n \tN_(\"git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}=<term>]\"\n \t\t\t\t\t    \" [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]\"),\n@@ -1227,12 +1226,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\t\treturn error(_(\"--bisect-reset requires either no argument or a commit\"));\n \t\tres = bisect_reset(argc ? argv[0] : NULL);\n \t\tbreak;\n-\tcase BISECT_NEXT_CHECK:\n-\t\tif (argc != 2 && argc != 3)\n-\t\t\treturn error(_(\"--bisect-next-check requires 2 or 3 arguments\"));\n-\t\tset_terms(&terms, argv[1], argv[0]);\n-\t\tres = bisect_next_check(&terms, argc == 3 ? argv[2] : NULL);\n-\t\tbreak;\n \tcase BISECT_TERMS:\n \t\tif (argc > 1)\n \t\t\treturn error(_(\"--bisect-terms requires 0 or 1 argument\"));\n-- \n2.29.2\n\n"},{"id":"433551","messageId":"nycvar.QRO.7.76.6.2108241541190.55@tvgsbejvaqbjf.bet","threadId":"56335","inReplyTo":"20210820172148.2249-6-mirucam@gmail.com","subject":"Re: [PATCH v5 5/6] bisect--helper: reimplement `bisect_run` shell function in C","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2021-08-24T13:59:19Z","receivedAt":"2021-08-24T13:59:24Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Miriam,\n\nOn Fri, 20 Aug 2021, Miriam Rubio wrote:\n\n> From: Tanushree Tumane <tanushreetumane@gmail.com>\n>\n> Reimplement the `bisect_run()` shell function\n> in C and also add `--bisect-run` subcommand to\n> `git bisect--helper` to call it from git-bisect.sh.\n>\n> Mentored-by: Christian Couder <chriscool@tuxfamily.org>\n> Signed-off-by: Tanushree Tumane <tanushreetumane@gmail.com>\n> Signed-off-by: Miriam Rubio <mirucam@gmail.com>\n> ---\n>  builtin/bisect--helper.c | 102 +++++++++++++++++++++++++++++++++++++++\n>  git-bisect.sh            |  62 +-----------------------\n>  2 files changed, 103 insertions(+), 61 deletions(-)\n>\n> diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\n> index 1e118a966a..8d33c809aa 100644\n> --- a/builtin/bisect--helper.c\n> +++ b/builtin/bisect--helper.c\n> @@ -18,6 +18,7 @@ static GIT_PATH_FUNC(git_path_bisect_log, \"BISECT_LOG\")\n>  static GIT_PATH_FUNC(git_path_head_name, \"head-name\")\n>  static GIT_PATH_FUNC(git_path_bisect_names, \"BISECT_NAMES\")\n>  static GIT_PATH_FUNC(git_path_bisect_first_parent, \"BISECT_FIRST_PARENT\")\n> +static GIT_PATH_FUNC(git_path_bisect_run, \"BISECT_RUN\")\n>\n>  static const char * const git_bisect_helper_usage[] = {\n>  \tN_(\"git bisect--helper --bisect-reset [<commit>]\"),\n> @@ -31,6 +32,7 @@ static const char * const git_bisect_helper_usage[] = {\n>  \tN_(\"git bisect--helper --bisect-replay <filename>\"),\n>  \tN_(\"git bisect--helper --bisect-skip [(<rev>|<range>)...]\"),\n>  \tN_(\"git bisect--helper --bisect-visualize\"),\n> +\tN_(\"git bisect--helper --bisect-run <cmd>...\"),\n>  \tNULL\n>  };\n>\n> @@ -144,6 +146,25 @@ static int append_to_file(const char *path, const char *format, ...)\n>  \treturn res;\n>  }\n>\n> +static int print_file_to_stdout(const char *path)\n> +{\n> +\tFILE *fp;\n> +\tchar c;\n> +\n> +\tfp = fopen(path, \"r\");\n> +\tif (!fp)\n> +\t\treturn error_errno(_(\"cannot open file '%s' in read mode\"), path);\n> +\n> +\tc = fgetc(fp);\n> +\twhile (c != EOF) {\n> +\t\tprintf (\"%c\", c);\n> +\t\tc = fgetc(fp);\n> +\t}\n> +\n> +\tfclose(fp);\n\nRather than reading byte for byte (even if buffered), how about using\n`copy_fd()`? Something like\n\n\tint fd = open(path, O_RDONLY), ret = 0;\n\n\tif (fd < 0)\n\t\treturn error_errno(_(\"cannot open file '%s' for reading\"), path);\n\tif (copy_fd(fd, 1) < 0)\n\t\tret = error_errno(_(\"failed to read '%s'\"), path);\n\tclose(fd);\n\treturn ret;\n\n> +\treturn 0;\n> +}\n> +\n>  static int check_term_format(const char *term, const char *orig_term)\n>  {\n>  \tint res;\n> @@ -1075,6 +1096,78 @@ static int bisect_visualize(struct bisect_terms *terms, const char **argv, int a\n>  \treturn res;\n>  }\n>\n> +static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n> +{\n> +\tint res = BISECT_OK;\n> +\tstruct strbuf command = STRBUF_INIT;\n> +\tstruct strvec args = STRVEC_INIT;\n> +\tstruct strvec run_args = STRVEC_INIT;\n> +\tconst char *new_state;\n> +\tint temporary_stdout_fd, saved_stdout;\n> +\n> +\tif (bisect_next_check(terms, NULL))\n> +\t\treturn BISECT_FAILED;\n> +\n> +\tif (argc)\n> +\t\tsq_quote_argv(&command, argv);\n> +\telse {\n> +\t\terror(_(\"bisect run failed: no command provided.\"));\n> +\t\treturn BISECT_FAILED;\n> +\t}\n> +\n> +\tstrvec_push(&run_args, command.buf);\n> +\n> +\twhile (1) {\n> +\t\tstrvec_clear(&args);\n> +\n> +\t\tprintf(_(\"running %s\\n\"), command.buf);\n> +\t\tres = run_command_v_opt(run_args.v, RUN_USING_SHELL);\n> +\n> +\t\tif (res < 0 || 128 <= res) {\n> +\t\t\terror(_(\"bisect run failed: exit code %d from\"\n> +\t\t\t\t\" '%s' is < 0 or >= 128\"), res, command.buf);\n> +\t\t\tstrbuf_release(&command);\n> +\t\t\treturn res;\n> +\t\t}\n> +\n> +\t\tif (res == 125)\n> +\t\t\tnew_state = \"skip\";\n> +\t\telse new_state = res > 0 ? terms->term_bad : terms->term_good;\n\nI do not care _all_ that much about formatting, but I think others on this\nlist do, and might point out that the `else` wants to live on its own\nline.\n\n> +\t\ttemporary_stdout_fd = open(git_path_bisect_run(), O_CREAT | O_WRONLY | O_TRUNC, 0666);\n> +\t\tsaved_stdout = dup(1);\n> +\t\tdup2(temporary_stdout_fd, 1);\n\nThis temporary redirection looks a bit iffy. I wonder whether there is a\nway to tell `bisect_state()` to print to a given file descriptor, _in\naddition to_ `stdout`? That would also make `print_file_to_stdout()`\nobsolete.\n\nWhat calls exactly are making that print to `stdout` anyway?\n\nThis is my only remaining issue with the current 5/6.\n\nThank you,\nDscho\n\n> +\n> +\t\tres = bisect_state(terms, &new_state, 1);\n> +\n> +\t\tdup2(saved_stdout, 1);\n> +\t\tclose(saved_stdout);\n> +\t\tclose(temporary_stdout_fd);\n> +\n> +\t\tprint_file_to_stdout(git_path_bisect_run());\n> +\n> +\t\tif (res == BISECT_ONLY_SKIPPED_LEFT)\n> +\t\t\terror(_(\"bisect run cannot continue any more\"));\n> +\t\telse if (res == BISECT_INTERNAL_SUCCESS_MERGE_BASE) {\n> +\t\t\tprintf(_(\"bisect run success\"));\n> +\t\t\tres = BISECT_OK;\n> +\t\t} else if (res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND) {\n> +\t\t\tprintf(_(\"bisect found first bad commit\"));\n> +\t\t\tres = BISECT_OK;\n> +\t\t} else if (res) {\n> +\t\t\terror(_(\"bisect run failed:'git bisect--helper --bisect-state\"\n> +\t\t\t\" %s' exited with error code %d\"), args.v[0], res);\n> +\t\t} else {\n> +\t\t\tcontinue;\n> +\t\t}\n> +\n> +\t\tstrbuf_release(&command);\n> +\t\tstrvec_clear(&args);\n> +\t\tstrvec_clear(&run_args);\n> +\t\treturn res;\n> +\t}\n> +}\n> +\n>  int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n>  {\n>  \tenum {\n> @@ -1089,6 +1182,7 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n>  \t\tBISECT_REPLAY,\n>  \t\tBISECT_SKIP,\n>  \t\tBISECT_VISUALIZE,\n> +\t\tBISECT_RUN,\n>  \t} cmdmode = 0;\n>  \tint res = 0, nolog = 0;\n>  \tstruct option options[] = {\n> @@ -1112,6 +1206,8 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n>  \t\t\t N_(\"skip some commits for checkout\"), BISECT_SKIP),\n>  \t\tOPT_CMDMODE(0, \"bisect-visualize\", &cmdmode,\n>  \t\t\t N_(\"visualize the bisection\"), BISECT_VISUALIZE),\n> +\t\tOPT_CMDMODE(0, \"bisect-run\", &cmdmode,\n> +\t\t\t N_(\"use <cmd>... to automatically bisect.\"), BISECT_RUN),\n>  \t\tOPT_BOOL(0, \"no-log\", &nolog,\n>  \t\t\t N_(\"no log for BISECT_WRITE\")),\n>  \t\tOPT_END()\n> @@ -1177,6 +1273,12 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n>  \t\tget_terms(&terms);\n>  \t\tres = bisect_visualize(&terms, argv, argc);\n>  \t\tbreak;\n> +\tcase BISECT_RUN:\n> +\t\tif (!argc)\n> +\t\t\treturn error(_(\"bisect run failed: no command provided.\"));\n> +\t\tget_terms(&terms);\n> +\t\tres = bisect_run(&terms, argv, argc);\n> +\t\tbreak;\n>  \tdefault:\n>  \t\tBUG(\"unknown subcommand %d\", cmdmode);\n>  \t}\n> diff --git a/git-bisect.sh b/git-bisect.sh\n> index 95f7f3fb8c..e83d011e17 100755\n> --- a/git-bisect.sh\n> +++ b/git-bisect.sh\n> @@ -39,66 +39,6 @@ _x40=\"$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40\"\n>  TERM_BAD=bad\n>  TERM_GOOD=good\n>\n> -bisect_run () {\n> -\tgit bisect--helper --bisect-next-check $TERM_GOOD $TERM_BAD fail || exit\n> -\n> -\ttest -n \"$*\" || die \"$(gettext \"bisect run failed: no command provided.\")\"\n> -\n> -\twhile true\n> -\tdo\n> -\t\tcommand=\"$@\"\n> -\t\teval_gettextln \"running \\$command\"\n> -\t\t\"$@\"\n> -\t\tres=$?\n> -\n> -\t\t# Check for really bad run error.\n> -\t\tif [ $res -lt 0 -o $res -ge 128 ]\n> -\t\tthen\n> -\t\t\teval_gettextln \"bisect run failed:\n> -exit code \\$res from '\\$command' is < 0 or >= 128\" >&2\n> -\t\t\texit $res\n> -\t\tfi\n> -\n> -\t\t# Find current state depending on run success or failure.\n> -\t\t# A special exit code of 125 means cannot test.\n> -\t\tif [ $res -eq 125 ]\n> -\t\tthen\n> -\t\t\tstate='skip'\n> -\t\telif [ $res -gt 0 ]\n> -\t\tthen\n> -\t\t\tstate=\"$TERM_BAD\"\n> -\t\telse\n> -\t\t\tstate=\"$TERM_GOOD\"\n> -\t\tfi\n> -\n> -\t\tgit bisect--helper --bisect-state $state >\"$GIT_DIR/BISECT_RUN\"\n> -\t\tres=$?\n> -\n> -\t\tcat \"$GIT_DIR/BISECT_RUN\"\n> -\n> -\t\tif sane_grep \"first $TERM_BAD commit could be any of\" \"$GIT_DIR/BISECT_RUN\" \\\n> -\t\t\t>/dev/null\n> -\t\tthen\n> -\t\t\tgettextln \"bisect run cannot continue any more\" >&2\n> -\t\t\texit $res\n> -\t\tfi\n> -\n> -\t\tif [ $res -ne 0 ]\n> -\t\tthen\n> -\t\t\teval_gettextln \"bisect run failed:\n> -'bisect-state \\$state' exited with error code \\$res\" >&2\n> -\t\t\texit $res\n> -\t\tfi\n> -\n> -\t\tif sane_grep \"is the first $TERM_BAD commit\" \"$GIT_DIR/BISECT_RUN\" >/dev/null\n> -\t\tthen\n> -\t\t\tgettextln \"bisect run success\"\n> -\t\t\texit 0;\n> -\t\tfi\n> -\n> -\tdone\n> -}\n> -\n>  get_terms () {\n>  \tif test -s \"$GIT_DIR/BISECT_TERMS\"\n>  \tthen\n> @@ -137,7 +77,7 @@ case \"$#\" in\n>  \tlog)\n>  \t\tgit bisect--helper --bisect-log || exit ;;\n>  \trun)\n> -\t\tbisect_run \"$@\" ;;\n> +\t\tgit bisect--helper --bisect-run \"$@\" || exit;;\n>  \tterms)\n>  \t\tgit bisect--helper --bisect-terms \"$@\" || exit;;\n>  \t*)\n> --\n> 2.29.2\n>\n>\n"},{"id":"433552","messageId":"nycvar.QRO.7.76.6.2108241559350.55@tvgsbejvaqbjf.bet","threadId":"56335","inReplyTo":"20210820172148.2249-1-mirucam@gmail.com","subject":"Re: [PATCH v5 0/6] Finish converting git bisect to C part 4","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2021-08-24T14:00:10Z","receivedAt":"2021-08-24T14:00:16Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Miriam,\n\nOn Fri, 20 Aug 2021, Miriam Rubio wrote:\n\n> These patches correspond to a fourth part of patch series\n> of Outreachy project \"Finish converting `git bisect` from shell to C\"\n> started by Pranit Bauva and Tanushree Tumane\n> (https://public-inbox.org/git/pull.117.git.gitgitgadget@gmail.com) and\n> continued by me.\n>\n> This fourth part is formed by reimplementations of some `git bisect`\n> subcommands, addition of tests and removal of some temporary subcommands.\n>\n> These patch series emails were generated from:\n> https://gitlab.com/mirucam/git/commits/git-bisect-work-part4-v5.\n\nApart from the stdout redirection in 5/6, the patches look really stable\nto me.\n\nThanks,\nDscho\n\n>\n> I would like to thank Johannes Schindelin, Bagas Sanjaya and\n> Christian Couder for reviewing this patch series.\n>\n> Specific changes\n> ----------------\n> [1/6] t6030-bisect-porcelain: add tests to control bisect run exit cases\n> * Add evaluation of error code 255 in test 'bisect run fails with exit\n> code equals or greater than 128'.\n> * Remove test with error code smaller than 0.\n> ---\n>\n> [4/6] bisect--helper: reimplement `bisect_visualize()`shell function in C\n> * Use strvec_push() instead of strvec_pushl().\n> ---\n>\n> [5/6] bisect--helper: reimplement `bisect_run` shell function in C\n> * Add error message.\n> * Remove exit variable.\n> * Write contents of bisect_state() in BISECT_RUN file and show to user.\n> ---\n>\n> Miriam Rubio (3):\n>   t6030-bisect-porcelain: add tests to control bisect run exit cases\n>   t6030-bisect-porcelain: add test for bisect visualize\n>   bisect--helper: retire `--bisect-next-check` subcommand\n>\n> Pranit Bauva (2):\n>   run-command: make `exists_in_PATH()` non-static\n>   bisect--helper: reimplement `bisect_visualize()`shell function in C\n>\n> Tanushree Tumane (1):\n>   bisect--helper: reimplement `bisect_run` shell function in C\n>\n>  builtin/bisect--helper.c    | 157 ++++++++++++++++++++++++++++++++++--\n>  git-bisect.sh               |  87 +-------------------\n>  run-command.c               |   2 +-\n>  run-command.h               |  12 +++\n>  t/t6030-bisect-porcelain.sh |  18 +++++\n>  5 files changed, 182 insertions(+), 94 deletions(-)\n>\n> --\n> 2.29.2\n>\n>\n"},{"id":"433847","messageId":"CAN7CjDAzAqDHBDaQ9UXoB999tdzeGwgNcixf+oB73j5U2mFK-A@mail.gmail.com","threadId":"56335","inReplyTo":"nycvar.QRO.7.76.6.2108241541190.55@tvgsbejvaqbjf.bet","subject":"Re: [PATCH v5 5/6] bisect--helper: reimplement `bisect_run` shell function in C","fromName":"Miriam R.","fromEmail":"mirucam@gmail.com","sentAt":"2021-08-26T16:46:17Z","receivedAt":"2021-08-26T16:46:30Z","isPatch":true,"sender":{"key":"mirucam@gmail.com","avatar":"https://avatars.githubusercontent.com/u/56339109?v=4"},"body":"Hi Johannes,\n\n\nEl mar, 24 ago 2021 a las 15:59, Johannes Schindelin\n(<Johannes.Schindelin@gmx.de>) escribió:\n>\n> Hi Miriam,\n>\n> On Fri, 20 Aug 2021, Miriam Rubio wrote:\n>\n> > From: Tanushree Tumane <tanushreetumane@gmail.com>\n> >\n> > Reimplement the `bisect_run()` shell function\n> > in C and also add `--bisect-run` subcommand to\n> > `git bisect--helper` to call it from git-bisect.sh.\n> >\n> > Mentored-by: Christian Couder <chriscool@tuxfamily.org>\n> > Signed-off-by: Tanushree Tumane <tanushreetumane@gmail.com>\n> > Signed-off-by: Miriam Rubio <mirucam@gmail.com>\n> > ---\n> >  builtin/bisect--helper.c | 102 +++++++++++++++++++++++++++++++++++++++\n> >  git-bisect.sh            |  62 +-----------------------\n> >  2 files changed, 103 insertions(+), 61 deletions(-)\n> >\n> > diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\n> > index 1e118a966a..8d33c809aa 100644\n> > --- a/builtin/bisect--helper.c\n> > +++ b/builtin/bisect--helper.c\n> > @@ -18,6 +18,7 @@ static GIT_PATH_FUNC(git_path_bisect_log, \"BISECT_LOG\")\n> >  static GIT_PATH_FUNC(git_path_head_name, \"head-name\")\n> >  static GIT_PATH_FUNC(git_path_bisect_names, \"BISECT_NAMES\")\n> >  static GIT_PATH_FUNC(git_path_bisect_first_parent, \"BISECT_FIRST_PARENT\")\n> > +static GIT_PATH_FUNC(git_path_bisect_run, \"BISECT_RUN\")\n> >\n> >  static const char * const git_bisect_helper_usage[] = {\n> >       N_(\"git bisect--helper --bisect-reset [<commit>]\"),\n> > @@ -31,6 +32,7 @@ static const char * const git_bisect_helper_usage[] = {\n> >       N_(\"git bisect--helper --bisect-replay <filename>\"),\n> >       N_(\"git bisect--helper --bisect-skip [(<rev>|<range>)...]\"),\n> >       N_(\"git bisect--helper --bisect-visualize\"),\n> > +     N_(\"git bisect--helper --bisect-run <cmd>...\"),\n> >       NULL\n> >  };\n> >\n> > @@ -144,6 +146,25 @@ static int append_to_file(const char *path, const char *format, ...)\n> >       return res;\n> >  }\n> >\n> > +static int print_file_to_stdout(const char *path)\n> > +{\n> > +     FILE *fp;\n> > +     char c;\n> > +\n> > +     fp = fopen(path, \"r\");\n> > +     if (!fp)\n> > +             return error_errno(_(\"cannot open file '%s' in read mode\"), path);\n> > +\n> > +     c = fgetc(fp);\n> > +     while (c != EOF) {\n> > +             printf (\"%c\", c);\n> > +             c = fgetc(fp);\n> > +     }\n> > +\n> > +     fclose(fp);\n>\n> Rather than reading byte for byte (even if buffered), how about using\n> `copy_fd()`? Something like\n>\n>         int fd = open(path, O_RDONLY), ret = 0;\n>\n>         if (fd < 0)\n>                 return error_errno(_(\"cannot open file '%s' for reading\"), path);\n>         if (copy_fd(fd, 1) < 0)\n>                 ret = error_errno(_(\"failed to read '%s'\"), path);\n>         close(fd);\n>         return ret;\n>\nOk. Noted.\n> > +     return 0;\n> > +}\n> > +\n> >  static int check_term_format(const char *term, const char *orig_term)\n> >  {\n> >       int res;\n> > @@ -1075,6 +1096,78 @@ static int bisect_visualize(struct bisect_terms *terms, const char **argv, int a\n> >       return res;\n> >  }\n> >\n> > +static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)\n> > +{\n> > +     int res = BISECT_OK;\n> > +     struct strbuf command = STRBUF_INIT;\n> > +     struct strvec args = STRVEC_INIT;\n> > +     struct strvec run_args = STRVEC_INIT;\n> > +     const char *new_state;\n> > +     int temporary_stdout_fd, saved_stdout;\n> > +\n> > +     if (bisect_next_check(terms, NULL))\n> > +             return BISECT_FAILED;\n> > +\n> > +     if (argc)\n> > +             sq_quote_argv(&command, argv);\n> > +     else {\n> > +             error(_(\"bisect run failed: no command provided.\"));\n> > +             return BISECT_FAILED;\n> > +     }\n> > +\n> > +     strvec_push(&run_args, command.buf);\n> > +\n> > +     while (1) {\n> > +             strvec_clear(&args);\n> > +\n> > +             printf(_(\"running %s\\n\"), command.buf);\n> > +             res = run_command_v_opt(run_args.v, RUN_USING_SHELL);\n> > +\n> > +             if (res < 0 || 128 <= res) {\n> > +                     error(_(\"bisect run failed: exit code %d from\"\n> > +                             \" '%s' is < 0 or >= 128\"), res, command.buf);\n> > +                     strbuf_release(&command);\n> > +                     return res;\n> > +             }\n> > +\n> > +             if (res == 125)\n> > +                     new_state = \"skip\";\n> > +             else new_state = res > 0 ? terms->term_bad : terms->term_good;\n>\n> I do not care _all_ that much about formatting, but I think others on this\n> list do, and might point out that the `else` wants to live on its own\n> line.\nOk. I'll change that.\n>\n> > +             temporary_stdout_fd = open(git_path_bisect_run(), O_CREAT | O_WRONLY | O_TRUNC, 0666);\n> > +             saved_stdout = dup(1);\n> > +             dup2(temporary_stdout_fd, 1);\n>\n> This temporary redirection looks a bit iffy. I wonder whether there is a\n> way to tell `bisect_state()` to print to a given file descriptor, _in\n> addition to_ `stdout`? That would also make `print_file_to_stdout()`\n> obsolete.\n>\n> What calls exactly are making that print to `stdout` anyway?\n\nI was trying to recreate the cat command with this solution as it is\nin the shell script, without changing behavior or parameters in other\nfunctions.\nI think the most important prints to stdout come from\nbisect_next_all() in bisect.c. The sequence is bisect_state()\n->bisect_auto_next() ->  bisect_next() ->bisect_next_all().\nJust to clarify: if we add a file descriptor as parameter in\nbisect_state(), we have to propagate it to a lot of functions, is that\nwhat we want?\n\n>\n> This is my only remaining issue with the current 5/6.\nThank you for reviewing!\nMiriam\n>\n> Thank you,\n> Dscho\n>\n> > +\n> > +             res = bisect_state(terms, &new_state, 1);\n> > +\n> > +             dup2(saved_stdout, 1);\n> > +             close(saved_stdout);\n> > +             close(temporary_stdout_fd);\n> > +\n> > +             print_file_to_stdout(git_path_bisect_run());\n> > +\n> > +             if (res == BISECT_ONLY_SKIPPED_LEFT)\n> > +                     error(_(\"bisect run cannot continue any more\"));\n> > +             else if (res == BISECT_INTERNAL_SUCCESS_MERGE_BASE) {\n> > +                     printf(_(\"bisect run success\"));\n> > +                     res = BISECT_OK;\n> > +             } else if (res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND) {\n> > +                     printf(_(\"bisect found first bad commit\"));\n> > +                     res = BISECT_OK;\n> > +             } else if (res) {\n> > +                     error(_(\"bisect run failed:'git bisect--helper --bisect-state\"\n> > +                     \" %s' exited with error code %d\"), args.v[0], res);\n> > +             } else {\n> > +                     continue;\n> > +             }\n> > +\n> > +             strbuf_release(&command);\n> > +             strvec_clear(&args);\n> > +             strvec_clear(&run_args);\n> > +             return res;\n> > +     }\n> > +}\n> > +\n> >  int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n> >  {\n> >       enum {\n> > @@ -1089,6 +1182,7 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n> >               BISECT_REPLAY,\n> >               BISECT_SKIP,\n> >               BISECT_VISUALIZE,\n> > +             BISECT_RUN,\n> >       } cmdmode = 0;\n> >       int res = 0, nolog = 0;\n> >       struct option options[] = {\n> > @@ -1112,6 +1206,8 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n> >                        N_(\"skip some commits for checkout\"), BISECT_SKIP),\n> >               OPT_CMDMODE(0, \"bisect-visualize\", &cmdmode,\n> >                        N_(\"visualize the bisection\"), BISECT_VISUALIZE),\n> > +             OPT_CMDMODE(0, \"bisect-run\", &cmdmode,\n> > +                      N_(\"use <cmd>... to automatically bisect.\"), BISECT_RUN),\n> >               OPT_BOOL(0, \"no-log\", &nolog,\n> >                        N_(\"no log for BISECT_WRITE\")),\n> >               OPT_END()\n> > @@ -1177,6 +1273,12 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n> >               get_terms(&terms);\n> >               res = bisect_visualize(&terms, argv, argc);\n> >               break;\n> > +     case BISECT_RUN:\n> > +             if (!argc)\n> > +                     return error(_(\"bisect run failed: no command provided.\"));\n> > +             get_terms(&terms);\n> > +             res = bisect_run(&terms, argv, argc);\n> > +             break;\n> >       default:\n> >               BUG(\"unknown subcommand %d\", cmdmode);\n> >       }\n> > diff --git a/git-bisect.sh b/git-bisect.sh\n> > index 95f7f3fb8c..e83d011e17 100755\n> > --- a/git-bisect.sh\n> > +++ b/git-bisect.sh\n> > @@ -39,66 +39,6 @@ _x40=\"$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40\"\n> >  TERM_BAD=bad\n> >  TERM_GOOD=good\n> >\n> > -bisect_run () {\n> > -     git bisect--helper --bisect-next-check $TERM_GOOD $TERM_BAD fail || exit\n> > -\n> > -     test -n \"$*\" || die \"$(gettext \"bisect run failed: no command provided.\")\"\n> > -\n> > -     while true\n> > -     do\n> > -             command=\"$@\"\n> > -             eval_gettextln \"running \\$command\"\n> > -             \"$@\"\n> > -             res=$?\n> > -\n> > -             # Check for really bad run error.\n> > -             if [ $res -lt 0 -o $res -ge 128 ]\n> > -             then\n> > -                     eval_gettextln \"bisect run failed:\n> > -exit code \\$res from '\\$command' is < 0 or >= 128\" >&2\n> > -                     exit $res\n> > -             fi\n> > -\n> > -             # Find current state depending on run success or failure.\n> > -             # A special exit code of 125 means cannot test.\n> > -             if [ $res -eq 125 ]\n> > -             then\n> > -                     state='skip'\n> > -             elif [ $res -gt 0 ]\n> > -             then\n> > -                     state=\"$TERM_BAD\"\n> > -             else\n> > -                     state=\"$TERM_GOOD\"\n> > -             fi\n> > -\n> > -             git bisect--helper --bisect-state $state >\"$GIT_DIR/BISECT_RUN\"\n> > -             res=$?\n> > -\n> > -             cat \"$GIT_DIR/BISECT_RUN\"\n> > -\n> > -             if sane_grep \"first $TERM_BAD commit could be any of\" \"$GIT_DIR/BISECT_RUN\" \\\n> > -                     >/dev/null\n> > -             then\n> > -                     gettextln \"bisect run cannot continue any more\" >&2\n> > -                     exit $res\n> > -             fi\n> > -\n> > -             if [ $res -ne 0 ]\n> > -             then\n> > -                     eval_gettextln \"bisect run failed:\n> > -'bisect-state \\$state' exited with error code \\$res\" >&2\n> > -                     exit $res\n> > -             fi\n> > -\n> > -             if sane_grep \"is the first $TERM_BAD commit\" \"$GIT_DIR/BISECT_RUN\" >/dev/null\n> > -             then\n> > -                     gettextln \"bisect run success\"\n> > -                     exit 0;\n> > -             fi\n> > -\n> > -     done\n> > -}\n> > -\n> >  get_terms () {\n> >       if test -s \"$GIT_DIR/BISECT_TERMS\"\n> >       then\n> > @@ -137,7 +77,7 @@ case \"$#\" in\n> >       log)\n> >               git bisect--helper --bisect-log || exit ;;\n> >       run)\n> > -             bisect_run \"$@\" ;;\n> > +             git bisect--helper --bisect-run \"$@\" || exit;;\n> >       terms)\n> >               git bisect--helper --bisect-terms \"$@\" || exit;;\n> >       *)\n> > --\n> > 2.29.2\n> >\n> >\n"}]}