drain.cpp 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. #include <array>
  2. #include <iostream>
  3. #include <reproc++/drain.hpp>
  4. #include <reproc++/reproc.hpp>
  5. static int fail(std::error_code ec)
  6. {
  7. std::cerr << ec.message();
  8. return ec.value();
  9. }
  10. // Uses `reproc::drain` to show the output of the given command.
  11. int main(int argc, const char **argv)
  12. {
  13. if (argc <= 1) {
  14. std::cerr << "No arguments provided. Example usage: "
  15. << "./drain cmake --help";
  16. return EXIT_FAILURE;
  17. }
  18. reproc::process process;
  19. // reproc++ uses error codes to report errors. If exceptions are preferred,
  20. // convert `std::error_code`'s to exceptions using `std::system_error`.
  21. std::error_code ec = process.start(argv + 1);
  22. // reproc++ converts system errors to `std::error_code`'s of the system
  23. // category. These can be matched against using values from the `std::errc`
  24. // error condition. See https://en.cppreference.com/w/cpp/error/errc for more
  25. // information.
  26. if (ec == std::errc::no_such_file_or_directory) {
  27. std::cerr << "Program not found. Make sure it's available from the PATH.";
  28. return ec.value();
  29. } else if (ec) {
  30. return fail(ec);
  31. }
  32. // `reproc::drain` reads from the stdout and stderr streams of `process` until
  33. // both are closed or an error occurs. Providing it with a string sink for a
  34. // specific stream makes it store all output of that stream in the string
  35. // passed to the string sink. Passing the same sink to both the `out` and
  36. // `err` arguments of `reproc::drain` causes the stdout and stderr output to
  37. // get stored in the same string.
  38. std::string output;
  39. reproc::sink::string sink(output);
  40. // By default, reproc only redirects stdout to a pipe and not stderr so we
  41. // pass `reproc::sink::null` as the sink for stderr here. We could also pass
  42. // `sink` but it wouldn't receive any data from stderr.
  43. ec = reproc::drain(process, sink, reproc::sink::null);
  44. if (ec) {
  45. return fail(ec);
  46. }
  47. std::cout << output << std::flush;
  48. // It's easy to define your own sinks as well. Take a look at `drain.hpp` in
  49. // the repository to see how `sink::string` and other sinks are implemented.
  50. // The documentation of `reproc::drain` also provides more information on the
  51. // requirements a sink should fulfill.
  52. // By default, The `process` destructor waits indefinitely for the child
  53. // process to exit to ensure proper cleanup. See the forward example for
  54. // information on how this can be configured. However, when relying on the
  55. // `process` destructor, we cannot check the exit status of the process so it
  56. // usually makes sense to explicitly wait for the process to exit and check
  57. // its exit status.
  58. int status = 0;
  59. std::tie(status, ec) = process.wait(reproc::infinite);
  60. if (ec) {
  61. return fail(ec);
  62. }
  63. return status;
  64. }