@@ -73,17 +73,19 @@ def _run(*args):
7373 print (out .encode ("ascii" , "replace" ).decode ("ascii" ))
7474 if p .returncode :
7575 raise RunError (p .returncode , out )
76+ return out
7677
7778
7879def call_ssh (* args , allow_fail = True ):
7980 if not UPLOAD_HOST or NO_UPLOAD or LOCAL_INDEX :
8081 print ("Skipping" , args , "because UPLOAD_HOST is missing" )
81- return
82+ return ""
8283 try :
83- _run (* _std_args (PLINK ), f"{ UPLOAD_USER } @{ UPLOAD_HOST } " , * args )
84- except RunError :
84+ return _run (* _std_args (PLINK ), f"{ UPLOAD_USER } @{ UPLOAD_HOST } " , * args )
85+ except RunError as ex :
8586 if not allow_fail :
8687 raise
88+ return ex .args [1 ]
8789
8890
8991def upload_ssh (source , dest ):
@@ -229,6 +231,13 @@ def install_sortkey(install):
229231 )
230232
231233
234+ def find_missing_from_index (url , installs ):
235+ with urlopen (url ) as r :
236+ x = {install_sortkey (i ) for i in json .load (r )["versions" ]}
237+ y = {install_sortkey (i ) for i in installs } - x
238+ return [i for i in installs if install_sortkey (i ) in y ]
239+
240+
232241UPLOADS = list (calculate_uploads ())
233242
234243if not UPLOADS :
@@ -241,8 +250,16 @@ def install_sortkey(install):
241250
242251index = {"versions" : []}
243252
253+ INDEX_MTIME = 0
254+
244255if INDEX_FILE :
245256 INDEX_PATH = url2path (INDEX_URL )
257+
258+ try :
259+ INDEX_MTIME = int (call_ssh ("stat" , "-c" , "%Y" , INDEX_PATH ) or "0" )
260+ except ValueError :
261+ pass
262+
246263 try :
247264 if not LOCAL_INDEX :
248265 download_ssh (INDEX_PATH , INDEX_FILE )
@@ -257,6 +274,8 @@ def install_sortkey(install):
257274 except FileNotFoundError :
258275 pass
259276
277+ print (INDEX_PATH , "mtime =" , INDEX_MTIME )
278+
260279
261280new_installs = [trim_install (i ) for i , * _ in UPLOADS ]
262281validate_new_installs (new_installs )
@@ -293,25 +312,44 @@ def install_sortkey(install):
293312 upload_ssh (sbom , sbom_dest )
294313
295314
296- if not NO_UPLOAD :
297- if INDEX_FILE :
298- print ("Uploading" , INDEX_FILE , "to" , INDEX_URL )
299- upload_ssh (INDEX_FILE , INDEX_PATH )
315+ # Check that nobody else has published while we were uploading
316+ if INDEX_FILE and INDEX_MTIME :
317+ try :
318+ mtime = int (call_ssh ("stat" , "-c" , "%Y" , INDEX_PATH ) or "0" )
319+ except ValueError :
320+ mtime = 0
321+ if mtime > INDEX_MTIME :
322+ print ("##[error]Lost a race with another publish step!" )
323+ print ("Expecting mtime" , INDEX_MTIME , "but saw" , mtime )
324+ sys .exit (1 )
300325
326+
327+ if not NO_UPLOAD :
301328 if MANIFEST_FILE :
302329 print ("Uploading" , MANIFEST_FILE , "to" , MANIFEST_URL )
303330 upload_ssh (MANIFEST_FILE , MANIFEST_PATH )
304331
332+ if INDEX_FILE :
333+ print ("Uploading" , INDEX_FILE , "to" , INDEX_URL )
334+ upload_ssh (INDEX_FILE , INDEX_PATH )
335+
305336 print ("Purging" , len (UPLOADS ), "uploaded files" )
306337 parents = set ()
307338 for i , * _ in UPLOADS :
308339 purge (i ["url" ])
309340 parents .add (i ["url" ].rpartition ("/" )[0 ] + "/" )
310341 for i in parents :
311342 purge (i )
312- if INDEX_URL :
313- purge (INDEX_URL )
314- purge (INDEX_URL .rpartition ("/" )[0 ] + "/" )
315343 if MANIFEST_URL :
316344 purge (MANIFEST_URL )
317345 purge (MANIFEST_URL .rpartition ("/" )[0 ] + "/" )
346+ if INDEX_URL :
347+ purge (INDEX_URL )
348+ purge (INDEX_URL .rpartition ("/" )[0 ] + "/" )
349+ missing = find_missing_from_index (INDEX_URL , [i for i , * _ in UPLOADS ])
350+ if missing :
351+ print ("##[error]Lost a race with another publish step!" )
352+ print ("Index at" , INDEX_URL , "does not contain installs:" )
353+ for m in missing :
354+ print (m ["id" ], m ["sort-version" ])
355+ sys .exit (1 )
0 commit comments