Skip to content

Commit dc4e5ea

Browse files
authoredApr 3, 2021
Restore local prebuilds feature (#137)
Previously removed in #81 / a069253.
1 parent 43d581a commit dc4e5ea

File tree

6 files changed

+149
-40
lines changed

6 files changed

+149
-40
lines changed
 

‎README.md

+17
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,23 @@ So if you are installing `leveldown@1.2.3` the resulting url will be:
9797
http://overriden-host.com/overriden-path/v1.2.3/leveldown-v1.2.3-node-v57-win32-x64.tar.gz
9898
```
9999

100+
101+
#### Local prebuilds
102+
103+
If you want to use prebuilds from your local filesystem, you can use the `% your package name %_local_prebuilds` .npmrc variable to set a path to the folder containing prebuilds. For example:
104+
105+
```
106+
leveldown_local_prebuilds=/path/to/prebuilds
107+
```
108+
109+
This option will look directly in that folder for bundles created with `prebuild`, for example:
110+
111+
```
112+
/path/to/prebuilds/leveldown-v1.2.3-node-v57-win32-x64.tar.gz
113+
```
114+
115+
Non-absolute paths resolve relative to the directory of the package invoking prebuild-install, e.g. for nested dependencies.
116+
100117
### Cache
101118

102119
All prebuilt binaries are cached to minimize traffic. So first `prebuild-install` picks binaries from the cache and if no binary could be found, it will be downloaded. Depending on the environment, the cache folder is determined in the following order:

‎download.js

+54-38
Original file line numberDiff line numberDiff line change
@@ -15,58 +15,74 @@ var mkdirp = require('mkdirp-classic')
1515

1616
function downloadPrebuild (downloadUrl, opts, cb) {
1717
var cachedPrebuild = util.cachedPrebuild(downloadUrl)
18+
var localPrebuild = util.localPrebuild(downloadUrl, opts)
1819
var tempFile = util.tempFile(cachedPrebuild)
1920
var log = opts.log || noop
2021

21-
ensureNpmCacheDir(function (err) {
22-
if (err) return onerror(err)
22+
if (opts.nolocal) return download()
2323

24-
log.info('looking for cached prebuild @', cachedPrebuild)
25-
fs.access(cachedPrebuild, fs.R_OK | fs.W_OK, function (err) {
26-
if (!(err && err.code === 'ENOENT')) {
27-
log.info('found cached prebuild')
28-
return unpack()
29-
}
24+
log.info('looking for local prebuild @', localPrebuild)
25+
fs.access(localPrebuild, fs.R_OK | fs.W_OK, function (err) {
26+
if (err && err.code === 'ENOENT') {
27+
return download()
28+
}
3029

31-
log.http('request', 'GET ' + downloadUrl)
32-
var reqOpts = proxy({ url: downloadUrl }, opts)
30+
log.info('found local prebuild')
31+
cachedPrebuild = localPrebuild
32+
unpack()
33+
})
3334

34-
if (opts.token) {
35-
reqOpts.url += '?access_token=' + opts.token
36-
reqOpts.headers = {
37-
'User-Agent': 'simple-get',
38-
Accept: 'application/octet-stream'
35+
function download () {
36+
ensureNpmCacheDir(function (err) {
37+
if (err) return onerror(err)
38+
39+
log.info('looking for cached prebuild @', cachedPrebuild)
40+
fs.access(cachedPrebuild, fs.R_OK | fs.W_OK, function (err) {
41+
if (!(err && err.code === 'ENOENT')) {
42+
log.info('found cached prebuild')
43+
return unpack()
3944
}
40-
}
4145

42-
var req = get(reqOpts, function (err, res) {
43-
if (err) return onerror(err)
44-
log.http(res.statusCode, downloadUrl)
45-
if (res.statusCode !== 200) return onerror()
46-
mkdirp(util.prebuildCache(), function () {
47-
log.info('downloading to @', tempFile)
48-
pump(res, fs.createWriteStream(tempFile), function (err) {
49-
if (err) return onerror(err)
50-
fs.rename(tempFile, cachedPrebuild, function (err) {
51-
if (err) return cb(err)
52-
log.info('renaming to @', cachedPrebuild)
53-
unpack()
46+
log.http('request', 'GET ' + downloadUrl)
47+
var reqOpts = proxy({ url: downloadUrl }, opts)
48+
49+
if (opts.token) {
50+
reqOpts.url += '?access_token=' + opts.token
51+
reqOpts.headers = {
52+
'User-Agent': 'simple-get',
53+
Accept: 'application/octet-stream'
54+
}
55+
}
56+
57+
var req = get(reqOpts, function (err, res) {
58+
if (err) return onerror(err)
59+
log.http(res.statusCode, downloadUrl)
60+
if (res.statusCode !== 200) return onerror()
61+
mkdirp(util.prebuildCache(), function () {
62+
log.info('downloading to @', tempFile)
63+
pump(res, fs.createWriteStream(tempFile), function (err) {
64+
if (err) return onerror(err)
65+
fs.rename(tempFile, cachedPrebuild, function (err) {
66+
if (err) return cb(err)
67+
log.info('renaming to @', cachedPrebuild)
68+
unpack()
69+
})
5470
})
5571
})
5672
})
57-
})
5873

59-
req.setTimeout(30 * 1000, function () {
60-
req.abort()
74+
req.setTimeout(30 * 1000, function () {
75+
req.abort()
76+
})
6177
})
62-
})
6378

64-
function onerror (err) {
65-
fs.unlink(tempFile, function () {
66-
cb(err || error.noPrebuilts(opts))
67-
})
68-
}
69-
})
79+
function onerror (err) {
80+
fs.unlink(tempFile, function () {
81+
cb(err || error.noPrebuilts(opts))
82+
})
83+
}
84+
})
85+
}
7086

7187
function unpack () {
7288
var binaryName

‎rc.js

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ module.exports = function (pkg) {
2525
proxy: env.npm_config_proxy || env['http_proxy'] || env['HTTP_PROXY'],
2626
'https-proxy': env.npm_config_https_proxy || env['https_proxy'] || env['HTTPS_PROXY'],
2727
'local-address': env.npm_config_local_address,
28+
'local-prebuilds': 'prebuilds',
2829
'tag-prefix': 'v',
2930
download: env.npm_config_download
3031
}, minimist(process.argv, {

‎test/download-test.js

+39-1
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,43 @@ test('cached prebuild', function (t) {
8989
})
9090
})
9191

92+
test('local prebuild', function (t) {
93+
t.plan(6)
94+
rm.sync(build)
95+
96+
var opts = getOpts()
97+
var downloadUrl = util.getDownloadUrl(opts)
98+
var cachedPrebuild = util.cachedPrebuild(downloadUrl)
99+
var localPrebuild = util.localPrebuild(downloadUrl, opts)
100+
101+
t.ok(fs.existsSync(cachedPrebuild), 'cached prebuild exists')
102+
103+
// fs.copyFileSync() not available before Node 8.5
104+
fs.writeFileSync(localPrebuild, fs.readFileSync(cachedPrebuild))
105+
106+
var _createWriteStream = fs.createWriteStream
107+
fs.createWriteStream = function (path) {
108+
t.ok(/\.node$/i.test(path), 'this is the unpacked file')
109+
return _createWriteStream(path)
110+
}
111+
112+
var _createReadStream = fs.createReadStream
113+
fs.createReadStream = function (path) {
114+
t.equal(path, localPrebuild, 'createReadStream called for localPrebuild')
115+
return _createReadStream(path)
116+
}
117+
118+
t.equal(fs.existsSync(build), false, 'no build folder')
119+
120+
download(downloadUrl, opts, function (err) {
121+
t.error(err, 'no error')
122+
t.equal(fs.existsSync(unpacked), true, unpacked + ' should exist')
123+
fs.createReadStream = _createReadStream
124+
fs.createWriteStream = _createWriteStream
125+
rm.sync(localPrebuild)
126+
})
127+
})
128+
92129
test('non existing host should fail with no dangling temp file', function (t) {
93130
t.plan(3)
94131

@@ -225,6 +262,7 @@ function getOpts () {
225262
platform: process.platform,
226263
arch: process.arch,
227264
path: __dirname,
228-
'tag-prefix': 'v'
265+
'tag-prefix': 'v',
266+
'local-prebuilds': __dirname
229267
}
230268
}

‎test/util-test.js

+26
Original file line numberDiff line numberDiff line change
@@ -190,3 +190,29 @@ test('getDownloadUrl() expands template to correct values', function (t) {
190190
t.equal(url3, url2, 'scope does not matter for download url')
191191
t.end()
192192
})
193+
194+
test('localPrebuild', function (t) {
195+
var envProp = 'npm_config_a_native_module_local_prebuilds'
196+
var basename = 'a-native-module-v1.4.0-node-v14-linux-x64.tar.gz'
197+
var url = 'https://github.com/a-native-module/a-native-module/releases/download/v1.4.0/' + basename
198+
var o1 = {
199+
pkg: {
200+
name: 'a-native-module'
201+
}
202+
}
203+
var path1 = util.localPrebuild(url, o1)
204+
t.equal(path1, path.join('prebuilds', basename))
205+
var o2 = {
206+
pkg: {
207+
name: 'a-native-module'
208+
},
209+
'local-prebuilds': path.join('', 'path', 'to', 'prebuilds')
210+
}
211+
var path2 = util.localPrebuild(url, o2)
212+
t.equal(path2, path.join(o2['local-prebuilds'], basename), 'opts overrides default')
213+
var envPrefix = path.join('', 'overriden', 'path', 'to', 'prebuilds')
214+
process.env[envProp] = envPrefix
215+
var path3 = util.localPrebuild(url, o2)
216+
t.equal(path3, path.join(envPrefix, basename), 'env overrides opts')
217+
t.end()
218+
})

‎util.js

+12-1
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,12 @@ function urlTemplate (opts) {
6060
return github(opts.pkg) + '/releases/download/{tag_prefix}{version}/' + packageName
6161
}
6262

63+
function getEnvPrefix (pkgName) {
64+
return 'npm_config_' + (pkgName || '').replace(/[^a-zA-Z0-9]/g, '_')
65+
}
66+
6367
function getHostMirrorUrl (opts) {
64-
var propName = 'npm_config_' + (opts.pkg.name || '').replace(/[^a-zA-Z0-9]/g, '_') + '_binary_host'
68+
var propName = getEnvPrefix(opts.pkg.name) + '_binary_host'
6569
return process.env[propName] || process.env[propName + '_mirror']
6670
}
6771

@@ -105,11 +109,18 @@ function packageOrigin (env, pkg) {
105109
}
106110
}
107111

112+
function localPrebuild (url, opts) {
113+
var propName = getEnvPrefix(opts.pkg.name) + '_local_prebuilds'
114+
var prefix = process.env[propName] || opts['local-prebuilds'] || 'prebuilds'
115+
return path.join(prefix, path.basename(url))
116+
}
117+
108118
exports.getDownloadUrl = getDownloadUrl
109119
exports.getApiUrl = getApiUrl
110120
exports.getAssetUrl = getAssetUrl
111121
exports.urlTemplate = urlTemplate
112122
exports.cachedPrebuild = cachedPrebuild
123+
exports.localPrebuild = localPrebuild
113124
exports.prebuildCache = prebuildCache
114125
exports.npmCache = npmCache
115126
exports.tempFile = tempFile

0 commit comments

Comments
 (0)
Please sign in to comment.