EDU-894 Save all course content in course.json

EDU-891 Drop courses cache

First iteration
This commit is contained in:
Ekaterina Tuzova
2017-04-06 14:54:32 +03:00
committed by Ekaterina Tuzova
parent 6f92410b5f
commit 2168b64066
52 changed files with 685 additions and 1439 deletions
@@ -33,10 +33,6 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.io.File;
import static com.jetbrains.edu.learning.courseGeneration.StudyProjectGenerator.OUR_COURSES_DIR;
public class PyCCProjectGenerator extends PythonProjectGenerator<PyNewProjectSettings> {
private static final Logger LOG = Logger.getInstance(PyCCProjectGenerator.class);
@@ -60,11 +56,7 @@ public class PyCCProjectGenerator extends PythonProjectGenerator<PyNewProjectSet
@NotNull PyNewProjectSettings settings,
@NotNull Module module,
@Nullable final PyProjectSynchronizer synchronizer) {
generateProject(project, baseDir, mySettingsPanel);
}
public static void generateProject(@NotNull final Project project, @NotNull final VirtualFile baseDir, CCNewProjectPanel settingsPanel) {
final Course course = getCourse(project, settingsPanel);
final Course course = getCourse(project, mySettingsPanel);
EduUsagesCollector.projectTypeCreated(CCUtils.COURSE_MODE);
final PsiDirectory projectDir = PsiManager.getInstance(project).findDirectory(baseDir);
@@ -107,9 +99,6 @@ public class PyCCProjectGenerator extends PythonProjectGenerator<PyNewProjectSet
course.setLanguage(language);
course.setCourseMode(CCUtils.COURSE_MODE);
File courseDir = new File(OUR_COURSES_DIR, name + "-" + project.getName());
course.setCourseDirectory(courseDir.getPath());
StudyTaskManager.getInstance(project).setCourse(course);
StudyUtils.registerStudyToolWindow(course, project);
return course;
@@ -15,20 +15,18 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.jetbrains.edu.coursecreator.CCUtils;
import com.jetbrains.edu.learning.StudyTaskManager;
import com.jetbrains.edu.learning.StudyUtils;
import com.jetbrains.edu.learning.checker.StudyCheckUtils;
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.tasks.Task;
import com.jetbrains.edu.learning.courseFormat.TaskFile;
import com.jetbrains.edu.learning.courseFormat.tasks.Task;
import com.jetbrains.python.run.CommandLinePatcher;
import com.jetbrains.python.run.PythonCommandLineState;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.util.Map;
public class PyCCCommandLineState extends PythonCommandLineState {
@@ -60,7 +58,6 @@ public class PyCCCommandLineState extends PythonCommandLineState {
assert course != null;
group.addParameter(myRunConfiguration.getPathToTest());
group.addParameter(new File(course.getCourseDirectory()).getPath());
String path = getCurrentTaskFilePath();
if (path != null) {
@@ -97,7 +94,6 @@ public class PyCCCommandLineState extends PythonCommandLineState {
@Override
public ExecutionResult execute(Executor executor, PythonProcessStarter processStarter, CommandLinePatcher... patchers) throws ExecutionException {
CCUtils.updateResources(myRunConfiguration.getProject(), myTask, myTaskDir);
ApplicationManager.getApplication().runWriteAction(() -> StudyCheckUtils.flushWindows(myTask, myTaskDir));
return super.execute(executor, processStarter, patchers);
@@ -14,12 +14,14 @@ import com.intellij.openapi.util.io.FileUtilRt;
import com.intellij.openapi.vfs.VirtualFile;
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.core.EduNames;
import com.jetbrains.edu.learning.courseFormat.Course;
import com.jetbrains.edu.learning.courseFormat.tasks.Task;
import com.jetbrains.edu.learning.courseFormat.tasks.TaskWithSubtasks;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -65,9 +67,8 @@ public class PyEduPluginConfigurator implements EduPluginConfigurator {
}
@Override
public boolean excludeFromArchive(@NotNull File pathname) {
String name = pathname.getName();
return name.contains("__pycache__") || name.contains(".pyc");
public boolean excludeFromArchive(@NotNull String name) {
return name.contains("__pycache__") || name.endsWith(".pyc");
}
@Override
@@ -126,4 +127,17 @@ public class PyEduPluginConfigurator implements EduPluginConfigurator {
public StudyCheckAction getCheckAction() {
return new PyStudyCheckAction();
}
@Override
public String getBundledCoursePath() {
@NonNls String jarPath = PathUtil.getJarPathForClass(PyEduPluginConfigurator.class);
if (jarPath.endsWith(".jar")) {
final File jarFile = new File(jarPath);
File pluginBaseDir = jarFile.getParentFile();
return new File(new File(pluginBaseDir, "courses"), "Introduction to Python.zip").getPath();
}
return new File(new File(jarPath, "courses"), "Introduction to Python.zip").getPath();
}
}
@@ -94,9 +94,9 @@ public class PyStudyCheckAction extends StudyCheckAction {
}
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);
}));
CommandProcessor.getInstance().runUndoTransparentAction(
() -> ApplicationManager.getApplication().runWriteAction(
() -> StudyCheckUtils.runSmartTestProcess(myTaskDir, testRunner, name, taskFile, project)));
}
}
final StudyToolWindow toolWindow = StudyUtils.getStudyToolWindow(project);
@@ -23,6 +23,7 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiManager;
import com.intellij.util.BooleanFunction;
import com.jetbrains.edu.learning.core.EduNames;
import com.jetbrains.edu.learning.courseFormat.Course;
import com.jetbrains.edu.learning.courseFormat.CourseInfo;
import com.jetbrains.edu.learning.courseGeneration.StudyProjectGenerator;
@@ -125,7 +126,7 @@ public class PyStudyDirectoryProjectGenerator extends PythonProjectGenerator<PyN
@NotNull Module module,
@Nullable PyProjectSynchronizer synchronizer) {
myGenerator.generateProject(project, baseDir);
final String testHelper = "test_helper.py";
final String testHelper = EduNames.TEST_HELPER;
if (baseDir.findChild(testHelper) != null) return;
final FileTemplate template = FileTemplateManager.getInstance(project).getInternalTemplate("test_helper");
final PsiDirectory projectDir = PsiManager.getInstance(project).findDirectory(baseDir);
@@ -160,11 +161,6 @@ public class PyStudyDirectoryProjectGenerator extends PythonProjectGenerator<PyN
return mySettingsPanel;
}
@NotNull
public List<CourseInfo> getCourses() {
return myGenerator.getCoursesUnderProgress(false, "Getting Courses", ProjectManager.getInstance().getDefaultProject());
}
public void setSelectedCourse(CourseInfo course) {
myGenerator.setSelectedCourse(course);
}
@@ -2,24 +2,18 @@ package com.jetbrains.edu.learning;
import com.intellij.codeInsight.CodeInsightSettings;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.openapi.project.ex.ProjectManagerEx;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.platform.templates.github.ZipUtil;
import com.intellij.util.PathUtil;
import com.intellij.util.messages.MessageBus;
import com.jetbrains.edu.learning.actions.PyStudyIntroductionCourseAction;
import com.jetbrains.edu.learning.courseGeneration.StudyProjectGenerator;
import org.jetbrains.annotations.NonNls;
import java.io.File;
import java.io.IOException;
@SuppressWarnings({"UtilityClassWithoutPrivateConstructor", "UtilityClassWithPublicConstructor"})
public class PyStudyInitialConfigurator {
private static final Logger LOG = Logger.getInstance(PyStudyInitialConfigurator.class.getName());
@NonNls private static final String CONFIGURED_V35 = "StudyPyCharm.InitialConfiguration35";
@NonNls private static final String CONFIGURED_V40 = "StudyPyCharm.InitialConfiguration40";
/**
* @noinspection UnusedParameters
@@ -29,42 +23,9 @@ public class PyStudyInitialConfigurator {
final PropertiesComponent propertiesComponent,
FileTypeManager fileTypeManager,
final ProjectManagerEx projectManager) {
final File file = new File(getCoursesRoot(), "Introduction to Python.zip");
if (!propertiesComponent.getBoolean(CONFIGURED_V35) && file.exists()) {
try {
File[] children = StudyProjectGenerator.OUR_COURSES_DIR.listFiles(
(dir, name) -> name.equals(PyStudyIntroductionCourseAction.INTRODUCTION_TO_PYTHON));
if (children != null) {
for (File child : children) {
FileUtil.delete(child);
}
}
copyCourse(file, StudyProjectGenerator.OUR_COURSES_DIR);
propertiesComponent.setValue(CONFIGURED_V35, "true");
}
catch (IOException e) {
LOG.warn("Couldn't copy bundled courses " + e);
}
if (!propertiesComponent.getBoolean(CONFIGURED_V40)) {
final File courses = new File(PathManager.getConfigPath(), "courses");
FileUtil.delete(courses);
}
}
private static void copyCourse(File bundledCourse, File userCourseDir) throws IOException {
String fileName = bundledCourse.getName();
String unzippedName = fileName.substring(0, fileName.indexOf("."));
File courseDir = new File(userCourseDir, unzippedName);
ZipUtil.unzip(null, courseDir, bundledCourse, null, null, true);
}
private static File getCoursesRoot() {
@NonNls String jarPath = PathUtil.getJarPathForClass(PyStudyInitialConfigurator.class);
if (jarPath.endsWith(".jar")) {
final File jarFile = new File(jarPath);
File pluginBaseDir = jarFile.getParentFile();
return new File(pluginBaseDir, "courses");
}
return new File(jarPath, "courses");
}
}
@@ -23,32 +23,25 @@ public class PyStudyShowTutorial extends AbstractProjectComponent {
@Override
public void projectOpened() {
ApplicationManager.getApplication().invokeLater(new DumbAwareRunnable() {
@Override
public void run() {
ApplicationManager.getApplication().runWriteAction(new DumbAwareRunnable() {
@Override
public void run() {
if (PropertiesComponent.getInstance().getBoolean(ourShowPopup, true)) {
final String content = "<html>If you'd like to learn more about PyCharm Edu, " +
"click <a href=\"https://www.jetbrains.com/pycharm-edu/quickstart/\">here</a> to watch a tutorial</html>";
final Notification notification = new Notification("Watch Tutorials!", "", content, NotificationType.INFORMATION,
new NotificationListener.UrlOpeningListener(true));
Notifications.Bus.notify(notification);
Balloon balloon = notification.getBalloon();
if (balloon != null) {
balloon.addListener(new JBPopupAdapter() {
@Override
public void onClosed(LightweightWindowEvent event) {
notification.expire();
}
});
ApplicationManager.getApplication().invokeLater((DumbAwareRunnable)() -> ApplicationManager.getApplication().runWriteAction(
(DumbAwareRunnable)() -> {
if (PropertiesComponent.getInstance().getBoolean(ourShowPopup, true)) {
final String content = "<html>If you'd like to learn more about PyCharm Edu, " +
"click <a href=\"https://www.jetbrains.com/pycharm-edu/quickstart/\">here</a> to watch a tutorial</html>";
final Notification notification = new Notification("Watch Tutorials!", "", content, NotificationType.INFORMATION,
new NotificationListener.UrlOpeningListener(true));
Notifications.Bus.notify(notification);
Balloon balloon = notification.getBalloon();
if (balloon != null) {
balloon.addListener(new JBPopupAdapter() {
@Override
public void onClosed(LightweightWindowEvent event) {
notification.expire();
}
notification.whenExpired(() -> PropertiesComponent.getInstance().setValue(ourShowPopup, false, true));
}
});
}
});
}
});
notification.whenExpired(() -> PropertiesComponent.getInstance().setValue(ourShowPopup, false, true));
}
}));
}
}
@@ -10,7 +10,6 @@ import com.intellij.openapi.util.io.FileUtilRt;
import com.intellij.openapi.vfs.VirtualFile;
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.tasks.Task;
import com.jetbrains.edu.learning.courseFormat.tasks.TaskWithSubtasks;
import com.jetbrains.python.sdk.PythonSdkType;
@@ -28,7 +27,6 @@ public class PyStudyTestRunner extends StudyTestRunner {
public Process createCheckProcess(@NotNull final Project project, @NotNull final String executablePath) throws ExecutionException {
final Sdk sdk = PythonSdkType.findPythonSdk(ModuleManager.getInstance(project).getModules()[0]);
Course course = myTask.getLesson().getCourse();
PyEduPluginConfigurator configurator = new PyEduPluginConfigurator();
String testsFileName = configurator.getTestFileName();
if (myTask instanceof TaskWithSubtasks) {
@@ -50,8 +48,6 @@ public class PyStudyTestRunner extends StudyTestRunner {
if (pythonPath != null) {
commandLine.setExePath(pythonPath);
commandLine.addParameter(testRunner.getPath());
File resourceFile = new File(course.getCourseDirectory());
commandLine.addParameter(resourceFile.getPath());
commandLine.addParameter(FileUtil.toSystemDependentName(executablePath));
return commandLine.createProcess();
}
@@ -19,9 +19,10 @@ import com.intellij.ide.impl.ProjectUtil;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.Presentation;
import com.jetbrains.edu.learning.EduPluginConfigurator;
import com.jetbrains.edu.learning.PyStudyDirectoryProjectGenerator;
import com.jetbrains.edu.learning.courseGeneration.StudyProjectGenerator;
import com.jetbrains.edu.learning.courseFormat.CourseInfo;
import com.jetbrains.python.PythonLanguage;
import com.jetbrains.python.newProject.steps.ProjectSpecificSettingsStep;
import com.jetbrains.python.newProject.steps.PythonGenerateProjectCallback;
import icons.InteractiveLearningPythonIcons;
@@ -44,7 +45,8 @@ public class PyStudyIntroductionCourseAction extends AnAction {
if (projectDir.exists()) {
return;
}
if (StudyProjectGenerator.getBundledIntro() != null) {
final EduPluginConfigurator configurator = EduPluginConfigurator.INSTANCE.forLanguage(PythonLanguage.getInstance());
if (configurator.getBundledCoursePath() != null) {
return;
}
Presentation presentation = e.getPresentation();
@@ -60,7 +62,9 @@ public class PyStudyIntroductionCourseAction extends AnAction {
}
else {
final PyStudyDirectoryProjectGenerator generator = new PyStudyDirectoryProjectGenerator();
CourseInfo introCourse = StudyProjectGenerator.getBundledIntro();
final EduPluginConfigurator configurator = EduPluginConfigurator.INSTANCE.forLanguage(PythonLanguage.getInstance());
final String bundledCoursePath = configurator.getBundledCoursePath();
CourseInfo introCourse = generator.getGenerator().getCourseInfo(bundledCoursePath);
if (introCourse == null) {
return;
}