1# SPDX-License-Identifier: Apache-2.0 2# 3# Copyright (C) 2015, ARM Limited and contributors. 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); you may 6# not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16# 17 18import os 19 20SCRIPT_NAME = 'remote_script.sh' 21 22class TargetScript(object): 23 """ 24 This class provides utility to create and run a script 25 directly on a devlib target. 26 27 The execute() method is made to look like Devlib's, so a Target instance can 28 be swapped with an instance of this TargetScript class, and the commands 29 will be accumulated for later use instead of being executed straight away. 30 31 :param env: Reference TestEnv instance. Will be used for some commands 32 that must really be executed instead of accumulated. 33 :type env: TestEnv 34 35 :param script_name: Name of the script that will be pushed on the target, 36 defaults to "remote_script.sh" 37 :type script_name: str 38 """ 39 40 _target_attrs = ['screen_resolution', 'android_id', 'abi', 'os_version', 'model'] 41 42 def __init__(self, env, script_name=SCRIPT_NAME): 43 self._env = env 44 self._target = env.target 45 self._script_name = script_name 46 self.commands = [] 47 48 # This is made to look like the devlib Target execute() 49 def execute(self, cmd): 50 """ 51 Accumulate command for later execution. 52 53 :param cmd: Command that would be run on the target 54 :type cmd: str 55 """ 56 self.append(cmd) 57 58 def append(self, cmd): 59 """ 60 Append a command to the script. 61 62 :param cmd: Command string to append 63 :type cmd: str 64 """ 65 self.commands.append(cmd) 66 67 # Some commands may require some info about the real target. 68 # For instance, System.{h,v}swipe needs to get the value of 69 # screen_resolution to generate a swipe command at a given 70 # screen coordinate percentage. 71 # Thus, if such a property is called on this object, 72 # it will be fetched from the 'real' target object. 73 def __getattr__(self, name): 74 if name in self._target_attrs: 75 return getattr(self._target, name) 76 77 return getattr(super, name) 78 79 def push(self): 80 """ 81 Push a script to the target 82 83 The script is created and stored on the host, 84 and is then sent to the target. 85 86 :param path: Path where the script will be locally created 87 :type path: str 88 :param actions: List of actions(commands) to run 89 :type actions: list(str) 90 """ 91 92 actions = ['set -e'] + self.commands + ['set +e'] 93 actions = ['#!{} sh'.format(self._target.busybox)] + actions 94 actions = str.join('\n', actions) 95 96 self._remote_path = self._target.path.join(self._target.executables_directory, 97 self._script_name) 98 self._local_path = os.path.join(self._env.res_dir, self._script_name) 99 100 # Create script locally 101 with open(self._local_path, 'w') as script: 102 script.write(actions) 103 104 # Push it on target 105 self._target.push(self._local_path, self._remote_path) 106 self._target.execute('chmod +x {}'.format(self._remote_path)) 107 108 def run(self): 109 """ 110 Run the previously pushed script 111 """ 112 113 if self._target.file_exists(self._remote_path): 114 self._target.execute(self._remote_path) 115 else: 116 raise IOError('Remote script was not found on target device') 117