mirror of
https://github.com/compiler-explorer/compiler-explorer.git
synced 2025-12-27 10:33:59 -05:00
Replace nopt with commander.js for argument parsing (#7673)
- Replace nopt with commander.js for better command-line argument parsing - Add automatic help generation with detailed descriptions - Maintain backward compatibility with existing arguments - Remove unused nopt dependency from package.json 🤖 Generated with [Claude Code](https://claude.ai/code) --------- Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
2
.github/workflows/test-frontend.yml
vendored
2
.github/workflows/test-frontend.yml
vendored
@@ -28,7 +28,7 @@ jobs:
|
|||||||
- name: Cypress run
|
- name: Cypress run
|
||||||
uses: cypress-io/github-action@v6
|
uses: cypress-io/github-action@v6
|
||||||
with:
|
with:
|
||||||
start: npm run dev -- --language c++ --noLocal
|
start: npm run dev -- --language c++ --no-local
|
||||||
wait-on: 'http://localhost:10240'
|
wait-on: 'http://localhost:10240'
|
||||||
wait-on-timeout: 120
|
wait-on-timeout: 120
|
||||||
config: screenshotOnRunFailure=true,video=false
|
config: screenshotOnRunFailure=true,video=false
|
||||||
|
|||||||
2
Makefile
2
Makefile
@@ -84,7 +84,7 @@ prebuild: prereqs scripts
|
|||||||
|
|
||||||
.PHONY: run-only
|
.PHONY: run-only
|
||||||
run-only: node-installed ## Runs the site like it runs in production without building it
|
run-only: node-installed ## Runs the site like it runs in production without building it
|
||||||
env NODE_ENV=production $(NODE) $(NODE_ARGS) ./out/dist/app.js --webpackContent ./out/webpack/static $(EXTRA_ARGS)
|
env NODE_ENV=production $(NODE) $(NODE_ARGS) ./out/dist/app.js --webpack-content ./out/webpack/static $(EXTRA_ARGS)
|
||||||
|
|
||||||
.PHONY: run
|
.PHONY: run
|
||||||
run: ## Runs the site like it runs in production
|
run: ## Runs the site like it runs in production
|
||||||
|
|||||||
225
app.ts
225
app.ts
@@ -35,12 +35,12 @@ import url from 'node:url';
|
|||||||
import * as fsSync from 'node:fs';
|
import * as fsSync from 'node:fs';
|
||||||
import fs from 'node:fs/promises';
|
import fs from 'node:fs/promises';
|
||||||
import * as Sentry from '@sentry/node';
|
import * as Sentry from '@sentry/node';
|
||||||
|
import {Command, OptionValues} from 'commander';
|
||||||
import compression from 'compression';
|
import compression from 'compression';
|
||||||
import express from 'express';
|
import express from 'express';
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import morgan from 'morgan';
|
import morgan from 'morgan';
|
||||||
import nopt from 'nopt';
|
|
||||||
import PromClient from 'prom-client';
|
import PromClient from 'prom-client';
|
||||||
import responseTime from 'response-time';
|
import responseTime from 'response-time';
|
||||||
import sanitize from 'sanitize-filename';
|
import sanitize from 'sanitize-filename';
|
||||||
@@ -92,73 +92,73 @@ import type {Language, LanguageKey} from './types/languages.interfaces.js';
|
|||||||
|
|
||||||
setBaseDirectory(new URL('.', import.meta.url));
|
setBaseDirectory(new URL('.', import.meta.url));
|
||||||
|
|
||||||
(nopt as any).invalidHandler = (key: string, val: unknown, types: unknown[]) => {
|
function parseNumberForOptions(value: string): number {
|
||||||
logger.error(
|
const parsedValue = Number.parseInt(value, 10);
|
||||||
`Command line argument type error for "--${key}=${val}",
|
if (Number.isNaN(parsedValue)) {
|
||||||
expected ${types.map((t: unknown) => typeof t).join(' | ')}`,
|
throw new Error(`Invalid number: "${value}"`);
|
||||||
);
|
}
|
||||||
};
|
return parsedValue;
|
||||||
|
}
|
||||||
|
|
||||||
type CompilerExplorerOptions = Partial<{
|
interface CompilerExplorerOptions extends OptionValues {
|
||||||
env: string[];
|
env: string[];
|
||||||
rootDir: string;
|
rootDir: string;
|
||||||
host: string;
|
host?: string;
|
||||||
port: number;
|
port: number;
|
||||||
propDebug: boolean;
|
propDebug?: boolean;
|
||||||
debug: boolean;
|
debug?: boolean;
|
||||||
dist: boolean;
|
dist?: boolean;
|
||||||
archivedVersions: string;
|
remoteFetch: boolean;
|
||||||
noRemoteFetch: boolean;
|
tmpDir?: string;
|
||||||
tmpDir: string;
|
wsl?: boolean;
|
||||||
wsl: boolean;
|
language?: string[];
|
||||||
language: string[];
|
cache: boolean;
|
||||||
noCache: boolean;
|
ensureNoIdClash?: boolean;
|
||||||
ensureNoIdClash: boolean;
|
logHost?: string;
|
||||||
logHost: string;
|
logPort?: number;
|
||||||
logPort: number;
|
hostnameForLogging?: string;
|
||||||
hostnameForLogging: string;
|
|
||||||
suppressConsoleLog: boolean;
|
suppressConsoleLog: boolean;
|
||||||
metricsPort: number;
|
metricsPort?: number;
|
||||||
loki: string;
|
loki?: string;
|
||||||
discoveryonly: string;
|
discoveryOnly?: string;
|
||||||
prediscovered: string;
|
prediscovered?: string;
|
||||||
|
webpackContent?: string;
|
||||||
|
local: boolean;
|
||||||
version: boolean;
|
version: boolean;
|
||||||
webpackContent: string;
|
}
|
||||||
noLocal: boolean;
|
|
||||||
}>;
|
|
||||||
|
|
||||||
// Parse arguments from command line 'node ./app.js args...'
|
const program = new Command();
|
||||||
const opts = nopt({
|
program
|
||||||
env: [String, Array],
|
.name('compiler-explorer')
|
||||||
rootDir: [String],
|
.description('Interactively investigate compiler output')
|
||||||
host: [String],
|
.option('--env <environments...>', 'Environment(s) to use', ['dev'])
|
||||||
port: [Number],
|
.option('--root-dir <dir>', 'Root directory for config files', './etc')
|
||||||
propDebug: [Boolean],
|
.option('--host <hostname>', 'Hostname to listen on')
|
||||||
debug: [Boolean],
|
.option('--port <port>', 'Port to listen on', parseNumberForOptions, 10240)
|
||||||
dist: [Boolean],
|
.option('--prop-debug', 'Debug properties')
|
||||||
archivedVersions: [String],
|
.option('--debug', 'Enable debug output')
|
||||||
// Ignore fetch marks and assume every compiler is found locally
|
.option('--dist', 'Running in dist mode')
|
||||||
noRemoteFetch: [Boolean],
|
.option('--no-remote-fetch', 'Ignore fetch marks and assume every compiler is found locally')
|
||||||
tmpDir: [String],
|
.option('--tmpDir, --tmp-dir <dir>', 'Directory to use for temporary files')
|
||||||
wsl: [Boolean],
|
.option('--wsl', 'Running under Windows Subsystem for Linux')
|
||||||
// If specified, only loads the specified languages, resulting in faster loadup/iteration times
|
.option('--language <languages...>', 'Only load specified languages for faster startup')
|
||||||
language: [String, Array],
|
.option('--no-cache', 'Do not use caching for compilation results')
|
||||||
// Do not use caching for compilation results (Requests might still be cached by the client's browser)
|
.option('--ensure-no-id-clash', "Don't run if compilers have clashing ids")
|
||||||
noCache: [Boolean],
|
.option('--logHost, --log-host <hostname>', 'Hostname for remote logging')
|
||||||
// Don't cleanly run if two or more compilers have clashing ids
|
.option('--logPort, --log-port <port>', 'Port for remote logging', parseNumberForOptions)
|
||||||
ensureNoIdClash: [Boolean],
|
.option('--hostname-for-logging <hostname>', 'Hostname to use in logs')
|
||||||
logHost: [String],
|
.option('--suppressConsoleLog, --suppress-console-log', 'Disable console logging')
|
||||||
logPort: [Number],
|
.option('--metricsPort, --metrics-port <port>', 'Port to serve metrics on', parseNumberForOptions)
|
||||||
hostnameForLogging: [String],
|
.option('--loki <url>', 'URL for Loki logging')
|
||||||
suppressConsoleLog: [Boolean],
|
.option('--discoveryonly, --discovery-only <file>', 'Output discovery info to file and exit')
|
||||||
metricsPort: [Number],
|
.option('--prediscovered <file>', 'Input discovery info from file')
|
||||||
loki: [String],
|
.option('--webpack-content <dir>', 'Path to webpack content')
|
||||||
discoveryonly: [String],
|
.option('--no-local', 'Disable local config')
|
||||||
prediscovered: [String],
|
.option('--version', 'Show version information');
|
||||||
version: [Boolean],
|
|
||||||
webpackContent: [String],
|
program.parse();
|
||||||
noLocal: [Boolean],
|
|
||||||
}) as CompilerExplorerOptions;
|
const opts = program.opts<CompilerExplorerOptions>();
|
||||||
|
|
||||||
if (opts.debug) logger.level = 'debug';
|
if (opts.debug) logger.level = 'debug';
|
||||||
|
|
||||||
@@ -222,39 +222,29 @@ const releaseBuildNumber = (() => {
|
|||||||
return '';
|
return '';
|
||||||
})();
|
})();
|
||||||
|
|
||||||
function patchUpLanguageArg(languages: string[] | undefined): string[] | null {
|
const appArgs: AppArguments = {
|
||||||
if (!languages) return null;
|
rootDir: opts.rootDir,
|
||||||
if (languages.length === 1) {
|
env: opts.env,
|
||||||
// Support old style comma-separated language args.
|
|
||||||
return languages[0].split(',');
|
|
||||||
}
|
|
||||||
return languages;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set default values for omitted arguments
|
|
||||||
const defArgs: AppArguments = {
|
|
||||||
rootDir: opts.rootDir || './etc',
|
|
||||||
env: opts.env || ['dev'],
|
|
||||||
hostname: opts.host,
|
hostname: opts.host,
|
||||||
port: opts.port || 10240,
|
port: opts.port,
|
||||||
gitReleaseName: gitReleaseName,
|
gitReleaseName: gitReleaseName,
|
||||||
releaseBuildNumber: releaseBuildNumber,
|
releaseBuildNumber: releaseBuildNumber,
|
||||||
wantedLanguages: patchUpLanguageArg(opts.language),
|
wantedLanguages: opts.language,
|
||||||
doCache: !opts.noCache,
|
doCache: opts.cache,
|
||||||
fetchCompilersFromRemote: !opts.noRemoteFetch,
|
fetchCompilersFromRemote: opts.remoteFetch,
|
||||||
ensureNoCompilerClash: opts.ensureNoIdClash,
|
ensureNoCompilerClash: opts.ensureNoIdClash,
|
||||||
suppressConsoleLog: opts.suppressConsoleLog || false,
|
suppressConsoleLog: opts.suppressConsoleLog,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (opts.logHost && opts.logPort) {
|
if (opts.logHost && opts.logPort) {
|
||||||
logToPapertrail(opts.logHost, opts.logPort, defArgs.env.join('.'), opts.hostnameForLogging);
|
logToPapertrail(opts.logHost, opts.logPort, appArgs.env.join('.'), opts.hostnameForLogging);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opts.loki) {
|
if (opts.loki) {
|
||||||
logToLoki(opts.loki);
|
logToLoki(opts.loki);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (defArgs.suppressConsoleLog) {
|
if (appArgs.suppressConsoleLog) {
|
||||||
logger.info('Disabling further console logging');
|
logger.info('Disabling further console logging');
|
||||||
suppressConsoleLog();
|
suppressConsoleLog();
|
||||||
}
|
}
|
||||||
@@ -276,12 +266,12 @@ function getFaviconFilename() {
|
|||||||
|
|
||||||
const propHierarchy = [
|
const propHierarchy = [
|
||||||
'defaults',
|
'defaults',
|
||||||
defArgs.env,
|
appArgs.env,
|
||||||
defArgs.env.map(e => `${e}.${process.platform}`),
|
appArgs.env.map(e => `${e}.${process.platform}`),
|
||||||
process.platform,
|
process.platform,
|
||||||
os.hostname(),
|
os.hostname(),
|
||||||
].flat();
|
].flat();
|
||||||
if (!opts.noLocal) {
|
if (opts.local) {
|
||||||
propHierarchy.push('local');
|
propHierarchy.push('local');
|
||||||
}
|
}
|
||||||
logger.info(`properties hierarchy: ${propHierarchy.join(', ')}`);
|
logger.info(`properties hierarchy: ${propHierarchy.join(', ')}`);
|
||||||
@@ -290,20 +280,20 @@ logger.info(`properties hierarchy: ${propHierarchy.join(', ')}`);
|
|||||||
if (opts.propDebug) props.setDebug(true);
|
if (opts.propDebug) props.setDebug(true);
|
||||||
|
|
||||||
// *All* files in config dir are parsed
|
// *All* files in config dir are parsed
|
||||||
const configDir = path.join(defArgs.rootDir, 'config');
|
const configDir = path.join(appArgs.rootDir, 'config');
|
||||||
props.initialize(configDir, propHierarchy);
|
props.initialize(configDir, propHierarchy);
|
||||||
// Instantiate a function to access records concerning "compiler-explorer"
|
// Instantiate a function to access records concerning "compiler-explorer"
|
||||||
// in hidden object props.properties
|
// in hidden object props.properties
|
||||||
const ceProps = props.propsFor('compiler-explorer');
|
const ceProps = props.propsFor('compiler-explorer');
|
||||||
const restrictToLanguages = ceProps<string>('restrictToLanguages');
|
const restrictToLanguages = ceProps<string>('restrictToLanguages');
|
||||||
if (restrictToLanguages) {
|
if (restrictToLanguages) {
|
||||||
defArgs.wantedLanguages = restrictToLanguages.split(',');
|
appArgs.wantedLanguages = restrictToLanguages.split(',');
|
||||||
}
|
}
|
||||||
|
|
||||||
const languages = (() => {
|
const languages = (() => {
|
||||||
if (defArgs.wantedLanguages) {
|
if (appArgs.wantedLanguages) {
|
||||||
const filteredLangs: Partial<Record<LanguageKey, Language>> = {};
|
const filteredLangs: Partial<Record<LanguageKey, Language>> = {};
|
||||||
for (const wantedLang of defArgs.wantedLanguages) {
|
for (const wantedLang of appArgs.wantedLanguages) {
|
||||||
for (const lang of Object.values(allLanguages)) {
|
for (const lang of Object.values(allLanguages)) {
|
||||||
if (lang.id === wantedLang || lang.name === wantedLang || lang.alias.includes(wantedLang)) {
|
if (lang.id === wantedLang || lang.name === wantedLang || lang.alias.includes(wantedLang)) {
|
||||||
filteredLangs[lang.id] = lang;
|
filteredLangs[lang.id] = lang;
|
||||||
@@ -459,8 +449,7 @@ function oldGoogleUrlHandler(req: express.Request, res: express.Response, next:
|
|||||||
}
|
}
|
||||||
|
|
||||||
function startListening(server: express.Express) {
|
function startListening(server: express.Express) {
|
||||||
const ss = systemdSocket();
|
const ss: {fd: number} | null = systemdSocket(); // TODO: I'm not sure this works any more
|
||||||
let _port;
|
|
||||||
if (ss) {
|
if (ss) {
|
||||||
// ms (5 min default)
|
// ms (5 min default)
|
||||||
const idleTimeout = process.env.IDLE_TIMEOUT;
|
const idleTimeout = process.env.IDLE_TIMEOUT;
|
||||||
@@ -478,9 +467,15 @@ function startListening(server: express.Express) {
|
|||||||
server.all('*', reset);
|
server.all('*', reset);
|
||||||
logger.info(` IDLE_TIMEOUT: ${idleTimeout}`);
|
logger.info(` IDLE_TIMEOUT: ${idleTimeout}`);
|
||||||
}
|
}
|
||||||
_port = ss;
|
logger.info(` Listening on systemd socket: ${JSON.stringify(ss)}`);
|
||||||
|
server.listen(ss);
|
||||||
} else {
|
} else {
|
||||||
_port = defArgs.port;
|
logger.info(` Listening on http://${appArgs.hostname || 'localhost'}:${appArgs.port}/`);
|
||||||
|
if (appArgs.hostname) {
|
||||||
|
server.listen(appArgs.port, appArgs.hostname);
|
||||||
|
} else {
|
||||||
|
server.listen(appArgs.port);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const startupGauge = new PromClient.Gauge({
|
const startupGauge = new PromClient.Gauge({
|
||||||
@@ -489,24 +484,8 @@ function startListening(server: express.Express) {
|
|||||||
});
|
});
|
||||||
startupGauge.set(process.uptime());
|
startupGauge.set(process.uptime());
|
||||||
const startupDurationMs = Math.floor(process.uptime() * 1000);
|
const startupDurationMs = Math.floor(process.uptime() * 1000);
|
||||||
if (Number.isNaN(Number.parseInt(_port))) {
|
logger.info(` Startup duration: ${startupDurationMs}ms`);
|
||||||
// unix socket, not a port number...
|
logger.info('=======================================');
|
||||||
logger.info(` Listening on socket: //${_port}/`);
|
|
||||||
logger.info(` Startup duration: ${startupDurationMs}ms`);
|
|
||||||
logger.info('=======================================');
|
|
||||||
server.listen(_port);
|
|
||||||
} else {
|
|
||||||
// normal port number
|
|
||||||
logger.info(` Listening on http://${defArgs.hostname || 'localhost'}:${_port}/`);
|
|
||||||
logger.info(` Startup duration: ${startupDurationMs}ms`);
|
|
||||||
logger.info('=======================================');
|
|
||||||
// silly express typing, passing undefined is fine but
|
|
||||||
if (defArgs.hostname) {
|
|
||||||
server.listen(_port, defArgs.hostname);
|
|
||||||
} else {
|
|
||||||
server.listen(_port);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const awsProps = props.propsFor('aws');
|
const awsProps = props.propsFor('aws');
|
||||||
@@ -514,31 +493,31 @@ const awsProps = props.propsFor('aws');
|
|||||||
// eslint-disable-next-line max-statements
|
// eslint-disable-next-line max-statements
|
||||||
async function main() {
|
async function main() {
|
||||||
await aws.initConfig(awsProps);
|
await aws.initConfig(awsProps);
|
||||||
SetupSentry(aws.getConfig('sentryDsn'), ceProps, releaseBuildNumber, gitReleaseName, defArgs);
|
SetupSentry(aws.getConfig('sentryDsn'), ceProps, releaseBuildNumber, gitReleaseName, appArgs);
|
||||||
const webServer = express();
|
const webServer = express();
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
startWineInit();
|
startWineInit();
|
||||||
|
|
||||||
RemoteExecutionQuery.initRemoteExecutionArchs(ceProps, defArgs.env);
|
RemoteExecutionQuery.initRemoteExecutionArchs(ceProps, appArgs.env);
|
||||||
|
|
||||||
const formattingService = new FormattingService();
|
const formattingService = new FormattingService();
|
||||||
await formattingService.initialize(ceProps);
|
await formattingService.initialize(ceProps);
|
||||||
|
|
||||||
const clientOptionsHandler = new ClientOptionsHandler(sources, compilerProps, defArgs);
|
const clientOptionsHandler = new ClientOptionsHandler(sources, compilerProps, appArgs);
|
||||||
const compilationQueue = CompilationQueue.fromProps(compilerProps.ceProps);
|
const compilationQueue = CompilationQueue.fromProps(compilerProps.ceProps);
|
||||||
const compilationEnvironment = new CompilationEnvironment(
|
const compilationEnvironment = new CompilationEnvironment(
|
||||||
compilerProps,
|
compilerProps,
|
||||||
awsProps,
|
awsProps,
|
||||||
compilationQueue,
|
compilationQueue,
|
||||||
formattingService,
|
formattingService,
|
||||||
defArgs.doCache,
|
appArgs.doCache,
|
||||||
);
|
);
|
||||||
const compileHandler = new CompileHandler(compilationEnvironment, awsProps);
|
const compileHandler = new CompileHandler(compilationEnvironment, awsProps);
|
||||||
compilationEnvironment.setCompilerFinder(compileHandler.findCompiler.bind(compileHandler));
|
compilationEnvironment.setCompilerFinder(compileHandler.findCompiler.bind(compileHandler));
|
||||||
const storageType = getStorageTypeByKey(storageSolution);
|
const storageType = getStorageTypeByKey(storageSolution);
|
||||||
const storageHandler = new storageType(httpRoot, compilerProps, awsProps);
|
const storageHandler = new storageType(httpRoot, compilerProps, awsProps);
|
||||||
const compilerFinder = new CompilerFinder(compileHandler, compilerProps, defArgs, clientOptionsHandler);
|
const compilerFinder = new CompilerFinder(compileHandler, compilerProps, appArgs, clientOptionsHandler);
|
||||||
|
|
||||||
const isExecutionWorker = ceProps<boolean>('execqueue.is_worker', false);
|
const isExecutionWorker = ceProps<boolean>('execqueue.is_worker', false);
|
||||||
const healthCheckFilePath = ceProps('healthCheckFilePath', null) as string | null;
|
const healthCheckFilePath = ceProps('healthCheckFilePath', null) as string | null;
|
||||||
@@ -576,7 +555,7 @@ async function main() {
|
|||||||
if (!isExecutionWorker && initialCompilers.length === 0) {
|
if (!isExecutionWorker && initialCompilers.length === 0) {
|
||||||
throw new Error('Unexpected failure, no compilers found!');
|
throw new Error('Unexpected failure, no compilers found!');
|
||||||
}
|
}
|
||||||
if (defArgs.ensureNoCompilerClash) {
|
if (appArgs.ensureNoCompilerClash) {
|
||||||
logger.warn('Ensuring no compiler ids clash');
|
logger.warn('Ensuring no compiler ids clash');
|
||||||
if (initialFindResults.foundClash) {
|
if (initialFindResults.foundClash) {
|
||||||
// If we are forced to have no clashes, throw an error with some explanation
|
// If we are forced to have no clashes, throw an error with some explanation
|
||||||
@@ -586,7 +565,7 @@ async function main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opts.discoveryonly) {
|
if (opts.discoveryOnly) {
|
||||||
for (const compiler of initialCompilers) {
|
for (const compiler of initialCompilers) {
|
||||||
if (compiler.buildenvsetup && compiler.buildenvsetup.id === '') delete compiler.buildenvsetup;
|
if (compiler.buildenvsetup && compiler.buildenvsetup.id === '') delete compiler.buildenvsetup;
|
||||||
|
|
||||||
@@ -597,8 +576,8 @@ async function main() {
|
|||||||
compiler.cachedPossibleArguments = compilerInstance.possibleArguments.possibleArguments;
|
compiler.cachedPossibleArguments = compilerInstance.possibleArguments.possibleArguments;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await fs.writeFile(opts.discoveryonly, JSON.stringify(initialCompilers));
|
await fs.writeFile(opts.discoveryOnly, JSON.stringify(initialCompilers));
|
||||||
logger.info(`Discovered compilers saved to ${opts.discoveryonly}`);
|
logger.info(`Discovered compilers saved to ${opts.discoveryOnly}`);
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -607,7 +586,7 @@ async function main() {
|
|||||||
clientOptionsHandler,
|
clientOptionsHandler,
|
||||||
renderConfig,
|
renderConfig,
|
||||||
storageHandler,
|
storageHandler,
|
||||||
defArgs.wantedLanguages?.[0],
|
appArgs.wantedLanguages?.[0],
|
||||||
);
|
);
|
||||||
const routeApi = new RouteAPI(router, {
|
const routeApi = new RouteAPI(router, {
|
||||||
compileHandler,
|
compileHandler,
|
||||||
@@ -615,7 +594,7 @@ async function main() {
|
|||||||
storageHandler,
|
storageHandler,
|
||||||
compilationEnvironment,
|
compilationEnvironment,
|
||||||
ceProps,
|
ceProps,
|
||||||
defArgs,
|
defArgs: appArgs,
|
||||||
renderConfig,
|
renderConfig,
|
||||||
renderGoldenLayout,
|
renderGoldenLayout,
|
||||||
});
|
});
|
||||||
@@ -649,7 +628,7 @@ async function main() {
|
|||||||
|
|
||||||
if (opts.metricsPort) {
|
if (opts.metricsPort) {
|
||||||
logger.info(`Running metrics server on port ${opts.metricsPort}`);
|
logger.info(`Running metrics server on port ${opts.metricsPort}`);
|
||||||
setupMetricsServer(opts.metricsPort, defArgs.hostname);
|
setupMetricsServer(opts.metricsPort, appArgs.hostname);
|
||||||
}
|
}
|
||||||
|
|
||||||
webServer
|
webServer
|
||||||
@@ -851,7 +830,7 @@ async function main() {
|
|||||||
noscriptHandler.initializeRoutes();
|
noscriptHandler.initializeRoutes();
|
||||||
routeApi.initializeRoutes();
|
routeApi.initializeRoutes();
|
||||||
|
|
||||||
if (!defArgs.doCache) {
|
if (!appArgs.doCache) {
|
||||||
logger.info(' with disabled caching');
|
logger.info(' with disabled caching');
|
||||||
}
|
}
|
||||||
setupEventLoopLagLogging();
|
setupEventLoopLagLogging();
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
// POSSIBILITY OF SUCH DAMAGE.
|
// POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
import nopt from 'nopt';
|
import {Command} from 'commander';
|
||||||
import _ from 'underscore';
|
import _ from 'underscore';
|
||||||
|
|
||||||
import {CompilerArguments} from './lib/compiler-arguments.js';
|
import {CompilerArguments} from './lib/compiler-arguments.js';
|
||||||
@@ -30,12 +30,20 @@ import * as Parsers from './lib/compilers/argument-parsers.js';
|
|||||||
import {executeDirect} from './lib/exec.js';
|
import {executeDirect} from './lib/exec.js';
|
||||||
import {logger} from './lib/logger.js';
|
import {logger} from './lib/logger.js';
|
||||||
|
|
||||||
const opts = nopt({
|
const program = new Command();
|
||||||
parser: [String],
|
program
|
||||||
exe: [String],
|
.name('compiler-args-app.ts')
|
||||||
padding: [Number],
|
.usage('--parser=<compilertype> --exe=<path> [--padding=<number>]')
|
||||||
debug: [Boolean],
|
.description(
|
||||||
});
|
'Extracts compiler arguments\nFor example: node --no-warnings=ExperimentalWarning --import=tsx compiler-args-app.ts --parser=clang --exe=/opt/compiler-explorer/clang-15.0.0/bin/clang++ --padding=50',
|
||||||
|
)
|
||||||
|
.requiredOption('--parser <type>', 'Compiler parser type')
|
||||||
|
.requiredOption('--exe <path>', 'Path to compiler executable')
|
||||||
|
.option('--padding <number>', 'Padding for output formatting', '40')
|
||||||
|
.option('--debug', 'Enable debug output');
|
||||||
|
|
||||||
|
program.parse();
|
||||||
|
const opts = program.opts();
|
||||||
|
|
||||||
if (opts.debug) logger.level = 'debug';
|
if (opts.debug) logger.level = 'debug';
|
||||||
|
|
||||||
@@ -73,7 +81,7 @@ class CompilerArgsApp {
|
|||||||
constructor() {
|
constructor() {
|
||||||
this.parserName = opts.parser;
|
this.parserName = opts.parser;
|
||||||
this.executable = opts.exe;
|
this.executable = opts.exe;
|
||||||
this.pad = opts.padding || 40;
|
this.pad = Number.parseInt(opts.padding, 10);
|
||||||
this.compiler = {
|
this.compiler = {
|
||||||
compiler: {
|
compiler: {
|
||||||
exe: this.executable,
|
exe: this.executable,
|
||||||
@@ -145,17 +153,7 @@ class CompilerArgsApp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!opts.parser || !opts.exe) {
|
const app = new CompilerArgsApp();
|
||||||
console.error(
|
app.doTheParsing()
|
||||||
'Usage: ' +
|
.then(() => app.print())
|
||||||
'node --no-warnings=ExperimentalWarning --import=tsx compiler-args-app.ts ' +
|
.catch(e => console.error(e));
|
||||||
'--parser=<compilertype> --exe=<path> [--padding=<number>]\n' +
|
|
||||||
'for example: --parser=clang --exe=/opt/compiler-explorer/clang-15.0.0/bin/clang++ --padding=50',
|
|
||||||
);
|
|
||||||
process.exit(1);
|
|
||||||
} else {
|
|
||||||
const app = new CompilerArgsApp();
|
|
||||||
app.doTheParsing()
|
|
||||||
.then(() => app.print())
|
|
||||||
.catch(e => console.error(e));
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -223,7 +223,7 @@ Note that path-style properties often support variable substitution as shown abo
|
|||||||
|
|
||||||
### Property Debugging
|
### Property Debugging
|
||||||
|
|
||||||
You can enable detailed debugging of property resolution by using the `--propDebug` flag when starting Compiler
|
You can enable detailed debugging of property resolution by using the `--prop-debug` flag when starting Compiler
|
||||||
Explorer. This shows every property lookup, including where properties are being overridden and which configuration
|
Explorer. This shows every property lookup, including where properties are being overridden and which configuration
|
||||||
source they come from.
|
source they come from.
|
||||||
|
|
||||||
@@ -257,7 +257,7 @@ The configuration system is implemented primarily in the following files:
|
|||||||
If you need to troubleshoot configuration issues, you can run Compiler Explorer with debug output:
|
If you need to troubleshoot configuration issues, you can run Compiler Explorer with debug output:
|
||||||
|
|
||||||
```
|
```
|
||||||
make EXTRA_ARGS='--propDebug' dev
|
make EXTRA_ARGS='--prop-debug' dev
|
||||||
```
|
```
|
||||||
|
|
||||||
This will show detailed logs about property resolution, including which properties are being overridden and from which
|
This will show detailed logs about property resolution, including which properties are being overridden and from which
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ Our frontend testing is done with cypress.
|
|||||||
|
|
||||||
To run the tests locally:
|
To run the tests locally:
|
||||||
|
|
||||||
- start a server with `npm run dev -- --language c++ --noLocal` - this configuration ensures your setup is clean of any
|
- start a server with `npm run dev -- --language c++ --no-local` - this configuration ensures your setup is clean of any
|
||||||
local properties.
|
local properties.
|
||||||
- in another terminal run `npx cypress open`, then choose "end to end" and then you should be able to run tests
|
- in another terminal run `npx cypress open`, then choose "end to end" and then you should be able to run tests
|
||||||
interactively.
|
interactively.
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ export type AppArguments = {
|
|||||||
port: number;
|
port: number;
|
||||||
gitReleaseName: string;
|
gitReleaseName: string;
|
||||||
releaseBuildNumber: string;
|
releaseBuildNumber: string;
|
||||||
wantedLanguages: string[] | null;
|
wantedLanguages: string[] | undefined;
|
||||||
doCache: boolean;
|
doCache: boolean;
|
||||||
fetchCompilersFromRemote: boolean;
|
fetchCompilersFromRemote: boolean;
|
||||||
ensureNoCompilerClash: boolean | undefined;
|
ensureNoCompilerClash: boolean | undefined;
|
||||||
|
|||||||
63
package-lock.json
generated
63
package-lock.json
generated
@@ -27,6 +27,7 @@
|
|||||||
"buffer": "^6.0.3",
|
"buffer": "^6.0.3",
|
||||||
"chart.js": "^4.4.9",
|
"chart.js": "^4.4.9",
|
||||||
"clipboard": "^2.0.11",
|
"clipboard": "^2.0.11",
|
||||||
|
"commander": "^13.1.0",
|
||||||
"compression": "^1.8.0",
|
"compression": "^1.8.0",
|
||||||
"copy-webpack-plugin": "^13.0.0",
|
"copy-webpack-plugin": "^13.0.0",
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
@@ -46,7 +47,6 @@
|
|||||||
"monaco-vim": "^0.4.2",
|
"monaco-vim": "^0.4.2",
|
||||||
"morgan": "^1.10.0",
|
"morgan": "^1.10.0",
|
||||||
"node-targz": "^0.2.0",
|
"node-targz": "^0.2.0",
|
||||||
"nopt": "^8.1.0",
|
|
||||||
"p-queue": "^8.1.0",
|
"p-queue": "^8.1.0",
|
||||||
"path-browserify": "^1.0.1",
|
"path-browserify": "^1.0.1",
|
||||||
"profanities": "^3.0.1",
|
"profanities": "^3.0.1",
|
||||||
@@ -87,7 +87,6 @@
|
|||||||
"@types/jquery": "^3.5.32",
|
"@types/jquery": "^3.5.32",
|
||||||
"@types/js-cookie": "^3.0.6",
|
"@types/js-cookie": "^3.0.6",
|
||||||
"@types/node-targz": "^0.2.4",
|
"@types/node-targz": "^0.2.4",
|
||||||
"@types/nopt": "^3.0.32",
|
|
||||||
"@types/request": "^2.48.12",
|
"@types/request": "^2.48.12",
|
||||||
"@types/response-time": "^2.3.8",
|
"@types/response-time": "^2.3.8",
|
||||||
"@types/serve-favicon": "^2.5.7",
|
"@types/serve-favicon": "^2.5.7",
|
||||||
@@ -5233,13 +5232,6 @@
|
|||||||
"@types/tar-fs": "*"
|
"@types/tar-fs": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/nopt": {
|
|
||||||
"version": "3.0.32",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/nopt/-/nopt-3.0.32.tgz",
|
|
||||||
"integrity": "sha512-UP8QR0GaR8AE3l4wDmyCx4lEkX5o/1YVeDBqb1UqmfHefZqFNedQLTsobfzw56CvlXVVbt6kAwJJbN1yDTp16Q==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/@types/pg": {
|
"node_modules/@types/pg": {
|
||||||
"version": "8.6.1",
|
"version": "8.6.1",
|
||||||
"resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.6.1.tgz",
|
||||||
@@ -5843,15 +5835,6 @@
|
|||||||
"integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==",
|
"integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==",
|
||||||
"license": "Apache-2.0"
|
"license": "Apache-2.0"
|
||||||
},
|
},
|
||||||
"node_modules/abbrev": {
|
|
||||||
"version": "3.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-3.0.1.tgz",
|
|
||||||
"integrity": "sha512-AO2ac6pjRB3SJmGJo+v5/aK6Omggp6fsLrs6wN9bd35ulu4cCwaAU9+7ZhXjeqHVkaHThLuzH0nZr0YpCDhygg==",
|
|
||||||
"license": "ISC",
|
|
||||||
"engines": {
|
|
||||||
"node": "^18.17.0 || >=20.5.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/accepts": {
|
"node_modules/accepts": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz",
|
||||||
@@ -6943,13 +6926,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/commander": {
|
"node_modules/commander": {
|
||||||
"version": "6.2.1",
|
"version": "13.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz",
|
||||||
"integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==",
|
"integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 6"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/common-tags": {
|
"node_modules/common-tags": {
|
||||||
@@ -7534,6 +7516,16 @@
|
|||||||
"ieee754": "^1.1.13"
|
"ieee754": "^1.1.13"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/cypress/node_modules/commander": {
|
||||||
|
"version": "6.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz",
|
||||||
|
"integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/dashdash": {
|
"node_modules/dashdash": {
|
||||||
"version": "1.14.1",
|
"version": "1.14.1",
|
||||||
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
|
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
|
||||||
@@ -9864,16 +9856,6 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/lint-staged/node_modules/commander": {
|
|
||||||
"version": "13.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz",
|
|
||||||
"integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/lint-staged/node_modules/emoji-regex": {
|
"node_modules/lint-staged/node_modules/emoji-regex": {
|
||||||
"version": "10.4.0",
|
"version": "10.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz",
|
||||||
@@ -10899,21 +10881,6 @@
|
|||||||
"node": ">= 0.10.0"
|
"node": ">= 0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/nopt": {
|
|
||||||
"version": "8.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/nopt/-/nopt-8.1.0.tgz",
|
|
||||||
"integrity": "sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A==",
|
|
||||||
"license": "ISC",
|
|
||||||
"dependencies": {
|
|
||||||
"abbrev": "^3.0.0"
|
|
||||||
},
|
|
||||||
"bin": {
|
|
||||||
"nopt": "bin/nopt.js"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": "^18.17.0 || >=20.5.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/normalize-path": {
|
"node_modules/normalize-path": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
|
||||||
|
|||||||
@@ -36,6 +36,7 @@
|
|||||||
"buffer": "^6.0.3",
|
"buffer": "^6.0.3",
|
||||||
"chart.js": "^4.4.9",
|
"chart.js": "^4.4.9",
|
||||||
"clipboard": "^2.0.11",
|
"clipboard": "^2.0.11",
|
||||||
|
"commander": "^13.1.0",
|
||||||
"compression": "^1.8.0",
|
"compression": "^1.8.0",
|
||||||
"copy-webpack-plugin": "^13.0.0",
|
"copy-webpack-plugin": "^13.0.0",
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
@@ -55,7 +56,6 @@
|
|||||||
"monaco-vim": "^0.4.2",
|
"monaco-vim": "^0.4.2",
|
||||||
"morgan": "^1.10.0",
|
"morgan": "^1.10.0",
|
||||||
"node-targz": "^0.2.0",
|
"node-targz": "^0.2.0",
|
||||||
"nopt": "^8.1.0",
|
|
||||||
"p-queue": "^8.1.0",
|
"p-queue": "^8.1.0",
|
||||||
"path-browserify": "^1.0.1",
|
"path-browserify": "^1.0.1",
|
||||||
"profanities": "^3.0.1",
|
"profanities": "^3.0.1",
|
||||||
@@ -96,7 +96,6 @@
|
|||||||
"@types/jquery": "^3.5.32",
|
"@types/jquery": "^3.5.32",
|
||||||
"@types/js-cookie": "^3.0.6",
|
"@types/js-cookie": "^3.0.6",
|
||||||
"@types/node-targz": "^0.2.4",
|
"@types/node-targz": "^0.2.4",
|
||||||
"@types/nopt": "^3.0.32",
|
|
||||||
"@types/request": "^2.48.12",
|
"@types/request": "^2.48.12",
|
||||||
"@types/response-time": "^2.3.8",
|
"@types/response-time": "^2.3.8",
|
||||||
"@types/serve-favicon": "^2.5.7",
|
"@types/serve-favicon": "^2.5.7",
|
||||||
|
|||||||
Reference in New Issue
Block a user