Skip to content

Instantly share code, notes, and snippets.

@fy0
Created August 10, 2020 11:58
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fy0/9ad489b9d8e7070ad82bdfbfabcc7f8c to your computer and use it in GitHub Desktop.
Save fy0/9ad489b9d8e7070ad82bdfbfabcc7f8c to your computer and use it in GitHub Desktop.
ungoogled-chromium-performance-test
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright (c) 2019 The ungoogled-chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""
ungoogled-chromium build script for Microsoft Windows
"""
import os
import time
import sys
if sys.version_info.major < 3 or sys.version_info.minor < 6:
raise RuntimeError('Python 3.6+ is required for this script. You have: {}.{}'.format(
sys.version_info.major, sys.version_info.minor))
import argparse
import os
import re
import shutil
import subprocess
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent / 'ungoogled-chromium' / 'utils'))
import downloads
import domain_substitution
import prune_binaries
import patches
from _common import ENCODING, USE_REGISTRY, ExtractorEnum, get_logger
sys.path.pop(0)
_ROOT_DIR = Path(__file__).resolve().parent
_PATCH_BIN_RELPATH = Path('third_party/git/usr/bin/patch.exe')
def _get_vcvars_path(name='64'):
"""
Returns the path to the corresponding vcvars*.bat path
As of VS 2017, name can be one of: 32, 64, all, amd64_x86, x86_amd64
"""
vswhere_exe = '%ProgramFiles(x86)%\\Microsoft Visual Studio\\Installer\\vswhere.exe'
result = subprocess.run(
'"{}" -latest -property installationPath'.format(vswhere_exe),
shell=True,
check=True,
stdout=subprocess.PIPE,
universal_newlines=True)
vcvars_path = Path(result.stdout.strip(), 'VC/Auxiliary/Build/vcvars{}.bat'.format(name))
if not vcvars_path.exists():
raise RuntimeError(
'Could not find vcvars batch script in expected location: {}'.format(vcvars_path))
return vcvars_path
def _run_build_process(*args, **kwargs):
"""
Runs the subprocess with the correct environment variables for building
"""
# Add call to set VC variables
cmd_input = ['call "%s" >nul' % _get_vcvars_path()]
cmd_input.append('set DEPOT_TOOLS_WIN_TOOLCHAIN=0')
cmd_input.append(' '.join(map('"{}"'.format, args)))
cmd_input.append('exit\n')
subprocess.run(('cmd.exe', '/k'),
input='\n'.join(cmd_input),
check=True,
encoding=ENCODING,
**kwargs)
def _test_python2(error_exit):
"""
Tests if Python 2 is setup with the proper requirements
"""
python2_exe = shutil.which('python')
if not python2_exe:
error_exit('Could not find "python" in PATH')
# Check Python version is at least 2.7.9 to avoid exec issues
result = subprocess.run((python2_exe, '--version'),
stderr=subprocess.PIPE,
check=True,
universal_newlines=True)
match = re.search(r'Python 2\.7\.([0-9]+)', result.stderr.strip())
if not match:
error_exit('Could not detect Python 2 version from output: {}'.format(
result.stdout.strip()))
if int(match.group(1)) < 9:
error_exit('At least Python 2.7.9 is required; found 2.7.{}'.format(match.group(1)))
# Check for pypiwin32 module
result = subprocess.run((python2_exe, '-c', 'import win32api'))
if result.returncode:
error_exit('Unable to find pypiwin32 module in Python 2 installation.')
def _make_tmp_paths():
"""Creates TMP and TEMP variable dirs so ninja won't fail"""
tmp_path = Path(os.environ['TMP'])
if not tmp_path.exists():
tmp_path.mkdir()
tmp_path = Path(os.environ['TEMP'])
if not tmp_path.exists():
tmp_path.mkdir()
def write_time(txt):
os.system('echo %s at %s >> log.txt' % (txt, time.time()))
def main():
"""CLI Entrypoint"""
write_time('boot')
write_time('patch done')
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument(
'--disable-ssl-verification',
action='store_true',
help='Disables SSL verification for downloading')
parser.add_argument(
'--7z-path',
dest='sevenz_path',
default=USE_REGISTRY,
help=('Command or path to 7-Zip\'s "7z" binary. If "_use_registry" is '
'specified, determine the path from the registry. Default: %(default)s'))
parser.add_argument(
'--winrar-path',
dest='winrar_path',
default=USE_REGISTRY,
help=('Command or path to WinRAR\'s "winrar.exe" binary. If "_use_registry" is '
'specified, determine the path from the registry. Default: %(default)s'))
args = parser.parse_args()
# Set common variables
source_tree = _ROOT_DIR / 'build' / 'src'
downloads_cache = _ROOT_DIR / 'build' / 'downloads_cache'
domsubcache = _ROOT_DIR / 'build' / 'domsubcache.tar.gz'
# Test environment
_test_python2(parser.error)
# Setup environment
source_tree.mkdir(parents=True, exist_ok=True)
downloads_cache.mkdir(parents=True, exist_ok=True)
_make_tmp_paths()
# Get download metadata (DownloadInfo)
download_info = downloads.DownloadInfo([
_ROOT_DIR / 'downloads.ini',
_ROOT_DIR / 'ungoogled-chromium' / 'downloads.ini',
])
# Retrieve downloads
get_logger().info('Downloading required files...')
downloads.retrieve_downloads(download_info, downloads_cache, True,
args.disable_ssl_verification)
try:
downloads.check_downloads(download_info, downloads_cache)
except downloads.HashMismatchError as exc:
get_logger().error('File checksum does not match: %s', exc)
exit(1)
# Unpack downloads
extractors = {
ExtractorEnum.SEVENZIP: args.sevenz_path,
ExtractorEnum.WINRAR: args.winrar_path,
}
get_logger().info('Unpacking downloads...')
write_time('unpack')
downloads.unpack_downloads(download_info, downloads_cache, source_tree, extractors)
write_time('unpack done')
# Prune binaries
unremovable_files = prune_binaries.prune_dir(
source_tree,
(_ROOT_DIR / 'ungoogled-chromium' / 'pruning.list').read_text(encoding=ENCODING).splitlines()
)
if unremovable_files:
get_logger().error('Files could not be pruned: %s', unremovable_files)
parser.exit(1)
write_time('patch')
# Apply patches
# First, ungoogled-chromium-patches
patches.apply_patches(
patches.generate_patches_from_series(_ROOT_DIR / 'ungoogled-chromium' / 'patches', resolve=True),
source_tree,
patch_bin_path=(source_tree / _PATCH_BIN_RELPATH)
)
# Then Windows-specific patches
patches.apply_patches(
patches.generate_patches_from_series(_ROOT_DIR / 'patches', resolve=True),
source_tree,
patch_bin_path=(source_tree / _PATCH_BIN_RELPATH)
)
# Substitute domains
domain_substitution.apply_substitution(
_ROOT_DIR / 'ungoogled-chromium' / 'domain_regex.list',
_ROOT_DIR / 'ungoogled-chromium' / 'domain_substitution.list',
source_tree,
domsubcache
)
write_time('patch done')
# Output args.gn
(source_tree / 'out/Default').mkdir(parents=True)
gn_flags = (_ROOT_DIR / 'ungoogled-chromium' / 'flags.gn').read_text(encoding=ENCODING)
gn_flags += '\n'
gn_flags += (_ROOT_DIR / 'flags.windows.gn').read_text(encoding=ENCODING)
(source_tree / 'out/Default/args.gn').write_text(gn_flags, encoding=ENCODING)
# Enter source tree to run build commands
os.chdir(source_tree)
# Run GN bootstrap
write_time('gn bootstrap')
_run_build_process(
shutil.which('python'), 'tools\\gn\\bootstrap\\bootstrap.py', '-o', 'out\\Default\\gn.exe',
'--skip-generate-buildfiles')
write_time('gn bootstrap done')
# Run gn gen
write_time('gn gen')
_run_build_process('out\\Default\\gn.exe', 'gen', 'out\\Default', '--fail-on-unused-args')
write_time('gn gen done')
# Run ninja
write_time('build')
_run_build_process('third_party\\ninja\\ninja.exe', '-C', 'out\\Default', 'chrome',
'chromedriver', 'mini_installer')
write_time('build done')
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment