summaryrefslogtreecommitdiff
path: root/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyCheckAction.java
diff options
context:
space:
mode:
Diffstat (limited to 'python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyCheckAction.java')
-rw-r--r--python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyCheckAction.java340
1 files changed, 340 insertions, 0 deletions
diff --git a/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyCheckAction.java b/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyCheckAction.java
new file mode 100644
index 000000000000..f8e10c9c4521
--- /dev/null
+++ b/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyCheckAction.java
@@ -0,0 +1,340 @@
+package com.jetbrains.python.edu.actions;
+
+import com.intellij.execution.ExecutionException;
+import com.intellij.execution.configurations.GeneralCommandLine;
+import com.intellij.ide.projectView.ProjectView;
+import com.intellij.openapi.actionSystem.ActionManager;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.command.CommandProcessor;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.fileEditor.FileDocumentManager;
+import com.intellij.openapi.fileEditor.FileEditor;
+import com.intellij.openapi.fileEditor.FileEditorManager;
+import com.intellij.openapi.module.ModuleManager;
+import com.intellij.openapi.project.DumbAwareAction;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.ui.popup.Balloon;
+import com.intellij.openapi.ui.popup.BalloonBuilder;
+import com.intellij.openapi.ui.popup.JBPopupFactory;
+import com.intellij.openapi.util.TextRange;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.ui.JBColor;
+import com.jetbrains.python.edu.StudyDocumentListener;
+import com.jetbrains.python.edu.StudyTaskManager;
+import com.jetbrains.python.edu.StudyUtils;
+import com.jetbrains.python.edu.course.*;
+import com.jetbrains.python.edu.editor.StudyEditor;
+import com.jetbrains.python.sdk.PythonSdkType;
+import org.jetbrains.annotations.NotNull;
+
+import javax.swing.*;
+import java.awt.*;
+import java.io.*;
+import java.util.*;
+import java.util.List;
+
+public class StudyCheckAction extends DumbAwareAction {
+
+ private static final Logger LOG = Logger.getInstance(StudyCheckAction.class.getName());
+ public static final String PYTHONPATH = "PYTHONPATH";
+
+ static class StudyTestRunner {
+ public static final String TEST_OK = "#study_plugin test OK";
+ private static final String TEST_FAILED = "#study_plugin FAILED + ";
+ private final Task myTask;
+ private final VirtualFile myTaskDir;
+
+ StudyTestRunner(Task task, VirtualFile taskDir) {
+ myTask = task;
+ myTaskDir = taskDir;
+ }
+
+ Process launchTests(Project project, String executablePath) throws ExecutionException {
+ Sdk sdk = PythonSdkType.findPythonSdk(ModuleManager.getInstance(project).getModules()[0]);
+ File testRunner = new File(myTaskDir.getPath(), myTask.getTestFile());
+ GeneralCommandLine commandLine = new GeneralCommandLine();
+ commandLine.setWorkDirectory(myTaskDir.getPath());
+ final Map<String, String> env = commandLine.getEnvironment();
+ final VirtualFile courseDir = project.getBaseDir();
+ if (courseDir != null)
+ env.put(PYTHONPATH, courseDir.getPath());
+ if (sdk != null) {
+ String pythonPath = sdk.getHomePath();
+ if (pythonPath != null) {
+ commandLine.setExePath(pythonPath);
+ commandLine.addParameter(testRunner.getPath());
+ final Course course = StudyTaskManager.getInstance(project).getCourse();
+ assert course != null;
+ commandLine.addParameter(new File(course.getResourcePath()).getParent());
+ commandLine.addParameter(FileUtil.toSystemDependentName(executablePath));
+ return commandLine.createProcess();
+ }
+ }
+ return null;
+ }
+
+
+ String getPassedTests(Process p) {
+ InputStream testOutput = p.getInputStream();
+ BufferedReader testOutputReader = new BufferedReader(new InputStreamReader(testOutput));
+ String line;
+ try {
+ while ((line = testOutputReader.readLine()) != null) {
+ if (line.contains(TEST_FAILED)) {
+ return line.substring(TEST_FAILED.length(), line.length());
+ }
+ }
+ }
+ catch (IOException e) {
+ LOG.error(e);
+ }
+ finally {
+ StudyUtils.closeSilently(testOutputReader);
+ }
+ return TEST_OK;
+ }
+ }
+
+ public void check(@NotNull final Project project) {
+ ApplicationManager.getApplication().runWriteAction(new Runnable() {
+ @Override
+ public void run() {
+ CommandProcessor.getInstance().runUndoTransparentAction(new Runnable() {
+ @Override
+ public void run() {
+ final Editor selectedEditor = StudyEditor.getSelectedEditor(project);
+ if (selectedEditor != null) {
+ final FileDocumentManager fileDocumentManager = FileDocumentManager.getInstance();
+ final VirtualFile openedFile = fileDocumentManager.getFile(selectedEditor.getDocument());
+ if (openedFile != null) {
+ StudyTaskManager taskManager = StudyTaskManager.getInstance(project);
+ final TaskFile selectedTaskFile = taskManager.getTaskFile(openedFile);
+ List<VirtualFile> filesToDelete = new ArrayList<VirtualFile>();
+ if (selectedTaskFile != null) {
+ final VirtualFile taskDir = openedFile.getParent();
+ Task currentTask = selectedTaskFile.getTask();
+ StudyStatus oldStatus = currentTask.getStatus();
+ Map<String, TaskFile> taskFiles = selectedTaskFile.getTask().getTaskFiles();
+ for (Map.Entry<String, TaskFile> entry : taskFiles.entrySet()) {
+ String name = entry.getKey();
+ TaskFile taskFile = entry.getValue();
+ VirtualFile virtualFile = taskDir.findChild(name);
+ if (virtualFile == null) {
+ continue;
+ }
+ VirtualFile windowFile = StudyUtils.flushWindows(FileDocumentManager.getInstance().getDocument(virtualFile), taskFile, virtualFile);
+ filesToDelete.add(windowFile);
+ FileDocumentManager.getInstance().saveAllDocuments();
+ }
+
+ StudyRunAction runAction = (StudyRunAction)ActionManager.getInstance().getAction(StudyRunAction.ACTION_ID);
+ if (runAction != null && currentTask.getTaskFiles().size() == 1) {
+ runAction.run(project);
+ }
+ final StudyTestRunner testRunner = new StudyTestRunner(currentTask, taskDir);
+ Process testProcess = null;
+ try {
+ testProcess = testRunner.launchTests(project, openedFile.getPath());
+ }
+ catch (ExecutionException e) {
+ LOG.error(e);
+ }
+ if (testProcess != null) {
+ String failedMessage = testRunner.getPassedTests(testProcess);
+ if (failedMessage.equals(StudyTestRunner.TEST_OK)) {
+ currentTask.setStatus(StudyStatus.Solved, oldStatus);
+ StudyUtils.updateStudyToolWindow(project);
+ selectedTaskFile.drawAllWindows(selectedEditor);
+ ProjectView.getInstance(project).refresh();
+ for (VirtualFile file:filesToDelete) {
+ try {
+ file.delete(this);
+ }
+ catch (IOException e) {
+ LOG.error(e);
+ }
+ }
+ createTestResultPopUp("Congratulations!", JBColor.GREEN, project);
+ return;
+ }
+ for (Map.Entry<String, TaskFile> entry : taskFiles.entrySet()) {
+ String name = entry.getKey();
+ TaskFile taskFile = entry.getValue();
+ TaskFile answerTaskFile = new TaskFile();
+ VirtualFile virtualFile = taskDir.findChild(name);
+ if (virtualFile == null) {
+ continue;
+ }
+ VirtualFile answerFile = getCopyWithAnswers(taskDir, virtualFile, taskFile, answerTaskFile);
+ for (TaskWindow taskWindow : answerTaskFile.getTaskWindows()) {
+ Document document = FileDocumentManager.getInstance().getDocument(virtualFile);
+ if (document == null) {
+ continue;
+ }
+ if (!taskWindow.isValid(document)) {
+ continue;
+ }
+ check(project, taskWindow, answerFile, answerTaskFile, taskFile, document, testRunner, virtualFile);
+ }
+ FileEditor fileEditor = FileEditorManager.getInstance(project).getSelectedEditor(virtualFile);
+ Editor editor = null;
+ if (fileEditor instanceof StudyEditor) {
+ StudyEditor studyEditor = (StudyEditor) fileEditor;
+ editor = studyEditor.getEditor();
+ }
+
+ if (editor != null) {
+ taskFile.drawAllWindows(editor);
+ StudyUtils.synchronize();
+ }
+ try {
+ answerFile.delete(this);
+ }
+ catch (IOException e) {
+ LOG.error(e);
+ }
+ }
+ for (VirtualFile file:filesToDelete) {
+ try {
+ file.delete(this);
+ }
+ catch (IOException e) {
+ LOG.error(e);
+ }
+ }
+ currentTask.setStatus(StudyStatus.Failed, oldStatus);
+ StudyUtils.updateStudyToolWindow(project);
+ createTestResultPopUp(failedMessage, JBColor.RED, project);
+ }
+ }
+ }
+ }
+
+ }
+ });
+ }
+ });
+ }
+
+ private void check(Project project,
+ TaskWindow taskWindow,
+ VirtualFile answerFile,
+ TaskFile answerTaskFile,
+ TaskFile usersTaskFile,
+ Document usersDocument,
+ StudyTestRunner testRunner,
+ VirtualFile openedFile) {
+
+ try {
+ VirtualFile windowCopy = answerFile.copy(this, answerFile.getParent(), answerFile.getNameWithoutExtension() + "_window" + taskWindow.getIndex() + ".py");
+ final FileDocumentManager documentManager = FileDocumentManager.getInstance();
+ final Document windowDocument = documentManager.getDocument(windowCopy);
+ if (windowDocument != null) {
+ StudyTaskManager taskManager = StudyTaskManager.getInstance(project);
+ Course course = taskManager.getCourse();
+ Task task = usersTaskFile.getTask();
+ int taskNum = task.getIndex() + 1;
+ int lessonNum = task.getLesson().getIndex() + 1;
+ assert course != null;
+ String pathToResource = FileUtil.join(new File(course.getResourcePath()).getParent(), Lesson.LESSON_DIR + lessonNum, Task.TASK_DIR + taskNum);
+ File resourceFile = new File(pathToResource, windowCopy.getName());
+ FileUtil.copy(new File(pathToResource, openedFile.getName()), resourceFile);
+ TaskFile windowTaskFile = new TaskFile();
+ TaskFile.copy(answerTaskFile, windowTaskFile);
+ StudyDocumentListener listener = new StudyDocumentListener(windowTaskFile);
+ windowDocument.addDocumentListener(listener);
+ int start = taskWindow.getRealStartOffset(windowDocument);
+ int end = start + taskWindow.getLength();
+ TaskWindow userTaskWindow = usersTaskFile.getTaskWindows().get(taskWindow.getIndex());
+ int userStart = userTaskWindow.getRealStartOffset(usersDocument);
+ int userEnd = userStart + userTaskWindow.getLength();
+ String text = usersDocument.getText(new TextRange(userStart, userEnd));
+ windowDocument.replaceString(start, end, text);
+ ApplicationManager.getApplication().runWriteAction(new Runnable() {
+ @Override
+ public void run() {
+ documentManager.saveDocument(windowDocument);
+ }
+ });
+ VirtualFile fileWindows = StudyUtils.flushWindows(windowDocument, windowTaskFile, windowCopy);
+ Process smartTestProcess = testRunner.launchTests(project, windowCopy.getPath());
+ boolean res = testRunner.getPassedTests(smartTestProcess).equals(StudyTestRunner.TEST_OK);
+ userTaskWindow.setStatus(res ? StudyStatus.Solved : StudyStatus.Failed, StudyStatus.Unchecked);
+ windowCopy.delete(this);
+ fileWindows.delete(this);
+ if (!resourceFile.delete()) {
+ LOG.error("failed to delete", resourceFile.getPath());
+ }
+ }
+ }
+ catch (IOException e) {
+ LOG.error(e);
+ }
+ catch (ExecutionException e) {
+ LOG.error(e);
+ }
+ }
+
+
+ private VirtualFile getCopyWithAnswers(final VirtualFile taskDir,
+ final VirtualFile file,
+ final TaskFile source,
+ TaskFile target) {
+ VirtualFile copy = null;
+ try {
+
+ copy = file.copy(this, taskDir, file.getNameWithoutExtension() +"_answers.py");
+ final FileDocumentManager documentManager = FileDocumentManager.getInstance();
+ final Document document = documentManager.getDocument(copy);
+ if (document != null) {
+ TaskFile.copy(source, target);
+ StudyDocumentListener listener = new StudyDocumentListener(target);
+ document.addDocumentListener(listener);
+ for (TaskWindow taskWindow : target.getTaskWindows()) {
+ if (!taskWindow.isValid(document)) {
+ continue;
+ }
+ final int start = taskWindow.getRealStartOffset(document);
+ final int end = start + taskWindow.getLength();
+ final String text = taskWindow.getPossibleAnswer();
+ document.replaceString(start, end, text);
+ }
+ ApplicationManager.getApplication().runWriteAction(new Runnable() {
+ @Override
+ public void run() {
+ documentManager.saveDocument(document);
+ }
+ });
+ }
+ }
+ catch (IOException e) {
+ LOG.error(e);
+ }
+
+
+ return copy;
+ }
+
+ private static void createTestResultPopUp(final String text, Color color, @NotNull final Project project) {
+ BalloonBuilder balloonBuilder =
+ JBPopupFactory.getInstance().createHtmlTextBalloonBuilder(text, null, color, null);
+ Balloon balloon = balloonBuilder.createBalloon();
+ StudyEditor studyEditor = StudyEditor.getSelectedStudyEditor(project);
+ assert studyEditor != null;
+ JButton checkButton = studyEditor.getCheckButton();
+ balloon.showInCenterOf(checkButton);
+ }
+
+ @Override
+ public void actionPerformed(AnActionEvent e) {
+ Project project = e.getProject();
+ if (project != null) {
+ check(project);
+ }
+ }
+}