11cb0ef41Sopenharmony_ci'use strict'
21cb0ef41Sopenharmony_ci
31cb0ef41Sopenharmony_ciconst { createWriteStream, promises: fs } = require('graceful-fs')
41cb0ef41Sopenharmony_ciconst os = require('os')
51cb0ef41Sopenharmony_ciconst { backOff } = require('exponential-backoff')
61cb0ef41Sopenharmony_ciconst tar = require('tar')
71cb0ef41Sopenharmony_ciconst path = require('path')
81cb0ef41Sopenharmony_ciconst { Transform, promises: { pipeline } } = require('stream')
91cb0ef41Sopenharmony_ciconst crypto = require('crypto')
101cb0ef41Sopenharmony_ciconst log = require('./log')
111cb0ef41Sopenharmony_ciconst semver = require('semver')
121cb0ef41Sopenharmony_ciconst { download } = require('./download')
131cb0ef41Sopenharmony_ciconst processRelease = require('./process-release')
141cb0ef41Sopenharmony_ci
151cb0ef41Sopenharmony_ciconst win = process.platform === 'win32'
161cb0ef41Sopenharmony_ci
171cb0ef41Sopenharmony_ciasync function install (gyp, argv) {
181cb0ef41Sopenharmony_ci  log.stdout()
191cb0ef41Sopenharmony_ci  const release = processRelease(argv, gyp, process.version, process.release)
201cb0ef41Sopenharmony_ci  // Detecting target_arch based on logic from create-cnfig-gyp.js. Used on Windows only.
211cb0ef41Sopenharmony_ci  const arch = win ? (gyp.opts.target_arch || gyp.opts.arch || process.arch || 'ia32') : ''
221cb0ef41Sopenharmony_ci  // Used to prevent downloading tarball if only new node.lib is required on Windows.
231cb0ef41Sopenharmony_ci  let shouldDownloadTarball = true
241cb0ef41Sopenharmony_ci
251cb0ef41Sopenharmony_ci  // Determine which node dev files version we are installing
261cb0ef41Sopenharmony_ci  log.verbose('install', 'input version string %j', release.version)
271cb0ef41Sopenharmony_ci
281cb0ef41Sopenharmony_ci  if (!release.semver) {
291cb0ef41Sopenharmony_ci    // could not parse the version string with semver
301cb0ef41Sopenharmony_ci    throw new Error('Invalid version number: ' + release.version)
311cb0ef41Sopenharmony_ci  }
321cb0ef41Sopenharmony_ci
331cb0ef41Sopenharmony_ci  if (semver.lt(release.version, '0.8.0')) {
341cb0ef41Sopenharmony_ci    throw new Error('Minimum target version is `0.8.0` or greater. Got: ' + release.version)
351cb0ef41Sopenharmony_ci  }
361cb0ef41Sopenharmony_ci
371cb0ef41Sopenharmony_ci  // 0.x.y-pre versions are not published yet and cannot be installed. Bail.
381cb0ef41Sopenharmony_ci  if (release.semver.prerelease[0] === 'pre') {
391cb0ef41Sopenharmony_ci    log.verbose('detected "pre" node version', release.version)
401cb0ef41Sopenharmony_ci    if (!gyp.opts.nodedir) {
411cb0ef41Sopenharmony_ci      throw new Error('"pre" versions of node cannot be installed, use the --nodedir flag instead')
421cb0ef41Sopenharmony_ci    }
431cb0ef41Sopenharmony_ci    log.verbose('--nodedir flag was passed; skipping install', gyp.opts.nodedir)
441cb0ef41Sopenharmony_ci    return
451cb0ef41Sopenharmony_ci  }
461cb0ef41Sopenharmony_ci
471cb0ef41Sopenharmony_ci  // flatten version into String
481cb0ef41Sopenharmony_ci  log.verbose('install', 'installing version: %s', release.versionDir)
491cb0ef41Sopenharmony_ci
501cb0ef41Sopenharmony_ci  // the directory where the dev files will be installed
511cb0ef41Sopenharmony_ci  const devDir = path.resolve(gyp.devDir, release.versionDir)
521cb0ef41Sopenharmony_ci
531cb0ef41Sopenharmony_ci  // If '--ensure' was passed, then don't *always* install the version;
541cb0ef41Sopenharmony_ci  // check if it is already installed, and only install when needed
551cb0ef41Sopenharmony_ci  if (gyp.opts.ensure) {
561cb0ef41Sopenharmony_ci    log.verbose('install', '--ensure was passed, so won\'t reinstall if already installed')
571cb0ef41Sopenharmony_ci    try {
581cb0ef41Sopenharmony_ci      await fs.stat(devDir)
591cb0ef41Sopenharmony_ci    } catch (err) {
601cb0ef41Sopenharmony_ci      if (err.code === 'ENOENT') {
611cb0ef41Sopenharmony_ci        log.verbose('install', 'version not already installed, continuing with install', release.version)
621cb0ef41Sopenharmony_ci        try {
631cb0ef41Sopenharmony_ci          return await go()
641cb0ef41Sopenharmony_ci        } catch (err) {
651cb0ef41Sopenharmony_ci          return rollback(err)
661cb0ef41Sopenharmony_ci        }
671cb0ef41Sopenharmony_ci      } else if (err.code === 'EACCES') {
681cb0ef41Sopenharmony_ci        return eaccesFallback(err)
691cb0ef41Sopenharmony_ci      }
701cb0ef41Sopenharmony_ci      throw err
711cb0ef41Sopenharmony_ci    }
721cb0ef41Sopenharmony_ci    log.verbose('install', 'version is already installed, need to check "installVersion"')
731cb0ef41Sopenharmony_ci    const installVersionFile = path.resolve(devDir, 'installVersion')
741cb0ef41Sopenharmony_ci    let installVersion = 0
751cb0ef41Sopenharmony_ci    try {
761cb0ef41Sopenharmony_ci      const ver = await fs.readFile(installVersionFile, 'ascii')
771cb0ef41Sopenharmony_ci      installVersion = parseInt(ver, 10) || 0
781cb0ef41Sopenharmony_ci    } catch (err) {
791cb0ef41Sopenharmony_ci      if (err.code !== 'ENOENT') {
801cb0ef41Sopenharmony_ci        throw err
811cb0ef41Sopenharmony_ci      }
821cb0ef41Sopenharmony_ci    }
831cb0ef41Sopenharmony_ci    log.verbose('got "installVersion"', installVersion)
841cb0ef41Sopenharmony_ci    log.verbose('needs "installVersion"', gyp.package.installVersion)
851cb0ef41Sopenharmony_ci    if (installVersion < gyp.package.installVersion) {
861cb0ef41Sopenharmony_ci      log.verbose('install', 'version is no good; reinstalling')
871cb0ef41Sopenharmony_ci      try {
881cb0ef41Sopenharmony_ci        return await go()
891cb0ef41Sopenharmony_ci      } catch (err) {
901cb0ef41Sopenharmony_ci        return rollback(err)
911cb0ef41Sopenharmony_ci      }
921cb0ef41Sopenharmony_ci    }
931cb0ef41Sopenharmony_ci    log.verbose('install', 'version is good')
941cb0ef41Sopenharmony_ci    if (win) {
951cb0ef41Sopenharmony_ci      log.verbose('on Windows; need to check node.lib')
961cb0ef41Sopenharmony_ci      const nodeLibPath = path.resolve(devDir, arch, 'node.lib')
971cb0ef41Sopenharmony_ci      try {
981cb0ef41Sopenharmony_ci        await fs.stat(nodeLibPath)
991cb0ef41Sopenharmony_ci      } catch (err) {
1001cb0ef41Sopenharmony_ci        if (err.code === 'ENOENT') {
1011cb0ef41Sopenharmony_ci          log.verbose('install', `version not already installed for ${arch}, continuing with install`, release.version)
1021cb0ef41Sopenharmony_ci          try {
1031cb0ef41Sopenharmony_ci            shouldDownloadTarball = false
1041cb0ef41Sopenharmony_ci            return await go()
1051cb0ef41Sopenharmony_ci          } catch (err) {
1061cb0ef41Sopenharmony_ci            return rollback(err)
1071cb0ef41Sopenharmony_ci          }
1081cb0ef41Sopenharmony_ci        } else if (err.code === 'EACCES') {
1091cb0ef41Sopenharmony_ci          return eaccesFallback(err)
1101cb0ef41Sopenharmony_ci        }
1111cb0ef41Sopenharmony_ci        throw err
1121cb0ef41Sopenharmony_ci      }
1131cb0ef41Sopenharmony_ci    }
1141cb0ef41Sopenharmony_ci  } else {
1151cb0ef41Sopenharmony_ci    try {
1161cb0ef41Sopenharmony_ci      return await go()
1171cb0ef41Sopenharmony_ci    } catch (err) {
1181cb0ef41Sopenharmony_ci      return rollback(err)
1191cb0ef41Sopenharmony_ci    }
1201cb0ef41Sopenharmony_ci  }
1211cb0ef41Sopenharmony_ci
1221cb0ef41Sopenharmony_ci  async function copyDirectory (src, dest) {
1231cb0ef41Sopenharmony_ci    try {
1241cb0ef41Sopenharmony_ci      await fs.stat(src)
1251cb0ef41Sopenharmony_ci    } catch {
1261cb0ef41Sopenharmony_ci      throw new Error(`Missing source directory for copy: ${src}`)
1271cb0ef41Sopenharmony_ci    }
1281cb0ef41Sopenharmony_ci    await fs.mkdir(dest, { recursive: true })
1291cb0ef41Sopenharmony_ci    const entries = await fs.readdir(src, { withFileTypes: true })
1301cb0ef41Sopenharmony_ci    for (const entry of entries) {
1311cb0ef41Sopenharmony_ci      if (entry.isDirectory()) {
1321cb0ef41Sopenharmony_ci        await copyDirectory(path.join(src, entry.name), path.join(dest, entry.name))
1331cb0ef41Sopenharmony_ci      } else if (entry.isFile()) {
1341cb0ef41Sopenharmony_ci        // with parallel installs, copying files may cause file errors on
1351cb0ef41Sopenharmony_ci        // Windows so use an exponential backoff to resolve collisions
1361cb0ef41Sopenharmony_ci        await backOff(async () => {
1371cb0ef41Sopenharmony_ci          try {
1381cb0ef41Sopenharmony_ci            await fs.copyFile(path.join(src, entry.name), path.join(dest, entry.name))
1391cb0ef41Sopenharmony_ci          } catch (err) {
1401cb0ef41Sopenharmony_ci            // if ensure, check if file already exists and that's good enough
1411cb0ef41Sopenharmony_ci            if (gyp.opts.ensure && err.code === 'EBUSY') {
1421cb0ef41Sopenharmony_ci              try {
1431cb0ef41Sopenharmony_ci                await fs.stat(path.join(dest, entry.name))
1441cb0ef41Sopenharmony_ci                return
1451cb0ef41Sopenharmony_ci              } catch {}
1461cb0ef41Sopenharmony_ci            }
1471cb0ef41Sopenharmony_ci            throw err
1481cb0ef41Sopenharmony_ci          }
1491cb0ef41Sopenharmony_ci        })
1501cb0ef41Sopenharmony_ci      } else {
1511cb0ef41Sopenharmony_ci        throw new Error('Unexpected file directory entry type')
1521cb0ef41Sopenharmony_ci      }
1531cb0ef41Sopenharmony_ci    }
1541cb0ef41Sopenharmony_ci  }
1551cb0ef41Sopenharmony_ci
1561cb0ef41Sopenharmony_ci  async function go () {
1571cb0ef41Sopenharmony_ci    log.verbose('ensuring devDir is created', devDir)
1581cb0ef41Sopenharmony_ci
1591cb0ef41Sopenharmony_ci    // first create the dir for the node dev files
1601cb0ef41Sopenharmony_ci    try {
1611cb0ef41Sopenharmony_ci      const created = await fs.mkdir(devDir, { recursive: true })
1621cb0ef41Sopenharmony_ci
1631cb0ef41Sopenharmony_ci      if (created) {
1641cb0ef41Sopenharmony_ci        log.verbose('created devDir', created)
1651cb0ef41Sopenharmony_ci      }
1661cb0ef41Sopenharmony_ci    } catch (err) {
1671cb0ef41Sopenharmony_ci      if (err.code === 'EACCES') {
1681cb0ef41Sopenharmony_ci        return eaccesFallback(err)
1691cb0ef41Sopenharmony_ci      }
1701cb0ef41Sopenharmony_ci
1711cb0ef41Sopenharmony_ci      throw err
1721cb0ef41Sopenharmony_ci    }
1731cb0ef41Sopenharmony_ci
1741cb0ef41Sopenharmony_ci    // now download the node tarball
1751cb0ef41Sopenharmony_ci    const tarPath = gyp.opts.tarball
1761cb0ef41Sopenharmony_ci    let extractErrors = false
1771cb0ef41Sopenharmony_ci    let extractCount = 0
1781cb0ef41Sopenharmony_ci    const contentShasums = {}
1791cb0ef41Sopenharmony_ci    const expectShasums = {}
1801cb0ef41Sopenharmony_ci
1811cb0ef41Sopenharmony_ci    // checks if a file to be extracted from the tarball is valid.
1821cb0ef41Sopenharmony_ci    // only .h header files and the gyp files get extracted
1831cb0ef41Sopenharmony_ci    function isValid (path) {
1841cb0ef41Sopenharmony_ci      const isValid = valid(path)
1851cb0ef41Sopenharmony_ci      if (isValid) {
1861cb0ef41Sopenharmony_ci        log.verbose('extracted file from tarball', path)
1871cb0ef41Sopenharmony_ci        extractCount++
1881cb0ef41Sopenharmony_ci      } else {
1891cb0ef41Sopenharmony_ci        // invalid
1901cb0ef41Sopenharmony_ci        log.silly('ignoring from tarball', path)
1911cb0ef41Sopenharmony_ci      }
1921cb0ef41Sopenharmony_ci      return isValid
1931cb0ef41Sopenharmony_ci    }
1941cb0ef41Sopenharmony_ci
1951cb0ef41Sopenharmony_ci    function onwarn (code, message) {
1961cb0ef41Sopenharmony_ci      extractErrors = true
1971cb0ef41Sopenharmony_ci      log.error('error while extracting tarball', code, message)
1981cb0ef41Sopenharmony_ci    }
1991cb0ef41Sopenharmony_ci
2001cb0ef41Sopenharmony_ci    // download the tarball and extract!
2011cb0ef41Sopenharmony_ci    // Ommited on Windows if only new node.lib is required
2021cb0ef41Sopenharmony_ci
2031cb0ef41Sopenharmony_ci    // on Windows there can be file errors from tar if parallel installs
2041cb0ef41Sopenharmony_ci    // are happening (not uncommon with multiple native modules) so
2051cb0ef41Sopenharmony_ci    // extract the tarball to a temp directory first and then copy over
2061cb0ef41Sopenharmony_ci    const tarExtractDir = win ? await fs.mkdtemp(path.join(os.tmpdir(), 'node-gyp-tmp-')) : devDir
2071cb0ef41Sopenharmony_ci
2081cb0ef41Sopenharmony_ci    try {
2091cb0ef41Sopenharmony_ci      if (shouldDownloadTarball) {
2101cb0ef41Sopenharmony_ci        if (tarPath) {
2111cb0ef41Sopenharmony_ci          await tar.extract({
2121cb0ef41Sopenharmony_ci            file: tarPath,
2131cb0ef41Sopenharmony_ci            strip: 1,
2141cb0ef41Sopenharmony_ci            filter: isValid,
2151cb0ef41Sopenharmony_ci            onwarn,
2161cb0ef41Sopenharmony_ci            cwd: tarExtractDir
2171cb0ef41Sopenharmony_ci          })
2181cb0ef41Sopenharmony_ci        } else {
2191cb0ef41Sopenharmony_ci          try {
2201cb0ef41Sopenharmony_ci            const res = await download(gyp, release.tarballUrl)
2211cb0ef41Sopenharmony_ci
2221cb0ef41Sopenharmony_ci            if (res.status !== 200) {
2231cb0ef41Sopenharmony_ci              throw new Error(`${res.status} response downloading ${release.tarballUrl}`)
2241cb0ef41Sopenharmony_ci            }
2251cb0ef41Sopenharmony_ci
2261cb0ef41Sopenharmony_ci            await pipeline(
2271cb0ef41Sopenharmony_ci              res.body,
2281cb0ef41Sopenharmony_ci              // content checksum
2291cb0ef41Sopenharmony_ci              new ShaSum((_, checksum) => {
2301cb0ef41Sopenharmony_ci                const filename = path.basename(release.tarballUrl).trim()
2311cb0ef41Sopenharmony_ci                contentShasums[filename] = checksum
2321cb0ef41Sopenharmony_ci                log.verbose('content checksum', filename, checksum)
2331cb0ef41Sopenharmony_ci              }),
2341cb0ef41Sopenharmony_ci              tar.extract({
2351cb0ef41Sopenharmony_ci                strip: 1,
2361cb0ef41Sopenharmony_ci                cwd: tarExtractDir,
2371cb0ef41Sopenharmony_ci                filter: isValid,
2381cb0ef41Sopenharmony_ci                onwarn
2391cb0ef41Sopenharmony_ci              })
2401cb0ef41Sopenharmony_ci            )
2411cb0ef41Sopenharmony_ci          } catch (err) {
2421cb0ef41Sopenharmony_ci          // something went wrong downloading the tarball?
2431cb0ef41Sopenharmony_ci            if (err.code === 'ENOTFOUND') {
2441cb0ef41Sopenharmony_ci              throw new Error('This is most likely not a problem with node-gyp or the package itself and\n' +
2451cb0ef41Sopenharmony_ci              'is related to network connectivity. In most cases you are behind a proxy or have bad \n' +
2461cb0ef41Sopenharmony_ci              'network settings.')
2471cb0ef41Sopenharmony_ci            }
2481cb0ef41Sopenharmony_ci            throw err
2491cb0ef41Sopenharmony_ci          }
2501cb0ef41Sopenharmony_ci        }
2511cb0ef41Sopenharmony_ci
2521cb0ef41Sopenharmony_ci        // invoked after the tarball has finished being extracted
2531cb0ef41Sopenharmony_ci        if (extractErrors || extractCount === 0) {
2541cb0ef41Sopenharmony_ci          throw new Error('There was a fatal problem while downloading/extracting the tarball')
2551cb0ef41Sopenharmony_ci        }
2561cb0ef41Sopenharmony_ci
2571cb0ef41Sopenharmony_ci        log.verbose('tarball', 'done parsing tarball')
2581cb0ef41Sopenharmony_ci      }
2591cb0ef41Sopenharmony_ci
2601cb0ef41Sopenharmony_ci      const installVersionPath = path.resolve(tarExtractDir, 'installVersion')
2611cb0ef41Sopenharmony_ci      await Promise.all([
2621cb0ef41Sopenharmony_ci      // need to download node.lib
2631cb0ef41Sopenharmony_ci        ...(win ? [downloadNodeLib()] : []),
2641cb0ef41Sopenharmony_ci        // write the "installVersion" file
2651cb0ef41Sopenharmony_ci        fs.writeFile(installVersionPath, gyp.package.installVersion + '\n'),
2661cb0ef41Sopenharmony_ci        // Only download SHASUMS.txt if we downloaded something in need of SHA verification
2671cb0ef41Sopenharmony_ci        ...(!tarPath || win ? [downloadShasums()] : [])
2681cb0ef41Sopenharmony_ci      ])
2691cb0ef41Sopenharmony_ci
2701cb0ef41Sopenharmony_ci      log.verbose('download contents checksum', JSON.stringify(contentShasums))
2711cb0ef41Sopenharmony_ci      // check content shasums
2721cb0ef41Sopenharmony_ci      for (const k in contentShasums) {
2731cb0ef41Sopenharmony_ci        log.verbose('validating download checksum for ' + k, '(%s == %s)', contentShasums[k], expectShasums[k])
2741cb0ef41Sopenharmony_ci        if (contentShasums[k] !== expectShasums[k]) {
2751cb0ef41Sopenharmony_ci          throw new Error(k + ' local checksum ' + contentShasums[k] + ' not match remote ' + expectShasums[k])
2761cb0ef41Sopenharmony_ci        }
2771cb0ef41Sopenharmony_ci      }
2781cb0ef41Sopenharmony_ci
2791cb0ef41Sopenharmony_ci      // copy over the files from the temp tarball extract directory to devDir
2801cb0ef41Sopenharmony_ci      if (tarExtractDir !== devDir) {
2811cb0ef41Sopenharmony_ci        await copyDirectory(tarExtractDir, devDir)
2821cb0ef41Sopenharmony_ci      }
2831cb0ef41Sopenharmony_ci    } finally {
2841cb0ef41Sopenharmony_ci      if (tarExtractDir !== devDir) {
2851cb0ef41Sopenharmony_ci        try {
2861cb0ef41Sopenharmony_ci          // try to cleanup temp dir
2871cb0ef41Sopenharmony_ci          await fs.rm(tarExtractDir, { recursive: true })
2881cb0ef41Sopenharmony_ci        } catch {
2891cb0ef41Sopenharmony_ci          log.warn('failed to clean up temp tarball extract directory')
2901cb0ef41Sopenharmony_ci        }
2911cb0ef41Sopenharmony_ci      }
2921cb0ef41Sopenharmony_ci    }
2931cb0ef41Sopenharmony_ci
2941cb0ef41Sopenharmony_ci    async function downloadShasums () {
2951cb0ef41Sopenharmony_ci      log.verbose('check download content checksum, need to download `SHASUMS256.txt`...')
2961cb0ef41Sopenharmony_ci      log.verbose('checksum url', release.shasumsUrl)
2971cb0ef41Sopenharmony_ci
2981cb0ef41Sopenharmony_ci      const res = await download(gyp, release.shasumsUrl)
2991cb0ef41Sopenharmony_ci
3001cb0ef41Sopenharmony_ci      if (res.status !== 200) {
3011cb0ef41Sopenharmony_ci        throw new Error(`${res.status}  status code downloading checksum`)
3021cb0ef41Sopenharmony_ci      }
3031cb0ef41Sopenharmony_ci
3041cb0ef41Sopenharmony_ci      for (const line of (await res.text()).trim().split('\n')) {
3051cb0ef41Sopenharmony_ci        const items = line.trim().split(/\s+/)
3061cb0ef41Sopenharmony_ci        if (items.length !== 2) {
3071cb0ef41Sopenharmony_ci          return
3081cb0ef41Sopenharmony_ci        }
3091cb0ef41Sopenharmony_ci
3101cb0ef41Sopenharmony_ci        // 0035d18e2dcf9aad669b1c7c07319e17abfe3762  ./node-v0.11.4.tar.gz
3111cb0ef41Sopenharmony_ci        const name = items[1].replace(/^\.\//, '')
3121cb0ef41Sopenharmony_ci        expectShasums[name] = items[0]
3131cb0ef41Sopenharmony_ci      }
3141cb0ef41Sopenharmony_ci
3151cb0ef41Sopenharmony_ci      log.verbose('checksum data', JSON.stringify(expectShasums))
3161cb0ef41Sopenharmony_ci    }
3171cb0ef41Sopenharmony_ci
3181cb0ef41Sopenharmony_ci    async function downloadNodeLib () {
3191cb0ef41Sopenharmony_ci      log.verbose('on Windows; need to download `' + release.name + '.lib`...')
3201cb0ef41Sopenharmony_ci      const dir = path.resolve(tarExtractDir, arch)
3211cb0ef41Sopenharmony_ci      const targetLibPath = path.resolve(dir, release.name + '.lib')
3221cb0ef41Sopenharmony_ci      const { libUrl, libPath } = release[arch]
3231cb0ef41Sopenharmony_ci      const name = `${arch} ${release.name}.lib`
3241cb0ef41Sopenharmony_ci      log.verbose(name, 'dir', dir)
3251cb0ef41Sopenharmony_ci      log.verbose(name, 'url', libUrl)
3261cb0ef41Sopenharmony_ci
3271cb0ef41Sopenharmony_ci      await fs.mkdir(dir, { recursive: true })
3281cb0ef41Sopenharmony_ci      log.verbose('streaming', name, 'to:', targetLibPath)
3291cb0ef41Sopenharmony_ci
3301cb0ef41Sopenharmony_ci      const res = await download(gyp, libUrl)
3311cb0ef41Sopenharmony_ci
3321cb0ef41Sopenharmony_ci      // Since only required node.lib is downloaded throw error if it is not fetched
3331cb0ef41Sopenharmony_ci      if (res.status !== 200) {
3341cb0ef41Sopenharmony_ci        throw new Error(`${res.status} status code downloading ${name}`)
3351cb0ef41Sopenharmony_ci      }
3361cb0ef41Sopenharmony_ci
3371cb0ef41Sopenharmony_ci      return pipeline(
3381cb0ef41Sopenharmony_ci        res.body,
3391cb0ef41Sopenharmony_ci        new ShaSum((_, checksum) => {
3401cb0ef41Sopenharmony_ci          contentShasums[libPath] = checksum
3411cb0ef41Sopenharmony_ci          log.verbose('content checksum', libPath, checksum)
3421cb0ef41Sopenharmony_ci        }),
3431cb0ef41Sopenharmony_ci        createWriteStream(targetLibPath)
3441cb0ef41Sopenharmony_ci      )
3451cb0ef41Sopenharmony_ci    } // downloadNodeLib()
3461cb0ef41Sopenharmony_ci  } // go()
3471cb0ef41Sopenharmony_ci
3481cb0ef41Sopenharmony_ci  /**
3491cb0ef41Sopenharmony_ci   * Checks if a given filename is "valid" for this installation.
3501cb0ef41Sopenharmony_ci   */
3511cb0ef41Sopenharmony_ci
3521cb0ef41Sopenharmony_ci  function valid (file) {
3531cb0ef41Sopenharmony_ci    // header files
3541cb0ef41Sopenharmony_ci    const extname = path.extname(file)
3551cb0ef41Sopenharmony_ci    return extname === '.h' || extname === '.gypi'
3561cb0ef41Sopenharmony_ci  }
3571cb0ef41Sopenharmony_ci
3581cb0ef41Sopenharmony_ci  async function rollback (err) {
3591cb0ef41Sopenharmony_ci    log.warn('install', 'got an error, rolling back install')
3601cb0ef41Sopenharmony_ci    // roll-back the install if anything went wrong
3611cb0ef41Sopenharmony_ci    await gyp.commands.remove([release.versionDir])
3621cb0ef41Sopenharmony_ci    throw err
3631cb0ef41Sopenharmony_ci  }
3641cb0ef41Sopenharmony_ci
3651cb0ef41Sopenharmony_ci  /**
3661cb0ef41Sopenharmony_ci   * The EACCES fallback is a workaround for npm's `sudo` behavior, where
3671cb0ef41Sopenharmony_ci   * it drops the permissions before invoking any child processes (like
3681cb0ef41Sopenharmony_ci   * node-gyp). So what happens is the "nobody" user doesn't have
3691cb0ef41Sopenharmony_ci   * permission to create the dev dir. As a fallback, make the tmpdir() be
3701cb0ef41Sopenharmony_ci   * the dev dir for this installation. This is not ideal, but at least
3711cb0ef41Sopenharmony_ci   * the compilation will succeed...
3721cb0ef41Sopenharmony_ci   */
3731cb0ef41Sopenharmony_ci
3741cb0ef41Sopenharmony_ci  async function eaccesFallback (err) {
3751cb0ef41Sopenharmony_ci    const noretry = '--node_gyp_internal_noretry'
3761cb0ef41Sopenharmony_ci    if (argv.indexOf(noretry) !== -1) {
3771cb0ef41Sopenharmony_ci      throw err
3781cb0ef41Sopenharmony_ci    }
3791cb0ef41Sopenharmony_ci    const tmpdir = os.tmpdir()
3801cb0ef41Sopenharmony_ci    gyp.devDir = path.resolve(tmpdir, '.node-gyp')
3811cb0ef41Sopenharmony_ci    let userString = ''
3821cb0ef41Sopenharmony_ci    try {
3831cb0ef41Sopenharmony_ci      // os.userInfo can fail on some systems, it's not critical here
3841cb0ef41Sopenharmony_ci      userString = ` ("${os.userInfo().username}")`
3851cb0ef41Sopenharmony_ci    } catch (e) {}
3861cb0ef41Sopenharmony_ci    log.warn('EACCES', 'current user%s does not have permission to access the dev dir "%s"', userString, devDir)
3871cb0ef41Sopenharmony_ci    log.warn('EACCES', 'attempting to reinstall using temporary dev dir "%s"', gyp.devDir)
3881cb0ef41Sopenharmony_ci    if (process.cwd() === tmpdir) {
3891cb0ef41Sopenharmony_ci      log.verbose('tmpdir == cwd', 'automatically will remove dev files after to save disk space')
3901cb0ef41Sopenharmony_ci      gyp.todo.push({ name: 'remove', args: argv })
3911cb0ef41Sopenharmony_ci    }
3921cb0ef41Sopenharmony_ci    return gyp.commands.install([noretry].concat(argv))
3931cb0ef41Sopenharmony_ci  }
3941cb0ef41Sopenharmony_ci}
3951cb0ef41Sopenharmony_ci
3961cb0ef41Sopenharmony_ciclass ShaSum extends Transform {
3971cb0ef41Sopenharmony_ci  constructor (callback) {
3981cb0ef41Sopenharmony_ci    super()
3991cb0ef41Sopenharmony_ci    this._callback = callback
4001cb0ef41Sopenharmony_ci    this._digester = crypto.createHash('sha256')
4011cb0ef41Sopenharmony_ci  }
4021cb0ef41Sopenharmony_ci
4031cb0ef41Sopenharmony_ci  _transform (chunk, _, callback) {
4041cb0ef41Sopenharmony_ci    this._digester.update(chunk)
4051cb0ef41Sopenharmony_ci    callback(null, chunk)
4061cb0ef41Sopenharmony_ci  }
4071cb0ef41Sopenharmony_ci
4081cb0ef41Sopenharmony_ci  _flush (callback) {
4091cb0ef41Sopenharmony_ci    this._callback(null, this._digester.digest('hex'))
4101cb0ef41Sopenharmony_ci    callback()
4111cb0ef41Sopenharmony_ci  }
4121cb0ef41Sopenharmony_ci}
4131cb0ef41Sopenharmony_ci
4141cb0ef41Sopenharmony_cimodule.exports = install
4151cb0ef41Sopenharmony_cimodule.exports.usage = 'Install node development files for the specified node version.'
416