Make generate_workspace also generate a BUILD file with transitive deps
Fixes #89.
--
MOS_MIGRATED_REVID=98832811
diff --git a/site/docs/external.md b/site/docs/external.md
index 84c5423..583aaab 100644
--- a/site/docs/external.md
+++ b/site/docs/external.md
@@ -42,40 +42,52 @@
files) or Maven projects (i.e., _pom.xml_ files). For example:
```bash
-$ bazel run src/main/java/com/google/devtools/build/workspace:generate_workspace \
+$ bazel run src/main/java/com/google/devtools/build/workspace:generate_workspace -- \
> --maven_project=/path/to/my/project \
> --bazel_project=/path/to/skunkworks \
> --bazel_project=/path/to/teleporter/project
-# --------------------
-# The following dependencies were calculated from:
-# /path/to/my/project/pom.xml
-# /path/to/skunkworks/WORKSPACE
-# /path/to/teleporter/project/WORKSPACE
-
-
-# com.example.some-project:a:1.2.3
-# com.example.another-project:b:3.2.1 wanted version 2.4
-maven_jar(
- name = "javax/servlet/servlet-api",
- artifact = "javax.servlet:servlet-api:2.5",
-)
-
-[Other dependencies]
-# --------------------
-
-WARNING /path/to/my/project/pom.xml:1: javax.servlet:servlet-api already processed for version 2.5 but com.example.another-project:b:3.2.1 wants version 2.4, ignoring.
+Wrote:
+/tmp/1437415510621-0/2015-07-20-14-05-10.WORKSPACE
+/tmp/1437415510621-0/2015-07-20-14-05-10.BUILD
```
-Everything after the second `--------------------` is printed to stderr, not
-stdout. This is where any errors or warnings are printed. You may need to edit
-the versions that `generate_workspace` automatically chooses for the artifacts.
+
+The _WORKSPACE_ file contains the transitive dependencies of given projects. The
+_BUILD_ file contains a single target, `transitive-deps`, that contains all of
+the dependencies. You can copy these files to your project and add
+`transitive-deps` as a dependency of your `java_` targets in _BUILD_ files.
If you specify multiple Bazel or Maven projects, they will all be combined into
one _WORKSPACE_ file (e.g., if the Bazel project depends on junit and the Maven
project also depends on junit, junit will only appear once as a dependency in
the output).
-Once these `maven_jar`s have been added to your _WORKSPACE_ file, you will still
-need to add the jars as dependencies of your `java_` targets in _BUILD_ files.
+You may wish to curate the generated _WORKSPACE_ file to ensure it is using the
+correct version of each dependency. If several different versions of an artifact
+are requested (by different libraries that depend on it), then
+`generate_workspace` chooses a version and annotates the `maven_jar` with the
+other versions requested, for example:
+
+```python
+# org.springframework:spring:2.5.6
+# javax.mail:mail:1.4
+# httpunit:httpunit:1.6 wanted version 1.0.2
+# org.springframework:spring-support:2.0.2 wanted version 1.0.2
+# org.slf4j:nlog4j:1.2.24 wanted version 1.0.2
+maven_jar(
+ name = "javax/activation/activation",
+ artifact = "javax.activation:activation:1.1",
+)
+```
+
+This indicates that `org.springframework:spring:2.5.6`, `javax.mail:mail:1.4`,
+`httpunit:httpunit:1.6`, `org.springframework:spring-support:2.0.2`, and
+`org.slf4j:nlog4j:1.2.24` all depend on javax.activation. However, two of these
+libraries wanted version 1.1 and three of them wanted 1.0.2. The _WORkSPACE_
+file is using version 1.1, but that might not be the right version to use.
+
+You may also want to break `transitive-deps` into smaller targets, as it is
+unlikely that all of your targets depend on the transitive closure of your
+maven jars.
# Types of external dependencies
diff --git a/src/main/java/com/google/devtools/build/workspace/GenerateWorkspace.java b/src/main/java/com/google/devtools/build/workspace/GenerateWorkspace.java
index 7b05c4a..9e64efe 100644
--- a/src/main/java/com/google/devtools/build/workspace/GenerateWorkspace.java
+++ b/src/main/java/com/google/devtools/build/workspace/GenerateWorkspace.java
@@ -14,6 +14,7 @@
package com.google.devtools.build.workspace;
+import com.google.common.io.Files;
import com.google.devtools.build.lib.events.Event;
import com.google.devtools.build.lib.events.StoredEventHandler;
import com.google.devtools.build.lib.packages.ExternalPackage;
@@ -24,8 +25,13 @@
import com.google.devtools.build.lib.vfs.UnixFileSystem;
import com.google.devtools.common.options.OptionsParser;
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintStream;
import java.nio.file.Paths;
+import java.text.SimpleDateFormat;
import java.util.Collections;
+import java.util.Date;
import java.util.List;
/**
@@ -49,7 +55,13 @@
GenerateWorkspace workspaceFileGenerator = new GenerateWorkspace();
workspaceFileGenerator.generateFromWorkspace(options.bazelProjects);
workspaceFileGenerator.generateFromPom(options.mavenProjects);
- workspaceFileGenerator.print();
+ if (!workspaceFileGenerator.hasErrors()) {
+ workspaceFileGenerator.writeResults();
+ }
+ workspaceFileGenerator.cleanup();
+ if (workspaceFileGenerator.hasErrors()) {
+ System.exit(1);
+ }
}
private static void printUsage(OptionsParser parser) {
@@ -91,10 +103,33 @@
return Paths.get(System.getProperty("user.dir")).resolve(path).toString();
}
- private void print() {
- resolver.writeDependencies(System.out);
- resolver.cleanup();
+ /**
+ * Returns if there were any errors generating the WORKSPACE and BUILD files.
+ */
+ private boolean hasErrors() {
+ return handler.hasErrors();
+ }
+ private void writeResults() {
+ String date = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(new Date());
+ File tempDir = Files.createTempDir();
+ File workspaceFile = new File(tempDir + "/" + date + ".WORKSPACE");
+ File buildFile = new File(tempDir + "/" + date + ".BUILD");
+ try (PrintStream workspaceStream = new PrintStream(workspaceFile);
+ PrintStream buildStream = new PrintStream(buildFile)) {
+ resolver.writeWorkspace(workspaceStream);
+ resolver.writeBuild(buildStream);
+ } catch (IOException e) {
+ handler.handle(Event.error(
+ "Could not write WORKSPACE and BUILD files to " + tempDir + ": " + e.getMessage()));
+ return;
+ }
+
+ System.err.println("Wrote:\n" + workspaceFile + "\n" + buildFile);
+ }
+
+ private void cleanup() {
+ resolver.cleanup();
for (Event event : handler.getEvents()) {
System.err.println(event);
}
diff --git a/src/main/java/com/google/devtools/build/workspace/maven/Resolver.java b/src/main/java/com/google/devtools/build/workspace/maven/Resolver.java
index 2ffd1b0..aa6b878 100644
--- a/src/main/java/com/google/devtools/build/workspace/maven/Resolver.java
+++ b/src/main/java/com/google/devtools/build/workspace/maven/Resolver.java
@@ -73,17 +73,35 @@
/**
* Writes all resolved dependencies in WORKSPACE file format to the outputStream.
*/
- public void writeDependencies(PrintStream outputStream) {
- outputStream.println("# --------------------\n"
- + "# The following dependencies were calculated from:");
+ public void writeWorkspace(PrintStream outputStream) {
+ writeHeader(outputStream);
+ for (Rule rule : deps.values()) {
+ outputStream.println(rule + "\n");
+ }
+ }
+
+ /**
+ * Write library rules to depend on the transitive closure of all of these rules.
+ */
+ public void writeBuild(PrintStream outputStream) {
+ writeHeader(outputStream);
+ outputStream.println("java_library(");
+ outputStream.println(" name = \"transitive-deps\",");
+ outputStream.println(" visibility = [\"//visibility:public\"],");
+ outputStream.println(" exports = [");
+ for (Rule rule : deps.values()) {
+ outputStream.println(" \"@" + rule.name() + "//jar\",");
+ }
+ outputStream.println(" ],");
+ outputStream.println(")");
+ }
+
+ private void writeHeader(PrintStream outputStream) {
+ outputStream.println("# The following dependencies were calculated from:");
for (String header : headers) {
outputStream.println("# " + header);
}
outputStream.print("\n\n");
- for (Rule rule : deps.values()) {
- outputStream.println(rule + "\n");
- }
- outputStream.println("# --------------------\n");
}
public void addHeader(String header) {
diff --git a/src/test/shell/bazel/workspace_test.sh b/src/test/shell/bazel/workspace_test.sh
index 5519435..51abf7f 100755
--- a/src/test/shell/bazel/workspace_test.sh
+++ b/src/test/shell/bazel/workspace_test.sh
@@ -58,7 +58,6 @@
EOF
bazel build @x//:x || fail "build failed"
- ls -l $(bazel info execution_root)/external/x/
assert_contains "bye" bazel-genfiles/out
}
@@ -73,67 +72,4 @@
bazel help &> $TEST_log || fail "Help failed"
}
-function write_pom() {
- cat > pom.xml <<EOF
-<project>
- <modelVersion>4.0.0</modelVersion>
- <groupId>com.mycompany.app</groupId>
- <artifactId>my-app</artifactId>
- <version>1</version>
- <packaging>pom</packaging>
- <modules>
- <module>my-module</module>
- </modules>
- <dependencies>
- <dependency>
- <groupId>com.y.z</groupId>
- <artifactId>x</artifactId>
- <version>3.2.1</version>
- </dependency>
- </dependencies>
-</project>
-EOF
-}
-
-function test_minimal_pom() {
- write_pom
-
- ${bazel_data}/src/main/java/com/google/devtools/build/workspace/generate_workspace \
- --maven_project=$(pwd) &> $TEST_log || fail "generating workspace failed"
- expect_log "artifact = \"com.y.z:x:3.2.1\","
-}
-
-function test_parent_pom_inheritence() {
- write_pom
- mkdir my-module
- cat > my-module/pom.xml <<EOF
-<project>
- <parent>
- <groupId>com.mycompany.app</groupId>
- <artifactId>my-app</artifactId>
- <version>1</version>
- </parent>
- <modelVersion>4.0.0</modelVersion>
- <groupId>com.mycompany.app</groupId>
- <artifactId>my-module</artifactId>
- <version>1</version>
- <dependencies>
- <dependency>
- <groupId>com.z.w</groupId>
- <artifactId>x</artifactId>
- <version>1.2.3</version>
- </dependency>
- </dependencies>
-</project>
-EOF
-
- ${bazel_data}/src/main/java/com/google/devtools/build/workspace/generate_workspace \
- --maven_project=$(pwd)/my-module &> $TEST_log || \
- fail "generating workspace failed"
- expect_log "name = \"com/y/z/x\","
- expect_log "artifact = \"com.y.z:x:3.2.1\","
- expect_log "name = \"com/z/w/x\","
- expect_log "artifact = \"com.z.w:x:1.2.3\","
-}
-
run_suite "workspace tests"