This commit is contained in:
Anthony Sottile 2025-11-07 17:02:17 -05:00
parent 65175f3cf3
commit 37e2ba87a7
13 changed files with 134 additions and 0 deletions

24
TODO.md Normal file
View file

@ -0,0 +1,24 @@
### tool resolutions
- deterministic `node lts`
- updateable
```sql
CREATE TABLE IF NOT EXISTS tool_resolutions (
tool TEXT NOT NULL,
version TEXT NOT NULL,
resolved TEXT NOT NULL,
PRIMARY KEY (tool, version)
);
```
```console
$ pre-commit tools autoupdate [--only ...] # update config override versions
$ pre-commit tools resolve [--only ...] # update resolved versions
```
```yaml
# in .pre-commit-config.yaml
tool_resolution:
node: {lts: '24.2.0'}
```

23
pre_commit/all_tools.py Normal file
View file

@ -0,0 +1,23 @@
from __future__ import annotations
from pre_commit.tool_base import Tool
from pre_commit.tools import go
from pre_commit.tools import node
from pre_commit.tools import python
from pre_commit.tools import rbenv
from pre_commit.tools import ruby
from pre_commit.tools import rust
from pre_commit.tools import rustup
from pre_commit.tools import uv
tools: dict[str, Tool] = {
'go': go,
'node': node,
'python': python,
'rbenv': rbenv,
'ruby': ruby,
'rust': rust,
'rustup': rustup,
'uv': uv,
}

16
pre_commit/request.py Normal file
View file

@ -0,0 +1,16 @@
from __future__ import annotations
import sys
import urllib.request
from typing import IO
from pre_commit.constants import VERSION
def fetch(url: str) -> IO[bytes]:
pyver = '.'.join(str(v) for v in sys.version_info[:3])
req = urllib.request.Request(
url,
headers={'User-Agent': f'pre-commit/{VERSION} python/{pyver}'},
)
return urllib.request.urlopen(req)

16
pre_commit/tool_base.py Normal file
View file

@ -0,0 +1,16 @@
from __future__ import annotations
from typing import Protocol
from pre_commit.prefix import Prefix
class Tool(Protocol):
# "special" versions which can be resolved
@property
def RESOLVABLE(self) -> tuple[str, ...]: ...
# TODO: what if not resolvable? (no current examples?)
def resolve(self, version: str) -> str: ...
def install(self, prefix: Prefix, version: str) -> None: ...
def health_check(self, prefix: Prefix, version: str) -> str | None: ...
# TODO: how to env patch?

View file

0
pre_commit/tools/go.py Normal file
View file

50
pre_commit/tools/node.py Normal file
View file

@ -0,0 +1,50 @@
from __future__ import annotations
import functools
import json
from pre_commit.prefix import Prefix
from pre_commit.request import fetch
RESOLVABLE = ('latest', 'lts')
@functools.cache
def _node_versions() -> dict[str, str]:
resp = fetch('https://nodejs.org/download/release/index.json')
contents = json.load(resp)
ret = {'latest': contents[0]['version']}
for dct in contents:
if dct['lts']:
ret['lts'] = dct['version']
break
else:
raise AssertionError('unreachable')
return ret
def resolve(version: str) -> str:
return _node_versions()[version]
@functools.cache
def _target_platform() -> str:
# to support:
# linux-arm64, linux-ppc64le, linux-s390x, linux-x64
# osx-arm64-tar, osx-x86-tar
# win-arm64-zip, win-x64-zip
# or fallback to `src` ?
raise NotImplementedError
def install(prefix: Prefix, version: str) -> None:
# TODO: download and extract to prefix
raise NotImplementedError
def health_check(prefix: Prefix, version: str) -> str | None:
# TODO: previously checked `node --version`
# TODO: but maybe just check that the installed os/arch is correct?
return None

View file

@ -0,0 +1,5 @@
from __future__ import annotations
# TODO: how to get "latest" supported uv python?
# TODO: should this support `3.##` as resolvable?
# TODO: how would dynamic resolvables work...

View file

0
pre_commit/tools/ruby.py Normal file
View file

0
pre_commit/tools/rust.py Normal file
View file

View file

0
pre_commit/tools/uv.py Normal file
View file