fix: demand --force to re-install stable browser channels (#13200)

This patch will check if browser channel is already installed.
If it is, it'll abort installation with the following error:

```
aslushnikov:~/prog/playwright$ npx playwright install msedge
Failed to install browsers
Error:
╔═════════════════════════════════════════════════════════════════╗
║ ATTENTION: "msedge" is already installed on the system!         ║
║                                                                 ║
║ "msedge" installation is not hermetic; installing newer version ║
║ requires *removal* of a current installation first.             ║
║                                                                 ║
║ To *uninstall* current version and re-install latest "msedge":  ║
║                                                                 ║
║ - Close all running instances of "msedge", if any               ║
║ - Use "--force" to install browser:                             ║
║                                                                 ║
║     npx playwright install --force msedge                       ║
║                                                                 ║
║ <3 Playwright Team                                              ║
╚═════════════════════════════════════════════════════════════════╝
```

To re-install browser channel, use `--force`.

Fixes https://github.com/microsoft/playwright/issues/13061
This commit is contained in:
Andrey Lushnikov 2022-04-01 11:05:53 -06:00 committed by GitHub
parent 7d7fe3c618
commit a87794dae6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 58 additions and 26 deletions

View File

@ -234,7 +234,7 @@ jobs:
env:
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
- run: npm run build
- run: npx playwright install --with-deps chrome
- run: npx playwright install --with-deps --force chrome
- run: xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- npm run ctest
env:
PWTEST_CHANNEL: chrome
@ -259,7 +259,7 @@ jobs:
env:
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
- run: npm run build
- run: npx playwright install --with-deps chrome
- run: npx playwright install --with-deps --force chrome
- run: npm run ctest
shell: bash
env:
@ -286,7 +286,7 @@ jobs:
env:
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
- run: npm run build
- run: npx playwright install --with-deps chrome
- run: npx playwright install --with-deps --force chrome
- run: npm run ctest
env:
PWTEST_CHANNEL: chrome
@ -388,7 +388,7 @@ jobs:
env:
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
- run: npm run build
- run: npx playwright install --with-deps msedge
- run: npx playwright install --with-deps --force msedge
- run: npm run ctest
env:
PWTEST_CHANNEL: msedge
@ -414,7 +414,7 @@ jobs:
env:
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
- run: npm run build
- run: npx playwright install --with-deps msedge
- run: npx playwright install --with-deps --force msedge
- run: npm run ctest
shell: bash
env:
@ -438,7 +438,7 @@ jobs:
env:
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
- run: npm run build
- run: npx playwright install --with-deps msedge
- run: npx playwright install --with-deps --force msedge
- run: xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- npm run ctest
env:
PWTEST_CHANNEL: msedge
@ -463,7 +463,7 @@ jobs:
env:
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
- run: npm run build
- run: npx playwright install --with-deps msedge-beta
- run: npx playwright install --with-deps --force msedge-beta
- run: npm run ctest
env:
PWTEST_CHANNEL: msedge-beta
@ -488,7 +488,7 @@ jobs:
env:
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
- run: npm run build
- run: npx playwright install --with-deps msedge-beta
- run: npx playwright install --with-deps --force msedge-beta
- run: npm run ctest
shell: bash
env:
@ -512,7 +512,7 @@ jobs:
env:
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
- run: npm run build
- run: npx playwright install --with-deps msedge-beta
- run: npx playwright install --with-deps --force msedge-beta
- run: xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- npm run ctest
env:
PWTEST_CHANNEL: msedge-beta
@ -537,7 +537,7 @@ jobs:
env:
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
- run: npm run build
- run: npx playwright install --with-deps msedge-dev
- run: npx playwright install --with-deps --force msedge-dev
- run: npm run ctest
env:
PWTEST_CHANNEL: msedge-dev
@ -562,7 +562,7 @@ jobs:
env:
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
- run: npm run build
- run: npx playwright install --with-deps msedge-dev
- run: npx playwright install --with-deps --force msedge-dev
- run: npm run ctest
shell: bash
env:
@ -586,7 +586,7 @@ jobs:
env:
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
- run: npm run build
- run: npx playwright install --with-deps msedge-dev
- run: npx playwright install --with-deps --force msedge-dev
- run: xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- npm run ctest
env:
PWTEST_CHANNEL: msedge-dev
@ -611,7 +611,7 @@ jobs:
env:
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
- run: npm run build
- run: npx playwright install --with-deps chrome-beta
- run: npx playwright install --with-deps --force chrome-beta
- run: xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- npm run ctest
env:
PWTEST_CHANNEL: chrome-beta
@ -636,7 +636,7 @@ jobs:
env:
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
- run: npm run build
- run: npx playwright install --with-deps chrome-beta
- run: npx playwright install --with-deps --force chrome-beta
- run: npm run ctest
shell: bash
env:
@ -663,7 +663,7 @@ jobs:
env:
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
- run: npm run build
- run: npx playwright install --with-deps chrome-beta
- run: npx playwright install --with-deps --force chrome-beta
- run: npm run ctest
env:
PWTEST_CHANNEL: chrome-beta

View File

@ -113,13 +113,14 @@ program
.command('install [browser...]')
.description('ensure browsers necessary for this version of Playwright are installed')
.option('--with-deps', 'install system dependencies for browsers')
.action(async function(args: string[], options: { withDeps?: boolean }) {
.option('--force', 'force reinstall of stable browser channels')
.action(async function(args: string[], options: { withDeps?: boolean, force?: boolean }) {
try {
if (!args.length) {
const executables = registry.defaultExecutables();
if (options.withDeps)
await registry.installDeps(executables, false);
await registry.install(executables);
await registry.install(executables, false /* forceReinstall */);
} else {
const installDockerImage = args.some(arg => arg === 'docker-image');
args = args.filter(arg => arg !== 'docker-image');
@ -135,7 +136,7 @@ program
const executables = checkBrowsersToInstall(args);
if (options.withDeps)
await registry.installDeps(executables, false);
await registry.install(executables);
await registry.install(executables, !!options.force /* forceReinstall */);
}
} catch (e) {
console.log(`Failed to install browsers\n${e}`);

View File

@ -21,7 +21,7 @@ import * as util from 'util';
import * as fs from 'fs';
import lockfile from 'proper-lockfile';
import { getUbuntuVersion } from './ubuntuVersion';
import { getFromENV, getAsBooleanFromENV, calculateSha1, removeFolders, existsAsync, hostPlatform, canAccessFile, spawnAsync, fetchData, wrapInASCIIBox, transformCommandsForRoot } from './utils';
import { getFromENV, getAsBooleanFromENV, getClientLanguage, calculateSha1, removeFolders, existsAsync, hostPlatform, canAccessFile, spawnAsync, fetchData, wrapInASCIIBox, transformCommandsForRoot } from './utils';
import { DependencyGroup, installDependenciesLinux, installDependenciesWindows, validateDependenciesLinux, validateDependenciesWindows } from './dependencies';
import { downloadBrowserWithProgressBar, logPolitely } from './browserFetcher';
@ -254,6 +254,7 @@ export interface Executable {
interface ExecutableImpl extends Executable {
_install?: () => Promise<void>;
_dependencyGroup?: DependencyGroup;
_isHermeticInstallation?: boolean;
}
export class Registry {
@ -303,6 +304,7 @@ export class Registry {
validateHostRequirements: (sdkLanguage: string) => this._validateHostRequirements(sdkLanguage, 'chromium', chromium.dir, ['chrome-linux'], [], ['chrome-win']),
_install: () => this._downloadExecutable(chromium, chromiumExecutable, DOWNLOAD_PATHS['chromium'][hostPlatform], 'PLAYWRIGHT_CHROMIUM_DOWNLOAD_HOST'),
_dependencyGroup: 'chromium',
_isHermeticInstallation: true,
});
const chromiumWithSymbols = descriptors.find(d => d.name === 'chromium-with-symbols')!;
@ -318,6 +320,7 @@ export class Registry {
validateHostRequirements: (sdkLanguage: string) => this._validateHostRequirements(sdkLanguage, 'chromium', chromiumWithSymbols.dir, ['chrome-linux'], [], ['chrome-win']),
_install: () => this._downloadExecutable(chromiumWithSymbols, chromiumWithSymbolsExecutable, DOWNLOAD_PATHS['chromium-with-symbols'][hostPlatform], 'PLAYWRIGHT_CHROMIUM_DOWNLOAD_HOST'),
_dependencyGroup: 'chromium',
_isHermeticInstallation: true,
});
this._executables.push(this._createChromiumChannel('chrome', {
@ -401,6 +404,7 @@ export class Registry {
validateHostRequirements: (sdkLanguage: string) => this._validateHostRequirements(sdkLanguage, 'firefox', firefox.dir, ['firefox'], [], ['firefox']),
_install: () => this._downloadExecutable(firefox, firefoxExecutable, DOWNLOAD_PATHS['firefox'][hostPlatform], 'PLAYWRIGHT_FIREFOX_DOWNLOAD_HOST'),
_dependencyGroup: 'firefox',
_isHermeticInstallation: true,
});
const firefoxBeta = descriptors.find(d => d.name === 'firefox-beta')!;
@ -416,6 +420,7 @@ export class Registry {
validateHostRequirements: (sdkLanguage: string) => this._validateHostRequirements(sdkLanguage, 'firefox', firefoxBeta.dir, ['firefox'], [], ['firefox']),
_install: () => this._downloadExecutable(firefoxBeta, firefoxBetaExecutable, DOWNLOAD_PATHS['firefox-beta'][hostPlatform], 'PLAYWRIGHT_FIREFOX_DOWNLOAD_HOST'),
_dependencyGroup: 'firefox',
_isHermeticInstallation: true,
});
const webkit = descriptors.find(d => d.name === 'webkit')!;
@ -439,6 +444,7 @@ export class Registry {
validateHostRequirements: (sdkLanguage: string) => this._validateHostRequirements(sdkLanguage, 'webkit', webkit.dir, webkitLinuxLddDirectories, ['libGLESv2.so.2', 'libx264.so'], ['']),
_install: () => this._downloadExecutable(webkit, webkitExecutable, DOWNLOAD_PATHS['webkit'][hostPlatform], 'PLAYWRIGHT_WEBKIT_DOWNLOAD_HOST'),
_dependencyGroup: 'webkit',
_isHermeticInstallation: true,
});
const ffmpeg = descriptors.find(d => d.name === 'ffmpeg')!;
@ -454,6 +460,7 @@ export class Registry {
validateHostRequirements: () => Promise.resolve(),
_install: () => this._downloadExecutable(ffmpeg, ffmpegExecutable, DOWNLOAD_PATHS['ffmpeg'][hostPlatform], 'PLAYWRIGHT_FFMPEG_DOWNLOAD_HOST'),
_dependencyGroup: 'tools',
_isHermeticInstallation: true,
});
}
@ -491,6 +498,7 @@ export class Registry {
executablePathOrDie: (sdkLanguage: string) => executablePath(sdkLanguage, true)!,
installType: install ? 'install-script' : 'none',
validateHostRequirements: () => Promise.resolve(),
_isHermeticInstallation: false,
_install: install,
};
}
@ -548,7 +556,7 @@ export class Registry {
return await installDependenciesLinux(targets, dryRun);
}
async install(executablesToInstall: Executable[]) {
async install(executablesToInstall: Executable[], forceReinstall: boolean) {
const executables = this._addRequirementsAndDedupe(executablesToInstall);
await fs.promises.mkdir(registryDirectory, { recursive: true });
const lockfilePath = path.join(registryDirectory, '__dirlock');
@ -578,10 +586,29 @@ export class Registry {
// Install browsers for this package.
for (const executable of executables) {
if (executable._install)
await executable._install();
else
if (!executable._install)
throw new Error(`ERROR: Playwright does not support installing ${executable.name}`);
const { langName } = getClientLanguage();
if (!executable._isHermeticInstallation && !forceReinstall && executable.executablePath(langName)) {
const command = buildPlaywrightCLICommand(langName, 'install --force ' + executable.name);
throw new Error('\n' + wrapInASCIIBox([
`ATTENTION: "${executable.name}" is already installed on the system!`,
``,
`"${executable.name}" installation is not hermetic; installing newer version`,
`requires *removal* of a current installation first.`,
``,
`To *uninstall* current version and re-install latest "${executable.name}":`,
``,
`- Close all running instances of "${executable.name}", if any`,
`- Use "--force" to install browser:`,
``,
` ${command}`,
``,
`<3 Playwright Team`,
].join('\n'), 1));
}
await executable._install();
}
} catch (e) {
if (e.code === 'ELOCKED') {
@ -761,7 +788,7 @@ export async function installBrowsersForNpmInstall(browsers: string[]) {
executables.push(executable);
}
await registry.install(executables);
await registry.install(executables, false /* forceReinstall */);
}
export function findChromiumChannel(sdkLanguage: string): string | undefined {

View File

@ -479,6 +479,11 @@ function determineUserAgent(): string {
}
}
const { langName, langVersion } = getClientLanguage();
return `Playwright/${getPlaywrightVersion()} (${os.arch()}; ${osIdentifier} ${osVersion}) ${langName}/${langVersion}`;
}
export function getClientLanguage(): { langName: string, langVersion: string } {
let langName = 'unknown';
let langVersion = 'unknown';
if (!process.env.PW_LANG_NAME) {
@ -488,8 +493,7 @@ function determineUserAgent(): string {
langName = process.env.PW_LANG_NAME;
langVersion = process.env.PW_LANG_NAME_VERSION ?? 'unknown';
}
return `Playwright/${getPlaywrightVersion()} (${os.arch()}; ${osIdentifier} ${osVersion}) ${langName}/${langVersion}`;
return { langName, langVersion };
}
export function getPlaywrightVersion(majorMinorOnly = false) {