0
# Repository Management
1
2
Repository and hook environment management through the Store system. The Store provides centralized management of hook repositories, environment caching, and cleanup operations for efficient hook execution and storage.
3
4
## Capabilities
5
6
### Store Class
7
8
Central repository and environment management system that handles cloning, caching, and lifecycle management of hook repositories.
9
10
```python { .api }
11
class Store:
12
"""
13
Centralized store for managing hook repositories and environments.
14
15
Provides caching, cloning, and cleanup functionality for hook repositories
16
and their associated environments. Manages the complete lifecycle from
17
initial repository cloning through environment installation to cleanup.
18
"""
19
20
def __init__(self, directory: str | None = None) -> None:
21
"""
22
Initialize store with optional custom directory.
23
24
Parameters:
25
- directory: Custom store directory path (uses default if None)
26
"""
27
28
def clone(self, repo: str, ref: str, deps: Sequence[str] = ()) -> str:
29
"""
30
Clone repository and return installation path.
31
32
Clones the specified repository at the given reference and prepares
33
it for hook installation. Handles caching to avoid duplicate clones.
34
35
Parameters:
36
- repo: Repository URL or local path
37
- ref: Git reference (tag, commit, branch)
38
- deps: Additional dependencies for environment
39
40
Returns:
41
- str: Path to cloned repository installation
42
"""
43
44
def make_local(self, deps: Sequence[str]) -> str:
45
"""
46
Create local repository installation for local hooks.
47
48
Sets up environment for locally defined hooks without external repository.
49
50
Parameters:
51
- deps: Dependencies for local hook environment
52
53
Returns:
54
- str: Path to local installation
55
"""
56
57
def mark_config_used(self, path: str) -> None:
58
"""
59
Mark configuration as recently used for garbage collection.
60
61
Parameters:
62
- path: Configuration file path to mark as used
63
"""
64
65
def select_all_configs(self) -> list[str]:
66
"""
67
Get all configuration files tracked by the store.
68
69
Returns:
70
- list: Paths to all tracked configuration files
71
"""
72
73
def delete_configs(self, configs: list[str]) -> None:
74
"""
75
Delete specified configuration files from tracking.
76
77
Parameters:
78
- configs: List of configuration paths to delete
79
"""
80
81
def select_all_repos(self) -> list[tuple[str, str, str]]:
82
"""
83
Get all repositories managed by the store.
84
85
Returns:
86
- list: Tuples of (repo_name, ref, path) for each repository
87
"""
88
89
def delete_repo(self, db_repo_name: str, ref: str, path: str) -> None:
90
"""
91
Delete repository from store and filesystem.
92
93
Parameters:
94
- db_repo_name: Database repository name
95
- ref: Git reference
96
- path: Repository path to delete
97
"""
98
99
@staticmethod
100
def get_default_directory() -> str:
101
"""
102
Get the default store directory path.
103
104
Returns:
105
- str: Default store directory (typically ~/.cache/pre-commit)
106
"""
107
```
108
109
### Repository Operations
110
111
High-level functions for working with repositories through the store system.
112
113
```python { .api }
114
def all_hooks(root_config: dict[str, Any], store: Store) -> tuple[Hook, ...]:
115
"""
116
Extract all configured hooks from configuration using store.
117
118
Processes the complete configuration file, clones required repositories
119
through the store, and creates Hook instances for all defined hooks.
120
121
Parameters:
122
- root_config: Loaded configuration dictionary
123
- store: Store instance for repository management
124
125
Returns:
126
- tuple: All configured Hook instances
127
"""
128
129
def install_hook_envs(hooks: Sequence[Hook], store: Store) -> None:
130
"""
131
Install environments for all provided hooks using store.
132
133
Coordinates with the store to ensure all hook environments are properly
134
installed and configured with their dependencies.
135
136
Parameters:
137
- hooks: Sequence of hooks requiring environment installation
138
- store: Store instance for environment management
139
"""
140
```
141
142
### Store Database Management
143
144
Internal database operations for tracking repositories and configurations.
145
146
```python { .api }
147
def _get_store_db(store_dir: str) -> sqlite3.Connection:
148
"""
149
Get database connection for store operations.
150
151
Parameters:
152
- store_dir: Store directory path
153
154
Returns:
155
- Connection: SQLite database connection
156
"""
157
158
def _init_store_db(db: sqlite3.Connection) -> None:
159
"""
160
Initialize store database with required tables.
161
162
Parameters:
163
- db: Database connection to initialize
164
"""
165
```
166
167
## Store Configuration
168
169
### Directory Structure
170
171
The store maintains a structured directory layout for efficient organization:
172
173
```
174
~/.cache/pre-commit/ # Default store directory
175
├── db.db # SQLite database for tracking
176
├── repos/ # Cloned repositories
177
│ ├── <repo-hash>/ # Individual repository directories
178
│ │ ├── .git/ # Git repository data
179
│ │ └── <hook-files> # Hook implementation files
180
│ └── ...
181
└── <language-envs>/ # Language-specific environments
182
├── py_env-<hash>/ # Python virtual environments
183
├── node_env-<hash>/ # Node.js environments
184
└── ...
185
```
186
187
### Store Initialization
188
189
```python { .api }
190
def initialize_store(directory: str | None = None) -> Store:
191
"""
192
Initialize a new store instance.
193
194
Parameters:
195
- directory: Custom directory (uses default if None)
196
197
Returns:
198
- Store: Initialized store instance
199
"""
200
```
201
202
## Repository Caching
203
204
### Cache Management
205
206
Functions for managing repository and environment caches.
207
208
```python { .api }
209
def clean_unused_repos(store: Store, configs_in_use: set[str]) -> None:
210
"""
211
Clean repositories not referenced by active configurations.
212
213
Parameters:
214
- store: Store instance to clean
215
- configs_in_use: Set of configuration files still in use
216
"""
217
218
def get_cache_stats(store: Store) -> dict[str, Any]:
219
"""
220
Get statistics about store cache usage.
221
222
Parameters:
223
- store: Store instance to analyze
224
225
Returns:
226
- dict: Cache statistics including size, file counts, etc.
227
"""
228
```
229
230
### Garbage Collection
231
232
```python { .api }
233
def garbage_collect_repos(store: Store) -> int:
234
"""
235
Perform garbage collection on unused repositories.
236
237
Removes repositories and environments that are no longer referenced
238
by any active configurations.
239
240
Parameters:
241
- store: Store instance to garbage collect
242
243
Returns:
244
- int: Number of items removed
245
"""
246
```
247
248
## Environment Management
249
250
### Environment Installation
251
252
```python { .api }
253
def ensure_environment(
254
hook: Hook,
255
store: Store,
256
language_version: str
257
) -> None:
258
"""
259
Ensure hook environment is installed and ready.
260
261
Parameters:
262
- hook: Hook requiring environment
263
- store: Store instance for management
264
- language_version: Specific language version to use
265
"""
266
```
267
268
### Environment Health Checks
269
270
```python { .api }
271
def check_environment_health(
272
prefix: Prefix,
273
language: str,
274
version: str
275
) -> str | None:
276
"""
277
Check if environment is healthy and functional.
278
279
Parameters:
280
- prefix: Environment installation prefix
281
- language: Programming language
282
- version: Language version
283
284
Returns:
285
- str | None: Error message if unhealthy, None if healthy
286
"""
287
```
288
289
## Usage Examples
290
291
### Basic Store Operations
292
293
```python
294
from pre_commit.store import Store
295
from pre_commit.clientlib import load_config
296
from pre_commit.repository import all_hooks, install_hook_envs
297
298
# Initialize store (uses default directory)
299
store = Store()
300
301
# Or initialize with custom directory
302
custom_store = Store('/path/to/custom/store')
303
304
# Load configuration and get all hooks
305
config = load_config('.pre-commit-config.yaml')
306
hooks = all_hooks(config, store)
307
308
print(f"Found {len(hooks)} hooks from {len(config['repos'])} repositories")
309
310
# Install environments for all hooks
311
install_hook_envs(hooks, store)
312
print("All hook environments installed")
313
```
314
315
### Repository Cloning and Management
316
317
```python
318
from pre_commit.store import Store
319
320
store = Store()
321
322
# Clone specific repository
323
repo_path = store.clone(
324
repo='https://github.com/psf/black',
325
ref='22.3.0',
326
deps=['black[jupyter]']
327
)
328
print(f"Repository cloned to: {repo_path}")
329
330
# Create local environment
331
local_path = store.make_local(deps=['flake8', 'mypy'])
332
print(f"Local environment created at: {local_path}")
333
334
# Mark configuration as used (for garbage collection)
335
store.mark_config_used('.pre-commit-config.yaml')
336
```
337
338
### Store Maintenance
339
340
```python
341
from pre_commit.store import Store
342
343
store = Store()
344
345
# Get all repositories managed by store
346
repos = store.select_all_repos()
347
print(f"Store manages {len(repos)} repositories:")
348
for repo_name, ref, path in repos:
349
print(f" {repo_name}@{ref} -> {path}")
350
351
# Get all tracked configurations
352
configs = store.select_all_configs()
353
print(f"Tracking {len(configs)} configurations:")
354
for config_path in configs:
355
print(f" {config_path}")
356
357
# Clean up unused configurations
358
# (In practice, you'd determine which are actually unused)
359
# store.delete_configs(['/path/to/unused/config.yaml'])
360
```
361
362
### Cache Statistics and Cleanup
363
364
```python
365
from pre_commit.store import Store, get_cache_stats, garbage_collect_repos
366
367
store = Store()
368
369
# Get cache statistics
370
stats = get_cache_stats(store)
371
print(f"Cache statistics:")
372
print(f" Total repositories: {stats.get('repo_count', 0)}")
373
print(f" Total size: {stats.get('total_size', 0)} bytes")
374
print(f" Environments: {stats.get('env_count', 0)}")
375
376
# Perform garbage collection
377
removed_count = garbage_collect_repos(store)
378
print(f"Garbage collection removed {removed_count} unused items")
379
```
380
381
### Working with Store Directory
382
383
```python
384
from pre_commit.store import Store
385
386
# Get default store directory
387
default_dir = Store.get_default_directory()
388
print(f"Default store directory: {default_dir}")
389
390
# Initialize store with explicit directory
391
store = Store(directory='/tmp/pre-commit-store')
392
393
# Verify store is using correct directory
394
# (Store doesn't expose directory directly, but you can check filesystem)
395
import os
396
if os.path.exists('/tmp/pre-commit-store'):
397
print("Custom store directory created successfully")
398
```
399
400
### Advanced Repository Operations
401
402
```python
403
from pre_commit.store import Store
404
405
store = Store()
406
407
# Work with multiple repositories
408
repositories = [
409
('https://github.com/psf/black', '22.3.0'),
410
('https://github.com/pycqa/flake8', '4.0.1'),
411
('https://github.com/pre-commit/mirrors-mypy', 'v0.950')
412
]
413
414
repo_paths = []
415
for repo_url, ref in repositories:
416
path = store.clone(repo=repo_url, ref=ref)
417
repo_paths.append(path)
418
print(f"Cloned {repo_url}@{ref} to {path}")
419
420
print(f"Successfully cloned {len(repo_paths)} repositories")
421
422
# Clean up specific repository if needed
423
# store.delete_repo('repo-name', 'ref', '/path/to/repo')
424
```