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);
}
}