Brian O'Connor
Committed by Gerrit Code Review

Updating buck to build OSGi JARs

Includes:
  OSGiWrapper to wrap Buck JARs
    - cfgdef file support
    - WAR file generation support
  Adding checkstyle support

Change-Id: Ia25c41f945980e4b94ad5a8bd161328fa5f79c27
......@@ -5,3 +5,6 @@
source_level = 8
target_level = 8
[download]
maven_repo = https://repo1.maven.org/maven2
in_build = true
......
include_defs('//bucklets/maven_jar.bucklet')
include_defs('//bucklets/onos.bucklet')
BASE_DEPS = [
'//lib:junit',
......
......@@ -119,6 +119,7 @@ def maven_jar(
prebuilt_jar(
name = '%s_src' % name,
binary_jar = ':%s__download_src' % name,
maven_coords = id,
deps = license,
visibility = visibility,
)
......@@ -136,6 +137,7 @@ def maven_jar(
deps = deps + license,
binary_jar = ':%s__download_bin' % name,
source_jar = ':%s__download_src' % name if srcjar else None,
maven_coords = id,
)
java_library(
name = name,
......@@ -149,6 +151,7 @@ def maven_jar(
binary_jar = ':%s__download_bin' % name,
source_jar = ':%s__download_src' % name if srcjar else None,
visibility = visibility,
maven_coords = id,
)
......
DEBUG_ARG='JAVA_TOOL_OPTIONS="-Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=5005,suspend=y"'
def osgi_jar(
name,
srcs,
group_id = 'org.onosproject',
version = '1.6.0-SNAPSHOT',
deps = [],
visibility = ['PUBLIC'],
license = 'NONE',
description = '',
debug = False,
web_context = 'NONE',
**kwargs
):
bare_jar_name = name + '-jar'
osgi_jar_name = name + '-osgi'
mvn_coords = group_id + ':' + name + ':' + version
java_library(
name = bare_jar_name,
srcs = srcs,
deps = deps,
visibility = [], #intentially, not visible
**kwargs
)
cp = ':'.join(['$(classpath %s)' % c for c in deps])
args = ( '$(location :%s)' % bare_jar_name, #input jar
'$OUT', #output jar
cp, #classpath
name, #bundle name
group_id, #group id
version, #version
license, #license url
web_context, #web context (REST API only)
description, #description
)
#TODO stage_jar is a horrendous hack
stage_jar = 'pushd $SRCDIR; mkdir bin; cd bin; jar xf $(location :%s); ls; popd; ' % bare_jar_name
wrap_jar = '$(exe //utils/osgiwrap:osgi-jar) ' + ' '.join(args)
bash = stage_jar + wrap_jar
if debug:
bash = stage_jar + DEBUG_ARG + ' ' + wrap_jar
print bash
# TODO this is a hack to add checkstyle as dependency before generating jar
bash = 'ls $(location :' + name + '-checkstyle) > /dev/null; ' + bash
genrule(
name = osgi_jar_name,
bash = bash,
out = name + '.jar',
visibility = [], #intentially, not visible
)
# TODO we really should shade the jar with maven flavor
prebuilt_jar(
name = name,
maven_coords = mvn_coords,
binary_jar = ':' + osgi_jar_name,
visibility = visibility,
)
### Checkstyle
chk_cmd = ' '.join(( 'java -jar $(location //lib:checkstyle)',
'-o $OUT',
'-c $(location //tools/build/conf:checkstyle-xml)',
' '.join(srcs) ))
error_cmd = '(touch $OUT; cat $OUT | grep "^\[ERROR\]"; exit 1)'
cmd = ' || '.join((chk_cmd, error_cmd))
genrule(
name = name + '-checkstyle',
bash = cmd,
srcs = srcs,
out = 'checkstyle.log',
)
### .m2 Install
mvn_cmd = ' '.join(('mvn install:install-file',
'-Dfile=$(location :%s)' % name,
'-DgroupId=%s' % group_id,
'-DartifactId=%s' % name,
'-Dversion=%s' % version,
'-Dpackaging=jar'
))
genrule(
name = name + '-install',
bash = mvn_cmd + ' > $OUT',
out = 'install.log',
visibility = visibility,
)
def onos_app(
name,
**kwargs):
osgi_jar(
name = name,
**kwargs
)
......@@ -781,3 +781,62 @@ maven_jar(
attach_source = False,
license = 'Apache2.0',
)
# ------ needed for OSGi Wrapper ------------------
#TODO should these live in osgiwrap or in lib
#FIXME replace with release version
maven_jar(
name = 'org.apache.felix.scr.bnd',
id = 'org.onosproject:org.apache.felix.scr.bnd:1.4.1-SNAPSHOT',
repository = 'https://oss.sonatype.org/content/repositories/snapshots',
full_url = 'https://oss.sonatype.org/content/repositories/snapshots/org/onosproject/org.apache.felix.scr.bnd/1.4.1-SNAPSHOT/org.apache.felix.scr.bnd-1.4.1-20160328.235003-2',
attach_source = False,
license = 'Apache2.0',
)
#TODO update this to org.apache.felix when changes are merged upstream
# prebuilt_jar(
# name = 'felix-bnd',
# binary_jar = ':org.apache.felix.scr.bnd-jar',
# )
# remote_file(
# name = 'org.apache.felix.scr.bnd-jar',
# out = 'org.apache.felix.scr.bnd-jar-1.4.1-SNAPSHOT.jar',
# url = 'mvn:https://oss.sonatype.org/content/repositories/snapshots:org.onosproject:org.apache.felix.scr.bnd:jar:1.4.1-SNAPSHOT',
# sha1 = '89b5161d60dfe4138046f13c789f17a6b89e823d',
# )
prebuilt_jar(
name = 'bndlib',
binary_jar = ':biz.aQute.bnd-biz.aQute.bndlib-jar',
visibility = [ 'PUBLIC' ] #:onlab-osgiwrap and :osgi-jar
# source_jar
# maven_coords
)
remote_file(
name = 'biz.aQute.bnd-biz.aQute.bndlib-jar',
out = 'biz.aQute.bnd-biz.aQute.bndlib-jar-3.1.0.jar',
url = 'mvn:biz.aQute.bnd:biz.aQute.bndlib:jar:3.1.0',
sha1 = '8e45564ca80bf089276a35f916e8702e7b798cbb',
)
prebuilt_jar(
name = 'checkstyle',
binary_jar = ':checkstyle-jar',
visibility = [ 'PUBLIC' ]
)
# TODO upgrade to newer version of checkstyle
# remote_file(
# name = 'checkstyle-jar',
# out = 'checkstyle-6.17-all.jar',
# url = 'http://onlab.vicci.org/onos/third-party/checkstyle-6.17-all.jar',
# sha1 = '11a02d7b0374f8a82fbd76361a69756faa6aefa0'
# )
remote_file(
name = 'checkstyle-jar',
out = 'checkstyle-6.11.2-all.jar',
url = 'http://onlab.vicci.org/onos/third-party/checkstyle-6.11.2-all.jar',
sha1 = 'f504187b1743e73ffe72c2eede0ff57d45536b7d'
)
......
checkstyle_source = 'src/main/resources/onos/checkstyle.xml'
suppression_source = 'src/main/resources/onos/suppressions.xml'
xml = ('<module name="SuppressionFilter">'
'<property name="file" value="$(location :suppressions.xml)"/>'
'</module>' )
cmd = "sed 's#<module name=\"Checker\">#<module name=\"Checker\">%s#' %s > $OUT" % ( xml, checkstyle_source )
genrule(
name = 'checkstyle-xml',
srcs = [ checkstyle_source ],
out = 'checkstyle.xml',
bash = cmd,
visibility = [ 'PUBLIC' ]
)
export_file(
name = 'suppressions.xml',
src = suppression_source,
)
SRC = 'src/main/java/org/onlab/**/'
TEST = 'src/test/java/org/onlab/**/'
CURRENT_NAME = 'onlab-osgiwrap'
CURRENT_TARGET = ':' + CURRENT_NAME
COMPILE_DEPS = [
'//lib:guava',
'//lib:bndlib',
'//lib:org.apache.felix.scr.bnd'
]
java_library(
name = CURRENT_NAME,
#maven_coords = 'org.onosproject:' + CURRENT_NAME + ':' + '1.2.3',
srcs = glob([SRC + '/*.java']),
deps = COMPILE_DEPS,
visibility = ['PUBLIC'],
)
java_binary(
name = 'osgi-jar',
deps = COMPILE_DEPS + [ ':' + CURRENT_NAME ],
main_class = 'org.onlab.OSGiWrapper',
visibility = [ 'PUBLIC' ]
)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>onlab-utils</artifactId>
<groupId>org.onosproject</groupId>
<version>1.6.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>osgiwrap</artifactId>
<version>0.9-SNAPSHOT</version>
<dependencies>
<!-- TODO update this to org.apache.felix when changes are merged upstream -->
<dependency>
<groupId>org.onosproject</groupId>
<artifactId>org.apache.felix.scr.bnd</artifactId>
<version>1.4.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>biz.aQute.bnd</groupId>
<artifactId>biz.aQute.bndlib</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>19.0</version>
</dependency>
</dependencies>
</project>
\ No newline at end of file
/*
* Copyright 2016 Open Networking Laboratory
*
* 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.
*/
package org.onlab.osgiwrap;
import aQute.bnd.osgi.Analyzer;
import aQute.bnd.osgi.Jar;
import com.google.common.base.Joiner;
import com.google.common.base.MoreObjects;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.felix.scrplugin.bnd.SCRDescriptorBndPlugin;
import java.io.File;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.jar.Manifest;
/**
* BND-based wrapper to convert Buck JARs to OSGi-compatible JARs.
*/
public class OSGiWrapper {
private String inputJar;
private String outputJar;
private List<String> classpath;
private String bundleName;
private String groupId;
private String bundleSymbolicName;
private String bundleVersion;
private String bundleDescription;
private String bundleLicense;
private String webContext;
public static void main(String[] args) {
if (args.length < 7) {
System.err.println("Not enough args");
System.exit(1);
}
String jar = args[0];
String output = args[1];
String cp = args[2];
String name = args[3];
String group = args[4];
String version = args[5];
String license = args[6];
String webContext = args[7];
String desc = Joiner.on(' ').join(Arrays.copyOfRange(args, 8, args.length));
OSGiWrapper wrapper = new OSGiWrapper(jar, output, cp,
name, group,
version, license,
webContext, desc);
wrapper.log(wrapper + "\n");
if (!wrapper.execute()) {
System.err.println("ERROR");
System.exit(2);
}
}
public OSGiWrapper(String inputJar,
String outputJar,
String classpath,
String bundleName,
String groupId,
String bundleVersion,
String bundleLicense,
String webContext,
String bundleDescription) {
this.inputJar = inputJar;
this.classpath = Lists.newArrayList(classpath.split(":"));
if (!this.classpath.contains(inputJar)) {
this.classpath.add(0, inputJar);
}
this.outputJar = outputJar;
this.bundleName = bundleName;
this.groupId = groupId;
this.bundleSymbolicName = String.format("%s.%s", groupId, bundleName);
this.bundleVersion = bundleVersion;
this.bundleLicense = bundleLicense;
this.bundleDescription = bundleDescription;
this.webContext = webContext;
}
private void setProperties(Analyzer analyzer) {
analyzer.setProperty(Analyzer.BUNDLE_NAME, bundleName);
analyzer.setProperty(Analyzer.BUNDLE_SYMBOLICNAME, bundleSymbolicName);
analyzer.setProperty(Analyzer.BUNDLE_VERSION, bundleVersion.replace('-', '.'));
analyzer.setProperty(Analyzer.BUNDLE_DESCRIPTION, bundleDescription);
analyzer.setProperty(Analyzer.BUNDLE_LICENSE, bundleLicense);
//TODO consider using stricter version policy
//analyzer.setProperty("-provider-policy", "${range;[===,==+)}");
//analyzer.setProperty("-consumer-policy", "${range;[===,==+)}");
// There are no good defaults so make sure you set the Import-Package
analyzer.setProperty(Analyzer.IMPORT_PACKAGE, "*,org.glassfish.jersey.servlet");
// TODO include version in export, but not in import
analyzer.setProperty(Analyzer.EXPORT_PACKAGE, "*");
// TODO we may need INCLUDE_RESOURCE, or that might be done by Buck
//analyzer.setProperty(analyzer.INCLUDE_RESOURCE, ...)
if (isWab()) {
analyzer.setProperty(Analyzer.WAB, "src/main/webapp/");
analyzer.setProperty("Web-ContextPath", webContext);
}
}
public boolean execute() {
Analyzer analyzer = new Analyzer();
try {
Jar jar = new Jar(new File(inputJar)); // where our data is
analyzer.setJar(jar); // give bnd the contents
// You can provide additional class path entries to allow
// bnd to pickup export version from the packageinfo file,
// Version annotation, or their manifests.
analyzer.addClasspath(classpath);
setProperties(analyzer);
// analyzer.setProperty("DESTDIR");
// analyzer.setBase();
// ------------- let's begin... -------------------------
// Analyze the target JAR first
analyzer.analyze();
// Scan the JAR for Felix SCR annotations and generate XML files
Map<String, String> properties = Maps.newHashMap();
SCRDescriptorBndPlugin scrDescriptorBndPlugin = new SCRDescriptorBndPlugin();
scrDescriptorBndPlugin.setProperties(properties);
scrDescriptorBndPlugin.setReporter(analyzer);
scrDescriptorBndPlugin.analyzeJar(analyzer);
// Repack the JAR as a WAR
doWabStaging(analyzer);
// Calculate the manifest
Manifest manifest = analyzer.calcManifest();
//OutputStream s = new FileOutputStream("/tmp/foo2.txt");
//manifest.write(s);
//s.close();
if (analyzer.isOk()) {
analyzer.getJar().setManifest(manifest);
analyzer.save(new File(outputJar), true);
log("Saved!\n");
} else {
warn("%s\n", analyzer.getErrors());
return false;
}
analyzer.close();
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
private boolean isWab() {
return !Objects.equals(webContext, "NONE");
}
private void doWabStaging(Analyzer analyzer) throws Exception {
if (!isWab()) {
return;
}
String wab = analyzer.getProperty(analyzer.WAB);
Jar dot = analyzer.getJar();
log("wab %s", wab);
analyzer.setBundleClasspath("WEB-INF/classes," +
analyzer.getProperty(analyzer.BUNDLE_CLASSPATH));
Set<String> paths = new HashSet<String>(dot.getResources().keySet());
for (String path : paths) {
if (path.indexOf('/') > 0 && !Character.isUpperCase(path.charAt(0))) {
log("wab: moving: %s", path);
dot.rename(path, "WEB-INF/classes/" + path);
}
}
}
private void log(String format, Object... objects) {
//System.err.printf(format, objects);
}
private void warn(String format, Object... objects) {
System.err.printf(format, objects);
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("inputJar", inputJar)
.add("outputJar", outputJar)
.add("classpath", classpath)
.add("bundleName", bundleName)
.add("groupId", groupId)
.add("bundleSymbolicName", bundleSymbolicName)
.add("bundleVersion", bundleVersion)
.add("bundleDescription", bundleDescription)
.add("bundleLicense", bundleLicense)
.toString();
}
}
/*
* Copyright 2016 Open Networking Laboratory
*
* 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.
*/
/**
* OSGi-wrapper for raw JARs.
*/
package org.onlab.osgiwrap;
......@@ -41,6 +41,7 @@
<module>stc</module>
<module>jdvue</module>
<module>jnc</module>
<module>osgiwrap</module>
</modules>
<dependencies>
......