@zkochan/pnpm
Version:
Fast, disk space efficient package manager
134 lines • 6.08 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const logger_1 = require("@pnpm/logger");
const server_1 = require("@pnpm/server");
const store_path_1 = require("@pnpm/store-path");
const delay_1 = require("delay");
const fs = require("mz/fs");
const path = require("path");
const createStore_1 = require("./createStore");
const pnpmPkgJson_1 = require("./pnpmPkgJson");
const runServerInBackground_1 = require("./runServerInBackground");
const serverConnectionInfoDir_1 = require("./serverConnectionInfoDir");
function cached(storeControllerCache, opts) {
return __awaiter(this, void 0, void 0, function* () {
const sp = yield store_path_1.default(opts.prefix, opts.store);
if (!storeControllerCache.has(sp)) {
storeControllerCache.set(sp, createStoreController(opts));
}
return yield storeControllerCache.get(sp);
});
}
exports.cached = cached;
function createStoreController(opts) {
return __awaiter(this, void 0, void 0, function* () {
const store = yield store_path_1.default(opts.prefix, opts.store);
const connectionInfoDir = serverConnectionInfoDir_1.default(store);
const serverJsonPath = path.join(connectionInfoDir, 'server.json');
let serverJson = yield tryLoadServerJson({ serverJsonPath, shouldRetryOnNoent: false });
if (serverJson !== null) {
if (serverJson.pnpmVersion !== pnpmPkgJson_1.default.version) {
logger_1.default.warn({
message: `The store server runs on pnpm v${serverJson.pnpmVersion}. It is recommended to connect with the same version (current is v${pnpmPkgJson_1.default.version})`,
prefix: opts.prefix,
});
}
logger_1.default.info({
message: 'A store server is running. All store manipulations are delegated to it.',
prefix: opts.prefix,
});
return {
ctrl: yield server_1.connectStoreController(serverJson.connectionOptions),
path: store,
};
}
if (opts.useRunningStoreServer) {
const err = new Error('No store server is running.');
err['code'] = 'ERR_PNPM_NO_STORE_SERVER'; // tslint:disable-line:no-string-literal
throw err;
}
if (opts.useStoreServer) {
runServerInBackground_1.default(store);
serverJson = yield tryLoadServerJson({ serverJsonPath, shouldRetryOnNoent: true });
logger_1.default.info({
message: 'A store server has been started. To stop it, use \`pnpm server stop\`',
prefix: opts.prefix,
});
return {
ctrl: yield server_1.connectStoreController(serverJson.connectionOptions),
path: store,
};
}
return yield createStore_1.default(Object.assign(opts, {
store,
}));
});
}
exports.default = createStoreController;
function tryLoadServerJson(options) {
return __awaiter(this, void 0, void 0, function* () {
let beforeFirstAttempt = true;
const startHRTime = process.hrtime();
while (true) {
if (!beforeFirstAttempt) {
const elapsedHRTime = process.hrtime(startHRTime);
// Time out after 10 seconds of waiting for the server to start, assuming something went wrong.
// E.g. server got a SIGTERM or was otherwise abruptly terminated, server has a bug or a third
// party is interfering.
if (elapsedHRTime[0] >= 10) {
// Delete the file in an attempt to recover from this bad state.
try {
yield fs.unlink(options.serverJsonPath);
}
catch (error) {
if (error.code !== 'ENOENT') {
throw error;
}
// Either the server.json was manually removed or another process already removed it.
}
return null;
}
// Poll for server startup every 200 milliseconds.
yield delay_1.default(200);
}
beforeFirstAttempt = false;
let serverJsonStr;
try {
serverJsonStr = yield fs.readFile(options.serverJsonPath, 'utf8');
}
catch (error) {
if (error.code !== 'ENOENT') {
throw error;
}
if (!options.shouldRetryOnNoent) {
return null;
}
continue;
}
let serverJson;
try {
serverJson = JSON.parse(serverJsonStr);
}
catch (error) {
// Server is starting or server.json was modified by a third party.
// We assume the best case and retry.
continue;
}
if (serverJson === null) {
// Our server should never write null to server.json, even though it is valid json.
throw new Error('server.json was modified by a third party');
}
return serverJson;
}
});
}
exports.tryLoadServerJson = tryLoadServerJson;
//# sourceMappingURL=createStoreController.js.map