scripts: Add build script
Add script to invoke trusty build system and run tests.
Bug: 117282103
Change-Id: I462e4b08d9427360728821d842f740a9b8f50c15
diff --git a/scripts/build.py b/scripts/build.py
new file mode 100755
index 0000000..e77ec55
--- /dev/null
+++ b/scripts/build.py
@@ -0,0 +1,210 @@
+#!/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)
+
+ # 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")
+
+ if args.buildid is None:
+ args.buildid = get_new_build_id(args.build_root)
+ print "BuildID", args.buildid
+
+ 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()