install-module-linked
Version:
Installs and symlinks a module into node_modules
180 lines • 8.79 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return ensureCached;
}
});
var _fs = /*#__PURE__*/ _interop_require_default(require("fs"));
var _fsremovecompat = require("fs-remove-compat");
var _lockfile = /*#__PURE__*/ _interop_require_default(require("lockfile"));
var _mkdirpclassic = /*#__PURE__*/ _interop_require_default(require("mkdirp-classic"));
var _path = /*#__PURE__*/ _interop_require_default(require("path"));
var _queuecb = /*#__PURE__*/ _interop_require_default(require("queue-cb"));
var _tempsuffix = /*#__PURE__*/ _interop_require_default(require("temp-suffix"));
var _getSpecifierts = /*#__PURE__*/ _interop_require_default(require("./getSpecifier.js"));
var _installts = /*#__PURE__*/ _interop_require_default(require("./install.js"));
var _parseInstallStringts = /*#__PURE__*/ _interop_require_default(require("./parseInstallString.js"));
var _renameWithFallbackts = /*#__PURE__*/ _interop_require_default(require("./renameWithFallback.js"));
function _array_like_to_array(arr, len) {
if (len == null || len > arr.length) len = arr.length;
for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
return arr2;
}
function _array_without_holes(arr) {
if (Array.isArray(arr)) return _array_like_to_array(arr);
}
function _define_property(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
} else {
obj[key] = value;
}
return obj;
}
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
function _iterable_to_array(iter) {
if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
}
function _non_iterable_spread() {
throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
function _object_spread(target) {
for(var i = 1; i < arguments.length; i++){
var source = arguments[i] != null ? arguments[i] : {};
var ownKeys = Object.keys(source);
if (typeof Object.getOwnPropertySymbols === "function") {
ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
return Object.getOwnPropertyDescriptor(source, sym).enumerable;
}));
}
ownKeys.forEach(function(key) {
_define_property(target, key, source[key]);
});
}
return target;
}
function _to_consumable_array(arr) {
return _array_without_holes(arr) || _iterable_to_array(arr) || _unsupported_iterable_to_array(arr) || _non_iterable_spread();
}
function _unsupported_iterable_to_array(o, minLen) {
if (!o) return;
if (typeof o === "string") return _array_like_to_array(o, minLen);
var n = Object.prototype.toString.call(o).slice(8, -1);
if (n === "Object" && o.constructor) n = o.constructor.name;
if (n === "Map" || n === "Set") return Array.from(n);
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
}
var LOCK_OPTIONS = {
wait: 600000,
pollPeriod: 100,
stale: 660000,
retries: 3
};
function ensureCached(installString, cachePath, callback) {
(0, _getSpecifierts.default)(installString, function(err, specifier) {
var doLockedInstall = function doLockedInstall() {
// Ensure lock file's parent directory exists (handles scoped packages like @scope/pkg)
(0, _mkdirpclassic.default)(_path.default.dirname(lockPath), function(mkdirErr) {
if (mkdirErr) return callback(mkdirErr);
var startTime = Date.now();
// Retry loop for Windows EPERM - treat it like EEXIST (lock held by another process)
function tryLock(cb) {
_lockfile.default.lock(lockPath, _object_spread({}, LOCK_OPTIONS), function(lockErr) {
if (lockErr && lockErr.code === 'EPERM' && Date.now() - startTime < LOCK_OPTIONS.wait) {
setTimeout(function() {
return tryLock(cb);
}, LOCK_OPTIONS.pollPeriod);
return;
}
cb(lockErr);
});
}
tryLock(function(lockErr) {
var done = // Single exit point - always unlock before calling back
function done(err) {
_lockfile.default.unlock(lockPath, function() {
return callback(err, err ? undefined : cachedAt);
});
};
if (lockErr) return callback(lockErr);
// Re-check cache (another process may have completed while we waited for lock)
_fs.default.stat(readyPath, function(readyErr) {
if (!readyErr) return done(); // Cache appeared while we waited
// Clean up any incomplete cache before installing
(0, _fsremovecompat.safeRm)(cachedAt, function(rmErr) {
if (rmErr) return done(rmErr);
doInstall(done);
});
});
});
});
};
var doInstall = function doInstall(cb) {
var _path1;
var tmp = "".concat(cachedAt, "-").concat((0, _tempsuffix.default)());
var tmpModulePath = (_path1 = _path.default).join.apply(_path1, [
tmp,
'node_modules'
].concat(_to_consumable_array(name.split('/'))));
var queue = new _queuecb.default(1);
queue.defer(function(cb) {
return (0, _mkdirpclassic.default)(tmp, function(err) {
return cb(err);
});
});
queue.defer(function(cb) {
return _fs.default.writeFile(_path.default.join(tmp, 'package.json'), '{}', 'utf8', function(err) {
return cb(err);
});
});
queue.defer(_installts.default.bind(null, specifier, tmp));
queue.defer(function(qcb) {
// Verify npm actually created the package directory - npm may silently skip
// installation (exit 0) when platform doesn't match (os/cpu/libc fields)
_fs.default.stat(tmpModulePath, function(statErr) {
if (statErr) return qcb(new Error("Package directory not created by npm. This may happen when the package has platform restrictions (os/cpu/libc) that don't match the current system: ".concat(tmpModulePath)));
qcb();
});
});
queue.defer(_renameWithFallbackts.default.bind(null, tmpModulePath, cachedAt));
queue.defer(_renameWithFallbackts.default.bind(null, _path.default.join(tmp, 'node_modules'), _path.default.join(cachedAt, 'node_modules')));
// Write .ready marker after both renames succeed
queue.defer(function(cb) {
return _fs.default.writeFile(readyPath, '', 'utf8', function(err) {
return cb(err);
});
});
queue.await(function(queueErr) {
// Clean up temp directory whether installed or not
(0, _fsremovecompat.safeRm)(tmp, function() {
return cb(queueErr);
});
});
};
if (err) return callback(err);
var cachedAt = _path.default.join(cachePath, specifier);
var lockPath = "".concat(cachedAt, ".lock");
var readyPath = _path.default.join(cachedAt, '.ready');
var name = (0, _parseInstallStringts.default)(installString).name;
// Check if already cached AND complete (fast path, no lock needed)
_fs.default.stat(readyPath, function(readyErr) {
if (!readyErr) return callback(undefined, cachedAt); // Valid cache
// Not cached or incomplete - acquire lock and install
doLockedInstall();
});
});
}
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (var key in exports) { exports.default[key] = exports[key]; } } catch (_) {}; module.exports = exports.default; }