@@ -10,7 +10,8 @@ const pipe = BB.promisify(require('mississippi').pipe)
10
10
const ssri = require ( 'ssri' )
11
11
const Y = require ( '../util/y.js' )
12
12
13
- BB . promisifyAll ( fs )
13
+ const lstatAsync = BB . promisify ( fs . lstat )
14
+ const readFileAsync = BB . promisify ( fs . readFile )
14
15
15
16
const ReadOpts = figgyPudding ( {
16
17
size : { }
@@ -19,10 +20,8 @@ const ReadOpts = figgyPudding({
19
20
module . exports = read
20
21
function read ( cache , integrity , opts ) {
21
22
opts = ReadOpts ( opts )
22
- return pickContentSri ( cache , integrity ) . then ( content => {
23
- const sri = content . sri
24
- const cpath = contentPath ( cache , sri )
25
- return fs . readFileAsync ( cpath , null ) . then ( data => {
23
+ return withContentSri ( cache , integrity , ( cpath , sri ) => {
24
+ return readFileAsync ( cpath , null ) . then ( data => {
26
25
if ( typeof opts . size === 'number' && opts . size !== data . length ) {
27
26
throw sizeError ( opts . size , data . length )
28
27
} else if ( ssri . checkData ( data , sri ) ) {
@@ -39,12 +38,11 @@ module.exports.readStream = readStream
39
38
function readStream ( cache , integrity , opts ) {
40
39
opts = ReadOpts ( opts )
41
40
const stream = new PassThrough ( )
42
- pickContentSri (
43
- cache , integrity
44
- ) . then ( content => {
45
- const sri = content . sri
41
+ withContentSri ( cache , integrity , ( cpath , sri ) => {
42
+ return lstatAsync ( cpath ) . then ( stat => ( { cpath, sri, stat} ) )
43
+ } ) . then ( ( { cpath, sri, stat} ) => {
46
44
return pipe (
47
- fs . createReadStream ( contentPath ( cache , sri ) ) ,
45
+ fs . createReadStream ( cpath ) ,
48
46
ssri . integrityStream ( {
49
47
integrity : sri ,
50
48
size : opts . size
@@ -57,60 +55,61 @@ function readStream (cache, integrity, opts) {
57
55
return stream
58
56
}
59
57
58
+ let copyFileAsync
60
59
if ( fs . copyFile ) {
61
60
module . exports . copy = copy
61
+ copyFileAsync = BB . promisify ( fs . copyFile )
62
62
}
63
63
function copy ( cache , integrity , dest , opts ) {
64
64
opts = ReadOpts ( opts )
65
- return pickContentSri ( cache , integrity ) . then ( content => {
66
- const sri = content . sri
67
- const cpath = contentPath ( cache , sri )
68
- return fs . copyFileAsync ( cpath , dest ) . then ( ( ) => content . size )
65
+ return withContentSri ( cache , integrity , ( cpath , sri ) => {
66
+ return copyFileAsync ( cpath , dest )
69
67
} )
70
68
}
71
69
72
70
module . exports . hasContent = hasContent
73
71
function hasContent ( cache , integrity ) {
74
72
if ( ! integrity ) { return BB . resolve ( false ) }
75
- return pickContentSri ( cache , integrity )
76
- . catch ( { code : 'ENOENT' } , ( ) => false )
77
- . catch ( { code : 'EPERM' } , err => {
73
+ return withContentSri ( cache , integrity , ( cpath , sri ) => {
74
+ return lstatAsync ( cpath ) . then ( stat => ( { size : stat . size , sri} ) )
75
+ } ) . catch ( err => {
76
+ if ( err . code === 'ENOENT' ) { return false }
77
+ if ( err . code === 'EPERM' ) {
78
78
if ( process . platform !== 'win32' ) {
79
79
throw err
80
80
} else {
81
81
return false
82
82
}
83
- } ) . then ( content => {
84
- if ( ! content . sri ) return false
85
- return ( { sri : content . sri , size : content . stat . size } )
86
- } )
83
+ }
84
+ } )
87
85
}
88
86
89
- module . exports . _pickContentSri = pickContentSri
90
- function pickContentSri ( cache , integrity ) {
91
- const sri = ssri . parse ( integrity )
92
- // If `integrity` has multiple entries, pick the first digest
93
- // with available local data.
94
- const algo = sri . pickAlgorithm ( )
95
- const digests = sri [ algo ]
96
- if ( digests . length <= 1 ) {
97
- const cpath = contentPath ( cache , digests [ 0 ] )
98
- return fs . lstatAsync ( cpath ) . then ( stat => ( { sri : digests [ 0 ] , stat } ) )
99
- } else {
100
- return BB . any ( sri [ sri . pickAlgorithm ( ) ] . map ( meta => {
101
- return pickContentSri ( cache , meta )
102
- } ) )
103
- . catch ( err => {
104
- if ( [ ] . some . call ( err , e => e . code === 'ENOENT' ) ) {
105
- throw Object . assign (
106
- new Error ( 'No matching content found for ' + sri . toString ( ) ) ,
107
- { code : 'ENOENT' }
108
- )
109
- } else {
110
- throw err [ 0 ]
111
- }
112
- } )
113
- }
87
+ function withContentSri ( cache , integrity , fn ) {
88
+ return BB . try ( ( ) => {
89
+ const sri = ssri . parse ( integrity )
90
+ // If `integrity` has multiple entries, pick the first digest
91
+ // with available local data.
92
+ const algo = sri . pickAlgorithm ( )
93
+ const digests = sri [ algo ]
94
+ if ( digests . length <= 1 ) {
95
+ const cpath = contentPath ( cache , digests [ 0 ] )
96
+ return fn ( cpath , digests [ 0 ] )
97
+ } else {
98
+ return BB . any ( sri [ sri . pickAlgorithm ( ) ] . map ( meta => {
99
+ return withContentSri ( cache , meta , fn )
100
+ } , { concurrency : 1 } ) )
101
+ . catch ( err => {
102
+ if ( [ ] . some . call ( err , e => e . code === 'ENOENT' ) ) {
103
+ throw Object . assign (
104
+ new Error ( 'No matching content found for ' + sri . toString ( ) ) ,
105
+ { code : 'ENOENT' }
106
+ )
107
+ } else {
108
+ throw err [ 0 ]
109
+ }
110
+ } )
111
+ }
112
+ } )
114
113
}
115
114
116
115
function sizeError ( expected , found ) {
0 commit comments