1 | var fs = require('fs')
|
2 | var path = require('path')
|
3 | var os = require('os')
|
4 |
|
5 |
|
6 | var runtimeRequire = typeof __webpack_require__ === 'function' ? __non_webpack_require__ : require
|
7 |
|
8 | var vars = (process.config && process.config.variables) || {}
|
9 | var prebuildsOnly = !!process.env.PREBUILDS_ONLY
|
10 | var abi = process.versions.modules
|
11 | var runtime = isElectron() ? 'electron' : (isNwjs() ? 'node-webkit' : 'node')
|
12 |
|
13 | var arch = process.env.npm_config_arch || os.arch()
|
14 | var platform = process.env.npm_config_platform || os.platform()
|
15 | var libc = process.env.LIBC || (isAlpine(platform) ? 'musl' : 'glibc')
|
16 | var armv = process.env.ARM_VERSION || (arch === 'arm64' ? '8' : vars.arm_version) || ''
|
17 | var uv = (process.versions.uv || '').split('.')[0]
|
18 |
|
19 | module.exports = load
|
20 |
|
21 | function load (dir) {
|
22 | return runtimeRequire(load.resolve(dir))
|
23 | }
|
24 |
|
25 | load.resolve = load.path = function (dir) {
|
26 | dir = path.resolve(dir || '.')
|
27 |
|
28 | try {
|
29 | var name = runtimeRequire(path.join(dir, 'package.json')).name.toUpperCase().replace(/-/g, '_')
|
30 | if (process.env[name + '_PREBUILD']) dir = process.env[name + '_PREBUILD']
|
31 | } catch (err) {}
|
32 |
|
33 | if (!prebuildsOnly) {
|
34 | var release = getFirst(path.join(dir, 'build/Release'), matchBuild)
|
35 | if (release) return release
|
36 |
|
37 | var debug = getFirst(path.join(dir, 'build/Debug'), matchBuild)
|
38 | if (debug) return debug
|
39 | }
|
40 |
|
41 | var prebuild = resolve(dir)
|
42 | if (prebuild) return prebuild
|
43 |
|
44 | var nearby = resolve(path.dirname(process.execPath))
|
45 | if (nearby) return nearby
|
46 |
|
47 | var target = [
|
48 | 'platform=' + platform,
|
49 | 'arch=' + arch,
|
50 | 'runtime=' + runtime,
|
51 | 'abi=' + abi,
|
52 | 'uv=' + uv,
|
53 | armv ? 'armv=' + armv : '',
|
54 | 'libc=' + libc,
|
55 | 'node=' + process.versions.node,
|
56 | process.versions.electron ? 'electron=' + process.versions.electron : '',
|
57 | typeof __webpack_require__ === 'function' ? 'webpack=true' : ''
|
58 | ].filter(Boolean).join(' ')
|
59 |
|
60 | throw new Error('No native build was found for ' + target + '\n loaded from: ' + dir + '\n')
|
61 |
|
62 | function resolve (dir) {
|
63 |
|
64 | var tuples = readdirSync(path.join(dir, 'prebuilds')).map(parseTuple)
|
65 | var tuple = tuples.filter(matchTuple(platform, arch)).sort(compareTuples)[0]
|
66 | if (!tuple) return
|
67 |
|
68 |
|
69 | var prebuilds = path.join(dir, 'prebuilds', tuple.name)
|
70 | var parsed = readdirSync(prebuilds).map(parseTags)
|
71 | var candidates = parsed.filter(matchTags(runtime, abi))
|
72 | var winner = candidates.sort(compareTags(runtime))[0]
|
73 | if (winner) return path.join(prebuilds, winner.file)
|
74 | }
|
75 | }
|
76 |
|
77 | function readdirSync (dir) {
|
78 | try {
|
79 | return fs.readdirSync(dir)
|
80 | } catch (err) {
|
81 | return []
|
82 | }
|
83 | }
|
84 |
|
85 | function getFirst (dir, filter) {
|
86 | var files = readdirSync(dir).filter(filter)
|
87 | return files[0] && path.join(dir, files[0])
|
88 | }
|
89 |
|
90 | function matchBuild (name) {
|
91 | return /\.node$/.test(name)
|
92 | }
|
93 |
|
94 | function parseTuple (name) {
|
95 |
|
96 | var arr = name.split('-')
|
97 | if (arr.length !== 2) return
|
98 |
|
99 | var platform = arr[0]
|
100 | var architectures = arr[1].split('+')
|
101 |
|
102 | if (!platform) return
|
103 | if (!architectures.length) return
|
104 | if (!architectures.every(Boolean)) return
|
105 |
|
106 | return { name, platform, architectures }
|
107 | }
|
108 |
|
109 | function matchTuple (platform, arch) {
|
110 | return function (tuple) {
|
111 | if (tuple == null) return false
|
112 | if (tuple.platform !== platform) return false
|
113 | return tuple.architectures.includes(arch)
|
114 | }
|
115 | }
|
116 |
|
117 | function compareTuples (a, b) {
|
118 |
|
119 | return a.architectures.length - b.architectures.length
|
120 | }
|
121 |
|
122 | function parseTags (file) {
|
123 | var arr = file.split('.')
|
124 | var extension = arr.pop()
|
125 | var tags = { file: file, specificity: 0 }
|
126 |
|
127 | if (extension !== 'node') return
|
128 |
|
129 | for (var i = 0; i < arr.length; i++) {
|
130 | var tag = arr[i]
|
131 |
|
132 | if (tag === 'node' || tag === 'electron' || tag === 'node-webkit') {
|
133 | tags.runtime = tag
|
134 | } else if (tag === 'napi') {
|
135 | tags.napi = true
|
136 | } else if (tag.slice(0, 3) === 'abi') {
|
137 | tags.abi = tag.slice(3)
|
138 | } else if (tag.slice(0, 2) === 'uv') {
|
139 | tags.uv = tag.slice(2)
|
140 | } else if (tag.slice(0, 4) === 'armv') {
|
141 | tags.armv = tag.slice(4)
|
142 | } else if (tag === 'glibc' || tag === 'musl') {
|
143 | tags.libc = tag
|
144 | } else {
|
145 | continue
|
146 | }
|
147 |
|
148 | tags.specificity++
|
149 | }
|
150 |
|
151 | return tags
|
152 | }
|
153 |
|
154 | function matchTags (runtime, abi) {
|
155 | return function (tags) {
|
156 | if (tags == null) return false
|
157 | if (tags.runtime && tags.runtime !== runtime && !runtimeAgnostic(tags)) return false
|
158 | if (tags.abi && tags.abi !== abi && !tags.napi) return false
|
159 | if (tags.uv && tags.uv !== uv) return false
|
160 | if (tags.armv && tags.armv !== armv) return false
|
161 | if (tags.libc && tags.libc !== libc) return false
|
162 |
|
163 | return true
|
164 | }
|
165 | }
|
166 |
|
167 | function runtimeAgnostic (tags) {
|
168 | return tags.runtime === 'node' && tags.napi
|
169 | }
|
170 |
|
171 | function compareTags (runtime) {
|
172 |
|
173 | return function (a, b) {
|
174 | if (a.runtime !== b.runtime) {
|
175 | return a.runtime === runtime ? -1 : 1
|
176 | } else if (a.abi !== b.abi) {
|
177 | return a.abi ? -1 : 1
|
178 | } else if (a.specificity !== b.specificity) {
|
179 | return a.specificity > b.specificity ? -1 : 1
|
180 | } else {
|
181 | return 0
|
182 | }
|
183 | }
|
184 | }
|
185 |
|
186 | function isNwjs () {
|
187 | return !!(process.versions && process.versions.nw)
|
188 | }
|
189 |
|
190 | function isElectron () {
|
191 | if (process.versions && process.versions.electron) return true
|
192 | if (process.env.ELECTRON_RUN_AS_NODE) return true
|
193 | return typeof window !== 'undefined' && window.process && window.process.type === 'renderer'
|
194 | }
|
195 |
|
196 | function isAlpine (platform) {
|
197 | return platform === 'linux' && fs.existsSync('/etc/alpine-release')
|
198 | }
|
199 |
|
200 |
|
201 |
|
202 | load.parseTags = parseTags
|
203 | load.matchTags = matchTags
|
204 | load.compareTags = compareTags
|
205 | load.parseTuple = parseTuple
|
206 | load.matchTuple = matchTuple
|
207 | load.compareTuples = compareTuples
|