blob: e7cdd2924beec69fd677d15922d6b4c1203af8a7 [file] [log] [blame]
# Copyright 2015 Erik Kuefler. 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.
def _groovy_jar_impl(ctx):
"""Creates a .jar file from Groovy sources. Users should rely on
groovy_library instead of using this rule directly.
"""
class_jar = ctx.outputs.class_jar
build_output = class_jar.path + ".build_output"
# Extract all transitive dependencies
# TODO(bazel-team): get transitive dependencies from other groovy libraries
all_deps = set(ctx.files.deps)
for this_dep in ctx.attr.deps:
if hasattr(this_dep, "java"):
all_deps += this_dep.java.transitive_runtime_deps
# Set up the output directory and set JAVA_HOME
cmd = "rm -rf %s\n" % build_output
cmd += "mkdir -p %s\n" % build_output
cmd += "export JAVA_HOME=external/local-jdk\n"
# Set GROOVY_HOME by scanning through the groovy SDK to find the license file,
# which should be at the root of the SDK.
for file in ctx.files._groovysdk:
if file.basename == "CLI-LICENSE.txt":
cmd += "export GROOVY_HOME=%s\n" % file.dirname
break
# Compile all files in srcs with groovyc
cmd += "$GROOVY_HOME/bin/groovyc %s -d %s %s\n" % (
"-cp " + ":".join([dep.path for dep in all_deps]) if len(all_deps) != 0 else "",
build_output,
" ".join([src.path for src in ctx.files.srcs]),
)
# Jar them together to produce a single output. To make this work we have
# to cd into the output directory, run find to locate all of the generated
# class files, pass the result to cut to trim the leading "./", then pass
# the resulting paths to the zipper.
cmd += "root=`pwd`\n"
cmd += "cd %s; $root/%s Cc ../%s `find . -name '*.class' | cut -c 3-`\n" % (
build_output,
ctx.executable._zipper.path,
class_jar.basename,
)
cmd += "cd $root\n"
# Clean up temporary output
cmd += "rm -rf %s" % build_output
# Execute the command
ctx.action(
inputs = (
ctx.files.srcs
+ list(all_deps)
+ ctx.files._groovysdk
+ ctx.files._jdk
+ ctx.files._zipper),
outputs = [class_jar],
mnemonic = "Groovyc",
command = "set -e;" + cmd,
use_default_shell_env = True,
)
_groovy_jar = rule(
implementation = _groovy_jar_impl,
attrs = {
"srcs": attr.label_list(
mandatory=False,
allow_files=FileType([".groovy"])),
"deps": attr.label_list(
mandatory=False,
allow_files=FileType([".jar"])),
"_groovysdk": attr.label(
default=Label("//external:groovy-sdk")),
"_jdk": attr.label(
default=Label("//tools/defaults:jdk")),
"_zipper": attr.label(
default=Label("//third_party/ijar:zipper"),
executable=True,
single_file=True),
},
outputs = {
"class_jar": "lib%{name}.jar",
},
)
def groovy_library(name, srcs=[], deps=[], **kwargs):
"""Rule analagous to java_library that accepts .groovy sources instead of
.java sources. The result is wrapped in a java_import so that java rules may
depend on it.
"""
_groovy_jar(
name = name + "-impl",
srcs = srcs,
deps = deps,
)
native.java_import(
name = name,
jars = [name + "-impl"],
**kwargs
)
def groovy_and_java_library(name, srcs=[], deps=[], **kwargs):
"""Accepts .groovy and .java srcs to create a groovy_library and a
java_library. The groovy_library will depend on the java_library, so the
Groovy code may reference the Java code but not vice-versa.
"""
groovy_deps = deps
jars = []
# Put all .java sources in a java_library
java_srcs = [src for src in srcs if src.endswith(".java")]
if java_srcs:
native.java_library(
name = name + "-java",
srcs = java_srcs,
deps = deps,
)
groovy_deps += [name + "-java"]
jars += ["lib" + name + "-java.jar"]
# Put all .groovy sources in a groovy_library depending on the java_library
groovy_srcs = [src for src in srcs if src.endswith(".groovy")]
if groovy_srcs:
_groovy_jar(
name = name + "-groovy",
srcs = groovy_srcs,
deps = groovy_deps,
)
jars += ["lib" + name + "-groovy.jar"]
# Output a java_import combining both libraries
native.java_import(
name = name,
jars = jars,
**kwargs
)
def groovy_binary(name, main_class, srcs=[], deps=[], **kwargs):
"""Rule analagous to java_binary that accepts .groovy sources instead of .java
sources.
"""
all_deps = deps
if srcs:
groovy_library(
name = name + "-lib",
srcs = srcs,
deps = deps,
)
all_deps += [name + "-lib"]
native.java_binary(
name = name,
main_class = main_class,
runtime_deps = all_deps,
**kwargs
)
def path_to_class(path):
if path.startswith("src/test/groovy/"):
return path[len("src/test/groovy/") : path.index(".groovy")].replace('/', '.')
elif path.startswith("src/test/java/"):
return path[len("src/test/java/") : path.index(".groovy")].replace('/', '.')
else:
fail("groovy_test sources must be under src/test/java or src/test/groovy")
def groovy_test_impl(ctx):
# Collect jars from the Groovy sdk
groovy_sdk_jars = [file
for file in ctx.files._groovysdk
if file.basename.endswith(".jar")
]
# Extract all transitive dependencies
all_deps = set(ctx.files.deps + ctx.files._implicit_deps + groovy_sdk_jars)
for this_dep in ctx.attr.deps:
if hasattr(this_dep, 'java'):
all_deps += this_dep.java.transitive_runtime_deps
# Infer a class name from each src file
classes = [path_to_class(src.path) for src in ctx.files.srcs]
# Write a file that executes JUnit on the inferred classes
cmd = "external/local-jdk/bin/java %s -cp %s org.junit.runner.JUnitCore %s\n" % (
" ".join(ctx.attr.jvm_flags),
":".join([dep.short_path for dep in all_deps]),
" ".join(classes),
)
ctx.file_action(
output = ctx.outputs.executable,
content = cmd
)
# Return all dependencies needed to run the tests
return struct(
runfiles=ctx.runfiles(files=list(all_deps) + ctx.files._jdk),
)
groovy_test = rule(
implementation = groovy_test_impl,
attrs = {
"srcs": attr.label_list(mandatory=True, allow_files=FileType([".groovy"])),
"deps": attr.label_list(allow_files=FileType([".jar"])),
"jvm_flags": attr.string_list(),
"_groovysdk": attr.label(
default=Label("//external:groovy-sdk")),
"_jdk": attr.label(
default=Label("//tools/defaults:jdk")),
"_implicit_deps": attr.label_list(default=[
Label("//external:junit"),
]),
},
test = True,
)