@@ -3,16 +3,21 @@ use anyhow::Result;
33use std:: collections:: HashMap ;
44use std:: path:: PathBuf ;
55use std:: process:: Command ;
6+ use std:: thread;
7+ use std:: time:: { Duration , Instant } ;
68
79const CRATE_OWNERS : & [ & str ] = & [ "cloutiertyler" , "jdetter" , "bfops" , "rekhoff" , "spacetimedb-devops" ] ;
10+ const CRATES_IO_POLL_INTERVAL : Duration = Duration :: from_secs ( 15 ) ;
11+ const CRATES_IO_POLL_TIMEOUT : Duration = Duration :: from_secs ( 15 * 60 ) ;
812
913pub struct CratesRelease {
14+ pub version : String ,
1015 pub dry_run : bool ,
1116}
1217
1318impl CratesRelease {
14- pub fn new ( dry_run : bool ) -> Self {
15- Self { dry_run }
19+ pub fn new ( version : String , dry_run : bool ) -> Self {
20+ Self { version , dry_run }
1621 }
1722
1823 /// Publishes a single crate to crates.io
@@ -61,6 +66,50 @@ impl CratesRelease {
6166 ) )
6267 }
6368
69+ fn wait_for_crate_available ( & self , crate_name : & str , version : & str ) -> Result < ( ) , String > {
70+ let spec = format ! ( "{}@{}" , crate_name, version) ;
71+ let deadline = Instant :: now ( ) + CRATES_IO_POLL_TIMEOUT ;
72+ let mut attempt = 1 ;
73+
74+ println ! (
75+ "Waiting for {} to be visible in the crates.io index before publishing dependent crates..." ,
76+ spec
77+ ) ;
78+
79+ loop {
80+ let mut cmd = Command :: new ( "cargo" ) ;
81+ cmd. args ( [ "info" , & spec] ) ;
82+ util:: print_command ( & cmd) ;
83+
84+ let output = cmd
85+ . output ( )
86+ . map_err ( |e| format ! ( "Failed to execute cargo info {}: {}" , spec, e) ) ?;
87+
88+ if output. status . success ( ) {
89+ println ! ( "{} is visible in the crates.io index." , spec) ;
90+ return Ok ( ( ) ) ;
91+ }
92+
93+ if Instant :: now ( ) >= deadline {
94+ return Err ( format ! (
95+ "Timed out waiting for {} to become visible in the crates.io index\n --- stdout ---\n {}\n --- stderr ---\n {}" ,
96+ spec,
97+ String :: from_utf8_lossy( & output. stdout) ,
98+ String :: from_utf8_lossy( & output. stderr)
99+ ) ) ;
100+ }
101+
102+ println ! (
103+ "{} is not visible yet; retrying in {}s (attempt {})." ,
104+ spec,
105+ CRATES_IO_POLL_INTERVAL . as_secs( ) ,
106+ attempt
107+ ) ;
108+ attempt += 1 ;
109+ thread:: sleep ( CRATES_IO_POLL_INTERVAL ) ;
110+ }
111+ }
112+
64113 fn add_crate_owners ( & self , crate_name : & str ) -> Result < ( ) , String > {
65114 println ! ( "Adding owners for crate: {}" , crate_name) ;
66115
@@ -126,8 +175,10 @@ impl ReleaseTarget for CratesRelease {
126175 }
127176
128177 println ! ( "\n Starting publish process..." ) ;
178+ let crates_io_version = self . version . strip_prefix ( 'v' ) . unwrap_or ( & self . version ) ;
129179 for crate_name in & crates {
130180 self . publish_crate ( crate_name, & manifest_map) ?;
181+ self . wait_for_crate_available ( crate_name, crates_io_version) ?;
131182 self . add_crate_owners ( crate_name) ?;
132183 }
133184
0 commit comments