306 lines
		
	
	
		
			9.5 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			306 lines
		
	
	
		
			9.5 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
#!/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'
 | 
						|
GWT = '//gerrit-gwtui:ui_module'
 | 
						|
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',
 | 
						|
  GWT: '//tools/eclipse:gwt_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')
 | 
						|
args, _ = opts.parse_args()
 | 
						|
 | 
						|
batch_option = '--batch' if args.batch else None
 | 
						|
 | 
						|
def _build_bazel_cmd(*args):
 | 
						|
  cmd = ['bazel']
 | 
						|
  if batch_option:
 | 
						|
    cmd.append('--batch')
 | 
						|
  for arg in args:
 | 
						|
    cmd.append(arg)
 | 
						|
  return cmd
 | 
						|
 | 
						|
def retrieve_ext_location():
 | 
						|
  return check_output(_build_bazel_cmd('info', 'output_base')).strip()
 | 
						|
 | 
						|
def gen_bazel_path():
 | 
						|
  bazel = check_output(['which', 'bazel']).strip().decode('UTF-8')
 | 
						|
  with open(path.join(ROOT, ".bazel_path"), 'w') as fd:
 | 
						|
    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"/>"""
 | 
						|
    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')
 | 
						|
    doc.documentElement.appendChild(e)
 | 
						|
 | 
						|
  doc = make_classpath()
 | 
						|
  src = set()
 | 
						|
  lib = set()
 | 
						|
  proto = set()
 | 
						|
  gwt_src = set()
 | 
						|
  gwt_lib = 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'):
 | 
						|
      # gwt_module() depends on -src.jar for Java to JavaScript compiles.
 | 
						|
      if p.startswith("external"):
 | 
						|
        p = path.join(ext, p)
 | 
						|
      gwt_lib.add(p)
 | 
						|
      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)
 | 
						|
 | 
						|
  for p in _query_classpath(GWT):
 | 
						|
    m = java_library.match(p)
 | 
						|
    if m:
 | 
						|
      gwt_src.add(m.group(1))
 | 
						|
 | 
						|
  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, gwt_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:
 | 
						|
        # Filter out the source JARs that we pull through transitive closure of
 | 
						|
        # GWT plugin API (we add source directories themself).  Exception is
 | 
						|
        # libEdit-src.jar, that is needed for GWT SDM to work.
 | 
						|
        m = java_library.match(j)
 | 
						|
        if m:
 | 
						|
          if m.group(1).startswith("gerrit-") and \
 | 
						|
              j.endswith("-src.jar") and \
 | 
						|
              not j.endswith("libEdit-src.jar"):
 | 
						|
            continue
 | 
						|
        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)
 | 
						|
 | 
						|
  for s in sorted(gwt_src):
 | 
						|
    p = path.join(ROOT, s, 'src', 'main', 'java')
 | 
						|
    if path.exists(p):
 | 
						|
      classpathentry('lib', p, out='eclipse-out/gwtsrc')
 | 
						|
 | 
						|
  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()
 | 
						|
 | 
						|
  # TODO(davido): Remove this when GWT gone
 | 
						|
  gwt_working_dir = ".gwt_work_dir"
 | 
						|
  if not path.isdir(gwt_working_dir):
 | 
						|
    makedirs(path.join(ROOT, gwt_working_dir))
 | 
						|
 | 
						|
  try:
 | 
						|
    check_call(_build_bazel_cmd('build', MAIN, GWT, '//java/org/eclipse/jgit:libEdit-src.jar'))
 | 
						|
  except CalledProcessError:
 | 
						|
    exit(1)
 | 
						|
except KeyboardInterrupt:
 | 
						|
  print('Interrupted by user', file=sys.stderr)
 | 
						|
  exit(1)
 |