"""Print a version and prepare the artifacts for "avd" CIPD package.
This script has the following two functions:
* latest: Prints a version for 3pp framework to decide if creating a new CIPD
package or not. The version value is calculated by computing the sha256
hash of all the dependent artifacts. In this way, it is guaranteed that a
new version will be generated if any of the dependencies get changed.
* checkout: Prepares the dependent artifacts for 3pp framework to package and
upload to CIPD by copying all the dependencies to a temporary checkout path
created by 3pp framework.
This script is normally called by 3pp framework from chromium_3pp recipe module.
"""
import argparse
import hashlib
import os
import re
import shutil
import subprocess
_SRC_PATH = os.path.abspath(
os.path.join(os.path.dirname(__file__), os.path.pardir, os.path.pardir,
os.path.pardir, os.path.pardir))
_BASE_DEPS = [
'.vpython3',
'third_party/android_sdk/public/cmdline-tools/',
'third_party/android_sdk/public/platform-tools/',
'tools/android/avd/proto/',
'build/android/devil_chromium.json',
'third_party/catapult/devil/devil/devil_dependencies.json',
'third_party/catapult/third_party/gsutil/',
'build/config/gclient_args.gni',
]
def _file_hash(sha, rel_path, base_path):
path = os.path.join(base_path, rel_path)
with open(path, 'rb') as f:
sha.update(str(len(rel_path)).encode('utf-8'))
sha.update(rel_path.encode('utf-8'))
while True:
f_stream = f.read(4096)
if not f_stream:
break
sha.update(str(len(f_stream)).encode('utf-8'))
sha.update(f_stream)
def _compute_hash_paths(base_path, *rel_paths):
sha = hashlib.sha256()
for rel_path in rel_paths:
path = os.path.join(base_path, rel_path)
if os.path.isfile(path):
_file_hash(sha, rel_path, base_path)
elif os.path.isdir(path):
for root, dirs, files in os.walk(path, topdown=True):
dirs.sort()
files.sort()
for f_name in files:
f_path = os.path.join(root, f_name)
if os.path.isfile(f_path):
rel_file_path = os.path.relpath(f_path, base_path)
_file_hash(sha, rel_file_path, base_path)
return sha.hexdigest()
def _get_deps(chromium_src_path):
deps_cmds = [
os.path.join(chromium_src_path, 'build', 'print_python_deps.py'),
'--root',
chromium_src_path,
os.path.join(chromium_src_path, 'tools', 'android', 'avd', 'avd.py'),
]
deps_output = subprocess.check_output(deps_cmds, universal_newlines=True)
deps_lines = deps_output.strip().split('\n')
deps_entries = [dep for dep in deps_lines if not dep.startswith('#')]
return sorted(_BASE_DEPS + deps_entries)
def do_latest():
deps = _get_deps(_SRC_PATH)
print(_compute_hash_paths(_SRC_PATH, *deps))
def do_checkout(checkout_path):
deps = _get_deps(_SRC_PATH)
for dep in deps:
dep_pieces = dep.split('/')
chromium_dep_path = os.path.join(_SRC_PATH, *dep_pieces)
checkout_dep_path = os.path.join(checkout_path, 'src', *dep_pieces)
checkout_dep_par_path = os.path.abspath(
os.path.join(checkout_dep_path, os.path.pardir))
if not os.path.exists(checkout_dep_par_path):
os.makedirs(checkout_dep_par_path)
if os.path.exists(checkout_dep_path):
continue
if os.path.isdir(chromium_dep_path):
shutil.copytree(chromium_dep_path, checkout_dep_path, symlinks=True)
else:
shutil.copy(chromium_dep_path, checkout_dep_path)
def main():
ap = argparse.ArgumentParser(
description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
sub = ap.add_subparsers()
latest = sub.add_parser("latest")
latest.set_defaults(func=lambda _opts: do_latest())
checkout = sub.add_parser("checkout")
checkout.add_argument("checkout_path")
checkout.set_defaults(func=lambda opts: do_checkout(opts.checkout_path))
opts = ap.parse_args()
opts.func(opts)
if __name__ == '__main__':
main()