google-nomulus/scripts/setup_eclipse.py
Michael Muller c458c05801 Rename Java packages to use the .google TLD
The dark lord Gosling designed the Java package naming system so that
ownership flows from the DNS system. Since we own the domain name
registry.google, it seems only appropriate that we should use
google.registry as our package name.
2016-05-13 20:04:42 -04:00

303 lines
9 KiB
Python

#!/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 "<classpathentry kind=\"{kind}\" path=\"{path}\"/>".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 ('<?xml version="1.0" encoding="UTF-8"?>\n'
"<classpath>\n"
"{entries}"
"\n</classpath>").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/google/"
"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 = """<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>{project_name}</name>
<comment>
</comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.python.pydev.PyDevBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.python.pydev.pythonNature</nature>
</natures>
</projectDescription>"""
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 ("<factorypathentry kind=\"{kind}\" id=\"{entry_id}\" "
"enabled=\"true\" runInBatchMode=\"false\"/>").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 ("<factorypath>\n"
"{entries}"
"\n</factorypath>").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/google/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/google/registry/...",
"//javatests/google/registry/..."])
# Builds a giant jar of all compile-time dependencies of the project
subprocess.check_call([
"bazel",
"build",
"//java/google/registry/eclipse:eclipse_deps",
])
# Builds a jar with all annotation processors
subprocess.check_call([
"bazel",
"build",
"//java/google/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()