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
168 additions
and
17 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"); |
| 221 | + } else { | ||
| 222 | + warn("Failed to create jar \n"); | ||
| 223 | + return false; | ||
| 224 | + } | ||
| 181 | } else { | 225 | } else { |
| 182 | - warn("%s\n", analyzer.getErrors()); | 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