@@ -15,6 +15,7 @@ use mdbook::{
15
15
16
16
const CHANNELS : & [ & str ] = & [ "stable" , "beta" , "nightly" ] ;
17
17
const CHANNEL_URL_PREFIX : & str = "https://static.rust-lang.org/dist/channel-rust-" ;
18
+ const MANIFESTS_URL : & str = "https://static.rust-lang.org/manifests.txt" ;
18
19
const RUSTUP_URLS : & str =
19
20
"https://raw.githubusercontent.com/rust-lang/rustup.rs/stable/ci/cloudfront-invalidation.txt" ;
20
21
@@ -45,6 +46,8 @@ pub struct Blacksmith {
45
46
rustup : Vec < String > ,
46
47
stable_version : Option < String > ,
47
48
platforms : BTreeMap < String , Platform > ,
49
+ #[ serde( default ) ]
50
+ previous_stable_versions : Vec < ( String , Vec < String > ) > ,
48
51
}
49
52
50
53
impl Blacksmith {
@@ -123,6 +126,140 @@ impl Blacksmith {
123
126
}
124
127
}
125
128
129
+ let latest_stable_version = & blacksmith. stable_version . clone ( ) . unwrap ( ) ;
130
+
131
+ // We need to use a map to deduplicate entries and sort them in the correct order.
132
+ // There are multiple entries for stable 1.8.0, 1.14.0, 1.15.1, 1.49.0 in MANIFESTS_URL.
133
+ // Keys contain (minor_version, patch_version) and values contain (full_version, platforms).
134
+ let mut previous_stable_version_map: BTreeMap < ( u32 , u32 ) , ( String , Vec < String > ) > =
135
+ BTreeMap :: new ( ) ;
136
+
137
+ // Go over stable versions in https://static.rust-lang.org/manifests.txt in reverse order.
138
+ let manifests_content = reqwest:: blocking:: get ( MANIFESTS_URL ) ?. text ( ) ?;
139
+ let stable_manifest_url_regex = regex:: Regex :: new (
140
+ r"^static\.rust-lang\.org/dist/\d{4}-\d{2}-\d{2}/channel-rust-1\.(\d+)\.(\d+)\.toml$" ,
141
+ )
142
+ . unwrap ( ) ;
143
+ for manifest_url in manifests_content. lines ( ) . rev ( ) {
144
+ let minor;
145
+ let patch;
146
+
147
+ // Check if it's a stable version.
148
+ if let Some ( captures) = stable_manifest_url_regex. captures ( & ( manifest_url) ) {
149
+ minor = captures. get ( 1 ) . unwrap ( ) . as_str ( ) . parse :: < u32 > ( ) . unwrap ( ) ;
150
+ patch = captures. get ( 2 ) . unwrap ( ) . as_str ( ) . parse :: < u32 > ( ) . unwrap ( ) ;
151
+ } else {
152
+ continue ;
153
+ }
154
+
155
+ let full_version = format ! ( "1.{}.{}" , minor, patch) ;
156
+
157
+ // Check if we already processed that version.
158
+ if previous_stable_version_map. contains_key ( & ( minor, patch) ) {
159
+ continue ;
160
+ }
161
+
162
+ // Skip latest stable version.
163
+ if & full_version == latest_stable_version {
164
+ continue ;
165
+ }
166
+
167
+ // Download https://static.rust-lang.org/dist/channel-rust-{major.minor.patch}.toml and process it.
168
+ let channel_url = format ! ( "{}{}.toml" , CHANNEL_URL_PREFIX , full_version) ;
169
+
170
+ let content = reqwest:: blocking:: get ( & channel_url) ?. text ( ) ?;
171
+ let rust = toml:: from_str :: < crate :: channel:: Channel > ( & content) ?
172
+ . pkg
173
+ . rust ;
174
+
175
+ log:: info!(
176
+ "Found {} targets for stable v{}" ,
177
+ rust. target. len( ) ,
178
+ rust. version
179
+ ) ;
180
+
181
+ let version = rust. version . split ( ' ' ) . next ( ) . unwrap ( ) . to_string ( ) ;
182
+
183
+ // Sanity check.
184
+ assert_eq ! ( & full_version, & version) ;
185
+
186
+ let platforms = rust
187
+ . target
188
+ . into_iter ( )
189
+ . filter_map ( |( target, content) | {
190
+ if content. available {
191
+ Some ( target)
192
+ } else {
193
+ None
194
+ }
195
+ } )
196
+ . collect :: < Vec < _ > > ( ) ;
197
+
198
+ previous_stable_version_map. insert ( ( minor, patch) , ( version, platforms) ) ;
199
+ }
200
+
201
+ // There are no manifests for stable versions before 1.8.0,
202
+ // so we hardcode them instead.
203
+ // i686-pc-windows-msvc wasn't supported until version 1.3.0.
204
+ for minor in 3 ..8 {
205
+ previous_stable_version_map. insert (
206
+ ( minor, 0 ) ,
207
+ (
208
+ format ! ( "1.{}.0" , minor) ,
209
+ Vec :: from ( [
210
+ "i686-apple-darwin" . to_string ( ) ,
211
+ "i686-pc-windows-gnu" . to_string ( ) ,
212
+ "i686-pc-windows-msvc" . to_string ( ) ,
213
+ "i686-unknown-linux-gnu" . to_string ( ) ,
214
+ "x86_64-apple-darwin" . to_string ( ) ,
215
+ "x86_64-pc-windows-gnu" . to_string ( ) ,
216
+ "x86_64-pc-windows-msvc" . to_string ( ) ,
217
+ "x86_64-unknown-linux-gnu" . to_string ( ) ,
218
+ ] ) ,
219
+ ) ,
220
+ ) ;
221
+ }
222
+
223
+ // x86_64-pc-windows-msvc wasn't supported until version 1.2.0.
224
+ previous_stable_version_map. insert (
225
+ ( 2 , 0 ) ,
226
+ (
227
+ "1.2.0" . to_string ( ) ,
228
+ Vec :: from ( [
229
+ "i686-apple-darwin" . to_string ( ) ,
230
+ "i686-pc-windows-gnu" . to_string ( ) ,
231
+ "i686-unknown-linux-gnu" . to_string ( ) ,
232
+ "x86_64-apple-darwin" . to_string ( ) ,
233
+ "x86_64-pc-windows-gnu" . to_string ( ) ,
234
+ "x86_64-pc-windows-msvc" . to_string ( ) ,
235
+ "x86_64-unknown-linux-gnu" . to_string ( ) ,
236
+ ] ) ,
237
+ ) ,
238
+ ) ;
239
+
240
+ for minor in 0 ..2 {
241
+ previous_stable_version_map. insert (
242
+ ( minor, 0 ) ,
243
+ (
244
+ format ! ( "1.{}.0" , minor) ,
245
+ Vec :: from ( [
246
+ "i686-apple-darwin" . to_string ( ) ,
247
+ "i686-pc-windows-gnu" . to_string ( ) ,
248
+ "i686-unknown-linux-gnu" . to_string ( ) ,
249
+ "x86_64-apple-darwin" . to_string ( ) ,
250
+ "x86_64-pc-windows-gnu" . to_string ( ) ,
251
+ "x86_64-unknown-linux-gnu" . to_string ( ) ,
252
+ ] ) ,
253
+ ) ,
254
+ ) ;
255
+ }
256
+
257
+ for ( _, ( version, platforms) ) in previous_stable_version_map. into_iter ( ) . rev ( ) {
258
+ blacksmith
259
+ . previous_stable_versions
260
+ . push ( ( version, platforms) ) ;
261
+ }
262
+
126
263
blacksmith. last_update = unix_time ( ) ;
127
264
Ok ( blacksmith)
128
265
}
@@ -169,28 +306,28 @@ impl Blacksmith {
169
306
writeln ! ( buffer, "---------|--------|------|--------" ) . unwrap ( ) ;
170
307
171
308
for ( name, platform) in & self . platforms {
172
- let extension = if name. contains ( "windows" ) {
173
- "msi"
309
+ let extensions : & [ & str ] = if name. contains ( "windows" ) {
310
+ & [ "msi" , "tar.xz" ]
174
311
} else if name. contains ( "darwin" ) {
175
- "pkg"
312
+ & [ "pkg" , "tar.xz" ]
176
313
} else {
177
- "tar.xz"
314
+ & [ "tar.xz" ]
178
315
} ;
179
316
180
317
let stable_links = platform
181
318
. stable
182
319
. as_ref ( )
183
- . map ( |version| generate_standalone_links ( "rust" , version, name, extension ) )
320
+ . map ( |version| generate_standalone_links ( "rust" , version, name, extensions ) )
184
321
. unwrap_or_else ( String :: new) ;
185
322
186
323
let beta_links = if platform. beta {
187
- generate_standalone_links ( "rust" , "beta" , name, extension )
324
+ generate_standalone_links ( "rust" , "beta" , name, extensions )
188
325
} else {
189
326
String :: new ( )
190
327
} ;
191
328
192
329
let nightly_links = if platform. nightly {
193
- generate_standalone_links ( "rust" , "nightly" , name, extension )
330
+ generate_standalone_links ( "rust" , "nightly" , name, extensions )
194
331
} else {
195
332
String :: new ( )
196
333
} ;
@@ -209,6 +346,45 @@ impl Blacksmith {
209
346
buffer
210
347
}
211
348
349
+ /// Generates tables of links to the previous stable standalone installer packages for
350
+ /// each platform.
351
+ fn generate_previous_stable_standalone_installers_tables ( & self ) -> String {
352
+ let mut buffer = String :: new ( ) ;
353
+
354
+ for ( stable_version, platforms) in & self . previous_stable_versions {
355
+ writeln ! ( buffer, "## Stable ({})" , stable_version) . unwrap ( ) ;
356
+ writeln ! ( buffer, "" ) . unwrap ( ) ;
357
+
358
+ writeln ! ( buffer, "platform | stable ({})" , stable_version) . unwrap ( ) ;
359
+ writeln ! ( buffer, "---------|--------" ) . unwrap ( ) ;
360
+
361
+ for name in platforms {
362
+ let extensions: & [ & str ] = if name. contains ( "windows" ) {
363
+ & [ "msi" , "tar.gz" ]
364
+ } else if name. contains ( "darwin" ) {
365
+ & [ "pkg" , "tar.gz" ]
366
+ } else {
367
+ & [ "tar.gz" ]
368
+ } ;
369
+
370
+ let stable_links =
371
+ generate_standalone_links ( "rust" , stable_version, name, extensions) ;
372
+
373
+ writeln ! (
374
+ buffer,
375
+ "`{name}` | {stable}" ,
376
+ name = name,
377
+ stable = stable_links,
378
+ )
379
+ . unwrap ( ) ;
380
+ }
381
+
382
+ writeln ! ( buffer, "" ) . unwrap ( ) ;
383
+ }
384
+
385
+ buffer
386
+ }
387
+
212
388
/// Generates a similar table to `generate_standalone_installers_table`
213
389
/// except for the rust source code packages.
214
390
fn generate_source_code_table ( & self ) -> String {
@@ -224,15 +400,15 @@ impl Blacksmith {
224
400
buffer,
225
401
"stable ({}) | {}" ,
226
402
stable_version,
227
- generate_standalone_links( "rustc" , stable_version, "src" , "tar.xz" )
403
+ generate_standalone_links( "rustc" , stable_version, "src" , & [ "tar.xz" ] )
228
404
)
229
405
. unwrap ( ) ;
230
406
} else {
231
407
writeln ! (
232
408
buffer,
233
409
"{} | {}" ,
234
410
channel,
235
- generate_standalone_links( "rustc" , & channel, "src" , "tar.xz" )
411
+ generate_standalone_links( "rustc" , & channel, "src" , & [ "tar.xz" ] )
236
412
)
237
413
. unwrap ( ) ;
238
414
}
@@ -244,20 +420,27 @@ impl Blacksmith {
244
420
245
421
/// Generates links to standalone installers provided a rust version or channel,
246
422
/// target name, and file extension.
247
- fn generate_standalone_links ( base : & str , stem : & str , name : & str , extension : & str ) -> String {
248
- let url = format ! (
249
- "https://static.rust-lang.org/dist/{base}-{stem}-{name}.{extension}" ,
250
- extension = extension,
251
- name = name,
252
- stem = stem,
253
- base = base,
254
- ) ;
255
-
256
- format ! (
257
- "[{extension}]({url}) <br> [{extension}.asc]({url}.asc)" ,
258
- extension = extension,
259
- url = url,
260
- )
423
+ fn generate_standalone_links ( base : & str , stem : & str , name : & str , extensions : & [ & str ] ) -> String {
424
+ let mut result = String :: new ( ) ;
425
+ for extension in extensions {
426
+ if !result. is_empty ( ) {
427
+ result. push_str ( " <br> " ) ;
428
+ }
429
+ let url = format ! (
430
+ "https://static.rust-lang.org/dist/{base}-{stem}-{name}.{extension}" ,
431
+ extension = extension,
432
+ name = name,
433
+ stem = stem,
434
+ base = base,
435
+ ) ;
436
+
437
+ result. push_str ( & format ! (
438
+ "[{extension}]({url}) <br> [{extension}.asc]({url}.asc)" ,
439
+ extension = extension,
440
+ url = url,
441
+ ) ) ;
442
+ }
443
+ result
261
444
}
262
445
263
446
fn unix_time ( ) -> Option < u64 > {
@@ -288,16 +471,23 @@ impl Preprocessor for Blacksmith {
288
471
289
472
let rustup_init_list = self . generate_rustup_init_list ( ) ;
290
473
let standalone_installers_table = self . generate_standalone_installers_table ( ) ;
474
+ let previous_stable_standalone_installers_tables =
475
+ self . generate_previous_stable_standalone_installers_tables ( ) ;
291
476
let source_code_table = self . generate_source_code_table ( ) ;
292
477
293
478
// TODO: Currently we're performing a global search for any of the
294
479
// variables as that's the most flexible for adding more dynamic
295
- // content, and the time to traverse is fast enough to not be noticable .
480
+ // content, and the time to traverse is fast enough to not be noticeable .
296
481
// However if the processing time begins to become a bottleneck this
297
482
// should change.
298
483
for item in & mut book. sections {
299
484
recursive_replace ( item, "{{#rustup_init_list}}" , & rustup_init_list) ;
300
485
recursive_replace ( item, "{{#installer_table}}" , & standalone_installers_table) ;
486
+ recursive_replace (
487
+ item,
488
+ "{{#previous_stable_standalone_installers_tables}}" ,
489
+ & previous_stable_standalone_installers_tables,
490
+ ) ;
301
491
recursive_replace ( item, "{{#source_code_table}}" , & source_code_table) ;
302
492
}
303
493
0 commit comments