diff options
Diffstat (limited to 'dom/webgpu/tests/cts/vendor')
-rw-r--r-- | dom/webgpu/tests/cts/vendor/Cargo.lock | 889 | ||||
-rw-r--r-- | dom/webgpu/tests/cts/vendor/Cargo.toml | 20 | ||||
-rw-r--r-- | dom/webgpu/tests/cts/vendor/src/fs.rs | 331 | ||||
-rw-r--r-- | dom/webgpu/tests/cts/vendor/src/main.rs | 565 | ||||
-rw-r--r-- | dom/webgpu/tests/cts/vendor/src/path.rs | 23 | ||||
-rw-r--r-- | dom/webgpu/tests/cts/vendor/src/process.rs | 85 |
6 files changed, 1913 insertions, 0 deletions
diff --git a/dom/webgpu/tests/cts/vendor/Cargo.lock b/dom/webgpu/tests/cts/vendor/Cargo.lock new file mode 100644 index 0000000000..ea51837ca5 --- /dev/null +++ b/dom/webgpu/tests/cts/vendor/Cargo.lock @@ -0,0 +1,889 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "ahash" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + +[[package]] +name = "aho-corasick" +version = "0.7.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" +dependencies = [ + "memchr", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi 0.1.19", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "backtrace" +version = "0.3.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "cc" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clap" +version = "4.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0b0588d44d4d63a87dbd75c136c166bbfd9a86a31cb89e09906521c7d3f5e3" +dependencies = [ + "bitflags", + "clap_derive", + "clap_lex", + "is-terminal", + "once_cell", + "strsim", + "termcolor", +] + +[[package]] +name = "clap_derive" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "684a277d672e91966334af371f1a7b5833f9aa00b07c84e92fbce95e00208ce8" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "350b9cf31731f9957399229e9b2adc51eeabdfbe9d71d9a0552275fd12710d09" +dependencies = [ + "os_str_bytes", +] + +[[package]] +name = "crossbeam" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2801af0d36612ae591caa9568261fddce32ce6e08a7275ea334a06a4ad021a2c" +dependencies = [ + "cfg-if", + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-epoch", + "crossbeam-queue", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf2b3e8478797446514c91ef04bafcb59faba183e621ad488df88983cc14128c" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-queue" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "dircpy" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10b6622b9d0dc20c70e74ff24c56493278d7d9299ac8729deb923703616e5a7e" +dependencies = [ + "jwalk", + "log", + "walkdir", +] + +[[package]] +name = "dunce" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bd4b30a6560bbd9b4620f4de34c3f14f60848e58a9b7216801afcb4c7b31c3c" + +[[package]] +name = "either" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" + +[[package]] +name = "env_logger" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" +dependencies = [ + "humantime", + "is-terminal", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "errno" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" +dependencies = [ + "errno-dragonfly", + "libc", + "winapi", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "format" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "901e1b63ac63f86d9fb836b1ae8b43e5a9f2338975e9de24f36a1af4acf23ac8" +dependencies = [ + "format-core", + "format-macro", +] + +[[package]] +name = "format-core" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e66b70d6700c47044b73e43dd0649e0d6bfef18f87919c23785cdbd1aaa9d3f5" + +[[package]] +name = "format-macro" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f9faac4e57f217563dd1fd58628a0c526aa37a681ffac76ca80d64907370a4c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "getrandom" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "gimli" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4" + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "io-lifetimes" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1abeb7a0dd0f8181267ff8adc397075586500b81b28a73e8a0208b00fc170fb3" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "is-terminal" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b6b32576413a8e69b90e952e4a026476040d81017b80445deda5f2d3921857" +dependencies = [ + "hermit-abi 0.3.1", + "io-lifetimes", + "rustix", + "windows-sys", +] + +[[package]] +name = "is_ci" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "616cde7c720bb2bb5824a224687d8f77bfd38922027f01d825cd7453be5099fb" + +[[package]] +name = "jwalk" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dbcda57db8b6dc067e589628b7348639014e793d9e8137d8cf215e8b133a0bd" +dependencies = [ + "crossbeam", + "rayon", +] + +[[package]] +name = "lets_find_up" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b91a14fb0b4300e025486cc8bc096c7173c2c615ce8f9c6da7829a4af3f5afbd" + +[[package]] +name = "libc" +version = "0.2.139" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" + +[[package]] +name = "linux-raw-sys" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "memoffset" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" +dependencies = [ + "autocfg", +] + +[[package]] +name = "miette" +version = "5.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4afd9b301defa984bbdbe112b4763e093ed191750a0d914a78c1106b2d0fe703" +dependencies = [ + "atty", + "backtrace", + "miette-derive", + "once_cell", + "owo-colors", + "supports-color", + "supports-hyperlinks", + "supports-unicode", + "terminal_size", + "textwrap", + "thiserror", + "unicode-width", +] + +[[package]] +name = "miette-derive" +version = "5.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97c2401ab7ac5282ca5c8b518a87635b1a93762b0b90b9990c509888eeccba29" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "miniz_oxide" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" +dependencies = [ + "adler", +] + +[[package]] +name = "num_cpus" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +dependencies = [ + "hermit-abi 0.2.6", + "libc", +] + +[[package]] +name = "object" +version = "0.30.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" + +[[package]] +name = "os_str_bytes" +version = "6.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee" + +[[package]] +name = "owo-colors" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.51" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rayon" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db3a213adf02b3bcfd2d3846bb41cb22857d131789e01df434fb7e7bc0759b7" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "356a0625f1954f730c0201cdab48611198dc6ce21f4acff55089b5a78e6e835b" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "num_cpus", +] + +[[package]] +name = "regex" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" + +[[package]] +name = "rustc-demangle" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" + +[[package]] +name = "rustix" +version = "0.36.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f43abb88211988493c1abb44a70efa56ff0ce98f233b7b276146f1f3f7ba9644" +dependencies = [ + "bitflags", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "shell-words" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" + +[[package]] +name = "smawk" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f67ad224767faa3c7d8b6d91985b78e70a1324408abcb1cfcc2be4c06bc06043" + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "supports-color" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ba6faf2ca7ee42fdd458f4347ae0a9bd6bcc445ad7cb57ad82b383f18870d6f" +dependencies = [ + "atty", + "is_ci", +] + +[[package]] +name = "supports-hyperlinks" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "590b34f7c5f01ecc9d78dba4b3f445f31df750a67621cf31626f3b7441ce6406" +dependencies = [ + "atty", +] + +[[package]] +name = "supports-unicode" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8b945e45b417b125a8ec51f1b7df2f8df7920367700d1f98aedd21e5735f8b2" +dependencies = [ + "atty", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "termcolor" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "terminal_size" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "textwrap" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7b3e525a49ec206798b40326a44121291b530c963cfb01018f63e135bac543d" +dependencies = [ + "smawk", + "unicode-linebreak", + "unicode-width", +] + +[[package]] +name = "thiserror" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "unicode-ident" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" + +[[package]] +name = "unicode-linebreak" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5faade31a542b8b35855fff6e8def199853b2da8da256da52f52f1316ee3137" +dependencies = [ + "hashbrown", + "regex", +] + +[[package]] +name = "unicode-width" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" + +[[package]] +name = "vendor-webgpu-cts" +version = "0.1.0" +dependencies = [ + "clap", + "dircpy", + "dunce", + "env_logger", + "format", + "lets_find_up", + "log", + "miette", + "regex", + "shell-words", + "thiserror", + "which", +] + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "walkdir" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +dependencies = [ + "same-file", + "winapi", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "which" +version = "4.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269" +dependencies = [ + "either", + "libc", + "once_cell", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" diff --git a/dom/webgpu/tests/cts/vendor/Cargo.toml b/dom/webgpu/tests/cts/vendor/Cargo.toml new file mode 100644 index 0000000000..d7721d1931 --- /dev/null +++ b/dom/webgpu/tests/cts/vendor/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "vendor-webgpu-cts" +version = "0.1.0" +edition = "2021" + +[dependencies] +clap = { version = "4.1.6", features = ["derive"] } +dircpy = "0.3.14" +dunce = "1.0.3" +env_logger = "0.10.0" +format = "0.2.4" +lets_find_up = "0.0.3" +log = "0.4.17" +miette = { version = "5.5.0", features = ["fancy"] } +regex = "1.7.1" +shell-words = "1.1.0" +thiserror = "1.0.38" +which = "4.4.0" + +[workspace] diff --git a/dom/webgpu/tests/cts/vendor/src/fs.rs b/dom/webgpu/tests/cts/vendor/src/fs.rs new file mode 100644 index 0000000000..31697f9758 --- /dev/null +++ b/dom/webgpu/tests/cts/vendor/src/fs.rs @@ -0,0 +1,331 @@ +use std::{ + ffi::OsStr, + fmt::{self, Display}, + fs, + ops::Deref, + path::{Path, PathBuf, StripPrefixError}, +}; + +use miette::{ensure, Context, IntoDiagnostic}; + +#[derive(Debug)] +pub(crate) struct FileRoot { + nickname: &'static str, + path: PathBuf, +} + +impl Eq for FileRoot {} + +impl PartialEq for FileRoot { + fn eq(&self, other: &Self) -> bool { + self.path == other.path + } +} + +impl Ord for FileRoot { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.path.cmp(&other.path) + } +} + +impl PartialOrd for FileRoot { + fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { + Some(self.cmp(other)) + } +} + +impl FileRoot { + pub(crate) fn new<P>(nickname: &'static str, path: P) -> miette::Result<Self> + where + P: AsRef<Path>, + { + let path = path.as_ref(); + Ok(Self { + nickname, + path: dunce::canonicalize(path) + .map_err(miette::Report::msg) + .wrap_err_with(|| format!("failed to canonicalize {path:?}"))?, + }) + } + + pub(crate) fn nickname(&self) -> &str { + self.nickname + } + + pub(crate) fn try_child<P>(&self, path: P) -> Result<Child<'_>, StripPrefixError> + where + P: AsRef<Path>, + { + let path = path.as_ref(); + if path.is_absolute() { + path.strip_prefix(&self.path)?; + } + Ok(Child { + root: self, + path: self.path.join(path), + }) + } + + #[track_caller] + pub(crate) fn child<P>(&self, path: P) -> Child<'_> + where + P: AsRef<Path>, + { + self.try_child(path) + .into_diagnostic() + .wrap_err("invariant violation: `path` is absolute and not a child of this file root") + .unwrap() + } + + fn removed_dir<P>(&self, path: P) -> miette::Result<Child<'_>> + where + P: AsRef<Path>, + { + let path = path.as_ref(); + let child = self.child(path); + if child.exists() { + log::info!("removing old contents of {child}…",); + log::trace!("removing directory {:?}", &*child); + fs::remove_dir_all(&*child) + .map_err(miette::Report::msg) + .wrap_err_with(|| format!("failed to remove old contents of {child}"))?; + } + Ok(child) + } + + fn removed_file<P>(&self, path: P) -> miette::Result<Child<'_>> + where + P: AsRef<Path>, + { + let path = path.as_ref(); + let child = self.child(path); + if child.exists() { + log::info!("removing old copy of {child}…",); + fs::remove_file(&*child) + .map_err(miette::Report::msg) + .wrap_err_with(|| format!("failed to remove old copy of {child}"))?; + } + Ok(child) + } + + pub(crate) fn regen_dir<P>( + &self, + path: P, + gen: impl FnOnce(&Child<'_>) -> miette::Result<()>, + ) -> miette::Result<Child<'_>> + where + P: AsRef<Path>, + { + let child = self.removed_dir(path)?; + gen(&child)?; + ensure!( + child.is_dir(), + "{} was not regenerated for an unknown reason", + child, + ); + Ok(child) + } + + pub(crate) fn regen_file<P>( + &self, + path: P, + gen: impl FnOnce(&Child<'_>) -> miette::Result<()>, + ) -> miette::Result<Child<'_>> + where + P: AsRef<Path>, + { + let child = self.removed_file(path)?; + gen(&child)?; + ensure!( + child.is_file(), + "{} was not regenerated for an unknown reason", + child, + ); + Ok(child) + } +} + +impl Deref for FileRoot { + type Target = Path; + + fn deref(&self) -> &Self::Target { + &self.path + } +} + +impl AsRef<Path> for FileRoot { + fn as_ref(&self) -> &Path { + &self.path + } +} + +impl AsRef<OsStr> for FileRoot { + fn as_ref(&self) -> &OsStr { + self.path.as_os_str() + } +} + +impl Display for FileRoot { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self { nickname, path } = self; + write!(f, "`{}` (AKA `<{nickname}>`)", path.display()) + } +} + +#[derive(Debug, Eq, Ord, PartialEq, PartialOrd)] +pub(crate) struct Child<'a> { + root: &'a FileRoot, + /// NOTE: This is always an absolute path that is a child of the `root`. + path: PathBuf, +} + +impl Child<'_> { + pub(crate) fn relative_path(&self) -> &Path { + let Self { root, path } = self; + path.strip_prefix(root).unwrap() + } + + pub(crate) fn try_child<P>(&self, path: P) -> Result<Self, StripPrefixError> + where + P: AsRef<Path>, + { + let child_path = path.as_ref(); + let Self { root, path } = self; + + if child_path.is_absolute() { + child_path.strip_prefix(path)?; + } + Ok(Child { + root, + path: path.join(child_path), + }) + } + + #[track_caller] + pub(crate) fn child<P>(&self, path: P) -> Self + where + P: AsRef<Path>, + { + self.try_child(path) + .into_diagnostic() + .wrap_err("invariant violation: `path` is absolute and not a child of this child") + .unwrap() + } +} + +impl Deref for Child<'_> { + type Target = Path; + + fn deref(&self) -> &Self::Target { + &self.path + } +} + +impl AsRef<Path> for Child<'_> { + fn as_ref(&self) -> &Path { + &self.path + } +} + +impl AsRef<OsStr> for Child<'_> { + fn as_ref(&self) -> &OsStr { + self.path.as_os_str() + } +} + +impl Display for Child<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "`<{}>{}{}`", + self.root.nickname(), + std::path::MAIN_SEPARATOR, + self.relative_path().display() + ) + } +} + +pub(crate) fn existing_file<P>(path: P) -> P +where + P: AsRef<Path>, +{ + let p = path.as_ref(); + assert!(p.is_file(), "{p:?} does not exist as a file"); + path +} + +pub(crate) fn copy_dir<P, Q>(source: P, dest: Q) -> miette::Result<()> +where + P: Display + AsRef<Path>, + Q: Display + AsRef<Path>, +{ + log::debug!( + "copy-merging directories from {} into {}", + source.as_ref().display(), + dest.as_ref().display(), + ); + ::dircpy::copy_dir(&source, &dest) + .into_diagnostic() + .wrap_err_with(|| format!("failed to copy files from {source} to {dest}")) +} + +pub(crate) fn read_to_string<P>(path: P) -> miette::Result<String> +where + P: AsRef<Path>, +{ + fs::read_to_string(&path) + .into_diagnostic() + .wrap_err_with(|| { + format!( + "failed to read UTF-8 string from path {}", + path.as_ref().display() + ) + }) +} + +pub(crate) fn copy<P1, P2>(from: P1, to: P2) -> miette::Result<u64> +where + P1: AsRef<Path>, + P2: AsRef<Path>, +{ + fs::copy(&from, &to).into_diagnostic().wrap_err_with(|| { + format!( + "failed to copy {} to {}", + from.as_ref().display(), + to.as_ref().display() + ) + }) +} + +pub(crate) fn create_dir_all<P>(path: P) -> miette::Result<()> +where + P: AsRef<Path>, +{ + fs::create_dir_all(&path) + .into_diagnostic() + .wrap_err_with(|| { + format!( + "failed to create directories leading up to {}", + path.as_ref().display() + ) + }) +} + +pub(crate) fn remove_file<P>(path: P) -> miette::Result<()> +where + P: AsRef<Path>, +{ + fs::remove_file(&path) + .into_diagnostic() + .wrap_err_with(|| format!("failed to remove file at path {}", path.as_ref().display())) +} + +pub(crate) fn write<P, C>(path: P, contents: C) -> miette::Result<()> +where + P: AsRef<Path>, + C: AsRef<[u8]>, +{ + fs::write(&path, &contents) + .into_diagnostic() + .wrap_err_with(|| format!("failed to write to path {}", path.as_ref().display())) +} diff --git a/dom/webgpu/tests/cts/vendor/src/main.rs b/dom/webgpu/tests/cts/vendor/src/main.rs new file mode 100644 index 0000000000..750b65c62e --- /dev/null +++ b/dom/webgpu/tests/cts/vendor/src/main.rs @@ -0,0 +1,565 @@ +use std::{ + collections::{BTreeMap, BTreeSet}, + env::{current_dir, set_current_dir}, + path::{Path, PathBuf}, + process::ExitCode, +}; + +use clap::Parser; +use lets_find_up::{find_up_with, FindUpKind, FindUpOptions}; +use miette::{bail, ensure, miette, Context, Diagnostic, IntoDiagnostic, Report, SourceSpan}; +use regex::Regex; + +use crate::{ + fs::{copy_dir, create_dir_all, existing_file, remove_file, FileRoot}, + path::join_path, + process::{which, EasyCommand}, +}; + +mod fs; +mod path; +mod process; + +/// Vendor WebGPU CTS tests from a local Git checkout of [our `gpuweb/cts` fork]. +/// +/// WPT tests are generated into `testing/web-platform/mozilla/tests/webgpu/`. If the set of tests +/// changes upstream, make sure that the generated output still matches up with test expectation +/// metadata in `testing/web-platform/mozilla/meta/webgpu/`. +/// +/// [our `gpuweb/cts` fork]: https://github.com/mozilla/gpuweb-cts +#[derive(Debug, Parser)] +struct CliArgs { + /// A path to the top-level directory of your WebGPU CTS checkout. + cts_checkout_path: PathBuf, +} + +fn main() -> ExitCode { + env_logger::builder() + .filter_level(log::LevelFilter::Info) + .parse_default_env() + .init(); + + let args = CliArgs::parse(); + + match run(args) { + Ok(()) => ExitCode::SUCCESS, + Err(e) => { + log::error!("{e:?}"); + ExitCode::FAILURE + } + } +} + +fn run(args: CliArgs) -> miette::Result<()> { + let CliArgs { cts_checkout_path } = args; + + let orig_working_dir = current_dir().unwrap(); + + let cts_dir = join_path(["dom", "webgpu", "tests", "cts"]); + let cts_vendor_dir = join_path([&*cts_dir, "vendor".as_ref()]); + let gecko_ckt = { + let find_up_opts = || FindUpOptions { + cwd: Path::new("."), + kind: FindUpKind::Dir, + }; + let find_up = |root_dir_name| { + let err = || { + miette!( + concat!( + "failed to find a Mercurial repository ({:?}) in any of current ", + "working directory and its parent directories", + ), + root_dir_name + ) + }; + find_up_with(root_dir_name, find_up_opts()) + .map_err(Report::msg) + .wrap_err_with(err) + .and_then(|loc_opt| loc_opt.ok_or_else(err)) + .map(|mut dir| { + dir.pop(); + dir + }) + }; + let gecko_source_root = find_up(".hg").or_else(|e| match find_up(".git") { + Ok(path) => { + log::debug!("{e:?}"); + Ok(path) + } + Err(e2) => { + log::warn!("{e:?}"); + log::warn!("{e2:?}"); + bail!("failed to find a Gecko repository root") + } + })?; + + let root = FileRoot::new("gecko", &gecko_source_root)?; + log::info!("detected Gecko repository root at {root}"); + + ensure!( + root.try_child(&orig_working_dir) + .map_or(false, |c| c.relative_path() == cts_vendor_dir), + concat!( + "It is expected to run this tool from the root of its Cargo project, ", + "but this does not appear to have been done. Bailing." + ) + ); + + root + }; + + let cts_vendor_dir = gecko_ckt.child(orig_working_dir.parent().unwrap()); + + let wpt_tests_dir = { + let child = gecko_ckt.child(join_path(["testing", "web-platform", "mozilla", "tests"])); + ensure!( + child.is_dir(), + "WPT tests dir ({child}) does not appear to exist" + ); + child + }; + + let (cts_ckt_git_dir, cts_ckt) = { + let failed_find_git_err = || { + miette!(concat!( + "failed to find a Git repository (`.git` directory) in the provided path ", + "and all of its parent directories" + )) + }; + let git_dir = find_up_with( + ".git", + FindUpOptions { + cwd: &cts_checkout_path, + kind: FindUpKind::Dir, + }, + ) + .map_err(Report::msg) + .wrap_err_with(failed_find_git_err)? + .ok_or_else(failed_find_git_err)?; + + let ckt = FileRoot::new("cts", git_dir.parent().unwrap())?; + log::debug!("detected CTS checkout root at {ckt}"); + (git_dir, ckt) + }; + + let git_bin = which("git", "Git binary")?; + let npm_bin = which("npm", "NPM binary")?; + + // XXX: It'd be nice to expose separate operations for copying in source and generating WPT + // cases from the vendored copy. Checks like these really only matter when updating source. + let ensure_no_child = |p1: &FileRoot, p2| { + ensure!( + p1.try_child(p2).is_err(), + "{p1} is a child path of {p2}, which is not supported" + ); + Ok(()) + }; + ensure_no_child(&cts_ckt, &gecko_ckt)?; + ensure_no_child(&gecko_ckt, &cts_ckt)?; + + log::info!("making a vendored copy of checked-in files from {cts_ckt}…",); + gecko_ckt.regen_file( + join_path([&*cts_dir, "checkout_commit.txt".as_ref()]), + |checkout_commit_file| { + let mut git_status_porcelain_cmd = EasyCommand::new(&git_bin, |cmd| { + cmd.args(["status", "--porcelain"]) + .envs([("GIT_DIR", &*cts_ckt_git_dir), ("GIT_WORK_TREE", &*cts_ckt)]) + }); + log::info!( + " …ensuring the working tree and index are clean with {}…", + git_status_porcelain_cmd + ); + let git_status_porcelain_output = git_status_porcelain_cmd.just_stdout_utf8()?; + ensure!( + git_status_porcelain_output.is_empty(), + concat!( + "expected a clean CTS working tree and index, ", + "but {}'s output was not empty; ", + "for reference, it was:\n\n{}", + ), + git_status_porcelain_cmd, + git_status_porcelain_output, + ); + + gecko_ckt.regen_dir(&cts_vendor_dir.join("checkout"), |vendored_ckt_dir| { + log::info!(" …copying files tracked by Git to {vendored_ckt_dir}…"); + let files_to_vendor = { + let mut git_ls_files_cmd = EasyCommand::new(&git_bin, |cmd| { + cmd.arg("ls-files").env("GIT_DIR", &cts_ckt_git_dir) + }); + log::debug!(" …getting files to vendor from {git_ls_files_cmd}…"); + let output = git_ls_files_cmd.just_stdout_utf8()?; + let mut files = output + .split_terminator('\n') + .map(PathBuf::from) + .collect::<BTreeSet<_>>(); + log::trace!(" …files from {git_ls_files_cmd}: {files:#?}"); + + log::trace!(" …validating that files from Git repo still exist…"); + let files_not_found = files + .iter() + .filter(|p| !cts_ckt.child(p).exists()) + .collect::<Vec<_>>(); + ensure!( + files_not_found.is_empty(), + concat!( + "the following files were returned by `git ls-files`, ", + "but do not exist on disk: {:#?}", + ), + files_not_found, + ); + + log::trace!(" …stripping files we actually don't want to vendor…"); + let files_to_actually_not_vendor = [ + // There's no reason to bring this over, and lots of reasons to not bring in + // security-sensitive content unless we have to. + "deploy_key.enc", + ] + .map(Path::new); + log::trace!(" …files we don't want: {files_to_actually_not_vendor:?}"); + for path in files_to_actually_not_vendor { + ensure!( + files.remove(path), + concat!( + "failed to remove {} from list of files to vendor; ", + "does it still exist?" + ), + cts_ckt.child(path) + ); + } + files + }; + + log::debug!(" …now doing the copying…"); + for path in files_to_vendor { + let vendor_from_path = cts_ckt.child(&path); + let vendor_to_path = vendored_ckt_dir.child(&path); + if let Some(parent) = vendor_to_path.parent() { + create_dir_all(vendored_ckt_dir.child(parent))?; + } + log::trace!(" …copying {vendor_from_path} to {vendor_to_path}…"); + fs::copy(&vendor_from_path, &vendor_to_path)?; + } + + Ok(()) + })?; + + log::info!(" …writing commit ref pointed to by `HEAD` to {checkout_commit_file}…"); + let mut git_rev_parse_head_cmd = EasyCommand::new(&git_bin, |cmd| { + cmd.args(["rev-parse", "HEAD"]) + .env("GIT_DIR", &cts_ckt_git_dir) + }); + log::trace!(" …getting output of {git_rev_parse_head_cmd}…"); + fs::write( + checkout_commit_file, + git_rev_parse_head_cmd.just_stdout_utf8()?, + ) + .wrap_err_with(|| format!("failed to write HEAD ref to {checkout_commit_file}")) + }, + )?; + + set_current_dir(&*cts_ckt) + .into_diagnostic() + .wrap_err("failed to change working directory to CTS checkout")?; + log::debug!("changed CWD to {cts_ckt}"); + + let mut npm_ci_cmd = EasyCommand::new(&npm_bin, |cmd| cmd.arg("ci")); + log::info!( + "ensuring a clean {} directory with {npm_ci_cmd}…", + cts_ckt.child("node_modules"), + ); + npm_ci_cmd.spawn()?; + + let out_wpt_dir = cts_ckt.regen_dir("out-wpt", |out_wpt_dir| { + let mut npm_run_wpt_cmd = EasyCommand::new(&npm_bin, |cmd| cmd.args(["run", "wpt"])); + log::info!("generating WPT test cases into {out_wpt_dir} with {npm_run_wpt_cmd}…"); + npm_run_wpt_cmd.spawn() + })?; + + let cts_https_html_path = out_wpt_dir.child("cts.https.html"); + log::info!("refining the output of {cts_https_html_path} with `npm run gen_wpt_cts_html …`…"); + EasyCommand::new(&npm_bin, |cmd| { + cmd.args(["run", "gen_wpt_cts_html"]).arg(existing_file( + &cts_ckt.child("tools/gen_wpt_cfg_unchunked.json"), + )) + }) + .spawn()?; + + { + let extra_cts_https_html_path = out_wpt_dir.child("cts-chunked2sec.https.html"); + log::info!("removing extraneous {extra_cts_https_html_path}…"); + remove_file(&*extra_cts_https_html_path)?; + } + + log::info!("analyzing {cts_https_html_path}…"); + let cts_https_html_content = fs::read_to_string(&*cts_https_html_path)?; + let cts_boilerplate_short_timeout; + let cts_boilerplate_long_timeout; + let cts_cases; + { + { + let (boilerplate, cases_start) = { + let cases_start_idx = cts_https_html_content + .find("<meta name=variant") + .ok_or_else(|| miette!("no test cases found; this is unexpected!"))?; + cts_https_html_content.split_at(cases_start_idx) + }; + + { + if !boilerplate.is_empty() { + #[derive(Debug, Diagnostic, thiserror::Error)] + #[error("last character before test cases was not a newline; bug, or weird?")] + #[diagnostic(severity("warning"))] + struct Oops { + #[label( + "this character ({:?}) was expected to be a newline, so that {}", + source_code.chars().last().unwrap(), + "the test spec. following it is on its own line" + )] + span: SourceSpan, + #[source_code] + source_code: String, + } + ensure!( + boilerplate.ends_with('\n'), + Oops { + span: SourceSpan::from(0..boilerplate.len()), + source_code: cts_https_html_content, + } + ); + } + + // NOTE: Adding `_mozilla` is necessary because [that's how it's mounted][source]. + // + // [source]: https://searchfox.org/mozilla-central/rev/cd2121e7d83af1b421c95e8c923db70e692dab5f/testing/web-platform/mozilla/README#1-4] + log::info!(concat!( + " …fixing `script` paths in WPT boilerplate ", + "so they work as Mozilla-private WPT tests…" + )); + let expected_wpt_script_tag = + "<script type=module src=/webgpu/common/runtime/wpt.js></script>"; + ensure!( + boilerplate.contains(expected_wpt_script_tag), + concat!( + "failed to find expected `script` tag for `wpt.js` ", + "({:?}); did something change upstream?", + ), + expected_wpt_script_tag + ); + let mut boilerplate = boilerplate.replacen( + expected_wpt_script_tag, + "<script type=module src=/_mozilla/webgpu/common/runtime/wpt.js></script>", + 1, + ); + + cts_boilerplate_short_timeout = boilerplate.clone(); + + let timeout_insert_idx = { + let meta_charset_utf8 = "\n<meta charset=utf-8>\n"; + let meta_charset_utf8_idx = + boilerplate.find(meta_charset_utf8).ok_or_else(|| { + miette!( + "could not find {:?} in document; did something change upstream?", + meta_charset_utf8 + ) + })?; + meta_charset_utf8_idx + meta_charset_utf8.len() + }; + boilerplate.insert_str( + timeout_insert_idx, + concat!( + r#"<meta name="timeout" content="long">"#, + " <!-- TODO: narrow to only where it's needed, see ", + "https://bugzilla.mozilla.org/show_bug.cgi?id=1850537", + " -->\n" + ), + ); + cts_boilerplate_long_timeout = boilerplate + }; + + log::info!(" …parsing test variants in {cts_https_html_path}…"); + let mut parsing_failed = false; + let meta_variant_regex = Regex::new(concat!( + "^", + "<meta name=variant content='\\?q=([^']*?):\\*'>", + "$" + )) + .unwrap(); + cts_cases = cases_start + .split_terminator('\n') + .filter_map(|line| { + let path_and_meta = meta_variant_regex + .captures(line) + .map(|caps| (caps[1].to_owned(), line)); + if path_and_meta.is_none() { + parsing_failed = true; + log::error!("line is not a test case: {line:?}"); + } + path_and_meta + }) + .collect::<Vec<_>>(); + ensure!( + !parsing_failed, + "one or more test case lines failed to parse, fix it and try again" + ); + }; + log::trace!("\"original\" HTML boilerplate:\n\n{cts_boilerplate_short_timeout}"); + + ensure!( + !cts_cases.is_empty(), + "no test cases found; this is unexpected!" + ); + log::info!(" …found {} test cases", cts_cases.len()); + } + + cts_ckt.regen_dir(out_wpt_dir.join("cts"), |cts_tests_dir| { + log::info!("re-distributing tests into single file per test path…"); + let mut failed_writing = false; + let mut cts_cases_by_spec_file_dir = BTreeMap::<_, BTreeSet<_>>::new(); + for (path, meta) in cts_cases { + let case_dir = { + // Context: We want to mirror CTS upstream's `src/webgpu/**/*.spec.ts` paths as + // entire WPT tests, with each subtest being a WPT variant. Here's a diagram of + // a CTS path to explain why the logic below is correct: + // + // ```sh + // webgpu:this,is,the,spec.ts,file,path:subtest_in_file:… + // \____/ \___________________________/^\_____________/ + // test `*.spec.ts` file path | | + // \__________________________________/| | + // | | | + // We want this… | …but not this. CTS upstream generates + // | this too, but we don't want to divide + // second ':' character here---/ here (yet). + // ``` + let subtest_and_later_start_idx = + match path.match_indices(':').nth(1).map(|(idx, _s)| idx) { + Some(some) => some, + None => { + failed_writing = true; + log::error!( + concat!( + "failed to split suite and test path segments ", + "from CTS path `{}`" + ), + path + ); + continue; + } + }; + let slashed = + path[..subtest_and_later_start_idx].replace(|c| matches!(c, ':' | ','), "/"); + cts_tests_dir.child(slashed) + }; + if !cts_cases_by_spec_file_dir + .entry(case_dir) + .or_default() + .insert(meta) + { + log::warn!("duplicate entry {meta:?} detected") + } + } + + struct WptEntry<'a> { + cases: BTreeSet<&'a str>, + timeout_length: TimeoutLength, + } + enum TimeoutLength { + Short, + Long, + } + let split_cases = { + let mut split_cases = BTreeMap::new(); + fn insert_with_default_name<'a>( + split_cases: &mut BTreeMap<fs::Child<'a>, WptEntry<'a>>, + spec_file_dir: fs::Child<'a>, + cases: WptEntry<'a>, + ) { + let path = spec_file_dir.child("cts.https.html"); + assert!(split_cases.insert(path, cases).is_none()); + } + { + let dld_path = + &cts_tests_dir.child("webgpu/api/validation/state/device_lost/destroy"); + let (spec_file_dir, cases) = cts_cases_by_spec_file_dir + .remove_entry(dld_path) + .expect("no `device_lost/destroy` tests found; did they move?"); + insert_with_default_name( + &mut split_cases, + spec_file_dir, + WptEntry { + cases, + timeout_length: TimeoutLength::Short, + }, + ); + } + for (spec_file_dir, cases) in cts_cases_by_spec_file_dir { + insert_with_default_name( + &mut split_cases, + spec_file_dir, + WptEntry { + cases, + timeout_length: TimeoutLength::Long, + }, + ); + } + split_cases + }; + + for (path, entry) in split_cases { + let dir = path.parent().expect("no parent found for "); + match create_dir_all(&dir) { + Ok(()) => log::trace!("made directory {}", dir.display()), + Err(e) => { + failed_writing = true; + log::error!("{e:#}"); + continue; + } + } + let file_contents = { + let WptEntry { + cases, + timeout_length, + } = entry; + let content = match timeout_length { + TimeoutLength::Short => &cts_boilerplate_short_timeout, + TimeoutLength::Long => &cts_boilerplate_long_timeout, + }; + let mut content = content.as_bytes().to_vec(); + for meta in cases { + content.extend(meta.as_bytes()); + content.extend(b"\n"); + } + content + }; + match fs::write(&path, &file_contents) + .wrap_err_with(|| miette!("failed to write output to path {path:?}")) + { + Ok(()) => log::debug!(" …wrote {path}"), + Err(e) => { + failed_writing = true; + log::error!("{e:#}"); + } + } + } + ensure!( + !failed_writing, + "failed to write one or more WPT test files; see above output for more details" + ); + log::debug!(" …finished writing new WPT test files!"); + + log::info!(" …removing {cts_https_html_path}, now that it's been divided up…"); + remove_file(&cts_https_html_path)?; + + Ok(()) + })?; + + gecko_ckt.regen_dir(wpt_tests_dir.join("webgpu"), |wpt_webgpu_tests_dir| { + log::info!("copying contents of {out_wpt_dir} to {wpt_webgpu_tests_dir}…"); + copy_dir(&out_wpt_dir, wpt_webgpu_tests_dir) + })?; + + log::info!("All done! Now get your CTS _ON_! :)"); + + Ok(()) +} diff --git a/dom/webgpu/tests/cts/vendor/src/path.rs b/dom/webgpu/tests/cts/vendor/src/path.rs new file mode 100644 index 0000000000..aa5bae2e6d --- /dev/null +++ b/dom/webgpu/tests/cts/vendor/src/path.rs @@ -0,0 +1,23 @@ +use std::path::{Path, PathBuf}; + +/// Construct a [`PathBuf`] from individual [`Path`] components. +/// +/// This is a simple and legible way to construct `PathBuf`s that use the system's native path +/// separator character. (It's ugly to see paths mixing `\` and `/`.) +/// +/// # Examples +/// +/// ```rust +/// # use std::path::Path; +/// # use vendor_webgpu_cts::path::join_path; +/// assert_eq!(&*join_path(["foo", "bar", "baz"]), Path::new("foo/bar/baz")); +/// ``` +pub(crate) fn join_path<I, P>(iter: I) -> PathBuf +where + I: IntoIterator<Item = P>, + P: AsRef<Path>, +{ + let mut path = PathBuf::new(); + path.extend(iter); + path +} diff --git a/dom/webgpu/tests/cts/vendor/src/process.rs b/dom/webgpu/tests/cts/vendor/src/process.rs new file mode 100644 index 0000000000..b36c3b953d --- /dev/null +++ b/dom/webgpu/tests/cts/vendor/src/process.rs @@ -0,0 +1,85 @@ +use std::{ + ffi::{OsStr, OsString}, + fmt::{self, Display}, + iter::once, + process::{Command, Output}, +}; + +use format::lazy_format; +use miette::{ensure, Context, IntoDiagnostic}; + +pub(crate) fn which(name: &'static str, desc: &str) -> miette::Result<OsString> { + let found = ::which::which(name) + .into_diagnostic() + .wrap_err(lazy_format!("failed to find `{name}` executable"))?; + log::debug!("using {desc} from {}", found.display()); + Ok(found.file_name().unwrap().to_owned()) +} + +pub(crate) struct EasyCommand { + inner: Command, +} + +impl EasyCommand { + pub(crate) fn new<C>(cmd: C, f: impl FnOnce(&mut Command) -> &mut Command) -> Self + where + C: AsRef<OsStr>, + { + let mut cmd = Command::new(cmd); + f(&mut cmd); + Self { inner: cmd } + } + + pub(crate) fn spawn(&mut self) -> miette::Result<()> { + log::debug!("spawning {self}…"); + let status = self + .inner + .spawn() + .into_diagnostic() + .wrap_err_with(|| format!("failed to spawn {self}"))? + .wait() + .into_diagnostic() + .wrap_err_with(|| format!("failed to wait for exit code from {self}"))?; + log::debug!("{self} returned {:?}", status.code()); + ensure!(status.success(), "{self} returned {:?}", status.code()); + Ok(()) + } + + fn just_stdout(&mut self) -> miette::Result<Vec<u8>> { + log::debug!("getting `stdout` output of {self}"); + let output = self + .inner + .output() + .into_diagnostic() + .wrap_err_with(|| format!("failed to execute `{self}`"))?; + let Output { + status, + stdout: _, + stderr, + } = &output; + log::debug!("{self} returned {:?}", status.code()); + ensure!( + status.success(), + "{self} returned {:?}; full output: {output:#?}", + status.code(), + ); + assert!(stderr.is_empty()); + Ok(output.stdout) + } + + pub(crate) fn just_stdout_utf8(&mut self) -> miette::Result<String> { + String::from_utf8(self.just_stdout()?) + .into_diagnostic() + .wrap_err_with(|| format!("output of {self} was not UTF-8 (!?)")) + } +} + +impl Display for EasyCommand { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self { inner } = self; + let prog = inner.get_program().to_string_lossy(); + let args = inner.get_args().map(|a| a.to_string_lossy()); + let shell_words = ::shell_words::join(once(prog).chain(args)); + write!(f, "`{shell_words}`") + } +} |