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