UNPKG

install-module-linked

Version:
50 lines (49 loc) 2.34 kB
var _process_env_OSTYPE; import fs from 'fs'; import { safeRm } from 'fs-remove-compat'; import mkdirp from 'mkdirp-classic'; import path from 'path'; import Queue from 'queue-cb'; import tempSuffix from 'temp-suffix'; import { DEFAULT_CACHE_PATH } from '../constants.js'; import cache from '../lib/cache.js'; import parseInstallString from '../lib/parseInstallString.js'; const isWindows = process.platform === 'win32' || /^(msys|cygwin)$/.test((_process_env_OSTYPE = process.env.OSTYPE) !== null && _process_env_OSTYPE !== void 0 ? _process_env_OSTYPE : ''); const symlinkType = isWindows ? 'junction' : 'dir'; export default function installModule(installString, nodeModulesPath, options, callback) { const cachePath = options.cachePath || DEFAULT_CACHE_PATH; const { name } = parseInstallString(installString); const dest = path.join(nodeModulesPath, ...name.split('/')); fs.stat(dest, (err)=>{ if (!err) return callback(undefined, dest); // already installed cache(installString, cachePath, (err, cachedAt)=>{ if (err) { console.log(`Could not install: ${installString}. Message: ${err.message}`); return callback(err); } // Use temp symlink + atomic rename to avoid cross-process race conditions const tempDest = tempSuffix(dest); const queue = new Queue(1); queue.defer((cb)=>mkdirp(path.dirname(dest), (err)=>cb(err))); queue.defer((cb)=>fs.symlink(cachedAt, tempDest, symlinkType, (err)=>cb(err))); queue.defer((cb)=>{ fs.rename(tempDest, dest, (err)=>{ var _err_code; // If rename fails because dest exists, another process won - that's ok if (err && [ 'EEXIST', 'ENOTEMPTY', 'EPERM' ].indexOf((_err_code = err.code) !== null && _err_code !== void 0 ? _err_code : '') >= 0) { safeRm(tempDest, ()=>cb()); return; } cb(err); }); }); queue.await((err)=>{ err ? safeRm(tempDest, ()=>callback(err)) : callback(undefined, dest); }); }); }); }