Minor Refresh project view on adding new recommendation, fix NPE in postAttemptToStepic
[idea/community.git] / python / educational-python / student-python / src / com / jetbrains / edu / learning / PyStudyCheckAction.java
1 package com.jetbrains.edu.learning;
2
3 import com.intellij.execution.ExecutionException;
4 import com.intellij.openapi.actionSystem.ActionManager;
5 import com.intellij.openapi.application.ApplicationManager;
6 import com.intellij.openapi.command.CommandProcessor;
7 import com.intellij.openapi.diagnostic.Logger;
8 import com.intellij.openapi.progress.ProgressManager;
9 import com.intellij.openapi.project.Project;
10 import com.intellij.openapi.vfs.VirtualFile;
11 import com.intellij.openapi.wm.IdeFocusManager;
12 import com.jetbrains.edu.learning.actions.StudyCheckAction;
13 import com.jetbrains.edu.learning.actions.StudyRunAction;
14 import com.jetbrains.edu.learning.checker.StudyCheckTask;
15 import com.jetbrains.edu.learning.checker.StudyCheckUtils;
16 import com.jetbrains.edu.learning.checker.StudyTestRunner;
17 import com.jetbrains.edu.learning.courseFormat.Course;
18 import com.jetbrains.edu.learning.courseFormat.StudyStatus;
19 import com.jetbrains.edu.learning.courseFormat.Task;
20 import com.jetbrains.edu.learning.courseFormat.TaskFile;
21 import com.jetbrains.edu.learning.editor.StudyEditor;
22 import com.jetbrains.edu.learning.ui.StudyToolWindow;
23 import org.jetbrains.annotations.NotNull;
24 import org.jetbrains.annotations.Nullable;
25
26 import java.util.Map;
27
28 public class PyStudyCheckAction extends StudyCheckAction {
29   private static final Logger LOG = Logger.getInstance(PyStudyCheckAction.class);
30   public static final String ACTION_ID = "PyCheckAction";
31   
32   public void check(@NotNull Project project) {
33     ApplicationManager.getApplication().runWriteAction(() -> {
34       CommandProcessor.getInstance().runUndoTransparentAction(() -> {
35         final StudyEditor selectedEditor = StudyUtils.getSelectedStudyEditor(project);
36         if (selectedEditor == null) return;
37         final StudyState studyState = new StudyState(selectedEditor);
38         if (!studyState.isValid()) {
39           LOG.info("StudyCheckAction was invoked outside study editor");
40           return;
41         }
42         if (StudyCheckUtils.hasBackgroundProcesses(project)) return;
43
44         final Course course = StudyTaskManager.getInstance(project).getCourse();
45         if (course != null && !course.isAdaptive() && !runTask(project)) return;
46
47         final Task task = studyState.getTask();
48         final VirtualFile taskDir = studyState.getTaskDir();
49         StudyCheckUtils.flushWindows(task, taskDir);
50
51
52         ApplicationManager.getApplication().invokeLater(
53           () -> IdeFocusManager.getInstance(project).requestFocus(studyState.getEditor().getComponent(), true));
54
55         final StudyTestRunner testRunner = StudyUtils.getTestRunner(task, taskDir);
56         Process testProcess = null;
57         String commandLine = "";
58         try {
59           final VirtualFile executablePath = getTaskVirtualFile(studyState, task, taskDir);
60           if (executablePath != null) {
61             commandLine = executablePath.getPath();
62             testProcess = testRunner.createCheckProcess(project, commandLine);
63           }
64         }
65         catch (ExecutionException e) {
66           LOG.error(e);
67         }
68         if (testProcess == null) {
69           return;
70         }
71         myCheckInProgress.set(true);
72         StudyCheckTask checkTask = getCheckTask(project, studyState, testRunner, testProcess, commandLine);
73         ProgressManager.getInstance().run(checkTask);
74       });
75     });
76   }
77
78   private static boolean runTask(@NotNull Project project) {
79     final StudyRunAction runAction = (StudyRunAction)ActionManager.getInstance().getAction(StudyRunAction.ACTION_ID);
80     if (runAction == null) {
81       return false;
82     }
83     runAction.run(project);
84     return true;
85   }
86
87   @NotNull
88   private StudyCheckTask getCheckTask(@NotNull final Project project,
89                                       final StudyState studyState,
90                                       final StudyTestRunner testRunner,
91                                       final Process testProcess,
92                                       final String commandLine) {
93     return new StudyCheckTask(project, studyState, myCheckInProgress, testProcess, commandLine) {
94       @Override
95       protected void onTaskFailed(String message) {
96         ApplicationManager.getApplication().invokeLater(() -> {
97           if (myTaskDir == null) return;
98           myTaskManger.setStatus(myTask, StudyStatus.Failed);
99           for (Map.Entry<String, TaskFile> entry : myTask.getTaskFiles().entrySet()) {
100             final String name = entry.getKey();
101             final TaskFile taskFile = entry.getValue();
102             if (taskFile.getAnswerPlaceholders().size() < 2) {
103               myTaskManger.setStatus(taskFile, StudyStatus.Failed);
104               continue;
105             }
106             CommandProcessor.getInstance().runUndoTransparentAction(() -> ApplicationManager.getApplication().runWriteAction(() -> {
107               StudyCheckUtils.runSmartTestProcess(myTaskDir, testRunner, name, taskFile, project);
108             }));
109           }
110           final StudyToolWindow toolWindow = StudyUtils.getStudyToolWindow(project);
111           if (toolWindow != null) {
112             StudyCheckUtils.showTestResults(project, message, false);
113             StudyCheckUtils.navigateToFailedPlaceholder(myStudyState, myTask, myTaskDir, project);
114           }
115         });
116       }
117     };
118   }
119
120
121   @Nullable
122   private static VirtualFile getTaskVirtualFile(@NotNull final StudyState studyState,
123                                                 @NotNull final Task task,
124                                                 @NotNull final VirtualFile taskDir) {
125     VirtualFile taskVirtualFile = studyState.getVirtualFile();
126     for (Map.Entry<String, TaskFile> entry : task.getTaskFiles().entrySet()) {
127       String name = entry.getKey();
128       TaskFile taskFile = entry.getValue();
129       VirtualFile virtualFile = taskDir.findChild(name);
130       if (virtualFile != null) {
131         if (!taskFile.getAnswerPlaceholders().isEmpty()) {
132           taskVirtualFile = virtualFile;
133         }
134       }
135     }
136     return taskVirtualFile;
137   }
138
139   @NotNull
140   @Override
141   public String getActionId() {
142     return ACTION_ID;
143   }
144 }