mirror of
https://github.com/pre-commit/pre-commit.git
synced 2026-04-15 18:11:48 +04:00
108 lines
3.4 KiB
Python
108 lines
3.4 KiB
Python
import io
|
|
import os
|
|
import platform
|
|
import re
|
|
import sys
|
|
import sysconfig
|
|
from tarfile import TarFile
|
|
from tarfile import TarInfo
|
|
from typing import Generator
|
|
from urllib.parse import urljoin
|
|
from urllib.request import urlopen
|
|
from zipfile import ZipFile
|
|
|
|
import pre_commit.constants as C
|
|
|
|
ARCHITECTURES = {
|
|
'x86': 'x86', # Windows Vista 32
|
|
'i686': 'x86',
|
|
'x86_64': 'x64', # Linux Ubuntu 64
|
|
'amd64': 'x64', # FreeBSD 64bits
|
|
'AMD64': 'x64', # Windows Server 2012 R2 (x64)
|
|
'armv6l': 'armv6l', # arm
|
|
'armv7l': 'armv7l',
|
|
'armv8l': 'armv7l',
|
|
'aarch64': 'arm64',
|
|
'arm64': 'arm64',
|
|
'arm64/v8': 'arm64',
|
|
'armv8': 'arm64',
|
|
'armv8.4': 'arm64',
|
|
'ppc64le': 'ppc64le', # Power PC
|
|
's390x': 's390x', # IBM S390x
|
|
}
|
|
|
|
NIX_NODE_SUBDIRS = re.compile(r'node[^/]+/(bin|lib|include|share)')
|
|
WINDOWS_NODE_SUBDIRS = re.compile(r'node[^/]+(np|node)')
|
|
|
|
|
|
def install_node(envdir: str, language_version: str) -> str:
|
|
windows = sys.platform in ('cygwin', 'win32')
|
|
|
|
if sysconfig.get_config_var('HOST_GNU_TYPE') == 'x86_64-pc-linux-musl':
|
|
domain = 'https://unofficial-builds.nodejs.org'
|
|
suffix = 'linux-x64-musl.tar.gz'
|
|
else:
|
|
domain = 'https://nodejs.org'
|
|
|
|
arch = ARCHITECTURES[platform.machine()]
|
|
if windows:
|
|
suffix = f'win-{arch}.zip'
|
|
else:
|
|
suffix = f'{platform.system().lower()}-{arch}.tar.gz'
|
|
|
|
version = _node_version(domain, language_version)
|
|
|
|
archive_name = f'node-{version}-{suffix}'
|
|
with urlopen(
|
|
urljoin(domain, f'download/release/{version}/{archive_name}'),
|
|
) as release:
|
|
compressed = io.BytesIO(release.read())
|
|
|
|
# TODO should i just extractall + rm the extra bits instead of partially
|
|
# extracting & renaming?
|
|
|
|
if windows:
|
|
# TODO this doesn't quite work
|
|
def renamed_members(z: ZipFile) -> Generator[str, None, None]:
|
|
prefix_len = len(f'{archive_name}/')
|
|
for m in z.filelist:
|
|
if WINDOWS_NODE_SUBDIRS.match(m.filename):
|
|
m.filename = m.filename[prefix_len:]
|
|
yield m.filename
|
|
|
|
with ZipFile(compressed) as z:
|
|
z.extractall(envdir, renamed_members(z))
|
|
|
|
raise NotImplementedError('TODO')
|
|
|
|
else:
|
|
def rename_members_tf(tf: TarFile) -> Generator[TarInfo, None, None]:
|
|
prefix_len = len(f'{archive_name}/')
|
|
for m in tf.getmembers():
|
|
if NIX_NODE_SUBDIRS.match(m.name):
|
|
m.path = m.path[prefix_len:]
|
|
yield m
|
|
|
|
with TarFile.open(fileobj=compressed) as tf:
|
|
tf.extractall(envdir, rename_members_tf(tf)) # type: ignore
|
|
|
|
for file in ('npm', 'npx', 'node'):
|
|
path = os.path.join(envdir, 'bin', file)
|
|
os.chmod(path, os.stat(path).st_mode | 0o111)
|
|
os.symlink('node', os.path.join(envdir, 'bin', 'nodejs'))
|
|
|
|
return os.path.join(envdir, 'bin', 'npm')
|
|
|
|
|
|
def _node_version(domain: str, language_version: str) -> str:
|
|
"""Looks up the node.js version based on the configured
|
|
version (uses the latest by default)"""
|
|
if language_version == C.DEFAULT:
|
|
# grab latest
|
|
with urlopen(urljoin(domain, 'download/release/index.tab')) as index:
|
|
_ = next(index) # header
|
|
version = next(index).split()[0].decode()
|
|
else:
|
|
version = f'v{language_version.replace("v", "")}'
|
|
|
|
return version
|