1 | const Fetcher = require('./fetcher.js')
|
---|
2 | const fsm = require('fs-minipass')
|
---|
3 | const cacache = require('cacache')
|
---|
4 | const { promisify } = require('util')
|
---|
5 | const readPackageJson = require('read-package-json-fast')
|
---|
6 | const _tarballFromResolved = Symbol.for('pacote.Fetcher._tarballFromResolved')
|
---|
7 | const _exeBins = Symbol('_exeBins')
|
---|
8 | const { resolve } = require('path')
|
---|
9 | const fs = require('fs')
|
---|
10 |
|
---|
11 | class FileFetcher extends Fetcher {
|
---|
12 | constructor (spec, opts) {
|
---|
13 | super(spec, opts)
|
---|
14 | // just the fully resolved filename
|
---|
15 | this.resolved = this.spec.fetchSpec
|
---|
16 | }
|
---|
17 |
|
---|
18 | get types () {
|
---|
19 | return ['file']
|
---|
20 | }
|
---|
21 |
|
---|
22 | manifest () {
|
---|
23 | if (this.package)
|
---|
24 | return Promise.resolve(this.package)
|
---|
25 |
|
---|
26 | // have to unpack the tarball for this.
|
---|
27 | return cacache.tmp.withTmp(this.cache, this.opts, dir =>
|
---|
28 | this.extract(dir)
|
---|
29 | .then(() => readPackageJson(dir + '/package.json'))
|
---|
30 | .then(mani => this.package = {
|
---|
31 | ...mani,
|
---|
32 | _integrity: this.integrity && String(this.integrity),
|
---|
33 | _resolved: this.resolved,
|
---|
34 | _from: this.from,
|
---|
35 | }))
|
---|
36 | }
|
---|
37 |
|
---|
38 | [_exeBins] (pkg, dest) {
|
---|
39 | if (!pkg.bin)
|
---|
40 | return Promise.resolve()
|
---|
41 |
|
---|
42 | return Promise.all(Object.keys(pkg.bin).map(k => new Promise(res => {
|
---|
43 | const script = resolve(dest, pkg.bin[k])
|
---|
44 | // Best effort. Ignore errors here, the only result is that
|
---|
45 | // a bin script is not executable. But if it's missing or
|
---|
46 | // something, we just leave it for a later stage to trip over
|
---|
47 | // when we can provide a more useful contextual error.
|
---|
48 | fs.stat(script, (er, st) => {
|
---|
49 | if (er)
|
---|
50 | return res()
|
---|
51 | const mode = st.mode | 0o111
|
---|
52 | if (mode === st.mode)
|
---|
53 | return res()
|
---|
54 | fs.chmod(script, mode, res)
|
---|
55 | })
|
---|
56 | })))
|
---|
57 | }
|
---|
58 |
|
---|
59 | extract (dest) {
|
---|
60 | // if we've already loaded the manifest, then the super got it.
|
---|
61 | // but if not, read the unpacked manifest and chmod properly.
|
---|
62 | return super.extract(dest)
|
---|
63 | .then(result => this.package ? result
|
---|
64 | : readPackageJson(dest + '/package.json').then(pkg =>
|
---|
65 | this[_exeBins](pkg, dest)).then(() => result))
|
---|
66 | }
|
---|
67 |
|
---|
68 | [_tarballFromResolved] () {
|
---|
69 | // create a read stream and return it
|
---|
70 | return new fsm.ReadStream(this.resolved)
|
---|
71 | }
|
---|
72 |
|
---|
73 | packument () {
|
---|
74 | // simulate based on manifest
|
---|
75 | return this.manifest().then(mani => ({
|
---|
76 | name: mani.name,
|
---|
77 | 'dist-tags': {
|
---|
78 | [this.defaultTag]: mani.version
|
---|
79 | },
|
---|
80 | versions: {
|
---|
81 | [mani.version]: {
|
---|
82 | ...mani,
|
---|
83 | dist: {
|
---|
84 | tarball: `file:${this.resolved}`,
|
---|
85 | integrity: this.integrity && String(this.integrity),
|
---|
86 | }
|
---|
87 | }
|
---|
88 | }
|
---|
89 | }))
|
---|
90 | }
|
---|
91 | }
|
---|
92 |
|
---|
93 | module.exports = FileFetcher
|
---|