diff --git a/python/educational-core/resources/META-INF/plugin.xml b/python/educational-core/resources/META-INF/plugin.xml index 5f794738eaa2..b3cf04f03d0c 100644 --- a/python/educational-core/resources/META-INF/plugin.xml +++ b/python/educational-core/resources/META-INF/plugin.xml @@ -195,4 +195,10 @@ + + + + com.jetbrains.edu.learning.stepic.EduCourseUpdater + + \ No newline at end of file diff --git a/python/educational-core/src/com/jetbrains/edu/learning/EduPluginConfigurator.java b/python/educational-core/src/com/jetbrains/edu/learning/EduPluginConfigurator.java index c41739bef591..0bc4152966a2 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/EduPluginConfigurator.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/EduPluginConfigurator.java @@ -9,6 +9,8 @@ import com.intellij.openapi.actionSystem.DefaultActionGroup; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.module.ModifiableModuleModel; import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleType; +import com.intellij.openapi.module.StdModuleTypes; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiDirectory; @@ -18,6 +20,7 @@ import com.jetbrains.edu.learning.courseFormat.Course; import com.jetbrains.edu.learning.courseFormat.Lesson; import com.jetbrains.edu.learning.courseFormat.tasks.Task; import com.jetbrains.edu.learning.courseFormat.tasks.TaskWithSubtasks; +import com.jetbrains.edu.learning.courseGeneration.StudyGenerator; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -126,9 +129,12 @@ public interface EduPluginConfigurator { @NotNull Project project, @NotNull Course course, @Nullable String moduleDir) { + StudyGenerator.createCourse(course, project.getBaseDir()); } default List getBundledCoursePaths() { return Collections.emptyList(); } + + default ModuleType getModuleType() {return StdModuleTypes.JAVA;} } diff --git a/python/educational-core/src/com/jetbrains/edu/learning/intellij/EduIntelliJTemplateFactory.java b/python/educational-core/src/com/jetbrains/edu/learning/intellij/EduIntelliJTemplateFactory.java index 19535068e1c1..73be3a89bcc2 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/intellij/EduIntelliJTemplateFactory.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/intellij/EduIntelliJTemplateFactory.java @@ -3,14 +3,11 @@ package com.jetbrains.edu.learning.intellij; import com.intellij.icons.AllIcons; import com.intellij.ide.util.projectWizard.WizardContext; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.progress.ProgressIndicator; -import com.intellij.openapi.progress.ProgressManager; -import com.intellij.openapi.progress.Task; import com.intellij.platform.ProjectTemplate; import com.intellij.platform.ProjectTemplatesFactory; import com.jetbrains.edu.learning.courseFormat.Course; -import com.jetbrains.edu.learning.courseGeneration.StudyProjectGenerator; import com.jetbrains.edu.learning.intellij.stepik.EduRemoteCourseTemplate; +import com.jetbrains.edu.learning.stepic.EduCourseUpdater; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -22,16 +19,6 @@ import java.util.List; @SuppressWarnings("unused") //used in other educational plugins that are stored in separate repository public class EduIntelliJTemplateFactory extends ProjectTemplatesFactory { private static final String GROUP_NAME = "Education"; - private static List ourRemoteCourses; - - static { - ProgressManager.getInstance().run(new Task.Backgroundable(null, "Updating Course") { - @Override - public void run(@NotNull ProgressIndicator indicator) { - ourRemoteCourses = new StudyProjectGenerator().getCourses(true); - } - }); - } @NotNull @Override @@ -43,10 +30,9 @@ public class EduIntelliJTemplateFactory extends ProjectTemplatesFactory { @Override public ProjectTemplate[] createTemplates(@Nullable String group, WizardContext context) { final ArrayList templates = new ArrayList<>(); - if (ourRemoteCourses != null) { - for (Course course : ourRemoteCourses) { - templates.add(new EduRemoteCourseTemplate(course)); - } + final List courses = EduCourseUpdater.getInstance().getRemoteCourses(); + for (Course course : courses) { + templates.add(new EduRemoteCourseTemplate(course)); } Collections.addAll(templates, ApplicationManager.getApplication().getExtensions(EduIntelliJProjectTemplate.EP_NAME)); return templates.toArray(new ProjectTemplate[templates.size()]); diff --git a/python/educational-core/src/com/jetbrains/edu/learning/intellij/localCourses/EduCustomCourseProjectTemplate.java b/python/educational-core/src/com/jetbrains/edu/learning/intellij/localCourses/EduCustomCourseProjectTemplate.java index c80e8f4bc686..378200a8ef58 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/intellij/localCourses/EduCustomCourseProjectTemplate.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/intellij/localCourses/EduCustomCourseProjectTemplate.java @@ -19,7 +19,7 @@ class EduCustomCourseProjectTemplate implements EduIntelliJProjectTemplate { @Nullable @Override public String getDescription() { - return "Custom Course Addition"; + return "Select and add local course from *.zip"; } @Override diff --git a/python/educational-core/src/com/jetbrains/edu/learning/intellij/stepik/EduRemoteCourseModuleBuilder.java b/python/educational-core/src/com/jetbrains/edu/learning/intellij/stepik/EduRemoteCourseModuleBuilder.java index 9aa0282e7985..2241f3344b76 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/intellij/stepik/EduRemoteCourseModuleBuilder.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/intellij/stepik/EduRemoteCourseModuleBuilder.java @@ -1,17 +1,17 @@ package com.jetbrains.edu.learning.intellij.stepik; -import com.intellij.ide.util.projectWizard.JavaModuleBuilder; +import com.intellij.ide.util.projectWizard.ModuleBuilder; import com.intellij.ide.util.projectWizard.ModuleWizardStep; -import com.intellij.ide.util.projectWizard.ProjectWizardStepFactory; import com.intellij.ide.util.projectWizard.SettingsStep; import com.intellij.lang.Language; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.module.ModifiableModuleModel; import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleType; import com.intellij.openapi.module.ModuleWithNameAlreadyExists; import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Conditions; +import com.intellij.openapi.roots.ModifiableRootModel; import com.intellij.openapi.util.InvalidDataException; import com.jetbrains.edu.learning.EduPluginConfigurator; import com.jetbrains.edu.learning.StudyTaskManager; @@ -23,13 +23,17 @@ import org.jetbrains.annotations.Nullable; import java.io.IOException; -class EduRemoteCourseModuleBuilder extends JavaModuleBuilder { +class EduRemoteCourseModuleBuilder extends ModuleBuilder { private static final Logger LOG = Logger.getInstance(EduRemoteCourseModuleBuilder.class); private final Course myCourse; + private final ModuleType myModuleType; + private final ModuleBuilder myModuleBuilder; private EduProjectGenerator myGenerator = new EduProjectGenerator(); public EduRemoteCourseModuleBuilder(Course course) { myCourse = course; + myModuleType = EduPluginConfigurator.INSTANCE.forLanguage(myCourse.getLanguageById()).getModuleType(); + myModuleBuilder = myModuleType.createModuleBuilder(); } @Nullable @@ -61,7 +65,7 @@ class EduRemoteCourseModuleBuilder extends JavaModuleBuilder { @Nullable @Override public ModuleWizardStep modifySettingsStep(@NotNull SettingsStep settingsStep) { - return ProjectWizardStepFactory.getInstance().createJavaSettingsStep(settingsStep, this, Conditions.alwaysTrue()); + return myModuleBuilder.modifySettingsStep(settingsStep); } @NotNull @@ -87,4 +91,20 @@ class EduRemoteCourseModuleBuilder extends JavaModuleBuilder { } return baseModule; } + + @Override + public void setupRootModel(ModifiableRootModel modifiableRootModel) throws ConfigurationException { + myModuleBuilder.setupRootModel(modifiableRootModel); + } + + @Override + public ModuleType getModuleType() { + return myModuleType; + } + + @Override + public void setContentEntryPath(String moduleRootPath) { + myModuleBuilder.setContentEntryPath(moduleRootPath); + super.setContentEntryPath(moduleRootPath); + } } diff --git a/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduCourseUpdater.java b/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduCourseUpdater.java new file mode 100644 index 000000000000..0a7721488be4 --- /dev/null +++ b/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduCourseUpdater.java @@ -0,0 +1,42 @@ +/* + * Copyright 2000-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.jetbrains.edu.learning.stepic; + +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.components.ApplicationComponent; +import com.jetbrains.edu.learning.courseFormat.Course; +import com.jetbrains.edu.learning.courseGeneration.StudyProjectGenerator; + +import java.util.ArrayList; +import java.util.List; + +public class EduCourseUpdater implements ApplicationComponent { + + private List ourRemoteCourses = new ArrayList<>(); + + public List getRemoteCourses() { + return ourRemoteCourses; + } + + public static EduCourseUpdater getInstance() { + return ApplicationManager.getApplication().getComponent(EduCourseUpdater.class); + } + + public EduCourseUpdater() { + ApplicationManager.getApplication().executeOnPooledThread( + () -> ourRemoteCourses = new StudyProjectGenerator().getCourses(true)); + } +} diff --git a/python/educational-python/Edu-Python/resources/META-INF/plugin.xml b/python/educational-python/Edu-Python/resources/META-INF/plugin.xml index 1d4b1055bfba..70ba9c6a50eb 100644 --- a/python/educational-python/Edu-Python/resources/META-INF/plugin.xml +++ b/python/educational-python/Edu-Python/resources/META-INF/plugin.xml @@ -45,8 +45,7 @@ - + diff --git a/python/educational-python/Edu-Python/src/com/jetbrains/edu/learning/PyEduPluginConfigurator.java b/python/educational-python/Edu-Python/src/com/jetbrains/edu/learning/PyEduPluginConfigurator.java index 3bbdd68f95a7..1bf1ad6c2fc4 100644 --- a/python/educational-python/Edu-Python/src/com/jetbrains/edu/learning/PyEduPluginConfigurator.java +++ b/python/educational-python/Edu-Python/src/com/jetbrains/edu/learning/PyEduPluginConfigurator.java @@ -7,7 +7,10 @@ import com.intellij.ide.fileTemplates.FileTemplateUtil; import com.intellij.ide.util.DirectoryUtil; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleType; import com.intellij.openapi.project.Project; +import com.intellij.openapi.startup.StartupManager; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.io.FileUtilRt; @@ -21,6 +24,7 @@ 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.PythonModuleTypeBase; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -144,4 +148,27 @@ public class PyEduPluginConfigurator implements EduPluginConfigurator { return Collections.singletonList(new File(new File(jarPath, "courses"), COURSE_NAME).getPath()); } + + public ModuleType getModuleType() { + return PythonModuleTypeBase.getInstance(); + } + + @Override + public void configureModule(@NotNull Module module) { + final Project project = module.getProject(); + StartupManager.getInstance(project).runWhenProjectIsInitialized(() -> { + final VirtualFile baseDir = project.getBaseDir(); + 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); + if (projectDir == null) return; + try { + FileTemplateUtil.createFromTemplate(template, testHelper, null, projectDir); + } + catch (Exception exception) { + LOG.error("Can't copy test_helper.py " + exception.getMessage()); + } + }); + } } diff --git a/python/educational-python/Edu-Python/src/com/jetbrains/edu/learning/PyStudyInitialConfigurator.java b/python/educational-python/Edu-Python/src/com/jetbrains/edu/learning/PyStudyInitialConfigurator.java index f94eb2f67989..fb87f4f59b8a 100644 --- a/python/educational-python/Edu-Python/src/com/jetbrains/edu/learning/PyStudyInitialConfigurator.java +++ b/python/educational-python/Edu-Python/src/com/jetbrains/edu/learning/PyStudyInitialConfigurator.java @@ -3,6 +3,7 @@ package com.jetbrains.edu.learning; import com.intellij.codeInsight.CodeInsightSettings; import com.intellij.ide.util.PropertiesComponent; import com.intellij.openapi.application.PathManager; +import com.intellij.openapi.components.ApplicationComponent; import com.intellij.openapi.fileTypes.FileTypeManager; import com.intellij.openapi.project.ex.ProjectManagerEx; import com.intellij.openapi.util.io.FileUtil; @@ -12,7 +13,7 @@ import org.jetbrains.annotations.NonNls; import java.io.File; @SuppressWarnings({"UtilityClassWithoutPrivateConstructor", "UtilityClassWithPublicConstructor"}) -public class PyStudyInitialConfigurator { +public class PyStudyInitialConfigurator implements ApplicationComponent { @NonNls private static final String CONFIGURED_V40 = "StudyPyCharm.InitialConfiguration40"; /**