Build the feature jar with Bazel (#37)
diff --git a/BUILD b/BUILD new file mode 100644 index 0000000..93df28b --- /dev/null +++ b/BUILD
@@ -0,0 +1 @@ +exports_files(["LICENSE.txt"])
diff --git a/WORKSPACE b/WORKSPACE index fba3f3b..fd4aa93 100644 --- a/WORKSPACE +++ b/WORKSPACE
@@ -1,9 +1,26 @@ workspace(name = "build_bazel_e4b") -load("//tools/build_defs:eclipse_plugin.bzl", "load_eclipse_deps") +load("//tools/build_defs:eclipse.bzl", "load_eclipse_deps") load_eclipse_deps() +new_http_archive( + name = "com_google_python_gflags", + url = "https://github.com/google/python-gflags/archive/python-gflags-2.0.zip", + strip_prefix = "python-gflags-python-gflags-2.0", + build_file_content = """ +py_library( + name = "gflags", + srcs = [ + "gflags.py", + "gflags_validators.py", + ], + visibility = ["//visibility:public"], +) +""", + sha256 = "344990e63d49b9b7a829aec37d5981d558fea12879f673ee7d25d2a109eb30ce", +) + # TODO(dmarting): Use http_file and relies on a mirror instead of maven_jar maven_jar( name = "com_google_guava",
diff --git a/com.google.devtools.bazel.e4b.feature/BUILD b/com.google.devtools.bazel.e4b.feature/BUILD new file mode 100644 index 0000000..70d2162 --- /dev/null +++ b/com.google.devtools.bazel.e4b.feature/BUILD
@@ -0,0 +1,15 @@ +load("//tools/build_defs:eclipse.bzl", "eclipse_feature") + +eclipse_feature( + name = "com.google.devtools.bazel.e4b.feature", + copyright = "Copyright 2016 The Bazel Authors", + description = "Integrate Eclipse with the Bazel build system.", + label = "Eclipse 4 Bazel", + license = "//:LICENSE.txt", + license_url = "http://www.apache.org/licenses/LICENSE-2.0", + plugins = ["//com.google.devtools.bazel.e4b"], + provider = "The Bazel Authors", + sites = {"Bazel": "https://bazel.build"}, + url = "https://github.com/bazelbuild/e4b", + version = "0.0.3.qualifier", +)
diff --git a/com.google.devtools.bazel.e4b/BUILD b/com.google.devtools.bazel.e4b/BUILD index 78ccfa5..c6413dd 100644 --- a/com.google.devtools.bazel.e4b/BUILD +++ b/com.google.devtools.bazel.e4b/BUILD
@@ -1,13 +1,14 @@ -load("//tools/build_defs:eclipse_plugin.bzl", "eclipse_plugin") +load("//tools/build_defs:eclipse.bzl", "eclipse_plugin") eclipse_plugin( name = "com.google.devtools.bazel.e4b", srcs = glob(["src/**/*.java"]), + activator = "com.google.devtools.bazel.e4b.Activator", bundle_name = "Eclipse 4 Bazel", resources = glob(["resources/**"]), - version = "0.0.3.qualifier", vendor = "The Bazel Authors", - activator = "com.google.devtools.bazel.e4b.Activator", + version = "0.0.3.qualifier", + visibility = ["//visibility:public"], deps = [ "//com.google.devtools.bazel.e4b/src/com/google/devtools/bazel/e4b/command", "@com_google_guava//jar",
diff --git a/tools/build_defs/BUILD b/tools/build_defs/BUILD index e69de29..07c8d68 100644 --- a/tools/build_defs/BUILD +++ b/tools/build_defs/BUILD
@@ -0,0 +1,7 @@ +package(default_visibility = ["//visibility:public"]) + +py_binary( + name = "feature_builder", + srcs = ["feature_builder.py"], + deps = ["@com_google_python_gflags//:gflags"], +)
diff --git a/tools/build_defs/eclipse_plugin.bzl b/tools/build_defs/eclipse.bzl similarity index 74% rename from tools/build_defs/eclipse_plugin.bzl rename to tools/build_defs/eclipse.bzl index 0170f14..dee905f 100644 --- a/tools/build_defs/eclipse_plugin.bzl +++ b/tools/build_defs/eclipse.bzl
@@ -97,7 +97,9 @@ "deps", "classpath_resources", "deploy_manifest_lines", + "visibility", "main_class"]} + visibility = kwargs["visibility"] if "visibility" in kwargs else None # Generate the .api_description to put in the final jar native.genrule( name = name + ".api_description", @@ -148,11 +150,64 @@ outs = ["%s_%s.jar" % (name, version)], cmd = "cp $< $@", output_to_bindir = 1, + visibility = visibility, ) -# TODO(dmarting): implement eclipse_feature. -# An eclipse feature is jar with only the feature.xml file in it. +def _eclipse_feature_impl(ctx): + feature_xml = ctx.new_file(ctx.outputs.out, ctx.label.name + ".xml") + ctx.action( + outputs = [feature_xml], + inputs = [ctx.file.license], + executable = ctx.executable._builder, + arguments = [ + "--output=" + feature_xml.path, + "--id=" + ctx.label.name, + "--label=" + ctx.attr.label, + "--version=" + ctx.attr.version, + "--provider=" + ctx.attr.provider, + "--url=" + ctx.attr.url, + "--description=" + ctx.attr.description, + "--copyright=" + ctx.attr.copyright, + "--license_url=" + ctx.attr.license_url, + "--license=" + ctx.file.license.path] + [ + "--site=%s=%s" % (site, ctx.attr.sites[site]) + for site in ctx.attr.sites] + [ + "--plugin=" + p.basename for p in ctx.files.plugins]) + ctx.action( + outputs = [ctx.outputs.out], + inputs = [feature_xml], + executable = ctx.executable._zipper, + arguments = ["c", + ctx.outputs.out.path, + "feature.xml=" + feature_xml.path], + ) + + +eclipse_feature = rule( + implementation=_eclipse_feature_impl, + attrs = { + "label": attr.string(mandatory=True), + "version": attr.string(mandatory=True), + "provider": attr.string(mandatory=True), + "description": attr.string(mandatory=True), + "url": attr.string(mandatory=True), + "copyright": attr.string(mandatory=True), + "license_url": attr.string(mandatory=True), + "license": attr.label(mandatory=True, allow_single_file=True), + "sites": attr.string_dict(), + # TODO(dmarting): restrict what can be passed to the plugins attribute. + "plugins": attr.label_list(), + "_zipper": attr.label(default=Label("@bazel_tools//tools/zip:zipper"), + executable=True, + cfg="host"), + "_builder": attr.label(default=Label("//tools/build_defs:feature_builder"), + executable=True, + cfg="host"), + }, + outputs = {"out": "%{name}_%{version}.jar"}) +"""Create an eclipse feature jar.""" + # TODO(dmarting): implement eclipse_p2updatesite. # An p2 site is a site which has the following layout:
diff --git a/tools/build_defs/feature_builder.py b/tools/build_defs/feature_builder.py new file mode 100644 index 0000000..0964ebc --- /dev/null +++ b/tools/build_defs/feature_builder.py
@@ -0,0 +1,111 @@ +# Copyright 2017 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. +"""This tool build feature.xml files describing an Eclipse feature.""" + +from xml.etree import ElementTree +from xml.dom import minidom +import gflags +import sys + +gflags.DEFINE_string("output", None, "The output file, mandatory") +gflags.MarkFlagAsRequired("output") + +gflags.DEFINE_string("id", None, "The feature ID, mandatory") +gflags.MarkFlagAsRequired("id") + +gflags.DEFINE_string( + "label", + None, + "The feature label (i.e. short description), mandatory") +gflags.MarkFlagAsRequired("label") + +gflags.DEFINE_string("version", None, "The feature version, mandatory") +gflags.MarkFlagAsRequired("version") + +gflags.DEFINE_string( + "provider", None, "The provider (i.e. the vendor) of the feature, mandatory") +gflags.MarkFlagAsRequired("provider") + +gflags.DEFINE_string( + "url", None, "A URL associated to the description, optional") + +gflags.DEFINE_string( + "description", None, "Description of the feature, mandatory") +gflags.MarkFlagAsRequired("description") + +gflags.DEFINE_string( + "copyright", None, "Copyright line for the repository, mandatory") +gflags.MarkFlagAsRequired("copyright") + +gflags.DEFINE_string( + "license_url", None, "URL pointing to the license, mandatory") +gflags.MarkFlagAsRequired("license_url") + +gflags.DEFINE_string( + "license", None, "Text file of the license of the feature, mandatory") +gflags.MarkFlagAsRequired("license") + +gflags.DEFINE_multistring( + "site", [], "Sites related to the plugin, in the form `label=url`") +gflags.DEFINE_multistring( + "plugin", [], "List of plugins that this feature contains (filename).") + +FLAGS=gflags.FLAGS + +def _plugins(parent, plugins): + for plugin in plugins: + if plugin.endswith(".jar"): + id, version = plugin[:-4].split("_", 1) + p = ElementTree.SubElement(parent, "plugin") + p.set("id", id) + p.set("download-size", "0") + p.set("install-size", "0") + p.set("version", version) + + +def _sites(parent, sites): + for site in sites: + label, url = site.split("=", 1) + p = ElementTree.SubElement(parent, "discovery") + p.set("label", label) + p.set("url", url) + + +def main(unused_argv): + feature = ElementTree.Element("feature") + feature.set("id", FLAGS.id) + feature.set("label", FLAGS.label) + feature.set("version", FLAGS.version) + feature.set("provider-name", FLAGS.provider) + description = ElementTree.SubElement(feature, "description") + if FLAGS.url: + description.set("url", FLAGS.url) + description.text = FLAGS.description + copyright = ElementTree.SubElement(feature, "copyright") + copyright.text = FLAGS.copyright + license = ElementTree.SubElement(feature, "license") + license.set("url", FLAGS.license_url) + with open(FLAGS.license, "r") as f: + license.text = f.read() + _sites(ElementTree.SubElement(feature, "url"), FLAGS.site) + _plugins(feature, FLAGS.plugin) + + # Pretty print the resulting tree + output = ElementTree.tostring(feature, 'utf-8') + reparsed = minidom.parseString(output) + with open(FLAGS.output, "w") as f: + f.write(reparsed.toprettyxml(indent=" ")) + +if __name__ == "__main__": + main(FLAGS(sys.argv))