blob: 4e8583f1a382661e56b0478d82971b4ca4ec4f27 [file] [log] [blame]
#!/usr/bin/env python2.7
#
# Copyright (C) 2018 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
"""Invoke trusty build system and run tests."""
import argparse
import multiprocessing
import os
import shutil
import subprocess
import sys
import run_tests
import trusty_build_config
script_dir = os.path.dirname(os.path.abspath(__file__))
def get_new_build_id(build_root):
"""Increment build-id file and return new build-id number."""
path = os.path.join(build_root, "BUILDID")
try:
with open(path, "r") as f:
num = int(f.read()) + 1
except IOError:
num = 1
with open(path, "w") as f:
f.write(str(num))
f.truncate()
# Return buildid string: <user>@<hostname>-<num>
return os.getlogin() + "@" + os.uname()[1] + "-" + str(num)
def mkdir(path):
"""Create directory includig parents if it does not already exist."""
try:
os.makedirs(path)
except OSError:
if not os.path.isdir(path):
raise
def copy_file(src, dest, optional=False):
"""Copy a file.
Copy a file or exit if the file cannot be copied.
Args:
src: Path of file to copy.
dest: Path to copy file to.
optional: Optional boolean argument. If True don't exit if source file
does not exist.
"""
if not os.path.exists(src) and optional:
return
print "Copy:", repr(src), "->", repr(dest)
shutil.copy(src, dest)
def archive_build_file(args, project, src, dest=None, optional=False):
"""Copy a file to build archive directory.
Construct src and dest path and call copy_file.
Args:
args: Program arguments.
project: Project name.
src: Source path relative to project build dir.
dest: Optional dest path relative to archive dir. Can be ommitted if src
is a simple filename.
optional: Optional boolean argument. If True don't exit if source file
does not exist.
"""
if not dest:
dest = src
src = os.path.join(args.build_root, "build-" + project, src)
dest = os.path.join(args.archive, project + "-" + args.buildid + "." + dest)
copy_file(src, dest, optional=optional)
def build(args):
"""Call build system and copy build files to archive dir."""
mkdir(args.build_root)
mkdir(args.archive)
if args.buildid is None:
args.buildid = get_new_build_id(args.build_root)
print "BuildID", args.buildid
# build projects
failed = []
for project in args.project:
cmd = "source " + os.path.join(script_dir, "envsetup.sh")
cmd += "; export BUILDROOT=" + args.build_root
cmd += "; export BUILDID=" + args.buildid
cmd += "; nice make " + project + " -j " + str(args.jobs)
status = subprocess.call(cmd, shell=True, executable="/bin/bash")
print "cmd: '" + cmd + "' returned", status
if status:
failed.append(project)
if failed:
print
print "some projects have failed to build:"
print str(failed)
exit(1)
# Copy the files we care about to the archive directory
for project in args.project:
# copy out tos.img if it exists
archive_build_file(args, project, "tos.img", optional=True)
# copy out monitor if it exists
archive_build_file(args, project, "monitor/monitor.bin", "monitor.bin",
optional=True)
# copy out lk image
archive_build_file(args, project, "lk.bin")
# collect and save all .lst
subprocess.call("cd " +
os.path.join(args.build_root, "build-" + project) +
';find . -name "*.lst" -print ' +
"| zip " + os.path.join(args.archive, project + "-" +
args.buildid + ".lst.zip") +
" -@", shell=True, executable="/bin/bash")
def main():
top = os.path.abspath(os.path.join(script_dir, "../../../../.."))
os.chdir(top)
parser = argparse.ArgumentParser()
parser.add_argument("project", type=str, nargs="*", default=[".test.all"],
help="Project to build and/or test.")
parser.add_argument("--build-root", type=str,
default=os.path.join(top, "build-root"),
help="Root of intermediate build directory.")
parser.add_argument("--archive", type=str, default=None,
help="Location of build results directory.")
parser.add_argument("--buildid", type=str, help="Server build id")
parser.add_argument("--jobs", type=str, default=multiprocessing.cpu_count(),
help="Max number of build jobs.")
parser.add_argument("--skip-build", action="store_true", help="Skip build.")
parser.add_argument("--skip-tests", action="store_true",
help="Skip running tests.")
args = parser.parse_args()
if args.archive is None:
args.archive = os.path.join(args.build_root, "archive")
build_config = trusty_build_config.TrustyBuildConfig()
projects = []
for project in args.project:
if project == ".test.all":
projects += build_config.get_projects(build=True)
elif project == ".test":
projects += build_config.get_projects(build=True, have_tests=True)
else:
projects.append(project)
args.project = projects
print "Projects", str(projects)
if args.skip_build:
print "Skip build for", args.project
else:
build(args)
# Run tests
if not args.skip_tests:
test_failed = []
test_results = []
for project in projects:
test_result = run_tests.run_tests(build_config, args.build_root,
project)
if not test_result.passed:
test_failed.append(project)
test_results.append(test_result)
for test_result in test_results:
test_result.print_results()
if test_failed:
sys.stdout.flush()
sys.stderr.write("\n")
sys.stderr.write(str(len(test_failed)) +
" projects have failed tests:\n")
sys.stderr.write(str(test_failed) + "\n")
exit(1)
if __name__ == "__main__":
main()