Skip to content

Commit bf33f4c

Browse files
committed
allow pre-commit to succeed on a readonly store directory
1 parent 4f5cb99 commit bf33f4c

File tree

2 files changed

+32
-0
lines changed

2 files changed

+32
-0
lines changed

pre_commit/store.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ class Store:
4343
def __init__(self, directory: Optional[str] = None) -> None:
4444
self.directory = directory or Store.get_default_directory()
4545
self.db_path = os.path.join(self.directory, 'db.db')
46+
self.readonly = (
47+
os.path.exists(self.directory) and
48+
not os.access(self.directory, os.W_OK)
49+
)
4650

4751
if not os.path.exists(self.directory):
4852
os.makedirs(self.directory, exist_ok=True)
@@ -218,6 +222,8 @@ def _create_config_table(self, db: sqlite3.Connection) -> None:
218222
)
219223

220224
def mark_config_used(self, path: str) -> None:
225+
if self.readonly: # pragma: win32 no cover
226+
return
221227
path = os.path.realpath(path)
222228
# don't insert config files that do not exist
223229
if not os.path.exists(path):

tests/store_test.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import os.path
22
import sqlite3
3+
import stat
34
from unittest import mock
45

56
import pytest
@@ -12,6 +13,7 @@
1213
from testing.fixtures import git_dir
1314
from testing.util import cwd
1415
from testing.util import git_commit
16+
from testing.util import xfailif_windows
1517

1618

1719
def test_our_session_fixture_works():
@@ -217,3 +219,27 @@ def test_select_all_configs_roll_forward(store):
217219
def test_mark_config_as_used_roll_forward(store, tmpdir):
218220
_simulate_pre_1_14_0(store)
219221
test_mark_config_as_used(store, tmpdir)
222+
223+
224+
@xfailif_windows # pragma: win32 no cover
225+
def test_mark_config_as_used_readonly(tmpdir):
226+
cfg = tmpdir.join('f').ensure()
227+
store_dir = tmpdir.join('store')
228+
# make a store, then we'll convert its directory to be readonly
229+
assert not Store(str(store_dir)).readonly # directory didn't exist
230+
assert not Store(str(store_dir)).readonly # directory did exist
231+
232+
def _chmod_minus_w(p):
233+
st = os.stat(p)
234+
os.chmod(p, st.st_mode & ~(stat.S_IWUSR | stat.S_IWOTH | stat.S_IWGRP))
235+
236+
_chmod_minus_w(store_dir)
237+
for fname in os.listdir(store_dir):
238+
assert not os.path.isdir(fname)
239+
_chmod_minus_w(os.path.join(store_dir, fname))
240+
241+
store = Store(str(store_dir))
242+
assert store.readonly
243+
# should be skipped due to readonly
244+
store.mark_config_used(str(cfg))
245+
assert store.select_all_configs() == []

0 commit comments

Comments
 (0)