22from __future__ import annotations
33
44import dataclasses
5+ from datetime import datetime
56import json
67import os
78import sys
2526
2627BBLOCK_METADATA_FILE = 'bblock.json'
2728
29+ EPOCH_STR = '1970-01-01T00:00:00'
30+
2831
2932def get_bblock_subdirs (identifier : str ) -> Path :
3033 return Path (* (identifier .split ('.' )[1 :]))
@@ -346,12 +349,13 @@ def get_files_with_references(self) -> list[PathOrUrl]:
346349class ImportedBuildingBlocks :
347350
348351 def __init__ (self , metadata_urls : list [str ] | None , ignore_git_repos : list [str ] | None = None ,
349- remote_cache_dir : Path | None = None ):
352+ remote_cache_dir : Path | None = None , is_local = False ):
350353 self .bblocks : dict [str , dict ] = {}
351354 self .imported_registers : dict [str , list [str ]] = {}
352355 self .real_metadata_urls : dict [str , str ] = {}
353356 self .ignore_git_repos : list [str ] | None = ([x for x in ignore_git_repos if x ]
354357 if ignore_git_repos else None )
358+ self .is_local = is_local
355359 self .remote_cache_dir = remote_cache_dir
356360 if remote_cache_dir :
357361 remote_cache_dir .mkdir (exist_ok = True , parents = True )
@@ -372,10 +376,31 @@ def load(self, metadata_url: str) -> tuple[list[str], str]:
372376
373377 metadata_url_trailing = metadata_url + ('' if metadata_url .endswith ('/' ) else '/' )
374378 collected_exceptions = {}
375- for url in (metadata_url ,
376- metadata_url_trailing + 'build/register.json' ,
377- metadata_url_trailing + 'register.json' ):
379+ try_urls = [
380+ metadata_url ,
381+ metadata_url_trailing + 'build/register.json' ,
382+ metadata_url_trailing + 'register.json'
383+ ]
384+ for i , url in enumerate (try_urls ):
378385 try :
386+ local_imported = None
387+ local_url = None
388+ if i == 1 and self .is_local :
389+ # test build-local/register.json
390+ local_url = metadata_url_trailing + 'build-local/register.json'
391+ tested_locations [local_url ] = True
392+ try :
393+ r = requests .get (local_url )
394+ r .raise_for_status ()
395+ local_imported = r .json ()
396+ if not isinstance (local_imported , dict ) or 'bblocks' not in local_imported :
397+ local_imported = None
398+ elif self .remote_cache_dir :
399+ cache_fn = self .remote_cache_dir .joinpath (sha256 (url .encode ('utf-8' )).hexdigest ())
400+ with open (cache_fn , 'wb' ) as f :
401+ f .write (r .content )
402+ except :
403+ pass
379404 tested_locations [url ] = True
380405 r = requests .get (url )
381406 if r .ok :
@@ -388,8 +413,18 @@ def load(self, metadata_url: str) -> tuple[list[str], str]:
388413 print (f"[WARN] Error writing cache file { cache_fn } for { url } " , file = sys .stderr )
389414 imported = r .json ()
390415 if (isinstance (imported , dict ) and 'bblocks' in imported ) or isinstance (imported , list ):
391- metadata_url = url
416+ if (local_imported
417+ and datetime .fromisoformat (local_imported .get ('modified' ))
418+ > datetime .fromisoformat (imported .get ('modified' ))):
419+ imported = local_imported
420+ metadata_url = local_url
421+ else :
422+ metadata_url = url
392423 break
424+ elif local_imported :
425+ imported = local_imported
426+ metadata_url = local_url
427+ break
393428 except Exception as e :
394429 collected_exceptions [url ] = e
395430 imported = None
@@ -589,7 +624,7 @@ def _resolve_bblock_deps(self, bblock: BuildingBlock) -> set[str]:
589624 # Check if target path in local bblock schemas
590625 rel_ref = str (os .path .relpath (source_fn .resolve_ref (ref ).resolve ()))
591626 if not Path (rel_ref ).is_file ():
592- raise ValueError (f"Invalid reference to { rel_ref } "
627+ raise ValueError (f"Invalid reference to { ref } (resolved to { rel_ref } ) "
593628 f" from { bblock .identifier } ({ source_fn } ) - target file does not exist"
594629 f" - check that the file exists (maybe schema.yaml instead of schema.json?)" )
595630 else :
0 commit comments