# Copyright 2015 Google Inc. 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. """Rules for supporting the Scala language.""" _scala_filetype = FileType([".scala"]) # TODO(bazel-team): Add local_repository to properly declare the dependency. _scala_library_path = "/usr/share/java/scala-library.jar" _scalac_path = "/usr/bin/scalac" def _compile(ctx, jars): cmd = """ set -e mkdir -p {out}_tmp {scalac} {scala_opts} {jvm_flags} -classpath "{jars}" $@ -d {out}_tmp # Make jar file deterministic by setting the timestamp of files touch -t 198001010000 $(find .) jar cmf {manifest} {out} -C {out}_tmp . """ cmd = cmd.format( scalac=_scalac_path, scala_opts=" ".join(ctx.attr.scalacopts), jvm_flags=" ".join(["-J" + flag for flag in ctx.attr.jvm_flags]), out=ctx.outputs.jar.path, manifest=ctx.outputs.manifest.path, jars=":".join([j.path for j in jars])) ctx.action( inputs=list(jars) + ctx.files.srcs + [ctx.outputs.manifest], outputs=[ctx.outputs.jar], command=cmd, progress_message="scala %s" % ctx.label, arguments=[f.path for f in ctx.files.srcs]) def _write_manifest(ctx): cp = "/usr/share/java/scala-library.jar" manifest = "Class-Path: %s\n" % cp if getattr(ctx.attr, "main_class", ""): manifest += "Main-Class: %s\n" % ctx.attr.main_class ctx.file_action( output = ctx.outputs.manifest, content = manifest) def _write_launcher(ctx, jars): content = """#!/bin/bash cd $0.runfiles java -cp {cp} {name} "$@" """ content = content.format( name=ctx.attr.main_class, deploy_jar=ctx.outputs.jar.path, cp=":".join([j.short_path for j in jars])) ctx.file_action( output=ctx.outputs.executable, content=content) def _collect_jars(ctx): jars = set() for target in ctx.attr.deps: if hasattr(target, "jar_files"): jars += target.jar_files elif hasattr(target, "java"): jars += target.java.transitive_runtime_deps return jars def _scala_library_impl(ctx): jars = _collect_jars(ctx) _write_manifest(ctx) _compile(ctx, jars) jars += [ctx.outputs.jar] runfiles = ctx.runfiles( files = list(jars), collect_data = True) return struct( files=jars, jar_files=jars, runfiles=runfiles) def _scala_binary_impl(ctx): jars = _collect_jars(ctx) _write_manifest(ctx) _compile(ctx, jars) jars += [ctx.outputs.jar] _write_launcher(ctx, jars) runfiles = ctx.runfiles( files = list(jars) + [ctx.outputs.executable], collect_data = True) return struct( files=set([ctx.outputs.executable]), runfiles=runfiles) scala_library = rule( implementation=_scala_library_impl, attrs={ "main_class": attr.string(), "srcs": attr.label_list( allow_files=_scala_filetype, non_empty=True), "deps": attr.label_list(), "data": attr.label_list(allow_files=True, cfg=DATA_CFG), "scalacopts": attr.string_list(), "jvm_flags": attr.string_list(), }, outputs={ "jar": "%{name}_deploy.jar", "manifest": "%{name}_MANIFEST.MF", }, ) scala_binary = rule( implementation=_scala_binary_impl, attrs={ "main_class": attr.string(mandatory=True), "srcs": attr.label_list( allow_files=_scala_filetype, non_empty=True), "deps": attr.label_list(), "data": attr.label_list(allow_files=True, cfg=DATA_CFG), "scalacopts":attr.string_list(), "jvm_flags": attr.string_list(), }, outputs={ "jar": "%{name}_deploy.jar", "manifest": "%{name}_MANIFEST.MF", }, executable=True, )