#!/usr/bin/env python3
# Copyright 2024 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import argparse
import datetime
import hashlib
import json
import os
import pathlib
import shutil
import sys
import tarfile
import urllib
import urllib.parse
import urllib.request
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
import bidimapper.append_notices as notices
_ALLOWED_LICENSES = [
# Regular valid open source licenses supported by Google.
'MIT',
'Apache-2.0',
'Apache 2.0',
'ISC',
]
_DEPENDENCY_DIVIDER = '-------------------- DEPENDENCY DIVIDER --------------------'
class RollerException(Exception):
pass
def get_chromium_dir() -> pathlib.Path:
return pathlib.Path(__file__).parent.parent.parent
def get_pinned_version(bidimapper_dir : pathlib.Path):
readme_path = bidimapper_dir / 'README.chromium'
if not readme_path.exists():
raise RollerException(f'File not found: {readme_path}')
with pathlib.Path(readme_path).open('r') as f:
for line in f.readlines():
prefix = 'Version:'
if line.startswith(_DEPENDENCY_DIVIDER):
# Avoid picking the version from a dependency
break
if not line.startswith(prefix):
continue
return line[len(prefix):].strip()
raise RollerException(f'Version not found in {readme_path}')
def main(chromium_src_dir: pathlib.Path, version: str):
bidimapper_dir = chromium_src_dir / 'third_party' / 'bidimapper'
readme_template_path = bidimapper_dir / 'README.chromium.in'
if not readme_template_path.exists():
print(f'File not found: {readme_template_path}', file=sys.stderr)
return 1
package_json = json.load(
urllib.request.urlopen(
f'https://registry.npmjs.org/chromium-bidi/{version}'))
git_revision = package_json['gitHead']
tarball_url = package_json['dist']['tarball']
# The script allows 'latest' as the valid value for the version argument.
# The line below obtains the actual version of the package.
version = package_json['version']
expected_sha1 = package_json['dist']['shasum']
pinned_version = get_pinned_version(bidimapper_dir)
if version == pinned_version:
print('BiDiMapper is already of the latest version', file=sys.stderr)
return 0
bidimapper_checkout_dir = bidimapper_dir / 'src'
if bidimapper_checkout_dir.exists():
shutil.rmtree(bidimapper_checkout_dir)
bidimapper_checkout_dir.mkdir()
tar_path = bidimapper_checkout_dir / 'chromium-bidi.tgz'
urllib.request.urlretrieve(url=tarball_url, filename=tar_path)
sha1 = hashlib.sha1()
sha1.update(tar_path.read_bytes())
actual_sha1 = sha1.hexdigest()
if actual_sha1 != expected_sha1:
print(
f'The NPM package checksum mismatch {actual_sha1} vs. {expected_sha1}',
file=sys.stderr)
return 1
with tarfile.open(tar_path) as tar:
tar.extract('package/lib/iife/mapperTab.js', path=bidimapper_checkout_dir)
tar.extract('package/lib/THIRD_PARTY_NOTICES', path=bidimapper_checkout_dir)
src_mapper_path = bidimapper_checkout_dir/ 'package' / 'lib' / 'iife' / 'mapperTab.js'
if not src_mapper_path.exists():
print(f'File not found: {src_mapper_path}', file=sys.stderr)
return 1
dest_mapper_path = bidimapper_dir / 'mapper.js'
try:
shutil.copy(src_mapper_path, dest_mapper_path)
except Exception as err:
print(
f'Error while copying {src_mapper_path} to {dest_mapper_path}: {err}'
)
return 1
sha512 = hashlib.sha512()
sha512.update(pathlib.Path(dest_mapper_path).read_bytes())
sha512sum = sha512.hexdigest()
src_notices_path = bidimapper_checkout_dir / 'package' / 'lib' / 'THIRD_PARTY_NOTICES'
if not src_notices_path.exists():
print(f'File not found: {src_notices_path}', file=sys.stderr)
return 1
with src_notices_path.open('r') as f:
for line in f.readlines():
prefix = 'License:'
if not line.startswith(prefix):
continue
license = line[len(prefix):].strip()
if license not in _ALLOWED_LICENSES:
print(f'Unsupported license type: {license}', file=sys.stderr)
return 1
readme_template = readme_template_path.read_text()
readme_template = readme_template.replace('${VERSION}', version)
readme_template = readme_template.replace('${URL}', tarball_url)
readme_template = readme_template.replace(
'${DATE}',
datetime.date.today().isoformat())
readme_template = readme_template.replace('${REVISION}', git_revision)
readme_template = readme_template.replace('${TAR-SHA512}', sha512sum)
readme_path = bidimapper_dir / 'README.chromium'
with pathlib.Path(readme_path).open('w') as readme_out:
readme_out.write(readme_template)
license_dir = bidimapper_dir / 'licenses'
try:
notice_parser = notices.ThirdPartyNoticeParser(src_notices_path,
readme_path=readme_path,
license_dir=license_dir)
notice_parser.parse_and_append_notices()
except Exception as ex:
print('Failed to append notices: %s' % (ex), file=sys.stderr)
return 1
return 0
if __name__ == '__main__':
parser = argparse.ArgumentParser(
description='Switch ChromeDriver to a different BiDiMapper version')
parser.add_argument('--chromium-source-dir',
type=pathlib.Path,
default=get_chromium_dir(),
help='Directory with Chromium repository checkout')
parser.add_argument('--version',
metavar='VERSION',
default='latest',
help='BiDiMapper version (default: latest)')
args = parser.parse_args()
sys.exit(main(args.chromium_source_dir, args.version))