11cb0ef41Sopenharmony_ciconst { resolve, dirname } = require('path')
21cb0ef41Sopenharmony_ciconst { lstat } = require('fs/promises')
31cb0ef41Sopenharmony_ciconst throwNonEnoent = er => {
41cb0ef41Sopenharmony_ci  if (er.code !== 'ENOENT') {
51cb0ef41Sopenharmony_ci    throw er
61cb0ef41Sopenharmony_ci  }
71cb0ef41Sopenharmony_ci}
81cb0ef41Sopenharmony_ci
91cb0ef41Sopenharmony_ciconst cmdShim = require('cmd-shim')
101cb0ef41Sopenharmony_ciconst readCmdShim = require('read-cmd-shim')
111cb0ef41Sopenharmony_ci
121cb0ef41Sopenharmony_ciconst fixBin = require('./fix-bin.js')
131cb0ef41Sopenharmony_ci
141cb0ef41Sopenharmony_ci// even in --force mode, we never create a shim over a shim we've
151cb0ef41Sopenharmony_ci// already created.  you can have multiple packages in a tree trying
161cb0ef41Sopenharmony_ci// to contend for the same bin, which creates a race condition and
171cb0ef41Sopenharmony_ci// nondeterminism.
181cb0ef41Sopenharmony_ciconst seen = new Set()
191cb0ef41Sopenharmony_ci
201cb0ef41Sopenharmony_ciconst failEEXIST = ({ path, to, from }) =>
211cb0ef41Sopenharmony_ci  Promise.reject(Object.assign(new Error('EEXIST: file already exists'), {
221cb0ef41Sopenharmony_ci    path: to,
231cb0ef41Sopenharmony_ci    dest: from,
241cb0ef41Sopenharmony_ci    code: 'EEXIST',
251cb0ef41Sopenharmony_ci  }))
261cb0ef41Sopenharmony_ci
271cb0ef41Sopenharmony_ciconst handleReadCmdShimError = ({ er, from, to }) =>
281cb0ef41Sopenharmony_ci  er.code === 'ENOENT' ? null
291cb0ef41Sopenharmony_ci  : er.code === 'ENOTASHIM' ? failEEXIST({ from, to })
301cb0ef41Sopenharmony_ci  : Promise.reject(er)
311cb0ef41Sopenharmony_ci
321cb0ef41Sopenharmony_ciconst SKIP = Symbol('skip - missing or already installed')
331cb0ef41Sopenharmony_ciconst shimBin = ({ path, to, from, absFrom, force }) => {
341cb0ef41Sopenharmony_ci  const shims = [
351cb0ef41Sopenharmony_ci    to,
361cb0ef41Sopenharmony_ci    to + '.cmd',
371cb0ef41Sopenharmony_ci    to + '.ps1',
381cb0ef41Sopenharmony_ci  ]
391cb0ef41Sopenharmony_ci
401cb0ef41Sopenharmony_ci  for (const shim of shims) {
411cb0ef41Sopenharmony_ci    if (seen.has(shim)) {
421cb0ef41Sopenharmony_ci      return true
431cb0ef41Sopenharmony_ci    }
441cb0ef41Sopenharmony_ci    seen.add(shim)
451cb0ef41Sopenharmony_ci  }
461cb0ef41Sopenharmony_ci
471cb0ef41Sopenharmony_ci  return Promise.all([
481cb0ef41Sopenharmony_ci    ...shims,
491cb0ef41Sopenharmony_ci    absFrom,
501cb0ef41Sopenharmony_ci  ].map(f => lstat(f).catch(throwNonEnoent))).then((stats) => {
511cb0ef41Sopenharmony_ci    const [, , , stFrom] = stats
521cb0ef41Sopenharmony_ci    if (!stFrom) {
531cb0ef41Sopenharmony_ci      return SKIP
541cb0ef41Sopenharmony_ci    }
551cb0ef41Sopenharmony_ci
561cb0ef41Sopenharmony_ci    if (force) {
571cb0ef41Sopenharmony_ci      return false
581cb0ef41Sopenharmony_ci    }
591cb0ef41Sopenharmony_ci
601cb0ef41Sopenharmony_ci    return Promise.all(shims.map((s, i) => [s, stats[i]]).map(([s, st]) => {
611cb0ef41Sopenharmony_ci      if (!st) {
621cb0ef41Sopenharmony_ci        return false
631cb0ef41Sopenharmony_ci      }
641cb0ef41Sopenharmony_ci      return readCmdShim(s)
651cb0ef41Sopenharmony_ci        .then(target => {
661cb0ef41Sopenharmony_ci          target = resolve(dirname(to), target)
671cb0ef41Sopenharmony_ci          if (target.indexOf(resolve(path)) !== 0) {
681cb0ef41Sopenharmony_ci            return failEEXIST({ from, to, path })
691cb0ef41Sopenharmony_ci          }
701cb0ef41Sopenharmony_ci          return false
711cb0ef41Sopenharmony_ci        }, er => handleReadCmdShimError({ er, from, to }))
721cb0ef41Sopenharmony_ci    }))
731cb0ef41Sopenharmony_ci  })
741cb0ef41Sopenharmony_ci    .then(skip => skip !== SKIP && doShim(absFrom, to))
751cb0ef41Sopenharmony_ci}
761cb0ef41Sopenharmony_ci
771cb0ef41Sopenharmony_ciconst doShim = (absFrom, to) =>
781cb0ef41Sopenharmony_ci  cmdShim(absFrom, to).then(() => fixBin(absFrom))
791cb0ef41Sopenharmony_ci
801cb0ef41Sopenharmony_ciconst resetSeen = () => {
811cb0ef41Sopenharmony_ci  for (const p of seen) {
821cb0ef41Sopenharmony_ci    seen.delete(p)
831cb0ef41Sopenharmony_ci  }
841cb0ef41Sopenharmony_ci}
851cb0ef41Sopenharmony_ci
861cb0ef41Sopenharmony_cimodule.exports = Object.assign(shimBin, { resetSeen })
87