2
2
3
3
use crate :: errors:: * ;
4
4
use log:: { info, warn} ;
5
+ use std:: fs;
5
6
use std:: fs:: File ;
7
+ use std:: io:: prelude:: * ;
6
8
use std:: path:: { Path , PathBuf } ;
7
9
use std:: process:: Command ;
8
10
@@ -62,8 +64,7 @@ impl ExternArgs {
62
64
let try_path: PathBuf = [ & proj_root. to_string_lossy ( ) , "src" , fname]
63
65
. iter ( )
64
66
. collect ( ) ;
65
- let f = File :: options ( ) . append ( true ) . open ( & try_path) ?;
66
- f. set_modified ( std:: time:: SystemTime :: now ( ) ) ?;
67
+ touch ( & try_path) ?;
67
68
break ;
68
69
// file should be closed when f goes out of scope at bottom of this loop
69
70
}
@@ -103,10 +104,16 @@ impl ExternArgs {
103
104
self . suffix_args
104
105
. push ( arg_iter. next ( ) . unwrap_or ( "" ) . to_owned ( ) ) ;
105
106
}
106
- "--extern" => { // needs a hack to force reference to rlib over rmeta
107
+ "--extern" => {
108
+ // needs a hack to force reference to rlib over rmeta
107
109
self . suffix_args . push ( arg. to_owned ( ) ) ;
108
- self . suffix_args
109
- . push ( arg_iter. next ( ) . unwrap_or ( "" ) . replace ( ".rmeta" , ".rlib" ) . to_owned ( ) ) ;
110
+ self . suffix_args . push (
111
+ arg_iter
112
+ . next ( )
113
+ . unwrap_or ( "" )
114
+ . replace ( ".rmeta" , ".rlib" )
115
+ . to_owned ( ) ,
116
+ ) ;
110
117
}
111
118
_ => { }
112
119
}
@@ -129,9 +136,31 @@ impl ExternArgs {
129
136
}
130
137
}
131
138
139
+ // Private "touch" function to update file modification time without changing content.
140
+ // needed because [std::fs::set_modified] is unstable in rust 1.74,
141
+ // which is currently the MSRV for mdBook. It is available in rust 1.76 onward.
142
+
143
+ fn touch ( victim : & Path ) -> Result < ( ) > {
144
+ let curr_content = fs:: read ( victim) . with_context ( || "reading existing file" ) ?;
145
+ let mut touchfs = File :: options ( )
146
+ . append ( true )
147
+ . open ( victim)
148
+ . with_context ( || "opening for touch" ) ?;
149
+
150
+ let _len_written = touchfs. write ( b"z" ) ?; // write a byte
151
+ touchfs. flush ( ) . expect ( "closing" ) ; // close the file
152
+ drop ( touchfs) ; // close modified file, hopefully updating modification time
153
+
154
+ fs:: write ( victim, curr_content) . with_context ( || "trying to restore old content" )
155
+ }
156
+
132
157
#[ cfg( test) ]
133
158
mod test {
134
159
use super :: * ;
160
+ use std:: fs;
161
+ use std:: thread;
162
+ use std:: time:: Duration ;
163
+ use tempfile;
135
164
136
165
#[ test]
137
166
fn parse_response_parses_string ( ) -> Result < ( ) > {
@@ -166,4 +195,35 @@ mod test {
166
195
167
196
Ok ( ( ) )
168
197
}
198
+
199
+ #[ test]
200
+ fn verify_touch ( ) -> Result < ( ) > {
201
+ const FILE_CONTENT : & [ u8 ] =
202
+ b"I am some random text with crlfs \r \n but also nls \n and terminated with a nl \n " ;
203
+ const DELAY : Duration = Duration :: from_millis ( 10 ) ; // don't hang up tests for too long.
204
+
205
+ let temp_dir = tempfile:: TempDir :: new ( ) ?;
206
+ let mut victim_path = temp_dir. path ( ) . to_owned ( ) ;
207
+ victim_path. push ( "workfile.dir" ) ;
208
+ fs:: write ( & victim_path, FILE_CONTENT ) ?;
209
+ let old_md = fs:: metadata ( & victim_path) ?;
210
+ thread:: sleep ( DELAY ) ;
211
+
212
+ touch ( & victim_path) ?;
213
+ let new_md = fs:: metadata ( & victim_path) ?;
214
+
215
+ let act_content = fs:: read ( & victim_path) ?;
216
+
217
+ assert_eq ! ( FILE_CONTENT , act_content) ;
218
+ assert ! (
219
+ new_md
220
+ . modified( )
221
+ . expect( "getting modified time" )
222
+ . duration_since( old_md. modified( ) . expect( "getting modified time old" ) )
223
+ . expect( "system botch" )
224
+ >= DELAY
225
+ ) ;
226
+
227
+ Ok ( ( ) )
228
+ }
169
229
}
0 commit comments