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
diff --git a/bucklets/onos.bucklet b/bucklets/onos.bucklet
index ee4b17d..ba2ed17 100644
--- a/bucklets/onos.bucklet
+++ b/bucklets/onos.bucklet
@@ -1,6 +1,8 @@
import random
DEBUG_ARG='JAVA_TOOL_OPTIONS="-Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=5005,suspend=y"'
+FORCE_INSTALL=True
+NONE='NONE'
def osgi_jar(
name,
@@ -12,7 +14,10 @@
license = 'NONE',
description = '',
debug = False,
- web_context = 'NONE',
+ import_packages = '*',
+ export_packages = '*',
+ include_resources = NONE,
+ web_context = NONE,
**kwargs
):
@@ -37,6 +42,9 @@
group_id, #group id
version, #version
license, #license url
+ "'%s'" % import_packages, #packages to import
+ "'%s'" % export_packages, #packages to export
+ include_resources, #custom includes to classpath
web_context, #web context (REST API only)
description, #description
)
@@ -55,6 +63,7 @@
name = osgi_jar_name,
bash = bash,
out = name + '.jar',
+ srcs = glob(['src/main/webapp/**']),
visibility = [], #intentially, not visible
)
@@ -89,9 +98,11 @@
'-DartifactId=%s' % name,
'-Dversion=%s' % version,
'-Dpackaging=jar' ))
- # TODO This rule must be run every time, adding random number as rule input.
- # We should make this configurable, perhaps with a flag.
- cmd = 'FOO=%s ' % random.random() + mvn_cmd + ' > $OUT'
+ cmd = mvn_cmd + ' > $OUT'
+ if FORCE_INSTALL:
+ # Add a random number to the command to force this rule to run.
+ # TODO We should make this configurable from CLI, perhaps with a flag.
+ cmd = 'FOO=%s ' % random.random() + cmd
genrule(
name = name + '-install',
bash = cmd,
diff --git a/utils/osgiwrap/src/main/java/org/onlab/osgiwrap/OSGiWrapper.java b/utils/osgiwrap/src/main/java/org/onlab/osgiwrap/OSGiWrapper.java
index 69d61df..6416de1 100644
--- a/utils/osgiwrap/src/main/java/org/onlab/osgiwrap/OSGiWrapper.java
+++ b/utils/osgiwrap/src/main/java/org/onlab/osgiwrap/OSGiWrapper.java
@@ -16,16 +16,28 @@
package org.onlab.osgiwrap;
+import aQute.bnd.header.Attrs;
+import aQute.bnd.header.Parameters;
import aQute.bnd.osgi.Analyzer;
import aQute.bnd.osgi.Builder;
+import aQute.bnd.osgi.FileResource;
import aQute.bnd.osgi.Jar;
+import aQute.bnd.osgi.Resource;
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 com.google.common.collect.Sets;
import org.apache.felix.scrplugin.bnd.SCRDescriptorBndPlugin;
import java.io.File;
+import java.io.IOException;
+import java.nio.file.FileVisitResult;
+import java.nio.file.FileVisitor;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
@@ -34,10 +46,13 @@
import java.util.Set;
import java.util.jar.Manifest;
+import static java.nio.file.Files.walkFileTree;
+
/**
* BND-based wrapper to convert Buck JARs to OSGi-compatible JARs.
*/
public class OSGiWrapper {
+ private static final String NONE = "NONE";
private String inputJar;
private String outputJar;
@@ -48,14 +63,18 @@
private String bundleSymbolicName;
private String bundleVersion;
+ private String importPackages;
+ private String exportPackages;
+ private String includeResources;
+ private Set<String> includedResources = Sets.newHashSet();
+
private String bundleDescription;
private String bundleLicense;
private String webContext;
public static void main(String[] args) {
-
- if (args.length < 7) {
+ if (args.length < 10) {
System.err.println("Not enough args");
System.exit(1);
}
@@ -67,16 +86,21 @@
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));
+ String importPackages = args[7];
+ String exportPackages = args[8];
+ String includeResources = args[9];
+ String webContext = args[10];
+ String desc = Joiner.on(' ').join(Arrays.copyOfRange(args, 11, args.length));
OSGiWrapper wrapper = new OSGiWrapper(jar, output, cp,
name, group,
version, license,
+ importPackages, exportPackages,
+ includeResources,
webContext, desc);
wrapper.log(wrapper + "\n");
if (!wrapper.execute()) {
- System.err.println("ERROR");
+ System.err.printf("Error generating %s\n", name);
System.exit(2);
}
}
@@ -89,6 +113,9 @@
String groupId,
String bundleVersion,
String bundleLicense,
+ String importPackages,
+ String exportPackages,
+ String includeResources,
String webContext,
String bundleDescription) {
this.inputJar = inputJar;
@@ -106,6 +133,12 @@
this.bundleLicense = bundleLicense;
this.bundleDescription = bundleDescription;
+ this.importPackages = importPackages;
+ this.exportPackages = exportPackages;
+ if (!Objects.equals(includeResources, NONE)) {
+ this.includeResources = includeResources;
+ }
+
this.webContext = webContext;
}
@@ -122,17 +155,20 @@
//analyzer.setProperty("-consumer-policy", "${range;[===,==+)}");
// There are no good defaults so make sure you set the Import-Package
- analyzer.setProperty(Analyzer.IMPORT_PACKAGE, "*");
+ analyzer.setProperty(Analyzer.IMPORT_PACKAGE, importPackages);
// TODO include version in export, but not in import
- analyzer.setProperty(Analyzer.EXPORT_PACKAGE, "*");
+ analyzer.setProperty(Analyzer.EXPORT_PACKAGE, exportPackages);
// TODO we may need INCLUDE_RESOURCE, or that might be done by Buck
- //analyzer.setProperty(analyzer.INCLUDE_RESOURCE, ...)
+ if (includeResources != null) {
+ analyzer.setProperty(Analyzer.INCLUDE_RESOURCE, includeResources);
+ }
+
if (isWab()) {
analyzer.setProperty(Analyzer.WAB, "src/main/webapp/");
analyzer.setProperty("Web-ContextPath", webContext);
- analyzer.setProperty(Analyzer.IMPORT_PACKAGE, "*,org.glassfish.jersey.servlet");
+ analyzer.setProperty(Analyzer.IMPORT_PACKAGE, "*,org.glassfish.jersey.servlet,org.jvnet.mimepull\n");
}
}
@@ -165,6 +201,10 @@
scrDescriptorBndPlugin.setReporter(analyzer);
scrDescriptorBndPlugin.analyzeJar(analyzer);
+ if (includeResources != null) {
+ doIncludeResources(analyzer);
+ }
+
// Repack the JAR as a WAR
doWabStaging(analyzer);
@@ -176,10 +216,14 @@
if (analyzer.isOk()) {
analyzer.getJar().setManifest(manifest);
- analyzer.save(new File(outputJar), true);
- log("Saved!\n");
+ if (analyzer.save(new File(outputJar), true)) {
+ log("Saved!\n");
+ } else {
+ warn("Failed to create jar \n");
+ return false;
+ }
} else {
- warn("%s\n", analyzer.getErrors());
+ warn("Analyzer Errors:\n%s\n", analyzer.getErrors());
return false;
}
@@ -193,7 +237,7 @@
}
private boolean isWab() {
- return !Objects.equals(webContext, "NONE");
+ return !Objects.equals(webContext, NONE);
}
private void doWabStaging(Analyzer analyzer) throws Exception {
@@ -215,6 +259,88 @@
dot.rename(path, "WEB-INF/classes/" + path);
}
}
+
+ Path wabRoot = Paths.get(wab);
+ includeFiles(dot, null, wabRoot.toString());
+ }
+
+ /**
+ * Parse the Bundle-Includes header. Files in the bundles Include header are
+ * included in the jar. The source can be a directory or a file.
+ *
+ * @throws Exception
+ */
+ private void doIncludeResources(Analyzer analyzer) throws Exception {
+ String includes = analyzer.getProperty(Analyzer.INCLUDE_RESOURCE);
+ if (includes == null) {
+ return;
+ }
+ Parameters clauses = analyzer.parseHeader(includes);
+ Jar jar = analyzer.getJar();
+
+ for (Map.Entry<String, Attrs> entry : clauses.entrySet()) {
+ String name = entry.getKey();
+ Map<String, String> extra = entry.getValue();
+ // TODO consider doing something with extras
+
+ String[] parts = name.split("\\s*=\\s*");
+ String source = parts[0];
+ String destination = parts[0];
+ if (parts.length == 2) {
+ source = parts[1];
+ }
+
+ includeFiles(jar, destination, source);
+ }
+ }
+
+ private void includeFiles(Jar jar, String destinationRoot, String sourceRoot)
+ throws IOException {
+ Path sourceRootPath = Paths.get(sourceRoot);
+ // iterate through sources
+ // put each source on the jar
+ FileVisitor<Path> visitor = new SimpleFileVisitor<Path>() {
+ @Override
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+ Path relativePath = sourceRootPath.relativize(file);
+ String destination = destinationRoot != null ?
+ destinationRoot + "/" + relativePath.toString() : //TODO
+ relativePath.toString();
+
+ addFileToJar(jar, destination, file.toAbsolutePath().toString());
+ return FileVisitResult.CONTINUE;
+ }
+ };
+ File dir = new File(sourceRoot);
+ if (dir.isFile()) {
+ addFileToJar(jar, destinationRoot, dir.getAbsolutePath());
+ } else if (dir.isDirectory()) {
+ walkFileTree(sourceRootPath, visitor);
+ } else {
+ warn("Skipping resource in bundle %s: %s (File Not Found)\n",
+ bundleSymbolicName, sourceRoot);
+ }
+ }
+
+ private boolean addFileToJar(Jar jar, String destination, String sourceAbsPath) {
+ if (includedResources.contains(sourceAbsPath)) {
+ log("Skipping already included resource: %s\n", sourceAbsPath);
+ return false;
+ }
+ File file = new File(sourceAbsPath);
+ if (!file.isFile()) {
+ throw new RuntimeException(
+ String.format("Skipping non-existent file: %s\n", sourceAbsPath));
+ }
+ Resource resource = new FileResource(file);
+ if (jar.getResource(destination) != null) {
+ warn("Skipping duplicate resource: %s\n", destination);
+ return false;
+ }
+ jar.putResource(destination, resource);
+ includedResources.add(sourceAbsPath);
+ log("Adding resource: %s\n", destination);
+ return true;
}
private void log(String format, Object... objects) {
diff --git a/web/gui/BUCK b/web/gui/BUCK
index 12ffbd0..b1a9a7c 100644
--- a/web/gui/BUCK
+++ b/web/gui/BUCK
@@ -22,6 +22,17 @@
'//lib:TEST',
]
+RESOURCES = [
+ 'WEB-INF/classes/index.html=src/main/webapp/index.html',
+ 'WEB-INF/classes/login.html=src/main/webapp/login.html',
+ 'WEB-INF/classes/error.html=src/main/webapp/error.html',
+ 'WEB-INF/classes/not-ready.html=src/main/webapp/not-ready.html',
+ 'WEB-INF/classes/onos.js=src/main/webapp/onos.js',
+ 'WEB-INF/classes/nav.html=src/main/webapp/nav.html',
+ 'WEB-INF/classes/app/view=src/main/webapp/app/view',
+ 'WEB-INF/classes/raw=src/main/webapp/raw',
+]
+
osgi_jar(
name = CURRENT_NAME,
srcs = glob([SRC + '/*.java']),
@@ -29,6 +40,9 @@
resources_root = RESOURCES_ROOT,
deps = COMPILE_DEPS,
visibility = ['PUBLIC'],
+ include_resources = ','.join(RESOURCES),
+ web_context = '/onos/ui',
+ debug = False,
)
java_test(