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 @@ ...@@ -5,3 +5,6 @@
5 source_level = 8 5 source_level = 8
6 target_level = 8 6 target_level = 8
7 7
8 +[download]
9 + maven_repo = https://repo1.maven.org/maven2
10 + in_build = true
......
1 include_defs('//bucklets/maven_jar.bucklet') 1 include_defs('//bucklets/maven_jar.bucklet')
2 +include_defs('//bucklets/onos.bucklet')
2 3
3 BASE_DEPS = [ 4 BASE_DEPS = [
4 '//lib:junit', 5 '//lib:junit',
......
...@@ -119,6 +119,7 @@ def maven_jar( ...@@ -119,6 +119,7 @@ def maven_jar(
119 prebuilt_jar( 119 prebuilt_jar(
120 name = '%s_src' % name, 120 name = '%s_src' % name,
121 binary_jar = ':%s__download_src' % name, 121 binary_jar = ':%s__download_src' % name,
122 + maven_coords = id,
122 deps = license, 123 deps = license,
123 visibility = visibility, 124 visibility = visibility,
124 ) 125 )
...@@ -136,6 +137,7 @@ def maven_jar( ...@@ -136,6 +137,7 @@ def maven_jar(
136 deps = deps + license, 137 deps = deps + license,
137 binary_jar = ':%s__download_bin' % name, 138 binary_jar = ':%s__download_bin' % name,
138 source_jar = ':%s__download_src' % name if srcjar else None, 139 source_jar = ':%s__download_src' % name if srcjar else None,
140 + maven_coords = id,
139 ) 141 )
140 java_library( 142 java_library(
141 name = name, 143 name = name,
...@@ -149,6 +151,7 @@ def maven_jar( ...@@ -149,6 +151,7 @@ def maven_jar(
149 binary_jar = ':%s__download_bin' % name, 151 binary_jar = ':%s__download_bin' % name,
150 source_jar = ':%s__download_src' % name if srcjar else None, 152 source_jar = ':%s__download_src' % name if srcjar else None,
151 visibility = visibility, 153 visibility = visibility,
154 + maven_coords = id,
152 ) 155 )
153 156
154 157
......
1 +
2 +DEBUG_ARG='JAVA_TOOL_OPTIONS="-Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=5005,suspend=y"'
3 +
4 +def osgi_jar(
5 + name,
6 + srcs,
7 + group_id = 'org.onosproject',
8 + version = '1.6.0-SNAPSHOT',
9 + deps = [],
10 + visibility = ['PUBLIC'],
11 + license = 'NONE',
12 + description = '',
13 + debug = False,
14 + web_context = 'NONE',
15 + **kwargs
16 + ):
17 +
18 + bare_jar_name = name + '-jar'
19 + osgi_jar_name = name + '-osgi'
20 + mvn_coords = group_id + ':' + name + ':' + version
21 +
22 + java_library(
23 + name = bare_jar_name,
24 + srcs = srcs,
25 + deps = deps,
26 + visibility = [], #intentially, not visible
27 + **kwargs
28 + )
29 +
30 + cp = ':'.join(['$(classpath %s)' % c for c in deps])
31 +
32 + args = ( '$(location :%s)' % bare_jar_name, #input jar
33 + '$OUT', #output jar
34 + cp, #classpath
35 + name, #bundle name
36 + group_id, #group id
37 + version, #version
38 + license, #license url
39 + web_context, #web context (REST API only)
40 + description, #description
41 + )
42 +
43 + #TODO stage_jar is a horrendous hack
44 + stage_jar = 'pushd $SRCDIR; mkdir bin; cd bin; jar xf $(location :%s); ls; popd; ' % bare_jar_name
45 + wrap_jar = '$(exe //utils/osgiwrap:osgi-jar) ' + ' '.join(args)
46 + bash = stage_jar + wrap_jar
47 + if debug:
48 + bash = stage_jar + DEBUG_ARG + ' ' + wrap_jar
49 + print bash
50 + # TODO this is a hack to add checkstyle as dependency before generating jar
51 + bash = 'ls $(location :' + name + '-checkstyle) > /dev/null; ' + bash
52 +
53 + genrule(
54 + name = osgi_jar_name,
55 + bash = bash,
56 + out = name + '.jar',
57 + visibility = [], #intentially, not visible
58 + )
59 +
60 + # TODO we really should shade the jar with maven flavor
61 + prebuilt_jar(
62 + name = name,
63 + maven_coords = mvn_coords,
64 + binary_jar = ':' + osgi_jar_name,
65 + visibility = visibility,
66 + )
67 +
68 +
69 +
70 + ### Checkstyle
71 + chk_cmd = ' '.join(( 'java -jar $(location //lib:checkstyle)',
72 + '-o $OUT',
73 + '-c $(location //tools/build/conf:checkstyle-xml)',
74 + ' '.join(srcs) ))
75 + error_cmd = '(touch $OUT; cat $OUT | grep "^\[ERROR\]"; exit 1)'
76 + cmd = ' || '.join((chk_cmd, error_cmd))
77 + genrule(
78 + name = name + '-checkstyle',
79 + bash = cmd,
80 + srcs = srcs,
81 + out = 'checkstyle.log',
82 + )
83 +
84 + ### .m2 Install
85 + mvn_cmd = ' '.join(('mvn install:install-file',
86 + '-Dfile=$(location :%s)' % name,
87 + '-DgroupId=%s' % group_id,
88 + '-DartifactId=%s' % name,
89 + '-Dversion=%s' % version,
90 + '-Dpackaging=jar'
91 + ))
92 + genrule(
93 + name = name + '-install',
94 + bash = mvn_cmd + ' > $OUT',
95 + out = 'install.log',
96 + visibility = visibility,
97 + )
98 +
99 +def onos_app(
100 + name,
101 + **kwargs):
102 +
103 + osgi_jar(
104 + name = name,
105 + **kwargs
106 + )
107 +
...@@ -781,3 +781,62 @@ maven_jar( ...@@ -781,3 +781,62 @@ maven_jar(
781 attach_source = False, 781 attach_source = False,
782 license = 'Apache2.0', 782 license = 'Apache2.0',
783 ) 783 )
784 +
785 +# ------ needed for OSGi Wrapper ------------------
786 +#TODO should these live in osgiwrap or in lib
787 +#FIXME replace with release version
788 +maven_jar(
789 + name = 'org.apache.felix.scr.bnd',
790 + id = 'org.onosproject:org.apache.felix.scr.bnd:1.4.1-SNAPSHOT',
791 + repository = 'https://oss.sonatype.org/content/repositories/snapshots',
792 + 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',
793 + attach_source = False,
794 + license = 'Apache2.0',
795 +)
796 +#TODO update this to org.apache.felix when changes are merged upstream
797 +# prebuilt_jar(
798 +# name = 'felix-bnd',
799 +# binary_jar = ':org.apache.felix.scr.bnd-jar',
800 +# )
801 +# remote_file(
802 +# name = 'org.apache.felix.scr.bnd-jar',
803 +# out = 'org.apache.felix.scr.bnd-jar-1.4.1-SNAPSHOT.jar',
804 +# url = 'mvn:https://oss.sonatype.org/content/repositories/snapshots:org.onosproject:org.apache.felix.scr.bnd:jar:1.4.1-SNAPSHOT',
805 +# sha1 = '89b5161d60dfe4138046f13c789f17a6b89e823d',
806 +# )
807 +
808 +prebuilt_jar(
809 + name = 'bndlib',
810 + binary_jar = ':biz.aQute.bnd-biz.aQute.bndlib-jar',
811 + visibility = [ 'PUBLIC' ] #:onlab-osgiwrap and :osgi-jar
812 +# source_jar
813 +# maven_coords
814 +)
815 +
816 +remote_file(
817 + name = 'biz.aQute.bnd-biz.aQute.bndlib-jar',
818 + out = 'biz.aQute.bnd-biz.aQute.bndlib-jar-3.1.0.jar',
819 + url = 'mvn:biz.aQute.bnd:biz.aQute.bndlib:jar:3.1.0',
820 + sha1 = '8e45564ca80bf089276a35f916e8702e7b798cbb',
821 +)
822 +
823 +prebuilt_jar(
824 + name = 'checkstyle',
825 + binary_jar = ':checkstyle-jar',
826 + visibility = [ 'PUBLIC' ]
827 +)
828 +
829 +# TODO upgrade to newer version of checkstyle
830 +# remote_file(
831 +# name = 'checkstyle-jar',
832 +# out = 'checkstyle-6.17-all.jar',
833 +# url = 'http://onlab.vicci.org/onos/third-party/checkstyle-6.17-all.jar',
834 +# sha1 = '11a02d7b0374f8a82fbd76361a69756faa6aefa0'
835 +# )
836 +
837 +remote_file(
838 + name = 'checkstyle-jar',
839 + out = 'checkstyle-6.11.2-all.jar',
840 + url = 'http://onlab.vicci.org/onos/third-party/checkstyle-6.11.2-all.jar',
841 + sha1 = 'f504187b1743e73ffe72c2eede0ff57d45536b7d'
842 +)
......
1 +checkstyle_source = 'src/main/resources/onos/checkstyle.xml'
2 +suppression_source = 'src/main/resources/onos/suppressions.xml'
3 +
4 +xml = ('<module name="SuppressionFilter">'
5 + '<property name="file" value="$(location :suppressions.xml)"/>'
6 + '</module>' )
7 +cmd = "sed 's#<module name=\"Checker\">#<module name=\"Checker\">%s#' %s > $OUT" % ( xml, checkstyle_source )
8 +
9 +genrule(
10 + name = 'checkstyle-xml',
11 + srcs = [ checkstyle_source ],
12 + out = 'checkstyle.xml',
13 + bash = cmd,
14 + visibility = [ 'PUBLIC' ]
15 +)
16 +
17 +export_file(
18 + name = 'suppressions.xml',
19 + src = suppression_source,
20 +)
1 +SRC = 'src/main/java/org/onlab/**/'
2 +TEST = 'src/test/java/org/onlab/**/'
3 +CURRENT_NAME = 'onlab-osgiwrap'
4 +CURRENT_TARGET = ':' + CURRENT_NAME
5 +
6 +COMPILE_DEPS = [
7 + '//lib:guava',
8 + '//lib:bndlib',
9 + '//lib:org.apache.felix.scr.bnd'
10 +]
11 +
12 +
13 +java_library(
14 + name = CURRENT_NAME,
15 + #maven_coords = 'org.onosproject:' + CURRENT_NAME + ':' + '1.2.3',
16 + srcs = glob([SRC + '/*.java']),
17 + deps = COMPILE_DEPS,
18 + visibility = ['PUBLIC'],
19 +)
20 +
21 +java_binary(
22 + name = 'osgi-jar',
23 + deps = COMPILE_DEPS + [ ':' + CURRENT_NAME ],
24 + main_class = 'org.onlab.OSGiWrapper',
25 + visibility = [ 'PUBLIC' ]
26 +)
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<project xmlns="http://maven.apache.org/POM/4.0.0"
3 + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5 + <parent>
6 + <artifactId>onlab-utils</artifactId>
7 + <groupId>org.onosproject</groupId>
8 + <version>1.6.0-SNAPSHOT</version>
9 + </parent>
10 + <modelVersion>4.0.0</modelVersion>
11 +
12 + <artifactId>osgiwrap</artifactId>
13 + <version>0.9-SNAPSHOT</version>
14 +
15 + <dependencies>
16 + <!-- TODO update this to org.apache.felix when changes are merged upstream -->
17 + <dependency>
18 + <groupId>org.onosproject</groupId>
19 + <artifactId>org.apache.felix.scr.bnd</artifactId>
20 + <version>1.4.1-SNAPSHOT</version>
21 + </dependency>
22 +
23 + <dependency>
24 + <groupId>biz.aQute.bnd</groupId>
25 + <artifactId>biz.aQute.bndlib</artifactId>
26 + <version>3.1.0</version>
27 + </dependency>
28 + <dependency>
29 + <groupId>com.google.guava</groupId>
30 + <artifactId>guava</artifactId>
31 + <version>19.0</version>
32 + </dependency>
33 + </dependencies>
34 +</project>
...\ No newline at end of file ...\ No newline at end of file
1 +/*
2 + * Copyright 2016 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +
17 +package org.onlab.osgiwrap;
18 +
19 +import aQute.bnd.osgi.Analyzer;
20 +import aQute.bnd.osgi.Jar;
21 +import com.google.common.base.Joiner;
22 +import com.google.common.base.MoreObjects;
23 +import com.google.common.collect.Lists;
24 +import com.google.common.collect.Maps;
25 +import org.apache.felix.scrplugin.bnd.SCRDescriptorBndPlugin;
26 +
27 +import java.io.File;
28 +import java.util.Arrays;
29 +import java.util.HashSet;
30 +import java.util.List;
31 +import java.util.Map;
32 +import java.util.Objects;
33 +import java.util.Set;
34 +import java.util.jar.Manifest;
35 +
36 +/**
37 + * BND-based wrapper to convert Buck JARs to OSGi-compatible JARs.
38 + */
39 +public class OSGiWrapper {
40 +
41 + private String inputJar;
42 + private String outputJar;
43 + private List<String> classpath;
44 +
45 + private String bundleName;
46 + private String groupId;
47 + private String bundleSymbolicName;
48 + private String bundleVersion;
49 +
50 + private String bundleDescription;
51 + private String bundleLicense;
52 +
53 + private String webContext;
54 +
55 + public static void main(String[] args) {
56 +
57 + if (args.length < 7) {
58 + System.err.println("Not enough args");
59 + System.exit(1);
60 + }
61 +
62 + String jar = args[0];
63 + String output = args[1];
64 + String cp = args[2];
65 + String name = args[3];
66 + String group = args[4];
67 + String version = args[5];
68 + String license = args[6];
69 + String webContext = args[7];
70 + String desc = Joiner.on(' ').join(Arrays.copyOfRange(args, 8, args.length));
71 +
72 + OSGiWrapper wrapper = new OSGiWrapper(jar, output, cp,
73 + name, group,
74 + version, license,
75 + webContext, desc);
76 + wrapper.log(wrapper + "\n");
77 + if (!wrapper.execute()) {
78 + System.err.println("ERROR");
79 + System.exit(2);
80 + }
81 + }
82 +
83 +
84 + public OSGiWrapper(String inputJar,
85 + String outputJar,
86 + String classpath,
87 + String bundleName,
88 + String groupId,
89 + String bundleVersion,
90 + String bundleLicense,
91 + String webContext,
92 + String bundleDescription) {
93 + this.inputJar = inputJar;
94 + this.classpath = Lists.newArrayList(classpath.split(":"));
95 + if (!this.classpath.contains(inputJar)) {
96 + this.classpath.add(0, inputJar);
97 + }
98 + this.outputJar = outputJar;
99 +
100 + this.bundleName = bundleName;
101 + this.groupId = groupId;
102 + this.bundleSymbolicName = String.format("%s.%s", groupId, bundleName);
103 +
104 + this.bundleVersion = bundleVersion;
105 + this.bundleLicense = bundleLicense;
106 + this.bundleDescription = bundleDescription;
107 +
108 + this.webContext = webContext;
109 + }
110 +
111 + private void setProperties(Analyzer analyzer) {
112 + analyzer.setProperty(Analyzer.BUNDLE_NAME, bundleName);
113 + analyzer.setProperty(Analyzer.BUNDLE_SYMBOLICNAME, bundleSymbolicName);
114 + analyzer.setProperty(Analyzer.BUNDLE_VERSION, bundleVersion.replace('-', '.'));
115 +
116 + analyzer.setProperty(Analyzer.BUNDLE_DESCRIPTION, bundleDescription);
117 + analyzer.setProperty(Analyzer.BUNDLE_LICENSE, bundleLicense);
118 +
119 + //TODO consider using stricter version policy
120 + //analyzer.setProperty("-provider-policy", "${range;[===,==+)}");
121 + //analyzer.setProperty("-consumer-policy", "${range;[===,==+)}");
122 +
123 + // There are no good defaults so make sure you set the Import-Package
124 + analyzer.setProperty(Analyzer.IMPORT_PACKAGE, "*,org.glassfish.jersey.servlet");
125 +
126 + // TODO include version in export, but not in import
127 + analyzer.setProperty(Analyzer.EXPORT_PACKAGE, "*");
128 +
129 + // TODO we may need INCLUDE_RESOURCE, or that might be done by Buck
130 + //analyzer.setProperty(analyzer.INCLUDE_RESOURCE, ...)
131 + if (isWab()) {
132 + analyzer.setProperty(Analyzer.WAB, "src/main/webapp/");
133 + analyzer.setProperty("Web-ContextPath", webContext);
134 + }
135 + }
136 +
137 + public boolean execute() {
138 + Analyzer analyzer = new Analyzer();
139 + try {
140 +
141 + Jar jar = new Jar(new File(inputJar)); // where our data is
142 + analyzer.setJar(jar); // give bnd the contents
143 +
144 + // You can provide additional class path entries to allow
145 + // bnd to pickup export version from the packageinfo file,
146 + // Version annotation, or their manifests.
147 + analyzer.addClasspath(classpath);
148 +
149 + setProperties(analyzer);
150 +
151 +// analyzer.setProperty("DESTDIR");
152 +// analyzer.setBase();
153 +
154 + // ------------- let's begin... -------------------------
155 +
156 + // Analyze the target JAR first
157 + analyzer.analyze();
158 +
159 + // Scan the JAR for Felix SCR annotations and generate XML files
160 + Map<String, String> properties = Maps.newHashMap();
161 + SCRDescriptorBndPlugin scrDescriptorBndPlugin = new SCRDescriptorBndPlugin();
162 + scrDescriptorBndPlugin.setProperties(properties);
163 + scrDescriptorBndPlugin.setReporter(analyzer);
164 + scrDescriptorBndPlugin.analyzeJar(analyzer);
165 +
166 + // Repack the JAR as a WAR
167 + doWabStaging(analyzer);
168 +
169 + // Calculate the manifest
170 + Manifest manifest = analyzer.calcManifest();
171 + //OutputStream s = new FileOutputStream("/tmp/foo2.txt");
172 + //manifest.write(s);
173 + //s.close();
174 +
175 + if (analyzer.isOk()) {
176 + analyzer.getJar().setManifest(manifest);
177 + analyzer.save(new File(outputJar), true);
178 + log("Saved!\n");
179 + } else {
180 + warn("%s\n", analyzer.getErrors());
181 + return false;
182 + }
183 +
184 + analyzer.close();
185 +
186 + return true;
187 + } catch (Exception e) {
188 + e.printStackTrace();
189 + return false;
190 + }
191 + }
192 +
193 + private boolean isWab() {
194 + return !Objects.equals(webContext, "NONE");
195 + }
196 +
197 + private void doWabStaging(Analyzer analyzer) throws Exception {
198 + if (!isWab()) {
199 + return;
200 + }
201 + String wab = analyzer.getProperty(analyzer.WAB);
202 + Jar dot = analyzer.getJar();
203 +
204 + log("wab %s", wab);
205 + analyzer.setBundleClasspath("WEB-INF/classes," +
206 + analyzer.getProperty(analyzer.BUNDLE_CLASSPATH));
207 +
208 + Set<String> paths = new HashSet<String>(dot.getResources().keySet());
209 +
210 + for (String path : paths) {
211 + if (path.indexOf('/') > 0 && !Character.isUpperCase(path.charAt(0))) {
212 + log("wab: moving: %s", path);
213 + dot.rename(path, "WEB-INF/classes/" + path);
214 + }
215 + }
216 + }
217 +
218 + private void log(String format, Object... objects) {
219 + //System.err.printf(format, objects);
220 + }
221 +
222 + private void warn(String format, Object... objects) {
223 + System.err.printf(format, objects);
224 + }
225 +
226 + @Override
227 + public String toString() {
228 + return MoreObjects.toStringHelper(this)
229 + .add("inputJar", inputJar)
230 + .add("outputJar", outputJar)
231 + .add("classpath", classpath)
232 + .add("bundleName", bundleName)
233 + .add("groupId", groupId)
234 + .add("bundleSymbolicName", bundleSymbolicName)
235 + .add("bundleVersion", bundleVersion)
236 + .add("bundleDescription", bundleDescription)
237 + .add("bundleLicense", bundleLicense)
238 + .toString();
239 +
240 + }
241 +}
1 +/*
2 + * Copyright 2016 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +
17 +/**
18 + * OSGi-wrapper for raw JARs.
19 + */
20 +package org.onlab.osgiwrap;
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
41 <module>stc</module> 41 <module>stc</module>
42 <module>jdvue</module> 42 <module>jdvue</module>
43 <module>jnc</module> 43 <module>jnc</module>
44 + <module>osgiwrap</module>
44 </modules> 45 </modules>
45 46
46 <dependencies> 47 <dependencies>
......