package jetbrains.mps.tool.builder;
/*Generated by MPS */
import org.apache.log4j.Logger;
import org.apache.log4j.LogManager;
import java.util.List;
import java.util.ArrayList;
import jetbrains.mps.tool.common.Script;
import jetbrains.mps.compiler.JavaCompilerOptions;
import jetbrains.mps.tool.environment.Environment;
import jetbrains.mps.tool.common.JavaCompilerProperties;
import jetbrains.mps.compiler.JavaCompilerOptionsComponent;
import jetbrains.mps.tool.environment.MpsEnvironment;
import jetbrains.mps.tool.environment.EnvironmentConfig;
import jetbrains.mps.internal.collections.runtime.IMapping;
import jetbrains.mps.internal.collections.runtime.MapSequence;
import java.io.File;
import jetbrains.mps.project.Project;
import jetbrains.mps.smodel.MPSModuleRepository;
import jetbrains.mps.make.MPSCompilationResult;
import jetbrains.mps.smodel.ModelAccessHelper;
import jetbrains.mps.util.Computable;
import jetbrains.mps.make.ModuleMaker;
import jetbrains.mps.util.IterableUtil;
import jetbrains.mps.progress.EmptyProgressMonitor;
import jetbrains.mps.classloading.ClassLoaderManager;
import java.util.Set;
import org.jetbrains.mps.openapi.model.SModel;
import org.jetbrains.mps.openapi.module.SModule;
import jetbrains.mps.smodel.SModelStereotype;
import jetbrains.mps.generator.GenerationFacade;
import java.util.Collection;
import jetbrains.mps.project.io.DescriptorIOFacade;
import jetbrains.mps.vfs.FileSystem;
import jetbrains.mps.smodel.ModuleFileTracker;
import java.util.Collections;
import jetbrains.mps.vfs.IFile;
import jetbrains.mps.smodel.BaseMPSModuleOwner;
import jetbrains.mps.library.ModulesMiner;
import jetbrains.mps.smodel.ModuleRepositoryFacade;
import jetbrains.mps.project.DevKit;
import jetbrains.mps.smodel.Language;
import jetbrains.mps.smodel.Generator;
import org.apache.log4j.Level;
import java.io.StringWriter;
import java.io.PrintWriter;
import java.util.LinkedHashSet;
public abstract class MpsWorker {
private static final Logger LOG = LogManager.getLogger(MpsWorker.class);
protected final List<String> myErrors = new ArrayList<String>();
protected final List<String> myWarnings = new ArrayList<String>();
protected final Script myWhatToDo;
protected final JavaCompilerOptions myJavaCompilerOptions;
protected final boolean mySkipCompilation;
private final MpsWorker.AntLogger myLogger;
protected Environment myEnvironment;
public MpsWorker(Script whatToDo, MpsWorker.AntLogger logger) {
myWhatToDo = whatToDo;
myLogger = logger;
JavaCompilerProperties javaProperties = new JavaCompilerProperties(myWhatToDo);
myJavaCompilerOptions = getJavaCompilerOptions(javaProperties);
mySkipCompilation = javaProperties.isSkipCompilation();
}
private static JavaCompilerOptions getJavaCompilerOptions(JavaCompilerProperties javaProperties) {
JavaCompilerOptionsComponent.JavaVersion parsedJavaVersion = JavaCompilerOptionsComponent.JavaVersion.parse(javaProperties.getTargetJavaVersion());
if (parsedJavaVersion == null) {
return JavaCompilerOptionsComponent.DEFAULT_JAVA_COMPILER_OPTIONS;
}
return new JavaCompilerOptions(parsedJavaVersion);
}
protected Environment createEnvironment() {
Environment env = MpsEnvironment.getOrCreate(createEnvConfig(myWhatToDo));
Logger.getRootLogger().setLevel(myWhatToDo.getLogLevel());
return env;
}
public static EnvironmentConfig createEnvConfig(Script whatToDo) {
EnvironmentConfig config = EnvironmentConfig.defaultConfig();
for (IMapping<String, String> macro : MapSequence.fromMap(whatToDo.getMacro())) {
config = config.addMacro(macro.key(), new File(macro.value()));
}
for (IMapping<String, File> lib : MapSequence.fromMap(whatToDo.getLibraries())) {
config = config.addLib(lib.value().getAbsolutePath());
}
if (whatToDo.isLoadBootstrapLibraries()) {
config = config.withBootstrapLibraries();
}
return config;
}
public void workFromMain() {
try {
work();
System.exit(0);
} catch (Throwable e) {
log(e);
System.exit(1);
}
}
public abstract void work();
protected Project createDummyProject() {
return myEnvironment.createEmptyProject();
}
protected void dispose() {
if (myEnvironment != null) {
myEnvironment.dispose();
myEnvironment = null;
}
}
protected void setupEnvironment() {
myEnvironment = createEnvironment();
make();
}
protected void make() {
// FIXME why do I care to make these modules?
final MPSModuleRepository repo = myEnvironment.getPlatform().findComponent(MPSModuleRepository.class);
MPSCompilationResult mpsCompilationResult = new ModelAccessHelper(repo).runReadAction(new Computable<MPSCompilationResult>() {
public MPSCompilationResult compute() {
ModuleMaker maker = new ModuleMaker();
return maker.make(IterableUtil.asCollection(repo.getModules()), new EmptyProgressMonitor(), myJavaCompilerOptions);
}
});
reload(mpsCompilationResult);
}
protected void reload(final MPSCompilationResult mpsCompilationResult) {
if (mpsCompilationResult.isReloadingNeeded()) {
myEnvironment.getPlatform().findComponent(MPSModuleRepository.class).getModelAccess().runWriteAction(new Runnable() {
public void run() {
ClassLoaderManager.getInstance().reloadModules(mpsCompilationResult.getChangedModules());
}
});
}
}
protected abstract void executeTask(Project project, MpsWorker.ObjectsToProcess go);
protected abstract void showStatistic();
protected StringBuffer formatErrorsReport(String taskName) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < 100; i++) {
sb.append('*');
}
sb.append("\n");
sb.append(myErrors.size());
sb.append(" errors during " + taskName + ":\n");
for (String error : myErrors) {
sb.append(error);
sb.append("\n");
}
for (int i = 0; i < 100; i++) {
sb.append('*');
}
return sb;
}
protected void failBuild(String name) {
if (!(myErrors.isEmpty()) && myWhatToDo.getFailOnError()) {
throw new RuntimeException(this.formatErrorsReport(name).toString());
}
}
protected void extractModels(Set<SModel> result, Project project) {
for (SModule module : project.getProjectModulesWithGenerators()) {
for (SModel model : module.getModels()) {
if (includeModel(model)) {
result.add(model);
}
}
}
}
private boolean includeModel(SModel model) {
return SModelStereotype.isUserModel(model) && GenerationFacade.canGenerate(model);
}
protected void extractModels(Collection<SModel> modelsList, SModule m) {
for (SModel d : m.getModels()) {
if (includeModel(d)) {
modelsList.add(d);
}
}
}
protected void collectFromModuleFiles(Set<SModule> modules) {
// FIXME GenTestWorker/GenTestTask still use module files as configuration argument (from Java code perspective, need to check actual tasks in scripts and generator thereof)
for (File moduleFile : myWhatToDo.getModules()) {
processModuleFile(moduleFile, modules);
}
}
protected void processModuleFile(final File moduleFile, final Set<SModule> modules) {
if (DescriptorIOFacade.getInstance().fromFileType(FileSystem.getInstance().getFileByPath(moduleFile.getPath())) == null) {
return;
}
List<SModule> tmpmodules = new ArrayList<SModule>();
SModule moduleByFile = ModuleFileTracker.getInstance().getModuleByFile(FileSystem.getInstance().getFileByPath(moduleFile.getAbsolutePath()));
if (moduleByFile != null) {
tmpmodules = Collections.singletonList(moduleByFile);
} else {
// XXX moduleFile.getPath vs moduleFile.getAbsolutePath above - why is it different?
IFile file = FileSystem.getInstance().getFileByPath(moduleFile.getPath());
// XXX new owner for each module?!
BaseMPSModuleOwner owner = new BaseMPSModuleOwner();
for (ModulesMiner.ModuleHandle moduleHandle : new ModulesMiner().collectModules(file).getCollectedModules()) {
SModule module = ModuleRepositoryFacade.createModule(moduleHandle, owner);
if (module != null) {
tmpmodules.add(module);
}
}
}
for (SModule module : tmpmodules) {
info("Loaded module " + module);
// XXX it's suspicious to ignore read-only module and DevKit when we have no idea what's the reason to load the module in the first place.
if (module.isReadOnly()) {
continue;
}
if (module instanceof DevKit) {
continue;
}
modules.add(module);
// FIXME Although MM.getCollectedModules gives us Generator modules directly, keep this code to handle ModuleFileTracker case, it's a Set anyway.
// Have to decide whether that branch makes sense at all. ModuleFileTracker likely to change anyway, if we allow more modules per 1 file.
if (module instanceof Language) {
Language language = (Language) module;
for (Generator gen : language.getGenerators()) {
modules.add(gen);
}
}
}
}
private void log(String text, Level level) {
if (!(level.isGreaterOrEqual(myWhatToDo.getLogLevel()))) {
return;
}
myLogger.log(text, level);
}
public void info(String text) {
log(text, Level.INFO);
}
public void warning(String text) {
log(text, Level.WARN);
myWarnings.add(text);
}
public void debug(String text) {
log(text, Level.DEBUG);
}
public void error(String text) {
log(text, Level.ERROR);
myErrors.add(text);
}
public void log(Throwable e) {
StringBuffer sb = MpsWorker.extractStackTrace(e);
error(sb.toString());
}
public void log(String text, Throwable e) {
StringBuffer sb = MpsWorker.extractStackTrace(e);
error(text + "\n" + sb.toString());
}
public static StringBuffer extractStackTrace(Throwable e) {
StringWriter writer = new StringWriter();
e.printStackTrace(new PrintWriter(writer));
return writer.getBuffer();
}
public interface AntLogger {
void log(String text, Level level);
}
public static class SystemOutLogger implements MpsWorker.AntLogger {
public SystemOutLogger() {
}
@Override
public void log(String text, Level level) {
if (level == Level.ERROR) {
System.err.println(text);
} else {
System.out.println(text);
}
}
}
public static class LogLogger implements MpsWorker.AntLogger {
public LogLogger() {
}
@Override
public void log(String text, Level level) {
switch (level.toInt()) {
case Level.ERROR_INT:
if (LOG.isEnabledFor(Level.ERROR)) {
LOG.error(text);
}
break;
case Level.WARN_INT:
if (LOG.isEnabledFor(Level.WARN)) {
LOG.warn(text);
}
break;
case Level.INFO_INT:
if (LOG.isInfoEnabled()) {
LOG.info(text);
}
break;
case Level.DEBUG_INT:
if (LOG.isDebugEnabled()) {
LOG.debug(text);
}
break;
default:
if (LOG.isEnabledFor(Level.FATAL)) {
LOG.fatal("[unknown level " + level + "] " + text);
}
break;
}
}
}
protected class ObjectsToProcess {
private final Set<Project> myProjects = new LinkedHashSet<Project>();
private final Set<SModule> myModules = new LinkedHashSet<SModule>();
private final Set<SModel> myModels = new LinkedHashSet<SModel>();
public ObjectsToProcess() {
}
public ObjectsToProcess(Set<? extends Project> mpsProjects, Set<SModule> modules, Set<SModel> models) {
myProjects.addAll(mpsProjects);
myModules.addAll(modules);
myModels.addAll(models);
}
public Set<Project> getProjects() {
return myProjects;
}
public Set<SModule> getModules() {
return myModules;
}
public Set<SModel> getModels() {
return myModels;
}
public boolean hasAnythingToGenerate() {
return !(myModels.isEmpty()) || !(myProjects.isEmpty()) || !(myModules.isEmpty());
}
}
}