blob: 1b6bb7e895a45a54d82db59aedcc8162e77751d5 [file] [edit]
#!/usr/bin/env python3
# Copyright (c) 2026, the R8 project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
import argparse
import json
import os
import shutil
import stat
import sys
import tempfile
import urllib.request
import zipfile
import utils
VERSION = "148.0.7778.96" # Default version, but can be overridden
API_URL = "https://googlechromelabs.github.io/chrome-for-testing/last-known-good-versions-with-downloads.json"
def get_latest_stable_version():
print("Fetching latest stable Chrome version from googlechromelabs...")
try:
req = urllib.request.Request(API_URL,
headers={'User-Agent': 'Mozilla/5.0'})
with urllib.request.urlopen(req) as response:
data = json.loads(response.read().decode('utf-8'))
channel_data = data.get("channels", {}).get("Stable")
if channel_data:
return channel_data.get("version")
except Exception as e:
print(f"Failed to fetch latest version: {e}")
return None
def parse_options():
parser = argparse.ArgumentParser(
description=
'Update chrome-headless-shell binaries for Playwright in third_party.')
parser.add_argument(
'--version',
help=
f'Chrome version to download. If not specified and --latest is not used, defaults to {VERSION}.'
)
parser.add_argument(
'--latest',
action='store_true',
help='Download the latest stable version of chrome-headless-shell.')
return parser.parse_args()
def download_and_extract(name, url, extract_to):
with tempfile.TemporaryDirectory() as tmpdir:
zip_path = os.path.join(tmpdir, f"{name}.zip")
print(f"Downloading {url} to {zip_path}...")
try:
urllib.request.urlretrieve(url, zip_path)
except Exception as e:
print(f"Failed to download {url}: {e}")
return False
print(f"Extracting {zip_path} to {tmpdir}...")
with zipfile.ZipFile(zip_path, 'r') as zip_ref:
zip_ref.extractall(tmpdir)
# Chrome zip usually contains a single top-level directory
zip_dirs = [
d for d in os.listdir(tmpdir)
if os.path.isdir(os.path.join(tmpdir, d))
]
if not zip_dirs:
print(f"No directory found in zip for {name}")
return False
src_dir = os.path.join(tmpdir, zip_dirs[0])
print(f"Moving contents of {src_dir} to {extract_to}...")
os.makedirs(extract_to, exist_ok=True)
for item in os.listdir(src_dir):
s = os.path.join(src_dir, item)
d = os.path.join(extract_to, item)
if os.path.exists(d):
if os.path.isdir(d):
shutil.rmtree(d)
else:
os.remove(d)
shutil.move(s, d)
return True
def set_executable(file_path):
if os.path.exists(file_path):
print(f"Making {file_path} executable...")
st = os.stat(file_path)
os.chmod(file_path,
st.st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
else:
print(f"Warning: File {file_path} not found to set executable.")
def main():
args = parse_options()
version = args.version
if args.latest:
version = get_latest_stable_version()
if not version:
print("Error: Could not retrieve latest stable version.")
sys.exit(1)
elif not version:
version = VERSION
print(f"Using Chrome version: {version}")
base_url = f"https://storage.googleapis.com/chrome-for-testing-public/{version}"
urls = {
"linux":
f"{base_url}/linux64/chrome-headless-shell-linux64.zip",
"mac-arm64":
f"{base_url}/mac-arm64/chrome-headless-shell-mac-arm64.zip",
"mac-x64":
f"{base_url}/mac-x64/chrome-headless-shell-mac-x64.zip",
"windows":
f"{base_url}/win64/chrome-headless-shell-win64.zip"
}
chrome_headless_dir = os.path.join(utils.THIRD_PARTY, 'chrome_headless')
linux_dir = os.path.join(chrome_headless_dir, 'linux')
mac_dir = os.path.join(chrome_headless_dir, 'mac')
mac_arm_dir = os.path.join(mac_dir, 'mac-arm64')
mac_x64_dir = os.path.join(mac_dir, 'mac-x64')
windows_dir = os.path.join(chrome_headless_dir, 'windows')
# Clean up existing directories if they exist
for d in [linux_dir, mac_dir, windows_dir]:
if os.path.exists(d):
print(f"Removing existing directory {d}...")
shutil.rmtree(d)
# 1. Linux
if download_and_extract("linux", urls["linux"], linux_dir):
set_executable(os.path.join(linux_dir, "chrome-headless-shell"))
# 2. Mac
download_arm = download_and_extract("mac-arm64", urls["mac-arm64"],
mac_arm_dir)
download_x64 = download_and_extract("mac-x64", urls["mac-x64"], mac_x64_dir)
if download_arm and download_x64:
set_executable(os.path.join(mac_arm_dir, "chrome-headless-shell"))
set_executable(os.path.join(mac_x64_dir, "chrome-headless-shell"))
# 3. Windows
download_and_extract("windows", urls["windows"], windows_dir)
print("\nLocal setup complete.")
print("If you want to upload these to Google Storage, run:")
print(
f" (cd {chrome_headless_dir}; upload_to_google_storage.py -a --bucket r8-deps linux)"
)
print(
f" (cd {chrome_headless_dir}; upload_to_google_storage.py -a --bucket r8-deps mac)"
)
print(
f" (cd {chrome_headless_dir}; upload_to_google_storage.py -a --bucket r8-deps windows)"
)
if __name__ == '__main__':
sys.exit(main())