| #!/usr/bin/env python | 
 | # Copyright (C) 2016 The Android Open Source Project | 
 | # | 
 | # 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. | 
 | # | 
 |  | 
 | from __future__ import print_function | 
 | # TODO(davido): use Google style for importing instead: | 
 | # import optparse | 
 | # ... | 
 | # optparse.OptionParser | 
 | from optparse import OptionParser | 
 | from os import environ, path, makedirs | 
 | from subprocess import CalledProcessError, check_call, check_output | 
 | from xml.dom import minidom | 
 | import re | 
 | import sys | 
 |  | 
 | MAIN = '//tools/eclipse:classpath' | 
 | AUTO = '//lib/auto:auto-value' | 
 | JRE = '/'.join([ | 
 |     'org.eclipse.jdt.launching.JRE_CONTAINER', | 
 |     'org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType', | 
 |     'JavaSE-1.8', | 
 | ]) | 
 | # Map of targets to corresponding classpath collector rules | 
 | cp_targets = { | 
 |     AUTO: '//tools/eclipse:autovalue_classpath_collect', | 
 |     MAIN: '//tools/eclipse:main_classpath_collect', | 
 | } | 
 |  | 
 | ROOT = path.abspath(__file__) | 
 | while not path.exists(path.join(ROOT, 'WORKSPACE')): | 
 |     ROOT = path.dirname(ROOT) | 
 |  | 
 | opts = OptionParser() | 
 | opts.add_option('--plugins', help='create eclipse projects for plugins', | 
 |                 action='store_true') | 
 | opts.add_option('--name', help='name of the generated project', | 
 |                 action='store', default='gerrit', dest='project_name') | 
 | opts.add_option('-b', '--batch', action='store_true', | 
 |                 dest='batch', help='Bazel batch option') | 
 | opts.add_option('-j', '--java', action='store', | 
 |                 dest='java', help='Post Java 8 support (9)') | 
 | opts.add_option('-e', '--edge_java', action='store', | 
 |                 dest='edge_java', help='Post Java 9 support (10|11|...)') | 
 | args, _ = opts.parse_args() | 
 |  | 
 | batch_option = '--batch' if args.batch else None | 
 | custom_java = args.java | 
 | edge_java = args.edge_java | 
 |  | 
 | def _build_bazel_cmd(*args): | 
 |     build = False | 
 |     cmd = ['bazel'] | 
 |     if batch_option: | 
 |         cmd.append('--batch') | 
 |     for arg in args: | 
 |         if arg == "build": | 
 |             build = True | 
 |         cmd.append(arg) | 
 |     if custom_java and not edge_java: | 
 |         cmd.append('--host_java_toolchain=@bazel_tools//tools/jdk:toolchain_java%s' % custom_java) | 
 |         cmd.append('--java_toolchain=@bazel_tools//tools/jdk:toolchain_java%s' % custom_java) | 
 |         if edge_java and build: | 
 |             cmd.append(edge_java) | 
 |     return cmd | 
 |  | 
 |  | 
 | def retrieve_ext_location(): | 
 |     return check_output(_build_bazel_cmd('info', 'output_base')).strip() | 
 |  | 
 |  | 
 | def gen_bazel_path(ext_location): | 
 |     bazel = check_output(['which', 'bazel']).strip().decode('UTF-8') | 
 |     with open(path.join(ROOT, ".bazel_path"), 'w') as fd: | 
 |         fd.write("output_base=%s\n" % ext_location) | 
 |         fd.write("bazel=%s\n" % bazel) | 
 |         fd.write("PATH=%s\n" % environ["PATH"]) | 
 |  | 
 |  | 
 | def _query_classpath(target): | 
 |     deps = [] | 
 |     t = cp_targets[target] | 
 |     try: | 
 |         check_call(_build_bazel_cmd('build', t)) | 
 |     except CalledProcessError: | 
 |         exit(1) | 
 |     name = 'bazel-bin/tools/eclipse/' + t.split(':')[1] + '.runtime_classpath' | 
 |     deps = [line.rstrip('\n') for line in open(name)] | 
 |     return deps | 
 |  | 
 |  | 
 | def gen_project(name='gerrit', root=ROOT): | 
 |     p = path.join(root, '.project') | 
 |     with open(p, 'w') as fd: | 
 |         print("""\ | 
 | <?xml version="1.0" encoding="UTF-8"?> | 
 | <projectDescription> | 
 |   <name>%(name)s</name> | 
 |   <buildSpec> | 
 |     <buildCommand> | 
 |       <name>org.eclipse.jdt.core.javabuilder</name> | 
 |     </buildCommand> | 
 |   </buildSpec> | 
 |   <natures> | 
 |     <nature>org.eclipse.jdt.core.javanature</nature> | 
 |   </natures> | 
 | </projectDescription>\ | 
 |     """ % {"name": name}, file=fd) | 
 |  | 
 |  | 
 | def gen_plugin_classpath(root): | 
 |     p = path.join(root, '.classpath') | 
 |     with open(p, 'w') as fd: | 
 |         if path.exists(path.join(root, 'src', 'test', 'java')): | 
 |             testpath = """ | 
 |   <classpathentry excluding="**/BUILD" kind="src" path="src/test/java"\ | 
 |  out="eclipse-out/test"> | 
 |     <attributes><attribute name="test" value="true"/></attributes> | 
 |   </classpathentry>""" | 
 |         else: | 
 |             testpath = "" | 
 |         print("""\ | 
 | <?xml version="1.0" encoding="UTF-8"?> | 
 | <classpath> | 
 |   <classpathentry excluding="**/BUILD" kind="src" path="src/main/java"/>%(testpath)s | 
 |   <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> | 
 |   <classpathentry combineaccessrules="false" kind="src" path="/gerrit"/> | 
 |   <classpathentry kind="output" path="eclipse-out/classes"/> | 
 | </classpath>""" % {"testpath": testpath}, file=fd) | 
 |  | 
 |  | 
 | def gen_classpath(ext): | 
 |     def make_classpath(): | 
 |         impl = minidom.getDOMImplementation() | 
 |         return impl.createDocument(None, 'classpath', None) | 
 |  | 
 |     def classpathentry(kind, path, src=None, out=None, exported=None): | 
 |         e = doc.createElement('classpathentry') | 
 |         e.setAttribute('kind', kind) | 
 |         # TODO(davido): Remove this and other exclude BUILD files hack | 
 |         # when this Bazel bug is fixed: | 
 |         # https://github.com/bazelbuild/bazel/issues/1083 | 
 |         if kind == 'src': | 
 |             e.setAttribute('excluding', '**/BUILD') | 
 |         e.setAttribute('path', path) | 
 |         if src: | 
 |             e.setAttribute('sourcepath', src) | 
 |         if out: | 
 |             e.setAttribute('output', out) | 
 |         if exported: | 
 |             e.setAttribute('exported', 'true') | 
 |         if out and "test" in out: | 
 |             atts = doc.createElement('attributes') | 
 |             testAtt = doc.createElement('attribute') | 
 |             testAtt.setAttribute('name', 'test') | 
 |             testAtt.setAttribute('value', 'true') | 
 |             atts.appendChild(testAtt) | 
 |             e.appendChild(atts) | 
 |         doc.documentElement.appendChild(e) | 
 |  | 
 |     doc = make_classpath() | 
 |     src = set() | 
 |     lib = set() | 
 |     proto = set() | 
 |     plugins = set() | 
 |  | 
 |     # Classpath entries are absolute for cross-cell support | 
 |     java_library = re.compile('bazel-out/.*?-fastbuild/bin/(.*)/[^/]+[.]jar$') | 
 |     srcs = re.compile('(.*/external/[^/]+)/jar/(.*)[.]jar') | 
 |     for p in _query_classpath(MAIN): | 
 |         if p.endswith('-src.jar'): | 
 |             continue | 
 |  | 
 |         m = java_library.match(p) | 
 |         if m: | 
 |             src.add(m.group(1)) | 
 |             # Exceptions: both source and lib | 
 |             if p.endswith('libquery_parser.jar') or \ | 
 |                p.endswith('libgerrit-prolog-common.jar'): | 
 |                 lib.add(p) | 
 |             # JGit dependency from external repository | 
 |             if 'gerrit-' not in p and 'jgit' in p: | 
 |                 lib.add(p) | 
 |             # Assume any jars in /proto/ are from java_proto_library rules | 
 |             if '/bin/proto/' in p: | 
 |                 proto.add(p) | 
 |         else: | 
 |             # Don't mess up with Bazel internal test runner dependencies. | 
 |             # When we use Eclipse we rely on it for running the tests | 
 |             if p.endswith( | 
 |                "external/bazel_tools/tools/jdk/TestRunner_deploy.jar"): | 
 |                 continue | 
 |             if p.startswith("external"): | 
 |                 p = path.join(ext, p) | 
 |             lib.add(p) | 
 |  | 
 |     classpathentry('src', 'java') | 
 |     classpathentry('src', 'javatests', out='eclipse-out/test') | 
 |     classpathentry('src', 'resources') | 
 |     for s in sorted(src): | 
 |         out = None | 
 |  | 
 |         if s.startswith('lib/'): | 
 |             out = 'eclipse-out/lib' | 
 |         elif s.startswith('plugins/'): | 
 |             if args.plugins: | 
 |                 plugins.add(s) | 
 |                 continue | 
 |             out = 'eclipse-out/' + s | 
 |  | 
 |         p = path.join(s, 'java') | 
 |         if path.exists(p): | 
 |             classpathentry('src', p, out=out) | 
 |             continue | 
 |  | 
 |         for env in ['main', 'test']: | 
 |             o = None | 
 |             if out: | 
 |                 o = out + '/' + env | 
 |             elif env == 'test': | 
 |                 o = 'eclipse-out/test' | 
 |  | 
 |             for srctype in ['java', 'resources']: | 
 |                 p = path.join(s, 'src', env, srctype) | 
 |                 if path.exists(p): | 
 |                     classpathentry('src', p, out=o) | 
 |  | 
 |     for libs in [lib]: | 
 |         for j in sorted(libs): | 
 |             s = None | 
 |             m = srcs.match(j) | 
 |             if m: | 
 |                 prefix = m.group(1) | 
 |                 suffix = m.group(2) | 
 |                 p = path.join(prefix, "jar", "%s-src.jar" % suffix) | 
 |                 if path.exists(p): | 
 |                     s = p | 
 |             if args.plugins: | 
 |                 classpathentry('lib', j, s, exported=True) | 
 |             else: | 
 |                 classpathentry('lib', j, s) | 
 |  | 
 |     for p in sorted(proto): | 
 |         s = p.replace('-fastbuild/bin/proto/lib', '-fastbuild/genfiles/proto/') | 
 |         s = s.replace('.jar', '-src.jar') | 
 |         classpathentry('lib', p, s) | 
 |  | 
 |     classpathentry('con', JRE) | 
 |     classpathentry('output', 'eclipse-out/classes') | 
 |  | 
 |     p = path.join(ROOT, '.classpath') | 
 |     with open(p, 'w') as fd: | 
 |         doc.writexml(fd, addindent='\t', newl='\n', encoding='UTF-8') | 
 |  | 
 |     if args.plugins: | 
 |         for plugin in plugins: | 
 |             plugindir = path.join(ROOT, plugin) | 
 |             try: | 
 |                 gen_project(plugin.replace('plugins/', ""), plugindir) | 
 |                 gen_plugin_classpath(plugindir) | 
 |             except (IOError, OSError) as err: | 
 |                 print('error generating project for %s: %s' % (plugin, err), | 
 |                       file=sys.stderr) | 
 |  | 
 |  | 
 | def gen_factorypath(ext): | 
 |     doc = minidom.getDOMImplementation().createDocument(None, 'factorypath', | 
 |                                                         None) | 
 |     for jar in _query_classpath(AUTO): | 
 |         e = doc.createElement('factorypathentry') | 
 |         e.setAttribute('kind', 'EXTJAR') | 
 |         e.setAttribute('id', path.join(ext, jar)) | 
 |         e.setAttribute('enabled', 'true') | 
 |         e.setAttribute('runInBatchMode', 'false') | 
 |         doc.documentElement.appendChild(e) | 
 |  | 
 |     p = path.join(ROOT, '.factorypath') | 
 |     with open(p, 'w') as fd: | 
 |         doc.writexml(fd, addindent='\t', newl='\n', encoding='UTF-8') | 
 |  | 
 |  | 
 | try: | 
 |     ext_location = retrieve_ext_location().decode("utf-8") | 
 |     gen_project(args.project_name) | 
 |     gen_classpath(ext_location) | 
 |     gen_factorypath(ext_location) | 
 |     gen_bazel_path(ext_location) | 
 |  | 
 |     try: | 
 |         check_call(_build_bazel_cmd('build', MAIN)) | 
 |     except CalledProcessError: | 
 |         exit(1) | 
 | except KeyboardInterrupt: | 
 |     print('Interrupted by user', file=sys.stderr) | 
 |     exit(1) |