@@ -10,14 +10,18 @@ use super::tests::LIBCORE_TESTS_SRC;
10
10
use super :: utils:: { copy_dir_recursively, git_command, retry_spawn_and_wait, spawn_and_wait} ;
11
11
12
12
pub ( crate ) fn prepare ( dirs : & Dirs , rustc : & Path ) {
13
- RelPath :: DOWNLOAD . ensure_fresh ( dirs) ;
13
+ RelPath :: DOWNLOAD . ensure_exists ( dirs) ;
14
+ super :: tests:: RAND_REPO . fetch ( dirs) ;
15
+ super :: tests:: REGEX_REPO . fetch ( dirs) ;
16
+ super :: tests:: PORTABLE_SIMD_REPO . fetch ( dirs) ;
14
17
18
+ // FIXME do this on the fly?
15
19
prepare_stdlib ( dirs, rustc) ;
16
20
prepare_coretests ( dirs, rustc) ;
17
21
18
- super :: tests:: RAND_REPO . fetch ( dirs) ;
19
- super :: tests:: REGEX_REPO . fetch ( dirs) ;
20
- super :: tests:: PORTABLE_SIMD_REPO . fetch ( dirs) ;
22
+ super :: tests:: RAND_REPO . patch ( dirs) ;
23
+ super :: tests:: REGEX_REPO . patch ( dirs) ;
24
+ super :: tests:: PORTABLE_SIMD_REPO . patch ( dirs) ;
21
25
}
22
26
23
27
fn prepare_stdlib ( dirs : & Dirs , rustc : & Path ) {
@@ -61,21 +65,57 @@ fn prepare_coretests(dirs: &Dirs, rustc: &Path) {
61
65
pub ( crate ) struct GitRepo {
62
66
url : GitRepoUrl ,
63
67
rev : & ' static str ,
68
+ content_hash : & ' static str ,
64
69
patch_name : & ' static str ,
65
70
}
66
71
67
72
enum GitRepoUrl {
68
73
Github { user : & ' static str , repo : & ' static str } ,
69
74
}
70
75
76
+ // Note: This uses a hasher which is not cryptographically secure. This is fine as the hash is meant
77
+ // to protect against accidental modification and outdated downloads, not against manipulation.
78
+ fn hash_file ( file : & std:: path:: Path ) -> u64 {
79
+ let contents = std:: fs:: read ( file) . unwrap ( ) ;
80
+ #[ allow( deprecated) ]
81
+ let mut hasher = std:: hash:: SipHasher :: new ( ) ;
82
+ std:: hash:: Hash :: hash ( & contents, & mut hasher) ;
83
+ std:: hash:: Hasher :: finish ( & hasher)
84
+ }
85
+
86
+ fn hash_dir ( dir : & std:: path:: Path ) -> u64 {
87
+ let mut sub_hashes = std:: collections:: BTreeMap :: new ( ) ;
88
+ for entry in std:: fs:: read_dir ( dir) . unwrap ( ) {
89
+ let entry = entry. unwrap ( ) ;
90
+ if entry. file_type ( ) . unwrap ( ) . is_dir ( ) {
91
+ sub_hashes
92
+ . insert ( entry. file_name ( ) . to_str ( ) . unwrap ( ) . to_owned ( ) , hash_dir ( & entry. path ( ) ) ) ;
93
+ } else {
94
+ sub_hashes
95
+ . insert ( entry. file_name ( ) . to_str ( ) . unwrap ( ) . to_owned ( ) , hash_file ( & entry. path ( ) ) ) ;
96
+ }
97
+ }
98
+ #[ allow( deprecated) ]
99
+ let mut hasher = std:: hash:: SipHasher :: new ( ) ;
100
+ std:: hash:: Hash :: hash ( & sub_hashes, & mut hasher) ;
101
+ std:: hash:: Hasher :: finish ( & hasher)
102
+ }
103
+
71
104
impl GitRepo {
72
105
pub ( crate ) const fn github (
73
106
user : & ' static str ,
74
107
repo : & ' static str ,
75
108
rev : & ' static str ,
109
+ content_hash : & ' static str ,
76
110
patch_name : & ' static str ,
77
111
) -> GitRepo {
78
- GitRepo { url : GitRepoUrl :: Github { user, repo } , rev, patch_name }
112
+ GitRepo { url : GitRepoUrl :: Github { user, repo } , rev, content_hash, patch_name }
113
+ }
114
+
115
+ fn download_dir ( & self , dirs : & Dirs ) -> PathBuf {
116
+ match self . url {
117
+ GitRepoUrl :: Github { user : _, repo } => RelPath :: DOWNLOAD . join ( repo) . to_path ( dirs) ,
118
+ }
79
119
}
80
120
81
121
pub ( crate ) const fn source_dir ( & self ) -> RelPath {
@@ -85,15 +125,42 @@ impl GitRepo {
85
125
}
86
126
87
127
pub ( crate ) fn fetch ( & self , dirs : & Dirs ) {
88
- let download_dir = match self . url {
89
- GitRepoUrl :: Github { user : _, repo } => RelPath :: DOWNLOAD . join ( repo) . to_path ( dirs) ,
90
- } ;
91
- let source_dir = self . source_dir ( ) ;
128
+ let download_dir = self . download_dir ( dirs) ;
129
+
130
+ if download_dir. exists ( ) {
131
+ let actual_hash = format ! ( "{:016x}" , hash_dir( & download_dir) ) ;
132
+ if actual_hash == self . content_hash {
133
+ println ! ( "[FRESH] {}" , download_dir. display( ) ) ;
134
+ return ;
135
+ } else {
136
+ println ! (
137
+ "Mismatched content hash for {download_dir}: {actual_hash} != {content_hash}. Downloading again." ,
138
+ download_dir = download_dir. display( ) ,
139
+ content_hash = self . content_hash,
140
+ ) ;
141
+ }
142
+ }
143
+
92
144
match self . url {
93
145
GitRepoUrl :: Github { user, repo } => {
94
146
clone_repo_shallow_github ( dirs, & download_dir, user, repo, self . rev ) ;
95
147
}
96
148
}
149
+
150
+ let actual_hash = format ! ( "{:016x}" , hash_dir( & download_dir) ) ;
151
+ if actual_hash != self . content_hash {
152
+ println ! (
153
+ "Download of {download_dir} failed with mismatched content hash: {actual_hash} != {content_hash}" ,
154
+ download_dir = download_dir. display( ) ,
155
+ content_hash = self . content_hash,
156
+ ) ;
157
+ std:: process:: exit ( 1 ) ;
158
+ }
159
+ }
160
+
161
+ pub ( crate ) fn patch ( & self , dirs : & Dirs ) {
162
+ let download_dir = self . download_dir ( dirs) ;
163
+ let source_dir = self . source_dir ( ) ;
97
164
source_dir. ensure_fresh ( dirs) ;
98
165
copy_dir_recursively ( & download_dir, & source_dir. to_path ( dirs) ) ;
99
166
apply_patches ( dirs, self . patch_name , & source_dir. to_path ( dirs) ) ;
0 commit comments