Jonathan Hart
Committed by Gerrit Code Review

ONOS maven plugin can substitute any propertiesdefined in the pom

in the generated files.

Change-Id: I528a693450211c74435530034c87b2545b2f7c1c
...@@ -19,7 +19,6 @@ import com.google.common.collect.ImmutableList; ...@@ -19,7 +19,6 @@ import com.google.common.collect.ImmutableList;
19 import org.apache.commons.configuration.ConfigurationException; 19 import org.apache.commons.configuration.ConfigurationException;
20 import org.apache.commons.configuration.XMLConfiguration; 20 import org.apache.commons.configuration.XMLConfiguration;
21 import org.apache.commons.io.FileUtils; 21 import org.apache.commons.io.FileUtils;
22 -import org.apache.commons.lang.StringUtils;
23 import org.apache.maven.artifact.repository.ArtifactRepository; 22 import org.apache.maven.artifact.repository.ArtifactRepository;
24 import org.apache.maven.plugin.AbstractMojo; 23 import org.apache.maven.plugin.AbstractMojo;
25 import org.apache.maven.plugin.MojoExecutionException; 24 import org.apache.maven.plugin.MojoExecutionException;
...@@ -30,24 +29,25 @@ import org.apache.maven.plugins.annotations.Parameter; ...@@ -30,24 +29,25 @@ import org.apache.maven.plugins.annotations.Parameter;
30 import org.apache.maven.project.MavenProject; 29 import org.apache.maven.project.MavenProject;
31 import org.apache.maven.project.MavenProjectHelper; 30 import org.apache.maven.project.MavenProjectHelper;
32 31
33 -import javax.imageio.ImageIO;
34 -import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
35 -import java.awt.image.BufferedImage;
36 -import java.awt.image.DataBufferByte;
37 -import java.awt.image.WritableRaster;
38 import java.io.File; 32 import java.io.File;
39 import java.io.FileInputStream; 33 import java.io.FileInputStream;
40 import java.io.FileNotFoundException; 34 import java.io.FileNotFoundException;
41 import java.io.FileOutputStream; 35 import java.io.FileOutputStream;
42 import java.io.IOException; 36 import java.io.IOException;
43 import java.io.InputStream; 37 import java.io.InputStream;
38 +import java.util.HashMap;
44 import java.util.List; 39 import java.util.List;
40 +import java.util.Map;
45 import java.util.stream.Collectors; 41 import java.util.stream.Collectors;
46 import java.util.zip.ZipEntry; 42 import java.util.zip.ZipEntry;
47 import java.util.zip.ZipOutputStream; 43 import java.util.zip.ZipOutputStream;
48 44
45 +import static com.google.common.base.Preconditions.checkArgument;
49 import static com.google.common.io.ByteStreams.toByteArray; 46 import static com.google.common.io.ByteStreams.toByteArray;
50 -import static org.codehaus.plexus.util.FileUtils.*; 47 +import static org.codehaus.plexus.util.FileUtils.copyFile;
48 +import static org.codehaus.plexus.util.FileUtils.fileRead;
49 +import static org.codehaus.plexus.util.FileUtils.fileWrite;
50 +import static org.codehaus.plexus.util.FileUtils.forceMkdir;
51 51
52 /** 52 /**
53 * Produces ONOS application archive using the app.xml file information. 53 * Produces ONOS application archive using the app.xml file information.
...@@ -77,6 +77,11 @@ public class OnosAppMojo extends AbstractMojo { ...@@ -77,6 +77,11 @@ public class OnosAppMojo extends AbstractMojo {
77 private static final String ONOS_APP_TITLE = "onos.app.title"; 77 private static final String ONOS_APP_TITLE = "onos.app.title";
78 private static final String ONOS_APP_README = "onos.app.readme"; 78 private static final String ONOS_APP_README = "onos.app.readme";
79 79
80 + private static final String PROJECT_GROUP_ID = "project.groupId";
81 + private static final String PROJECT_ARTIFACT_ID = "project.artifactId";
82 + private static final String PROJECT_VERSION = "project.version";
83 + private static final String PROJECT_DESCRIPTION = "project.description";
84 +
80 private static final String JAR = "jar"; 85 private static final String JAR = "jar";
81 private static final String XML = "xml"; 86 private static final String XML = "xml";
82 private static final String APP_ZIP = "oar"; 87 private static final String APP_ZIP = "oar";
...@@ -93,6 +98,9 @@ public class OnosAppMojo extends AbstractMojo { ...@@ -93,6 +98,9 @@ public class OnosAppMojo extends AbstractMojo {
93 private static final String DEFAULT_ARTIFACT = 98 private static final String DEFAULT_ARTIFACT =
94 "mvn:${project.groupId}/${project.artifactId}/${project.version}"; 99 "mvn:${project.groupId}/${project.artifactId}/${project.version}";
95 100
101 + private static final String PROP_START = "${";
102 + private static final String PROP_END = "}";
103 +
96 private static final int BUFFER_SIZE = 8192; 104 private static final int BUFFER_SIZE = 8192;
97 105
98 private String name; 106 private String name;
...@@ -160,6 +168,7 @@ public class OnosAppMojo extends AbstractMojo { ...@@ -160,6 +168,7 @@ public class OnosAppMojo extends AbstractMojo {
160 private File m2Directory; 168 private File m2Directory;
161 protected File stageDirectory; 169 protected File stageDirectory;
162 protected String projectPath; 170 protected String projectPath;
171 + private Map<String, String> properties;
163 172
164 @Override 173 @Override
165 public void execute() throws MojoExecutionException { 174 public void execute() throws MojoExecutionException {
...@@ -199,15 +208,17 @@ public class OnosAppMojo extends AbstractMojo { ...@@ -199,15 +208,17 @@ public class OnosAppMojo extends AbstractMojo {
199 readme = (String) project.getProperties().get(ONOS_APP_README); 208 readme = (String) project.getProperties().get(ONOS_APP_README);
200 readme = readme != null ? readme : projectDescription; 209 readme = readme != null ? readme : projectDescription;
201 210
211 + properties = buildProperties();
212 +
202 if (appFile.exists()) { 213 if (appFile.exists()) {
203 loadAppFile(appFile); 214 loadAppFile(appFile);
204 } else { 215 } else {
205 - artifacts = ImmutableList.of(eval(DEFAULT_ARTIFACT)); 216 + artifacts = ImmutableList.of(expand(DEFAULT_ARTIFACT));
206 } 217 }
207 218
208 // If there are any artifacts, stage the 219 // If there are any artifacts, stage the
209 if (!artifacts.isEmpty()) { 220 if (!artifacts.isEmpty()) {
210 - getLog().info("Building ONOS application package for " + name + " (v" + eval(version) + ")"); 221 + getLog().info("Building ONOS application package for " + name + " (v" + expand(version) + ")");
211 artifacts.forEach(a -> getLog().debug("Including artifact: " + a)); 222 artifacts.forEach(a -> getLog().debug("Including artifact: " + a));
212 223
213 if (stageDirectory.exists() || stageDirectory.mkdirs()) { 224 if (stageDirectory.exists() || stageDirectory.mkdirs()) {
...@@ -222,6 +233,24 @@ public class OnosAppMojo extends AbstractMojo { ...@@ -222,6 +233,24 @@ public class OnosAppMojo extends AbstractMojo {
222 } 233 }
223 } 234 }
224 235
236 + // Sets up a properties dictionary with the properties from the POM file,
237 + // some of which have been sanitized with nice defaults
238 + private Map<String, String> buildProperties() {
239 + Map<String, String> properties = new HashMap();
240 + project.getProperties().forEach((k, v) -> properties.put((String) k, (String) v));
241 + properties.put(PROJECT_GROUP_ID, projectGroupId);
242 + properties.put(PROJECT_ARTIFACT_ID, projectArtifactId);
243 + properties.put(PROJECT_VERSION, projectVersion);
244 + properties.put(PROJECT_DESCRIPTION, readme);
245 + properties.put(ONOS_APP_ORIGIN, origin);
246 + properties.put(ONOS_APP_REQUIRES, requiredApps);
247 + properties.put(ONOS_APP_CATEGORY, category);
248 + properties.put(ONOS_APP_URL, url);
249 + properties.put(ONOS_APP_TITLE, title);
250 + properties.put(ONOS_APP_README, readme);
251 + return properties;
252 + }
253 +
225 // Loads the app.xml file. 254 // Loads the app.xml file.
226 private void loadAppFile(File appFile) throws MojoExecutionException { 255 private void loadAppFile(File appFile) throws MojoExecutionException {
227 XMLConfiguration xml = new XMLConfiguration(); 256 XMLConfiguration xml = new XMLConfiguration();
...@@ -233,11 +262,11 @@ public class OnosAppMojo extends AbstractMojo { ...@@ -233,11 +262,11 @@ public class OnosAppMojo extends AbstractMojo {
233 xml.setDelimiterParsingDisabled(true); 262 xml.setDelimiterParsingDisabled(true);
234 263
235 name = xml.getString(NAME); 264 name = xml.getString(NAME);
236 - version = eval(xml.getString(VERSION)); 265 + version = expand(xml.getString(VERSION));
237 - featuresRepo = eval(xml.getString(FEATURES_REPO)); 266 + featuresRepo = expand(xml.getString(FEATURES_REPO));
238 267
239 artifacts = xml.configurationsAt(ARTIFACT).stream() 268 artifacts = xml.configurationsAt(ARTIFACT).stream()
240 - .map(cfg -> eval(cfg.getRootNode().getValue().toString())) 269 + .map(cfg -> expand(cfg.getRootNode().getValue().toString()))
241 .collect(Collectors.toList()); 270 .collect(Collectors.toList());
242 271
243 } catch (ConfigurationException e) { 272 } catch (ConfigurationException e) {
...@@ -262,7 +291,7 @@ public class OnosAppMojo extends AbstractMojo { ...@@ -262,7 +291,7 @@ public class OnosAppMojo extends AbstractMojo {
262 byte[] bytes = toByteArray(getClass().getResourceAsStream(APP_XML)); 291 byte[] bytes = toByteArray(getClass().getResourceAsStream(APP_XML));
263 contents = new String(bytes); 292 contents = new String(bytes);
264 } 293 }
265 - fileWrite(file.getAbsolutePath(), eval(contents)); 294 + fileWrite(file.getAbsolutePath(), expand(contents));
266 } catch (IOException e) { 295 } catch (IOException e) {
267 throw new MojoExecutionException("Unable to process app.xml", e); 296 throw new MojoExecutionException("Unable to process app.xml", e);
268 } 297 }
...@@ -305,7 +334,7 @@ public class OnosAppMojo extends AbstractMojo { ...@@ -305,7 +334,7 @@ public class OnosAppMojo extends AbstractMojo {
305 artifactFile(projectArtifactId, projectVersion, XML, "features"); 334 artifactFile(projectArtifactId, projectVersion, XML, "features");
306 File dstDir = new File(stageDirectory, projectPath); 335 File dstDir = new File(stageDirectory, projectPath);
307 forceMkdir(dstDir); 336 forceMkdir(dstDir);
308 - String s = eval(new String(toByteArray(stream))); 337 + String s = expand(new String(toByteArray(stream)));
309 fileWrite(new File(dstDir, featuresArtifact).getAbsolutePath(), s); 338 fileWrite(new File(dstDir, featuresArtifact).getAbsolutePath(), s);
310 } 339 }
311 340
...@@ -386,19 +415,51 @@ public class OnosAppMojo extends AbstractMojo { ...@@ -386,19 +415,51 @@ public class OnosAppMojo extends AbstractMojo {
386 aid + "-" + version + "-" + classifier + "." + type; 415 aid + "-" + version + "-" + classifier + "." + type;
387 } 416 }
388 417
389 - // Returns the given string with project variable substitutions. 418 + /**
390 - private String eval(String string) { 419 + * Expands any environment variables in the specified string. These are
391 - return string == null ? null : 420 + * specified as ${property} tokens.
392 - string.replaceAll("\\$\\{onos.app.name\\}", name) 421 + *
393 - .replaceAll("\\$\\{onos.app.origin\\}", origin) 422 + * @param string string to be processed
394 - .replaceAll("\\$\\{onos.app.requires\\}", requiredApps) 423 + * @return original string with expanded substitutions
395 - .replaceAll("\\$\\{onos.app.category\\}", category) 424 + */
396 - .replaceAll("\\$\\{onos.app.title\\}", title) 425 + private String expand(String string) {
397 - .replaceAll("\\$\\{onos.app.url\\}", url) 426 + return expand(string, properties);
398 - .replaceAll("\\$\\{project.groupId\\}", projectGroupId) 427 + }
399 - .replaceAll("\\$\\{project.artifactId\\}", projectArtifactId) 428 +
400 - .replaceAll("\\$\\{project.version\\}", projectVersion) 429 + /**
401 - .replaceAll("\\$\\{project.description\\}", readme); 430 + * Expands any environment variables in the specified string. These are
431 + * specified as ${property} tokens.
432 + *
433 + * @param string string to be processed
434 + * @param properties dictionary of property values to substitute
435 + * @return original string with expanded substitutions
436 + */
437 + private String expand(String string, Map<String, String> properties) {
438 + if (string == null) {
439 + return null;
440 + }
441 +
442 + String pString = string;
443 + StringBuilder sb = new StringBuilder();
444 + int start, end, last = 0;
445 + while ((start = pString.indexOf(PROP_START, last)) >= 0) {
446 + end = pString.indexOf(PROP_END, start + PROP_START.length());
447 + checkArgument(end > start, "Malformed property in %s", pString);
448 + sb.append(pString.substring(last, start));
449 + String prop = pString.substring(start + PROP_START.length(), end);
450 + String value;
451 +
452 + value = properties.get(prop);
453 +
454 + if (value == null) {
455 + sb.append(PROP_START).append(prop).append(PROP_END);
456 + } else {
457 + sb.append(value != null ? value : "");
458 + }
459 + last = end + 1;
460 + }
461 + sb.append(pString.substring(last));
462 + return sb.toString();
402 } 463 }
403 464
404 // Recursively archives the specified directory into a given ZIP stream. 465 // Recursively archives the specified directory into a given ZIP stream.
......