Committed by
Gerrit Code Review
Adding src/main/webapp resources to WARs
This fixes onos-gui, so now onos-rest and onos-gui work. We also exclude duplicate resources in the output jar. Change-Id: I5fef1376a9f7e88cb7248a606e8f568f641ab45b
Showing
3 changed files
with
167 additions
and
16 deletions
1 | import random | 1 | import random |
2 | 2 | ||
3 | DEBUG_ARG='JAVA_TOOL_OPTIONS="-Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=5005,suspend=y"' | 3 | DEBUG_ARG='JAVA_TOOL_OPTIONS="-Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=5005,suspend=y"' |
4 | +FORCE_INSTALL=True | ||
5 | +NONE='NONE' | ||
4 | 6 | ||
5 | def osgi_jar( | 7 | def osgi_jar( |
6 | name, | 8 | name, |
... | @@ -12,7 +14,10 @@ def osgi_jar( | ... | @@ -12,7 +14,10 @@ def osgi_jar( |
12 | license = 'NONE', | 14 | license = 'NONE', |
13 | description = '', | 15 | description = '', |
14 | debug = False, | 16 | debug = False, |
15 | - web_context = 'NONE', | 17 | + import_packages = '*', |
18 | + export_packages = '*', | ||
19 | + include_resources = NONE, | ||
20 | + web_context = NONE, | ||
16 | **kwargs | 21 | **kwargs |
17 | ): | 22 | ): |
18 | 23 | ||
... | @@ -37,6 +42,9 @@ def osgi_jar( | ... | @@ -37,6 +42,9 @@ def osgi_jar( |
37 | group_id, #group id | 42 | group_id, #group id |
38 | version, #version | 43 | version, #version |
39 | license, #license url | 44 | license, #license url |
45 | + "'%s'" % import_packages, #packages to import | ||
46 | + "'%s'" % export_packages, #packages to export | ||
47 | + include_resources, #custom includes to classpath | ||
40 | web_context, #web context (REST API only) | 48 | web_context, #web context (REST API only) |
41 | description, #description | 49 | description, #description |
42 | ) | 50 | ) |
... | @@ -55,6 +63,7 @@ def osgi_jar( | ... | @@ -55,6 +63,7 @@ def osgi_jar( |
55 | name = osgi_jar_name, | 63 | name = osgi_jar_name, |
56 | bash = bash, | 64 | bash = bash, |
57 | out = name + '.jar', | 65 | out = name + '.jar', |
66 | + srcs = glob(['src/main/webapp/**']), | ||
58 | visibility = [], #intentially, not visible | 67 | visibility = [], #intentially, not visible |
59 | ) | 68 | ) |
60 | 69 | ||
... | @@ -89,9 +98,11 @@ def osgi_jar( | ... | @@ -89,9 +98,11 @@ def osgi_jar( |
89 | '-DartifactId=%s' % name, | 98 | '-DartifactId=%s' % name, |
90 | '-Dversion=%s' % version, | 99 | '-Dversion=%s' % version, |
91 | '-Dpackaging=jar' )) | 100 | '-Dpackaging=jar' )) |
92 | - # TODO This rule must be run every time, adding random number as rule input. | 101 | + cmd = mvn_cmd + ' > $OUT' |
93 | - # We should make this configurable, perhaps with a flag. | 102 | + if FORCE_INSTALL: |
94 | - cmd = 'FOO=%s ' % random.random() + mvn_cmd + ' > $OUT' | 103 | + # Add a random number to the command to force this rule to run. |
104 | + # TODO We should make this configurable from CLI, perhaps with a flag. | ||
105 | + cmd = 'FOO=%s ' % random.random() + cmd | ||
95 | genrule( | 106 | genrule( |
96 | name = name + '-install', | 107 | name = name + '-install', |
97 | bash = cmd, | 108 | bash = cmd, | ... | ... |
... | @@ -16,16 +16,28 @@ | ... | @@ -16,16 +16,28 @@ |
16 | 16 | ||
17 | package org.onlab.osgiwrap; | 17 | package org.onlab.osgiwrap; |
18 | 18 | ||
19 | +import aQute.bnd.header.Attrs; | ||
20 | +import aQute.bnd.header.Parameters; | ||
19 | import aQute.bnd.osgi.Analyzer; | 21 | import aQute.bnd.osgi.Analyzer; |
20 | import aQute.bnd.osgi.Builder; | 22 | import aQute.bnd.osgi.Builder; |
23 | +import aQute.bnd.osgi.FileResource; | ||
21 | import aQute.bnd.osgi.Jar; | 24 | import aQute.bnd.osgi.Jar; |
25 | +import aQute.bnd.osgi.Resource; | ||
22 | import com.google.common.base.Joiner; | 26 | import com.google.common.base.Joiner; |
23 | import com.google.common.base.MoreObjects; | 27 | import com.google.common.base.MoreObjects; |
24 | import com.google.common.collect.Lists; | 28 | import com.google.common.collect.Lists; |
25 | import com.google.common.collect.Maps; | 29 | import com.google.common.collect.Maps; |
30 | +import com.google.common.collect.Sets; | ||
26 | import org.apache.felix.scrplugin.bnd.SCRDescriptorBndPlugin; | 31 | import org.apache.felix.scrplugin.bnd.SCRDescriptorBndPlugin; |
27 | 32 | ||
28 | import java.io.File; | 33 | import java.io.File; |
34 | +import java.io.IOException; | ||
35 | +import java.nio.file.FileVisitResult; | ||
36 | +import java.nio.file.FileVisitor; | ||
37 | +import java.nio.file.Path; | ||
38 | +import java.nio.file.Paths; | ||
39 | +import java.nio.file.SimpleFileVisitor; | ||
40 | +import java.nio.file.attribute.BasicFileAttributes; | ||
29 | import java.util.Arrays; | 41 | import java.util.Arrays; |
30 | import java.util.HashSet; | 42 | import java.util.HashSet; |
31 | import java.util.List; | 43 | import java.util.List; |
... | @@ -34,10 +46,13 @@ import java.util.Objects; | ... | @@ -34,10 +46,13 @@ import java.util.Objects; |
34 | import java.util.Set; | 46 | import java.util.Set; |
35 | import java.util.jar.Manifest; | 47 | import java.util.jar.Manifest; |
36 | 48 | ||
49 | +import static java.nio.file.Files.walkFileTree; | ||
50 | + | ||
37 | /** | 51 | /** |
38 | * BND-based wrapper to convert Buck JARs to OSGi-compatible JARs. | 52 | * BND-based wrapper to convert Buck JARs to OSGi-compatible JARs. |
39 | */ | 53 | */ |
40 | public class OSGiWrapper { | 54 | public class OSGiWrapper { |
55 | + private static final String NONE = "NONE"; | ||
41 | 56 | ||
42 | private String inputJar; | 57 | private String inputJar; |
43 | private String outputJar; | 58 | private String outputJar; |
... | @@ -48,14 +63,18 @@ public class OSGiWrapper { | ... | @@ -48,14 +63,18 @@ public class OSGiWrapper { |
48 | private String bundleSymbolicName; | 63 | private String bundleSymbolicName; |
49 | private String bundleVersion; | 64 | private String bundleVersion; |
50 | 65 | ||
66 | + private String importPackages; | ||
67 | + private String exportPackages; | ||
68 | + private String includeResources; | ||
69 | + private Set<String> includedResources = Sets.newHashSet(); | ||
70 | + | ||
51 | private String bundleDescription; | 71 | private String bundleDescription; |
52 | private String bundleLicense; | 72 | private String bundleLicense; |
53 | 73 | ||
54 | private String webContext; | 74 | private String webContext; |
55 | 75 | ||
56 | public static void main(String[] args) { | 76 | public static void main(String[] args) { |
57 | - | 77 | + if (args.length < 10) { |
58 | - if (args.length < 7) { | ||
59 | System.err.println("Not enough args"); | 78 | System.err.println("Not enough args"); |
60 | System.exit(1); | 79 | System.exit(1); |
61 | } | 80 | } |
... | @@ -67,16 +86,21 @@ public class OSGiWrapper { | ... | @@ -67,16 +86,21 @@ public class OSGiWrapper { |
67 | String group = args[4]; | 86 | String group = args[4]; |
68 | String version = args[5]; | 87 | String version = args[5]; |
69 | String license = args[6]; | 88 | String license = args[6]; |
70 | - String webContext = args[7]; | 89 | + String importPackages = args[7]; |
71 | - String desc = Joiner.on(' ').join(Arrays.copyOfRange(args, 8, args.length)); | 90 | + String exportPackages = args[8]; |
91 | + String includeResources = args[9]; | ||
92 | + String webContext = args[10]; | ||
93 | + String desc = Joiner.on(' ').join(Arrays.copyOfRange(args, 11, args.length)); | ||
72 | 94 | ||
73 | OSGiWrapper wrapper = new OSGiWrapper(jar, output, cp, | 95 | OSGiWrapper wrapper = new OSGiWrapper(jar, output, cp, |
74 | name, group, | 96 | name, group, |
75 | version, license, | 97 | version, license, |
98 | + importPackages, exportPackages, | ||
99 | + includeResources, | ||
76 | webContext, desc); | 100 | webContext, desc); |
77 | wrapper.log(wrapper + "\n"); | 101 | wrapper.log(wrapper + "\n"); |
78 | if (!wrapper.execute()) { | 102 | if (!wrapper.execute()) { |
79 | - System.err.println("ERROR"); | 103 | + System.err.printf("Error generating %s\n", name); |
80 | System.exit(2); | 104 | System.exit(2); |
81 | } | 105 | } |
82 | } | 106 | } |
... | @@ -89,6 +113,9 @@ public class OSGiWrapper { | ... | @@ -89,6 +113,9 @@ public class OSGiWrapper { |
89 | String groupId, | 113 | String groupId, |
90 | String bundleVersion, | 114 | String bundleVersion, |
91 | String bundleLicense, | 115 | String bundleLicense, |
116 | + String importPackages, | ||
117 | + String exportPackages, | ||
118 | + String includeResources, | ||
92 | String webContext, | 119 | String webContext, |
93 | String bundleDescription) { | 120 | String bundleDescription) { |
94 | this.inputJar = inputJar; | 121 | this.inputJar = inputJar; |
... | @@ -106,6 +133,12 @@ public class OSGiWrapper { | ... | @@ -106,6 +133,12 @@ public class OSGiWrapper { |
106 | this.bundleLicense = bundleLicense; | 133 | this.bundleLicense = bundleLicense; |
107 | this.bundleDescription = bundleDescription; | 134 | this.bundleDescription = bundleDescription; |
108 | 135 | ||
136 | + this.importPackages = importPackages; | ||
137 | + this.exportPackages = exportPackages; | ||
138 | + if (!Objects.equals(includeResources, NONE)) { | ||
139 | + this.includeResources = includeResources; | ||
140 | + } | ||
141 | + | ||
109 | this.webContext = webContext; | 142 | this.webContext = webContext; |
110 | } | 143 | } |
111 | 144 | ||
... | @@ -122,17 +155,20 @@ public class OSGiWrapper { | ... | @@ -122,17 +155,20 @@ public class OSGiWrapper { |
122 | //analyzer.setProperty("-consumer-policy", "${range;[===,==+)}"); | 155 | //analyzer.setProperty("-consumer-policy", "${range;[===,==+)}"); |
123 | 156 | ||
124 | // There are no good defaults so make sure you set the Import-Package | 157 | // There are no good defaults so make sure you set the Import-Package |
125 | - analyzer.setProperty(Analyzer.IMPORT_PACKAGE, "*"); | 158 | + analyzer.setProperty(Analyzer.IMPORT_PACKAGE, importPackages); |
126 | 159 | ||
127 | // TODO include version in export, but not in import | 160 | // TODO include version in export, but not in import |
128 | - analyzer.setProperty(Analyzer.EXPORT_PACKAGE, "*"); | 161 | + analyzer.setProperty(Analyzer.EXPORT_PACKAGE, exportPackages); |
129 | 162 | ||
130 | // TODO we may need INCLUDE_RESOURCE, or that might be done by Buck | 163 | // TODO we may need INCLUDE_RESOURCE, or that might be done by Buck |
131 | - //analyzer.setProperty(analyzer.INCLUDE_RESOURCE, ...) | 164 | + if (includeResources != null) { |
165 | + analyzer.setProperty(Analyzer.INCLUDE_RESOURCE, includeResources); | ||
166 | + } | ||
167 | + | ||
132 | if (isWab()) { | 168 | if (isWab()) { |
133 | analyzer.setProperty(Analyzer.WAB, "src/main/webapp/"); | 169 | analyzer.setProperty(Analyzer.WAB, "src/main/webapp/"); |
134 | analyzer.setProperty("Web-ContextPath", webContext); | 170 | analyzer.setProperty("Web-ContextPath", webContext); |
135 | - analyzer.setProperty(Analyzer.IMPORT_PACKAGE, "*,org.glassfish.jersey.servlet"); | 171 | + analyzer.setProperty(Analyzer.IMPORT_PACKAGE, "*,org.glassfish.jersey.servlet,org.jvnet.mimepull\n"); |
136 | } | 172 | } |
137 | } | 173 | } |
138 | 174 | ||
... | @@ -165,6 +201,10 @@ public class OSGiWrapper { | ... | @@ -165,6 +201,10 @@ public class OSGiWrapper { |
165 | scrDescriptorBndPlugin.setReporter(analyzer); | 201 | scrDescriptorBndPlugin.setReporter(analyzer); |
166 | scrDescriptorBndPlugin.analyzeJar(analyzer); | 202 | scrDescriptorBndPlugin.analyzeJar(analyzer); |
167 | 203 | ||
204 | + if (includeResources != null) { | ||
205 | + doIncludeResources(analyzer); | ||
206 | + } | ||
207 | + | ||
168 | // Repack the JAR as a WAR | 208 | // Repack the JAR as a WAR |
169 | doWabStaging(analyzer); | 209 | doWabStaging(analyzer); |
170 | 210 | ||
... | @@ -176,10 +216,14 @@ public class OSGiWrapper { | ... | @@ -176,10 +216,14 @@ public class OSGiWrapper { |
176 | 216 | ||
177 | if (analyzer.isOk()) { | 217 | if (analyzer.isOk()) { |
178 | analyzer.getJar().setManifest(manifest); | 218 | analyzer.getJar().setManifest(manifest); |
179 | - analyzer.save(new File(outputJar), true); | 219 | + if (analyzer.save(new File(outputJar), true)) { |
180 | log("Saved!\n"); | 220 | log("Saved!\n"); |
181 | } else { | 221 | } else { |
182 | - warn("%s\n", analyzer.getErrors()); | 222 | + warn("Failed to create jar \n"); |
223 | + return false; | ||
224 | + } | ||
225 | + } else { | ||
226 | + warn("Analyzer Errors:\n%s\n", analyzer.getErrors()); | ||
183 | return false; | 227 | return false; |
184 | } | 228 | } |
185 | 229 | ||
... | @@ -193,7 +237,7 @@ public class OSGiWrapper { | ... | @@ -193,7 +237,7 @@ public class OSGiWrapper { |
193 | } | 237 | } |
194 | 238 | ||
195 | private boolean isWab() { | 239 | private boolean isWab() { |
196 | - return !Objects.equals(webContext, "NONE"); | 240 | + return !Objects.equals(webContext, NONE); |
197 | } | 241 | } |
198 | 242 | ||
199 | private void doWabStaging(Analyzer analyzer) throws Exception { | 243 | private void doWabStaging(Analyzer analyzer) throws Exception { |
... | @@ -215,6 +259,88 @@ public class OSGiWrapper { | ... | @@ -215,6 +259,88 @@ public class OSGiWrapper { |
215 | dot.rename(path, "WEB-INF/classes/" + path); | 259 | dot.rename(path, "WEB-INF/classes/" + path); |
216 | } | 260 | } |
217 | } | 261 | } |
262 | + | ||
263 | + Path wabRoot = Paths.get(wab); | ||
264 | + includeFiles(dot, null, wabRoot.toString()); | ||
265 | + } | ||
266 | + | ||
267 | + /** | ||
268 | + * Parse the Bundle-Includes header. Files in the bundles Include header are | ||
269 | + * included in the jar. The source can be a directory or a file. | ||
270 | + * | ||
271 | + * @throws Exception | ||
272 | + */ | ||
273 | + private void doIncludeResources(Analyzer analyzer) throws Exception { | ||
274 | + String includes = analyzer.getProperty(Analyzer.INCLUDE_RESOURCE); | ||
275 | + if (includes == null) { | ||
276 | + return; | ||
277 | + } | ||
278 | + Parameters clauses = analyzer.parseHeader(includes); | ||
279 | + Jar jar = analyzer.getJar(); | ||
280 | + | ||
281 | + for (Map.Entry<String, Attrs> entry : clauses.entrySet()) { | ||
282 | + String name = entry.getKey(); | ||
283 | + Map<String, String> extra = entry.getValue(); | ||
284 | + // TODO consider doing something with extras | ||
285 | + | ||
286 | + String[] parts = name.split("\\s*=\\s*"); | ||
287 | + String source = parts[0]; | ||
288 | + String destination = parts[0]; | ||
289 | + if (parts.length == 2) { | ||
290 | + source = parts[1]; | ||
291 | + } | ||
292 | + | ||
293 | + includeFiles(jar, destination, source); | ||
294 | + } | ||
295 | + } | ||
296 | + | ||
297 | + private void includeFiles(Jar jar, String destinationRoot, String sourceRoot) | ||
298 | + throws IOException { | ||
299 | + Path sourceRootPath = Paths.get(sourceRoot); | ||
300 | + // iterate through sources | ||
301 | + // put each source on the jar | ||
302 | + FileVisitor<Path> visitor = new SimpleFileVisitor<Path>() { | ||
303 | + @Override | ||
304 | + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { | ||
305 | + Path relativePath = sourceRootPath.relativize(file); | ||
306 | + String destination = destinationRoot != null ? | ||
307 | + destinationRoot + "/" + relativePath.toString() : //TODO | ||
308 | + relativePath.toString(); | ||
309 | + | ||
310 | + addFileToJar(jar, destination, file.toAbsolutePath().toString()); | ||
311 | + return FileVisitResult.CONTINUE; | ||
312 | + } | ||
313 | + }; | ||
314 | + File dir = new File(sourceRoot); | ||
315 | + if (dir.isFile()) { | ||
316 | + addFileToJar(jar, destinationRoot, dir.getAbsolutePath()); | ||
317 | + } else if (dir.isDirectory()) { | ||
318 | + walkFileTree(sourceRootPath, visitor); | ||
319 | + } else { | ||
320 | + warn("Skipping resource in bundle %s: %s (File Not Found)\n", | ||
321 | + bundleSymbolicName, sourceRoot); | ||
322 | + } | ||
323 | + } | ||
324 | + | ||
325 | + private boolean addFileToJar(Jar jar, String destination, String sourceAbsPath) { | ||
326 | + if (includedResources.contains(sourceAbsPath)) { | ||
327 | + log("Skipping already included resource: %s\n", sourceAbsPath); | ||
328 | + return false; | ||
329 | + } | ||
330 | + File file = new File(sourceAbsPath); | ||
331 | + if (!file.isFile()) { | ||
332 | + throw new RuntimeException( | ||
333 | + String.format("Skipping non-existent file: %s\n", sourceAbsPath)); | ||
334 | + } | ||
335 | + Resource resource = new FileResource(file); | ||
336 | + if (jar.getResource(destination) != null) { | ||
337 | + warn("Skipping duplicate resource: %s\n", destination); | ||
338 | + return false; | ||
339 | + } | ||
340 | + jar.putResource(destination, resource); | ||
341 | + includedResources.add(sourceAbsPath); | ||
342 | + log("Adding resource: %s\n", destination); | ||
343 | + return true; | ||
218 | } | 344 | } |
219 | 345 | ||
220 | private void log(String format, Object... objects) { | 346 | private void log(String format, Object... objects) { | ... | ... |
... | @@ -22,6 +22,17 @@ TEST_DEPS = [ | ... | @@ -22,6 +22,17 @@ TEST_DEPS = [ |
22 | '//lib:TEST', | 22 | '//lib:TEST', |
23 | ] | 23 | ] |
24 | 24 | ||
25 | +RESOURCES = [ | ||
26 | + 'WEB-INF/classes/index.html=src/main/webapp/index.html', | ||
27 | + 'WEB-INF/classes/login.html=src/main/webapp/login.html', | ||
28 | + 'WEB-INF/classes/error.html=src/main/webapp/error.html', | ||
29 | + 'WEB-INF/classes/not-ready.html=src/main/webapp/not-ready.html', | ||
30 | + 'WEB-INF/classes/onos.js=src/main/webapp/onos.js', | ||
31 | + 'WEB-INF/classes/nav.html=src/main/webapp/nav.html', | ||
32 | + 'WEB-INF/classes/app/view=src/main/webapp/app/view', | ||
33 | + 'WEB-INF/classes/raw=src/main/webapp/raw', | ||
34 | +] | ||
35 | + | ||
25 | osgi_jar( | 36 | osgi_jar( |
26 | name = CURRENT_NAME, | 37 | name = CURRENT_NAME, |
27 | srcs = glob([SRC + '/*.java']), | 38 | srcs = glob([SRC + '/*.java']), |
... | @@ -29,6 +40,9 @@ osgi_jar( | ... | @@ -29,6 +40,9 @@ osgi_jar( |
29 | resources_root = RESOURCES_ROOT, | 40 | resources_root = RESOURCES_ROOT, |
30 | deps = COMPILE_DEPS, | 41 | deps = COMPILE_DEPS, |
31 | visibility = ['PUBLIC'], | 42 | visibility = ['PUBLIC'], |
43 | + include_resources = ','.join(RESOURCES), | ||
44 | + web_context = '/onos/ui', | ||
45 | + debug = False, | ||
32 | ) | 46 | ) |
33 | 47 | ||
34 | java_test( | 48 | java_test( | ... | ... |
-
Please register or login to post a comment