blob: 5cef20f4dfb400d9d513953fbd6dbc8440b553a8 [file] [log] [blame]
/*
* Copyright 2000-2012 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 org.jetbrains.jps.incremental.artifacts.builders;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.containers.ClassMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.builders.BuildTarget;
import org.jetbrains.jps.builders.TargetOutputIndex;
import org.jetbrains.jps.builders.java.JavaModuleBuildTargetType;
import org.jetbrains.jps.incremental.ModuleBuildTarget;
import org.jetbrains.jps.incremental.artifacts.instructions.ArtifactCompilerInstructionCreator;
import org.jetbrains.jps.incremental.artifacts.instructions.ArtifactInstructionsBuilderContext;
import org.jetbrains.jps.incremental.artifacts.instructions.CopyToDirectoryInstructionCreator;
import org.jetbrains.jps.model.artifact.JpsArtifact;
import org.jetbrains.jps.model.artifact.elements.*;
import org.jetbrains.jps.model.java.JpsProductionModuleOutputPackagingElement;
import org.jetbrains.jps.model.java.JpsTestModuleOutputPackagingElement;
import org.jetbrains.jps.model.module.JpsModule;
import org.jetbrains.jps.service.JpsServiceManager;
import org.jetbrains.jps.util.JpsPathUtil;
import java.io.File;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
/**
* @author nik
*/
public class LayoutElementBuildersRegistry {
private static final Logger LOG = Logger.getInstance("#org.jetbrains.jps.incremental.artifacts.builders.LayoutElementBuildersRegistry");
private static class InstanceHolder {
static final LayoutElementBuildersRegistry ourInstance = new LayoutElementBuildersRegistry();
}
public static LayoutElementBuildersRegistry getInstance() {
return InstanceHolder.ourInstance;
}
private ClassMap<LayoutElementBuilderService> myBuilders;
private LayoutElementBuildersRegistry() {
myBuilders = new ClassMap<LayoutElementBuilderService>();
LayoutElementBuilderService<?>[] standardBuilders = {
new RootElementBuilder(), new DirectoryElementBuilder(), new ArchiveElementBuilder(), new DirectoryCopyElementBuilder(),
new FileCopyElementBuilder(), new ExtractedDirectoryElementBuilder(), new ModuleOutputElementBuilder(),
new ModuleTestOutputElementBuilder(), new ComplexElementBuilder(), new ArtifactOutputElementBuilder()
};
for (LayoutElementBuilderService<?> builder : standardBuilders) {
myBuilders.put(builder.getElementClass(), builder);
}
for (LayoutElementBuilderService builder : JpsServiceManager.getInstance().getExtensions(LayoutElementBuilderService.class)) {
myBuilders.put(builder.getElementClass(), builder);
}
}
public void generateInstructions(JpsArtifact artifact, CopyToDirectoryInstructionCreator creator, ArtifactInstructionsBuilderContext context) {
context.enterArtifact(artifact);
generateInstructions(artifact.getRootElement(), creator, context);
}
public Collection<BuildTarget<?>> getDependencies(JpsPackagingElement element, TargetOutputIndex outputIndex) {
LayoutElementBuilderService builder = getElementBuilder(element);
if (builder != null) {
//noinspection unchecked
return builder.getDependencies(element, outputIndex);
}
return Collections.emptyList();
}
private void generateInstructions(JpsPackagingElement layoutElement, ArtifactCompilerInstructionCreator instructionCreator,
ArtifactInstructionsBuilderContext builderContext) {
final LayoutElementBuilderService builder = getElementBuilder(layoutElement);
if (builder != null) {
//noinspection unchecked
builder.generateInstructions(layoutElement, instructionCreator, builderContext);
}
}
private LayoutElementBuilderService<?> getElementBuilder(JpsPackagingElement layoutElement) {
final LayoutElementBuilderService<?> builder = myBuilders.get(layoutElement.getClass());
if (builder == null) {
LOG.error("Builder not found for artifact output layout element of class " + layoutElement.getClass());
}
return builder;
}
private void generateChildrenInstructions(JpsCompositePackagingElement element, ArtifactCompilerInstructionCreator instructionCreator,
ArtifactInstructionsBuilderContext builderContext) {
generateInstructions(element.getChildren(), instructionCreator, builderContext);
}
private void generateSubstitutionInstructions(JpsComplexPackagingElement element,
ArtifactCompilerInstructionCreator instructionCreator,
ArtifactInstructionsBuilderContext builderContext) {
final List<JpsPackagingElement> substitution = element.getSubstitution();
if (substitution != null) {
generateInstructions(substitution, instructionCreator, builderContext);
}
}
private void generateInstructions(final List<JpsPackagingElement> elements, ArtifactCompilerInstructionCreator instructionCreator,
ArtifactInstructionsBuilderContext builderContext) {
for (JpsPackagingElement child : elements) {
generateInstructions(child, instructionCreator, builderContext);
}
}
private static void generateModuleOutputInstructions(@Nullable String outputUrl, ArtifactCompilerInstructionCreator creator) {
if (outputUrl != null) {
creator.addDirectoryCopyInstructions(JpsPathUtil.urlToFile(outputUrl));
}
}
private class RootElementBuilder extends LayoutElementBuilderService<JpsArtifactRootElement> {
public RootElementBuilder() {
super(JpsArtifactRootElement.class);
}
@Override
public void generateInstructions(JpsArtifactRootElement element, ArtifactCompilerInstructionCreator instructionCreator, ArtifactInstructionsBuilderContext builderContext) {
generateChildrenInstructions(element, instructionCreator, builderContext);
}
}
private class DirectoryElementBuilder extends LayoutElementBuilderService<JpsDirectoryPackagingElement> {
public DirectoryElementBuilder() {
super(JpsDirectoryPackagingElement.class);
}
@Override
public void generateInstructions(JpsDirectoryPackagingElement element,
ArtifactCompilerInstructionCreator instructionCreator,
ArtifactInstructionsBuilderContext builderContext) {
generateChildrenInstructions(element, instructionCreator.subFolder(element.getDirectoryName()), builderContext);
}
}
private class ArchiveElementBuilder extends LayoutElementBuilderService<JpsArchivePackagingElement> {
public ArchiveElementBuilder() {
super(JpsArchivePackagingElement.class);
}
@Override
public void generateInstructions(JpsArchivePackagingElement element, ArtifactCompilerInstructionCreator instructionCreator,
ArtifactInstructionsBuilderContext builderContext) {
generateChildrenInstructions(element, instructionCreator.archive(element.getArchiveName()), builderContext);
}
}
private static class DirectoryCopyElementBuilder extends LayoutElementBuilderService<JpsDirectoryCopyPackagingElement> {
public DirectoryCopyElementBuilder() {
super(JpsDirectoryCopyPackagingElement.class);
}
@Override
public void generateInstructions(JpsDirectoryCopyPackagingElement element, ArtifactCompilerInstructionCreator instructionCreator,
ArtifactInstructionsBuilderContext builderContext) {
final String dirPath = element.getDirectoryPath();
if (dirPath != null) {
final File directory = new File(dirPath);
instructionCreator.addDirectoryCopyInstructions(directory);
}
}
@Override
public Collection<? extends BuildTarget<?>> getDependencies(@NotNull JpsDirectoryCopyPackagingElement element,
TargetOutputIndex outputIndex) {
String dirPath = element.getDirectoryPath();
if (dirPath != null) {
return outputIndex.getTargetsByOutputFile(new File(dirPath));
}
return Collections.emptyList();
}
}
private static class FileCopyElementBuilder extends LayoutElementBuilderService<JpsFileCopyPackagingElement> {
public FileCopyElementBuilder() {
super(JpsFileCopyPackagingElement.class);
}
@Override
public void generateInstructions(JpsFileCopyPackagingElement element, ArtifactCompilerInstructionCreator instructionCreator,
ArtifactInstructionsBuilderContext builderContext) {
final String filePath = element.getFilePath();
if (filePath != null) {
final File file = new File(filePath);
final String fileName = element.getRenamedOutputFileName();
instructionCreator.addFileCopyInstruction(file, fileName != null ? fileName : file.getName());
}
}
@Override
public Collection<? extends BuildTarget<?>> getDependencies(@NotNull JpsFileCopyPackagingElement element,
TargetOutputIndex outputIndex) {
String filePath = element.getFilePath();
if (filePath != null) {
return outputIndex.getTargetsByOutputFile(new File(filePath));
}
return Collections.emptyList();
}
}
private static class ExtractedDirectoryElementBuilder extends LayoutElementBuilderService<JpsExtractedDirectoryPackagingElement> {
public ExtractedDirectoryElementBuilder() {
super(JpsExtractedDirectoryPackagingElement.class);
}
@Override
public void generateInstructions(JpsExtractedDirectoryPackagingElement element,
ArtifactCompilerInstructionCreator instructionCreator,
ArtifactInstructionsBuilderContext builderContext) {
final String jarPath = element.getFilePath();
final String pathInJar = element.getPathInJar();
instructionCreator.addExtractDirectoryInstruction(new File(jarPath), pathInJar);
}
}
private static class ModuleOutputElementBuilder extends LayoutElementBuilderService<JpsProductionModuleOutputPackagingElement> {
public ModuleOutputElementBuilder() {
super(JpsProductionModuleOutputPackagingElement.class);
}
@Override
public void generateInstructions(JpsProductionModuleOutputPackagingElement element,
ArtifactCompilerInstructionCreator instructionCreator,
ArtifactInstructionsBuilderContext builderContext) {
generateModuleOutputInstructions(element.getOutputUrl(), instructionCreator);
}
@Override
public Collection<? extends BuildTarget<?>> getDependencies(@NotNull JpsProductionModuleOutputPackagingElement element,
TargetOutputIndex outputIndex) {
JpsModule module = element.getModuleReference().resolve();
if (module != null) {
return Collections.singletonList(new ModuleBuildTarget(module, JavaModuleBuildTargetType.PRODUCTION));
}
return Collections.emptyList();
}
}
private static class ModuleTestOutputElementBuilder extends LayoutElementBuilderService<JpsTestModuleOutputPackagingElement> {
public ModuleTestOutputElementBuilder() {
super(JpsTestModuleOutputPackagingElement.class);
}
@Override
public void generateInstructions(JpsTestModuleOutputPackagingElement element,
ArtifactCompilerInstructionCreator instructionCreator,
ArtifactInstructionsBuilderContext builderContext) {
generateModuleOutputInstructions(element.getOutputUrl(), instructionCreator);
}
@Override
public Collection<? extends BuildTarget<?>> getDependencies(@NotNull JpsTestModuleOutputPackagingElement element,
TargetOutputIndex outputIndex) {
JpsModule module = element.getModuleReference().resolve();
if (module != null) {
return Collections.singletonList(new ModuleBuildTarget(module, JavaModuleBuildTargetType.TEST));
}
return Collections.emptyList();
}
}
private class ComplexElementBuilder extends LayoutElementBuilderService<JpsComplexPackagingElement> {
public ComplexElementBuilder() {
super(JpsComplexPackagingElement.class);
}
@Override
public void generateInstructions(JpsComplexPackagingElement element,
ArtifactCompilerInstructionCreator instructionCreator,
ArtifactInstructionsBuilderContext builderContext) {
generateSubstitutionInstructions(element, instructionCreator, builderContext);
}
}
private class ArtifactOutputElementBuilder extends LayoutElementBuilderService<JpsArtifactOutputPackagingElement> {
public ArtifactOutputElementBuilder() {
super(JpsArtifactOutputPackagingElement.class);
}
@Override
public void generateInstructions(JpsArtifactOutputPackagingElement element,
ArtifactCompilerInstructionCreator instructionCreator,
ArtifactInstructionsBuilderContext builderContext) {
final JpsArtifact artifact = element.getArtifactReference().resolve();
if (artifact == null) return;
Set<JpsArtifact> parentArtifacts = builderContext.getParentArtifacts();
List<JpsPackagingElement> customLayout = getCustomArtifactLayout(artifact, parentArtifacts);
final String outputPath = artifact.getOutputPath();
if (StringUtil.isEmpty(outputPath) || customLayout != null) {
try {
if (builderContext.enterArtifact(artifact)) {
if (customLayout != null) {
LayoutElementBuildersRegistry.this.generateInstructions(customLayout, instructionCreator, builderContext);
}
else {
generateSubstitutionInstructions(element, instructionCreator, builderContext);
}
}
}
finally {
builderContext.leaveArtifact(artifact);
}
return;
}
final JpsPackagingElement rootElement = artifact.getRootElement();
final File outputDir = new File(outputPath);
if (rootElement instanceof JpsArchivePackagingElement) {
final String fileName = ((JpsArchivePackagingElement)rootElement).getArchiveName();
instructionCreator.addFileCopyInstruction(new File(outputDir, fileName), fileName);
}
else {
instructionCreator.addDirectoryCopyInstructions(outputDir);
}
}
@Nullable
private List<JpsPackagingElement> getCustomArtifactLayout(@NotNull JpsArtifact artifact, @NotNull Set<JpsArtifact> parentArtifacts) {
for (ArtifactLayoutCustomizationService service : JpsServiceManager.getInstance().getExtensions(ArtifactLayoutCustomizationService.class)) {
List<JpsPackagingElement> elements = service.getCustomizedLayout(artifact, parentArtifacts);
if (elements != null) {
return elements;
}
}
return null;
}
}
}