@@ -79,6 +79,11 @@ fn run() -> Result<()> {
79
79
. short ( "f" )
80
80
. help ( "Path to file (or named pipe) to read from" )
81
81
. takes_value ( true ) )
82
+ . arg ( Arg :: with_name ( "follow" )
83
+ . long ( "follow" )
84
+ . short ( "F" )
85
+ . help ( "Keep the file open after reading through it and \
86
+ append new output as it is written. Like `tail -f'.") )
82
87
. arg ( Arg :: with_name ( "port" )
83
88
. long ( "stimulus" )
84
89
. short ( "s" )
@@ -96,6 +101,8 @@ fn run() -> Result<()> {
96
101
. parse :: < u8 > ( )
97
102
. expect ( "Arg validator should ensure this parses" ) ;
98
103
104
+ let follow = matches. is_present ( "follow" ) ;
105
+
99
106
let mut stream = open_read ( & matches) ?;
100
107
101
108
let stdout = io:: stdout ( ) ;
@@ -135,13 +142,23 @@ fn run() -> Result<()> {
135
142
}
136
143
}
137
144
} ) ( ) {
138
- match e. kind ( ) {
139
- io:: ErrorKind :: UnexpectedEof => {
145
+ // Error caught in main loop as `e`.
146
+ if e. kind ( ) == io:: ErrorKind :: UnexpectedEof {
147
+ if follow {
148
+ // TODO: There's a bug here where we can lose data.
149
+ // UnexpectedEof is returned when read_exact() encounters EOF
150
+ // before it fills its buffer, but in that case it may have
151
+ // already read _some_ data, which we discard here.
152
+ //
153
+ // We could buffer input until we can read a full packet,
154
+ // or turn parsing into a state machine.
140
155
thread:: sleep ( Duration :: from_millis ( 100 ) ) ;
156
+ } else {
157
+ // !follow and EOF. Exit.
158
+ return Ok ( ( ) )
141
159
}
142
- _ => {
143
- error ! ( "{}" , e) ;
144
- }
160
+ } else {
161
+ error ! ( "{}" , e) ;
145
162
}
146
163
}
147
164
}
0 commit comments