3 use indexmap::IndexMap;
4 use std::collections::HashMap;
5 use std::convert::TryInto;
7 const DIST_SERVER: &str = "https://static.rust-lang.org";
8 const COMPILER_COMPONENTS: &[&str] = &["rustc", "rust-std", "cargo"];
9 const RUSTFMT_COMPONENTS: &[&str] = &["rustfmt-preview"];
14 checksums: IndexMap<String, String>,
18 fn new() -> Result<Self, Error> {
19 let channel = match std::fs::read_to_string("src/ci/channel")?.trim() {
20 "stable" => Channel::Stable,
21 "beta" => Channel::Beta,
22 "nightly" => Channel::Nightly,
23 other => anyhow::bail!("unsupported channel: {}", other),
26 // Split "1.42.0" into [1, 42, 0]
27 let version = std::fs::read_to_string("src/version")?
30 .map(|val| val.parse())
31 .collect::<Result<Vec<_>, _>>()?
33 .map_err(|_| anyhow::anyhow!("failed to parse version"))?;
35 Ok(Self { channel, version, checksums: IndexMap::new() })
38 fn update_json(mut self) -> Result<(), Error> {
43 serde_json::to_string_pretty(&Stage0 {
44 comment: "Generated by `./x.py run src/tools/bump-stage0`. \
45 Run that command again to update the bootstrap compiler.",
46 dist_server: DIST_SERVER.into(),
47 compiler: self.detect_compiler()?,
48 rustfmt: self.detect_rustfmt()?,
50 // Keys are sorted here instead of beforehand because values in this map
51 // are added while filling the other struct fields just above this block.
52 self.checksums.sort_keys();
61 // Currently Rust always bootstraps from the previous stable release, and in our train model
62 // this means that the master branch bootstraps from beta, beta bootstraps from current stable,
63 // and stable bootstraps from the previous stable release.
65 // On the master branch the compiler version is configured to `beta` whereas if you're looking
66 // at the beta or stable channel you'll likely see `1.x.0` as the version, with the previous
67 // release's version number.
68 fn detect_compiler(&mut self) -> Result<Stage0Toolchain, Error> {
69 let channel = match self.channel {
70 Channel::Stable | Channel::Beta => {
71 // The 1.XX manifest points to the latest point release of that minor release.
72 format!("{}.{}", self.version[0], self.version[1] - 1)
74 Channel::Nightly => "beta".to_string(),
77 let manifest = fetch_manifest(&channel)?;
78 self.collect_checksums(&manifest, COMPILER_COMPONENTS)?;
81 version: if self.channel == Channel::Nightly {
84 // The version field is like "1.42.0 (abcdef1234 1970-01-01)"
88 .expect("invalid version field")
95 /// We use a nightly rustfmt to format the source because it solves some bootstrapping issues
96 /// with use of new syntax in this repo. For the beta/stable channels rustfmt is not provided,
97 /// as we don't want to depend on rustfmt from nightly there.
98 fn detect_rustfmt(&mut self) -> Result<Option<Stage0Toolchain>, Error> {
99 if self.channel != Channel::Nightly {
103 let manifest = fetch_manifest("nightly")?;
104 self.collect_checksums(&manifest, RUSTFMT_COMPONENTS)?;
105 Ok(Some(Stage0Toolchain { date: manifest.date, version: "nightly".into() }))
108 fn collect_checksums(&mut self, manifest: &Manifest, components: &[&str]) -> Result<(), Error> {
109 let prefix = format!("{}/", DIST_SERVER);
110 for component in components {
114 .ok_or_else(|| anyhow::anyhow!("missing component from manifest: {}", component))?;
115 for target in pkg.target.values() {
116 for pair in &[(&target.url, &target.hash), (&target.xz_url, &target.xz_hash)] {
117 if let (Some(url), Some(sha256)) = pair {
119 .strip_prefix(&prefix)
121 anyhow::anyhow!("url doesn't start with dist server base: {}", url)
124 self.checksums.insert(url, sha256.clone());
133 fn main() -> Result<(), Error> {
134 let tool = Tool::new()?;
139 fn fetch_manifest(channel: &str) -> Result<Manifest, Error> {
140 Ok(toml::from_slice(&http_get(&format!(
141 "{}/dist/channel-rust-{}.toml",
146 fn http_get(url: &str) -> Result<Vec<u8>, Error> {
147 let mut data = Vec::new();
148 let mut handle = Easy::new();
149 handle.fail_on_error(true)?;
152 let mut transfer = handle.transfer();
153 transfer.write_function(|new_data| {
154 data.extend_from_slice(new_data);
162 #[derive(Debug, PartialEq, Eq)]
169 #[derive(Debug, serde::Serialize)]
171 #[serde(rename = "__comment")]
172 comment: &'static str,
174 compiler: Stage0Toolchain,
175 rustfmt: Option<Stage0Toolchain>,
176 checksums_sha256: IndexMap<String, String>,
179 #[derive(Debug, serde::Serialize)]
180 struct Stage0Toolchain {
185 #[derive(Debug, serde::Deserialize)]
188 pkg: HashMap<String, ManifestPackage>,
191 #[derive(Debug, serde::Deserialize)]
192 struct ManifestPackage {
194 target: HashMap<String, ManifestTargetPackage>,
197 #[derive(Debug, serde::Deserialize)]
198 struct ManifestTargetPackage {
200 hash: Option<String>,
201 xz_url: Option<String>,
202 xz_hash: Option<String>,