Skip to content

Commit 7816390

Browse files
andyleisersoncwfitzgerald
authored andcommitted
Make vendor-web-sys xtask accept a SHA
Also, update wasm-bindgen URLs
1 parent 0c30efe commit 7816390

File tree

3 files changed

+157
-138
lines changed

3 files changed

+157
-138
lines changed

xtask/src/cts.rs

Lines changed: 2 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ use regex_lite::{Regex, RegexBuilder};
3636
use std::{ffi::OsString, sync::LazyLock};
3737
use xshell::Shell;
3838

39+
use crate::util::git_version_at_least;
40+
3941
/// Path within the repository where the CTS will be checked out.
4042
const CTS_CHECKOUT_PATH: &str = "cts";
4143

@@ -244,119 +246,3 @@ pub fn run_cts(shell: Shell, mut args: Arguments) -> anyhow::Result<()> {
244246

245247
Ok(())
246248
}
247-
248-
fn git_version_at_least(shell: &Shell, version: GitVersion) -> anyhow::Result<bool> {
249-
let output = shell
250-
.cmd("git")
251-
.args(["--version"])
252-
.output()
253-
.context("Failed to invoke `git --version`")?;
254-
255-
let Some(code) = output.status.code() else {
256-
anyhow::bail!("`git --version` failed to return an exit code; interrupt via signal, maybe?")
257-
};
258-
259-
anyhow::ensure!(code == 0, "`git --version` returned a nonzero exit code");
260-
261-
let fmt_err_msg = "`git --version` did not have the expected structure";
262-
263-
let stdout = String::from_utf8(output.stdout).expect(fmt_err_msg);
264-
265-
let parsed = parse_git_version_output(&stdout).expect(fmt_err_msg);
266-
267-
Ok(parsed >= version)
268-
}
269-
270-
pub type GitVersion = [u8; 3];
271-
272-
fn parse_git_version_output(output: &str) -> anyhow::Result<GitVersion> {
273-
const PREFIX: &str = "git version ";
274-
275-
let raw_version = output
276-
.strip_prefix(PREFIX)
277-
.with_context(|| format!("missing `{PREFIX}` prefix"))?;
278-
279-
let raw_version = raw_version.trim_end(); // There should always be a newline at the end, but
280-
// we don't care if it's missing.
281-
282-
// Git for Windows suffixes the version with ".windows.<n>".
283-
// Strip it if present.
284-
let raw_version = raw_version
285-
.split_once(".windows")
286-
.map_or(raw_version, |(before, _after)| before);
287-
288-
let parsed = GitVersion::try_from(
289-
raw_version
290-
.splitn(3, '.')
291-
.enumerate()
292-
.map(|(idx, s)| {
293-
s.parse().with_context(|| {
294-
format!("failed to parse version number {idx} ({s:?}) as `u8`")
295-
})
296-
})
297-
.collect::<Result<Vec<_>, _>>()?,
298-
)
299-
.map_err(|vec| anyhow::Error::msg(format!("less than 3 version numbers found: {vec:?}")))?;
300-
301-
log::debug!("detected Git version {raw_version}");
302-
303-
Ok(parsed)
304-
}
305-
306-
#[test]
307-
fn test_git_version_parsing() {
308-
macro_rules! test_ok {
309-
($input:expr, $expected:expr) => {
310-
assert_eq!(parse_git_version_output($input).unwrap(), $expected);
311-
};
312-
}
313-
test_ok!("git version 2.3.0", [2, 3, 0]);
314-
test_ok!("git version 0.255.0", [0, 255, 0]);
315-
test_ok!("git version 4.5.6", [4, 5, 6]);
316-
test_ok!("git version 2.3.0.windows.1", [2, 3, 0]);
317-
318-
macro_rules! test_err {
319-
($input:expr, $msg:expr) => {
320-
assert_eq!(
321-
parse_git_version_output($input).unwrap_err().to_string(),
322-
$msg
323-
)
324-
};
325-
}
326-
test_err!("2.3.0", "missing `git version ` prefix");
327-
test_err!("", "missing `git version ` prefix");
328-
329-
test_err!(
330-
"git version 1.2",
331-
"less than 3 version numbers found: [1, 2]"
332-
);
333-
334-
test_err!(
335-
"git version 9001",
336-
"failed to parse version number 0 (\"9001\") as `u8`"
337-
);
338-
test_err!(
339-
"git version ",
340-
"failed to parse version number 0 (\"\") as `u8`"
341-
);
342-
test_err!(
343-
"git version asdf",
344-
"failed to parse version number 0 (\"asdf\") as `u8`"
345-
);
346-
test_err!(
347-
"git version 23.beta",
348-
"failed to parse version number 1 (\"beta\") as `u8`"
349-
);
350-
test_err!(
351-
"git version 1.2.wat",
352-
"failed to parse version number 2 (\"wat\") as `u8`"
353-
);
354-
test_err!(
355-
"git version 1.2.3.",
356-
"failed to parse version number 2 (\"3.\") as `u8`"
357-
);
358-
test_err!(
359-
"git version 1.2.3.4",
360-
"failed to parse version number 2 (\"3.4\") as `u8`"
361-
);
362-
}

xtask/src/util.rs

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,17 @@
11
use std::{io, process::Command};
22

3+
use anyhow::Context;
4+
use xshell::Shell;
5+
36
pub(crate) struct Program {
47
pub crate_name: &'static str,
58
pub binary_name: &'static str,
69
}
710

11+
pub(crate) fn looks_like_git_sha(input: &str) -> bool {
12+
input.len() == 40 && input.chars().all(|c| c.is_ascii_hexdigit())
13+
}
14+
815
pub(crate) fn check_all_programs(programs: &[Program]) -> anyhow::Result<()> {
916
let mut failed_crates = Vec::new();
1017
for &Program {
@@ -41,3 +48,119 @@ pub(crate) fn check_all_programs(programs: &[Program]) -> anyhow::Result<()> {
4148

4249
Ok(())
4350
}
51+
52+
pub(crate) fn git_version_at_least(shell: &Shell, version: GitVersion) -> anyhow::Result<bool> {
53+
let output = shell
54+
.cmd("git")
55+
.args(["--version"])
56+
.output()
57+
.context("Failed to invoke `git --version`")?;
58+
59+
let Some(code) = output.status.code() else {
60+
anyhow::bail!("`git --version` failed to return an exit code; interrupt via signal, maybe?")
61+
};
62+
63+
anyhow::ensure!(code == 0, "`git --version` returned a nonzero exit code");
64+
65+
let fmt_err_msg = "`git --version` did not have the expected structure";
66+
67+
let stdout = String::from_utf8(output.stdout).expect(fmt_err_msg);
68+
69+
let parsed = parse_git_version_output(&stdout).expect(fmt_err_msg);
70+
71+
Ok(parsed >= version)
72+
}
73+
74+
pub(crate) type GitVersion = [u8; 3];
75+
76+
fn parse_git_version_output(output: &str) -> anyhow::Result<GitVersion> {
77+
const PREFIX: &str = "git version ";
78+
79+
let raw_version = output
80+
.strip_prefix(PREFIX)
81+
.with_context(|| format!("missing `{PREFIX}` prefix"))?;
82+
83+
let raw_version = raw_version.trim_end(); // There should always be a newline at the end, but
84+
// we don't care if it's missing.
85+
86+
// Git for Windows suffixes the version with ".windows.<n>".
87+
// Strip it if present.
88+
let raw_version = raw_version
89+
.split_once(".windows")
90+
.map_or(raw_version, |(before, _after)| before);
91+
92+
let parsed = GitVersion::try_from(
93+
raw_version
94+
.splitn(3, '.')
95+
.enumerate()
96+
.map(|(idx, s)| {
97+
s.parse().with_context(|| {
98+
format!("failed to parse version number {idx} ({s:?}) as `u8`")
99+
})
100+
})
101+
.collect::<Result<Vec<_>, _>>()?,
102+
)
103+
.map_err(|vec| anyhow::Error::msg(format!("less than 3 version numbers found: {vec:?}")))?;
104+
105+
log::debug!("detected Git version {raw_version}");
106+
107+
Ok(parsed)
108+
}
109+
110+
#[test]
111+
fn test_git_version_parsing() {
112+
macro_rules! test_ok {
113+
($input:expr, $expected:expr) => {
114+
assert_eq!(parse_git_version_output($input).unwrap(), $expected);
115+
};
116+
}
117+
test_ok!("git version 2.3.0", [2, 3, 0]);
118+
test_ok!("git version 0.255.0", [0, 255, 0]);
119+
test_ok!("git version 4.5.6", [4, 5, 6]);
120+
test_ok!("git version 2.3.0.windows.1", [2, 3, 0]);
121+
122+
macro_rules! test_err {
123+
($input:expr, $msg:expr) => {
124+
assert_eq!(
125+
parse_git_version_output($input).unwrap_err().to_string(),
126+
$msg
127+
)
128+
};
129+
}
130+
test_err!("2.3.0", "missing `git version ` prefix");
131+
test_err!("", "missing `git version ` prefix");
132+
133+
test_err!(
134+
"git version 1.2",
135+
"less than 3 version numbers found: [1, 2]"
136+
);
137+
138+
test_err!(
139+
"git version 9001",
140+
"failed to parse version number 0 (\"9001\") as `u8`"
141+
);
142+
test_err!(
143+
"git version ",
144+
"failed to parse version number 0 (\"\") as `u8`"
145+
);
146+
test_err!(
147+
"git version asdf",
148+
"failed to parse version number 0 (\"asdf\") as `u8`"
149+
);
150+
test_err!(
151+
"git version 23.beta",
152+
"failed to parse version number 1 (\"beta\") as `u8`"
153+
);
154+
test_err!(
155+
"git version 1.2.wat",
156+
"failed to parse version number 2 (\"wat\") as `u8`"
157+
);
158+
test_err!(
159+
"git version 1.2.3.",
160+
"failed to parse version number 2 (\"3.\") as `u8`"
161+
);
162+
test_err!(
163+
"git version 1.2.3.4",
164+
"failed to parse version number 2 (\"3.4\") as `u8`"
165+
);
166+
}

xtask/src/vendor_web_sys.rs

Lines changed: 32 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@ use pico_args::Arguments;
33
use std::fmt::Write;
44
use xshell::Shell;
55

6-
use crate::bad_arguments;
6+
use crate::{
7+
bad_arguments,
8+
util::{git_version_at_least, looks_like_git_sha},
9+
};
710

811
/// Path to the webgpu_sys folder relative to the root of the repository
912
const WEBGPU_SYS_PATH: &str = "wgpu/src/backend/webgpu/webgpu_sys";
@@ -198,24 +201,31 @@ pub(crate) fn run_vendor_web_sys(shell: Shell, mut args: Arguments) -> anyhow::R
198201
.remove_path(WEBGPU_SYS_PATH)
199202
.context("could not remove webgpu_sys")?;
200203

201-
if let Some(ref version) = version {
204+
if let Some(version) = version.as_deref() {
202205
eprintln!("# Cloning wasm-bindgen repository with version {version}");
203-
shell
204-
.cmd("git")
205-
.args([
206-
"clone",
207-
"-b",
208-
version,
209-
"--depth",
210-
"1",
211-
git_url
212-
.as_deref()
213-
.unwrap_or("https://github.com/rustwasm/wasm-bindgen.git"),
214-
WASM_BINDGEN_TEMP_CLONE_PATH,
215-
])
216-
.ignore_stderr()
217-
.run()
218-
.context("Could not clone wasm-bindgen repository")?;
206+
let mut cmd = shell.cmd("git").args(["clone"]);
207+
208+
if looks_like_git_sha(version) {
209+
if git_version_at_least(&shell, [2, 49, 0])? {
210+
cmd = cmd.args(["--revision", version]);
211+
} else {
212+
bad_arguments!("Must have git >= 2.49 to clone a SHA with --revision");
213+
}
214+
} else {
215+
cmd = cmd.args(["-b", version]);
216+
}
217+
218+
cmd.args([
219+
"--depth",
220+
"1",
221+
git_url
222+
.as_deref()
223+
.unwrap_or("https://github.com/wasm-bindgen/wasm-bindgen.git"),
224+
WASM_BINDGEN_TEMP_CLONE_PATH,
225+
])
226+
.ignore_stderr()
227+
.run()
228+
.context("Could not clone wasm-bindgen repository")?;
219229
}
220230

221231
if let Some(ref path) = path_to_checkout_arg {
@@ -229,7 +239,7 @@ pub(crate) fn run_vendor_web_sys(shell: Shell, mut args: Arguments) -> anyhow::R
229239
// The indentation here does not matter, as rustfmt will normalize it.
230240
let file_prefix = format!("\
231241
// DO NOT EDIT THIS FILE!
232-
//
242+
//
233243
// This module part of a subset of web-sys that is used by wgpu's webgpu backend.
234244
//
235245
// These bindings are vendored into wgpu for the sole purpose of letting
@@ -246,8 +256,8 @@ pub(crate) fn run_vendor_web_sys(shell: Shell, mut args: Arguments) -> anyhow::R
246256
// Vendoring also allows us to avoid building `web-sys` with
247257
// `--cfg=web_sys_unstable_apis`, needed to get the WebGPU bindings.
248258
//
249-
// If you want to improve the generated code, please submit a PR to the https://github.com/rustwasm/wasm-bindgen repository.
250-
//
259+
// If you want to improve the generated code, please submit a PR to the https://github.com/wasm-bindgen/wasm-bindgen repository.
260+
//
251261
// This file was generated by the `cargo xtask vendor-web-sys {argument_description}` command.\n"
252262
);
253263

@@ -286,7 +296,7 @@ pub(crate) fn run_vendor_web_sys(shell: Shell, mut args: Arguments) -> anyhow::R
286296
let mut module_file_contents = format!(
287297
"\
288298
//! Bindings to the WebGPU API.
289-
//!
299+
//!
290300
//! Internally vendored from the `web-sys` crate until the WebGPU binding are stabilized.
291301
{file_prefix}
292302
#![allow(unused_imports, non_snake_case)]\n"

0 commit comments

Comments
 (0)