Initial revision
Change-Id: I51b57261d8076c36ca3b85ec002129bdc1eccf9a
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..0d20b64
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+*.pyc
diff --git a/java7.bucklet b/java7.bucklet
new file mode 100644
index 0000000..488fba4
--- /dev/null
+++ b/java7.bucklet
@@ -0,0 +1,52 @@
+# see https://github.com/facebook/buck/pull/67
+original_java_library = java_library
+def java_library(
+ name,
+ srcs=[],
+ resources=[],
+ source='7',
+ target='7',
+ proguard_config=None,
+ deps=[],
+ exported_deps=[],
+ visibility=[],
+ ):
+ original_java_library(
+ name=name,
+ srcs=srcs,
+ resources=resources,
+ source=source,
+ target=target,
+ proguard_config=proguard_config,
+ deps=deps,
+ exported_deps=exported_deps,
+ visibility=visibility,
+ )
+
+original_java_test = java_test
+def java_test(
+ name,
+ srcs=[],
+ labels=[],
+ resources=[],
+ source='7',
+ target='7',
+ vm_args=[],
+ source_under_test=[],
+ contacts=[],
+ deps=[],
+ visibility=[],
+ ):
+ original_java_test(
+ name=name,
+ srcs=srcs,
+ labels=labels,
+ resources=resources,
+ source=source,
+ target=target,
+ vm_args=vm_args,
+ source_under_test=source_under_test,
+ contacts=contacts,
+ deps=deps,
+ visibility=visibility,
+ )
diff --git a/java8.bucklet b/java8.bucklet
new file mode 100644
index 0000000..1fb22aa
--- /dev/null
+++ b/java8.bucklet
@@ -0,0 +1,52 @@
+# see https://github.com/facebook/buck/pull/67
+original_java_library = java_library
+def java_library(
+ name,
+ srcs=[],
+ resources=[],
+ source='8',
+ target='8',
+ proguard_config=None,
+ deps=[],
+ exported_deps=[],
+ visibility=[],
+ ):
+ original_java_library(
+ name=name,
+ srcs=srcs,
+ resources=resources,
+ source=source,
+ target=target,
+ proguard_config=proguard_config,
+ deps=deps,
+ exported_deps=exported_deps,
+ visibility=visibility,
+ )
+
+original_java_test = java_test
+def java_test(
+ name,
+ srcs=[],
+ labels=[],
+ resources=[],
+ source='8',
+ target='8',
+ vm_args=[],
+ source_under_test=[],
+ contacts=[],
+ deps=[],
+ visibility=[],
+ ):
+ original_java_test(
+ name=name,
+ srcs=srcs,
+ labels=labels,
+ resources=resources,
+ source=source,
+ target=target,
+ vm_args=vm_args,
+ source_under_test=source_under_test,
+ contacts=contacts,
+ deps=deps,
+ visibility=visibility,
+ )
diff --git a/java_doc.bucklet b/java_doc.bucklet
new file mode 100644
index 0000000..8df3f85
--- /dev/null
+++ b/java_doc.bucklet
@@ -0,0 +1,32 @@
+def java_doc(
+ name,
+ title,
+ pkg,
+ paths,
+ srcs = [],
+ deps = [],
+ visibility = []
+ ):
+ genrule(
+ name = name,
+ cmd = ' '.join([
+ 'javadoc',
+ '-quiet',
+ '-protected',
+ '-encoding UTF-8',
+ '-charset UTF-8',
+ '-notimestamp',
+ '-windowtitle "' + title + '"',
+ '-link http://docs.oracle.com/javase/7/docs/api',
+ '-subpackages ' + pkg,
+ '-sourcepath ',
+ ':'.join([n for n in paths]),
+ ' -classpath ',
+ ':'.join(['$(location %s)' % n for n in deps]),
+ '-d $TMP',
+ ]) + ';jar cf $OUT -C $TMP .',
+ srcs = srcs,
+ deps = deps,
+ out = name + '.jar',
+ visibility = visibility,
+)
diff --git a/java_library2.bucklet b/java_library2.bucklet
new file mode 100644
index 0000000..8fe78e8
--- /dev/null
+++ b/java_library2.bucklet
@@ -0,0 +1,37 @@
+# Compiles a Java library with additional compile-time dependencies
+# that do not show up as transitive dependencies to java_library()
+# or java_binary() rule that depends on this library.
+# work around for: https://github.com/facebook/buck/issues/63
+def java_library2(
+ name,
+ srcs = [],
+ resources = [],
+ deps = [],
+ compile_deps = [],
+ visibility = []):
+ c = name + '__compile'
+ t = name + '__link'
+ j = 'lib__%s__output/%s.jar' % (c, c)
+ o = 'lib__%s__output/%s.jar' % (name, name)
+ java_library(
+ name = c,
+ srcs = srcs,
+ resources = resources,
+ deps = deps + compile_deps,
+ visibility = visibility,
+ )
+ # Break the dependency chain by passing the newly built
+ # JAR to consumers through a prebuilt_jar().
+ genrule(
+ name = t,
+ cmd = 'mkdir -p $(dirname $OUT);ln -s $SRCS $OUT',
+ srcs = [genfile(j)],
+ deps = [':' + c],
+ out = o,
+ )
+ prebuilt_jar(
+ name = name,
+ binary_jar = genfile(o),
+ deps = deps + [':' + t],
+ visibility = visibility,
+ )
diff --git a/java_sources.bucklet b/java_sources.bucklet
new file mode 100644
index 0000000..0b3974e
--- /dev/null
+++ b/java_sources.bucklet
@@ -0,0 +1,10 @@
+def java_sources(
+ name,
+ srcs,
+ visibility = []
+ ):
+ java_library(
+ name = name,
+ resources = srcs,
+ visibility = visibility,
+ )
diff --git a/local_jar.bucklet b/local_jar.bucklet
new file mode 100644
index 0000000..8131daa
--- /dev/null
+++ b/local_jar.bucklet
@@ -0,0 +1,50 @@
+#
+# If a dependent library is undergoing active development it must be
+# recompiled and the change must be reflected in the Buck build process. For
+# example testing Gerrit against changed JGit snapshot version. After building
+# JGit library, the artifacts are created in local Maven build directory.
+#
+# To shorten that workflow and take the installation of the artifacts to the
+# local Maven repository and fetching it again from there out of the picture,
+# `local_jar()` method is used:
+#
+# local_jar(
+# name = 'jgit',
+# jar = '/home/<user>/projects/jgit/org.eclipse.jgit/target/org.eclipse.jgit-3.3.0-SNAPSHOT.jar',
+# src = '/home/<user>/projects/jgit/org.eclipse.jgit/target/org.eclipse.jgit-3.3.0-SNAPSHOT-sources.jar',
+# deps = [':ewah']
+# )
+
+def local_jar(
+ name,
+ jar,
+ src = None,
+ deps = [],
+ visibility = ['PUBLIC']):
+ binjar = name + '.jar'
+ srcjar = name + '-src.jar'
+ genrule(
+ name = name + '__local_bin',
+ cmd = 'ln -s %s $OUT' % jar,
+ out = binjar)
+ if src:
+ genrule(
+ name = name + '__local_src',
+ cmd = 'ln -s %s $OUT' % src,
+ out = srcjar)
+ prebuilt_jar(
+ name = name + '_src',
+ deps = [':' + name + '__local_src'],
+ binary_jar = genfile(srcjar),
+ visibility = visibility,
+ )
+ else:
+ srcjar = None
+
+ prebuilt_jar(
+ name = name,
+ deps = deps + [':' + name + '__local_bin'],
+ binary_jar = genfile(binjar),
+ source_jar = genfile(srcjar) if srcjar else None,
+ visibility = visibility,
+ )
diff --git a/maven_jar.bucklet b/maven_jar.bucklet
new file mode 100644
index 0000000..19a06f9
--- /dev/null
+++ b/maven_jar.bucklet
@@ -0,0 +1,105 @@
+#
+# Fetch artifacts from Maven repository
+# see: https://github.com/facebook/buck/issues/64
+#
+
+GERRIT = 'GERRIT:'
+GERRIT_API = 'GERRIT_API:'
+ECLIPSE = 'ECLIPSE:'
+MAVEN_CENTRAL = 'MAVEN_CENTRAL:'
+MAVEN_LOCAL = 'MAVEN_LOCAL:'
+
+def maven_jar(
+ name,
+ id,
+ exclude = [],
+ exclude_java_sources = False,
+ unsign = False,
+ deps = [],
+ exported_deps = [],
+ sha1 = '', bin_sha1 = '', src_sha1 = '',
+ repository = MAVEN_CENTRAL,
+ attach_source = True,
+ visibility = ['PUBLIC']):
+ from os import path
+
+ parts = id.split(':')
+ if len(parts) != 3:
+ raise NameError('expected id="groupId:artifactId:version"')
+ group, artifact, version = parts
+
+ jar = path.join(name, artifact.lower() + '-' + version)
+ url = '/'.join([
+ repository,
+ group.replace('.', '/'), artifact, version,
+ artifact + '-' + version])
+
+ binjar = jar + '.jar'
+ binurl = url + '.jar'
+
+ srcjar = jar + '-src.jar'
+ srcurl = url + '-sources.jar'
+
+ cmd = ['$(exe //bucklets/tools:download_file)', '-o', '$OUT', '-u', binurl]
+ if sha1:
+ cmd.extend(['-v', sha1])
+ elif bin_sha1:
+ cmd.extend(['-v', bin_sha1])
+ for x in exclude:
+ cmd.extend(['-x', x])
+ if exclude_java_sources:
+ cmd.append('--exclude_java_sources')
+ if unsign:
+ cmd.append('--unsign')
+
+ genrule(
+ name = name + '__download_bin',
+ cmd = ' '.join(cmd),
+ deps = ['//bucklets/tools:download_file'],
+ out = binjar,
+ )
+
+ if src_sha1 or attach_source:
+ cmd = ['$(exe //bucklets/tools:download_file)', '-o', '$OUT', '-u', srcurl]
+ if src_sha1:
+ cmd.extend(['-v', src_sha1])
+ genrule(
+ name = name + '__download_src',
+ cmd = ' '.join(cmd),
+ deps = ['//bucklets/tools:download_file'],
+ out = srcjar,
+ )
+ prebuilt_jar(
+ name = name + '_src',
+ binary_jar = genfile(srcjar),
+ deps = [':' + name + '__download_src'],
+ visibility = visibility,
+ )
+ else:
+ srcjar = None
+ genrule(
+ name = name + '__download_src',
+ cmd = ':>$OUT',
+ out = '__' + name + '__no_src',
+ )
+
+ if exported_deps:
+ prebuilt_jar(
+ name = name + '__jar',
+ deps = deps + [':' + name + '__download_bin'],
+ binary_jar = genfile(binjar),
+ source_jar = genfile(srcjar) if srcjar else None,
+ )
+ java_library(
+ name = name,
+ exported_deps = exported_deps + [':' + name + '__jar'],
+ visibility = visibility,
+ )
+ else:
+ prebuilt_jar(
+ name = name,
+ deps = deps + [':' + name + '__download_bin'],
+ binary_jar = genfile(binjar),
+ source_jar = genfile(srcjar) if srcjar else None,
+ visibility = visibility,
+ )
diff --git a/maven_package.bucklet b/maven_package.bucklet
new file mode 100644
index 0000000..0e865b6
--- /dev/null
+++ b/maven_package.bucklet
@@ -0,0 +1,46 @@
+# Copyright (C) 2013 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.
+
+def maven_package(
+ version,
+ repository = None,
+ url = None,
+ jar = {},
+ src = {},
+ doc = {}):
+ cmd = ['$(exe //bucklets/tools:mvn)', '-v', version, '-o', '$OUT']
+ dep = []
+
+ for type,d in [('jar', jar), ('java-source', src), ('javadoc', doc)]:
+ for a,t in d.iteritems():
+ cmd.append('-s %s:%s:$(location %s)' % (a,type,t))
+ dep.append(t)
+
+ genrule(
+ name = 'install',
+ cmd = ' '.join(cmd + ['-a', 'install']),
+ deps = dep + ['//bucklets/tools:mvn'],
+ out = 'install.info',
+ )
+
+ if repository and url:
+ genrule(
+ name = 'deploy',
+ cmd = ' '.join(cmd + [
+ '-a', 'deploy',
+ '--repository', repository,
+ '--url', url]),
+ deps = dep + ['//bucklets/tools:mvn'],
+ out = 'deploy.info',
+ )
diff --git a/tools/BUCK b/tools/BUCK
new file mode 100644
index 0000000..4bdfe5a
--- /dev/null
+++ b/tools/BUCK
@@ -0,0 +1,46 @@
+python_binary(
+ name = 'download_file',
+ main = 'download_file.py',
+ deps = [':util'],
+ visibility = ['PUBLIC'],
+)
+
+python_binary(
+ name = 'pack_war',
+ main = 'pack_war.py',
+ deps = [':util'],
+ visibility = ['PUBLIC'],
+)
+
+python_binary(
+ name = 'mvn',
+ main = 'mvn.py',
+ deps = [':util'],
+ visibility = ['PUBLIC']
+)
+
+python_library(
+ name = 'util',
+ srcs = [
+ 'util.py',
+ '__init__.py'
+ ],
+ visibility = ['PUBLIC'],
+)
+
+def shquote(s):
+ return s.replace("'", "'\\''")
+
+def os_path():
+ from os import environ
+ return environ.get('PATH')
+
+genrule(
+ name = 'buck.properties',
+ cmd = 'echo buck=`which buck`>$OUT;' +
+ ("echo PATH=\''%s'\' >>$OUT;" % shquote(os_path())),
+ deps = [],
+ out = 'buck.properties',
+ visibility = ['PUBLIC'],
+)
+
diff --git a/tools/__init__.py b/tools/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tools/__init__.py
diff --git a/tools/download_all.py b/tools/download_all.py
new file mode 100755
index 0000000..a70cbda
--- /dev/null
+++ b/tools/download_all.py
@@ -0,0 +1,44 @@
+#!/usr/bin/python
+# Copyright (C) 2013 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 optparse import OptionParser
+import re
+from subprocess import check_call, CalledProcessError, Popen, PIPE
+
+MAIN = ['//:classpath']
+PAT = re.compile(r'"(//.*?)" -> "//bucklets/tools:download_file"')
+
+opts = OptionParser()
+opts.add_option('--src', action='store_true')
+args, _ = opts.parse_args()
+
+targets = set()
+
+p = Popen(['buck', 'audit', 'classpath', '--dot'] + MAIN, stdout = PIPE)
+for line in p.stdout:
+ m = PAT.search(line)
+ if m:
+ n = m.group(1)
+ if args.src and n.endswith('__download_bin'):
+ n = n[:-4] + '_src'
+ targets.add(n)
+r = p.wait()
+if r != 0:
+ exit(r)
+
+try:
+ check_call(['buck', 'build'] + sorted(targets))
+except CalledProcessError as err:
+ exit(1)
diff --git a/tools/download_file.py b/tools/download_file.py
new file mode 100755
index 0000000..3e6fca9
--- /dev/null
+++ b/tools/download_file.py
@@ -0,0 +1,186 @@
+#!/usr/bin/python
+# Copyright (C) 2013 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
+
+from hashlib import sha1
+from optparse import OptionParser
+from os import link, makedirs, path, remove
+import shutil
+from subprocess import check_call, CalledProcessError
+from sys import stderr
+from util import resolve_url
+from zipfile import ZipFile, BadZipfile, LargeZipFile
+
+GERRIT_HOME = path.expanduser('~/.gerritcodereview')
+CACHE_DIR = path.join(GERRIT_HOME, 'buck-cache')
+LOCAL_PROPERTIES = 'local.properties'
+
+def hashfile(p):
+ d = sha1()
+ with open(p, 'rb') as f:
+ while True:
+ b = f.read(8192)
+ if not b:
+ break
+ d.update(b)
+ return d.hexdigest()
+
+def safe_mkdirs(d):
+ if path.isdir(d):
+ return
+ try:
+ makedirs(d)
+ except OSError as err:
+ if not path.isdir(d):
+ raise err
+
+def download_properties(root_dir):
+ """ Get the download properties.
+
+ First tries to find the properties file in the given root directory,
+ and if not found there, tries in the Gerrit settings folder in the
+ user's home directory.
+
+ Returns a set of download properties, which may be empty.
+
+ """
+ p = {}
+ local_prop = path.join(root_dir, LOCAL_PROPERTIES)
+ if not path.isfile(local_prop):
+ local_prop = path.join(GERRIT_HOME, LOCAL_PROPERTIES)
+ if path.isfile(local_prop):
+ try:
+ with open(local_prop) as fd:
+ for line in fd:
+ if line.startswith('download.'):
+ d = [e.strip() for e in line.split('=', 1)]
+ name, url = d[0], d[1]
+ p[name[len('download.'):]] = url
+ except OSError:
+ pass
+ return p
+
+def cache_entry(args):
+ if args.v:
+ h = args.v
+ else:
+ h = sha1(args.u).hexdigest()
+ name = '%s-%s' % (path.basename(args.o), h)
+ return path.join(CACHE_DIR, name)
+
+opts = OptionParser()
+opts.add_option('-o', help='local output file')
+opts.add_option('-u', help='URL to download')
+opts.add_option('-v', help='expected content SHA-1')
+opts.add_option('-x', action='append', help='file to delete from ZIP')
+opts.add_option('--exclude_java_sources', action='store_true')
+opts.add_option('--unsign', action='store_true')
+args, _ = opts.parse_args()
+
+root_dir = args.o
+while root_dir:
+ root_dir, n = path.split(root_dir)
+ if n == 'buck-out':
+ break
+
+redirects = download_properties(root_dir)
+cache_ent = cache_entry(args)
+src_url = resolve_url(args.u, redirects)
+
+if not path.exists(cache_ent):
+ try:
+ safe_mkdirs(path.dirname(cache_ent))
+ except OSError as err:
+ print('error creating directory %s: %s' %
+ (path.dirname(cache_ent), err), file=stderr)
+ exit(1)
+
+ print('Download %s' % src_url, file=stderr)
+ try:
+ check_call(['curl', '--proxy-anyauth', '-sfo', cache_ent, src_url])
+ except OSError as err:
+ print('could not invoke curl: %s\nis curl installed?' % err, file=stderr)
+ exit(1)
+ except CalledProcessError as err:
+ print('error using curl: %s' % err, file=stderr)
+ exit(1)
+
+if args.v:
+ have = hashfile(cache_ent)
+ if args.v != have:
+ print((
+ '%s:\n' +
+ 'expected %s\n' +
+ 'received %s\n') % (src_url, args.v, have), file=stderr)
+ try:
+ remove(cache_ent)
+ except OSError as err:
+ if path.exists(cache_ent):
+ print('error removing %s: %s' % (cache_ent, err), file=stderr)
+ exit(1)
+
+exclude = []
+if args.x:
+ exclude += args.x
+if args.exclude_java_sources:
+ try:
+ zf = ZipFile(cache_ent, 'r')
+ try:
+ for n in zf.namelist():
+ if n.endswith('.java'):
+ exclude.append(n)
+ finally:
+ zf.close()
+ except (BadZipfile, LargeZipFile) as err:
+ print('error opening %s: %s' % (cache_ent, err), file=stderr)
+ exit(1)
+
+if args.unsign:
+ try:
+ zf = ZipFile(cache_ent, 'r')
+ try:
+ for n in zf.namelist():
+ if (n.endswith('.RSA')
+ or n.endswith('.SF')
+ or n.endswith('.LIST')):
+ exclude.append(n)
+ finally:
+ zf.close()
+ except (BadZipfile, LargeZipFile) as err:
+ print('error opening %s: %s' % (cache_ent, err), file=stderr)
+ exit(1)
+
+safe_mkdirs(path.dirname(args.o))
+if exclude:
+ try:
+ shutil.copyfile(cache_ent, args.o)
+ except (shutil.Error, IOError) as err:
+ print('error copying to %s: %s' % (args.o, err), file=stderr)
+ exit(1)
+ try:
+ check_call(['zip', '-d', args.o] + exclude)
+ except CalledProcessError as err:
+ print('error removing files from zip: %s' % err, file=stderr)
+ exit(1)
+else:
+ try:
+ link(cache_ent, args.o)
+ except OSError as err:
+ try:
+ shutil.copyfile(cache_ent, args.o)
+ except (shutil.Error, IOError) as err:
+ print('error copying to %s: %s' % (args.o, err), file=stderr)
+ exit(1)
diff --git a/tools/eclipse.py b/tools/eclipse.py
new file mode 100755
index 0000000..f5b46f8
--- /dev/null
+++ b/tools/eclipse.py
@@ -0,0 +1,156 @@
+#!/usr/bin/python
+# Copyright (C) 2013 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.
+#
+# TODO(sop): Remove hack after Buck supports Eclipse
+
+from __future__ import print_function
+from optparse import OptionParser
+from os import path
+from subprocess import Popen, PIPE, CalledProcessError, check_call
+from xml.dom import minidom
+import re
+import sys
+
+MAIN = ['//:classpath']
+JRE = '/'.join([
+ 'org.eclipse.jdt.launching.JRE_CONTAINER',
+ 'org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType',
+ 'JavaSE-1.7',
+])
+
+ROOT = path.abspath(__file__)
+for _ in range(0, 3):
+ ROOT = path.dirname(ROOT)
+
+opts = OptionParser()
+opts.add_option('--src', action='store_true')
+opts.add_option('-n', '--name')
+args, _ = opts.parse_args()
+
+def gen_project():
+ p = path.join(ROOT, '.project')
+ name = args.name if args.name else path.basename(ROOT)
+ with open(p, 'w') as fd:
+ print("""\
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <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,), file=fd)
+
+def gen_classpath():
+ def query_classpath(targets):
+ deps = []
+ p = Popen(['buck', 'audit', 'classpath'] + targets, stdout=PIPE)
+ for line in p.stdout:
+ deps.append(line.strip())
+ s = p.wait()
+ if s != 0:
+ exit(s)
+ return deps
+
+ def make_classpath():
+ impl = minidom.getDOMImplementation()
+ return impl.createDocument(None, 'classpath', None)
+
+ def classpathentry(kind, path, src=None, out=None):
+ e = doc.createElement('classpathentry')
+ e.setAttribute('kind', kind)
+ e.setAttribute('path', path)
+ if src:
+ e.setAttribute('sourcepath', src)
+ if out:
+ e.setAttribute('output', out)
+ doc.documentElement.appendChild(e)
+
+ doc = make_classpath()
+ src = set()
+ lib = set()
+
+ java_library = re.compile(r'[^/]+/gen/(.*)/lib__[^/]+__output/[^/]+[.]jar$')
+ for p in query_classpath(MAIN):
+ m = java_library.match(p)
+ if m:
+ src.add(m.group(1))
+ else:
+ lib.add(p)
+
+ for s in sorted(src):
+ out = None
+
+ if s.startswith('lib/'):
+ out = 'buck-out/eclipse/lib'
+ elif s.startswith('plugins/'):
+ out = 'buck-out/eclipse/' + 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 = 'buck-out/eclipse/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
+ if j.endswith('.jar'):
+ s = j[:-4] + '-src.jar'
+ if not path.exists(s):
+ s = None
+ classpathentry('lib', j, s)
+
+ classpathentry('con', JRE)
+ classpathentry('output', 'buck-out/eclipse/classes')
+
+ p = path.join(ROOT, '.classpath')
+ with open(p, 'w') as fd:
+ doc.writexml(fd, addindent='\t', newl='\n', encoding='UTF-8')
+
+try:
+ if args.src:
+ try:
+ check_call([path.join(ROOT, 'bucklets/tools', 'download_all.py'), '--src'])
+ except CalledProcessError as err:
+ exit(1)
+
+ gen_project()
+ gen_classpath()
+
+ try:
+ targets = ['//bucklets/tools:buck.properties'] + MAIN
+ check_call(['buck', 'build'] + targets)
+ except CalledProcessError as err:
+ exit(1)
+except KeyboardInterrupt:
+ print('Interrupted by user', file=sys.stderr)
+ exit(1)
diff --git a/tools/mvn.py b/tools/mvn.py
new file mode 100644
index 0000000..0518439
--- /dev/null
+++ b/tools/mvn.py
@@ -0,0 +1,80 @@
+#!/usr/bin/python
+# Copyright (C) 2013 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
+from optparse import OptionParser
+from os import path
+
+from sys import stderr
+from util import check_output
+
+def mvn(action):
+ return ['mvn', '--file', path.join(ROOT, 'fake_pom_%s.xml' % action)]
+
+def mvn(action):
+ return ['mvn', '--file', path.join(ROOT, 'fake_pom_%s.xml' % action)]
+
+opts = OptionParser()
+opts.add_option('--repository', help='maven repository id')
+opts.add_option('--url', help='maven repository url')
+opts.add_option('-o')
+opts.add_option('-a', help='action (valid actions are: install,deploy)')
+opts.add_option('-v', help='gerrit version')
+opts.add_option('-s', action='append', help='triplet of artifactId:type:path')
+
+args, ctx = opts.parse_args()
+if not args.v:
+ print('version is empty', file=stderr)
+ exit(1)
+
+common = [
+ '-DgroupId=com.google.gerrit',
+ '-Dversion=%s' % args.v,
+]
+
+ROOT = path.abspath(__file__)
+for _ in range(0, 3):
+ ROOT = path.dirname(ROOT)
+
+if 'install' == args.a:
+ cmd = mvn(args.a) + ['install:install-file'] + common
+elif 'deploy' == args.a:
+ cmd = mvn(args.a) + [
+ 'deploy:deploy-file',
+ '-DrepositoryId=%s' % args.repository,
+ '-Durl=%s' % args.url,
+ ] + common
+else:
+ print("unknown action -a %s" % args.a, file=stderr)
+ exit(1)
+
+for spec in args.s:
+ artifact, packaging_type, src = spec.split(':')
+ try:
+ check_output(cmd + [
+ '-DartifactId=%s' % artifact,
+ '-Dpackaging=%s' % packaging_type,
+ '-Dfile=%s' % src,
+ ])
+ except Exception as e:
+ print('%s command failed: %s' % (args.a, e), file=stderr)
+ exit(1)
+
+with open(args.o, 'w') as fd:
+ if args.repository:
+ print('Repository: %s' % args.repository, file=fd)
+ if args.url:
+ print('URL: %s' % args.url, file=fd)
+ print('Version: %s' % args.v, file=fd)
diff --git a/tools/pack_war.py b/tools/pack_war.py
new file mode 100755
index 0000000..6c71d81
--- /dev/null
+++ b/tools/pack_war.py
@@ -0,0 +1,55 @@
+#!/usr/bin/python
+# Copyright (C) 2013 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
+from optparse import OptionParser
+from os import makedirs, path, symlink
+from subprocess import check_call
+import sys
+from util import check_output
+
+opts = OptionParser()
+opts.add_option('-o', help='path to write WAR to')
+opts.add_option('--lib', action='append', help='target for WEB-INF/lib')
+opts.add_option('--pgmlib', action='append', help='target for WEB-INF/pgm-lib')
+opts.add_option('--tmp', help='temporary directory')
+args, ctx = opts.parse_args()
+
+war = args.tmp
+root = war[:war.index('buck-out')]
+jars = set()
+
+def link_jars(libs, directory):
+ makedirs(directory)
+ cp = check_output(['buck', 'audit', 'classpath'] + libs)
+ for j in cp.strip().splitlines():
+ if j not in jars:
+ jars.add(j)
+ n = path.basename(j)
+ if j.startswith('buck-out/gen/gerrit-'):
+ n = j.split('/')[2] + '-' + n
+ symlink(path.join(root, j), path.join(directory, n))
+
+if args.lib:
+ link_jars(args.lib, path.join(war, 'WEB-INF', 'lib'))
+if args.pgmlib:
+ link_jars(args.pgmlib, path.join(war, 'WEB-INF', 'pgm-lib'))
+try:
+ for s in ctx:
+ check_call(['unzip', '-q', '-d', war, s])
+ check_call(['zip', '-9qr', args.o, '.'], cwd = war)
+except KeyboardInterrupt:
+ print('Interrupted by user', file=sys.stderr)
+ exit(1)
diff --git a/tools/util.py b/tools/util.py
new file mode 100644
index 0000000..9115ac7
--- /dev/null
+++ b/tools/util.py
@@ -0,0 +1,58 @@
+# Copyright (C) 2013 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 os import path
+
+try:
+ from subprocess import check_output
+except ImportError:
+ from subprocess import Popen, PIPE
+ def check_output(*cmd):
+ return Popen(*cmd, stdout=PIPE).communicate()[0]
+
+REPO_ROOTS = {
+ 'GERRIT': 'http://gerrit-maven.storage.googleapis.com',
+ 'GERRIT_API': 'https://gerrit-api.commondatastorage.googleapis.com/release',
+ 'ECLIPSE': 'https://repo.eclipse.org/content/groups/releases',
+ 'MAVEN_CENTRAL': 'http://repo1.maven.org/maven2',
+ 'MAVEN_LOCAL': 'file://' + path.expanduser('~/.m2/repository'),
+}
+
+def resolve_url(url, redirects):
+ """ Resolve URL of a Maven artifact.
+
+ prefix:path is passed as URL. prefix identifies known or custom
+ repositories that can be rewritten in redirects set, passed as
+ second arguments.
+
+ A special case is supported, when prefix neither exists in
+ REPO_ROOTS, no in redirects set: the url is returned as is.
+ This enables plugins to pass custom maven_repository URL as is
+ directly to maven_jar().
+
+ Returns a resolved path for Maven artifact.
+ """
+ s = url.find(':')
+ if s < 0:
+ return url
+ scheme, rest = url[:s], url[s+1:]
+ if scheme in redirects:
+ root = redirects[scheme]
+ elif scheme in REPO_ROOTS:
+ root = REPO_ROOTS[scheme]
+ else:
+ return url
+ root = root.rstrip('/')
+ rest = rest.lstrip('/')
+ return '/'.join([root, rest])
diff --git a/war.bucklet b/war.bucklet
new file mode 100644
index 0000000..2987e05
--- /dev/null
+++ b/war.bucklet
@@ -0,0 +1,36 @@
+def war(
+ name,
+ libs = [],
+ pgmlibs = [],
+ context = [],
+ visibility = [],
+ ):
+ cmd = ['$(exe //bucklets/tools:pack_war)', '-o', '$OUT', '--tmp', '$TMP']
+ for l in libs:
+ cmd.extend(['--lib', l])
+ for l in pgmlibs:
+ cmd.extend(['--pgmlib', l])
+
+ src = []
+ dep = []
+ if context:
+ root = get_base_path()
+ if root:
+ root = '/'.join(['..' for _ in root.split('/')]) + '/'
+ for r in context:
+ dep.append(r[:r.rindex('.')])
+ if r.startswith('//'):
+ r = root + r[2:]
+ r = r.replace(':', '/')
+ src.append(genfile(r))
+ if src:
+ cmd.append('$SRCS')
+
+ genrule(
+ name = name,
+ cmd = ' '.join(cmd),
+ srcs = src,
+ deps = libs + pgmlibs + dep + ['//bucklets/tools:pack_war'],
+ out = name + '.war',
+ visibility = visibility,
+ )