From ae5cab7489fe014dd3aa818cf2655d7a4714af83 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Sat, 16 Dec 2017 17:42:12 +0200 Subject: Improve process execution diagnostics by reusing run_*() API --- build2/utility.hxx | 134 ++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 111 insertions(+), 23 deletions(-) (limited to 'build2/utility.hxx') diff --git a/build2/utility.hxx b/build2/utility.hxx index 77c46a8..db6460c 100644 --- a/build2/utility.hxx +++ b/build2/utility.hxx @@ -166,12 +166,16 @@ namespace build2 // Basic process utilities. // + // The run*() functions with process_path assume that you are printing + // the process command line yourself. - // Start a process with the specified arguments printing the command at - // verbosity level 3 and higher. Redirect STDOUT to a pipe. If error is - // false, then redirecting STDERR to STDOUT (this can be used to suppress - // diagnostics from the child process). Issue diagnostics and throw failed - // in case of an error. + extern uint16_t verb; // diagnostics.hxx + + void + print_process (const char* const*, size_t); // diagnostics.hxx + + // Search for a process executable. Issue diagnostics and throw failed in + // case of an error. // process_path run_search (const char*& args0); @@ -179,20 +183,88 @@ namespace build2 process_path run_search (const path&, bool init, const dir_path& fallback = dir_path ()); + // Wait for process termination. Issue diagnostics and throw failed in case + // of abnormal termination. If the process has terminated normally but with + // a non-zero exit status, then, if error is true, assume the diagnostics + // has already been issued and throw failed as well. Otherwise (error is + // false), return false. The last argument is used in cooperation with + // run_start() in case STDERR is redirected to STDOUT. + // + bool + run_finish (const char* args[], + process&, + bool error = true, + const string& = string ()); + + inline void + run_finish (cstrings& args, process& pr) + { + run_finish (args.data (), pr); + } + + // Start a process with the specified arguments. If out is -1, redirect + // STDOUT to a pipe. If error is false, then redirecting STDERR to STDOUT + // (this can be used to suppress diagnostics from the child process). Issue + // diagnostics and throw failed in case of an error. + // process - run_start (const process_path&, const char* args[], bool error = true); + run_start (const process_path&, + const char* args[], + int out, + bool error = true, + const dir_path& cwd = dir_path ()); + + inline void + run (const process_path& p, + const char* args[], + const dir_path& cwd = dir_path ()) + { + process pr (run_start (p, args, 1 /* stdout */, true, cwd)); + run_finish (args, pr); + } + inline void + run (const process_path& p, + cstrings& args, + const dir_path& cwd = dir_path ()) + { + run (p, args.data (), cwd); + } + + // As above, but search for the process (including updating args[0]) and + // print the process commands line at the specified verbosity level. + // inline process - run_start (const char* args[], bool error = true) + run_start (uint16_t verbosity, + const char* args[], + int out, + bool error = true, + const dir_path& cwd = dir_path ()) { - return run_start (run_search (args[0]), args, error); + process_path pp (run_search (args[0])); + + if (verb >= verbosity) + print_process (args, 0); + + return run_start (pp, args, out, error, cwd); } - bool - run_finish (const char* args[], - process&, - bool error = true, - const string& = string ()); + inline void + run (uint16_t verbosity, + const char* args[], + const dir_path& cwd = dir_path ()) + { + process pr (run_start (verbosity, args, 1 /* stdout */, true, cwd)); + run_finish (args, pr); + } + + inline void + run (uint16_t verbosity, + cstrings& args, + const dir_path& cwd = dir_path ()) + { + run (verbosity, args.data (), cwd); + } // Start the process as above and then call the specified function on each // trimmed line of the output until it returns a non-empty object T (tested @@ -220,40 +292,50 @@ namespace build2 template inline T - run (const char* args[], + run (uint16_t verbosity, + const char* args[], F&& f, bool error = true, bool ignore_exit = false, sha256* checksum = nullptr) { - return run ( - run_search ( - args[0]), args, forward (f), error, ignore_exit, checksum); + process_path pp (run_search (args[0])); + + if (verb >= verbosity) + print_process (args, 0); + + return run (pp, args, forward (f), error, ignore_exit, checksum); } // run // template inline T - run (const path& prog, + run (uint16_t verb, + const path& prog, F&& f, bool error = true, bool ignore_exit = false, sha256* checksum = nullptr) { const char* args[] = {prog.string ().c_str (), nullptr}; - return run (args, forward (f), error, ignore_exit, checksum); + return run (verb, args, forward (f), error, ignore_exit, checksum); } template inline T - run (const process_path& pp, + run (uint16_t verbosity, + const process_path& pp, F&& f, bool error = true, bool ignore_exit = false, sha256* checksum = nullptr) { const char* args[] = {pp.recall_string (), nullptr}; + + if (verb >= verbosity) + print_process (args, 0); + return run (pp, args, forward (f), error, ignore_exit, checksum); } @@ -261,7 +343,8 @@ namespace build2 // template inline T - run (const path& prog, + run (uint16_t verb, + const path& prog, const char* arg, F&& f, bool error = true, @@ -269,12 +352,13 @@ namespace build2 sha256* checksum = nullptr) { const char* args[] = {prog.string ().c_str (), arg, nullptr}; - return run (args, forward (f), error, ignore_exit, checksum); + return run (verb, args, forward (f), error, ignore_exit, checksum); } template inline T - run (const process_path& pp, + run (uint16_t verbosity, + const process_path& pp, const char* arg, F&& f, bool error = true, @@ -282,6 +366,10 @@ namespace build2 sha256* checksum = nullptr) { const char* args[] = {pp.recall_string (), arg, nullptr}; + + if (verb >= verbosity) + print_process (args, 0); + return run (pp, args, forward (f), error, ignore_exit, checksum); } -- cgit v1.1