UNPKG

10.1 kBJavaScriptView Raw
1import * as path from 'path';
2import { Command } from 'commander';
3import * as fs from 'fs';
4import invariant from 'invariant';
5import loudRejection from 'loud-rejection';
6import semver from 'semver';
7import { ConsoleReporter, JSONReporter } from './reporters/index.js';
8import { commands } from './commands/index.js';
9import * as helpCommand from './commands/help.js';
10import * as constants from './constants.js';
11import { MessageError } from '@pika/types';
12import Config from './config.js';
13import handleSignals from './util/signal-handler.js';
14import { boolify, boolifyWithDefault } from './util/conversion.js';
15import map from './util/map.js';
16import stripBOM from 'strip-bom';
17import uri2path from 'file-uri-to-path';
18const commander = new Command();
19// @ts-ignore
20const currentFilename = uri2path(import.meta.url);
21function getVersion() {
22 const packageJsonContent = fs.readFileSync(path.resolve(currentFilename, '../../package.json'), { encoding: 'utf-8' });
23 const { version } = map(JSON.parse(stripBOM(packageJsonContent)));
24 return version;
25}
26function findProjectRoot(base) {
27 let prev = null;
28 let dir = base;
29 do {
30 if (fs.existsSync(path.join(dir, constants.NODE_PACKAGE_JSON))) {
31 return dir;
32 }
33 prev = dir;
34 dir = path.dirname(dir);
35 } while (dir !== prev);
36 return base;
37}
38export async function main({ startArgs, args, endArgs, }) {
39 const version = getVersion();
40 loudRejection();
41 handleSignals();
42 // set global options
43 commander.version(version, '-v, --version');
44 commander.usage('[command] [flags]');
45 commander.option('--verbose', 'output verbose messages on internal operations');
46 commander.option('--json', 'format Pika log messages as lines of JSON (see jsonlines.org)');
47 // commander.option('--force', 'install and build packages even if they were built before, overwrite lockfile');
48 // commander.option('--prod, --production [prod]', '', boolify);
49 commander.option('--emoji [bool]', 'enable emoji in output', boolify, process.platform === 'darwin' || process.env.TERM_PROGRAM === 'Hyper' || process.env.TERM_PROGRAM === 'HyperTerm');
50 commander.option('-s, --silent', 'skip Pika console logs, other types of logs (script output) will be printed');
51 commander.option('--cwd <cwd>', 'working directory to use', process.cwd());
52 commander.option('--no-progress', 'disable progress bar');
53 commander.option('--no-node-version-check', 'do not warn when using a potentially unsupported Node version');
54 commander.option('--pipeline <pipeline>', 'the build pipeline to run');
55 // if -v is the first command, then always exit after returning the version
56 if (args[0] === '-v') {
57 console.log(version.trim());
58 process.exitCode = 0;
59 return;
60 }
61 // get command name
62 const firstNonFlagIndex = args.findIndex((arg, idx, arr) => {
63 const isOption = arg.startsWith('-');
64 const prev = idx > 0 && arr[idx - 1];
65 const prevOption = prev && prev.startsWith('-') && commander.optionFor(prev);
66 const boundToPrevOption = prevOption && (prevOption.optional || prevOption.required);
67 return !isOption && !boundToPrevOption;
68 });
69 let preCommandArgs;
70 let commandName = '';
71 if (firstNonFlagIndex > -1) {
72 preCommandArgs = args.slice(0, firstNonFlagIndex);
73 commandName = args[firstNonFlagIndex];
74 args = args.slice(firstNonFlagIndex + 1);
75 }
76 else {
77 preCommandArgs = args;
78 args = [];
79 }
80 let isKnownCommand = Object.prototype.hasOwnProperty.call(commands, commandName);
81 const isHelp = arg => arg === '--help' || arg === '-h';
82 const helpInPre = preCommandArgs.findIndex(isHelp);
83 const helpInArgs = args.findIndex(isHelp);
84 const setHelpMode = () => {
85 if (isKnownCommand) {
86 args.unshift(commandName);
87 }
88 commandName = 'help';
89 isKnownCommand = true;
90 };
91 if (helpInPre > -1) {
92 preCommandArgs.splice(helpInPre);
93 setHelpMode();
94 }
95 else if (isKnownCommand && helpInArgs === 0) {
96 args.splice(helpInArgs);
97 setHelpMode();
98 }
99 if (!commandName) {
100 commandName = 'help';
101 isKnownCommand = true;
102 }
103 if (!isKnownCommand) {
104 // if command is not recognized, then set default to `run`
105 args.unshift(commandName);
106 commandName = 'help';
107 }
108 const command = commandName === 'help' ? helpCommand : commands[commandName];
109 commander.originalArgs = args;
110 args = [...preCommandArgs, ...args];
111 command.setFlags(commander);
112 commander.parse([
113 ...startArgs,
114 // we use this for https://github.com/tj/commander.js/issues/346, otherwise
115 // it will strip some args that match with any options
116 'this-arg-will-get-stripped-later',
117 ...args,
118 ]);
119 commander.args = commander.args.concat(endArgs.slice(1));
120 // we strip cmd
121 console.assert(commander.args.length >= 1);
122 console.assert(commander.args[0] === 'this-arg-will-get-stripped-later');
123 commander.args.shift();
124 //
125 const Reporter = commander.json ? JSONReporter : ConsoleReporter;
126 const reporter = new Reporter({
127 emoji: process.stdout.isTTY && commander.emoji,
128 verbose: commander.verbose,
129 noProgress: !commander.progress,
130 isSilent: boolifyWithDefault(process.env.PIKA_SILENT, false) || commander.silent,
131 nonInteractive: commander.nonInteractive,
132 });
133 const exit = (exitCode = 0) => {
134 if (exitCode === 0) {
135 clearErrorReport();
136 }
137 process.exitCode = exitCode;
138 reporter.close();
139 };
140 reporter.initPeakMemoryCounter();
141 const outputWrapperEnabled = boolifyWithDefault(process.env.PIKA_WRAP_OUTPUT, true);
142 const shouldWrapOutput = outputWrapperEnabled && !commander.json && command.hasWrapper(commander, commander.args);
143 // if (shouldWrapOutput) {
144 reporter.header(commandName, { name: '@pika/pack', version });
145 // }
146 if (commander.nodeVersionCheck && !semver.satisfies(process.versions.node, constants.SUPPORTED_NODE_VERSIONS)) {
147 reporter.warn(reporter.lang('unsupportedNodeVersion', process.versions.node, constants.SUPPORTED_NODE_VERSIONS));
148 }
149 if (command.noArguments && commander.args.length) {
150 reporter.error(reporter.lang('noArguments'));
151 // reporter.info(command.getDocsInfo);
152 exit(1);
153 return;
154 }
155 //
156 // if (commander.yes) {
157 // reporter.warn(reporter.lang('yesWarning'));
158 // }
159 //
160 const run = () => {
161 invariant(command, 'missing command');
162 // if (warnAboutRunDashDash) {
163 // reporter.warn(reporter.lang('dashDashDeprecation'));
164 // }
165 return command.run(config, reporter, commander, commander.args).then(exitCode => {
166 if (shouldWrapOutput) {
167 reporter.footer(false);
168 }
169 return exitCode;
170 });
171 };
172 function onUnexpectedError(err) {
173 function indent(str) {
174 return '\n ' + str.trim().split('\n').join('\n ');
175 }
176 const log = [];
177 log.push(`Arguments: ${indent(process.argv.join(' '))}`);
178 log.push(`PATH: ${indent(process.env.PATH || 'undefined')}`);
179 log.push(`Pika version: ${indent(version)}`);
180 log.push(`Node version: ${indent(process.versions.node)}`);
181 log.push(`Platform: ${indent(process.platform + ' ' + process.arch)}`);
182 log.push(`Trace: ${indent(err.stack)}`);
183 const errorReportLoc = writeErrorReport(log);
184 reporter.error(reporter.lang('unexpectedError', err.message));
185 if (errorReportLoc) {
186 reporter.info(reporter.lang('bugReport', errorReportLoc));
187 }
188 }
189 function writeErrorReport(log) {
190 const errorReportLoc = path.join(config.cwd, 'pika-error.log');
191 try {
192 fs.writeFileSync(errorReportLoc, log.join('\n\n') + '\n');
193 }
194 catch (err) {
195 reporter.error(reporter.lang('fileWriteError', errorReportLoc, err.message));
196 return undefined;
197 }
198 return errorReportLoc;
199 }
200 function clearErrorReport() {
201 const errorReportLoc = path.join(config.cwd, 'pika-error.log');
202 if (fs.existsSync(errorReportLoc)) {
203 try {
204 fs.unlinkSync(errorReportLoc);
205 }
206 catch (err) {
207 reporter.error(reporter.lang('fileDeleteError', errorReportLoc, err.message));
208 return undefined;
209 }
210 }
211 return errorReportLoc;
212 }
213 const cwd = command.shouldRunInCurrentCwd ? commander.cwd : findProjectRoot(commander.cwd);
214 const config = new Config(reporter, cwd, commander);
215 await config.loadPackageManifest();
216 try {
217 // option "no-progress" stored in pika config
218 const noProgressConfig = false; //config.registries.pika.getOption('no-progress');
219 if (noProgressConfig) {
220 reporter.disableProgress();
221 }
222 // verbose logs outputs process.uptime() with this line we can sync uptime to absolute time on the computer
223 reporter.verbose(`current time: ${new Date().toISOString()}`);
224 return run().then(exit);
225 }
226 catch (err) {
227 reporter.verbose(err.stack);
228 if (err instanceof MessageError) {
229 reporter.error(err.message);
230 }
231 else {
232 onUnexpectedError(err);
233 }
234 // if (command.getDocsInfo) {
235 // reporter.info(command.getDocsInfo);
236 // }
237 return exit(1);
238 }
239}
240async function start() {
241 // ignore all arguments after a --
242 const doubleDashIndex = process.argv.findIndex(element => element === '--');
243 const startArgs = process.argv.slice(0, 2);
244 const args = process.argv.slice(2, doubleDashIndex === -1 ? process.argv.length : doubleDashIndex);
245 const endArgs = doubleDashIndex === -1 ? [] : process.argv.slice(doubleDashIndex);
246 await main({ startArgs, args, endArgs });
247}
248export const autoRun = false;
249export default start;