285 строки
8.6 KiB
Python
285 строки
8.6 KiB
Python
import subprocess
|
|
import shutil
|
|
import time
|
|
import os
|
|
import stat
|
|
import utils
|
|
|
|
"""
|
|
Runner functions:
|
|
- start
|
|
- kill:
|
|
Kill a given subprocess
|
|
- killall:
|
|
Kill all processes given a specific name
|
|
- killAllInstances:
|
|
Kill all instances of the default
|
|
|
|
- getdir:
|
|
Returns the directory where the files are installed.
|
|
On most runners this will just return the path again.
|
|
On android this will give back the directory on the device.
|
|
- write:
|
|
Write the content to a file on the device
|
|
- rm:
|
|
Remove a file or directory on the device
|
|
- mkdir:
|
|
Create a directory on the device
|
|
- find:
|
|
find specific file inside a directory and return the path
|
|
- install:
|
|
Install an executable on the system.
|
|
- put:
|
|
Move a file or directory to the device if needed.
|
|
- set_exec_bit:
|
|
Sets the executable bit on a file.
|
|
|
|
"""
|
|
class Runner(object):
|
|
def __init__(self, info):
|
|
self.info = info
|
|
|
|
def rm(self, path):
|
|
if not os.path.exists(path):
|
|
print "rm", path, "(non-existing)"
|
|
return
|
|
|
|
print "rm", path
|
|
shutil.rmtree(path)
|
|
|
|
def kill(self, process):
|
|
print "kill", process.pid
|
|
process.terminate()
|
|
|
|
for i in range(100):
|
|
time.sleep(0.1)
|
|
if process.poll():
|
|
return
|
|
time.sleep(0.1)
|
|
|
|
try:
|
|
os.kill(int(process.pid), signal.SIGTERM)
|
|
except:
|
|
pass
|
|
|
|
def write(self, path, content):
|
|
print "write", path, content
|
|
fp = open(path, 'w')
|
|
fp.write(content);
|
|
fp.close()
|
|
|
|
def mkdir(self, path):
|
|
print "mkdir", path
|
|
os.mkdir(path)
|
|
|
|
def getdir(self, path):
|
|
return path
|
|
|
|
def set_exec_bit(self, path):
|
|
print "chmod u+x", path
|
|
st = os.stat(path)
|
|
os.chmod(path, st.st_mode | stat.S_IEXEC)
|
|
|
|
def find(self, path, file):
|
|
paths = subprocess.check_output(["find", path])
|
|
paths = [path.rstrip() for path in paths.splitlines()]
|
|
return [path for path in paths if path.endswith(file)]
|
|
|
|
def put(self, path, recursive=True):
|
|
return path
|
|
|
|
def execute(self, command, env, path="."):
|
|
print " ".join(command)
|
|
print os.getcwd()
|
|
print path
|
|
with utils.chdir(path):
|
|
return utils.run_realtime(command, env=env)
|
|
|
|
class LinuxRunner(Runner):
|
|
def killall(self, name):
|
|
print "killall", name
|
|
process = subprocess.Popen(["killall", name])
|
|
# Wait for killall to finish
|
|
while process.poll() is None:
|
|
time.sleep(0.5)
|
|
|
|
def killAllInstances(self):
|
|
print "killallinstances"
|
|
self.killall(self.info["linux_processname"])
|
|
|
|
def start(self, exe, args = [], env = {}):
|
|
print "start", exe, args, env
|
|
return subprocess.Popen([exe] + args, env=env)
|
|
|
|
def install(self, exe):
|
|
path = os.path.dirname(exe)
|
|
paths = subprocess.check_output(["find", path])
|
|
paths = [path.rstrip() for path in paths.splitlines()]
|
|
for path in paths:
|
|
self.set_exec_bit(path)
|
|
|
|
return exe
|
|
|
|
class WindowsRunner(LinuxRunner):
|
|
""" we assume cygwin, e.g. similar to the linux runner """
|
|
|
|
def killAllInstances(self):
|
|
print "killallinstances"
|
|
self.killall(self.info["windows_processname"])
|
|
|
|
def killall(self, name):
|
|
print "killall", name
|
|
try:
|
|
subprocess.check_output("kill $(ps aux | grep '"+name+"$' | awk '{print $2}')", shell=True)
|
|
except:
|
|
pass
|
|
|
|
def install(self, exe):
|
|
path = os.path.dirname(exe)
|
|
paths = subprocess.check_output(["find", path])
|
|
paths = [path.rstrip() for path in paths.splitlines()]
|
|
for path in paths:
|
|
self.set_exec_bit(path)
|
|
|
|
return exe
|
|
|
|
class OSXRunner(Runner):
|
|
def killall(self, name):
|
|
print "killall", name
|
|
process = subprocess.Popen(["killall", name])
|
|
# Wait for killall to finish
|
|
while process.poll() is None:
|
|
time.sleep(0.5)
|
|
|
|
def killAllInstances(self):
|
|
|
|
if "osx_mount_point" not in self.info or not os.path.exists(self.info["osx_mount_point"]):
|
|
return
|
|
|
|
print "killallinstances"
|
|
try:
|
|
subprocess.check_output("kill $(ps aux | grep '"+self.info["osx_mount_point"]+"[^[]' | awk '{print $2}')", shell=True)
|
|
except:
|
|
pass
|
|
try:
|
|
subprocess.check_output(["hdiutil", "detach", "-force", self.info["osx_mount_point"]])
|
|
except:
|
|
pass
|
|
|
|
def start(self, exe, args = [], env = {}):
|
|
print "start", exe, args, env
|
|
return subprocess.Popen([exe] + args, env=env)
|
|
|
|
def install(self, exe):
|
|
if exe.endswith(".dmg"):
|
|
print "install", exe
|
|
subprocess.check_output(["hdiutil", "attach", exe])
|
|
return self.info["osx_binary"]
|
|
else:
|
|
path = os.path.dirname(exe)
|
|
paths = subprocess.check_output(["find", path])
|
|
paths = [path.rstrip() for path in paths.splitlines()]
|
|
for path in paths:
|
|
self.set_exec_bit(path)
|
|
|
|
return exe
|
|
|
|
class AndroidRunner(Runner):
|
|
def __init__(self, info):
|
|
self.info = info
|
|
|
|
def killall(self, name):
|
|
pass
|
|
|
|
def killAllInstances(self):
|
|
subprocess.check_output(["adb", "shell", "pm", "clear", self.info["android_processname"]]);
|
|
pass
|
|
|
|
def start(self, path, args, env):
|
|
pass
|
|
|
|
def rm(self, path):
|
|
subprocess.check_output(["adb", "shell", "rm -rf " + self.getdir(path)])
|
|
|
|
def install(self, exe):
|
|
subprocess.check_output(["adb", "install", "-r", exe])
|
|
|
|
def kill(self):
|
|
self.killAllInstances()
|
|
|
|
def write(self, path, content):
|
|
assert "'" not in content
|
|
|
|
subprocess.check_output(["adb", "shell", "echo '" + content + "' > " + self.getdir(path)])
|
|
|
|
def mkdir(self, path):
|
|
print "adb", "shell", "mkdir", self.getdir(path)
|
|
subprocess.check_output(["adb", "shell", "mkdir " + self.getdir(path)])
|
|
|
|
def getdir(self, path):
|
|
return "/data/local/tmp/" + path
|
|
|
|
def put(self, path, recursive=True):
|
|
print "put", path, "on device"
|
|
name = os.path.basename(path)
|
|
if os.path.isdir(path):
|
|
hash1 = subprocess.check_output(["adb", "shell", "cat /data/local/tmp/"+name+"/123hash"]).splitlines()[0]
|
|
hash2 = subprocess.check_output("tar -cf - "+os.path.normpath(path)+" | md5sum", shell=True).splitlines()[0]
|
|
|
|
if hash1 != hash2:
|
|
syncDir = os.path.dirname(os.path.realpath(__file__))
|
|
if recursive:
|
|
adbSync = os.path.join(syncDir, "adb-sync-r")
|
|
else:
|
|
adbSync = os.path.join(syncDir, "adb-sync")
|
|
assert os.path.isfile(adbSync)
|
|
print adbSync, path, self.getdir("")
|
|
subprocess.check_output([adbSync, path, self.getdir("")])
|
|
|
|
self.write(os.path.join(name, "123hash"), hash2)
|
|
else:
|
|
print "adb", "push", path, self.getdir(name)
|
|
subprocess.check_output(["adb", "push", path, self.getdir(name)])
|
|
return self.getdir(name)
|
|
|
|
def set_exec_bit(self, path):
|
|
print "set_exec_bit not yet supported on AndroidRunner"
|
|
assert False
|
|
|
|
def find(self, path):
|
|
print "find not yet supported on AndroidRunner"
|
|
assert False
|
|
|
|
def execute(self, command, env, path="."):
|
|
env_flags = ""
|
|
|
|
shebang = subprocess.check_output(["adb", "shell", "head "+os.path.join(path, command[0])])
|
|
if shebang.startswith("#!/bin/bash"):
|
|
command = ["sh"] + command
|
|
if shebang.startswith("#!/usr/bin/perl"):
|
|
# Make sure we have perl. Copied from corion.net/perl-android
|
|
perlDir = os.path.dirname(os.path.realpath(__file__))
|
|
perlDir = os.path.join(perlDir, "perl-android")
|
|
self.put(perlDir)
|
|
|
|
command = ["perl"] + command
|
|
|
|
env_flags += 'PATH="$PATH:/data/local/tmp/perl-android/bin/" '
|
|
env_flags += 'PERL5LIB=/data/local/tmp/perl-android/lib:/data/local/tmp/perl-android/lib/site_perl '
|
|
for i in env:
|
|
env_flags += i+"="+env[i]+" "
|
|
|
|
print env_flags
|
|
print "adb shell ... " + " ".join(command) + " ..."
|
|
return utils.run_realtime(["adb", "shell", "cd "+path+";"+env_flags+" " + " ".join(command) + "; exit"])
|
|
|
|
def getRunner(platform, info = {}):
|
|
if platform == "linux":
|
|
return LinuxRunner(info)
|
|
if platform == "osx":
|
|
return OSXRunner(info)
|
|
if platform == "android":
|
|
return AndroidRunner(info)
|
|
if platform == "windows":
|
|
return WindowsRunner(info)
|