-
Notifications
You must be signed in to change notification settings - Fork 302
Eclipse file generation script #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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", | ||
| ]), | ||
| ) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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): | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You don't have to bother making this change, since you wrote such good documentation. But in the future, you probably could have made a lot of these methods private (prefix underscore) and then the pydocs wouldn't be required.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I had the same thought :) |
||
| """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], | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Optional] Here's a purely stylistic thing you may not have considered, which you are 100% free to ignore. A generic method could be created from this defenition: |
||
| 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"}, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How about bazel-genfiles/javatests?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good question. I don't think there are any generated files in javatests that we need here. Those that are generated are produced by the annotation processors - would you prefer it is added here just for completeness?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure why not? It's better than having us start generating stuff under javatests down the road, and then having to spend two hours figuring out why it doesn't show up in Eclipse. |
||
| { | ||
| "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 = """<?xml version="1.0" encoding="UTF-8"?> | ||
| <projectDescription> | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It would be super cool if this could generate the config that puts AutoValue, Dagger, and AutoFactory into the annotation processor project settings config. |
||
| <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/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() | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah yes testing dependencies. Makes sense that you'd need them here.