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
|
const tar = require('tar')
const { minimatch } = require('minimatch')
const normalizeMatch = str => str
.replace(/\\+/g, '/')
.replace(/^\.\/|^\./, '')
// files and refs are mutating params
// filterFiles, item, prefix and opts are read-only options
const untar = ({ files, refs }, { filterFiles, item, prefix }) => {
tar.list({
filter: (path, entry) => {
const fileMatch = () =>
(!filterFiles.length ||
filterFiles.some(f => {
const pattern = normalizeMatch(f)
return minimatch(
normalizeMatch(path),
`{package/,}${pattern}`,
{ matchBase: pattern.startsWith('*') }
)
}))
// expands usage of simple path filters, e.g: lib or src/
const folderMatch = () =>
filterFiles.some(f =>
normalizeMatch(path).startsWith(normalizeMatch(f)) ||
normalizeMatch(path).startsWith(`package/${normalizeMatch(f)}`))
if (
entry.type === 'File' &&
(fileMatch() || folderMatch())
) {
const key = path.replace(/^[^/]+\/?/, '')
files.add(key)
// should skip reading file when using --name-only option
let content
try {
entry.setEncoding('utf8')
content = entry.concat()
} catch (e) {
/* istanbul ignore next */
throw Object.assign(
new Error('failed to read files'),
{ code: 'EDIFFUNTAR' }
)
}
refs.set(`${prefix}${key}`, {
content,
mode: `100${entry.mode.toString(8)}`,
})
return true
}
},
})
.on('error', /* istanbul ignore next */ e => {
throw e
})
.end(item)
}
const readTarballs = async (tarballs, opts = {}) => {
const files = new Set()
const refs = new Map()
const arr = [].concat(tarballs)
const filterFiles = opts.diffFiles || []
for (const i of arr) {
untar({
files,
refs,
}, {
item: i.item,
prefix: i.prefix,
filterFiles,
})
}
// await to read all content from included files
const allRefs = [...refs.values()]
const contents = await Promise.all(allRefs.map(async ref => ref.content))
contents.forEach((content, index) => {
allRefs[index].content = content
})
return {
files,
refs,
}
}
module.exports = readTarballs
|