mirror of https://gitee.com/openkylin/npm.git
97 lines
2.3 KiB
JavaScript
97 lines
2.3 KiB
JavaScript
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
|