UNPKG

tachometer

Version:
215 lines (198 loc) 6.5 kB
/** * @license * Copyright (c) 2019 The Polymer Project Authors. All rights reserved. * This code may only be used under the BSD style license found at * http://polymer.github.io/LICENSE.txt The complete set of authors may be found * at http://polymer.github.io/AUTHORS.txt The complete set of contributors may * be found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by * Google as part of the polymer project is also subject to an additional IP * rights grant found at http://polymer.github.io/PATENTS.txt */ import * as path from 'path'; import {parseBrowserConfigString, validateBrowserConfig, WindowSize} from './browser'; import {Config, urlFromLocalPath} from './config'; import * as defaults from './defaults'; import {Opts} from './flags'; import {Server} from './server'; import {BenchmarkSpec, LocalUrl, PackageVersion, RemoteUrl} from './types'; import {isHttpUrl} from './util'; import {parsePackageVersions} from './versions'; /** * Derive the set of benchmark specifications we should run according to the * given options, which may require checking the layout on disk of the * benchmarks/ directory. */ export async function specsFromOpts(opts: Opts): Promise<BenchmarkSpec[]> { let windowSize: WindowSize; if (opts['window-size']) { const match = opts['window-size'].match(/^(\d+),(\d+)$/); if (match === null) { throw new Error( `Invalid --window-size flag, must match "width,height, " ` + `but was "${opts['window-size']}"`); } windowSize = { width: Number(match[1]), height: Number(match[2]), }; } else { windowSize = { width: defaults.windowWidth, height: defaults.windowHeight, }; } const browserStrings = new Set((opts.browser || defaults.browserName) .replace(/\s+/, '') .split(',') .filter((b) => b !== '')); if (browserStrings.size === 0) { throw new Error('At least one --browser must be specified'); } const browsers = [...browserStrings].map((str) => { const config = { ...parseBrowserConfigString(str), windowSize, }; validateBrowserConfig(config); return config; }); const specs: BenchmarkSpec[] = []; const versions: Array<PackageVersion|undefined> = parsePackageVersions(opts['package-version']); if (versions.length === 0) { versions.push(undefined); } // Benchmark paths/URLs are the bare arguments not associated with a flag, so // they are found in _unknown. for (const argStr of opts._unknown || []) { const arg = parseBenchmarkArgument(argStr); if (arg.kind === 'remote') { const url: RemoteUrl = { kind: 'remote', url: arg.url, }; const measurement = opts.measure !== undefined ? opts.measure : defaults.measurement(url); const measurementExpression = measurement === 'global' ? (opts['measurement-expression'] !== undefined ? opts['measurement-expression'] : defaults.measurementExpression) : undefined; for (const browser of browsers) { const spec: BenchmarkSpec = { name: arg.alias || arg.url, browser, measurement, url, }; if (measurementExpression) { spec.measurementExpression = measurementExpression; } specs.push(spec); } } else { const root = opts.root || defaults.root; const urlPath = await urlFromLocalPath(root, arg.diskPath); let name = arg.alias; if (name === undefined) { const serverRelativePath = path.relative(root, arg.diskPath); name = serverRelativePath.replace(path.win32.sep, '/'); } for (const browser of browsers) { for (const version of versions) { const url: LocalUrl = { kind: 'local', urlPath, queryString: arg.queryString, version, }; const measurement = opts.measure !== undefined ? opts.measure : defaults.measurement(url); const measurementExpression = measurement === 'global' ? (opts['measurement-expression'] !== undefined ? opts['measurement-expression'] : defaults.measurementExpression) : undefined; const spec: BenchmarkSpec = { name, browser, measurement, url, }; if (measurementExpression) { spec.measurementExpression = measurementExpression; } specs.push(spec); } } } } return specs; } function parseBenchmarkArgument(str: string): {kind: 'remote', url: string, alias?: string}| {kind: 'local', diskPath: string, queryString: string, alias?: string} { if (isHttpUrl(str)) { // http://example.com return { kind: 'remote', url: str, }; } if (str.includes('=')) { const eq = str.indexOf('='); const maybeUrl = str.substring(eq + 1); if (isHttpUrl(maybeUrl)) { // foo=http://example.com return { kind: 'remote', url: maybeUrl, alias: str.substring(0, eq), }; } } let queryString = ''; if (str.includes('?')) { // a/b.html?a=b // foo=a/b.html?a=b const q = str.indexOf('?'); queryString = str.substring(q); str = str.substring(0, q); } let alias = undefined; if (str.includes('=')) { // foo=a/b.html?a=b // foo=a/b.html const eq = str.indexOf('='); alias = str.substring(0, eq); str = str.substring(eq + 1); } // a/b.html // a/b.html?a=b // foo=a/b.html // foo=a/b.html?a=b return { kind: 'local', alias, diskPath: str, queryString: queryString, }; } export function specUrl( spec: BenchmarkSpec, servers: Map<BenchmarkSpec, Server>, config: Config): string { if (spec.url.kind === 'remote') { return spec.url.url; } const server = servers.get(spec); if (server === undefined) { throw new Error('Internal error: no server for spec'); } if (config.remoteAccessibleHost !== '' && spec.browser.remoteUrl !== undefined) { return 'http://' + config.remoteAccessibleHost + ':' + server.port + spec.url.urlPath + spec.url.queryString; } return server.url + spec.url.urlPath + spec.url.queryString; }