11from __future__ import annotations
22
3+ import json
34import logging
45import os
56from typing import Any
2223logger = logging .getLogger ('pre_commit' )
2324
2425
26+ def _state (additional_deps : Sequence [str ]) -> object :
27+ return {'additional_dependencies' : sorted (additional_deps )}
28+
29+
2530def _state_filename (venv : str ) -> str :
26- return os .path .join (venv , '.install_state_v2' )
31+ return os .path .join (venv , f'.install_state_v{ C .INSTALLED_STATE_VERSION } ' )
32+
33+
34+ def _read_state (venv : str ) -> object | None :
35+ filename = _state_filename (venv )
36+ if not os .path .exists (filename ):
37+ return None
38+ else :
39+ with open (filename ) as f :
40+ return json .load (f )
2741
2842
2943def _hook_installed (hook : Hook ) -> bool :
@@ -37,7 +51,7 @@ def _hook_installed(hook: Hook) -> bool:
3751 hook .language_version ,
3852 )
3953 return (
40- os . path . exists ( _state_filename ( venv )) and
54+ _read_state ( venv ) == _state ( hook . additional_dependencies ) and
4155 not lang .health_check (hook .prefix , hook .language_version )
4256 )
4357
@@ -73,8 +87,13 @@ def _hook_install(hook: Hook) -> None:
7387 f'your environment\n \n '
7488 f'more info:\n \n { health_error } ' ,
7589 )
76- # touch state file to indicate we're installed
77- open (_state_filename (venv ), 'a+' ).close ()
90+ # Write our state to indicate we're installed
91+ state_filename = _state_filename (venv )
92+ staging = f'{ state_filename } staging'
93+ with open (staging , 'w' ) as state_file :
94+ state_file .write (json .dumps (_state (hook .additional_dependencies )))
95+ # Move the file into place atomically to indicate we've installed
96+ os .replace (staging , state_filename )
7897
7998
8099def _hook (
0 commit comments