@zkochan/pnpm
Version:
Fast, disk space efficient package manager
135 lines • 6.06 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 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