blob: 19eb87cef57b484149ef7068dfc60dfb59068673 [file] [log] [blame]
// Copyright 2014 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.devtools.build.lib.bazel.repository;
import com.google.common.base.Optional;
import com.google.devtools.build.lib.analysis.BlazeDirectories;
import com.google.devtools.build.lib.analysis.RuleDefinition;
import com.google.devtools.build.lib.bazel.repository.MavenDownloader.JarPaths;
import com.google.devtools.build.lib.bazel.rules.workspace.MavenJarRule;
import com.google.devtools.build.lib.events.ExtendedEventHandler;
import com.google.devtools.build.lib.packages.Rule;
import com.google.devtools.build.lib.rules.repository.RepositoryDirectoryValue;
import com.google.devtools.build.lib.rules.repository.RepositoryFunction;
import com.google.devtools.build.lib.rules.repository.WorkspaceAttributeMapper;
import com.google.devtools.build.lib.skyframe.PrecomputedValue;
import com.google.devtools.build.lib.syntax.EvalException;
import com.google.devtools.build.lib.syntax.StarlarkSemantics;
import com.google.devtools.build.lib.syntax.Type;
import com.google.devtools.build.lib.util.Fingerprint;
import com.google.devtools.build.lib.vfs.FileSystemUtils;
import com.google.devtools.build.lib.vfs.Path;
import com.google.devtools.build.skyframe.SkyFunction.Environment;
import com.google.devtools.build.skyframe.SkyFunctionException.Transience;
import com.google.devtools.build.skyframe.SkyKey;
import java.io.IOException;
import java.util.Map;
/** Implementation of maven_jar. */
public class MavenJarFunction extends RepositoryFunction {
protected final MavenDownloader downloader;
public MavenJarFunction(MavenDownloader mavenDownloader) {
super();
this.downloader = mavenDownloader;
}
private static final String DEFAULT_SERVER = "default";
@Override
public boolean isLocal(Rule rule) {
return false;
}
@Override
protected byte[] getRuleSpecificMarkerData(Rule rule, Environment env)
throws RepositoryFunctionException, InterruptedException {
MavenServerValue serverValue = getServer(rule, env);
if (env.valuesMissing()) {
return null;
}
return new Fingerprint()
.addString(serverValue.getUrl())
.addBytes(serverValue.getSettingsFingerprint())
.digestAndReset();
}
private static MavenServerValue getServer(Rule rule, Environment env)
throws RepositoryFunctionException, InterruptedException {
WorkspaceAttributeMapper mapper = WorkspaceAttributeMapper.of(rule);
boolean hasRepository = mapper.isAttributeValueExplicitlySpecified("repository");
boolean hasServer = mapper.isAttributeValueExplicitlySpecified("server");
if (hasRepository && hasServer) {
throw new RepositoryFunctionException(new EvalException(
rule.getLocation(), rule + " specifies both "
+ "'repository' and 'server', which are mutually exclusive options"),
Transience.PERSISTENT);
}
try {
if (hasRepository) {
return MavenServerValue.createFromUrl(mapper.get("repository", Type.STRING));
} else {
String serverName = DEFAULT_SERVER;
if (hasServer) {
serverName = mapper.get("server", Type.STRING);
}
return (MavenServerValue) env.getValue(MavenServerValue.key(serverName));
}
} catch (EvalException e) {
throw new RepositoryFunctionException(e, Transience.PERSISTENT);
}
}
@Override
public RepositoryDirectoryValue.Builder fetch(
Rule rule,
Path outputDirectory,
BlazeDirectories directories,
Environment env,
Map<String, String> markerData,
SkyKey key)
throws RepositoryFunctionException, InterruptedException {
// Deprecation in favor of the Starlark rule
StarlarkSemantics starlarkSemantics = PrecomputedValue.STARLARK_SEMANTICS.get(env);
if (starlarkSemantics == null) {
return null;
}
if (starlarkSemantics.incompatibleRemoveNativeMavenJar()) {
throw new RepositoryFunctionException(
new EvalException(
null,
"The native maven_jar rule is deprecated."
+ " See https://docs.bazel.build/versions/master/skylark/"
+ "backward-compatibility.html#remove-native-maven-jar for migration information."
+ "\nUse --incompatible_remove_native_maven_jar=false to temporarily continue"
+ " using the native rule."),
Transience.PERSISTENT);
}
MavenServerValue serverValue = getServer(rule, env);
if (env.valuesMissing()) {
return null;
}
Path outputDir = getExternalRepositoryDirectory(directories).getRelative(rule.getName());
return createOutputTree(rule, outputDir, serverValue, env.getListener());
}
private void createDirectory(Path path) throws RepositoryFunctionException {
try {
FileSystemUtils.createDirectoryAndParents(path);
} catch (IOException e) {
throw new RepositoryFunctionException(e, Transience.TRANSIENT);
}
}
private RepositoryDirectoryValue.Builder createOutputTree(
Rule rule,
Path outputDirectory,
MavenServerValue serverValue,
ExtendedEventHandler eventHandler)
throws RepositoryFunctionException {
MavenDownloader mavenDownloader = downloader;
createDirectory(outputDirectory);
String name = rule.getName();
final JarPaths repositoryJars;
try {
repositoryJars =
mavenDownloader.download(
name, WorkspaceAttributeMapper.of(rule), outputDirectory, serverValue, eventHandler);
} catch (IOException e) {
throw new RepositoryFunctionException(e, Transience.TRANSIENT);
} catch (EvalException e) {
throw new RepositoryFunctionException(e, Transience.TRANSIENT);
}
// Add a WORKSPACE file & BUILD file to the Maven jar.
DecompressorDescriptor jar = getDescriptorBuilder(name, repositoryJars.jar, outputDirectory);
DecompressorDescriptor srcjar =
repositoryJars.srcjar.isPresent()
? getDescriptorBuilder(name, repositoryJars.srcjar.get(), outputDirectory)
: null;
JarDecompressor decompressor = (JarDecompressor) jar.getDecompressor();
Path result = decompressor.decompressWithSrcjar(jar, Optional.fromNullable(srcjar));
return RepositoryDirectoryValue.builder().setPath(result);
}
private DecompressorDescriptor getDescriptorBuilder(String name, Path jar, Path outputDirectory)
throws RepositoryFunctionException {
return DecompressorDescriptor.builder()
.setDecompressor(JarDecompressor.INSTANCE)
.setTargetKind(MavenJarRule.NAME)
.setTargetName(name)
.setArchivePath(jar)
.setRepositoryPath(outputDirectory)
.build();
}
@Override
public Class<? extends RuleDefinition> getRuleDefinition() {
return MavenJarRule.class;
}
}