diff --git a/.gitignore b/.gitignore index 45dcb048f..64fc08d9a 100644 --- a/.gitignore +++ b/.gitignore @@ -68,3 +68,11 @@ local.properties # Code Recommenders .recommenders/ + +# Auto-generated java files +autogenerated/ + +###################################################################### +# Python Ignores + +*.pyc diff --git a/java/com/google/domain/registry/eclipse/BUILD b/java/com/google/domain/registry/eclipse/BUILD new file mode 100644 index 000000000..c4d999b77 --- /dev/null +++ b/java/com/google/domain/registry/eclipse/BUILD @@ -0,0 +1,59 @@ +package( + default_visibility = ["//java/com/google/domain/registry:registry_project"], +) + +java_binary( + name = "annotation_processors_ide", + create_executable = False, + runtime_deps = [ + "@auto_factory//jar", + "@auto_service//jar", + "@auto_value//jar", + "@javawriter//jar", + "//third_party/java/dagger:dagger-compiler", + ], +) + +java_binary( + name = "registry_deps", + create_executable = 0, + runtime_deps = [ + "//java/com/google/common/testing", + "//java/com/google/domain/registry/module/frontend", + "//java/com/google/domain/registry/module/backend", + "//java/com/google/domain/registry/module/tools", + "//java/com/google/domain/registry/tools", + "//third_party/java/appengine:appengine-api-link", + "//third_party/java/appengine:appengine-remote-api-link", + "//third_party/java/appengine:appengine-stubs", + "//third_party/java/appengine:appengine-integration-testing", + "//third_party/java/appengine:appengine-testing", + "//third_party/java/apache_sshd", + "//third_party/java/ftpserver", + "//third_party/java/hamcrest", + "//third_party/java/jetty/v6_1_22", + "//third_party/java/junit", + "//third_party/java/mockito", + "//third_party/java/truth", + ], +) + +# This rule creates a copy of the registry_deps_deploy.jar with all of the +# domain-registry code removed. This is to avoid having duplicate instances +# of domain-registry classes on the eclipse build path. +genrule( + name = "eclipse_deps", + srcs = ["//java/com/google/domain/registry/eclipse:registry_deps_deploy.jar"], + outs = ["eclipse_deps.jar"], + cmd = " && ".join([ + "IN=$$(pwd)/$(SRCS)", + "OUT=$$(pwd)/$@", + "TMP=$$(mktemp -d $${TMPDIR:-/tmp}/eclipse_deps.XXXXXXXX)", + "cd $$TMP", + "jar -xf $$IN", + "rm -rf com/google/domain/registry", + "jar -cmf META-INF/MANIFEST.MF eclipse_deps.jar .", + "mv eclipse_deps.jar $$OUT", + "rm -rf $$TMP", + ]), +) diff --git a/java/com/google/domain/registry/tools/BUILD b/java/com/google/domain/registry/tools/BUILD index 220bfcec6..d48a53a83 100644 --- a/java/com/google/domain/registry/tools/BUILD +++ b/java/com/google/domain/registry/tools/BUILD @@ -11,6 +11,7 @@ package_group( packages = [ "//java/com/google/domain/registry/testing", "//java/com/google/domain/registry/tools", + "//java/com/google/domain/registry/eclipse", "//javatests/com/google/domain/registry/tools", ], ) diff --git a/scripts/setup_eclipse.py b/scripts/setup_eclipse.py new file mode 100644 index 000000000..7f0ed8819 --- /dev/null +++ b/scripts/setup_eclipse.py @@ -0,0 +1,303 @@ +#!/usr/bin/python + +# Copyright 2016 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. + +"Script for generating eclipse .project and .classpath files." + +import os +import subprocess +import sys + + +def bazel_info(key): + """Invokes the bazel info subcommand. + + Invokes bazel info on the command line, parses the output and returns it + + Args: + key: The argument that is passed to bazel info. See + http://bazel.io/docs/bazel-user-manual.html#info for example values. + + Returns: + The output of the bazel info invocation as a string. If multiple lines + are returned by bazel info, only the first line is returned. + """ + bazel_process = subprocess.Popen( + ["bazel", "info", key], + stdout=subprocess.PIPE, + ) + result = [line.strip() for line in iter(bazel_process.stdout.readline, "")] + return result[0] + + +def classpath_entry_xml(kind, path): + """ + Generates an eclipse xml classpath entry. + + Args: + kind: Kind of classpath entry. + Example values are 'lib', 'src', and 'con' + path: Absolute or relative path to the referenced resource. + Paths that are not absolute are relative to the project root. + + Returns: + xml classpath entry element with the specified kind and path. + """ + return "".format( + kind=kind, path=path, + ) + + +def classpath_xml(entries): + """ + Produces the xml for an eclipse classpath file. + + Args: + entries: list of dictionaries in the form of: + { + "kind": (str), + "path": (str) + } + + Returns: + Contents of the eclipse .classpath file. + """ + entries_xml = "\n".join([ + " " + classpath_entry_xml(**entry) for entry in entries]) + return ('\n' + "\n" + "{entries}" + "\n").format(entries=entries_xml) + + +def build_classpath(): + """ + Builds eclipse classpath file + + Generates an eclipse .classpath file that has references to all of the + project source folders, autogenerated source code, and external binary + dependencies. + + Returns: + Contents of the eclipse .classpath file. + """ + # source folder for autogenerated files must reference + # symlinked bazel-genfiles folder inside of the project. + bazel_genfiles = bazel_info("bazel-genfiles") + classpath_entries = [ + {"kind": "con", "path": "org.eclipse.jdt.launching.JRE_CONTAINER"}, + {"kind": "src", "path": "java"}, + {"kind": "src", "path": "javatests"}, + {"kind": "src", "path": "bazel-genfiles/java"}, + { + "kind": "lib", + "path": ("%s/java/com/google/domain/" + "registry/eclipse/eclipse_deps.jar" % bazel_genfiles) + }, + {"kind": "output", "path": "bin"}, + ] + + return classpath_xml(classpath_entries) + + +def build_project(project_name): + """ + Builds eclipse project file + + Uses a very simple template to generate an eclipse .project file + with a configurable project name. + + Args: + project_name: Name of the eclipse project. When importing the project + into an eclipse workspace, this is the name that will be shown. + Returns: + Contents of the eclipse .project file. + """ + template = """ + + {project_name} + + + + + + + org.python.pydev.PyDevBuilder + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + org.python.pydev.pythonNature + +""" + return template.format(project_name=project_name) + + +def factorypath_entry_xml(kind, entry_id): + """ + Generates an eclipse xml factorypath entry. + + Args: + kind: Kind of factorypath entry. + Example values are 'PLUGIN', 'WKSPJAR' + entry_id: Unique identifier for the factorypath entry + + Returns: + xml factorypath entry element with the specified kind and id. + """ + return ("").format( + kind=kind, entry_id=entry_id) + +def factorypath_xml(entries): + """ + Produces the xml for an eclipse factorypath file. + + Args: + entries: list of dictionaries in the form of: + { + "kind": (str), + "entry_id": (str) + } + + Returns: + Contents of the eclipse .factorypath file. + """ + entries_xml = "\n".join([ + " " + factorypath_entry_xml(**entry) for entry in entries]) + return ("\n" + "{entries}" + "\n").format(entries=entries_xml) + + +def build_factorypath(): + """ + Builds eclipse factorypath file + + Generates an eclipse .factorypath file that links to the jar containing + all required annotation processors for the project. + + Returns: + Contents of the eclipse .factorypath file. + """ + bazel_bin = bazel_info("bazel-bin") + annotations_jar = os.path.join( + bazel_bin, + "java/com/google/domain/registry/eclipse" + "/annotation_processors_ide_deploy.jar", + ) + factorypath_entries = [ + { + "kind": "PLUGIN", + "entry_id": "org.eclipse.jst.ws.annotations.core", + }, + { + "kind": "EXTJAR", + "entry_id": annotations_jar, + } + ] + return factorypath_xml(factorypath_entries) + + +def build_dependencies(): + """ + Builds dependencies for producing eclipse project files + + Runs bazel build for the entire project and builds a single jar with all + binary dependencies for eclipse to compile the project. + + Raises: + subprocess.CalledProcessError: A bazel build failed + """ + # Build entire project first + subprocess.check_call([ + "bazel", + "build", + "//java/com/google/domain/registry/...", + "//javatests/com/google/domain/registry/..."]) + + # Builds a giant jar of all compile-time dependencies of the project + subprocess.check_call([ + "bazel", + "build", + "//java/com/google/domain/registry/eclipse:eclipse_deps", + ]) + + # Builds a jar with all annotation processors + subprocess.check_call([ + "bazel", + "build", + "//java/com/google/domain/registry/eclipse" + ":annotation_processors_ide_deploy.jar" + ]) + +def main(): + """ + Builds eclipse project files + + Before building the eclipse files, a working bazel build is required. + After building the eclipse dependencies jar and the tests, eclipse + project files are produced. + """ + build_dependencies() + workspace_directory = bazel_info("workspace") + classpath = build_classpath() + with open(os.path.join( + workspace_directory, ".classpath"), "w") as classpath_file: + classpath_file.write(classpath) + if len(sys.argv) > 1: + project_name = sys.argv[1] + else: + project_name = "domain-registry" + project = build_project(project_name) + with open(os.path.join(workspace_directory, ".project"), + "w") as project_file: + project_file.write(project) + factorypath = build_factorypath() + with open(os.path.join(workspace_directory, ".factorypath"), + "w") as factorypath_file: + factorypath_file.write(factorypath) + if not os.path.exists(".settings"): + os.makedirs(".settings") + # XXX: Avoid wiping out existing settings from org.eclipse.jdt.core.prefs + with open(os.path.join( + workspace_directory, + ".settings", + "org.eclipse.jdt.core.prefs"), "w") as prefs_file: + prefs_file.write("\n".join([ + "eclipse.preferences.version=1", + "org.eclipse.jdt.core.compiler.processAnnotations=enabled", + ])) + with open(os.path.join( + workspace_directory, + ".settings", + "org.eclipse.jdt.apt.core.prefs"), "w") as prefs_file: + prefs_file.write("\n".join([ + "eclipse.preferences.version=1", + "org.eclipse.jdt.apt.aptEnabled=true", + "org.eclipse.jdt.apt.genSrcDir=autogenerated", + "org.eclipse.jdt.apt.reconcileEnabled=true", + ])) + + +if __name__ == "__main__": + main() diff --git a/third_party/java/dagger/BUILD b/third_party/java/dagger/BUILD index 518e4bce4..443f32c8b 100644 --- a/third_party/java/dagger/BUILD +++ b/third_party/java/dagger/BUILD @@ -27,6 +27,7 @@ java_library( java_library( name = "dagger-compiler", exports = ["@dagger_compiler//jar"], + visibility = ["//visibility:public"], runtime_deps = [ "@gson//jar", "@guava//jar",