blob: 8cacef7908a165d70d4fb77f4a536101b4529c1e [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.builders.impl;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.io.FileUtil;
import gnu.trove.THashSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jps.builders.BuildOutputConsumer;
import org.jetbrains.jps.builders.BuildTarget;
import org.jetbrains.jps.builders.storage.SourceToOutputMapping;
import org.jetbrains.jps.incremental.CompileContext;
import org.jetbrains.jps.incremental.ModuleBuildTarget;
import org.jetbrains.jps.incremental.artifacts.ArtifactBuildTarget;
import org.jetbrains.jps.incremental.messages.FileGeneratedEvent;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
/**
* @author Eugene Zhuravlev
* Date: 11/16/12
*/
public class BuildOutputConsumerImpl implements BuildOutputConsumer {
private static final Logger LOG = Logger.getInstance(BuildOutputConsumerImpl.class);
private final BuildTarget<?> myTarget;
private final CompileContext myContext;
private FileGeneratedEvent myFileGeneratedEvent;
private Collection<File> myOutputs;
private THashSet<String> myRegisteredSources = new THashSet<String>(FileUtil.PATH_HASHING_STRATEGY);
public BuildOutputConsumerImpl(BuildTarget<?> target, CompileContext context) {
myTarget = target;
myContext = context;
myFileGeneratedEvent = new FileGeneratedEvent();
myOutputs = myTarget.getOutputRoots(context);
}
private void registerOutput(final File output, boolean isDirectory, Collection<String> sourcePaths) throws IOException {
final String outputPath = FileUtil.toSystemIndependentName(output.getPath());
for (File outputRoot : myOutputs) {
final String outputRootPath = FileUtil.toSystemIndependentName(outputRoot.getPath());
final String relativePath = FileUtil.getRelativePath(outputRootPath, outputPath, '/');
if (relativePath != null && !relativePath.startsWith("../")) {
// the relative path must be under the root or equal to it
if (isDirectory) {
addEventsRecursively(output, outputRootPath, relativePath);
}
else {
myFileGeneratedEvent.add(outputRootPath, relativePath);
}
}
}
final SourceToOutputMapping mapping = myContext.getProjectDescriptor().dataManager.getSourceToOutputMap(myTarget);
for (String sourcePath : sourcePaths) {
if (myRegisteredSources.add(FileUtil.toSystemIndependentName(sourcePath))) {
mapping.setOutput(sourcePath, outputPath);
}
else {
mapping.appendOutput(sourcePath, outputPath);
}
}
}
private void addEventsRecursively(File output, String outputRootPath, String relativePath) {
File[] children = output.listFiles();
if (children == null) {
myFileGeneratedEvent.add(outputRootPath, relativePath);
}
else {
String prefix = relativePath.isEmpty() || relativePath.equals(".") ? "" : relativePath + "/";
for (File child : children) {
addEventsRecursively(child, outputRootPath, prefix + child.getName());
}
}
}
@Override
public void registerOutputFile(@NotNull final File outputFile, @NotNull Collection<String> sourcePaths) throws IOException {
registerOutput(outputFile, false, sourcePaths);
}
@Override
public void registerOutputDirectory(@NotNull File outputDir, @NotNull Collection<String> sourcePaths) throws IOException {
LOG.assertTrue(!(myTarget instanceof ModuleBuildTarget) && !(myTarget instanceof ArtifactBuildTarget),
"'registerOutputDirectory' method cannot be used for target " + myTarget + ", it will break incremental compilation");
registerOutput(outputDir, true, sourcePaths);
}
public void fireFileGeneratedEvent() {
if (!myFileGeneratedEvent.getPaths().isEmpty()) {
myContext.processMessage(myFileGeneratedEvent);
}
}
}