/* * Copyright 2003-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jetbrains.mps.project.facets; import jetbrains.mps.generator.fileGenerator.FileGenerationUtil; import jetbrains.mps.project.AbstractModule; import jetbrains.mps.project.ProjectPathUtil; import jetbrains.mps.vfs.IFile; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.mps.openapi.model.SModel; import org.jetbrains.mps.openapi.module.SModule; import org.jetbrains.mps.openapi.module.SModuleFacet; import java.util.Set; // FIXME why some API is with String for files (like getLibraryClassPath, getClassPath, getAdditionalSourcePaths), not IFile? public interface JavaModuleFacet extends SModuleFacet, GenerationTargetFacet { String FACET_TYPE = "java"; // flag for internal use (we can compile either in MPS or in Idea) // for "generate" task boolean isCompileInMps(); /** * @return root folder where generated classes of any module's model reside, or {@code null} if associated module doesn't expect class files to be written. * Note, although generated classes are part of {@linkplain #getClassPath() classpath}, this method is to access design-time location of generated * classes, not that at deployment time. For deployed modules, this method may return {@code null}, while generated module classes would be available * for classloading through {@link #getClassPath()}. */ // for "generate" task if isCompileInMPS == true @Nullable IFile getClassesGen(); /** * * @param model model of a module this facet is associated with * @return FS location where model class files reside, {@code null} for deployed modules */ @Nullable default IFile getClassesLocation(@NotNull SModel model) { IFile classesGen = getClassesGen(); if (classesGen == null) { return null; } return FileGenerationUtil.getDefaultOutputDir(model.getReference(), classesGen); } /** * PROVISIONAL Perhaps, worth moving to {@link GenerationTargetFacet}. OTOH, don't see a reason to restrict output of the facet to single root * Need one here for transition period to have default implementations for {@link #getOutputLocation(SModel)} and {@link #getOutputCacheLocation(SModel)} * Perhaps, shall be private to JavaModuleFacetImpl (need to get rid of default implementations of the dependant methods first). * * Top location where all 'primary' output goes, generally bound to module location, although no assumption shall be made about that. * Known as {@code source_gen} * * @return {@code null} if associated module doesn't allow generation. */ @Nullable default IFile getOutputRoot() { if (getModule() instanceof AbstractModule ) { // there's no output location for packaged/deployed modules String outputPath = ProjectPathUtil.getGeneratorOutputPath(((AbstractModule) getModule()).getModuleDescriptor()); return outputPath == null ? null : ((AbstractModule) getModule()).getFileSystem().getFile(outputPath); } return null; } /** * PROVISIONAL, see {@link #getOutputRoot()} for details. * * Top location where auxiliary (dependencies, hashes) output goes, generally bound to {@linkplain #getOutputRoot() module's output location}. * Known as {@code source_gen.caches} * * @return {@code null} if associated module doesn't have sources/doesn't allow generation */ @Nullable default IFile getOutputCacheRoot() { IFile outputRoot = getOutputRoot(); return outputRoot == null ? null : FileGenerationUtil.getCachesDir(outputRoot); } /** * E.g. source_gen/qualified/model/name/ * FIXME decide whether shall look into model output overrides (see DefaultStreamManager.Provider.getOverriddenOutputDir()). Didn't check for * override right away as I don't like use of distinct boolean option isGenerateIntoModelFolder() to describe an output alternative, and * would like to come up with a better alternative * @return {@code null} if this module doesn't allow generation (e.g. packaged) */ @Nullable @Override default IFile getOutputLocation(@NotNull SModel model) { final SModule associatedModule = getModule(); assert model.getModule() == associatedModule; IFile outputRoot = getOutputRoot(); return outputRoot == null ? null : FileGenerationUtil.getDefaultOutputDir(model.getReference(), outputRoot); } /** * E.g. source_gen.caches/qualified/model/name/ * @return {@code null} if this module doesn't allow generation (e.g. packaged) */ @Nullable @Override default IFile getOutputCacheLocation(@NotNull SModel model) { final SModule associatedModule = getModule(); assert model.getModule() == associatedModule; IFile outputRoot = getOutputRoot(); return outputRoot == null ? null : FileGenerationUtil.getDefaultOutputDir(model.getReference(), FileGenerationUtil.getCachesDir(outputRoot)); } // for "compilation" task // contains classes folder if isCompileInMPS == false && folder exists Set<String> getLibraryClassPath(); // for "run" task, classpath == classes folder + library class path Set<String> getClassPath(); /** * @return extra locations with source files to compile along with module's own generated artifacts from {@link #getOutputRoot()}, or empty collection. */ Set<String> getAdditionalSourcePaths(); }