| 1083 | } |
| 1084 | |
| 1085 | void ClientBase::initTTYBuffer(ProgressOption progress_option, ProgressOption progress_table_option) |
| 1086 | { |
| 1087 | if (tty_buf) |
| 1088 | return; |
| 1089 | |
| 1090 | if (progress_option == ProgressOption::OFF || (!is_interactive && progress_option == ProgressOption::DEFAULT)) |
| 1091 | need_render_progress = false; |
| 1092 | |
| 1093 | if (progress_table_option == ProgressOption::OFF || (!is_interactive && progress_table_option == ProgressOption::DEFAULT)) |
| 1094 | need_render_progress_table = false; |
| 1095 | |
| 1096 | if (!need_render_progress && !need_render_progress_table) |
| 1097 | return; |
| 1098 | |
| 1099 | progress_table_toggle_enabled = getClientConfiguration().getBool("enable-progress-table-toggle"); |
| 1100 | progress_table_toggle_on = !progress_table_toggle_enabled; |
| 1101 | |
| 1102 | /// If need_render_progress and need_render_progress_table are enabled, |
| 1103 | /// use ProgressOption that was set for the progress bar for progress table as well. |
| 1104 | ProgressOption progress = progress_option ? progress_option : progress_table_option; |
| 1105 | |
| 1106 | /// Output all progress bar commands to terminal at once to avoid flicker. |
| 1107 | /// This size is usually greater than the window size. |
| 1108 | static constexpr size_t buf_size = 1024; |
| 1109 | |
| 1110 | /// Prefer to use an existing fd for the tty, from stdin/stdout/stderr, to allow redirecting |
| 1111 | /// progress indication to a different terminal. |
| 1112 | int tty_fd = -1; |
| 1113 | |
| 1114 | if (stderr_is_a_tty || progress == ProgressOption::ERR) |
| 1115 | { |
| 1116 | tty_fd = stderr_fd; |
| 1117 | } |
| 1118 | else if (stdout_is_a_tty || isEmbeeddedClient()) |
| 1119 | { |
| 1120 | // If we are embedded into server, there is no need to access terminal device via opening a file. |
| 1121 | // Actually we need to pass tty's name, if we don't want this condition statement, |
| 1122 | // because /dev/tty stands for controlling terminal of the process, thus a client will not see progress line. |
| 1123 | // So it's easier to just pass a descriptor, without the terminal name. |
| 1124 | tty_fd = stdout_fd; |
| 1125 | } |
| 1126 | else if (stdin_is_a_tty) |
| 1127 | { |
| 1128 | /// If stdin is a tty, it's writable, tty can't be readonly. |
| 1129 | tty_fd = stdin_fd; |
| 1130 | } |
| 1131 | |
| 1132 | if (tty_fd != -1) |
| 1133 | { |
| 1134 | tty_buf = std::make_unique<AutoCanceledWriteBuffer<WriteBufferFromFileDescriptor>>(tty_fd, buf_size); |
| 1135 | return; |
| 1136 | } |
| 1137 | |
| 1138 | /// If none of stdin/stdout/stderr are tty but progress rendering was requested, open /dev/tty. |
| 1139 | |
| 1140 | static constexpr auto tty_file_name = "/dev/tty"; |
| 1141 | |
| 1142 | std::error_code ec; |