mirror of
https://github.com/crate-ci/typos.git
synced 2024-11-22 17:11:07 -05:00
Merge pull request #289 from scop/feat/pre-commit-py
feat(pre-commit): add binary based install
This commit is contained in:
commit
e01a34ad08
4 changed files with 180 additions and 1 deletions
|
@ -1,6 +1,14 @@
|
||||||
- id: typos
|
- id: typos
|
||||||
name: typos
|
name: typos
|
||||||
description: Source code spell checker
|
description: Source code spell checker, binary install
|
||||||
|
language: python
|
||||||
|
entry: typos
|
||||||
|
args: [--write-changes]
|
||||||
|
types: [text]
|
||||||
|
|
||||||
|
- id: typos-src
|
||||||
|
name: typos
|
||||||
|
description: Source code spell checker, source install
|
||||||
language: rust
|
language: rust
|
||||||
entry: typos
|
entry: typos
|
||||||
args: [--write-changes]
|
args: [--write-changes]
|
||||||
|
|
|
@ -38,6 +38,7 @@ pre-release-replacements = [
|
||||||
{file="CHANGELOG.md", search="<!-- next-url -->", replace="<!-- next-url -->\n[Unreleased]: https://github.com/assert-rs/predicates-rs/compare/{{tag_name}}...HEAD", exactly=1},
|
{file="CHANGELOG.md", search="<!-- next-url -->", replace="<!-- next-url -->\n[Unreleased]: https://github.com/assert-rs/predicates-rs/compare/{{tag_name}}...HEAD", exactly=1},
|
||||||
{file="docker/Dockerfile", search="ARG VERSION=.*", replace="ARG VERSION={{version}}", min=1},
|
{file="docker/Dockerfile", search="ARG VERSION=.*", replace="ARG VERSION={{version}}", min=1},
|
||||||
{file="docs/pre-commit.md", search="rev: .*", replace="rev: {{tag_name}}", exactly=1},
|
{file="docs/pre-commit.md", search="rev: .*", replace="rev: {{tag_name}}", exactly=1},
|
||||||
|
{file="setup.py", search="TYPOS_VERSION = .*", replace="TYPOS_VERSION = '{{version}}'", exactly=1},
|
||||||
]
|
]
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
|
|
|
@ -11,6 +11,10 @@ repos:
|
||||||
- id: typos
|
- id: typos
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The `typos` id installs a prebuilt executable from GitHub releases. If
|
||||||
|
one does not exist for the target platform, or if one built from
|
||||||
|
sources is preferred, use `typos-src` as the hook id instead.
|
||||||
|
|
||||||
Be sure to change `rev` to use the desired `typos` git tag or
|
Be sure to change `rev` to use the desired `typos` git tag or
|
||||||
revision.
|
revision.
|
||||||
|
|
||||||
|
|
166
setup.py
Normal file
166
setup.py
Normal file
|
@ -0,0 +1,166 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
import hashlib
|
||||||
|
import http
|
||||||
|
import io
|
||||||
|
import os.path
|
||||||
|
import stat
|
||||||
|
import sys
|
||||||
|
import tarfile
|
||||||
|
import urllib.request
|
||||||
|
import zipfile
|
||||||
|
from distutils.command.build import build as orig_build
|
||||||
|
from distutils.core import Command
|
||||||
|
from typing import Tuple
|
||||||
|
|
||||||
|
from setuptools import setup
|
||||||
|
from setuptools.command.install import install as orig_install
|
||||||
|
|
||||||
|
TYPOS_VERSION = '1.0.9'
|
||||||
|
POSTFIX_SHA256 = {
|
||||||
|
'linux': (
|
||||||
|
'x86_64-unknown-linux-gnu.tar.gz',
|
||||||
|
'', # TODO: sha256 hexhash when we can generate it with release
|
||||||
|
),
|
||||||
|
'darwin': (
|
||||||
|
'x86_64-apple-darwin.tar.gz',
|
||||||
|
'', # TODO: sha256 hexhash when we can generate it with release
|
||||||
|
),
|
||||||
|
'win32': (
|
||||||
|
'x86_64-pc-windows-msvc.zip',
|
||||||
|
'', # TODO: sha256 hexhash when we can generate it with release
|
||||||
|
),
|
||||||
|
}
|
||||||
|
PY_VERSION = '1'
|
||||||
|
|
||||||
|
|
||||||
|
def get_download_url() -> Tuple[str, str]:
|
||||||
|
postfix, sha256 = POSTFIX_SHA256[sys.platform]
|
||||||
|
url = (
|
||||||
|
f'https://github.com/crate-ci/typos/releases/download/'
|
||||||
|
f'v{TYPOS_VERSION}/typos-v{TYPOS_VERSION}-{postfix}'
|
||||||
|
)
|
||||||
|
return url, sha256
|
||||||
|
|
||||||
|
|
||||||
|
def download(url: str, sha256: str) -> bytes:
|
||||||
|
with urllib.request.urlopen(url) as resp:
|
||||||
|
code = resp.getcode()
|
||||||
|
if code != http.HTTPStatus.OK:
|
||||||
|
raise ValueError(f'HTTP failure. Code: {code}')
|
||||||
|
data = resp.read()
|
||||||
|
|
||||||
|
if not sha256:
|
||||||
|
return data
|
||||||
|
|
||||||
|
checksum = hashlib.sha256(data).hexdigest()
|
||||||
|
if checksum != sha256:
|
||||||
|
raise ValueError(f'sha256 mismatch, expected {sha256}, got {checksum}')
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
def extract(url: str, data: bytes) -> bytes:
|
||||||
|
with io.BytesIO(data) as bio:
|
||||||
|
if '.tar.' in url:
|
||||||
|
with tarfile.open(fileobj=bio) as tarf:
|
||||||
|
for info in tarf.getmembers():
|
||||||
|
if info.isfile() and info.name.endswith('typos'):
|
||||||
|
return tarf.extractfile(info).read()
|
||||||
|
elif url.endswith('.zip'):
|
||||||
|
with zipfile.ZipFile(bio) as zipf:
|
||||||
|
for info in zipf.infolist():
|
||||||
|
if info.filename.endswith('.exe'):
|
||||||
|
return zipf.read(info.filename)
|
||||||
|
|
||||||
|
raise AssertionError(f'unreachable {url}')
|
||||||
|
|
||||||
|
|
||||||
|
def save_executable(data: bytes, base_dir: str):
|
||||||
|
exe = 'typos' if sys.platform != 'win32' else 'typos.exe'
|
||||||
|
output_path = os.path.join(base_dir, exe)
|
||||||
|
os.makedirs(base_dir)
|
||||||
|
|
||||||
|
with open(output_path, 'wb') as fp:
|
||||||
|
fp.write(data)
|
||||||
|
|
||||||
|
# Mark as executable.
|
||||||
|
# https://stackoverflow.com/a/14105527
|
||||||
|
mode = os.stat(output_path).st_mode
|
||||||
|
mode |= stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
|
||||||
|
os.chmod(output_path, mode)
|
||||||
|
|
||||||
|
|
||||||
|
class build(orig_build):
|
||||||
|
sub_commands = orig_build.sub_commands + [('fetch_binaries', None)]
|
||||||
|
|
||||||
|
|
||||||
|
class install(orig_install):
|
||||||
|
sub_commands = orig_install.sub_commands + [('install_typos', None)]
|
||||||
|
|
||||||
|
|
||||||
|
class fetch_binaries(Command):
|
||||||
|
build_temp = None
|
||||||
|
|
||||||
|
def initialize_options(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def finalize_options(self):
|
||||||
|
self.set_undefined_options('build', ('build_temp', 'build_temp'))
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
# save binary to self.build_temp
|
||||||
|
url, sha256 = get_download_url()
|
||||||
|
archive = download(url, sha256)
|
||||||
|
data = extract(url, archive)
|
||||||
|
save_executable(data, self.build_temp)
|
||||||
|
|
||||||
|
|
||||||
|
class install_typos(Command):
|
||||||
|
description = 'install the typos executable'
|
||||||
|
outfiles = ()
|
||||||
|
build_dir = install_dir = None
|
||||||
|
|
||||||
|
def initialize_options(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def finalize_options(self):
|
||||||
|
# this initializes attributes based on other commands' attributes
|
||||||
|
self.set_undefined_options('build', ('build_temp', 'build_dir'))
|
||||||
|
self.set_undefined_options(
|
||||||
|
'install', ('install_scripts', 'install_dir'),
|
||||||
|
)
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
self.outfiles = self.copy_tree(self.build_dir, self.install_dir)
|
||||||
|
|
||||||
|
def get_outputs(self):
|
||||||
|
return self.outfiles
|
||||||
|
|
||||||
|
|
||||||
|
command_overrides = {
|
||||||
|
'install': install,
|
||||||
|
'install_typos': install_typos,
|
||||||
|
'build': build,
|
||||||
|
'fetch_binaries': fetch_binaries,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
from wheel.bdist_wheel import bdist_wheel as orig_bdist_wheel
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
class bdist_wheel(orig_bdist_wheel):
|
||||||
|
def finalize_options(self):
|
||||||
|
orig_bdist_wheel.finalize_options(self)
|
||||||
|
# Mark us as not a pure python package
|
||||||
|
self.root_is_pure = False
|
||||||
|
|
||||||
|
def get_tag(self):
|
||||||
|
_, _, plat = orig_bdist_wheel.get_tag(self)
|
||||||
|
# We don't contain any python source, nor any python extensions
|
||||||
|
return 'py2.py3', 'none', plat
|
||||||
|
|
||||||
|
command_overrides['bdist_wheel'] = bdist_wheel
|
||||||
|
|
||||||
|
setup(version=f'{TYPOS_VERSION}.{PY_VERSION}', cmdclass=command_overrides)
|
Loading…
Reference in a new issue