package jetbrains.mps.ide.newSolutionDialog; /*Generated by MPS */ import jetbrains.mps.util.annotation.ToRemove; import jetbrains.mps.project.Solution; import jetbrains.mps.smodel.Language; import jetbrains.mps.project.MPSProject; import java.io.IOException; import java.io.File; import org.jetbrains.mps.openapi.model.EditableSModel; import jetbrains.mps.smodel.SModelInternal; import org.jetbrains.mps.openapi.language.SLanguage; import jetbrains.mps.smodel.adapter.structure.MetaAdapterFactory; import jetbrains.mps.smodel.SLanguageHierarchy; import jetbrains.mps.smodel.language.LanguageRegistry; import java.util.Collections; import jetbrains.mps.project.Project; import jetbrains.mps.vfs.IFile; import jetbrains.mps.project.MPSExtentions; import jetbrains.mps.project.structure.modules.SolutionDescriptor; import jetbrains.mps.project.persistence.SolutionDescriptorPersistence; import jetbrains.mps.util.MacrosFactory; import jetbrains.mps.smodel.ModuleRepositoryFacade; import jetbrains.mps.library.ModulesMiner; import jetbrains.mps.project.DevKit; import jetbrains.mps.project.structure.modules.DevkitDescriptor; import jetbrains.mps.project.persistence.DevkitDescriptorPersistence; import jetbrains.mps.baseLanguage.closures.runtime._FunctionTypes; import com.intellij.openapi.application.ApplicationManager; import org.jetbrains.mps.openapi.module.SRepository; import javax.lang.model.SourceVersion; import jetbrains.mps.ide.NewModuleCheckUtil; import jetbrains.mps.smodel.ModelAccessHelper; import jetbrains.mps.util.Computable; import jetbrains.mps.util.NameUtil; import jetbrains.mps.project.structure.modules.LanguageDescriptor; import jetbrains.mps.project.persistence.LanguageDescriptorPersistence; import jetbrains.mps.project.structure.modules.GeneratorDescriptor; import jetbrains.mps.smodel.Generator; import org.jetbrains.mps.openapi.model.SModel; import jetbrains.mps.smodel.SModelStereotype; import jetbrains.mps.project.SModuleOperations; import org.jetbrains.mps.openapi.model.SModelName; import org.jetbrains.mps.openapi.model.SNode; import jetbrains.mps.lang.smodel.generator.smodelAdapter.SModelOperations; import jetbrains.mps.lang.smodel.generator.smodelAdapter.SPropertyOperations; import jetbrains.mps.smodel.LanguageAspect; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import jetbrains.mps.persistence.DefaultModelRoot; import jetbrains.mps.project.structure.model.ModelRootDescriptor; import jetbrains.mps.persistence.MementoImpl; import jetbrains.mps.project.ProjectPathUtil; import jetbrains.mps.vfs.FileSystem; import jetbrains.mps.project.ModuleId; import org.jetbrains.mps.openapi.module.SModule; import org.jetbrains.mps.openapi.persistence.ModelRoot; @ToRemove(version = 3.5) public class NewModuleUtil { public static Solution createRuntimeSolution(Language language, String languageRootPath, MPSProject project) throws IOException { String basePath = languageRootPath + File.separator + "runtime"; String namespace = language.getModuleName() + ".runtime"; Solution runtime = NewModuleUtil.createSolution(namespace, basePath, project); EditableSModel runtimeModel = createModel(runtime, namespace); runtimeModel.save(); return runtime; } public static Solution createSandboxSolution(Language language, String languageRootPath, MPSProject project) throws IOException { String basePath = languageRootPath + File.separator + "sandbox"; String namespace = language.getModuleName() + ".sandbox"; Solution sandbox = NewModuleUtil.createSolution(namespace, basePath, project); SModelInternal sandboxModel = (SModelInternal) createModel(sandbox, namespace); SLanguage l = MetaAdapterFactory.getLanguage(language.getModuleReference()); sandboxModel.addLanguage(l); for (SLanguage extendedLanguage : new SLanguageHierarchy(LanguageRegistry.getInstance(project.getRepository()), Collections.singleton(l)).getExtended()) { sandboxModel.addLanguage(extendedLanguage); } sandbox.save(); ((EditableSModel) sandboxModel).save(); return sandbox; } /** * create new solution module and register it with the project */ public static Solution createSolution(String namespace, String rootPath, Project project) { IFile descriptorFile = NewModuleUtil.getModuleFile(namespace, rootPath, MPSExtentions.DOT_SOLUTION); assert !(descriptorFile.exists()); SolutionDescriptor descriptor = createNewSolutionDescriptor(namespace, descriptorFile); SolutionDescriptorPersistence.saveSolutionDescriptor(descriptorFile, descriptor, MacrosFactory.forModuleFile(descriptorFile)); Solution module = (Solution) new ModuleRepositoryFacade(project).instantiateModule(new ModulesMiner().loadModuleHandle(descriptorFile), project); project.addModule(module); module.save(); return module; } /** * create new language module and register it with the project */ public static Language createLanguage(String namespace, String rootPath, Project project) { IFile descriptorFile = NewModuleUtil.getModuleFile(namespace, rootPath, MPSExtentions.DOT_LANGUAGE); Language module = createNewLanguage(namespace, descriptorFile, true, project); project.addModule(module); module.save(); return module; } /** * create new devkit module and register it with the project */ public static DevKit createDevKit(String namespace, String rootPath, Project project) { IFile descriptorFile = NewModuleUtil.getModuleFile(namespace, rootPath, MPSExtentions.DOT_DEVKIT); assert !(descriptorFile.exists()); DevkitDescriptor descriptor = createNewDevkitDescriptor(namespace); DevkitDescriptorPersistence.saveDevKitDescriptor(descriptorFile, descriptor); DevKit module = (DevKit) new ModuleRepositoryFacade(project).instantiateModule(new ModulesMiner().loadModuleHandle(descriptorFile), project); project.addModule(module); module.save(); return module; } public static void runModuleCreation(Project p, final _FunctionTypes._void_P0_E0 r) { p.getRepository().getModelAccess().executeCommand(new Runnable() { public void run() { ApplicationManager.getApplication().assertWriteAccessAllowed(); r.invoke(); } }); } public static String check(final SRepository repo, String extension, final String namespace, String rootPath) { if (MPSExtentions.DOT_LANGUAGE.equals(extension) && !(SourceVersion.isName(namespace))) { return "Language namespace should be valid Java package"; } if (rootPath.length() == 0) { return "Path should be specified"; } String message = NewModuleCheckUtil.checkModuleDirectory(new File(rootPath), extension, "Module"); if (message != null) { return message; } if (namespace.length() == 0) { return "Namespace should be specified"; } boolean duplicateName = new ModelAccessHelper(repo).runReadAction(new Computable<Boolean>() { public Boolean compute() { return new ModuleRepositoryFacade(repo).getModelByName(namespace) != null; } }); if (duplicateName) { return "Module namespace already exists"; } if (NameUtil.shortNameFromLongName(namespace).length() == 0) { return "Enter valid namespace"; } IFile moduleDir = getModuleFile(namespace, rootPath, extension).getParent(); // FIXME it's suspicious to check existence of a model directory to tell existence of a module // E.g. it might be empty, or named differently. Left intact for now, although deserves a refactoring if (moduleDir.getDescendant(Language.LANGUAGE_MODELS).exists() || moduleDir.getDescendant(Language.LEGACY_LANGUAGE_MODELS).exists() || moduleDir.getDescendant(Solution.SOLUTION_MODELS).exists()) { return "Module already exists in this folder"; } return null; } @Deprecated private static Language createNewLanguage(String namespace, IFile descriptorFile, boolean createMainAspectModels, Project project) { if (descriptorFile.exists()) { throw new IllegalArgumentException("Descriptor file " + descriptorFile + " already exists"); } LanguageDescriptor descriptor = createNewLanguageDescriptor(namespace, descriptorFile); LanguageDescriptorPersistence.saveLanguageDescriptor(descriptorFile, descriptor, MacrosFactory.forModuleFile(descriptorFile)); ModuleRepositoryFacade projectRepoFacade = new ModuleRepositoryFacade(project); Language language = (Language) projectRepoFacade.instantiateModule(new ModulesMiner().loadModuleHandle(descriptorFile), project); descriptor = language.getModuleDescriptor(); if (createMainAspectModels) { try { createMainLanguageAspects(language); } catch (IOException e) { // todo: ??? throw new RuntimeException(e); } } IFile generatorLocation = descriptorFile.getParent().getDescendant("generator"); IFile templateModelsLocation = generatorLocation.getDescendant("template"); templateModelsLocation.mkdirs(); final GeneratorDescriptor generatorDescriptor = createGeneratorDescriptor(Generator.generateGeneratorUID(language), generatorLocation, templateModelsLocation); generatorDescriptor.setSourceLanguage(language.getModuleReference()); descriptor.getGenerators().add(generatorDescriptor); language.setModuleDescriptor(descriptor); language.save(); final Generator newGenerator = projectRepoFacade.getModule(generatorDescriptor.getModuleReference(), Generator.class); createTemplateModelIfNoneYet(newGenerator); return language; } public static void createTemplateModelIfNoneYet(Generator newGenerator) { boolean alreadyOwnsTemplateModel = false; for (SModel modelDescriptor : newGenerator.getModels()) { if (SModelStereotype.isGeneratorModel(modelDescriptor)) { alreadyOwnsTemplateModel = true; break; } } if (!(alreadyOwnsTemplateModel)) { SModel templateModel = SModuleOperations.createModelWithAdjustments(new SModelName(null, "main", SModelStereotype.GENERATOR).getValue(), newGenerator.getModelRoots().iterator().next()); SNode mappingConfiguration = SModelOperations.createNewNode(templateModel, null, MetaAdapterFactory.getConcept(0xb401a68083254110L, 0x8fd384331ff25befL, 0xff0bea0475L, "jetbrains.mps.lang.generator.structure.MappingConfiguration")); // both model and MC named 'main' is a bit confusing SPropertyOperations.set(mappingConfiguration, MetaAdapterFactory.getProperty(0xceab519525ea4f22L, 0x9b92103b95ca8c0cL, 0x110396eaaa4L, 0x110396ec041L, "name"), "main"); SModelOperations.addRootNode(templateModel, mappingConfiguration); ((EditableSModel) templateModel).save(); } } public static void createMainLanguageAspects(Language language) throws IOException { assert language.getModelRoots().iterator().hasNext(); ((EditableSModel) LanguageAspect.STRUCTURE.createNew(language)).save(); ((EditableSModel) LanguageAspect.EDITOR.createNew(language)).save(); ((EditableSModel) LanguageAspect.CONSTRAINTS.createNew(language)).save(); ((EditableSModel) LanguageAspect.BEHAVIOR.createNew(language)).save(); ((EditableSModel) LanguageAspect.TYPESYSTEM.createNew(language)).save(); } /** * Fill in new descriptor of Generator module with defaults. * This code is shared with NewGeneratorDialog. Please refactor this class, full of static, to something that * an ocassional OOP stroller would admire. * * * @param generatorModuleLocation base root for generator module. This method doesn't care if location exist, nor ensures its existence. * @param templateModelsLocation generally a location under generator module root to keem template models. May be the same as {@code generatorModuleLocation}. Use {@code null} to use default ('templates'). */ @NotNull public static GeneratorDescriptor createGeneratorDescriptor(String namespace, @NotNull IFile generatorModuleLocation, @Nullable IFile templateModelsLocation) { final GeneratorDescriptor generatorDescriptor = new GeneratorDescriptor(); generatorDescriptor.setNamespace(namespace); // unlike other modules, in outburst of pure antagonism, namespace in generator used to mean alias. Now, it's the way it has to be. generatorDescriptor.setAlias("main"); DefaultModelRoot templateModelsRoot = new DefaultModelRoot(); // XXX instead of this odd logic and conventions, need a factory object with reasobable defaults, so that external code that cares about // IFile.mkdirs doesn't need to pass location here, and instead can rely on factory to obtain actual value. IFile modelsDir = (templateModelsLocation == null ? generatorModuleLocation.getDescendant("template") : templateModelsLocation); // there used to be 2 approaches, contentRoot = moduleRoot + sourceRoot descendant, and the one with both pointing to the same location // no idea how to reason to pick one, go ahead and change if you're brave to prove. templateModelsRoot.setContentRoot(modelsDir.getPath()); templateModelsRoot.addFile(DefaultModelRoot.SOURCE_ROOTS, modelsDir.getPath()); ModelRootDescriptor mrd = new ModelRootDescriptor(templateModelsRoot.getType(), new MementoImpl()); templateModelsRoot.save(mrd.getMemento()); generatorDescriptor.getModelRootDescriptors().add(mrd); ProjectPathUtil.setGeneratorOutputPath(generatorDescriptor, generatorModuleLocation.getDescendant("source_gen").getPath()); return generatorDescriptor; } private static IFile getModuleFile(String namespace, String rootPath, String extension) { String path = rootPath + File.separator + namespace + extension; return FileSystem.getInstance().getFileByPath(path); } private static SolutionDescriptor createNewSolutionDescriptor(String namespace, IFile descriptorFile) { SolutionDescriptor descriptor = new SolutionDescriptor(); descriptor.setNamespace(namespace); descriptor.setId(ModuleId.regular()); IFile moduleLocation = descriptorFile.getParent(); final IFile modelsDir = moduleLocation.getDescendant(Solution.SOLUTION_MODELS); if (modelsDir.exists() && modelsDir.getChildren().size() != 0) { throw new IllegalStateException("Trying to create a solution in an existing solution's directory: " + moduleLocation); } else { // we assume create happens under proper application write lock, would be odd to manage locks here modelsDir.mkdirs(); } // default descriptorModel roots DefaultModelRoot modelRoot = new DefaultModelRoot(); modelRoot.setContentRoot(modelsDir.getParent().getPath()); modelRoot.addFile(DefaultModelRoot.SOURCE_ROOTS, modelsDir.getPath()); descriptor.getModelRootDescriptors().add(modelRoot.toDescriptor()); ProjectPathUtil.setGeneratorOutputPath(descriptor, moduleLocation.getDescendant("source_gen").getPath()); return descriptor; } private static LanguageDescriptor createNewLanguageDescriptor(String languageNamespace, IFile descriptorFile) { LanguageDescriptor languageDescriptor = new LanguageDescriptor(); languageDescriptor.setNamespace(languageNamespace); languageDescriptor.setId(ModuleId.regular()); IFile moduleLocation = descriptorFile.getParent(); IFile languageModels = moduleLocation.getDescendant(Language.LANGUAGE_MODELS); if (languageModels.exists()) { throw new IllegalStateException("Trying to create a language in an existing language's directory " + languageModels); } // default descriptorModel roots DefaultModelRoot modelRoot = new DefaultModelRoot(); modelRoot.setContentRoot(languageModels.getParent().getPath()); modelRoot.addFile(DefaultModelRoot.SOURCE_ROOTS, languageModels.getPath()); languageDescriptor.getModelRootDescriptors().add(modelRoot.toDescriptor()); ProjectPathUtil.setGeneratorOutputPath(languageDescriptor, moduleLocation.getDescendant("source_gen").getPath()); return languageDescriptor; } private static DevkitDescriptor createNewDevkitDescriptor(String namespace) { DevkitDescriptor d = new DevkitDescriptor(); d.setNamespace(namespace); d.setId(ModuleId.regular()); return d; } private static EditableSModel createModel(SModule module, String modelName) { for (ModelRoot root : module.getModelRoots()) { if (root.canCreateModels() && root.canCreateModel(modelName)) { EditableSModel model = (EditableSModel) root.createModel(modelName); // todo: ??? // this is strict model loading. without it save() not working - isLoaded() returns false in save method // model.getSModel() model.save(); return model; } } throw new IllegalStateException("can't create model with " + modelName + " in module " + module.getModuleName()); } }