/*
* Copyright 2016-present Facebook, Inc.
*
* 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 com.facebook.buck.jvm.java;
import com.facebook.buck.io.ProjectFilesystem;
import com.facebook.buck.util.HumanReadableException;
import com.facebook.buck.util.ObjectMappers;
import com.google.common.collect.ImmutableSetMultimap;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Collection;
import java.util.Comparator;
import java.util.Map;
import java.util.Optional;
import javax.tools.StandardJavaFileManager;
public final class DefaultClassUsageFileWriter implements ClassUsageFileWriter {
private final Path relativePath;
private final ClassUsageTracker tracker = new ClassUsageTracker();
public DefaultClassUsageFileWriter(Path relativePath) {
this.relativePath = relativePath;
}
public Path getRelativePath() {
return relativePath;
}
@Override
public StandardJavaFileManager wrapFileManager(StandardJavaFileManager inner) {
return tracker.wrapFileManager(inner);
}
@Override
public void writeFile(ProjectFilesystem filesystem) {
ImmutableSetMultimap<Path, Path> classUsageMap = tracker.getClassUsageMap();
try {
ObjectMappers.WRITER.writeValue(
filesystem.resolve(relativePath).toFile(), relativizeMap(classUsageMap, filesystem));
} catch (IOException e) {
throw new HumanReadableException(e, "Unable to write used classes file.");
}
}
private static ImmutableSetMultimap<Path, Path> relativizeMap(
ImmutableSetMultimap<Path, Path> classUsageMap, ProjectFilesystem filesystem) {
final ImmutableSetMultimap.Builder<Path, Path> builder = ImmutableSetMultimap.builder();
// Ensure deterministic ordering.
builder.orderKeysBy(Comparator.naturalOrder());
builder.orderValuesBy(Comparator.naturalOrder());
for (Map.Entry<Path, Collection<Path>> jarClassesEntry : classUsageMap.asMap().entrySet()) {
Path jarAbsolutePath = jarClassesEntry.getKey();
Optional<Path> jarRelativePath = filesystem.getPathRelativeToProjectRoot(jarAbsolutePath);
// Don't include jars that are outside of the filesystem
if (!jarRelativePath.isPresent()) {
// Paths outside the project would make these class usage files problematic for caching.
// Fortunately, such paths are also not interesting for the main use cases that these files
// address, namely understanding the dependencies one java rule has on others. Jar files
// outside the project are coming from a build tool (e.g. JDK or Android SDK).
continue;
}
builder.putAll(jarRelativePath.get(), jarClassesEntry.getValue());
}
return builder.build();
}
}