mirror of
https://github.com/pre-commit/pre-commit.git
synced 2026-02-17 08:14:42 +04:00
Add types to pre-commit
This commit is contained in:
parent
fa536a8693
commit
327ed924a3
62 changed files with 911 additions and 411 deletions
|
|
@ -3,6 +3,12 @@ import logging
|
|||
import os.path
|
||||
import sqlite3
|
||||
import tempfile
|
||||
from typing import Callable
|
||||
from typing import Generator
|
||||
from typing import List
|
||||
from typing import Optional
|
||||
from typing import Sequence
|
||||
from typing import Tuple
|
||||
|
||||
import pre_commit.constants as C
|
||||
from pre_commit import file_lock
|
||||
|
|
@ -18,7 +24,7 @@ from pre_commit.util import rmtree
|
|||
logger = logging.getLogger('pre_commit')
|
||||
|
||||
|
||||
def _get_default_directory():
|
||||
def _get_default_directory() -> str:
|
||||
"""Returns the default directory for the Store. This is intentionally
|
||||
underscored to indicate that `Store.get_default_directory` is the intended
|
||||
way to get this information. This is also done so
|
||||
|
|
@ -34,7 +40,7 @@ def _get_default_directory():
|
|||
class Store:
|
||||
get_default_directory = staticmethod(_get_default_directory)
|
||||
|
||||
def __init__(self, directory=None):
|
||||
def __init__(self, directory: Optional[str] = None) -> None:
|
||||
self.directory = directory or Store.get_default_directory()
|
||||
self.db_path = os.path.join(self.directory, 'db.db')
|
||||
|
||||
|
|
@ -66,21 +72,24 @@ class Store:
|
|||
' PRIMARY KEY (repo, ref)'
|
||||
');',
|
||||
)
|
||||
self._create_config_table_if_not_exists(db)
|
||||
self._create_config_table(db)
|
||||
|
||||
# Atomic file move
|
||||
os.rename(tmpfile, self.db_path)
|
||||
|
||||
@contextlib.contextmanager
|
||||
def exclusive_lock(self):
|
||||
def blocked_cb(): # pragma: no cover (tests are single-process)
|
||||
def exclusive_lock(self) -> Generator[None, None, None]:
|
||||
def blocked_cb() -> None: # pragma: no cover (tests are in-process)
|
||||
logger.info('Locking pre-commit directory')
|
||||
|
||||
with file_lock.lock(os.path.join(self.directory, '.lock'), blocked_cb):
|
||||
yield
|
||||
|
||||
@contextlib.contextmanager
|
||||
def connect(self, db_path=None):
|
||||
def connect(
|
||||
self,
|
||||
db_path: Optional[str] = None,
|
||||
) -> Generator[sqlite3.Connection, None, None]:
|
||||
db_path = db_path or self.db_path
|
||||
# sqlite doesn't close its fd with its contextmanager >.<
|
||||
# contextlib.closing fixes this.
|
||||
|
|
@ -91,24 +100,29 @@ class Store:
|
|||
yield db
|
||||
|
||||
@classmethod
|
||||
def db_repo_name(cls, repo, deps):
|
||||
def db_repo_name(cls, repo: str, deps: Sequence[str]) -> str:
|
||||
if deps:
|
||||
return '{}:{}'.format(repo, ','.join(sorted(deps)))
|
||||
else:
|
||||
return repo
|
||||
|
||||
def _new_repo(self, repo, ref, deps, make_strategy):
|
||||
def _new_repo(
|
||||
self,
|
||||
repo: str,
|
||||
ref: str,
|
||||
deps: Sequence[str],
|
||||
make_strategy: Callable[[str], None],
|
||||
) -> str:
|
||||
repo = self.db_repo_name(repo, deps)
|
||||
|
||||
def _get_result():
|
||||
def _get_result() -> Optional[str]:
|
||||
# Check if we already exist
|
||||
with self.connect() as db:
|
||||
result = db.execute(
|
||||
'SELECT path FROM repos WHERE repo = ? AND ref = ?',
|
||||
(repo, ref),
|
||||
).fetchone()
|
||||
if result:
|
||||
return result[0]
|
||||
return result[0] if result else None
|
||||
|
||||
result = _get_result()
|
||||
if result:
|
||||
|
|
@ -133,14 +147,14 @@ class Store:
|
|||
)
|
||||
return directory
|
||||
|
||||
def _complete_clone(self, ref, git_cmd):
|
||||
def _complete_clone(self, ref: str, git_cmd: Callable[..., None]) -> None:
|
||||
"""Perform a complete clone of a repository and its submodules """
|
||||
|
||||
git_cmd('fetch', 'origin', '--tags')
|
||||
git_cmd('checkout', ref)
|
||||
git_cmd('submodule', 'update', '--init', '--recursive')
|
||||
|
||||
def _shallow_clone(self, ref, git_cmd):
|
||||
def _shallow_clone(self, ref: str, git_cmd: Callable[..., None]) -> None:
|
||||
"""Perform a shallow clone of a repository and its submodules """
|
||||
|
||||
git_config = 'protocol.version=2'
|
||||
|
|
@ -151,14 +165,14 @@ class Store:
|
|||
'--depth=1',
|
||||
)
|
||||
|
||||
def clone(self, repo, ref, deps=()):
|
||||
def clone(self, repo: str, ref: str, deps: Sequence[str] = ()) -> str:
|
||||
"""Clone the given url and checkout the specific ref."""
|
||||
|
||||
def clone_strategy(directory):
|
||||
def clone_strategy(directory: str) -> None:
|
||||
git.init_repo(directory, repo)
|
||||
env = git.no_git_env()
|
||||
|
||||
def _git_cmd(*args):
|
||||
def _git_cmd(*args: str) -> None:
|
||||
cmd_output_b('git', *args, cwd=directory, env=env)
|
||||
|
||||
try:
|
||||
|
|
@ -173,8 +187,8 @@ class Store:
|
|||
'pre_commit_dummy_package.gemspec', 'setup.py', 'environment.yml',
|
||||
)
|
||||
|
||||
def make_local(self, deps):
|
||||
def make_local_strategy(directory):
|
||||
def make_local(self, deps: Sequence[str]) -> str:
|
||||
def make_local_strategy(directory: str) -> None:
|
||||
for resource in self.LOCAL_RESOURCES:
|
||||
contents = resource_text(f'empty_template_{resource}')
|
||||
with open(os.path.join(directory, resource), 'w') as f:
|
||||
|
|
@ -183,7 +197,7 @@ class Store:
|
|||
env = git.no_git_env()
|
||||
|
||||
# initialize the git repository so it looks more like cloned repos
|
||||
def _git_cmd(*args):
|
||||
def _git_cmd(*args: str) -> None:
|
||||
cmd_output_b('git', *args, cwd=directory, env=env)
|
||||
|
||||
git.init_repo(directory, '<<unknown>>')
|
||||
|
|
@ -194,7 +208,7 @@ class Store:
|
|||
'local', C.LOCAL_REPO_VERSION, deps, make_local_strategy,
|
||||
)
|
||||
|
||||
def _create_config_table_if_not_exists(self, db):
|
||||
def _create_config_table(self, db: sqlite3.Connection) -> None:
|
||||
db.executescript(
|
||||
'CREATE TABLE IF NOT EXISTS configs ('
|
||||
' path TEXT NOT NULL,'
|
||||
|
|
@ -202,32 +216,32 @@ class Store:
|
|||
');',
|
||||
)
|
||||
|
||||
def mark_config_used(self, path):
|
||||
def mark_config_used(self, path: str) -> None:
|
||||
path = os.path.realpath(path)
|
||||
# don't insert config files that do not exist
|
||||
if not os.path.exists(path):
|
||||
return
|
||||
with self.connect() as db:
|
||||
# TODO: eventually remove this and only create in _create
|
||||
self._create_config_table_if_not_exists(db)
|
||||
self._create_config_table(db)
|
||||
db.execute('INSERT OR IGNORE INTO configs VALUES (?)', (path,))
|
||||
|
||||
def select_all_configs(self):
|
||||
def select_all_configs(self) -> List[str]:
|
||||
with self.connect() as db:
|
||||
self._create_config_table_if_not_exists(db)
|
||||
self._create_config_table(db)
|
||||
rows = db.execute('SELECT path FROM configs').fetchall()
|
||||
return [path for path, in rows]
|
||||
|
||||
def delete_configs(self, configs):
|
||||
def delete_configs(self, configs: List[str]) -> None:
|
||||
with self.connect() as db:
|
||||
rows = [(path,) for path in configs]
|
||||
db.executemany('DELETE FROM configs WHERE path = ?', rows)
|
||||
|
||||
def select_all_repos(self):
|
||||
def select_all_repos(self) -> List[Tuple[str, str, str]]:
|
||||
with self.connect() as db:
|
||||
return db.execute('SELECT repo, ref, path from repos').fetchall()
|
||||
|
||||
def delete_repo(self, db_repo_name, ref, path):
|
||||
def delete_repo(self, db_repo_name: str, ref: str, path: str) -> None:
|
||||
with self.connect() as db:
|
||||
db.execute(
|
||||
'DELETE FROM repos WHERE repo = ? and ref = ?',
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue