package org.jetbrains.plugins.coursecreator.actions; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.intellij.icons.AllIcons; import com.intellij.ide.projectView.ProjectView; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileManager; import com.intellij.util.io.ZipUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.coursecreator.CCProjectService; import org.jetbrains.plugins.coursecreator.StudyDocumentListener; import org.jetbrains.plugins.coursecreator.format.*; import org.jetbrains.plugins.coursecreator.ui.CreateCourseArchiveDialog; import java.io.*; import java.util.*; import java.util.zip.ZipOutputStream; public class CreateCourseArchive extends DumbAwareAction { private static final Logger LOG = Logger.getInstance(CreateCourseArchive.class.getName()); private String myZipName; private String myLocationDir; public void setZipName(String zipName) { myZipName = zipName; } public void setLocationDir(String locationDir) { myLocationDir = locationDir; } public CreateCourseArchive() { super("Generate course archive", "Generate course archive", AllIcons.FileTypes.Archive); } @Override public void actionPerformed(AnActionEvent e) { final Project project = e.getData(CommonDataKeys.PROJECT); if (project == null) { return; } final CCProjectService service = CCProjectService.getInstance(project); final Course course = service.getCourse(); if (course == null) return; CreateCourseArchiveDialog dlg = new CreateCourseArchiveDialog(project, this); dlg.show(); if (dlg.getExitCode() != DialogWrapper.OK_EXIT_CODE) { return; } final VirtualFile baseDir = project.getBaseDir(); final Map lessons = course.getLessonsMap(); //map to store initial task file final Map taskFiles = new HashMap(); for (Map.Entry lesson : lessons.entrySet()) { final VirtualFile lessonDir = baseDir.findChild(lesson.getKey()); if (lessonDir == null) continue; for (Map.Entry task : lesson.getValue().myTasksMap.entrySet()) { final VirtualFile taskDir = lessonDir.findChild(task.getKey()); if (taskDir == null) continue; for (final Map.Entry entry : task.getValue().task_files.entrySet()) { ApplicationManager.getApplication().runWriteAction(new Runnable() { @Override public void run() { createUserFile(project, taskFiles, taskDir, taskDir, entry); } }); } } } generateJson(project); packCourse(baseDir, lessons); resetTaskFiles(taskFiles); synchronize(project); } public static void createUserFile(@NotNull final Project project, @NotNull final Map taskFilesCopy, @NotNull final VirtualFile userFileDir, @NotNull final VirtualFile answerFileDir, @NotNull final Map.Entry taskFiles) { final String name = taskFiles.getKey(); VirtualFile file = userFileDir.findChild(name); if (file != null) { try { file.delete(project); } catch (IOException e) { LOG.error(e); } } try { userFileDir.createChildData(project, name); } catch (IOException e) { LOG.error(e); } file = userFileDir.findChild(name); assert file != null; String answerFileName = file.getNameWithoutExtension() + ".answer"; VirtualFile answerFile = answerFileDir.findChild(answerFileName); if (answerFile == null) { return; } final Document answerDocument = FileDocumentManager.getInstance().getDocument(answerFile); if (answerDocument == null) { return; } final Document document = FileDocumentManager.getInstance().getDocument(file); if (document == null) return; final TaskFile taskFile = taskFiles.getValue(); TaskFile taskFileSaved = new TaskFile(); taskFile.copy(taskFileSaved); CommandProcessor.getInstance().executeCommand(project, new Runnable() { @Override public void run() { ApplicationManager.getApplication().runWriteAction(new Runnable() { @Override public void run() { document.replaceString(0, document.getTextLength(), answerDocument.getText()); } }); } }, "x", "qwe"); InsertionListener listener = new InsertionListener(taskFile); document.addDocumentListener(listener); taskFilesCopy.put(taskFile, taskFileSaved); Collections.sort(taskFile.getTaskWindows()); for (int i = taskFile.getTaskWindows().size() - 1; i >= 0; i--) { final TaskWindow taskWindow = taskFile.getTaskWindows().get(i); replaceTaskWindow(project, document, taskWindow); } document.removeDocumentListener(listener); } private static void replaceTaskWindow(@NotNull final Project project, @NotNull final Document document, @NotNull final TaskWindow taskWindow) { final String taskText = taskWindow.getTaskText(); final int lineStartOffset = document.getLineStartOffset(taskWindow.line); final int offset = lineStartOffset + taskWindow.start; CommandProcessor.getInstance().executeCommand(project, new Runnable() { @Override public void run() { ApplicationManager.getApplication().runWriteAction(new Runnable() { @Override public void run() { document.replaceString(offset, offset + taskWindow.getReplacementLength(), taskText); FileDocumentManager.getInstance().saveDocument(document); } }); } }, "x", "qwe"); } private static void synchronize(@NotNull final Project project) { VirtualFileManager.getInstance().refreshWithoutFileWatcher(true); ProjectView.getInstance(project).refresh(); } public static void resetTaskFiles(@NotNull final Map taskFiles) { for (Map.Entry entry : taskFiles.entrySet()) { TaskFile realTaskFile = entry.getKey(); TaskFile savedTaskFile = entry.getValue(); realTaskFile.update(savedTaskFile); } } private void packCourse(@NotNull final VirtualFile baseDir, @NotNull final Map lessons) { try { File zipFile = new File(myLocationDir, myZipName + ".zip"); ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(zipFile))); for (Map.Entry entry : lessons.entrySet()) { final VirtualFile lessonDir = baseDir.findChild(entry.getKey()); if (lessonDir == null) continue; ZipUtil.addFileOrDirRecursively(zos, null, new File(lessonDir.getPath()), lessonDir.getName(), new FileFilter() { @Override public boolean accept(File pathname) { return !pathname.getName().contains(".answer"); } }, null); } ZipUtil.addFileOrDirRecursively(zos, null, new File(baseDir.getPath(), "hints"), "hints", null, null); ZipUtil.addFileOrDirRecursively(zos, null, new File(baseDir.getPath(), "course.json"), "course.json", null, null); ZipUtil.addFileOrDirRecursively(zos, null, new File(baseDir.getPath(), "test_helper.py"), "test_helper.py", null, null); zos.close(); Messages.showInfoMessage("Course archive was saved to " + zipFile.getPath(), "Course Archive Was Created Successfully"); } catch (IOException e1) { LOG.error(e1); } } private static void generateJson(@NotNull final Project project) { final CCProjectService service = CCProjectService.getInstance(project); final Course course = service.getCourse(); final Gson gson = new GsonBuilder().setPrettyPrinting().excludeFieldsWithoutExposeAnnotation().create(); final String json = gson.toJson(course); final File courseJson = new File(project.getBasePath(), "course.json"); FileWriter writer = null; try { writer = new FileWriter(courseJson); writer.write(json); } catch (IOException e) { Messages.showErrorDialog(e.getMessage(), "Failed to Generate Json"); LOG.info(e); } catch (Exception e) { Messages.showErrorDialog(e.getMessage(), "Failed to Generate Json"); LOG.info(e); } finally { try { if (writer != null) { writer.close(); } } catch (IOException e1) { //close silently } } } private static class InsertionListener extends StudyDocumentListener { public InsertionListener(TaskFile taskFile) { super(taskFile); } @Override protected void updateTaskWindowLength(CharSequence fragment, TaskWindow taskWindow, int change) { //we don't need to update task window length } } }