UNPKG

@zkochan/pnpm

Version:

Fast, disk space efficient package manager

135 lines 6.06 kB
"use strict"; 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 Diable = require("diable"); const getPort = require("get-port"); const isWindows = require("is-windows"); const mkdirp = require("mkdirp-promise"); const fs = require("mz/fs"); const path = require("path"); const onExit = require("signal-exit"); const createStore_1 = require("../../createStore"); const pnpmPkgJson_1 = require("../../pnpmPkgJson"); const serverConnectionInfoDir_1 = require("../../serverConnectionInfoDir"); exports.default = (opts) => __awaiter(this, void 0, void 0, function* () { if (opts.protocol === 'ipc' && opts.port) { throw new Error('Port cannot be selected when server communicates via IPC'); } if (opts.background && !Diable.isDaemon()) { Diable(); } const pathOfStore = yield store_path_1.default(opts.prefix, opts.store); const connectionInfoDir = serverConnectionInfoDir_1.default(pathOfStore); const serverJsonPath = path.join(connectionInfoDir, 'server.json'); yield mkdirp(connectionInfoDir); // Open server.json with exclusive write access to ensure only one process can successfully // start the server. Note: NFS does not support exclusive writing, but do we really care? // Source: https://github.com/moxystudio/node-proper-lockfile#user-content-comparison let fd; try { fd = yield fs.open(serverJsonPath, 'wx'); } catch (error) { if (error.code !== 'EEXIST') { throw error; } const err = new Error(`Canceling startup of server (pid ${process.pid}) because another process got exclusive access to server.json`); err['code'] = 'ERR_PNPM_SERVER_MANIFEST_LOCKED'; // tslint:disable-line:no-string-literal throw err; } let server = null; onExit(() => { if (server !== null) { // Note that server.close returns a Promise, but we cannot wait for it because we may be // inside the 'exit' even of process. server.close(); } if (fd !== null) { try { fs.closeSync(fd); } catch (error) { logger_1.storeLogger.error(error, `Got error while closing file descriptor of server.json, but the process is already exiting`); } } try { fs.unlinkSync(serverJsonPath); } catch (error) { if (error.code !== 'ENOENT') { logger_1.storeLogger.error(error, `Got error unlinking server.json, but the process is already exiting`); } } }); const store = yield createStore_1.default(Object.assign(opts, { store: pathOfStore, })); const protocol = opts.protocol || opts.port && 'tcp' || 'auto'; const serverOptions = yield getServerOptions(connectionInfoDir, { protocol, port: opts.port }); const connectionOptions = { remotePrefix: serverOptions.path ? `http://unix:${serverOptions.path}:` : `http://${serverOptions.hostname}:${serverOptions.port}`, }; server = server_1.createServer(store.ctrl, Object.assign({}, serverOptions, { ignoreStopRequests: opts.ignoreStopRequests, ignoreUploadRequests: opts.ignoreUploadRequests })); // Make sure to populate server.json after the server has started, so clients know that the server is // listening if a server.json with valid JSON content exists. const serverJson = { connectionOptions, pid: process.pid, pnpmVersion: pnpmPkgJson_1.default.version, }; const serverJsonStr = JSON.stringify(serverJson, undefined, 2); // undefined and 2 are for formatting. const serverJsonBuffer = Buffer.from(serverJsonStr, 'utf8'); // fs.write on NodeJS 4 requires the parameters offset and length to be set: // https://nodejs.org/docs/latest-v4.x/api/fs.html#fs_fs_write_fd_buffer_offset_length_position_callback yield fs.write(fd, serverJsonBuffer, 0, serverJsonBuffer.byteLength); const fdForClose = fd; // Set fd to null so we only attempt to close it once. fd = null; yield fs.close(fdForClose); }); function getServerOptions(connectionInfoDir, opts) { return __awaiter(this, void 0, void 0, function* () { switch (opts.protocol) { case 'tcp': return yield getTcpOptions(); case 'ipc': if (isWindows()) { throw new Error('IPC protocol is not supported on Windows currently'); } return getIpcOptions(); case 'auto': if (isWindows()) { return yield getTcpOptions(); } return getIpcOptions(); default: throw new Error(`Protocol ${opts.protocol} is not supported`); } function getTcpOptions() { return __awaiter(this, void 0, void 0, function* () { return { hostname: 'localhost', port: opts.port || (yield getPort({ port: 5813 })), }; }); } function getIpcOptions() { return { path: path.join(connectionInfoDir, 'socket'), }; } }); } //# sourceMappingURL=start.js.map