Repository navigation
Expand file tree
/
Copy pathnode_env.py
More file actions
108 lines (88 loc) · 3.39 KB
/
Copy pathnode_env.py
File metadata and controls
108 lines (88 loc) · 3.39 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
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