@@ -15,6 +15,7 @@ use mdbook::{
1515
1616const CHANNELS : & [ & str ] = & [ "stable" , "beta" , "nightly" ] ;
1717const CHANNEL_URL_PREFIX : & str = "https://static.rust-lang.org/dist/channel-rust-" ;
18+ const MANIFESTS_URL : & str = "https://static.rust-lang.org/manifests.txt" ;
1819const RUSTUP_URLS : & str =
1920 "https://raw.githubusercontent.com/rust-lang/rustup.rs/stable/ci/cloudfront-invalidation.txt" ;
2021
@@ -45,6 +46,8 @@ pub struct Blacksmith {
4546 rustup : Vec < String > ,
4647 stable_version : Option < String > ,
4748 platforms : BTreeMap < String , Platform > ,
49+ #[ serde( default ) ]
50+ previous_stable_versions : Vec < ( String , Vec < String > ) > ,
4851}
4952
5053impl Blacksmith {
@@ -123,6 +126,64 @@ impl Blacksmith {
123126 }
124127 }
125128
129+ let latest_stable_version = & blacksmith. stable_version . clone ( ) . unwrap ( ) ;
130+
131+ // Go over stable versions in https://static.rust-lang.org/manifests.txt in reverse order.
132+ let manifests_content = reqwest:: blocking:: get ( MANIFESTS_URL ) ?. text ( ) ?;
133+ let stable_manifest_url_regex =
134+ regex:: Regex :: new ( r"^static\.rust-lang\.org/dist/\d{4}-\d{2}-\d{2}/channel-rust-1\.(\d+)\.(\d+)\.toml$" ) . unwrap ( ) ;
135+ for manifest_url in manifests_content. lines ( ) . rev ( ) {
136+ let minor;
137+ let patch;
138+
139+ // Check if it's a stable version.
140+ if let Some ( captures) = stable_manifest_url_regex. captures ( & ( manifest_url) ) {
141+ minor = captures. get ( 1 ) . unwrap ( ) . as_str ( ) ;
142+ patch = captures. get ( 2 ) . unwrap ( ) . as_str ( ) ;
143+ } else {
144+ continue
145+ }
146+
147+ let full_version = format ! ( "1.{}.{}" , minor, patch) ;
148+
149+ // Skip latest stable version.
150+ if & full_version == latest_stable_version {
151+ continue
152+ }
153+
154+ // Download https://static.rust-lang.org/dist/channel-rust-{major.minor.patch}.toml and process it.
155+ let channel_url = format ! ( "{}{}.toml" , CHANNEL_URL_PREFIX , full_version) ;
156+
157+ let content = reqwest:: blocking:: get ( & channel_url) ?. text ( ) ?;
158+ let rust = toml:: from_str :: < crate :: channel:: Channel > ( & content) ?
159+ . pkg
160+ . rust ;
161+
162+ log:: info!(
163+ "Found {} targets for stable v{}" ,
164+ rust. target. len( ) ,
165+ rust. version
166+ ) ;
167+
168+ let version = rust. version . split ( ' ' ) . next ( ) . unwrap ( ) . to_string ( ) ;
169+
170+ let platforms = rust
171+ . target
172+ . into_iter ( )
173+ . filter_map ( |( target, content) | {
174+ if content. available {
175+ Some ( target)
176+ } else {
177+ None
178+ }
179+ } )
180+ . collect :: < Vec < _ > > ( ) ;
181+
182+ blacksmith
183+ . previous_stable_versions
184+ . push ( ( version. clone ( ) , platforms) ) ;
185+ }
186+
126187 blacksmith. last_update = unix_time ( ) ;
127188 Ok ( blacksmith)
128189 }
@@ -209,6 +270,45 @@ impl Blacksmith {
209270 buffer
210271 }
211272
273+ /// Generates tables of links to the previous stable standalone installer packages for
274+ /// each platform.
275+ fn generate_previous_stable_standalone_installers_tables ( & self ) -> String {
276+ let mut buffer = String :: new ( ) ;
277+
278+ for ( stable_version, platforms) in & self . previous_stable_versions {
279+ writeln ! ( buffer, "## Stable ({})" , stable_version) . unwrap ( ) ;
280+ writeln ! ( buffer, "" ) . unwrap ( ) ;
281+
282+ writeln ! ( buffer, "platform | stable ({})" , stable_version) . unwrap ( ) ;
283+ writeln ! ( buffer, "---------|--------" ) . unwrap ( ) ;
284+
285+ for name in platforms {
286+ let extension = if name. contains ( "windows" ) {
287+ "msi"
288+ } else if name. contains ( "darwin" ) {
289+ "pkg"
290+ } else {
291+ "tar.gz"
292+ } ;
293+
294+ let stable_links =
295+ generate_standalone_links ( "rust" , stable_version, name, extension) ;
296+
297+ writeln ! (
298+ buffer,
299+ "`{name}` | {stable}" ,
300+ name = name,
301+ stable = stable_links,
302+ )
303+ . unwrap ( ) ;
304+ }
305+
306+ writeln ! ( buffer, "" ) . unwrap ( ) ;
307+ }
308+
309+ buffer
310+ }
311+
212312 /// Generates a similar table to `generate_standalone_installers_table`
213313 /// except for the rust source code packages.
214314 fn generate_source_code_table ( & self ) -> String {
@@ -288,16 +388,23 @@ impl Preprocessor for Blacksmith {
288388
289389 let rustup_init_list = self . generate_rustup_init_list ( ) ;
290390 let standalone_installers_table = self . generate_standalone_installers_table ( ) ;
391+ let previous_stable_standalone_installers_tables =
392+ self . generate_previous_stable_standalone_installers_tables ( ) ;
291393 let source_code_table = self . generate_source_code_table ( ) ;
292394
293395 // TODO: Currently we're performing a global search for any of the
294396 // 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 .
397+ // content, and the time to traverse is fast enough to not be noticeable .
296398 // However if the processing time begins to become a bottleneck this
297399 // should change.
298400 for item in & mut book. sections {
299401 recursive_replace ( item, "{{#rustup_init_list}}" , & rustup_init_list) ;
300402 recursive_replace ( item, "{{#installer_table}}" , & standalone_installers_table) ;
403+ recursive_replace (
404+ item,
405+ "{{#previous_stable_standalone_installers_tables}}" ,
406+ & previous_stable_standalone_installers_tables,
407+ ) ;
301408 recursive_replace ( item, "{{#source_code_table}}" , & source_code_table) ;
302409 }
303410
0 commit comments