(self, directory: str | None = None)
| 60 | get_default_directory = staticmethod(_get_default_directory) |
| 61 | |
| 62 | def __init__(self, directory: str | None = None) -> None: |
| 63 | self.directory = directory or Store.get_default_directory() |
| 64 | self.db_path = os.path.join(self.directory, 'db.db') |
| 65 | self.readonly = ( |
| 66 | os.path.exists(self.directory) and |
| 67 | not os.access(self.directory, os.W_OK) |
| 68 | ) |
| 69 | |
| 70 | if not os.path.exists(self.directory): |
| 71 | os.makedirs(self.directory, exist_ok=True) |
| 72 | with open(os.path.join(self.directory, 'README'), 'w') as f: |
| 73 | f.write( |
| 74 | 'This directory is maintained by the pre-commit project.\n' |
| 75 | 'Learn more: https://github.com/pre-commit/pre-commit\n', |
| 76 | ) |
| 77 | |
| 78 | if os.path.exists(self.db_path): |
| 79 | return |
| 80 | with self.exclusive_lock(): |
| 81 | # Another process may have already completed this work |
| 82 | if os.path.exists(self.db_path): # pragma: no cover (race) |
| 83 | return |
| 84 | # To avoid a race where someone ^Cs between db creation and |
| 85 | # execution of the CREATE TABLE statement |
| 86 | fd, tmpfile = tempfile.mkstemp(dir=self.directory) |
| 87 | # We'll be managing this file ourselves |
| 88 | os.close(fd) |
| 89 | with self.connect(db_path=tmpfile) as db: |
| 90 | db.executescript( |
| 91 | 'CREATE TABLE repos (' |
| 92 | ' repo TEXT NOT NULL,' |
| 93 | ' ref TEXT NOT NULL,' |
| 94 | ' path TEXT NOT NULL,' |
| 95 | ' PRIMARY KEY (repo, ref)' |
| 96 | ');', |
| 97 | ) |
| 98 | self._create_configs_table(db) |
| 99 | |
| 100 | # Atomic file move |
| 101 | os.replace(tmpfile, self.db_path) |
| 102 | |
| 103 | @contextlib.contextmanager |
| 104 | def exclusive_lock(self) -> Generator[None]: |
nothing calls this directly
no test coverage detected