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