check for PyCharm tasks (EDU-882)

This commit is contained in:
Liana.Bakradze
2017-04-18 17:11:17 +03:00
parent 4e9d785e20
commit d996b96ea1
13 changed files with 174 additions and 344 deletions
@@ -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);
@@ -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();
}
@@ -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);
}
}
@@ -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"/>
@@ -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
@@ -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;
}
}
@@ -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));
}
}
@@ -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;
}
}
@@ -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;
}
}