]> git.proxmox.com Git - rustc.git/blame - src/tools/bump-stage0/src/main.rs
New upstream version 1.68.2+dfsg1
[rustc.git] / src / tools / bump-stage0 / src / main.rs
CommitLineData
f25598a0 1use anyhow::{Context, Error};
c295e0f8
XL
2use curl::easy::Easy;
3use indexmap::IndexMap;
4use std::collections::HashMap;
5use std::convert::TryInto;
6
923072b8 7const PATH: &str = "src/stage0.json";
c295e0f8
XL
8const COMPILER_COMPONENTS: &[&str] = &["rustc", "rust-std", "cargo"];
9const RUSTFMT_COMPONENTS: &[&str] = &["rustfmt-preview"];
10
11struct Tool {
923072b8
FG
12 config: Config,
13 comments: Vec<String>,
14
c295e0f8 15 channel: Channel,
f25598a0 16 date: Option<String>,
c295e0f8
XL
17 version: [u16; 3],
18 checksums: IndexMap<String, String>,
19}
20
21impl Tool {
f25598a0 22 fn new(date: Option<String>) -> Result<Self, Error> {
c295e0f8
XL
23 let channel = match std::fs::read_to_string("src/ci/channel")?.trim() {
24 "stable" => Channel::Stable,
25 "beta" => Channel::Beta,
26 "nightly" => Channel::Nightly,
27 other => anyhow::bail!("unsupported channel: {}", other),
28 };
29
30 // Split "1.42.0" into [1, 42, 0]
31 let version = std::fs::read_to_string("src/version")?
32 .trim()
33 .split('.')
34 .map(|val| val.parse())
35 .collect::<Result<Vec<_>, _>>()?
36 .try_into()
37 .map_err(|_| anyhow::anyhow!("failed to parse version"))?;
38
923072b8
FG
39 let existing: Stage0 = serde_json::from_slice(&std::fs::read(PATH)?)?;
40
41 Ok(Self {
42 channel,
43 version,
f25598a0 44 date,
923072b8
FG
45 config: existing.config,
46 comments: existing.comments,
47 checksums: IndexMap::new(),
48 })
c295e0f8
XL
49 }
50
51 fn update_json(mut self) -> Result<(), Error> {
52 std::fs::write(
923072b8 53 PATH,
c295e0f8
XL
54 format!(
55 "{}\n",
56 serde_json::to_string_pretty(&Stage0 {
c295e0f8
XL
57 compiler: self.detect_compiler()?,
58 rustfmt: self.detect_rustfmt()?,
59 checksums_sha256: {
60 // Keys are sorted here instead of beforehand because values in this map
61 // are added while filling the other struct fields just above this block.
62 self.checksums.sort_keys();
63 self.checksums
923072b8
FG
64 },
65 config: self.config,
66 comments: self.comments,
c295e0f8
XL
67 })?
68 ),
69 )?;
70 Ok(())
71 }
72
73 // Currently Rust always bootstraps from the previous stable release, and in our train model
74 // this means that the master branch bootstraps from beta, beta bootstraps from current stable,
75 // and stable bootstraps from the previous stable release.
76 //
77 // On the master branch the compiler version is configured to `beta` whereas if you're looking
78 // at the beta or stable channel you'll likely see `1.x.0` as the version, with the previous
79 // release's version number.
80 fn detect_compiler(&mut self) -> Result<Stage0Toolchain, Error> {
81 let channel = match self.channel {
82 Channel::Stable | Channel::Beta => {
83 // The 1.XX manifest points to the latest point release of that minor release.
84 format!("{}.{}", self.version[0], self.version[1] - 1)
85 }
86 Channel::Nightly => "beta".to_string(),
87 };
88
f25598a0 89 let manifest = fetch_manifest(&self.config, &channel, self.date.as_deref())?;
c295e0f8
XL
90 self.collect_checksums(&manifest, COMPILER_COMPONENTS)?;
91 Ok(Stage0Toolchain {
92 date: manifest.date,
93 version: if self.channel == Channel::Nightly {
94 "beta".to_string()
95 } else {
96 // The version field is like "1.42.0 (abcdef1234 1970-01-01)"
97 manifest.pkg["rust"]
98 .version
99 .split_once(' ')
100 .expect("invalid version field")
101 .0
102 .to_string()
103 },
104 })
105 }
106
107 /// We use a nightly rustfmt to format the source because it solves some bootstrapping issues
108 /// with use of new syntax in this repo. For the beta/stable channels rustfmt is not provided,
109 /// as we don't want to depend on rustfmt from nightly there.
110 fn detect_rustfmt(&mut self) -> Result<Option<Stage0Toolchain>, Error> {
111 if self.channel != Channel::Nightly {
112 return Ok(None);
113 }
114
f25598a0 115 let manifest = fetch_manifest(&self.config, "nightly", self.date.as_deref())?;
c295e0f8
XL
116 self.collect_checksums(&manifest, RUSTFMT_COMPONENTS)?;
117 Ok(Some(Stage0Toolchain { date: manifest.date, version: "nightly".into() }))
118 }
119
120 fn collect_checksums(&mut self, manifest: &Manifest, components: &[&str]) -> Result<(), Error> {
923072b8 121 let prefix = format!("{}/", self.config.dist_server);
c295e0f8
XL
122 for component in components {
123 let pkg = manifest
124 .pkg
125 .get(*component)
126 .ok_or_else(|| anyhow::anyhow!("missing component from manifest: {}", component))?;
127 for target in pkg.target.values() {
128 for pair in &[(&target.url, &target.hash), (&target.xz_url, &target.xz_hash)] {
129 if let (Some(url), Some(sha256)) = pair {
130 let url = url
131 .strip_prefix(&prefix)
132 .ok_or_else(|| {
133 anyhow::anyhow!("url doesn't start with dist server base: {}", url)
134 })?
135 .to_string();
136 self.checksums.insert(url, sha256.clone());
137 }
138 }
139 }
140 }
141 Ok(())
142 }
143}
144
145fn main() -> Result<(), Error> {
f25598a0 146 let tool = Tool::new(std::env::args().nth(1))?;
c295e0f8
XL
147 tool.update_json()?;
148 Ok(())
149}
150
f25598a0
FG
151fn fetch_manifest(config: &Config, channel: &str, date: Option<&str>) -> Result<Manifest, Error> {
152 let url = if let Some(date) = date {
153 format!("{}/dist/{}/channel-rust-{}.toml", config.dist_server, date, channel)
154 } else {
155 format!("{}/dist/channel-rust-{}.toml", config.dist_server, channel)
156 };
157
158 Ok(toml::from_slice(&http_get(&url)?)?)
c295e0f8
XL
159}
160
161fn http_get(url: &str) -> Result<Vec<u8>, Error> {
162 let mut data = Vec::new();
163 let mut handle = Easy::new();
164 handle.fail_on_error(true)?;
165 handle.url(url)?;
166 {
167 let mut transfer = handle.transfer();
168 transfer.write_function(|new_data| {
169 data.extend_from_slice(new_data);
170 Ok(new_data.len())
171 })?;
f25598a0 172 transfer.perform().context(format!("failed to fetch {url}"))?;
c295e0f8
XL
173 }
174 Ok(data)
175}
176
177#[derive(Debug, PartialEq, Eq)]
178enum Channel {
179 Stable,
180 Beta,
181 Nightly,
182}
183
923072b8 184#[derive(Debug, serde::Serialize, serde::Deserialize)]
c295e0f8 185struct Stage0 {
923072b8
FG
186 config: Config,
187 // Comments are explicitly below the config, do not move them above.
188 //
189 // Downstream forks of the compiler codebase can change the configuration values defined above,
190 // but doing so would risk merge conflicts whenever they import new changes that include a
191 // bootstrap compiler bump.
192 //
193 // To lessen the pain, a big block of comments is placed between the configuration and the
194 // auto-generated parts of the file, preventing git diffs of the config to include parts of the
195 // auto-generated content and vice versa. This should prevent merge conflicts.
196 #[serde(rename = "__comments")]
197 comments: Vec<String>,
c295e0f8
XL
198 compiler: Stage0Toolchain,
199 rustfmt: Option<Stage0Toolchain>,
200 checksums_sha256: IndexMap<String, String>,
201}
202
923072b8
FG
203#[derive(Debug, serde::Serialize, serde::Deserialize)]
204struct Config {
205 dist_server: String,
064997fb
FG
206 // There are other fields in the configuration, which will be read by src/bootstrap or other
207 // tools consuming stage0.json. To avoid the need to update bump-stage0 every time a new field
208 // is added, we collect all the fields in an untyped Value and serialize them back with the
209 // same order and structure they were deserialized in.
210 #[serde(flatten)]
211 other: serde_json::Value,
923072b8
FG
212}
213
214#[derive(Debug, serde::Serialize, serde::Deserialize)]
c295e0f8
XL
215struct Stage0Toolchain {
216 date: String,
217 version: String,
218}
219
923072b8 220#[derive(Debug, serde::Serialize, serde::Deserialize)]
c295e0f8
XL
221struct Manifest {
222 date: String,
223 pkg: HashMap<String, ManifestPackage>,
224}
225
923072b8 226#[derive(Debug, serde::Serialize, serde::Deserialize)]
c295e0f8
XL
227struct ManifestPackage {
228 version: String,
229 target: HashMap<String, ManifestTargetPackage>,
230}
231
923072b8 232#[derive(Debug, serde::Serialize, serde::Deserialize)]
c295e0f8 233struct ManifestTargetPackage {
c295e0f8
XL
234 url: Option<String>,
235 hash: Option<String>,
236 xz_url: Option<String>,
237 xz_hash: Option<String>,
238}