@NotNull public static Set<SModuleReference> getModules(SRepository repository, final Library library) { if (!ModuleLibraryType.isModuleLibrary(library)) { return Collections.emptySet(); } final Set<SModuleReference> modules = new HashSet<SModuleReference>(); final Set<IFile> moduleXmls = new HashSet<IFile>(); for (VirtualFile file : library.getFiles(ModuleXmlRootDetector.MPS_MODULE_XML)) { moduleXmls.add(VirtualFileUtils.toIFile(file)); } repository .getModelAccess() .runReadAction( new Runnable() { @Override public void run() { for (IFile moduleDescriptor : moduleXmls) { SModule moduleByFile = ModuleFileTracker.getInstance().getModuleByFile(moduleDescriptor); if (moduleByFile != null) { modules.add(moduleByFile.getModuleReference()); } } } }); return modules; }
@Override public SModel resolve(SRepository repo) { if (myModuleReference != null) { final SRepository repository; if (repo == null) { // see StaticReference, which seems to be the only place we pass null as repository repository = MPSModuleRepository.getInstance(); } else { repository = repo; } Computable<SModel> c = new Computable<SModel>() { @Override public SModel compute() { SModule module = repository.getModule(myModuleReference.getModuleId()); if (module == null) { return null; } return module.getModel(myModelId); } }; if (!repository.getModelAccess().canRead()) { LOG.warn( "Attempt to resolve a model not from read action. What are you going to do with return value? Hint: at least, read. Please ensure proper model access then.", new Throwable()); return new ModelAccessHelper(repository).runReadAction(c); } else { return c.compute(); } } // FIXME !!! use supplied SRepository, not global model repo !!! // If there's no module reference, and model id is global, it's supposed we shall get the model // from a global repository. // However, at the moment, there's no easy way to get model from SRepository (other than to // iterate over all modules and models, // which doesn't sound like a good approach). Either shall provide method to find model from // SRepository, or drop // 'globally unique' model id altogether. What's the benefit of them? // NOTE, shall tolerate null repo unless every single piece of code that expects StaticReference // of a newly created node // hanging in the air to resolve. @see StaticReference#getTargetSModel return SModelRepository.getInstance().getModelDescriptor(this); }
private SNode getNode(AbstractTreeNode treeNode) { if (!(treeNode instanceof MPSPsiElementTreeNode)) { return null; } MPSPsiNodeBase psiNode = ((MPSPsiElementTreeNode) treeNode).getValue(); if (!(psiNode instanceof MPSPsiRealNode)) { return null; } final SNodeReference nodeRef = ((MPSPsiRealNode) psiNode).getSNodeReference(); final SRepository repository = ProjectHelper.getProjectRepository(treeNode.getProject()); // TODO remove read action from here once SModelFileTracker stops doing the same (creating read // action if not already in one) return new ModelComputeRunnable<SNode>( new Computable<SNode>() { @Override public SNode compute() { return nodeRef.resolve(repository); } }) .runRead(repository.getModelAccess()); }
/** * Returns whether the given node belongs to the repository (or to one of its parent * repositories). */ public static boolean isAccessible(@NotNull SNode node, @NotNull SRepository inRepository) { SModel model = node.getModel(); if (model == null) return false; SRepository mrep = model.getRepository(); if (mrep == null) return false; mrep.getModelAccess().checkReadAccess(); if (inRepository == mrep) { return true; } // FIXME this is a hack to deal with incomplete story of repository relationship. // We have at least two repositories, ProjectRepository and MPSModuleRepository, and with // repository.getParent() dropped, there are no chance // to figure out node coming from MPSModuleRepository is visible in ProjectRepository // (EditorComponent.editNode() passes here project's repository // but node might come from an MPSModuleRepository (e.g. temp node from console), and they don't // match. // Here, assume node is accessible even if repositories are different if its module is identical // in both. inRepository.getModelAccess().checkReadAccess(); return model.getModule() == inRepository.getModule(model.getModule().getModuleId()); }
/** * recounting the status map * * @see #isChanged() */ private void recountStatus() { if (!isChanged()) return; myRepository .getModelAccess() .runReadAction( new Runnable() { @Override public void run() { if (!isChanged()) return; LOG.debug("Recount status map for modules"); boolean updated = myModuleUpdater.refreshGraph(); Collection<SModuleReference> invalidModules = findInvalidModules(); updated |= (!invalidModules.equals(myCurrentInvalidModules)); if (updated) { myCurrentInvalidModules = invalidModules; refillStatusMap(invalidModules); } } }); }
@NotNull private Collection<SModuleReference> findInvalidModules0(boolean errorLevel) { myRepository.getModelAccess().checkReadAccess(); Map<ReloadableModule, AbsentDependencyException> modulesWithAbsentDeps = myModuleUpdater.getModulesWithAbsentDeps(); Collection<SModuleReference> result = new HashSet<SModuleReference>(); Collection<? extends SModuleReference> allModuleRefs = getAllModules(); for (SModuleReference mRef : allModuleRefs) { if (!result.contains(mRef)) { String msg = getModuleProblemMessage(mRef, modulesWithAbsentDeps); if (msg == null) { continue; } if (errorLevel) LOG.error(msg); else LOG.debug(msg); result.add(mRef); } } return result; }
@Override public void doExecute(@NotNull final AnActionEvent event, final Map<String, Object> _params) { List<SModel> m = ((List<SModel>) MapSequence.fromMap(_params).get("models")); final Iterable<SModel> seq = ListSequence.fromList(m) .where( new IWhereFilter<SModel>() { public boolean accept(SModel it) { return !(it.isReadOnly()) && it.getSource() instanceof FileDataSource; } }); final SRepository repo = ((MPSProject) MapSequence.fromMap(_params).get("project")).getRepository(); final FolderModelFactory filePerRootFactory = PersistenceRegistry.getInstance().getFolderModelFactory("file-per-root"); repo.getModelAccess() .runWriteAction( new Runnable() { public void run() { // see MPS-18743 repo.saveAll(); for (SModel smodel : Sequence.fromIterable(seq)) { IFile oldFile = ((FileDataSource) smodel.getSource()).getFile(); ModelRoot modelRoot = smodel.getModelRoot(); if (!(modelRoot instanceof FileBasedModelRoot)) { continue; } SModel newModel = PersistenceUtil.loadModel(oldFile); if (newModel == null) { if (LOG.isEnabledFor(Level.ERROR)) { LOG.error("cannot read " + smodel); } continue; } Iterable<SModel.Problem> problems = Sequence.fromIterable(((Iterable<SModel.Problem>) newModel.getProblems())) .where( new IWhereFilter<SModel.Problem>() { public boolean accept(SModel.Problem it) { return it.isError(); } }); if (Sequence.fromIterable(problems).isNotEmpty()) { if (LOG.isEnabledFor(Level.ERROR)) { LOG.error( "cannot read " + smodel + ": " + Sequence.fromIterable(problems).first().getText()); } continue; } try { DataSource newSource = filePerRootFactory.createNewSource( (FileBasedModelRoot) modelRoot, null, newModel.getModelName(), new HashMap<String, String>()); SModule module = smodel.getModule(); filePerRootFactory.save(newModel, newSource); if (module != null) { ((SModuleBase) module).unregisterModel((SModelBase) smodel); } oldFile.delete(); ((AbstractModule) module).updateModelsSet(); } catch (IOException ex) { if (LOG.isEnabledFor(Level.ERROR)) { LOG.error("cannot write " + smodel, ex); } } catch (ModelSaveException ex) { // shouldn't happen if (LOG.isEnabledFor(Level.ERROR)) { LOG.error("cannot write " + smodel, ex); } } } } }); }
/** * @return <code>true</code> to indicate generation success (what does constitute a success is, * alas, undefined) */ private boolean process0( @NotNull final ProgressMonitor monitor, @NotNull final List<? extends GeneratorTask> tasks) { final boolean[] result = new boolean[1]; myTransientModelsProvider.startGeneration(myGenerationOptions.getNumberOfModelsToKeep()); final GeneratorLoggerAdapter logger = new GeneratorLoggerAdapter( myMessageHandler, myGenerationOptions.isShowInfo(), myGenerationOptions.isShowWarnings()); myRepository .getModelAccess() .runWriteAction( new Runnable() { @Override public void run() { for (GeneratorTask t : tasks) { SModel d = t.getModel(); if (d instanceof EditableSModel && ((EditableSModel) d).needsReloading()) { ((EditableSModel) d).reloadFromSource(); logger.info("Model " + d + " reloaded from disk."); } myTransientModelsProvider.createModule(d.getModule()); } } }); myTransientModelsProvider .initCheckpointModule(); // at the moment, starts write action, thus shall start outside of // read GenControllerContext ctx = new GenControllerContext( myRepository, myGenerationOptions, myTransientModelsProvider, myStreamProvider); GeneratorTaskListener<GeneratorTask> taskListener; if (myTaskListener != null) { taskListener = myTaskListener; } else { taskListener = new EmptyTaskListener(); } final GenerationController gc = new GenerationController(tasks, ctx, taskListener, logger); myRepository .getModelAccess() .runReadAction( new Runnable() { @Override public void run() { result[0] = UndoHelper.getInstance() .runNonUndoableAction( new Computable<Boolean>() { @Override public Boolean compute() { return gc.generate(monitor); } }); } }); // XXX removeAllTransients done from make facet, perhaps publish shall be part of external code // as well? myTransientModelsProvider.publishAll(); CleanupManager.getInstance().cleanup(); return result[0]; }
@Override public void processQuery( @NotNull SearchParameters queryParameters, @NotNull final Processor<PsiReference> consumer) { if (!(queryParameters.getEffectiveSearchScope() instanceof GlobalSearchScope)) { return; } final GlobalSearchScope scope = (GlobalSearchScope) queryParameters.getEffectiveSearchScope(); final PsiElement target = queryParameters.getElementToSearch(); // Only class names can be prefixes in foreign ids of other nodes if (!(target instanceof PsiClass)) return; final SRepository repository = ProjectHelper.getProjectRepository(scope.getProject()); if (repository == null) { return; } repository .getModelAccess() .runReadAction( new Runnable() { @Override public void run() { final NodePtr nodePtr = JavaForeignIdBuilder.computeNodePtr(target); if (nodePtr == null) return; final SNodeReference mpsTarget = new SNodePointer(nodePtr.getSModelReference(), nodePtr.getNodeId()); // do we have this node? if (mpsTarget.resolve(MPSModuleRepository.getInstance()) == null) return; String prefix = nodePtr.getNodeId().toString(); final String prefixToSearch = (prefix.startsWith(Foreign.ID_PREFIX) ? prefix.substring(1) : prefix); final String prefixToSearchWithDot = prefixToSearch + "."; final Project project = target.getProject(); // first look into changed models SearchScope mpsSearchScope = new IdeaSearchScope(scope, true); CollectConsumer<VirtualFile> processedFilesConsumer = new CollectConsumer<VirtualFile>(); for (SModel model : mpsSearchScope.getModels()) { boolean changed = model instanceof EditableSModel && ((EditableSModel) model).isChanged(); if (!changed) continue; findInModel( model, prefixToSearch, processedFilesConsumer, new Consumer<SReference>() { @Override public void consume(SReference ref) { String role = ref.getRole(); SNode source = ref.getSourceNode(); PsiElement psiNode = MPSPsiProvider.getInstance(project).getPsi(source.getReference()); assert psiNode instanceof MPSPsiNode; consumer.process(new IdPrefixReference(mpsTarget, role, psiNode)); } }); } // now index final Collection<VirtualFile> filesOfChangedModels = processedFilesConsumer.getResult(); GlobalSearchScope truncatedScope = new DelegatingGlobalSearchScope(scope) { @Override public boolean contains(VirtualFile file) { if (filesOfChangedModels.contains(file)) return false; return super.contains(file); } }; ValueProcessor<Collection<Pair<SNodeDescriptor, String>>> sReferenceProcessor = new ValueProcessor<Collection<Pair<SNodeDescriptor, String>>>() { @Override public boolean process( VirtualFile file, Collection<Pair<SNodeDescriptor, String>> refs) { for (Pair<SNodeDescriptor, String> ref : refs) { SNodeReference nodeRef = ref.o1.getNodeReference(); String role = ref.o2; // index got out-of-date on this // unfortunately our indices are not always up-to-date, as we don't index // yet-unsaved changes if (nodeRef.resolve(repository) == null) continue; PsiElement psiNode = MPSPsiProvider.getInstance(project).getPsi(nodeRef); // original node came from MPS index, it must be converted to our PSI // element assert psiNode instanceof MPSPsiNode; consumer.process(new IdPrefixReference(mpsTarget, role, psiNode)); } return true; } }; FileBasedIndex.getInstance() .processValues( ForeignIdReferenceIndex.ID, prefixToSearchWithDot, null, sReferenceProcessor, truncatedScope); } }); }
@Override public void processQuery( @NotNull SearchParameters queryParameters, final @NotNull Processor<PsiReference> consumer) { if (!(queryParameters.getEffectiveSearchScope() instanceof GlobalSearchScope)) { return; } final GlobalSearchScope scope = (GlobalSearchScope) queryParameters.getEffectiveSearchScope(); final PsiElement psiTarget = queryParameters.getElementToSearch(); if (psiTarget instanceof MPSPsiNodeBase) return; final Project project = psiTarget.getProject(); final MPSPsiProvider psiProvider = MPSPsiProvider.getInstance(project); SRepository repository = ProjectHelper.getProjectRepository(project); repository .getModelAccess() .runReadAction( new Runnable() { @Override public void run() { if (DumbService.getInstance(project).isDumb()) { return; } if (psiTarget instanceof LightElement) { // we don't handle light psi elements we don't know about // we may not be able to compute their node id and their Java meaning can be // represented in baseLanguage // in a special way return; } // if MPSReferenceSearch is moved to mps-core, it will be // MPS2PsiMapperUtil.getNodeId final SNode targetNode = getNodeForElement(psiTarget); if (targetNode == null) { // it can't be referenced from MPS return; } Set<SNode> targetNodes = new HashSet<SNode>(1); targetNodes.add(targetNode); Set<SReference> references; try { references = FindUsagesFacade.getInstance() .findUsages(new IdeaSearchScope(scope), targetNodes, null); } catch (IndexNotReadyException e) { // DumbService doesn't seem to work return; } for (SReference sReference : references) { SNode source = sReference.getSourceNode(); MPSPsiNode psiNode = (MPSPsiNode) psiProvider.getPsi(source); // the source could have come from the psi stub itself if (psiNode == null) return; String refRole = sReference.getRole(); MPSPsiRef[] refs = psiNode.getReferences(refRole); if (refs.length == 0) continue; for (MPSPsiRef r : refs) { if (targetNode.getNodeId().equals(r.getNodeId())) { // it's our reference: giving it out to find usages consumer.process(r.getReference()); } } } } }); }