0
# Language Support
1
2
Multi-language support system with plugin-based architecture for 22+ programming languages. Pre-commit provides a standardized interface for integrating hooks written in different programming languages, each with their own environment management and execution requirements.
3
4
## Capabilities
5
6
### Language Protocol
7
8
Base protocol that all language implementations must follow.
9
10
```python { .api }
11
class Language(Protocol):
12
"""
13
Protocol defining the interface for language implementations.
14
15
Each supported language must implement this protocol to provide
16
consistent environment management and hook execution.
17
"""
18
19
@property
20
def ENVIRONMENT_DIR(self) -> str | None:
21
"""
22
Directory name for language-specific environments.
23
24
Returns None for languages that don't require separate environments.
25
26
Returns:
27
- str | None: Environment directory name or None
28
"""
29
30
def get_default_version(self) -> str:
31
"""
32
Get the default version identifier for this language.
33
34
Returns:
35
- str: Default version string (e.g., 'default', 'system')
36
"""
37
38
def health_check(self, prefix: Prefix, version: str) -> str | None:
39
"""
40
Check if the language environment is healthy and functional.
41
42
Parameters:
43
- prefix: Installation prefix for the environment
44
- version: Language version to check
45
46
Returns:
47
- str | None: Error message if unhealthy, None if healthy
48
"""
49
50
def install_environment(
51
self,
52
prefix: Prefix,
53
version: str,
54
additional_dependencies: Sequence[str]
55
) -> None:
56
"""
57
Install or update the language environment.
58
59
Parameters:
60
- prefix: Installation prefix for the environment
61
- version: Language version to install
62
- additional_dependencies: Extra packages to install
63
"""
64
65
def in_env(self, prefix: Prefix, version: str) -> ContextManager[None]:
66
"""
67
Context manager for executing within the language environment.
68
69
Parameters:
70
- prefix: Installation prefix for the environment
71
- version: Language version to use
72
73
Returns:
74
- ContextManager: Context for environment activation
75
"""
76
77
def run_hook(
78
self,
79
prefix: Prefix,
80
version: str,
81
cmd: Sequence[str],
82
*,
83
file_args: Sequence[str],
84
prepend_base_dir: bool,
85
require_serial: bool,
86
color: bool
87
) -> tuple[int, bytes]:
88
"""
89
Execute a hook within the language environment.
90
91
Parameters:
92
- prefix: Installation prefix for the environment
93
- version: Language version to use
94
- cmd: Command and arguments to execute
95
- file_args: Files to pass to the hook
96
- prepend_base_dir: Whether to prepend base directory to paths
97
- require_serial: Whether serial execution is required
98
- color: Whether to enable colored output
99
100
Returns:
101
- tuple: (exit_code, output_bytes)
102
"""
103
```
104
105
### Supported Languages
106
107
Complete registry of supported languages with their implementations.
108
109
```python { .api }
110
languages: dict[str, Language] = {
111
'conda': conda, # Conda package manager
112
'coursier': coursier, # Scala/Coursier dependency manager
113
'dart': dart, # Dart programming language
114
'docker': docker, # Docker containers
115
'docker_image': docker_image, # Pre-built Docker images
116
'dotnet': dotnet, # .NET framework
117
'fail': fail, # Always-fail hook for testing
118
'golang': golang, # Go programming language
119
'haskell': haskell, # Haskell programming language
120
'julia': julia, # Julia programming language
121
'lua': lua, # Lua programming language
122
'node': node, # Node.js/npm
123
'perl': perl, # Perl programming language
124
'pygrep': pygrep, # Python regex-based hooks
125
'python': python, # Python programming language
126
'r': r, # R programming language
127
'ruby': ruby, # Ruby programming language
128
'rust': rust, # Rust programming language
129
'script': script, # Shell scripts
130
'swift': swift, # Swift programming language
131
'system': system # System executables
132
}
133
```
134
135
## Individual Language Implementations
136
137
### Python Language Support
138
139
```python { .api }
140
class PythonLanguage:
141
"""Python language implementation with virtual environment support."""
142
143
ENVIRONMENT_DIR = 'py_env'
144
145
def get_default_version(self) -> str:
146
"""Returns 'python3' as default Python version."""
147
148
def install_environment(
149
self,
150
prefix: Prefix,
151
version: str,
152
additional_dependencies: Sequence[str]
153
) -> None:
154
"""
155
Create virtual environment and install dependencies.
156
157
Creates a Python virtual environment and installs the hook
158
package along with any additional dependencies.
159
"""
160
161
def run_hook(self, prefix: Prefix, version: str, cmd: Sequence[str], **kwargs) -> tuple[int, bytes]:
162
"""Execute hook within Python virtual environment."""
163
```
164
165
### Node.js Language Support
166
167
```python { .api }
168
class NodeLanguage:
169
"""Node.js language implementation with npm package management."""
170
171
ENVIRONMENT_DIR = 'node_env'
172
173
def get_default_version(self) -> str:
174
"""Returns 'node' as default Node.js version."""
175
176
def install_environment(
177
self,
178
prefix: Prefix,
179
version: str,
180
additional_dependencies: Sequence[str]
181
) -> None:
182
"""
183
Install Node.js packages using npm.
184
185
Sets up npm environment and installs hook package with dependencies.
186
"""
187
188
def run_hook(self, prefix: Prefix, version: str, cmd: Sequence[str], **kwargs) -> tuple[int, bytes]:
189
"""Execute hook with Node.js runtime."""
190
```
191
192
### Go Language Support
193
194
```python { .api }
195
class GolangLanguage:
196
"""Go language implementation with module support."""
197
198
ENVIRONMENT_DIR = 'go_env'
199
200
def get_default_version(self) -> str:
201
"""Returns 'go' as default Go version."""
202
203
def install_environment(
204
self,
205
prefix: Prefix,
206
version: str,
207
additional_dependencies: Sequence[str]
208
) -> None:
209
"""
210
Install Go modules and build binaries.
211
212
Downloads Go modules and builds executable binaries for hook execution.
213
"""
214
215
def run_hook(self, prefix: Prefix, version: str, cmd: Sequence[str], **kwargs) -> tuple[int, bytes]:
216
"""Execute Go binary hook."""
217
```
218
219
### Ruby Language Support
220
221
```python { .api }
222
class RubyLanguage:
223
"""Ruby language implementation with gem management."""
224
225
ENVIRONMENT_DIR = 'ruby_env'
226
227
def get_default_version(self) -> str:
228
"""Returns 'ruby' as default Ruby version."""
229
230
def install_environment(
231
self,
232
prefix: Prefix,
233
version: str,
234
additional_dependencies: Sequence[str]
235
) -> None:
236
"""
237
Install Ruby gems in isolated environment.
238
239
Creates gem environment and installs hook gem with dependencies.
240
"""
241
242
def run_hook(self, prefix: Prefix, version: str, cmd: Sequence[str], **kwargs) -> tuple[int, bytes]:
243
"""Execute hook with Ruby runtime."""
244
```
245
246
### Docker Language Support
247
248
```python { .api }
249
class DockerLanguage:
250
"""Docker language implementation for containerized hooks."""
251
252
ENVIRONMENT_DIR = None # No local environment needed
253
254
def get_default_version(self) -> str:
255
"""Returns 'default' for Docker version."""
256
257
def install_environment(
258
self,
259
prefix: Prefix,
260
version: str,
261
additional_dependencies: Sequence[str]
262
) -> None:
263
"""
264
Build Docker image for hook execution.
265
266
Builds Docker image with hook and its dependencies.
267
"""
268
269
def run_hook(self, prefix: Prefix, version: str, cmd: Sequence[str], **kwargs) -> tuple[int, bytes]:
270
"""Execute hook within Docker container."""
271
```
272
273
### System Language Support
274
275
```python { .api }
276
class SystemLanguage:
277
"""System language for executing system-installed binaries."""
278
279
ENVIRONMENT_DIR = None # Uses system executables
280
281
def get_default_version(self) -> str:
282
"""Returns 'system' for system executables."""
283
284
def install_environment(
285
self,
286
prefix: Prefix,
287
version: str,
288
additional_dependencies: Sequence[str]
289
) -> None:
290
"""
291
No installation needed for system executables.
292
293
Validates that required executables are available on system PATH.
294
"""
295
296
def run_hook(self, prefix: Prefix, version: str, cmd: Sequence[str], **kwargs) -> tuple[int, bytes]:
297
"""Execute system executable directly."""
298
```
299
300
## Language Utilities
301
302
### Language Resolution
303
304
Functions for resolving and working with language implementations.
305
306
```python { .api }
307
def get_language(language: str) -> Language:
308
"""
309
Get language implementation by name.
310
311
Parameters:
312
- language: Language name
313
314
Returns:
315
- Language: Language implementation instance
316
317
Raises:
318
- ValueError: If language is not supported
319
"""
320
321
def language_version_info(language: str, version: str) -> dict[str, Any]:
322
"""
323
Get version information for a language.
324
325
Parameters:
326
- language: Language name
327
- version: Version string
328
329
Returns:
330
- dict: Version information and capabilities
331
"""
332
```
333
334
### Environment Management
335
336
Utilities for managing language environments across hooks.
337
338
```python { .api }
339
def clean_environment(prefix: Prefix, language: str) -> None:
340
"""
341
Clean up language environment files.
342
343
Parameters:
344
- prefix: Installation prefix
345
- language: Language name
346
"""
347
348
def environment_exists(prefix: Prefix, language: str, version: str) -> bool:
349
"""
350
Check if language environment is installed.
351
352
Parameters:
353
- prefix: Installation prefix
354
- language: Language name
355
- version: Language version
356
357
Returns:
358
- bool: True if environment exists
359
"""
360
```
361
362
## Language-Specific Features
363
364
### Python Features
365
366
```python { .api }
367
def python_venv_info(prefix: Prefix) -> dict[str, str]:
368
"""Get Python virtual environment information."""
369
370
def install_python_requirements(prefix: Prefix, requirements: list[str]) -> None:
371
"""Install Python packages from requirements list."""
372
```
373
374
### Node.js Features
375
376
```python { .api }
377
def node_package_info(prefix: Prefix) -> dict[str, Any]:
378
"""Get Node.js package information."""
379
380
def install_node_packages(prefix: Prefix, packages: list[str]) -> None:
381
"""Install Node.js packages via npm."""
382
```
383
384
### Docker Features
385
386
```python { .api }
387
def docker_image_exists(image: str) -> bool:
388
"""Check if Docker image exists locally."""
389
390
def pull_docker_image(image: str) -> None:
391
"""Pull Docker image from registry."""
392
```
393
394
## Usage Examples
395
396
### Working with Language Implementations
397
398
```python
399
from pre_commit.languages import languages
400
from pre_commit.prefix import Prefix
401
402
# Get Python language implementation
403
python_lang = languages['python']
404
print(f"Python environment dir: {python_lang.ENVIRONMENT_DIR}")
405
print(f"Default version: {python_lang.get_default_version()}")
406
407
# Create prefix for hook installation
408
prefix = Prefix('/tmp/hook-env')
409
410
# Install Python environment with additional dependencies
411
python_lang.install_environment(
412
prefix=prefix,
413
version='python3.9',
414
additional_dependencies=['black', 'flake8']
415
)
416
417
# Check environment health
418
health_result = python_lang.health_check(prefix, 'python3.9')
419
if health_result is None:
420
print("Python environment is healthy")
421
else:
422
print(f"Environment issue: {health_result}")
423
```
424
425
### Executing Hooks with Language Support
426
427
```python
428
from pre_commit.languages import languages
429
430
# Get language implementation
431
node_lang = languages['node']
432
433
# Execute hook within Node.js environment
434
with node_lang.in_env(prefix, 'node'):
435
exit_code, output = node_lang.run_hook(
436
prefix=prefix,
437
version='node',
438
cmd=['eslint', '--fix'],
439
file_args=['src/app.js', 'src/utils.js'],
440
prepend_base_dir=True,
441
require_serial=False,
442
color=True
443
)
444
445
print(f"Hook exit code: {exit_code}")
446
if output:
447
print(f"Hook output: {output.decode()}")
448
```
449
450
### Language Environment Management
451
452
```python
453
from pre_commit.languages import get_language, environment_exists
454
455
# Work with Go language
456
go_lang = get_language('golang')
457
458
# Check if environment exists
459
if environment_exists(prefix, 'golang', 'go1.19'):
460
print("Go environment already installed")
461
else:
462
print("Installing Go environment...")
463
go_lang.install_environment(prefix, 'go1.19', [])
464
465
# Get language version info
466
version_info = language_version_info('golang', 'go1.19')
467
print(f"Go version info: {version_info}")
468
```
469
470
### Multi-Language Hook Processing
471
472
```python
473
from pre_commit.languages import languages
474
475
# Process hooks for different languages
476
hook_configs = [
477
{'language': 'python', 'version': 'python3.9', 'deps': ['black']},
478
{'language': 'node', 'version': 'node16', 'deps': ['eslint']},
479
{'language': 'golang', 'version': 'go1.19', 'deps': []},
480
]
481
482
for config in hook_configs:
483
lang_impl = languages[config['language']]
484
485
# Install environment
486
lang_impl.install_environment(
487
prefix=prefix,
488
version=config['version'],
489
additional_dependencies=config['deps']
490
)
491
492
print(f"Installed {config['language']} environment")
493
```