11cb0ef41Sopenharmony_ciconst tar = require('tar')
21cb0ef41Sopenharmony_ciconst { minimatch } = require('minimatch')
31cb0ef41Sopenharmony_ci
41cb0ef41Sopenharmony_ciconst normalizeMatch = str => str
51cb0ef41Sopenharmony_ci  .replace(/\\+/g, '/')
61cb0ef41Sopenharmony_ci  .replace(/^\.\/|^\./, '')
71cb0ef41Sopenharmony_ci
81cb0ef41Sopenharmony_ci// files and refs are mutating params
91cb0ef41Sopenharmony_ci// filterFiles, item, prefix and opts are read-only options
101cb0ef41Sopenharmony_ciconst untar = ({ files, refs }, { filterFiles, item, prefix }) => {
111cb0ef41Sopenharmony_ci  tar.list({
121cb0ef41Sopenharmony_ci    filter: (path, entry) => {
131cb0ef41Sopenharmony_ci      const fileMatch = () =>
141cb0ef41Sopenharmony_ci        (!filterFiles.length ||
151cb0ef41Sopenharmony_ci          filterFiles.some(f => {
161cb0ef41Sopenharmony_ci            const pattern = normalizeMatch(f)
171cb0ef41Sopenharmony_ci            return minimatch(
181cb0ef41Sopenharmony_ci              normalizeMatch(path),
191cb0ef41Sopenharmony_ci              `{package/,}${pattern}`,
201cb0ef41Sopenharmony_ci              { matchBase: pattern.startsWith('*') }
211cb0ef41Sopenharmony_ci            )
221cb0ef41Sopenharmony_ci          }))
231cb0ef41Sopenharmony_ci
241cb0ef41Sopenharmony_ci      // expands usage of simple path filters, e.g: lib or src/
251cb0ef41Sopenharmony_ci      const folderMatch = () =>
261cb0ef41Sopenharmony_ci        filterFiles.some(f =>
271cb0ef41Sopenharmony_ci          normalizeMatch(path).startsWith(normalizeMatch(f)) ||
281cb0ef41Sopenharmony_ci          normalizeMatch(path).startsWith(`package/${normalizeMatch(f)}`))
291cb0ef41Sopenharmony_ci
301cb0ef41Sopenharmony_ci      if (
311cb0ef41Sopenharmony_ci        entry.type === 'File' &&
321cb0ef41Sopenharmony_ci        (fileMatch() || folderMatch())
331cb0ef41Sopenharmony_ci      ) {
341cb0ef41Sopenharmony_ci        const key = path.replace(/^[^/]+\/?/, '')
351cb0ef41Sopenharmony_ci        files.add(key)
361cb0ef41Sopenharmony_ci
371cb0ef41Sopenharmony_ci        // should skip reading file when using --name-only option
381cb0ef41Sopenharmony_ci        let content
391cb0ef41Sopenharmony_ci        try {
401cb0ef41Sopenharmony_ci          entry.setEncoding('utf8')
411cb0ef41Sopenharmony_ci          content = entry.concat()
421cb0ef41Sopenharmony_ci        } catch (e) {
431cb0ef41Sopenharmony_ci          /* istanbul ignore next */
441cb0ef41Sopenharmony_ci          throw Object.assign(
451cb0ef41Sopenharmony_ci            new Error('failed to read files'),
461cb0ef41Sopenharmony_ci            { code: 'EDIFFUNTAR' }
471cb0ef41Sopenharmony_ci          )
481cb0ef41Sopenharmony_ci        }
491cb0ef41Sopenharmony_ci
501cb0ef41Sopenharmony_ci        refs.set(`${prefix}${key}`, {
511cb0ef41Sopenharmony_ci          content,
521cb0ef41Sopenharmony_ci          mode: `100${entry.mode.toString(8)}`,
531cb0ef41Sopenharmony_ci        })
541cb0ef41Sopenharmony_ci        return true
551cb0ef41Sopenharmony_ci      }
561cb0ef41Sopenharmony_ci    },
571cb0ef41Sopenharmony_ci  })
581cb0ef41Sopenharmony_ci    .on('error', /* istanbul ignore next */ e => {
591cb0ef41Sopenharmony_ci      throw e
601cb0ef41Sopenharmony_ci    })
611cb0ef41Sopenharmony_ci    .end(item)
621cb0ef41Sopenharmony_ci}
631cb0ef41Sopenharmony_ci
641cb0ef41Sopenharmony_ciconst readTarballs = async (tarballs, opts = {}) => {
651cb0ef41Sopenharmony_ci  const files = new Set()
661cb0ef41Sopenharmony_ci  const refs = new Map()
671cb0ef41Sopenharmony_ci  const arr = [].concat(tarballs)
681cb0ef41Sopenharmony_ci
691cb0ef41Sopenharmony_ci  const filterFiles = opts.diffFiles || []
701cb0ef41Sopenharmony_ci
711cb0ef41Sopenharmony_ci  for (const i of arr) {
721cb0ef41Sopenharmony_ci    untar({
731cb0ef41Sopenharmony_ci      files,
741cb0ef41Sopenharmony_ci      refs,
751cb0ef41Sopenharmony_ci    }, {
761cb0ef41Sopenharmony_ci      item: i.item,
771cb0ef41Sopenharmony_ci      prefix: i.prefix,
781cb0ef41Sopenharmony_ci      filterFiles,
791cb0ef41Sopenharmony_ci    })
801cb0ef41Sopenharmony_ci  }
811cb0ef41Sopenharmony_ci
821cb0ef41Sopenharmony_ci  // await to read all content from included files
831cb0ef41Sopenharmony_ci  const allRefs = [...refs.values()]
841cb0ef41Sopenharmony_ci  const contents = await Promise.all(allRefs.map(async ref => ref.content))
851cb0ef41Sopenharmony_ci
861cb0ef41Sopenharmony_ci  contents.forEach((content, index) => {
871cb0ef41Sopenharmony_ci    allRefs[index].content = content
881cb0ef41Sopenharmony_ci  })
891cb0ef41Sopenharmony_ci
901cb0ef41Sopenharmony_ci  return {
911cb0ef41Sopenharmony_ci    files,
921cb0ef41Sopenharmony_ci    refs,
931cb0ef41Sopenharmony_ci  }
941cb0ef41Sopenharmony_ci}
951cb0ef41Sopenharmony_ci
961cb0ef41Sopenharmony_cimodule.exports = readTarballs
97