remove usages of redundant CCProjectService
[idea/community.git] / python / educational-core / course-creator / src / com / jetbrains / edu / coursecreator / actions / CCCreateCourseArchive.java
1 package com.jetbrains.edu.coursecreator.actions;
2
3 import com.google.gson.Gson;
4 import com.google.gson.GsonBuilder;
5 import com.intellij.icons.AllIcons;
6 import com.intellij.ide.projectView.ProjectView;
7 import com.intellij.openapi.actionSystem.AnActionEvent;
8 import com.intellij.openapi.actionSystem.CommonDataKeys;
9 import com.intellij.openapi.actionSystem.LangDataKeys;
10 import com.intellij.openapi.actionSystem.Presentation;
11 import com.intellij.openapi.application.ApplicationManager;
12 import com.intellij.openapi.diagnostic.Logger;
13 import com.intellij.openapi.module.Module;
14 import com.intellij.openapi.project.DumbAwareAction;
15 import com.intellij.openapi.project.Project;
16 import com.intellij.openapi.ui.DialogWrapper;
17 import com.intellij.openapi.ui.Messages;
18 import com.intellij.openapi.util.io.FileUtil;
19 import com.intellij.openapi.vfs.VfsUtil;
20 import com.intellij.openapi.vfs.VirtualFile;
21 import com.intellij.openapi.vfs.VirtualFileManager;
22 import com.intellij.util.containers.HashMap;
23 import com.intellij.util.io.ZipUtil;
24 import com.jetbrains.edu.learning.StudyTaskManager;
25 import com.jetbrains.edu.learning.core.EduNames;
26 import com.jetbrains.edu.learning.core.EduUtils;
27 import com.jetbrains.edu.learning.courseFormat.Course;
28 import com.jetbrains.edu.learning.courseFormat.Lesson;
29 import com.jetbrains.edu.learning.courseFormat.Task;
30 import com.jetbrains.edu.learning.courseFormat.TaskFile;
31 import com.jetbrains.edu.coursecreator.CCLanguageManager;
32 import com.jetbrains.edu.coursecreator.CCUtils;
33 import com.jetbrains.edu.coursecreator.ui.CreateCourseArchiveDialog;
34 import org.jetbrains.annotations.NotNull;
35
36 import java.io.*;
37 import java.util.List;
38 import java.util.Map;
39 import java.util.zip.ZipOutputStream;
40
41 public class CCCreateCourseArchive extends DumbAwareAction {
42   private static final Logger LOG = Logger.getInstance(CCCreateCourseArchive.class.getName());
43   private String myZipName;
44   private String myLocationDir;
45
46   public void setZipName(String zipName) {
47     myZipName = zipName;
48   }
49
50   public void setLocationDir(String locationDir) {
51     myLocationDir = locationDir;
52   }
53
54   public CCCreateCourseArchive() {
55     super("Generate Course Archive", "Generate Course Archive", AllIcons.FileTypes.Archive);
56   }
57
58   @Override
59   public void update(@NotNull AnActionEvent e) {
60     Presentation presentation = e.getPresentation();
61     Project project = e.getProject();
62     presentation.setEnabledAndVisible(project != null && CCUtils.isCourseCreator(project));
63   }
64
65   @Override
66   public void actionPerformed(@NotNull AnActionEvent e) {
67     final Project project = e.getData(CommonDataKeys.PROJECT);
68     final Module module = e.getData(LangDataKeys.MODULE);
69     if (project == null || module == null) {
70       return;
71     }
72     createCourseArchive(project, module);
73   }
74
75   private void createCourseArchive(final Project project, Module module) {
76     final Course course = StudyTaskManager.getInstance(project).getCourse();
77     if (course == null) return;
78     CreateCourseArchiveDialog dlg = new CreateCourseArchiveDialog(project, this);
79     dlg.show();
80     if (dlg.getExitCode() != DialogWrapper.OK_EXIT_CODE) {
81       return;
82     }
83     final VirtualFile baseDir = project.getBaseDir();
84
85     VirtualFile archiveFolder = CCUtils.generateFolder(project, module, this, myZipName);
86     if (archiveFolder == null) {
87       return;
88     }
89
90     CCLanguageManager manager = CCUtils.getStudyLanguageManager(course);
91     if (manager == null) {
92       return;
93     }
94     FileFilter filter = new FileFilter() {
95       @Override
96       public boolean accept(File pathname) {
97         return !manager.doNotPackFile(pathname);
98       }
99     };
100
101     for (VirtualFile child : baseDir.getChildren()) {
102       String name = child.getName();
103       File fromFile = new File(child.getPath());
104       if (CCUtils.GENERATED_FILES_FOLDER.equals(name) || ".idea".equals(name)
105           || name.contains("iml") || manager.doNotPackFile(fromFile)) {
106         continue;
107       }
108       copyChild(archiveFolder, filter, child, fromFile);
109     }
110
111     final List<Lesson> lessons = course.getLessons();
112
113     ApplicationManager.getApplication().runWriteAction(new Runnable() {
114       @Override
115       public void run() {
116         final Map<TaskFile, TaskFile> savedTaskFiles = new HashMap<TaskFile, TaskFile>();
117         replaceAnswerFilesWithTaskFiles(savedTaskFiles);
118         generateJson(project, archiveFolder);
119         resetTaskFiles(savedTaskFiles);
120         VirtualFileManager.getInstance().refreshWithoutFileWatcher(false);
121         packCourse(archiveFolder);
122         synchronize(project);
123       }
124
125       private void replaceAnswerFilesWithTaskFiles(Map<TaskFile, TaskFile> savedTaskFiles) {
126         for (Lesson lesson : lessons) {
127           final VirtualFile lessonDir = baseDir.findChild(EduNames.LESSON + String.valueOf(lesson.getIndex()));
128           if (lessonDir == null) continue;
129           for (Task task : lesson.getTaskList()) {
130             final VirtualFile taskDir = lessonDir.findChild(EduNames.TASK + String.valueOf(task.getIndex()));
131             if (taskDir == null) continue;
132             for (final Map.Entry<String, TaskFile> entry : task.getTaskFiles().entrySet()) {
133               TaskFile taskFileCopy = new TaskFile();
134               TaskFile taskFile = entry.getValue();
135               TaskFile.copy(taskFile, taskFileCopy);
136               savedTaskFiles.put(taskFile, taskFileCopy);
137
138               VirtualFile userFileDir = VfsUtil.findRelativeFile(archiveFolder, lessonDir.getName(), taskDir.getName());
139               if (userFileDir == null) {
140                 continue;
141               }
142               String taskFileName = entry.getKey();
143               EduUtils.createStudentFileFromAnswer(project, userFileDir, taskDir, taskFileName, taskFile);
144             }
145           }
146         }
147       }
148     });
149
150
151   }
152
153   private static void copyChild(VirtualFile archiveFolder, FileFilter filter, VirtualFile child, File fromFile) {
154     File toFile = new File(archiveFolder.getPath(), child.getName());
155
156     try {
157       if (child.isDirectory()) {
158         FileUtil.copyDir(fromFile, toFile, filter);
159       }
160       else {
161         if (filter.accept(fromFile)) {
162           FileUtil.copy(fromFile, toFile);
163         }
164       }
165     }
166     catch (IOException e) {
167       LOG.info("Failed to copy" + fromFile.getPath(), e);
168     }
169   }
170
171   private static void resetTaskFiles(Map<TaskFile, TaskFile> savedTaskFiles) {
172     for (Map.Entry<TaskFile, TaskFile> entry : savedTaskFiles.entrySet()) {
173       entry.getKey().setAnswerPlaceholders(entry.getValue().getAnswerPlaceholders());
174     }
175   }
176
177   private static void synchronize(@NotNull final Project project) {
178     VirtualFileManager.getInstance().refreshWithoutFileWatcher(true);
179     ProjectView.getInstance(project).refresh();
180   }
181
182   private void packCourse(@NotNull final VirtualFile baseDir) {
183     try {
184       final File zipFile = new File(myLocationDir, myZipName + ".zip");
185       ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(zipFile)));
186       VirtualFile[] courseFiles = baseDir.getChildren();
187       for (VirtualFile file : courseFiles) {
188         ZipUtil.addFileOrDirRecursively(zos, null, new File(file.getPath()), file.getName(), null, null);
189       }
190       zos.close();
191       Messages.showInfoMessage("Course archive was saved to " + zipFile.getPath(), "Course Archive Was Created Successfully");
192     }
193     catch (IOException e1) {
194       LOG.error(e1);
195     }
196   }
197
198   @SuppressWarnings("IOResourceOpenedButNotSafelyClosed")
199   private static void generateJson(@NotNull final Project project, VirtualFile parentDir) {
200     final Course course = StudyTaskManager.getInstance(project).getCourse();
201     final Gson gson = new GsonBuilder().setPrettyPrinting().excludeFieldsWithoutExposeAnnotation().create();
202     final String json = gson.toJson(course);
203     final File courseJson = new File(parentDir.getPath(), EduNames.COURSE_META_FILE);
204     OutputStreamWriter outputStreamWriter = null;
205     try {
206       outputStreamWriter = new OutputStreamWriter(new FileOutputStream(courseJson), "UTF-8");
207       outputStreamWriter.write(json);
208     }
209     catch (Exception e) {
210       Messages.showErrorDialog(e.getMessage(), "Failed to Generate Json");
211       LOG.info(e);
212     }
213     finally {
214       try {
215         if (outputStreamWriter != null) {
216           outputStreamWriter.close();
217         }
218       }
219       catch (IOException e1) {
220         //close silently
221       }
222     }
223   }
224 }