diff options
author | 2017-08-23 19:32:49 +0200 | |
---|---|---|
committer | 2017-08-24 13:58:50 +0200 | |
commit | 7a7c41d7d342cd427e74f091b55690eed13e280d (patch) | |
tree | 9dff41110751ad6e1a0b0a12e15a11e8d8f8e9ac /src/main/java/com/google/devtools/build | |
parent | 49bb72377153fc208708267f90791644f389bd31 (diff) |
Pull maven -src jars when available alongside jars re:
https://github.com/bazelbuild/bazel/issues/308
RELNOTES: None.
PiperOrigin-RevId: 166219871
Diffstat (limited to 'src/main/java/com/google/devtools/build')
3 files changed, 169 insertions, 52 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/repository/JarDecompressor.java b/src/main/java/com/google/devtools/build/lib/bazel/repository/JarDecompressor.java index 703c4a32dd..26286adef0 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/repository/JarDecompressor.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/repository/JarDecompressor.java @@ -15,6 +15,7 @@ package com.google.devtools.build.lib.bazel.repository; import com.google.common.base.Joiner; +import com.google.common.base.Optional; import com.google.devtools.build.lib.bazel.repository.DecompressorValue.Decompressor; import com.google.devtools.build.lib.rules.repository.RepositoryFunction; import com.google.devtools.build.lib.rules.repository.RepositoryFunction.RepositoryFunctionException; @@ -34,34 +35,46 @@ public class JarDecompressor implements Decompressor { protected JarDecompressor() { } - /** - * The .jar can be used compressed, so this just exposes it in a way Bazel can use. - * - * <p>It moves the jar from some-name/x/y/z/foo.jar to some-name/jar/foo.jar and creates a - * BUILD.bazel file containing one entry: the .jar. - */ @Override @Nullable public Path decompress(DecompressorDescriptor descriptor) throws RepositoryFunctionException { - // Example: archiveFile is external/some-name/foo.jar. - String baseName = descriptor.archivePath().getBaseName(); + return decompressWithSrcjar(descriptor, Optional.absent()); + } + /** + * The jar (and srcjar if available) can be used compressed, so this just exposes them in a way + * Bazel can use. + * + * <p>It moves the jar(s) from some-name/x/y/z/foo.jar to some-name/jar/foo.jar and creates a + * BUILD.bazel file containing only the jar(s). + */ + public Path decompressWithSrcjar( + DecompressorDescriptor descriptor, Optional<DecompressorDescriptor> srcjarDescriptor) + throws RepositoryFunctionException { try { + // external/some-name/ FileSystemUtils.createDirectoryAndParents(descriptor.repositoryPath()); - // external/some-name/WORKSPACE. + // external/some-name/WORKSPACE RepositoryFunction.createWorkspaceFile( descriptor.repositoryPath(), descriptor.targetKind(), descriptor.targetName()); - // external/some-name/jar. + // external/some-name/jar/ Path jarDirectory = descriptor.repositoryPath().getRelative(getPackageName()); FileSystemUtils.createDirectoryAndParents(jarDirectory); - // external/some-name/repository/jar/foo.jar is a symbolic link to the jar in - // external/some-name. - Path jarSymlink = jarDirectory.getRelative(baseName); - if (!jarSymlink.exists()) { - jarSymlink.createSymbolicLink(descriptor.archivePath()); - } - // external/some-name/repository/jar/BUILD.bazel defines the //jar target. + // external/some-name/jar/BUILD.bazel defines the //jar target. Path buildFile = jarDirectory.getRelative("BUILD.bazel"); + + // Example: get foo.jar from external/some-name/foo.jar. + String baseName = descriptor.archivePath().getBaseName(); + makeSymlink(descriptor); + String buildFileContents; + if (srcjarDescriptor.isPresent()) { + String srcjarBaseName = srcjarDescriptor.get().archivePath().getBaseName(); + makeSymlink(srcjarDescriptor.get()); + buildFileContents = createBuildFileWithSrcjar(baseName, srcjarBaseName); + } else { + buildFileContents = createBuildFile(baseName); + } + FileSystemUtils.writeLinesAs( buildFile, Charset.forName("UTF-8"), @@ -69,7 +82,7 @@ public class JarDecompressor implements Decompressor { + descriptor.targetKind() + " rule " + descriptor.targetName(), - createBuildFile(baseName)); + buildFileContents); if (descriptor.executable()) { descriptor.archivePath().chmod(0755); } @@ -80,6 +93,25 @@ public class JarDecompressor implements Decompressor { return descriptor.repositoryPath(); } + /* + * Links some-name/x/y/z/foo.jar to some-name/jar/foo.jar (represented by {@code descriptor} + */ + protected void makeSymlink(DecompressorDescriptor descriptor) throws RepositoryFunctionException { + try { + Path jarDirectory = descriptor.repositoryPath().getRelative(getPackageName()); + // external/some-name/jar/foo.jar is a symbolic link to the jar in + // external/some-name. + Path jarSymlink = jarDirectory.getRelative(descriptor.archivePath().getBaseName()); + if (!jarSymlink.exists()) { + jarSymlink.createSymbolicLink(descriptor.archivePath()); + } + } catch (IOException e) { + throw new RepositoryFunctionException( + new IOException("Error auto-creating jar repo structure: " + e.getMessage()), + Transience.TRANSIENT); + } + } + protected String getPackageName() { return "jar"; } @@ -99,4 +131,24 @@ public class JarDecompressor implements Decompressor { " visibility = ['//visibility:public']", ")"); } + + protected String createBuildFileWithSrcjar(String baseName, String srcjarBaseName) { + return Joiner.on("\n") + .join( + "java_import(", + " name = 'jar',", + " jars = ['" + baseName + "'],", + " srcjar = '" + srcjarBaseName + "',", + " visibility = ['//visibility:public']", + ")", + "", + "filegroup(", + " name = 'file',", + " srcs = [", + " '" + baseName + "',", + " '" + srcjarBaseName + "',", + " ],", + " visibility = ['//visibility:public']", + ")"); + } } diff --git a/src/main/java/com/google/devtools/build/lib/bazel/repository/MavenDownloader.java b/src/main/java/com/google/devtools/build/lib/bazel/repository/MavenDownloader.java index 264173ef8f..e663a80499 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/repository/MavenDownloader.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/repository/MavenDownloader.java @@ -14,6 +14,7 @@ package com.google.devtools.build.lib.bazel.repository; +import com.google.common.base.Optional; import com.google.common.base.Strings; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; @@ -72,9 +73,10 @@ public class MavenDownloader extends HttpDownloader { } /** - * Download the Maven artifact to the output directory. Returns the path to the jar. + * Download the Maven artifact to the output directory. Returns the path to the jar (and the + * srcjar if available). */ - public Path download(String name, WorkspaceAttributeMapper mapper, Path outputDirectory, + public JarPaths download(String name, WorkspaceAttributeMapper mapper, Path outputDirectory, MavenServerValue serverValue) throws IOException, EvalException { this.name = name; this.outputDirectory = outputDirectory; @@ -82,59 +84,73 @@ public class MavenDownloader extends HttpDownloader { String url = serverValue.getUrl(); Server server = serverValue.getServer(); + // Initialize maven artifacts Artifact artifact; - String artifactId = mapper.get("artifact", Type.STRING); - String sha1 = mapper.isAttributeValueExplicitlySpecified("sha1") - ? mapper.get("sha1", Type.STRING) : null; - if (sha1 != null && !KeyType.SHA1.isValid(sha1)) { - throw new IOException("Invalid SHA-1 for maven_jar " + name + ": '" + sha1 + "'"); - } + String artifactCoords = mapper.get("artifact", Type.STRING); + String sha1 = + mapper.isAttributeValueExplicitlySpecified("sha1") ? mapper.get("sha1", Type.STRING) : null; + if (sha1 != null && !KeyType.SHA1.isValid(sha1)) { + throw new IOException("Invalid SHA-1 for maven_jar " + name + ": '" + sha1 + "'"); + } + try { - artifact = new DefaultArtifact(artifactId); + artifact = new DefaultArtifact(artifactCoords); } catch (IllegalArgumentException e) { throw new IOException(e.getMessage()); } - + boolean isCaching = repositoryCache.isEnabled() && KeyType.SHA1.isValid(sha1); if (isCaching) { Path downloadPath = getDownloadDestination(artifact); Path cachedDestination = repositoryCache.get(sha1, downloadPath, KeyType.SHA1); if (cachedDestination != null) { - return cachedDestination; + return new JarPaths(cachedDestination, Optional.absent()); } } + // Setup env for fetching jars MavenConnector connector = new MavenConnector(outputDirectory.getPathString()); RepositorySystem system = connector.newRepositorySystem(); RepositorySystemSession session = connector.newRepositorySystemSession(system); + RemoteRepository repository = + new RemoteRepository.Builder(name, MavenServerValue.DEFAULT_ID, url) + .setAuthentication(new MavenAuthentication(server)) + .build(); - RemoteRepository repository = new RemoteRepository.Builder( - name, MavenServerValue.DEFAULT_ID, url) - .setAuthentication(new MavenAuthentication(server)) - .build(); - ArtifactRequest artifactRequest = new ArtifactRequest(); - - artifactRequest.setArtifact(artifact); - artifactRequest.setRepositories(ImmutableList.of(repository)); - + // Try fetching jar. + final Path jarDownload; try { - ArtifactResult artifactResult = system.resolveArtifact(session, artifactRequest); - artifact = artifactResult.getArtifact(); + artifact = downloadArtifact(artifact, repository, session, system); } catch (ArtifactResolutionException e) { throw new IOException("Failed to fetch Maven dependency: " + e.getMessage()); } - Path downloadPath = outputDirectory.getRelative(artifact.getFile().getAbsolutePath()); + // Try also fetching srcjar. + Artifact artifactWithSrcs = srcjarCoords(artifact); + try { + artifactWithSrcs = downloadArtifact(artifactWithSrcs, repository, session, system); + } catch (ArtifactResolutionException e) { + // Intentionally ignored - missing srcjar is not an error. + } + + jarDownload = outputDirectory.getRelative(artifact.getFile().getAbsolutePath()); // Verify checksum. if (!Strings.isNullOrEmpty(sha1)) { - RepositoryCache.assertFileChecksum(sha1, downloadPath, KeyType.SHA1); + RepositoryCache.assertFileChecksum(sha1, jarDownload, KeyType.SHA1); } if (isCaching) { - repositoryCache.put(sha1, downloadPath, KeyType.SHA1); + repositoryCache.put(sha1, jarDownload, KeyType.SHA1); + } + + if (artifactWithSrcs.getFile() != null) { + Path srcjarDownload = + outputDirectory.getRelative(artifactWithSrcs.getFile().getAbsolutePath()); + return new JarPaths(jarDownload, Optional.fromNullable(srcjarDownload)); + } else { + return new JarPaths(jarDownload, Optional.absent()); } - return downloadPath; } private Path getDownloadDestination(Artifact artifact) { @@ -149,6 +165,40 @@ public class MavenDownloader extends HttpDownloader { return outputDirectory.getRelative(joiner.toString()); } + private Artifact srcjarCoords(Artifact jar) { + return new DefaultArtifact( + jar.getGroupId(), jar.getArtifactId(), "sources", jar.getExtension(), jar.getVersion()); + } + + /* + * Set up request for and resolve (retrieve to local repo) artifact + */ + private Artifact downloadArtifact( + Artifact artifact, + RemoteRepository repository, + RepositorySystemSession session, + RepositorySystem system) + throws ArtifactResolutionException { + ArtifactRequest artifactRequest = new ArtifactRequest(); + artifactRequest.setArtifact(artifact); + artifactRequest.setRepositories(ImmutableList.of(repository)); + ArtifactResult artifactResult = system.resolveArtifact(session, artifactRequest); + return artifactResult.getArtifact(); + } + + /* + * Class for packaging srcjar and jar paths together when srcjar is available. + */ + static class JarPaths { + final Path jar; + @Nullable final Optional<Path> srcjar; + + private JarPaths(Path jar, Optional<Path> srcjar) { + this.jar = jar; + this.srcjar = srcjar; + } + } + private static class MavenAuthentication implements Authentication { private final Map<String, String> authenticationInfo; diff --git a/src/main/java/com/google/devtools/build/lib/bazel/repository/MavenJarFunction.java b/src/main/java/com/google/devtools/build/lib/bazel/repository/MavenJarFunction.java index 907227e959..45aa2bab6f 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/repository/MavenJarFunction.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/repository/MavenJarFunction.java @@ -14,9 +14,11 @@ package com.google.devtools.build.lib.bazel.repository; +import com.google.common.base.Optional; import com.google.common.base.Preconditions; 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.packages.Rule; import com.google.devtools.build.lib.rules.repository.RepositoryDirectoryValue; @@ -98,7 +100,7 @@ public class MavenJarFunction extends HttpArchiveFunction { if (env.valuesMissing()) { return null; } - + Path outputDir = getExternalRepositoryDirectory(directories).getRelative(rule.getName()); return createOutputTree(rule, outputDir, serverValue); } @@ -110,10 +112,11 @@ public class MavenJarFunction extends HttpArchiveFunction { createDirectory(outputDirectory); String name = rule.getName(); - Path repositoryJar; + final JarPaths repositoryJars; try { - repositoryJar = mavenDownloader.download( - name, WorkspaceAttributeMapper.of(rule), outputDirectory, serverValue); + repositoryJars = + mavenDownloader.download( + name, WorkspaceAttributeMapper.of(rule), outputDirectory, serverValue); } catch (IOException e) { throw new RepositoryFunctionException(e, Transience.TRANSIENT); } catch (EvalException e) { @@ -121,13 +124,25 @@ public class MavenJarFunction extends HttpArchiveFunction { } // Add a WORKSPACE file & BUILD file to the Maven jar. - Path result = DecompressorValue.decompress(DecompressorDescriptor.builder() + 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, InterruptedException { + return DecompressorDescriptor.builder() .setDecompressor(JarDecompressor.INSTANCE) .setTargetKind(MavenJarRule.NAME) .setTargetName(name) - .setArchivePath(repositoryJar) - .setRepositoryPath(outputDirectory).build()); - return RepositoryDirectoryValue.builder().setPath(result); + .setArchivePath(jar) + .setRepositoryPath(outputDirectory) + .build(); } /** |