#!/usr/bin/python2.4 # # # Copyright 2009, 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. """Utility to create Android project files for tests.""" # python imports import datetime import optparse import os import string import sys # local imports import android_mk import android_manifest class TestsConsts(object): """Constants for test Android.mk and AndroidManifest.xml creation.""" MK_BUILD_INCLUDE = "call all-makefiles-under,$(LOCAL_PATH)" MK_BUILD_STRING = "\ninclude $(%s)\n" % MK_BUILD_INCLUDE TEST_MANIFEST_TEMPLATE = """ """ TEST_MK_TEMPLATE = """LOCAL_PATH := $$(call my-dir) include $$(CLEAR_VARS) LOCAL_MODULE_TAGS := tests LOCAL_JAVA_LIBRARIES := android.test.runner LOCAL_SRC_FILES := $$(call all-java-files-under, src) LOCAL_PACKAGE_NAME := ${MODULE_NAME}Tests${CERTIFICATE} LOCAL_INSTRUMENTATION_FOR := ${MODULE_NAME} LOCAL_SDK_VERSION := current include $$(BUILD_PACKAGE) """ TESTS_FOLDER = "tests" def _GenerateTestManifest(manifest, module_name, mapping=None): """Create and populate tests/AndroidManifest.xml with variable values from Android.mk and AndroidManifest.xml. Does nothing if tests/AndroidManifest.xml already exists. Args: manifest: AndroidManifest object for application manifest module_name: module name used for labelling mapping: optional user defined mapping of variable values, replaces values extracted from AndroidManifest.xml Raises: IOError: tests/AndroidManifest.xml cannot be opened for writing """ # skip if file already exists tests_path = "%s/%s" % (manifest.GetAppPath(), TestsConsts.TESTS_FOLDER) tests_manifest_path = "%s/%s" % (tests_path, manifest.FILENAME) if os.path.exists(tests_manifest_path): _PrintMessage("%s already exists, not overwritten" % tests_manifest_path) return if not mapping: package_name = manifest.GetPackageName() mapping = {"PACKAGE_NAME":package_name, "MODULE_NAME":module_name, "YEAR":datetime.date.today().year} output = string.Template(TestsConsts.TEST_MANIFEST_TEMPLATE).substitute(mapping) # create tests folder if not existent if not os.path.exists(tests_path): os.mkdir(tests_path) # write tests/AndroidManifest.xml tests_manifest = open(tests_manifest_path, mode="w") tests_manifest.write(output) tests_manifest.close() _PrintMessage("Created %s" % tests_manifest_path) def _GenerateTestMK(mk, app_path, mapping=None): """Create and populate tests/Android.mk with variable values from Android.mk. Does nothing if tests/Android.mk already exists. Args: mk: AndroidMK object for application makefile app_path: path to the application being tested mapping: optional user defined mapping of variable values, replaces values stored in mk Raises: IOError: tests/Android.mk cannot be opened for writing """ # skip if file already exists tests_path = "%s/%s" % (app_path, TestsConsts.TESTS_FOLDER) tests_mk_path = "%s/%s" % (tests_path, mk.FILENAME) if os.path.exists(tests_mk_path): _PrintMessage("%s already exists, not overwritten" % tests_mk_path) return # append test build if not existent in makefile if not mk.HasInclude(TestsConsts.MK_BUILD_INCLUDE): mk_path = "%s/%s" % (app_path, mk.FILENAME) mk_file = open(mk_path, mode="a") mk_file.write(TestsConsts.MK_BUILD_STRING) mk_file.close() # construct tests/Android.mk # include certificate definition if existent in makefile certificate = mk.GetVariable(mk.CERTIFICATE) if certificate: cert_definition = ("\n%s := %s" % (mk.CERTIFICATE, certificate)) else: cert_definition = "" if not mapping: module_name = mk.GetVariable(mk.PACKAGE_NAME) mapping = {"MODULE_NAME":module_name, "CERTIFICATE":cert_definition} output = string.Template(TestsConsts.TEST_MK_TEMPLATE).substitute(mapping) # create tests folder if not existent if not os.path.exists(tests_path): os.mkdir(tests_path) # write tests/Android.mk to disk tests_mk = open(tests_mk_path, mode="w") tests_mk.write(output) tests_mk.close() _PrintMessage("Created %s" % tests_mk_path) def _ParseArgs(argv): """Parse the command line arguments. Args: argv: the list of command line arguments Returns: a tuple of options and individual command line arguments. """ parser = optparse.OptionParser(usage="%s " % sys.argv[0]) options, args = parser.parse_args(argv) if len(args) < 1: _PrintError("Error: Incorrect syntax") parser.print_usage() sys.exit() return (options, args) def _PrintMessage(msg): print >> sys.stdout, msg def _PrintError(msg): print >> sys.stderr, msg def _ValidateInputFiles(mk, manifest): """Verify that required variables are defined in input files. Args: mk: AndroidMK object for application makefile manifest: AndroidManifest object for application manifest Raises: RuntimeError: mk does not define LOCAL_PACKAGE_NAME or manifest does not define package variable """ module_name = mk.GetVariable(mk.PACKAGE_NAME) if not module_name: raise RuntimeError("Variable %s missing from %s" % (mk.PACKAGE_NAME, mk.FILENAME)) package_name = manifest.GetPackageName() if not package_name: raise RuntimeError("Variable package missing from %s" % manifest.FILENAME) def main(argv): options, args = _ParseArgs(argv) app_path = args[0]; if not os.path.exists(app_path): _PrintError("Error: Application path %s not found" % app_path) sys.exit() try: mk = android_mk.CreateAndroidMK(path=app_path) manifest = android_manifest.AndroidManifest(app_path=app_path) _ValidateInputFiles(mk, manifest) module_name = mk.GetVariable(mk.PACKAGE_NAME) _GenerateTestMK(mk, app_path) _GenerateTestManifest(manifest, module_name) except Exception, e: _PrintError("Error: %s" % e) _PrintError("Error encountered, script aborted") sys.exit() src_path = app_path + "/tests/src" if not os.path.exists(src_path): os.mkdir(src_path) if __name__ == "__main__": main(sys.argv[1:])