1 package com.jetbrains.edu.coursecreator.actions;
3 import com.google.gson.Gson;
4 import com.google.gson.GsonBuilder;
5 import com.intellij.ide.projectView.ProjectView;
6 import com.intellij.openapi.actionSystem.AnActionEvent;
7 import com.intellij.openapi.actionSystem.CommonDataKeys;
8 import com.intellij.openapi.actionSystem.LangDataKeys;
9 import com.intellij.openapi.actionSystem.Presentation;
10 import com.intellij.openapi.application.ApplicationManager;
11 import com.intellij.openapi.diagnostic.Logger;
12 import com.intellij.openapi.module.Module;
13 import com.intellij.openapi.project.DumbAwareAction;
14 import com.intellij.openapi.project.Project;
15 import com.intellij.openapi.ui.DialogWrapper;
16 import com.intellij.openapi.ui.Messages;
17 import com.intellij.openapi.util.io.FileUtil;
18 import com.intellij.openapi.vfs.VfsUtil;
19 import com.intellij.openapi.vfs.VirtualFile;
20 import com.intellij.openapi.vfs.VirtualFileManager;
21 import com.intellij.util.containers.HashMap;
22 import com.intellij.util.io.ZipUtil;
23 import com.jetbrains.edu.coursecreator.CCLanguageManager;
24 import com.jetbrains.edu.coursecreator.CCUtils;
25 import com.jetbrains.edu.coursecreator.ui.CreateCourseArchiveDialog;
26 import com.jetbrains.edu.learning.StudyTaskManager;
27 import com.jetbrains.edu.learning.core.EduNames;
28 import com.jetbrains.edu.learning.core.EduUtils;
29 import com.jetbrains.edu.learning.courseFormat.Course;
30 import com.jetbrains.edu.learning.courseFormat.Lesson;
31 import com.jetbrains.edu.learning.courseFormat.Task;
32 import com.jetbrains.edu.learning.courseFormat.TaskFile;
33 import org.jetbrains.annotations.NotNull;
36 import java.util.List;
38 import java.util.zip.ZipOutputStream;
40 public class CCCreateCourseArchive extends DumbAwareAction {
41 private static final Logger LOG = Logger.getInstance(CCCreateCourseArchive.class.getName());
42 private String myZipName;
43 private String myLocationDir;
45 public void setZipName(String zipName) {
49 public void setLocationDir(String locationDir) {
50 myLocationDir = locationDir;
53 public CCCreateCourseArchive() {
54 super("Generate Course Archive", "Generate Course Archive", null);
58 public void update(@NotNull AnActionEvent e) {
59 Presentation presentation = e.getPresentation();
60 Project project = e.getProject();
61 presentation.setEnabledAndVisible(project != null && CCUtils.isCourseCreator(project));
65 public void actionPerformed(@NotNull AnActionEvent e) {
66 final Project project = e.getData(CommonDataKeys.PROJECT);
67 final Module module = e.getData(LangDataKeys.MODULE);
68 if (project == null || module == null) {
71 createCourseArchive(project, module);
74 private void createCourseArchive(final Project project, Module module) {
75 final Course course = StudyTaskManager.getInstance(project).getCourse();
76 if (course == null) return;
77 CreateCourseArchiveDialog dlg = new CreateCourseArchiveDialog(project, this);
79 if (dlg.getExitCode() != DialogWrapper.OK_EXIT_CODE) {
82 final VirtualFile baseDir = project.getBaseDir();
84 VirtualFile archiveFolder = CCUtils.generateFolder(project, module, this, myZipName);
85 if (archiveFolder == null) {
89 CCLanguageManager manager = CCUtils.getStudyLanguageManager(course);
90 if (manager == null) {
93 FileFilter filter = pathname -> !manager.doNotPackFile(pathname);
95 for (VirtualFile child : baseDir.getChildren()) {
96 String name = child.getName();
97 File fromFile = new File(child.getPath());
98 if (CCUtils.GENERATED_FILES_FOLDER.equals(name) || ".idea".equals(name)
99 || name.contains("iml") || manager.doNotPackFile(fromFile)) {
102 copyChild(archiveFolder, filter, child, fromFile);
105 final List<Lesson> lessons = course.getLessons();
107 ApplicationManager.getApplication().runWriteAction(new Runnable() {
110 final Map<TaskFile, TaskFile> savedTaskFiles = new HashMap<TaskFile, TaskFile>();
111 replaceAnswerFilesWithTaskFiles(savedTaskFiles);
112 generateJson(project, archiveFolder);
113 resetTaskFiles(savedTaskFiles);
114 VirtualFileManager.getInstance().refreshWithoutFileWatcher(false);
115 packCourse(archiveFolder);
116 synchronize(project);
119 private void replaceAnswerFilesWithTaskFiles(Map<TaskFile, TaskFile> savedTaskFiles) {
120 for (Lesson lesson : lessons) {
121 final VirtualFile lessonDir = baseDir.findChild(EduNames.LESSON + String.valueOf(lesson.getIndex()));
122 if (lessonDir == null) continue;
123 for (Task task : lesson.getTaskList()) {
124 final VirtualFile taskDir = lessonDir.findChild(EduNames.TASK + String.valueOf(task.getIndex()));
125 if (taskDir == null) continue;
126 for (final Map.Entry<String, TaskFile> entry : task.getTaskFiles().entrySet()) {
127 TaskFile taskFileCopy = new TaskFile();
128 TaskFile taskFile = entry.getValue();
129 TaskFile.copy(taskFile, taskFileCopy);
130 savedTaskFiles.put(taskFile, taskFileCopy);
132 VirtualFile userFileDir = VfsUtil.findRelativeFile(archiveFolder, lessonDir.getName(), taskDir.getName());
133 if (userFileDir == null) {
136 String taskFileName = entry.getKey();
137 EduUtils.createStudentFileFromAnswer(project, userFileDir, taskDir, taskFileName, taskFile);
147 private static void copyChild(VirtualFile archiveFolder, FileFilter filter, VirtualFile child, File fromFile) {
148 File toFile = new File(archiveFolder.getPath(), child.getName());
151 if (child.isDirectory()) {
152 FileUtil.copyDir(fromFile, toFile, filter);
155 if (filter.accept(fromFile)) {
156 FileUtil.copy(fromFile, toFile);
160 catch (IOException e) {
161 LOG.info("Failed to copy" + fromFile.getPath(), e);
165 private static void resetTaskFiles(Map<TaskFile, TaskFile> savedTaskFiles) {
166 for (Map.Entry<TaskFile, TaskFile> entry : savedTaskFiles.entrySet()) {
167 entry.getKey().setAnswerPlaceholders(entry.getValue().getAnswerPlaceholders());
171 private static void synchronize(@NotNull final Project project) {
172 VirtualFileManager.getInstance().refreshWithoutFileWatcher(true);
173 ProjectView.getInstance(project).refresh();
176 private void packCourse(@NotNull final VirtualFile baseDir) {
178 final File zipFile = new File(myLocationDir, myZipName + ".zip");
179 ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(zipFile)));
180 VirtualFile[] courseFiles = baseDir.getChildren();
181 for (VirtualFile file : courseFiles) {
182 ZipUtil.addFileOrDirRecursively(zos, null, new File(file.getPath()), file.getName(), null, null);
185 Messages.showInfoMessage("Course archive was saved to " + zipFile.getPath(), "Course Archive Was Created Successfully");
187 catch (IOException e1) {
192 @SuppressWarnings("IOResourceOpenedButNotSafelyClosed")
193 private static void generateJson(@NotNull final Project project, VirtualFile parentDir) {
194 final Course course = StudyTaskManager.getInstance(project).getCourse();
195 final Gson gson = new GsonBuilder().setPrettyPrinting().excludeFieldsWithoutExposeAnnotation().create();
196 final String json = gson.toJson(course);
197 final File courseJson = new File(parentDir.getPath(), EduNames.COURSE_META_FILE);
198 OutputStreamWriter outputStreamWriter = null;
200 outputStreamWriter = new OutputStreamWriter(new FileOutputStream(courseJson), "UTF-8");
201 outputStreamWriter.write(json);
203 catch (Exception e) {
204 Messages.showErrorDialog(e.getMessage(), "Failed to Generate Json");
209 if (outputStreamWriter != null) {
210 outputStreamWriter.close();
213 catch (IOException e1) {