Mercurial > public > mercurial-scm > hg-stable
annotate rust/rhg/src/ui.rs @ 45382:eb55274d3650
rhg: add buffered stdout writing possibility
Improve batch stdout writing performance.
At some point line buffered output should be introduced.
Differential Revision: https://phab.mercurial-scm.org/D8866
author | Antoine Cezar <antoine.cezar@octobus.net> |
---|---|
date | Wed, 29 Jul 2020 10:26:17 +0200 |
parents | 513b3ef277a3 |
children | 10c36ead86f8 |
rev | line source |
---|---|
45050
513b3ef277a3
rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff
changeset
|
1 use std::io; |
45382
eb55274d3650
rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents:
45050
diff
changeset
|
2 use std::io::{ErrorKind, Write}; |
45050
513b3ef277a3
rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff
changeset
|
3 |
45382
eb55274d3650
rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents:
45050
diff
changeset
|
4 #[derive(Debug)] |
eb55274d3650
rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents:
45050
diff
changeset
|
5 pub struct Ui { |
eb55274d3650
rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents:
45050
diff
changeset
|
6 stdout: std::io::Stdout, |
eb55274d3650
rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents:
45050
diff
changeset
|
7 stderr: std::io::Stderr, |
eb55274d3650
rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents:
45050
diff
changeset
|
8 } |
45050
513b3ef277a3
rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff
changeset
|
9 |
513b3ef277a3
rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff
changeset
|
10 /// The kind of user interface error |
513b3ef277a3
rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff
changeset
|
11 pub enum UiError { |
513b3ef277a3
rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff
changeset
|
12 /// The standard output stream cannot be written to |
513b3ef277a3
rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff
changeset
|
13 StdoutError(io::Error), |
513b3ef277a3
rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff
changeset
|
14 /// The standard error stream cannot be written to |
513b3ef277a3
rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff
changeset
|
15 StderrError(io::Error), |
513b3ef277a3
rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff
changeset
|
16 } |
513b3ef277a3
rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff
changeset
|
17 |
513b3ef277a3
rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff
changeset
|
18 /// The commandline user interface |
513b3ef277a3
rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff
changeset
|
19 impl Ui { |
513b3ef277a3
rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff
changeset
|
20 pub fn new() -> Self { |
45382
eb55274d3650
rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents:
45050
diff
changeset
|
21 Ui { |
eb55274d3650
rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents:
45050
diff
changeset
|
22 stdout: std::io::stdout(), |
eb55274d3650
rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents:
45050
diff
changeset
|
23 stderr: std::io::stderr(), |
eb55274d3650
rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents:
45050
diff
changeset
|
24 } |
eb55274d3650
rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents:
45050
diff
changeset
|
25 } |
eb55274d3650
rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents:
45050
diff
changeset
|
26 |
eb55274d3650
rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents:
45050
diff
changeset
|
27 /// Returns a buffered handle on stdout for faster batch printing |
eb55274d3650
rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents:
45050
diff
changeset
|
28 /// operations. |
eb55274d3650
rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents:
45050
diff
changeset
|
29 pub fn stdout_buffer(&self) -> StdoutBuffer<std::io::StdoutLock> { |
eb55274d3650
rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents:
45050
diff
changeset
|
30 StdoutBuffer::new(self.stdout.lock()) |
45050
513b3ef277a3
rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff
changeset
|
31 } |
513b3ef277a3
rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff
changeset
|
32 |
513b3ef277a3
rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff
changeset
|
33 /// Write bytes to stdout |
513b3ef277a3
rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff
changeset
|
34 pub fn write_stdout(&self, bytes: &[u8]) -> Result<(), UiError> { |
45382
eb55274d3650
rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents:
45050
diff
changeset
|
35 let mut stdout = self.stdout.lock(); |
45050
513b3ef277a3
rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff
changeset
|
36 |
513b3ef277a3
rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff
changeset
|
37 self.write_stream(&mut stdout, bytes) |
45382
eb55274d3650
rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents:
45050
diff
changeset
|
38 .or_else(|e| self.handle_stdout_error(e))?; |
45050
513b3ef277a3
rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff
changeset
|
39 |
45382
eb55274d3650
rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents:
45050
diff
changeset
|
40 stdout.flush().or_else(|e| self.handle_stdout_error(e)) |
45050
513b3ef277a3
rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff
changeset
|
41 } |
513b3ef277a3
rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff
changeset
|
42 |
45382
eb55274d3650
rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents:
45050
diff
changeset
|
43 /// Sometimes writing to stdout is not possible, try writing to stderr to |
eb55274d3650
rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents:
45050
diff
changeset
|
44 /// signal that failure, otherwise just bail. |
eb55274d3650
rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents:
45050
diff
changeset
|
45 fn handle_stdout_error(&self, error: io::Error) -> Result<(), UiError> { |
45050
513b3ef277a3
rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff
changeset
|
46 self.write_stderr( |
513b3ef277a3
rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff
changeset
|
47 &[b"abort: ", error.to_string().as_bytes(), b"\n"].concat(), |
513b3ef277a3
rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff
changeset
|
48 )?; |
513b3ef277a3
rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff
changeset
|
49 Err(UiError::StdoutError(error)) |
513b3ef277a3
rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff
changeset
|
50 } |
513b3ef277a3
rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff
changeset
|
51 |
513b3ef277a3
rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff
changeset
|
52 /// Write bytes to stderr |
513b3ef277a3
rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff
changeset
|
53 pub fn write_stderr(&self, bytes: &[u8]) -> Result<(), UiError> { |
45382
eb55274d3650
rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents:
45050
diff
changeset
|
54 let mut stderr = self.stderr.lock(); |
45050
513b3ef277a3
rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff
changeset
|
55 |
513b3ef277a3
rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff
changeset
|
56 self.write_stream(&mut stderr, bytes) |
513b3ef277a3
rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff
changeset
|
57 .or_else(|e| Err(UiError::StderrError(e)))?; |
513b3ef277a3
rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff
changeset
|
58 |
513b3ef277a3
rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff
changeset
|
59 stderr.flush().or_else(|e| Err(UiError::StderrError(e))) |
513b3ef277a3
rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff
changeset
|
60 } |
513b3ef277a3
rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff
changeset
|
61 |
513b3ef277a3
rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff
changeset
|
62 fn write_stream( |
513b3ef277a3
rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff
changeset
|
63 &self, |
513b3ef277a3
rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff
changeset
|
64 stream: &mut impl Write, |
513b3ef277a3
rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff
changeset
|
65 bytes: &[u8], |
513b3ef277a3
rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff
changeset
|
66 ) -> Result<(), io::Error> { |
513b3ef277a3
rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff
changeset
|
67 stream.write_all(bytes) |
513b3ef277a3
rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff
changeset
|
68 } |
513b3ef277a3
rhg: add RootCommand using hg-core FindRoot operation to prepare `hg root`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff
changeset
|
69 } |
45382
eb55274d3650
rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents:
45050
diff
changeset
|
70 |
eb55274d3650
rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents:
45050
diff
changeset
|
71 /// A buffered stdout writer for faster batch printing operations. |
eb55274d3650
rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents:
45050
diff
changeset
|
72 pub struct StdoutBuffer<W: Write> { |
eb55274d3650
rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents:
45050
diff
changeset
|
73 buf: io::BufWriter<W>, |
eb55274d3650
rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents:
45050
diff
changeset
|
74 } |
eb55274d3650
rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents:
45050
diff
changeset
|
75 |
eb55274d3650
rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents:
45050
diff
changeset
|
76 impl<W: Write> StdoutBuffer<W> { |
eb55274d3650
rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents:
45050
diff
changeset
|
77 pub fn new(writer: W) -> Self { |
eb55274d3650
rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents:
45050
diff
changeset
|
78 let buf = io::BufWriter::new(writer); |
eb55274d3650
rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents:
45050
diff
changeset
|
79 Self { buf } |
eb55274d3650
rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents:
45050
diff
changeset
|
80 } |
eb55274d3650
rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents:
45050
diff
changeset
|
81 |
eb55274d3650
rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents:
45050
diff
changeset
|
82 /// Write bytes to stdout buffer |
eb55274d3650
rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents:
45050
diff
changeset
|
83 pub fn write_all(&mut self, bytes: &[u8]) -> Result<(), UiError> { |
eb55274d3650
rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents:
45050
diff
changeset
|
84 self.buf.write_all(bytes).or_else(|e| self.io_err(e)) |
eb55274d3650
rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents:
45050
diff
changeset
|
85 } |
eb55274d3650
rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents:
45050
diff
changeset
|
86 |
eb55274d3650
rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents:
45050
diff
changeset
|
87 /// Flush bytes to stdout |
eb55274d3650
rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents:
45050
diff
changeset
|
88 pub fn flush(&mut self) -> Result<(), UiError> { |
eb55274d3650
rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents:
45050
diff
changeset
|
89 self.buf.flush().or_else(|e| self.io_err(e)) |
eb55274d3650
rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents:
45050
diff
changeset
|
90 } |
eb55274d3650
rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents:
45050
diff
changeset
|
91 |
eb55274d3650
rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents:
45050
diff
changeset
|
92 fn io_err(&self, error: io::Error) -> Result<(), UiError> { |
eb55274d3650
rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents:
45050
diff
changeset
|
93 if let ErrorKind::BrokenPipe = error.kind() { |
eb55274d3650
rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents:
45050
diff
changeset
|
94 // This makes `| head` work for example |
eb55274d3650
rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents:
45050
diff
changeset
|
95 return Ok(()); |
eb55274d3650
rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents:
45050
diff
changeset
|
96 } |
eb55274d3650
rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents:
45050
diff
changeset
|
97 let mut stderr = io::stderr(); |
eb55274d3650
rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents:
45050
diff
changeset
|
98 |
eb55274d3650
rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents:
45050
diff
changeset
|
99 stderr |
eb55274d3650
rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents:
45050
diff
changeset
|
100 .write_all( |
eb55274d3650
rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents:
45050
diff
changeset
|
101 &[b"abort: ", error.to_string().as_bytes(), b"\n"].concat(), |
eb55274d3650
rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents:
45050
diff
changeset
|
102 ) |
eb55274d3650
rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents:
45050
diff
changeset
|
103 .map_err(|e| UiError::StderrError(e))?; |
eb55274d3650
rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents:
45050
diff
changeset
|
104 |
eb55274d3650
rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents:
45050
diff
changeset
|
105 stderr.flush().map_err(|e| UiError::StderrError(e))?; |
eb55274d3650
rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents:
45050
diff
changeset
|
106 |
eb55274d3650
rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents:
45050
diff
changeset
|
107 Err(UiError::StdoutError(error)) |
eb55274d3650
rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents:
45050
diff
changeset
|
108 } |
eb55274d3650
rhg: add buffered stdout writing possibility
Antoine Cezar <antoine.cezar@octobus.net>
parents:
45050
diff
changeset
|
109 } |