@@ -36,16 +36,19 @@ use regex_lite::{Regex, RegexBuilder};
3636use std:: { ffi:: OsString , sync:: LazyLock } ;
3737use xshell:: Shell ;
3838
39- use crate :: util:: git_version_at_least;
39+ use crate :: util:: { git_version_at_least, looks_like_git_sha } ;
4040
4141/// Path within the repository where the CTS will be checked out.
4242const CTS_CHECKOUT_PATH : & str = "cts" ;
4343
44+ /// Path to git's `shallow` file.
45+ const GIT_SHALLOW_PATH : & str = ".git/shallow" ;
46+
4447/// Path within the repository to a file containing the git revision of the CTS to check out.
4548const CTS_REVISION_PATH : & str = "cts_runner/revision.txt" ;
4649
4750/// URL of the CTS git repository.
48- const CTS_GIT_URL : & str = "https://github.com/ gpuweb/cts.git " ;
51+ const CTS_GITHUB_PATH : & str = "gpuweb/cts" ;
4952
5053/// Path to default CTS test list.
5154const CTS_DEFAULT_TEST_LIST : & str = "cts_runner/test.lst" ;
@@ -56,6 +59,100 @@ struct TestLine {
5659 pub fails_if : Vec < String > ,
5760}
5861
62+ fn have_git_sha ( shell : & Shell , sha : & str ) -> bool {
63+ shell
64+ . cmd ( "git" )
65+ . args ( [ "cat-file" , "commit" , sha] )
66+ . quiet ( )
67+ . ignore_stdout ( )
68+ . ignore_stderr ( )
69+ . run ( )
70+ . is_ok ( )
71+ }
72+
73+ fn maybe_deepen_git_repo ( shell : & Shell , desired : & str ) -> anyhow:: Result < ( ) > {
74+ if shell
75+ . cmd ( "curl" )
76+ . args ( [
77+ "-f" ,
78+ "-L" ,
79+ "-I" ,
80+ "-H" ,
81+ "Accept: application/vnd.github+json" ,
82+ "-H" ,
83+ "X-GitHub-Api-Version: 2022-11-28" ,
84+ ] )
85+ . arg ( format ! (
86+ "https://api.github.com/repos/{CTS_GITHUB_PATH}/commits/{desired}"
87+ ) )
88+ . quiet ( )
89+ . ignore_stdout ( )
90+ . ignore_stderr ( )
91+ . run ( )
92+ . is_err ( )
93+ {
94+ log:: warn!( "Not deepening repo because the desired CTS SHA was not found on GitHub." ) ;
95+ return Ok ( ( ) ) ;
96+ }
97+
98+ if !shell. path_exists ( GIT_SHALLOW_PATH ) {
99+ log:: warn!( "Not deepening repo because it is not a shallow clone." ) ;
100+ return Ok ( ( ) ) ;
101+ }
102+
103+ let shallow = shell
104+ . read_file ( GIT_SHALLOW_PATH )
105+ . context ( format ! (
106+ "Failed to read git shallow SHA from {GIT_SHALLOW_PATH}"
107+ ) ) ?
108+ . trim ( )
109+ . to_string ( ) ;
110+
111+ if !looks_like_git_sha ( & shallow) {
112+ log:: warn!(
113+ "Automatic deepening of git repo requires a shallow clone with a single graft point"
114+ ) ;
115+ return Ok ( ( ) ) ;
116+ }
117+
118+ let output = shell
119+ . cmd ( "curl" )
120+ . args ( [
121+ "-f" ,
122+ "-L" ,
123+ "-H" ,
124+ "Accept: application/vnd.github+json" ,
125+ "-H" ,
126+ "X-GitHub-Api-Version: 2022-11-28" ,
127+ ] )
128+ . arg ( format ! (
129+ "https://api.github.com/repos/{CTS_GITHUB_PATH}/compare/{desired}...{shallow}"
130+ ) )
131+ . output ( )
132+ . context ( "Error calling GitHub API" ) ?;
133+
134+ let gh_json: serde_json:: Map < String , serde_json:: Value > =
135+ serde_json:: from_slice ( & output. stdout ) . context ( "Failed parsing GitHub API JSON" ) ?;
136+
137+ let Some ( deepen_count) = gh_json
138+ . get ( "total_commits" )
139+ . and_then ( serde_json:: Value :: as_u64)
140+ else {
141+ bail ! ( "missing or invalid total_commits" ) ;
142+ } ;
143+
144+ log:: info!( "Fetching CTS with --deepen {deepen_count}" ) ;
145+
146+ shell
147+ . cmd ( "git" )
148+ . args ( [ "fetch" , "--deepen" , & deepen_count. to_string ( ) ] )
149+ . quiet ( )
150+ . run ( )
151+ . context ( "Failed to deepen git repo" ) ?;
152+
153+ Ok ( ( ) )
154+ }
155+
59156pub fn run_cts (
60157 shell : Shell ,
61158 mut args : Arguments ,
@@ -142,7 +239,11 @@ pub fn run_cts(
142239 }
143240 let mut cmd = shell
144241 . cmd ( "git" )
145- . args ( [ "clone" , CTS_GIT_URL , CTS_CHECKOUT_PATH ] )
242+ . args ( [
243+ "clone" ,
244+ & format ! ( "https://github.com/{CTS_GITHUB_PATH}.git" ) ,
245+ CTS_CHECKOUT_PATH ,
246+ ] )
146247 . quiet ( ) ;
147248
148249 if git_version_at_least ( & shell, [ 2 , 49 , 0 ] ) ? {
@@ -187,23 +288,25 @@ pub fn run_cts(
187288 }
188289
189290 // If we don't have the CTS commit we want, try to fetch it.
190- if shell
191- . cmd ( "git" )
192- . args ( [ "cat-file" , "commit" , & cts_revision] )
193- . quiet ( )
194- . ignore_stdout ( )
195- . ignore_stderr ( )
196- . run ( )
197- . is_err ( )
198- {
199- log:: info!( "Fetching CTS" ) ;
291+ if !have_git_sha ( & shell, & cts_revision) {
292+ log:: info!( "Desired SHA not found, fetching CTS" ) ;
200293 shell
201294 . cmd ( "git" )
202295 . args ( [ "fetch" , "--quiet" ] )
203296 . quiet ( )
204297 . run ( )
205298 . context ( "Failed to fetch CTS" ) ?;
206299 }
300+
301+ // If we still don't have the commit we want, maybe we need more history.
302+ if !have_git_sha ( & shell, & cts_revision) {
303+ log:: info!( "Desired SHA still not found, checking if missing from shallow clone" ) ;
304+ maybe_deepen_git_repo ( & shell, & cts_revision) ?;
305+ }
306+
307+ if !have_git_sha ( & shell, & cts_revision) {
308+ bail ! ( "Unable to obtain the desired CTS revision {cts_revision}" ) ;
309+ }
207310 } else {
208311 shell. change_dir ( CTS_CHECKOUT_PATH ) ;
209312 }
0 commit comments