22
33use crate :: errors:: * ;
44use log:: { info, warn} ;
5+ use std:: fs;
56use std:: fs:: File ;
7+ use std:: io:: prelude:: * ;
68use std:: path:: { Path , PathBuf } ;
79use std:: process:: Command ;
810
@@ -62,8 +64,7 @@ impl ExternArgs {
6264 let try_path: PathBuf = [ & proj_root. to_string_lossy ( ) , "src" , fname]
6365 . iter ( )
6466 . collect ( ) ;
65- let f = File :: options ( ) . append ( true ) . open ( & try_path) ?;
66- f. set_modified ( std:: time:: SystemTime :: now ( ) ) ?;
67+ touch ( & try_path) ?;
6768 break ;
6869 // file should be closed when f goes out of scope at bottom of this loop
6970 }
@@ -103,10 +104,16 @@ impl ExternArgs {
103104 self . suffix_args
104105 . push ( arg_iter. next ( ) . unwrap_or ( "" ) . to_owned ( ) ) ;
105106 }
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
107109 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+ ) ;
110117 }
111118 _ => { }
112119 }
@@ -129,9 +136,31 @@ impl ExternArgs {
129136 }
130137}
131138
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+
132157#[ cfg( test) ]
133158mod test {
134159 use super :: * ;
160+ use std:: fs;
161+ use std:: thread;
162+ use std:: time:: Duration ;
163+ use tempfile;
135164
136165 #[ test]
137166 fn parse_response_parses_string ( ) -> Result < ( ) > {
@@ -166,4 +195,35 @@ mod test {
166195
167196 Ok ( ( ) )
168197 }
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+ }
169229}
0 commit comments