@@ -860,16 +860,17 @@ def find_cache_meta(id: str, path: str, manager: BuildManager) -> Optional[Cache
860
860
"""
861
861
# TODO: May need to take more build options into account
862
862
meta_json , data_json = get_cache_names (id , path , manager )
863
- manager .trace ('Looking for {} {}' .format (id , data_json ))
863
+ manager .trace ('Looking for {} at {}' .format (id , meta_json ))
864
864
if not os .path .exists (meta_json ):
865
- manager .trace ('Could not load cache for {}: could not find {}' .format (id , meta_json ))
865
+ manager .log ('Could not load cache for {}: could not find {}' .format (id , meta_json ))
866
866
return None
867
867
with open (meta_json , 'r' ) as f :
868
868
meta_str = f .read ()
869
869
manager .trace ('Meta {} {}' .format (id , meta_str .rstrip ()))
870
870
meta = json .loads (meta_str ) # TODO: Errors
871
871
if not isinstance (meta , dict ):
872
- manager .trace ('Could not load cache for {}: meta cache is not a dict' .format (id ))
872
+ manager .log ('Could not load cache for {}: meta cache is not a dict: {}'
873
+ .format (id , repr (meta )))
873
874
return None
874
875
m = CacheMeta (
875
876
meta .get ('id' ),
@@ -891,27 +892,36 @@ def find_cache_meta(id: str, path: str, manager: BuildManager) -> Optional[Cache
891
892
if (m .id != id or
892
893
m .mtime is None or m .size is None or
893
894
m .dependencies is None or m .data_mtime is None ):
894
- manager .trace ('Metadata abandoned for {}: attributes are missing' .format (id ))
895
+ manager .log ('Metadata abandoned for {}: attributes are missing' .format (id ))
895
896
return None
896
897
897
898
# Ignore cache if generated by an older mypy version.
898
899
if ((m .version_id != manager .version_id and not manager .options .skip_version_check )
899
900
or m .options is None
900
901
or len (m .dependencies ) != len (m .dep_prios )):
901
- manager .trace ('Metadata abandoned for {}: new attributes are missing' .format (id ))
902
+ manager .log ('Metadata abandoned for {}: new attributes are missing' .format (id ))
902
903
return None
903
904
904
905
# Ignore cache if (relevant) options aren't the same.
906
+ # Note that it's fine to mutilate cached_options since it's only used here.
905
907
cached_options = m .options
906
908
current_options = manager .options .clone_for_module (id ).select_options_affecting_cache ()
907
909
if manager .options .quick_and_dirty :
908
910
# In quick_and_dirty mode allow non-quick_and_dirty cache files.
909
911
cached_options ['quick_and_dirty' ] = True
910
- if not cached_options .get ('platform' ) and manager .options .skip_version_check :
911
- # Older versions didn't write platform.
912
- cached_options ['platform' ] = manager .options .platform
912
+ if manager .options .skip_version_check :
913
+ # When we're lax about version we're also lax about platform.
914
+ cached_options ['platform' ] = current_options ['platform' ]
915
+ if 'debug_cache' in cached_options :
916
+ # Older versions included debug_cache, but it's silly to compare it.
917
+ del cached_options ['debug_cache' ]
913
918
if cached_options != current_options :
914
- manager .trace ('Metadata abandoned for {}: options differ' .format (id ))
919
+ manager .log ('Metadata abandoned for {}: options differ' .format (id ))
920
+ if manager .options .verbosity >= 2 :
921
+ for key in sorted (set (cached_options ) | set (current_options )):
922
+ if cached_options .get (key ) != current_options .get (key ):
923
+ manager .trace (' {}: {} != {}'
924
+ .format (key , cached_options .get (key ), current_options .get (key )))
915
925
return None
916
926
917
927
return m
@@ -948,41 +958,63 @@ def validate_meta(meta: Optional[CacheMeta], id: str, path: str,
948
958
# we use cache data file mtime to propagate information about changes in the dependencies.
949
959
950
960
if meta is None :
961
+ manager .log ('Metadata not found for {}' .format (id ))
962
+ return None
963
+
964
+ # Check data_json; assume if its mtime matches it's good.
965
+ # TODO: stat() errors
966
+ data_mtime = getmtime (meta .data_json )
967
+ if data_mtime != meta .data_mtime :
968
+ manager .log ('Metadata abandoned for {}: data cache is modified' .format (id ))
951
969
return None
952
970
953
971
# TODO: Share stat() outcome with find_module()
954
972
path = os .path .abspath (path )
955
973
st = manager .get_stat (path ) # TODO: Errors
956
- if st .st_size != meta .size :
974
+ size = st .st_size
975
+ if size != meta .size :
957
976
manager .log ('Metadata abandoned for {}: file {} has different size' .format (id , path ))
958
977
return None
959
978
960
- if int (st .st_mtime ) != meta .mtime or path != meta .path :
979
+ mtime = int (st .st_mtime )
980
+ if mtime != meta .mtime or path != meta .path :
961
981
with open (path , 'rb' ) as f :
962
982
source_hash = hashlib .md5 (f .read ()).hexdigest ()
963
983
if source_hash != meta .hash :
964
984
manager .log ('Metadata abandoned for {}: file {} has different hash' .format (id , path ))
965
985
return None
966
986
else :
967
- manager .log ('Metadata ok for {}: file {} (match on path, size, hash)' .format (id , path ))
968
987
# Optimization: update mtime and path (otherwise, this mismatch will reappear).
969
- meta = meta ._replace (mtime = int (st .st_mtime ), path = path )
988
+ meta = meta ._replace (mtime = mtime , path = path )
989
+ # Construct a dict we can pass to json.dumps() (compare to write_cache()).
990
+ meta_dict = {
991
+ 'id' : id ,
992
+ 'path' : path ,
993
+ 'mtime' : mtime ,
994
+ 'size' : size ,
995
+ 'hash' : source_hash ,
996
+ 'data_mtime' : data_mtime ,
997
+ 'dependencies' : meta .dependencies ,
998
+ 'suppressed' : meta .suppressed ,
999
+ 'child_modules' : meta .child_modules ,
1000
+ 'options' : (manager .options .clone_for_module (id )
1001
+ .select_options_affecting_cache ()),
1002
+ 'dep_prios' : meta .dep_prios ,
1003
+ 'interface_hash' : meta .interface_hash ,
1004
+ 'version_id' : manager .version_id ,
1005
+ }
970
1006
if manager .options .debug_cache :
971
- meta_str = json .dumps (meta , indent = 2 , sort_keys = True )
1007
+ meta_str = json .dumps (meta_dict , indent = 2 , sort_keys = True )
972
1008
else :
973
- meta_str = json .dumps (meta )
1009
+ meta_str = json .dumps (meta_dict )
974
1010
meta_json , _ = get_cache_names (id , path , manager )
975
1011
manager .log ('Updating mtime for {}: file {}, meta {}, mtime {}'
976
1012
.format (id , path , meta_json , meta .mtime ))
977
- atomic_write (meta_json , meta_str ) # Ignore errors, since this is just an optimization.
1013
+ atomic_write (meta_json , meta_str , '\n ' ) # Ignore errors, it's just an optimization.
1014
+ return meta
978
1015
979
- # It's a match on (id, path, mtime/hash, size).
980
- # Check data_json; assume if its mtime matches it's good.
981
- # TODO: stat() errors
982
- if getmtime (meta .data_json ) != meta .data_mtime :
983
- manager .log ('Metadata abandoned for {}: data cache is modified' .format (id ))
984
- return None
985
- manager .log ('Found {} {} (metadata is fresh)' .format (id , meta .data_json ))
1016
+ # It's a match on (id, path, size, hash, mtime).
1017
+ manager .log ('Metadata fresh for {}: file {}' .format (id , path ))
986
1018
return meta
987
1019
988
1020
@@ -1096,7 +1128,7 @@ def write_cache(id: str, path: str, tree: MypyFile,
1096
1128
meta_str = json .dumps (meta , indent = 2 , sort_keys = True )
1097
1129
else :
1098
1130
meta_str = json .dumps (meta )
1099
- if not atomic_write (meta_json , meta_str ):
1131
+ if not atomic_write (meta_json , meta_str , ' \n ' ):
1100
1132
# Most likely the error is the replace() call
1101
1133
# (see https://github.com/python/mypy/issues/3215).
1102
1134
# The next run will simply find the cache entry out of date.
0 commit comments