diff --git a/src/main/java/net/geedge/api/controller/APIController.java b/src/main/java/net/geedge/api/controller/APIController.java index c6d59e4..08bd1d4 100644 --- a/src/main/java/net/geedge/api/controller/APIController.java +++ b/src/main/java/net/geedge/api/controller/APIController.java @@ -268,11 +268,12 @@ public class APIController { public R execPlaybook(@RequestParam("file") MultipartFile file, @RequestParam("packageName") String packageName, @RequestParam("id") String id, + @RequestParam("type") String type, @RequestParam("reInstall") Boolean reInstall, @RequestParam("clearCache") Boolean clearCache, @RequestParam("unInstall") Boolean unInstall) { File apkFile = null; - File playbookAirDir = null; + File scriptPath = null; File destination = null; try { File playbookDir = T.FileUtil.file(Constant.TEMP_PATH, id); @@ -299,14 +300,24 @@ public class APIController { })).findFirst().get(); // unzip playbook zip - T.ZipUtil.unzip(playbook, playbookDir); - playbookAirDir = Arrays.stream(playbookDir.listFiles(new FileFilter() { - @Override - public boolean accept(File pathname) { - return pathname.getName().endsWith(".air"); - } - })).findFirst().get(); - + if (T.StrUtil.equals(type, "python")){ + playbookDir = T.FileUtil.file(Constant.TEMP_PATH, id, "main"); + T.ZipUtil.unzip(playbook, playbookDir); + scriptPath = Arrays.stream(playbookDir.listFiles(new FileFilter() { + @Override + public boolean accept(File pathname) { + return pathname.getName().equals("main.py"); + } + })).findFirst().get(); + }else { + T.ZipUtil.unzip(playbook, playbookDir); + scriptPath = Arrays.stream(playbookDir.listFiles(new FileFilter() { + @Override + public boolean accept(File pathname) { + return pathname.getName().endsWith(".air"); + } + })).findFirst().get(); + } } catch (Exception e) { log.error(e.getMessage()); throw new APIException(RCode.ERROR); @@ -314,7 +325,7 @@ public class APIController { T.FileUtil.del(destination); } - PlaybookRunnable playbookRunnable = new PlaybookRunnable(apiYml, apkFile, playbookAirDir, id, packageName, reInstall, clearCache, unInstall); + PlaybookRunnable playbookRunnable = new PlaybookRunnable(apiYml, apkFile, scriptPath, id, packageName, type, reInstall, clearCache, unInstall); ThreadUtil.execAsync(playbookRunnable); return R.ok(); } @@ -391,7 +402,7 @@ public class APIController { File playbookDir = Arrays.stream(jobResult.listFiles(new FilenameFilter() { @Override public boolean accept(File dir, String name) { - return name.endsWith(".air"); + return name.endsWith(".air") || name.equals("main"); } })).toList().getFirst(); diff --git a/src/main/java/net/geedge/api/util/AdbCommandBuilder.java b/src/main/java/net/geedge/api/util/AdbCommandBuilder.java index e3ae515..5a47ed9 100644 --- a/src/main/java/net/geedge/api/util/AdbCommandBuilder.java +++ b/src/main/java/net/geedge/api/util/AdbCommandBuilder.java @@ -229,19 +229,6 @@ public class AdbCommandBuilder { return this; } - public AdbCommandBuilder buildRunPlaybook(String launcher, String path, String jobId, String packageName, String serial) { - this.command.add(launcher); - this.command.add(path); - this.command.add("--device"); - this.command.add(T.StrUtil.concat(true,"Android://127.0.0.1:5037/", serial)); - this.command.add("--job_id"); - this.command.add(jobId); - this.command.add("--job_path"); - this.command.add(path); - this.command.add("--package_name"); - this.command.add(packageName); - return this; - } public List build() { return this.command; diff --git a/src/main/java/net/geedge/api/util/AdbUtil.java b/src/main/java/net/geedge/api/util/AdbUtil.java index 46a74e4..35a9e41 100644 --- a/src/main/java/net/geedge/api/util/AdbUtil.java +++ b/src/main/java/net/geedge/api/util/AdbUtil.java @@ -10,6 +10,7 @@ import net.geedge.common.RCode; import net.geedge.common.T; import java.io.*; +import java.nio.file.Path; import java.nio.file.Paths; import java.util.*; import java.util.concurrent.*; @@ -901,11 +902,32 @@ public class AdbUtil { } - public CommandResult execPlaybook(String playbookPath, String tid, String packageName, File logFile) { + public CommandResult execPlaybook(String scriptPath, String tid, String packageName, String type, File logFile) { log.info("[execPlaybook] [begin!] [serial:{}]", this.getSerial()); - List command = new AdbCommandBuilder("python") - .buildRunPlaybook(ANDROID_LAUNCHER, playbookPath, tid, packageName, this.getSerial()) - .build(); + List command; + File environment = null; + if (T.StrUtil.equals(type, "python")){ + // check requirements.txt + Path parent = Paths.get(scriptPath).getParent(); + Path resolve = parent.resolve("requirements.txt"); + command = new PythonCommandBuilder("python") + .buildRunPythonScript(scriptPath, tid, packageName, this.getSerial()) + .build(); + if (T.FileUtil.exist(resolve.toString())){ + // create venv + environment = T.FileUtil.file(parent.toString(), "environment"); + commandExec.exec(new PythonCommandBuilder("python").buildCreateVenv(environment.getAbsolutePath()).build()); + commandExec.exec(new PythonCommandBuilder(T.StrUtil.concat(true, environment.getAbsolutePath(), "/bin/pip")).buildUpgradePip().build()); + commandExec.exec(new PythonCommandBuilder(T.StrUtil.concat(true, environment.getAbsolutePath(), "/bin/pip")).buildInstallRequirements(resolve.toString()).build()); + command = new PythonCommandBuilder(T.StrUtil.concat(true, environment.getAbsolutePath(), "/bin/python")) + .buildRunPythonScript(scriptPath, tid, packageName, this.getSerial()) + .build(); + } + }else { + command = new PythonCommandBuilder("python") + .buildRunAirScript(ANDROID_LAUNCHER, scriptPath, tid, packageName, this.getSerial()) + .build(); + } Process process = commandExec.execForProcess(command); T.FileUtil.appendString(T.StrUtil.concat(true, "$ ", command.stream().collect(Collectors.joining(" ")), "\n"), logFile, "UTF-8"); @@ -929,6 +951,7 @@ public class AdbUtil { process.destroyForcibly(); throw new APIException(RCode.ERROR); }finally { + T.FileUtil.del(environment); T.IoUtil.close(inputStreamReader); T.IoUtil.close(bufferedReader); } diff --git a/src/main/java/net/geedge/api/util/PlaybookRunnable.java b/src/main/java/net/geedge/api/util/PlaybookRunnable.java index 23d9719..8bcfcc9 100644 --- a/src/main/java/net/geedge/api/util/PlaybookRunnable.java +++ b/src/main/java/net/geedge/api/util/PlaybookRunnable.java @@ -22,18 +22,20 @@ public class PlaybookRunnable implements Runnable { private String tid; private File apkFile; private String packageName; - private File playbookDir; + private File scriptPath; + private String type; private boolean reInstall; private boolean clearCache; private boolean unInstall; private boolean interrupt; - public PlaybookRunnable(EnvApiYml envApiYml, File apkFile, File playbookDir, String tid, String packageName, Boolean reInstall, Boolean clearCache, Boolean unInstall) { + public PlaybookRunnable(EnvApiYml envApiYml, File apkFile, File scriptPath, String tid, String packageName, String type, Boolean reInstall, Boolean clearCache, Boolean unInstall) { this.envApiYml = envApiYml; this.tid = tid; this.apkFile = apkFile; this.packageName = packageName; - this.playbookDir = playbookDir; + this.scriptPath = scriptPath; + this.type = type; this.reInstall = reInstall; this.clearCache = clearCache; this.unInstall = unInstall; @@ -118,7 +120,7 @@ public class PlaybookRunnable implements Runnable { // exec playbook if (interrupt) return; - AdbUtil.CommandResult airtestResult = adbUtil.execPlaybook(playbookDir.getPath(), tid, packageName, logFile); + AdbUtil.CommandResult airtestResult = adbUtil.execPlaybook(scriptPath.getPath(), tid, packageName, type, logFile); if (0 != airtestResult.exitCode()) { T.FileUtil.appendString(String.format("ERROR: Exec playbook failed: exit code %s \n", airtestResult.exitCode()), logFile, "UTF-8"); throw new APIException("playbook exec error"); diff --git a/src/main/java/net/geedge/api/util/PythonCommandBuilder.java b/src/main/java/net/geedge/api/util/PythonCommandBuilder.java new file mode 100644 index 0000000..032de65 --- /dev/null +++ b/src/main/java/net/geedge/api/util/PythonCommandBuilder.java @@ -0,0 +1,80 @@ +package net.geedge.api.util; + +import net.geedge.common.T; + +import java.util.LinkedList; +import java.util.List; + +public class PythonCommandBuilder { + + private final String pythonPath; + private final List command; + + public PythonCommandBuilder(String pythonPath) { + this.pythonPath = pythonPath; + this.command = new LinkedList<>(); + this.command.add(pythonPath); + } + + public static PythonCommandBuilder builder() { + return new PythonCommandBuilder("python"); + } + + public static PythonCommandBuilder builder(String pythonPath) { + return new PythonCommandBuilder(pythonPath); + } + public PythonCommandBuilder buildRunAirScript(String launcher, String path, String jobId, String packageName, String serial) { + this.command.add(launcher); + this.command.add(path); + this.command.add("--device"); + this.command.add(T.StrUtil.concat(true,"Android://127.0.0.1:5037/", serial)); + this.command.add("--job_id"); + this.command.add(jobId); + this.command.add("--job_path"); + this.command.add(path); + this.command.add("--package_name"); + this.command.add(packageName); + return this; + } + + public PythonCommandBuilder buildRunPythonScript(String path, String jobId, String packageName, String serial) { + this.command.add(path); + this.command.add("--device"); + this.command.add(T.StrUtil.concat(true,"Android://127.0.0.1:5037/", serial)); + this.command.add("--serial"); + this.command.add(serial); + this.command.add("--job_id"); + this.command.add(jobId); + this.command.add("--job_path"); + this.command.add(path); + this.command.add("--package_name"); + this.command.add(packageName); + return this; + } + + public PythonCommandBuilder buildCreateVenv(String path) { + this.command.add("-m"); + this.command.add("venv"); + this.command.add(path); + this.command.add("--system-site-packages"); + return this; + } + + public PythonCommandBuilder buildUpgradePip() { + this.command.add("install"); + this.command.add("--upgrade"); + this.command.add("pip"); + return this; + } + + public PythonCommandBuilder buildInstallRequirements(String path) { + this.command.add("install"); + this.command.add("-r"); + this.command.add(path); + return this; + } + + public List build() { + return this.command; + } +} \ No newline at end of file