@@ -2,72 +2,96 @@ use std::path::Path;
2
2
use std:: process:: Command ;
3
3
use std:: time:: { Duration , SystemTime } ;
4
4
use std:: { env, thread} ;
5
+ use std:: io;
5
6
7
+ /// Python binary depending on OS
6
8
#[ cfg( windows) ]
7
9
const PYTHON : & str = "python" ;
8
-
9
10
#[ cfg( not( windows) ) ]
10
11
const PYTHON : & str = "python3" ;
11
12
12
- /// # Panics
13
+ /// Run a local live server for Clippy docs and lints.
13
14
///
14
- /// Panics if the python commands could not be spawned
15
+ /// # Arguments
16
+ /// * `port` - Port to run the HTTP server on.
17
+ /// * `lint` - Optional lint name to open directly in the browser.
18
+ ///
19
+ /// # Panics
20
+ /// Panics if spawning processes fails or the HTTP server cannot be launched.
15
21
pub fn run ( port : u16 , lint : Option < String > ) -> ! {
16
22
let mut url = Some ( match lint {
17
- None => format ! ( "http://localhost:{port}" ) ,
18
23
Some ( lint) => format ! ( "http://localhost:{port}/#{lint}" ) ,
24
+ None => format ! ( "http://localhost:{port}" ) ,
19
25
} ) ;
20
26
27
+ let mut server_started = false ;
28
+
21
29
loop {
22
- let index_time = mtime ( "util/gh-pages/index.html" ) ;
30
+ // Check last modified times of critical files
31
+ let index_time = mtime ( "util/gh-pages/index.html" ) . unwrap_or ( SystemTime :: UNIX_EPOCH ) ;
23
32
let times = [
24
33
"clippy_lints/src" ,
25
34
"util/gh-pages/index_template.html" ,
26
35
"tests/compile-test.rs" ,
27
36
]
28
- . map ( mtime) ;
37
+ . iter ( )
38
+ . filter_map ( |p| mtime ( p) . ok ( ) )
39
+ . collect :: < Vec < _ > > ( ) ;
29
40
41
+ // Rebuild metadata if any file is newer than index.html
30
42
if times. iter ( ) . any ( |& time| index_time < time) {
31
43
Command :: new ( env:: var ( "CARGO" ) . unwrap_or_else ( |_| "cargo" . into ( ) ) )
32
44
. arg ( "collect-metadata" )
33
45
. spawn ( )
34
- . unwrap ( )
46
+ . expect ( "Failed to spawn cargo collect-metadata process" )
35
47
. wait ( )
36
- . unwrap ( ) ;
48
+ . expect ( "Cargo collect-metadata process failed" ) ;
37
49
}
38
- if let Some ( url) = url. take ( ) {
39
- thread:: spawn ( move || {
40
- let mut child = Command :: new ( PYTHON )
41
- . arg ( "-m" )
42
- . arg ( "http.server" )
43
- . arg ( port. to_string ( ) )
44
- . current_dir ( "util/gh-pages" )
45
- . spawn ( )
46
- . unwrap ( ) ;
47
- // Give some time for python to start
48
- thread:: sleep ( Duration :: from_millis ( 500 ) ) ;
49
- // Launch browser after first export.py has completed and http.server is up
50
- let _result = opener:: open ( url) ;
51
- child. wait ( ) . unwrap ( ) ;
52
- } ) ;
50
+
51
+ // Start HTTP server and open browser once
52
+ if !server_started {
53
+ if let Some ( url) = url. take ( ) {
54
+ thread:: spawn ( move || {
55
+ let mut child = Command :: new ( PYTHON )
56
+ . arg ( "-m" )
57
+ . arg ( "http.server" )
58
+ . arg ( port. to_string ( ) )
59
+ . current_dir ( "util/gh-pages" )
60
+ . spawn ( )
61
+ . expect ( "Failed to spawn Python HTTP server" ) ;
62
+
63
+ // Wait until server starts
64
+ thread:: sleep ( Duration :: from_millis ( 500 ) ) ;
65
+
66
+ // Open browser after first export
67
+ let _ = opener:: open ( url) ;
68
+
69
+ child. wait ( ) . expect ( "Python HTTP server process failed" ) ;
70
+ } ) ;
71
+ server_started = true ;
72
+ }
53
73
}
74
+
54
75
thread:: sleep ( Duration :: from_millis ( 1000 ) ) ;
55
76
}
56
77
}
57
78
58
- fn mtime ( path : impl AsRef < Path > ) -> SystemTime {
79
+ /// Get the most recent modification time of a file or directory recursively.
80
+ /// Returns `io::Result<SystemTime>`.
81
+ fn mtime ( path : impl AsRef < Path > ) -> io:: Result < SystemTime > {
59
82
let path = path. as_ref ( ) ;
83
+
60
84
if path. is_dir ( ) {
61
- path. read_dir ( )
62
- . into_iter ( )
63
- . flatten ( )
64
- . flatten ( )
65
- . map ( |entry| mtime ( entry. path ( ) ) )
66
- . max ( )
67
- . unwrap_or ( SystemTime :: UNIX_EPOCH )
85
+ let mut latest = SystemTime :: UNIX_EPOCH ;
86
+ for entry in path. read_dir ( ) ? {
87
+ let entry = entry?;
88
+ let entry_time = mtime ( entry. path ( ) ) ?;
89
+ if entry_time > latest {
90
+ latest = entry_time;
91
+ }
92
+ }
93
+ Ok ( latest)
68
94
} else {
69
- path. metadata ( )
70
- . and_then ( |metadata| metadata. modified ( ) )
71
- . unwrap_or ( SystemTime :: UNIX_EPOCH )
95
+ Ok ( path. metadata ( ) ?. modified ( ) ?)
72
96
}
73
97
}
0 commit comments