package jetbrains.mps.ide.migration.wizard; /*Generated by MPS */ import org.apache.log4j.Logger; import org.apache.log4j.LogManager; import com.intellij.history.LocalHistoryAction; import java.util.List; import jetbrains.mps.ide.migration.ScriptApplied; import jetbrains.mps.internal.collections.runtime.ListSequence; import java.util.ArrayList; import jetbrains.mps.progress.ProgressMonitorAdapter; import jetbrains.mps.persistence.PersistenceRegistry; import org.apache.log4j.Level; import java.util.Map; import org.jetbrains.mps.openapi.module.SModule; import jetbrains.mps.internal.collections.runtime.MapSequence; import jetbrains.mps.project.Project; import com.intellij.history.LocalHistory; import jetbrains.mps.ide.project.ProjectHelper; import java.awt.Color; import jetbrains.mps.baseLanguage.closures.runtime._FunctionTypes; import jetbrains.mps.baseLanguage.closures.runtime.Wrappers; import org.jetbrains.mps.openapi.util.ProgressMonitor; import javax.swing.JComponent; import com.intellij.openapi.wm.impl.status.InlineProgressIndicator; import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.application.ApplicationManager; import jetbrains.mps.migration.global.ProjectMigration; import jetbrains.mps.migration.global.CleanupProjectMigration; import java.util.HashMap; import jetbrains.mps.internal.collections.runtime.Sequence; import jetbrains.mps.migration.component.util.MigrationsUtil; import java.util.Set; import jetbrains.mps.internal.collections.runtime.SetSequence; import java.util.HashSet; import jetbrains.mps.project.dependency.GlobalModuleDependenciesManager; import jetbrains.mps.internal.collections.runtime.ISelector; import jetbrains.mps.internal.collections.runtime.IVisitor; import jetbrains.mps.internal.collections.runtime.IWhereFilter; import jetbrains.mps.ide.migration.check.MigrationCheckUtil; import jetbrains.mps.lang.migration.runtime.base.BaseScriptReference; import jetbrains.mps.util.NameUtil; public class MigrationTask { private static final Logger LOG = LogManager.getLogger(MigrationTask.class); public static final String STARTED = "Migration started"; public static final String FINISHED = "Migration finished"; public static final String APPLY = "Applying migration "; private MigrationSession mySession; private volatile boolean myIsComplete = false; private LocalHistoryAction myCurrentChange = null; private List<ScriptApplied> myWereRun = ListSequence.fromList(new ArrayList<ScriptApplied>()); private ProgressMonitorAdapter myMonitor; private int myLastStep = 0; public MigrationTask(MigrationSession session, ProgressMonitorAdapter monitor) { mySession = session; myMonitor = monitor; myLastStep = 0; myMonitor.start("Migrating...", 100); } public void run() { PersistenceRegistry.getInstance().disableFastFindUsages(); try { mySession.setErrorDescriptor(null); myIsComplete = doRun(); } catch (Throwable t) { if (LOG.isEnabledFor(Level.ERROR)) { LOG.error("exception occurred on pre-migration check", t); } } PersistenceRegistry.getInstance().enableFastFindUsages(); } protected boolean doRun() { if (myLastStep == 0) { myLastStep++; List<ScriptApplied> missingMigrations = findMissingMigrations(myMonitor.subTask(5)); if (ListSequence.fromList(missingMigrations).isNotEmpty()) { result(myMonitor, new MigrationsMissingError(missingMigrations), "Some migrations are missing."); return false; } } if (myLastStep == 1) { myLastStep++; if (!((runCleanupMigrations(myMonitor.subTask(10))))) { result(myMonitor, new MigrationExceptionError(), "Error while running cleanup migration."); return false; } } if (myLastStep == 2) { myLastStep++; Map<SModule, SModule> errsToShow = checkMigratedLibs(myMonitor.subTask(5)); if (MapSequence.fromMap(errsToShow).isNotEmpty()) { result(myMonitor, new NotMigratedLibsError(errsToShow), "Some dependent modules are not migrated."); return false; } } if (myLastStep == 3) { myLastStep++; // null - no error, true - must stop, false - can ignore boolean errors = checkModels(myMonitor.subTask(20)); if (errors) { result(myMonitor, new PreCheckError(mySession.getProject(), errors), "Errors were found in models"); return false; } } // from here, we don't ignore errors addGlobalLabel(mySession.getProject(), STARTED); if (!((runProjectMigrations(myMonitor.subTask(5))))) { result(myMonitor, new MigrationExceptionError(), "Exception while running migration"); return true; } if (!((runLanguageMigrations(myMonitor.subTask(40))))) { result(myMonitor, new MigrationExceptionError(), "Exception while running migration"); return true; } addGlobalLabel(mySession.getProject(), FINISHED); // todo move from here to migration annotations if (findNotMigrated(myMonitor.subTask(15))) { result(myMonitor, new PostCheckError(mySession.getProject(), myWereRun, false), "Problems are detected after executing migrations."); return true; } result(myMonitor, null, "Done!"); myMonitor.done(); return true; } protected static void addGlobalLabel(Project p, String label) { LocalHistory.getInstance().putSystemLabel(ProjectHelper.toIdeaProject(p), label, Color.ORANGE.getRGB()); } protected void result(ProgressMonitorAdapter m, MigrationErrorDescriptor error, String msg) { m.step(msg); m.advance(0); mySession.setErrorDescriptor(error); } public boolean forceComplete() { myMonitor.done(); return myIsComplete = true; } public boolean isComplete() { return myIsComplete; } private static _FunctionTypes._void_P1_E0<? super Double> frac2inc(final int amount, final _FunctionTypes._void_P1_E0<? super Integer> progress) { final Wrappers._int done = new Wrappers._int(0); return new _FunctionTypes._void_P1_E0<Double>() { public void invoke(Double fraction) { int newDone = (int) Math.round(fraction * amount); progress.invoke(newDone - done.value); done.value = newDone; } }; } private boolean executeSingleStep(final ProgressMonitor m, final String localHistCaption, final _FunctionTypes._void_P0_E0 execute, final _FunctionTypes._return_P0_E0<? extends Boolean> merge) { final Wrappers._boolean noException = new Wrappers._boolean(true); // todo pass ModalityState to constructor/via session? // in tests, we have EmptyProgressIndicator and use NON_MODAL JComponent modalityComponent = check_ajmasp_a0e0cb(as_ajmasp_a0a0e0db(myMonitor.getIndicator(), InlineProgressIndicator.class)); ModalityState modalityState = (modalityComponent == null ? ModalityState.NON_MODAL : ModalityState.stateForComponent(modalityComponent)); ApplicationManager.getApplication().invokeAndWait(new Runnable() { public void run() { if (myCurrentChange == null) { myCurrentChange = LocalHistory.getInstance().startAction(APPLY + localHistCaption); } mySession.getProject().getRepository().getModelAccess().executeCommand(new Runnable() { public void run() { try { execute.invoke(); } catch (Throwable t) { if (LOG.isEnabledFor(Level.ERROR)) { LOG.error("Exception during migration", t); } noException.value = false; } } }); if (merge == null || !(merge.invoke())) { final Project project = mySession.getProject(); m.step("Saving project..."); project.getRepository().getModelAccess().runWriteAction(new Runnable() { public void run() { project.getRepository().saveAll(); } }); myCurrentChange.finish(); myCurrentChange = null; } } }, modalityState); return noException.value; } private boolean runCleanupMigrations(ProgressMonitor m) { int cleanupStepsCount = mySession.getMigrationManager().projectStepsCount(true); m.start("Cleaning...", cleanupStepsCount); boolean success = true; if (cleanupStepsCount != 0) { addGlobalLabel(mySession.getProject(), "Cleanup started"); while (true) { final ProjectMigration pm = mySession.getMigrationManager().nextProjectStep(mySession.getOptions(), true); if (pm == null) { break; } m.step(pm.getDescription()); if (!(executeSingleStep(m, pm.getDescription(), new _FunctionTypes._void_P0_E0() { public void invoke() { pm.execute(mySession.getProject()); } }, null))) { success = false; if (pm instanceof CleanupProjectMigration) { ((CleanupProjectMigration) pm).forceExecutionNextTime(mySession.getProject()); } break; } m.advance(1); } addGlobalLabel(mySession.getProject(), "Cleanup finished"); } m.done(); return success; } private List<ScriptApplied> findMissingMigrations(ProgressMonitor m) { m.start("Checking migrations consistency...", 1); try { return mySession.getMigrationManager().getMissingMigrations(); } finally { m.done(); } } private Map<SModule, SModule> checkMigratedLibs(ProgressMonitor m) { m.start("Checking dependencies...", 1); final Map<SModule, SModule> errsToShow = MapSequence.fromMap(new HashMap<SModule, SModule>()); final Project mpsProject = mySession.getProject(); mpsProject.getRepository().getModelAccess().runReadAction(new Runnable() { public void run() { final List<SModule> projectModules = Sequence.fromIterable(MigrationsUtil.getMigrateableModulesFromProject(mpsProject)).toListSequence(); Set<SModule> depModules = SetSequence.fromSetWithValues(new HashSet<SModule>(), new GlobalModuleDependenciesManager(projectModules).getModules(GlobalModuleDependenciesManager.Deptype.VISIBLE)); SetSequence.fromSet(depModules).removeSequence(Sequence.fromIterable(((Iterable<SModule>) mpsProject.getModulesWithGenerators()))); List<ScriptApplied> depMigrationsToRun = mySession.getMigrationManager().getModuleMigrationsToApply(depModules); Iterable<SModule> notMigratedModules = ListSequence.fromList(depMigrationsToRun).select(new ISelector<ScriptApplied, SModule>() { public SModule select(ScriptApplied it) { return it.getModule(); } }).distinct(); Sequence.fromIterable(notMigratedModules).visitAll(new IVisitor<SModule>() { public void visit(final SModule notMigrated) { MapSequence.fromMap(errsToShow).put(notMigrated, ListSequence.fromList(projectModules).findFirst(new IWhereFilter<SModule>() { public boolean accept(SModule depCandidate) { return new GlobalModuleDependenciesManager(depCandidate).getModules(GlobalModuleDependenciesManager.Deptype.VISIBLE).contains(notMigrated); } })); } }); } }); m.done(); return errsToShow; } private boolean checkModels(final ProgressMonitor m) { final Wrappers._boolean hasErrors = new Wrappers._boolean(); final Project mpsProject = mySession.getProject(); mpsProject.getRepository().getModelAccess().runReadAction(new Runnable() { public void run() { List<SModule> modules = Sequence.fromIterable(MigrationsUtil.getMigrateableModulesFromProject(mpsProject)).toListSequence(); hasErrors.value = MigrationCheckUtil.haveProblems(modules, m); } }); return hasErrors.value; } private boolean runProjectMigrations(ProgressMonitor m) { int projectStepsCount = mySession.getMigrationManager().projectStepsCount(false); m.start("Running project migrations...", projectStepsCount); boolean success = true; while (true) { final ProjectMigration pm = mySession.getMigrationManager().nextProjectStep(mySession.getOptions(), false); if (pm == null) { break; } m.step(pm.getDescription()); if (!(executeSingleStep(m, pm.getDescription(), new _FunctionTypes._void_P0_E0() { public void invoke() { pm.execute(mySession.getProject()); } }, null))) { success = false; break; } m.advance(1); } m.done(); return success; } private boolean runLanguageMigrations(ProgressMonitor m) { int languageStepsCount = mySession.getMigrationManager().moduleStepsCount(); m.start("Running language migrations...", languageStepsCount); boolean success = true; final Wrappers._T<BaseScriptReference> preferredId = new Wrappers._T<BaseScriptReference>(null); while (true) { final ScriptApplied sa = mySession.getMigrationManager().nextModuleStep(preferredId.value); if (sa == null) { break; } preferredId.value = sa.getScriptReference(); String caption = sa.getScriptReference().resolve(false).getCaption(); m.step(caption + " [" + NameUtil.compactNamespace(sa.getModule().getModuleName()) + "]"); ListSequence.fromList(myWereRun).addElement(sa); if (!(executeSingleStep(m, caption, new _FunctionTypes._void_P0_E0() { public void invoke() { mySession.getMigrationManager().executeScript(sa); } }, new _FunctionTypes._return_P0_E0<Boolean>() { public Boolean invoke() { ScriptApplied next = mySession.getMigrationManager().nextModuleStep(preferredId.value); if (next == null) { return false; } return eq_ajmasp_a0c0a0a3a0h0f0pb(sa.getScriptReference(), next.getScriptReference()); } }))) { success = false; break; } m.advance(1); } m.done(); return success; } private boolean findNotMigrated(final ProgressMonitor m) { final Project project = mySession.getProject(); final Wrappers._boolean haveNotMigrated = new Wrappers._boolean(); project.getRepository().getModelAccess().runReadAction(new Runnable() { public void run() { Iterable<SModule> modules = MigrationsUtil.getMigrateableModulesFromProject(project); m.start("Finding not migrated code...", Sequence.fromIterable(modules).count()); haveNotMigrated.value = MigrationCheckUtil.haveNotMigrated(myWereRun, frac2inc(Sequence.fromIterable(modules).count(), new _FunctionTypes._void_P1_E0<Integer>() { public void invoke(Integer processed) { m.advance(processed); } })); } }); return haveNotMigrated.value; } private static JComponent check_ajmasp_a0e0cb(InlineProgressIndicator checkedDotOperand) { if (null != checkedDotOperand) { return checkedDotOperand.getComponent(); } return null; } private static <T> T as_ajmasp_a0a0e0db(Object o, Class<T> type) { return (type.isInstance(o) ? (T) o : null); } private static boolean eq_ajmasp_a0c0a0a3a0h0f0pb(Object a, Object b) { return (a != null ? a.equals(b) : a == b); } }