Last active
February 10, 2023 01:39
-
-
Save wolfgangmeyers/49d8edaa763f5fcdcdf7 to your computer and use it in GitHub Desktop.
Eclipse setup script for bazel
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
java_binary( | |
name = "annotation_processors_ide", | |
create_executable = False, | |
runtime_deps = [ | |
// annotation processor dependencies here | |
], | |
) | |
java_binary( | |
name = "project_deps", | |
create_executable = 0, | |
runtime_deps = [ | |
// build and test dependencies here | |
], | |
) | |
# This rule creates a copy of the project_deps_deploy.jar with all of the | |
# project code removed. This is to avoid having duplicate instances | |
# of project classes on the eclipse build path. | |
genrule( | |
name = "eclipse_deps", | |
srcs = ["//src/main/java/eclipse:project_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 <project code base package>", | |
// add additional lines if you need to remove other artifacts | |
// from the output jar file. | |
"jar -cmf META-INF/MANIFEST.MF eclipse_deps.jar .", | |
"mv eclipse_deps.jar $$OUT", | |
"rm -rf $$TMP", | |
]), | |
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
"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": "src/main/java"}, | |
{"kind": "src", "path": "src/test/java"}, | |
{"kind": "src", "path": "bazel-genfiles/java"}, | |
{ | |
"kind": "lib", | |
"path": ("%s/src/main/java/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, | |
"src/main/java/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", | |
"//src/main/java/...", | |
"//src/test/java/..."]) | |
# Builds a giant jar of all compile-time dependencies of the project | |
subprocess.check_call([ | |
"bazel", | |
"build", | |
"//src/main/java/eclipse:eclipse_deps", | |
]) | |
# Builds a jar with all annotation processors | |
subprocess.check_call([ | |
"bazel", | |
"build", | |
"//src/main/java/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. | |
""" | |
if len(sys.argv) < 2: | |
print "Usage: setup_eclipse.py <project name>" | |
sys.exit(1) | |
project_name = sys.argv[1] | |
build_dependencies() | |
workspace_directory = bazel_info("workspace") | |
classpath = build_classpath() | |
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() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment