1c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org#!/usr/bin/env python
2c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org#
3c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org# Copyright 2012 the V8 project authors. All rights reserved.
4c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org# Redistribution and use in source and binary forms, with or without
5c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org# modification, are permitted provided that the following conditions are
6c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org# met:
7c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org#
8c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org#     * Redistributions of source code must retain the above copyright
9c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org#       notice, this list of conditions and the following disclaimer.
10c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org#     * Redistributions in binary form must reproduce the above
11c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org#       copyright notice, this list of conditions and the following
12c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org#       disclaimer in the documentation and/or other materials provided
13c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org#       with the distribution.
14c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org#     * Neither the name of Google Inc. nor the names of its
15c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org#       contributors may be used to endorse or promote products derived
16c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org#       from this software without specific prior written permission.
17c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org#
18c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org
30c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org# This script executes the passed command line on Android device
31c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org# using 'adb shell' command. Unfortunately, 'adb shell' always
32c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org# returns exit code 0, ignoring the exit code of executed command.
33c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org# Since we need to return non-zero exit code if the command failed,
34c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org# we augment the passed command line with exit code checking statement
35c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org# and output special error string in case of non-zero exit code.
36c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org# Then we parse the output of 'adb shell' and look for that error string.
37c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org
38c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.orgimport os
39c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.orgfrom os.path import join, dirname, abspath
40c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.orgimport subprocess
41c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.orgimport sys
42c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.orgimport tempfile
43c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org
44c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.orgdef Check(output, errors):
45304cc33f8259ef467e8e3c79f448d0bae0e8cd85yangguo@chromium.org  failed = any([s.startswith('/system/bin/sh:') or s.startswith('ANDROID')
46c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org                for s in output.split('\n')])
47c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org  return 1 if failed else 0
48c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org
49c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.orgdef Execute(cmdline):
50c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org  (fd_out, outname) = tempfile.mkstemp()
51c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org  (fd_err, errname) = tempfile.mkstemp()
52c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org  process = subprocess.Popen(
53c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org    args=cmdline,
54c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org    shell=True,
55c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org    stdout=fd_out,
56c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org    stderr=fd_err,
57c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org  )
58c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org  exit_code = process.wait()
59c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org  os.close(fd_out)
60c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org  os.close(fd_err)
61c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org  output = file(outname).read()
62c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org  errors = file(errname).read()
63c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org  os.unlink(outname)
64c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org  os.unlink(errname)
65c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org  sys.stdout.write(output)
66c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org  sys.stderr.write(errors)
67c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org  return exit_code or Check(output, errors)
68c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org
69c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.orgdef Escape(arg):
70c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org  def ShouldEscape():
71c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org    for x in arg:
72c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org      if not x.isalnum() and x != '-' and x != '_':
73c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org        return True
74c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org    return False
75c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org
76c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org  return arg if not ShouldEscape() else '"%s"' % (arg.replace('"', '\\"'))
77c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org
78c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.orgdef WriteToTemporaryFile(data):
79c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org  (fd, fname) = tempfile.mkstemp()
80c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org  os.close(fd)
81c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org  tmp_file = open(fname, "w")
82c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org  tmp_file.write(data)
83c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org  tmp_file.close()
84c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org  return fname
85c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org
86c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.orgdef Main():
87c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org  if (len(sys.argv) == 1):
88c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org    print("Usage: %s <command-to-run-on-device>" % sys.argv[0])
89c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org    return 1
90c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org  workspace = abspath(join(dirname(sys.argv[0]), '..'))
911510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.org  android_workspace = os.getenv("ANDROID_V8", "/data/local/tmp/v8")
92c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org  args = [Escape(arg) for arg in sys.argv[1:]]
93c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org  script = (" ".join(args) + "\n"
94753aee4dcf0868130789b5af7c1eeb6ab2ab24f9verwaest@chromium.org            "case $? in\n"
95304cc33f8259ef467e8e3c79f448d0bae0e8cd85yangguo@chromium.org            "  0) ;;\n"
96304cc33f8259ef467e8e3c79f448d0bae0e8cd85yangguo@chromium.org            "  *) echo \"ANDROID: Error returned by test\";;\n"
97753aee4dcf0868130789b5af7c1eeb6ab2ab24f9verwaest@chromium.org            "esac\n")
98c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org  script = script.replace(workspace, android_workspace)
99c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org  script_file = WriteToTemporaryFile(script)
100c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org  android_script_file = android_workspace + "/" + script_file
101c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org  command =  ("adb push '%s' %s;" % (script_file, android_script_file) +
102c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org              "adb shell 'sh %s';" % android_script_file +
103c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org              "adb shell 'rm %s'" % android_script_file)
104c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org  error_code = Execute(command)
105c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org  os.unlink(script_file)
106c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org  return error_code
107c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org
108c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.orgif __name__ == '__main__':
109c6d9cee74ef337517b541fbd58e5438920699a77mstarzinger@chromium.org  sys.exit(Main())
110