mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
check for PyCharm tasks (EDU-882)
This commit is contained in:
@@ -15,9 +15,11 @@ import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiDirectory;
|
||||
import com.jetbrains.edu.learning.actions.*;
|
||||
import com.jetbrains.edu.learning.checker.StudyTaskChecker;
|
||||
import com.jetbrains.edu.learning.core.EduNames;
|
||||
import com.jetbrains.edu.learning.courseFormat.Course;
|
||||
import com.jetbrains.edu.learning.courseFormat.Lesson;
|
||||
import com.jetbrains.edu.learning.courseFormat.tasks.PyCharmTask;
|
||||
import com.jetbrains.edu.learning.courseFormat.tasks.Task;
|
||||
import com.jetbrains.edu.learning.courseFormat.tasks.TaskWithSubtasks;
|
||||
import com.jetbrains.edu.learning.courseGeneration.StudyGenerator;
|
||||
@@ -93,13 +95,13 @@ public interface EduPluginConfigurator {
|
||||
@NotNull
|
||||
default String getLanguageScriptUrl() {return "";}
|
||||
|
||||
StudyCheckAction getCheckAction();
|
||||
@NotNull
|
||||
StudyTaskChecker<PyCharmTask> getPyCharmTaskChecker(@NotNull PyCharmTask task, @NotNull Project project);
|
||||
|
||||
@NotNull
|
||||
default DefaultActionGroup getTaskDescriptionActionGroup() {
|
||||
final DefaultActionGroup group = new DefaultActionGroup();
|
||||
group.add(getCheckAction());
|
||||
String[] ids = new String[]{StudyPreviousTaskAction.ACTION_ID, StudyNextTaskAction.ACTION_ID, StudyRefreshTaskFileAction.ACTION_ID,
|
||||
String[] ids = new String[]{StudyCheckAction.ACTION_ID, StudyPreviousTaskAction.ACTION_ID, StudyNextTaskAction.ACTION_ID, StudyRefreshTaskFileAction.ACTION_ID,
|
||||
StudyShowHintAction.ACTION_ID};
|
||||
for (String id : ids) {
|
||||
AnAction action = ActionManager.getInstance().getAction(id);
|
||||
|
||||
+4
-1
@@ -37,7 +37,7 @@ import javax.swing.*;
|
||||
|
||||
public class StudyCheckAction extends StudyActionWithShortcut {
|
||||
public static final String SHORTCUT = "ctrl alt pressed ENTER";
|
||||
private static final String ACTION_ID = "Edu.Check";
|
||||
public static final String ACTION_ID = "Edu.Check";
|
||||
private static final String TEXT = "Check Task";
|
||||
public static final String FAILED_CHECK_LAUNCH = "Failed to launch checking";
|
||||
|
||||
@@ -109,16 +109,19 @@ public class StudyCheckAction extends StudyActionWithShortcut {
|
||||
listener.afterCheck(project, task);
|
||||
}
|
||||
checker.clearState();
|
||||
myCheckInProgress.set(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancel() {
|
||||
checker.clearState();
|
||||
myCheckInProgress.set(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(@NotNull ProgressIndicator indicator) {
|
||||
indicator.setIndeterminate(true);
|
||||
myCheckInProgress.set(true);
|
||||
myResult = isRemote ? checkOnRemote() : checker.check();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,201 +0,0 @@
|
||||
package com.jetbrains.edu.learning.checker;
|
||||
|
||||
import com.intellij.execution.process.CapturingProcessHandler;
|
||||
import com.intellij.execution.process.ProcessOutput;
|
||||
import com.intellij.ide.projectView.ProjectView;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.MessageType;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.jetbrains.edu.learning.StudySettings;
|
||||
import com.jetbrains.edu.learning.StudyState;
|
||||
import com.jetbrains.edu.learning.StudyTaskManager;
|
||||
import com.jetbrains.edu.learning.StudyUtils;
|
||||
import com.jetbrains.edu.learning.core.EduNames;
|
||||
import com.jetbrains.edu.learning.core.EduUtils;
|
||||
import com.jetbrains.edu.learning.courseFormat.Course;
|
||||
import com.jetbrains.edu.learning.courseFormat.StudyStatus;
|
||||
import com.jetbrains.edu.learning.courseFormat.tasks.ChoiceTask;
|
||||
import com.jetbrains.edu.learning.courseFormat.tasks.Task;
|
||||
import com.jetbrains.edu.learning.courseFormat.tasks.TheoryTask;
|
||||
import com.jetbrains.edu.learning.stepic.EduAdaptiveStepicConnector;
|
||||
import com.jetbrains.edu.learning.stepic.EduStepicConnector;
|
||||
import com.jetbrains.edu.learning.stepic.StepicUser;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class StudyCheckTask extends com.intellij.openapi.progress.Task.Backgroundable {
|
||||
|
||||
private static final Logger LOG = Logger.getInstance(StudyCheckTask.class);
|
||||
private final Project myProject;
|
||||
protected final StudyState myStudyState;
|
||||
protected final Task myTask;
|
||||
protected final VirtualFile myTaskDir;
|
||||
protected final StudyTaskManager myTaskManger;
|
||||
private final StudyStatus myStatusBeforeCheck;
|
||||
private final Ref<Boolean> myCheckInProcess;
|
||||
private final Process myTestProcess;
|
||||
private final String myCommandLine;
|
||||
private static final String FAILED_CHECK_LAUNCH = "Failed to launch checking";
|
||||
|
||||
public StudyCheckTask(Project project, StudyState studyState, Ref<Boolean> checkInProcess, Process testProcess, String commandLine) {
|
||||
super(project, "Checking Task");
|
||||
myProject = project;
|
||||
myStudyState = studyState;
|
||||
myCheckInProcess = checkInProcess;
|
||||
myTestProcess = testProcess;
|
||||
myCommandLine = commandLine;
|
||||
myTask = studyState.getTask();
|
||||
myTaskDir = studyState.getTaskDir();
|
||||
myTaskManger = StudyTaskManager.getInstance(myProject);
|
||||
myStatusBeforeCheck = myTask.getStatus();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
StudyUtils.updateToolWindows(myProject);
|
||||
StudyCheckUtils.drawAllPlaceholders(myProject, myTask);
|
||||
ProjectView.getInstance(myProject).refresh();
|
||||
clearState();
|
||||
}
|
||||
|
||||
protected void clearState() {
|
||||
EduUtils.deleteWindowDescriptions(myTask, myTaskDir);
|
||||
myCheckInProcess.set(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancel() {
|
||||
myTask.setStatus(myStatusBeforeCheck);
|
||||
clearState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(@NotNull ProgressIndicator indicator) {
|
||||
final Course course = StudyTaskManager.getInstance(myProject).getCourse();
|
||||
if (course != null) {
|
||||
if (course.isAdaptive()) {
|
||||
checkForAdaptiveCourse(indicator);
|
||||
}
|
||||
else {
|
||||
checkForEduCourse(indicator);
|
||||
}
|
||||
runAfterTaskCheckedActions();
|
||||
}
|
||||
}
|
||||
|
||||
private void checkForEduCourse(@NotNull ProgressIndicator indicator) {
|
||||
final StudyTestsOutputParser.TestsOutput testsOutput = getTestOutput(indicator);
|
||||
if (testsOutput != null) {
|
||||
if (testsOutput.isSuccess()) {
|
||||
onTaskSolved(testsOutput.getMessage());
|
||||
}
|
||||
else {
|
||||
onTaskFailed(testsOutput.getMessage());
|
||||
}
|
||||
final Course course = StudyTaskManager.getInstance(myProject).getCourse();
|
||||
if (course != null && EduNames.STUDY.equals(course.getCourseMode())) {
|
||||
StepicUser user = StudySettings.getInstance().getUser();
|
||||
if (user != null) {
|
||||
EduStepicConnector.postSolution(myTask, testsOutput.isSuccess(), myProject);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private StudyTestsOutputParser.TestsOutput getTestOutput(@NotNull ProgressIndicator indicator) {
|
||||
final CapturingProcessHandler handler = new CapturingProcessHandler(myTestProcess, null, myCommandLine);
|
||||
final ProcessOutput output = handler.runProcessWithProgressIndicator(indicator);
|
||||
if (indicator.isCanceled()) {
|
||||
ApplicationManager.getApplication().invokeLater(
|
||||
() -> StudyCheckUtils.showTestResultPopUp("Check cancelled", MessageType.WARNING.getPopupBackground(), myProject));
|
||||
}
|
||||
final Course course = StudyTaskManager.getInstance(myProject).getCourse();
|
||||
if (course != null) {
|
||||
final StudyTestsOutputParser.TestsOutput testsOutput = StudyTestsOutputParser.getTestsOutput(output, course.isAdaptive());
|
||||
String stderr = output.getStderr();
|
||||
if (!stderr.isEmpty() && output.getStdout().isEmpty()) {
|
||||
//log error output of tests
|
||||
LOG.info("#educational " + stderr);
|
||||
return new StudyTestsOutputParser.TestsOutput(false, stderr);
|
||||
}
|
||||
return testsOutput;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void checkForAdaptiveCourse(@NotNull ProgressIndicator indicator) {
|
||||
final StepicUser user = StudySettings.getInstance().getUser();
|
||||
if (user == null) {
|
||||
LOG.warn("User is null");
|
||||
ApplicationManager.getApplication().invokeLater(() ->
|
||||
StudyUtils.showErrorPopupOnToolbar(myProject,
|
||||
"Failed to launch checking: you're not authorized"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (myTask instanceof ChoiceTask) {
|
||||
final Pair<Boolean, String> result = EduAdaptiveStepicConnector.checkChoiceTask(myProject, (ChoiceTask)myTask, user);
|
||||
processStepicCheckOutput(result);
|
||||
}
|
||||
else if (myTask instanceof TheoryTask) {
|
||||
myTask.setStatus(StudyStatus.Solved);
|
||||
}
|
||||
else {
|
||||
final StudyTestsOutputParser.TestsOutput testOutput = getTestOutput(indicator);
|
||||
if (testOutput != null) {
|
||||
// As tests in adaptive courses are created from
|
||||
// samples and stored in task, to disable it we should ignore local testing results
|
||||
if (StudySettings.getInstance().isEnableTestingFromSamples() && !testOutput.isSuccess()) {
|
||||
onTaskFailed(testOutput.getMessage());
|
||||
}
|
||||
else {
|
||||
final Pair<Boolean, String> pair = EduAdaptiveStepicConnector.checkCodeTask(myProject, myTask, user);
|
||||
processStepicCheckOutput(pair);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void processStepicCheckOutput(@Nullable Pair<Boolean, String> pair) {
|
||||
if (pair != null && pair.getFirst() != null) {
|
||||
if (pair.getFirst()) {
|
||||
onTaskSolved("Congratulations! Remote tests passed.");
|
||||
}
|
||||
else {
|
||||
final String checkMessage = pair.getSecond();
|
||||
onTaskFailed(checkMessage);
|
||||
}
|
||||
}
|
||||
else {
|
||||
ApplicationManager.getApplication().invokeLater(() -> {
|
||||
String message = pair == null ? FAILED_CHECK_LAUNCH : pair.getSecond();
|
||||
StudyCheckUtils.showTestResultPopUp(message,
|
||||
MessageType.WARNING
|
||||
.getPopupBackground(),
|
||||
myProject);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
protected void onTaskFailed(@NotNull String message) {
|
||||
myTask.setStatus(StudyStatus.Failed);
|
||||
myTask.getChecker(myProject).onTaskFailed(message);
|
||||
}
|
||||
|
||||
protected void onTaskSolved(@NotNull String message) {
|
||||
myTask.setStatus(StudyStatus.Solved);
|
||||
myTask.getChecker(myProject).onTaskSolved(message);
|
||||
}
|
||||
|
||||
private void runAfterTaskCheckedActions() {
|
||||
for (StudyCheckListener listener : StudyCheckListener.EP_NAME.getExtensions()) {
|
||||
listener.afterCheck(myProject, myTask);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
package com.jetbrains.edu.learning.checker;
|
||||
|
||||
import com.intellij.execution.impl.ConsoleViewImpl;
|
||||
import com.intellij.execution.process.CapturingProcessHandler;
|
||||
import com.intellij.execution.process.ProcessOutput;
|
||||
import com.intellij.execution.ui.ConsoleViewContentType;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
@@ -10,6 +12,7 @@ import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.fileEditor.FileEditor;
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.progress.TaskInfo;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.popup.Balloon;
|
||||
@@ -223,4 +226,18 @@ public class StudyCheckUtils {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static StudyTestsOutputParser.TestsOutput getTestOutput(@NotNull Process testProcess,
|
||||
@NotNull String commandLine,
|
||||
boolean isAdaptive) {
|
||||
final CapturingProcessHandler handler = new CapturingProcessHandler(testProcess, null, commandLine);
|
||||
final ProcessOutput output = handler.runProcessWithProgressIndicator(ProgressManager.getInstance().getProgressIndicator());
|
||||
final StudyTestsOutputParser.TestsOutput testsOutput = StudyTestsOutputParser.getTestsOutput(output, isAdaptive);
|
||||
String stderr = output.getStderr();
|
||||
if (!stderr.isEmpty() && output.getStdout().isEmpty()) {
|
||||
LOG.info("#educational " + stderr);
|
||||
return new StudyTestsOutputParser.TestsOutput(false, stderr);
|
||||
}
|
||||
return testsOutput;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.jetbrains.edu.learning.checker;
|
||||
|
||||
import com.intellij.execution.ExecutionException;
|
||||
import com.intellij.execution.configurations.GeneralCommandLine;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.jetbrains.edu.learning.courseFormat.tasks.Task;
|
||||
@@ -16,4 +17,6 @@ public abstract class StudyTestRunner {protected final Task myTask;
|
||||
|
||||
public abstract Process createCheckProcess(@NotNull final Project project, @NotNull final String executablePath) throws ExecutionException;
|
||||
|
||||
public abstract GeneralCommandLine getCommandLine();
|
||||
|
||||
}
|
||||
|
||||
+11
@@ -1,5 +1,9 @@
|
||||
package com.jetbrains.edu.learning.courseFormat.tasks;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.jetbrains.edu.learning.EduPluginConfigurator;
|
||||
import com.jetbrains.edu.learning.checker.StudyTaskChecker;
|
||||
import com.jetbrains.edu.learning.courseFormat.Course;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
@@ -18,4 +22,11 @@ public class PyCharmTask extends Task {
|
||||
public String getTaskType() {
|
||||
return "pycharm";
|
||||
}
|
||||
|
||||
@Override
|
||||
public StudyTaskChecker getChecker(@NotNull Project project) {
|
||||
Course course = getLesson().getCourse();
|
||||
EduPluginConfigurator configurator = EduPluginConfigurator.INSTANCE.forLanguage(course.getLanguageById());
|
||||
return configurator != null ? configurator.getPyCharmTaskChecker(this, project) : super.getChecker(project);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -34,7 +34,7 @@ public class TheoryTask extends Task {
|
||||
|
||||
@Override
|
||||
public StudyCheckResult checkOnRemote(@NotNull StepicUser user) {
|
||||
return new StudyCheckResult(StudyStatus.Solved, "");
|
||||
return check();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -45,7 +45,6 @@
|
||||
<action id="StudyWatchTutorial" class="com.jetbrains.edu.learning.actions.PyStudyWatchTutorialAction">
|
||||
<add-to-group group-id="HelpMenu" anchor="before" relative-to-action="HelpTopics"/>
|
||||
</action>
|
||||
<action class="com.jetbrains.edu.learning.PyStudyCheckAction" id="PyCheckAction"/>
|
||||
<!--course creator-->
|
||||
<action class="com.jetbrains.edu.coursecreator.PyCCCreateProjectFromArchive" id="PyCC.NewEdu">
|
||||
<add-to-group group-id="CCFileGroup" anchor="last"/>
|
||||
|
||||
+5
-3
@@ -19,9 +19,10 @@ import com.intellij.psi.PsiDirectory;
|
||||
import com.intellij.psi.PsiManager;
|
||||
import com.intellij.util.PathUtil;
|
||||
import com.jetbrains.edu.coursecreator.settings.CCSettings;
|
||||
import com.jetbrains.edu.learning.actions.StudyCheckAction;
|
||||
import com.jetbrains.edu.learning.checker.StudyTaskChecker;
|
||||
import com.jetbrains.edu.learning.core.EduNames;
|
||||
import com.jetbrains.edu.learning.courseFormat.Course;
|
||||
import com.jetbrains.edu.learning.courseFormat.tasks.PyCharmTask;
|
||||
import com.jetbrains.edu.learning.courseFormat.tasks.Task;
|
||||
import com.jetbrains.edu.learning.courseFormat.tasks.TaskWithSubtasks;
|
||||
import com.jetbrains.python.PythonModuleTypeBase;
|
||||
@@ -131,8 +132,9 @@ public class PyEduPluginConfigurator implements EduPluginConfigurator {
|
||||
}
|
||||
|
||||
@Override
|
||||
public StudyCheckAction getCheckAction() {
|
||||
return new PyStudyCheckAction();
|
||||
@NotNull
|
||||
public StudyTaskChecker<PyCharmTask> getPyCharmTaskChecker(@NotNull PyCharmTask task, @NotNull Project project) {
|
||||
return new PyStudyTaskChecker(task, project);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
-126
@@ -1,126 +0,0 @@
|
||||
package com.jetbrains.edu.learning;
|
||||
|
||||
import com.intellij.execution.ExecutionException;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.command.CommandProcessor;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.wm.IdeFocusManager;
|
||||
import com.jetbrains.edu.learning.actions.StudyCheckAction;
|
||||
import com.jetbrains.edu.learning.checker.StudyCheckTask;
|
||||
import com.jetbrains.edu.learning.checker.StudyCheckUtils;
|
||||
import com.jetbrains.edu.learning.checker.StudyTestRunner;
|
||||
import com.jetbrains.edu.learning.core.EduNames;
|
||||
import com.jetbrains.edu.learning.courseFormat.Course;
|
||||
import com.jetbrains.edu.learning.courseFormat.TaskFile;
|
||||
import com.jetbrains.edu.learning.courseFormat.tasks.Task;
|
||||
import com.jetbrains.edu.learning.editor.StudyEditor;
|
||||
import com.jetbrains.edu.learning.statistics.EduUsagesCollector;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class PyStudyCheckAction extends StudyCheckAction {
|
||||
private static final Logger LOG = Logger.getInstance(PyStudyCheckAction.class);
|
||||
public static final String ACTION_ID = "PyCheckAction";
|
||||
|
||||
public void check(@NotNull Project project) {
|
||||
EduUsagesCollector.taskChecked();
|
||||
ApplicationManager.getApplication().runWriteAction(() -> CommandProcessor.getInstance().runUndoTransparentAction(() -> {
|
||||
final StudyEditor selectedEditor = StudyUtils.getSelectedStudyEditor(project);
|
||||
if (selectedEditor == null) return;
|
||||
final StudyState studyState = new StudyState(selectedEditor);
|
||||
if (!studyState.isValid()) {
|
||||
LOG.info("StudyCheckAction was invoked outside study editor");
|
||||
return;
|
||||
}
|
||||
if (StudyCheckUtils.hasBackgroundProcesses(project)) return;
|
||||
|
||||
final Task task = studyState.getTask();
|
||||
final VirtualFile taskDir = studyState.getTaskDir();
|
||||
StudyCheckUtils.flushWindows(task, taskDir);
|
||||
|
||||
|
||||
ApplicationManager.getApplication().invokeLater(
|
||||
() -> IdeFocusManager.getInstance(project).requestFocus(studyState.getEditor().getComponent(), true));
|
||||
|
||||
final StudyTestRunner testRunner = new PyStudyTestRunner(task, taskDir);
|
||||
Process testProcess = null;
|
||||
String commandLine = "";
|
||||
try {
|
||||
final VirtualFile executablePath = getTaskVirtualFile(studyState, task, taskDir);
|
||||
if (executablePath != null) {
|
||||
commandLine = executablePath.getPath();
|
||||
testProcess = testRunner.createCheckProcess(project, commandLine);
|
||||
}
|
||||
}
|
||||
catch (ExecutionException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
if (testProcess == null) {
|
||||
return;
|
||||
}
|
||||
myCheckInProgress.set(true);
|
||||
StudyCheckTask checkTask = getCheckTask(project, studyState, testRunner, testProcess, commandLine);
|
||||
ProgressManager.getInstance().run(checkTask);
|
||||
}));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private StudyCheckTask getCheckTask(@NotNull final Project project,
|
||||
final StudyState studyState,
|
||||
final StudyTestRunner testRunner,
|
||||
final Process testProcess,
|
||||
final String commandLine) {
|
||||
return new StudyCheckTask(project, studyState, myCheckInProgress, testProcess, commandLine) {
|
||||
@Override
|
||||
protected void onTaskFailed(@NotNull String message) {
|
||||
super.onTaskFailed(message);
|
||||
ApplicationManager.getApplication().invokeLater(() -> {
|
||||
if (myTaskDir == null) return;
|
||||
for (Map.Entry<String, TaskFile> entry : myTask.getTaskFiles().entrySet()) {
|
||||
final String name = entry.getKey();
|
||||
final TaskFile taskFile = entry.getValue();
|
||||
if (taskFile.getActivePlaceholders().size() < 2) {
|
||||
continue;
|
||||
}
|
||||
final Course course = myTaskManger.getCourse();
|
||||
if (course != null && EduNames.STUDY.equals(course.getCourseMode())) {
|
||||
CommandProcessor.getInstance().runUndoTransparentAction(
|
||||
() -> ApplicationManager.getApplication().runWriteAction(
|
||||
() -> StudyCheckUtils.runSmartTestProcess(myTaskDir, testRunner, name, taskFile, project)));
|
||||
}
|
||||
}
|
||||
StudyCheckUtils.navigateToFailedPlaceholder(myStudyState, myTask, myTaskDir, project);
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static VirtualFile getTaskVirtualFile(@NotNull final StudyState studyState,
|
||||
@NotNull final Task task,
|
||||
@NotNull final VirtualFile taskDir) {
|
||||
VirtualFile taskVirtualFile = studyState.getVirtualFile();
|
||||
for (Map.Entry<String, TaskFile> entry : task.getTaskFiles().entrySet()) {
|
||||
String name = entry.getKey();
|
||||
TaskFile taskFile = entry.getValue();
|
||||
VirtualFile virtualFile = taskDir.findFileByRelativePath(name);
|
||||
if (virtualFile != null) {
|
||||
if (!taskFile.getActivePlaceholders().isEmpty()) {
|
||||
taskVirtualFile = virtualFile;
|
||||
}
|
||||
}
|
||||
}
|
||||
return taskVirtualFile;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getActionId() {
|
||||
return ACTION_ID;
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -20,7 +20,7 @@ public class PyStudyInstructionPainter extends EditorEmptyTextPainter {
|
||||
appendAction(painter, "Navigate between tasks", getActionShortcutText(StudyPreviousTaskAction.ACTION_ID) + separator +
|
||||
getActionShortcutText(StudyNextTaskAction.ACTION_ID));
|
||||
appendAction(painter, "Reset current task file", getActionShortcutText(StudyRefreshTaskFileAction.ACTION_ID));
|
||||
appendAction(painter, "Check task", getActionShortcutText(PyStudyCheckAction.ACTION_ID));
|
||||
appendAction(painter, "Check task", getActionShortcutText(StudyCheckAction.ACTION_ID));
|
||||
appendAction(painter, "Get hint for the answer placeholder", getActionShortcutText(StudyShowHintAction.ACTION_ID));
|
||||
}
|
||||
}
|
||||
+114
@@ -0,0 +1,114 @@
|
||||
package com.jetbrains.edu.learning;
|
||||
|
||||
import com.intellij.execution.ExecutionException;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.command.CommandProcessor;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.jetbrains.edu.learning.actions.StudyCheckAction;
|
||||
import com.jetbrains.edu.learning.checker.*;
|
||||
import com.jetbrains.edu.learning.core.EduNames;
|
||||
import com.jetbrains.edu.learning.core.EduUtils;
|
||||
import com.jetbrains.edu.learning.courseFormat.Course;
|
||||
import com.jetbrains.edu.learning.courseFormat.StudyStatus;
|
||||
import com.jetbrains.edu.learning.courseFormat.TaskFile;
|
||||
import com.jetbrains.edu.learning.courseFormat.tasks.PyCharmTask;
|
||||
import com.jetbrains.edu.learning.courseFormat.tasks.Task;
|
||||
import com.jetbrains.edu.learning.stepic.EduStepicConnector;
|
||||
import com.jetbrains.edu.learning.stepic.StepicUser;
|
||||
import one.util.streamex.EntryStream;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class PyStudyTaskChecker extends StudyTaskChecker<PyCharmTask> {
|
||||
private static final Logger LOG = Logger.getInstance(PyStudyTaskChecker.class);
|
||||
|
||||
public PyStudyTaskChecker(PyCharmTask task, Project project) {
|
||||
super(task, project);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StudyCheckResult check() {
|
||||
VirtualFile taskDir = myTask.getTaskDir(myProject);
|
||||
if (taskDir == null) {
|
||||
LOG.info("taskDir is null for task " + myTask.getName());
|
||||
return new StudyCheckResult(StudyStatus.Unchecked, "Task is broken");
|
||||
}
|
||||
ApplicationManager.getApplication()
|
||||
.invokeLater(() -> ApplicationManager.getApplication().runWriteAction(() -> StudyCheckUtils.flushWindows(myTask, taskDir)));
|
||||
final StudyTestRunner testRunner = new PyStudyTestRunner(myTask, taskDir);
|
||||
try {
|
||||
final VirtualFile fileToCheck = getTaskVirtualFile(myTask, taskDir);
|
||||
if (fileToCheck != null) {
|
||||
Process testProcess = testRunner.createCheckProcess(myProject, fileToCheck.getPath());
|
||||
StudyTestsOutputParser.TestsOutput output =
|
||||
StudyCheckUtils
|
||||
.getTestOutput(testProcess, testRunner.getCommandLine().getCommandLineString(), myTask.getLesson().getCourse().isAdaptive());
|
||||
return new StudyCheckResult(output.isSuccess() ? StudyStatus.Solved : StudyStatus.Failed, output.getMessage());
|
||||
}
|
||||
}
|
||||
catch (ExecutionException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
return new StudyCheckResult(StudyStatus.Unchecked, StudyCheckAction.FAILED_CHECK_LAUNCH);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearState() {
|
||||
ApplicationManager.getApplication().invokeLater(() -> {
|
||||
StudyCheckUtils.drawAllPlaceholders(myProject, myTask);
|
||||
VirtualFile taskDir = myTask.getTaskDir(myProject);
|
||||
if (taskDir != null) {
|
||||
EduUtils.deleteWindowDescriptions(myTask, taskDir);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTaskFailed(@NotNull String message) {
|
||||
super.onTaskFailed(message);
|
||||
ApplicationManager.getApplication().invokeLater(() -> {
|
||||
VirtualFile taskDir = myTask.getTaskDir(myProject);
|
||||
if (taskDir == null) return;
|
||||
for (Map.Entry<String, TaskFile> entry : myTask.getTaskFiles().entrySet()) {
|
||||
final String name = entry.getKey();
|
||||
final TaskFile taskFile = entry.getValue();
|
||||
if (taskFile.getActivePlaceholders().size() < 2) {
|
||||
continue;
|
||||
}
|
||||
final Course course = myTask.getLesson().getCourse();
|
||||
if (course != null && EduNames.STUDY.equals(course.getCourseMode())) {
|
||||
CommandProcessor.getInstance().runUndoTransparentAction(
|
||||
() -> ApplicationManager.getApplication().runWriteAction(
|
||||
() -> StudyCheckUtils.runSmartTestProcess(taskDir, new PyStudyTestRunner(myTask, taskDir), name, taskFile, myProject)));
|
||||
}
|
||||
}
|
||||
StudyCheckUtils.navigateToFailedPlaceholder(new StudyState(StudyUtils.getSelectedStudyEditor(myProject)), myTask, taskDir, myProject);
|
||||
});
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static VirtualFile getTaskVirtualFile(@NotNull final Task task,
|
||||
@NotNull final VirtualFile taskDir) {
|
||||
|
||||
Map<TaskFile, VirtualFile> fileMap =
|
||||
EntryStream.of(task.getTaskFiles()).invert().mapValues(name -> taskDir.findFileByRelativePath(name)).nonNullValues().toMap();
|
||||
Map.Entry<TaskFile, VirtualFile> entry = EntryStream.of(fileMap).findAny(e -> !e.getKey().getActivePlaceholders().isEmpty())
|
||||
.orElse(fileMap.entrySet().stream().findFirst().orElse(null));
|
||||
return entry == null ? null : entry.getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public StudyCheckResult checkOnRemote(@NotNull StepicUser user) {
|
||||
StudyCheckResult result = check();
|
||||
final Course course = StudyTaskManager.getInstance(myProject).getCourse();
|
||||
StudyStatus status = result.getStatus();
|
||||
if (course != null && EduNames.STUDY.equals(course.getCourseMode()) && status != StudyStatus.Unchecked) {
|
||||
EduStepicConnector.postSolution(myTask, status == StudyStatus.Solved, myProject);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
+13
-7
@@ -20,6 +20,7 @@ import java.util.Map;
|
||||
|
||||
public class PyStudyTestRunner extends StudyTestRunner {
|
||||
private static final String PYTHONPATH = "PYTHONPATH";
|
||||
private GeneralCommandLine myCommandLine;
|
||||
|
||||
PyStudyTestRunner(@NotNull final Task task, @NotNull final VirtualFile taskDir) {
|
||||
super(task, taskDir);
|
||||
@@ -35,9 +36,9 @@ public class PyStudyTestRunner extends StudyTestRunner {
|
||||
testsFileName += EduNames.SUBTASK_MARKER + index + "." + FileUtilRt.getExtension(configurator.getTestFileName());
|
||||
}
|
||||
final File testRunner = new File(myTaskDir.getPath(), testsFileName);
|
||||
final GeneralCommandLine commandLine = new GeneralCommandLine();
|
||||
commandLine.withWorkDirectory(myTaskDir.getPath());
|
||||
final Map<String, String> env = commandLine.getEnvironment();
|
||||
myCommandLine = new GeneralCommandLine();
|
||||
myCommandLine.withWorkDirectory(myTaskDir.getPath());
|
||||
final Map<String, String> env = myCommandLine.getEnvironment();
|
||||
|
||||
final VirtualFile courseDir = project.getBaseDir();
|
||||
if (courseDir != null) {
|
||||
@@ -46,12 +47,17 @@ public class PyStudyTestRunner extends StudyTestRunner {
|
||||
if (sdk != null) {
|
||||
String pythonPath = sdk.getHomePath();
|
||||
if (pythonPath != null) {
|
||||
commandLine.setExePath(pythonPath);
|
||||
commandLine.addParameter(testRunner.getPath());
|
||||
commandLine.addParameter(FileUtil.toSystemDependentName(executablePath));
|
||||
return commandLine.createProcess();
|
||||
myCommandLine.setExePath(pythonPath);
|
||||
myCommandLine.addParameter(testRunner.getPath());
|
||||
myCommandLine.addParameter(FileUtil.toSystemDependentName(executablePath));
|
||||
return myCommandLine.createProcess();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GeneralCommandLine getCommandLine() {
|
||||
return myCommandLine;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user