blob: 52fced059e654e77b5671a8c45853bb6857d85a8 [file] [log] [blame]
/*
* Copyright 2016 The Bazel Authors. All rights reserved.
*
* 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.google.idea.blaze.java.sync.source;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.idea.blaze.base.async.FutureUtil;
import com.google.idea.blaze.base.filecache.FileDiffer;
import com.google.idea.blaze.base.ideinfo.ArtifactLocation;
import com.google.idea.blaze.base.ideinfo.TargetKey;
import com.google.idea.blaze.base.io.InputStreamProvider;
import com.google.idea.blaze.base.prefetch.PrefetchService;
import com.google.idea.blaze.base.scope.BlazeContext;
import com.google.idea.blaze.base.sync.workspace.ArtifactLocationDecoder;
import com.google.repackaged.devtools.build.lib.ideinfo.androidstudio.PackageManifestOuterClass.JavaSourcePackage;
import com.google.repackaged.devtools.build.lib.ideinfo.androidstudio.PackageManifestOuterClass.PackageManifest;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
/** Reads package manifests. */
public class PackageManifestReader {
private static final Logger logger = Logger.getInstance(SourceDirectoryCalculator.class);
public static PackageManifestReader getInstance() {
return ServiceManager.getService(PackageManifestReader.class);
}
private ImmutableMap<File, Long> fileDiffState;
private Map<File, TargetKey> fileToLabelMap = Maps.newHashMap();
private final Map<TargetKey, Map<ArtifactLocation, String>> manifestMap = Maps.newConcurrentMap();
/** @return A map from java source absolute file path to declared package string. */
public Map<TargetKey, Map<ArtifactLocation, String>> readPackageManifestFiles(
Project project,
BlazeContext context,
ArtifactLocationDecoder decoder,
Map<TargetKey, ArtifactLocation> javaPackageManifests,
ListeningExecutorService executorService) {
Map<File, TargetKey> fileToLabelMap = Maps.newHashMap();
for (Map.Entry<TargetKey, ArtifactLocation> entry : javaPackageManifests.entrySet()) {
TargetKey key = entry.getKey();
File file = decoder.decode(entry.getValue());
fileToLabelMap.put(file, key);
}
List<File> updatedFiles = Lists.newArrayList();
List<File> removedFiles = Lists.newArrayList();
fileDiffState =
FileDiffer.updateFiles(fileDiffState, fileToLabelMap.keySet(), updatedFiles, removedFiles);
ListenableFuture<?> fetchFuture =
PrefetchService.getInstance().prefetchFiles(project, updatedFiles);
if (!FutureUtil.waitForFuture(context, fetchFuture)
.timed("FetchPackageManifests")
.withProgressMessage("Reading package manifests...")
.run()
.success()) {
return null;
}
List<ListenableFuture<Void>> futures = Lists.newArrayList();
for (File file : updatedFiles) {
futures.add(
executorService.submit(
() -> {
Map<ArtifactLocation, String> manifest = parseManifestFile(file);
manifestMap.put(fileToLabelMap.get(file), manifest);
return null;
}));
}
for (File file : removedFiles) {
TargetKey key = this.fileToLabelMap.get(file);
if (key != null) {
manifestMap.remove(key);
}
}
this.fileToLabelMap = fileToLabelMap;
try {
Futures.allAsList(futures).get();
} catch (ExecutionException | InterruptedException e) {
logger.error(e);
throw new IllegalStateException("Could not read sources");
}
return manifestMap;
}
protected Map<ArtifactLocation, String> parseManifestFile(File packageManifest) {
Map<ArtifactLocation, String> outputMap = Maps.newHashMap();
InputStreamProvider inputStreamProvider = InputStreamProvider.getInstance();
try (InputStream input = inputStreamProvider.getFile(packageManifest)) {
try (BufferedInputStream bufferedInputStream = new BufferedInputStream(input)) {
PackageManifest proto = PackageManifest.parseFrom(bufferedInputStream);
for (JavaSourcePackage source : proto.getSourcesList()) {
ArtifactLocation artifactLocation =
ArtifactLocation.builder()
.setRootExecutionPathFragment(
source.getArtifactLocation().getRootExecutionPathFragment())
.setRelativePath(source.getArtifactLocation().getRelativePath())
.setIsSource(source.getArtifactLocation().getIsSource())
.build();
outputMap.put(artifactLocation, source.getPackageString());
}
}
return outputMap;
} catch (IOException e) {
logger.error(e);
return outputMap;
}
}
}