1 /* 2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.atest.commandAdapter; 17 18 import com.android.atest.AtestUtils; 19 import com.android.atest.Constants; 20 import com.android.atest.toolWindow.AtestToolWindow; 21 import com.android.atest.widget.AtestNotification; 22 import com.intellij.build.BuildTextConsoleView; 23 import com.intellij.execution.ExecutionException; 24 import com.intellij.execution.ExecutionManager; 25 import com.intellij.execution.configurations.PtyCommandLine; 26 import com.intellij.execution.executors.DefaultRunExecutor; 27 import com.intellij.execution.process.KillableColoredProcessHandler; 28 import com.intellij.execution.process.ProcessListener; 29 import com.intellij.execution.ui.RunContentDescriptor; 30 import com.intellij.notification.Notifications; 31 import com.intellij.openapi.diagnostic.Logger; 32 import com.intellij.openapi.project.Project; 33 import org.jetbrains.annotations.NotNull; 34 35 import javax.swing.*; 36 import java.awt.*; 37 import java.nio.charset.StandardCharsets; 38 import java.util.ArrayList; 39 import java.util.Arrays; 40 41 /** A manager to handle command. */ 42 public class CommandRunner { 43 44 private static final Logger LOG = Logger.getInstance(CommandRunner.class); 45 private static final String ATEST_COMMAND_PREFIX = 46 "export USER_FROM_TOOL=\"IntelliJ_Atest_plugin\" && source build/envsetup.sh && lunch "; 47 private static KillableColoredProcessHandler sProcessHandler; 48 private PtyCommandLine mCommand; 49 private ProcessListener mProcessListener; 50 private Project mProject; 51 52 /** 53 * Initializes CommandRunner by the command. 54 * 55 * @param cmds the command to run. 56 * @param workPath the work path to run the command. 57 */ CommandRunner(ArrayList<String> cmds, String workPath)58 public CommandRunner(ArrayList<String> cmds, String workPath) { 59 mCommand = new PtyCommandLine(cmds); 60 mCommand.setCharset(StandardCharsets.UTF_8); 61 mCommand.setWorkDirectory(workPath); 62 } 63 64 /** 65 * Initializes CommandRunner by Atest lunch target and test target. 66 * 67 * @param lunchTarget the Atest lunch target. 68 * @param testTarget the Atest test target. 69 * @param workPath the work path to run the command. 70 * @param toolWindow an AtestToolWindow to display the output. 71 * @param project the current intelliJ project. 72 */ CommandRunner( String lunchTarget, String testTarget, String workPath, @NotNull AtestToolWindow toolWindow, @NotNull Project project)73 public CommandRunner( 74 String lunchTarget, 75 String testTarget, 76 String workPath, 77 @NotNull AtestToolWindow toolWindow, 78 @NotNull Project project) 79 throws IllegalArgumentException { 80 if (AtestUtils.checkEmpty(lunchTarget, testTarget, workPath)) { 81 throw new IllegalArgumentException(); 82 } 83 mProject = project; 84 StringBuffer commandBuffer = new StringBuffer(ATEST_COMMAND_PREFIX); 85 String atestCommand = 86 commandBuffer 87 .append(lunchTarget) 88 .append(" && atest ") 89 .append(testTarget) 90 .toString(); 91 LOG.info("Atest command: " + atestCommand + ", work path: " + workPath); 92 93 String[] commandArray = {"/bin/bash", "-c", atestCommand}; 94 ArrayList<String> cmds = new ArrayList<>(Arrays.asList(commandArray)); 95 mCommand = new PtyCommandLine(cmds); 96 mCommand.setCharset(StandardCharsets.UTF_8); 97 mCommand.setWorkDirectory(workPath); 98 mProcessListener = new AtestProcessListener(toolWindow); 99 } 100 101 /** 102 * Sets the process listener. 103 * 104 * @param processListener a processListener handle the output. 105 */ setProcessListener(ProcessListener processListener)106 public void setProcessListener(ProcessListener processListener) { 107 mProcessListener = processListener; 108 } 109 110 /** 111 * Executes the command in processHandler. 112 * 113 * <p>Execute this method when caller is ready to access linux command. 114 */ run()115 public void run() { 116 try { 117 stopProcess(mProject); 118 sProcessHandler = new KillableColoredProcessHandler(mCommand); 119 if (mProcessListener != null) { 120 sProcessHandler.addProcessListener(mProcessListener); 121 } 122 launchConsole(); 123 sProcessHandler.startNotify(); 124 } catch (ExecutionException e) { 125 Notifications.Bus.notify(new AtestNotification("Command execution failed.")); 126 LOG.error("Command executes fail: " + mCommand.getCommandLineString()); 127 } 128 } 129 130 /** Launch the console view of current process. */ launchConsole()131 private void launchConsole() { 132 BuildTextConsoleView consoleView = new BuildTextConsoleView(mProject); 133 JPanel panel = new JPanel(new BorderLayout()); 134 consoleView.attachToProcess(sProcessHandler); 135 panel.add(consoleView.getComponent(), BorderLayout.CENTER); 136 panel.updateUI(); 137 RunContentDescriptor contentDescriptor = 138 new RunContentDescriptor(consoleView, sProcessHandler, panel, Constants.ATEST_NAME); 139 ExecutionManager.getInstance(mProject) 140 .getContentManager() 141 .showRunContent(DefaultRunExecutor.getRunExecutorInstance(), contentDescriptor); 142 } 143 144 /** 145 * Stops the current process. 146 * 147 * @param project the current intelliJ project. 148 */ stopProcess(Project project)149 public static void stopProcess(Project project) { 150 if (sProcessHandler != null) { 151 RunContentDescriptor contentDescriptor = 152 ExecutionManager.getInstance(project) 153 .getContentManager() 154 .findContentDescriptor( 155 DefaultRunExecutor.getRunExecutorInstance(), sProcessHandler); 156 ExecutionManager.getInstance(project) 157 .getContentManager() 158 .hideRunContent(DefaultRunExecutor.getRunExecutorInstance(), contentDescriptor); 159 sProcessHandler.killProcess(); 160 sProcessHandler = null; 161 } 162 } 163 } 164