blob: 3bff799158789162aef76e7055a16a6fcb33210c [file] [log] [blame]
Thomas Vachuska8c8b0372015-03-10 11:11:24 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2015-present Open Networking Foundation
Thomas Vachuska8c8b0372015-03-10 11:11:24 -07003 *
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 */
16package org.onosproject.maven;
17
Thomas Vachuska586afd82015-04-17 11:06:53 -070018import com.google.common.collect.ImmutableList;
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -070019import org.apache.commons.configuration.ConfigurationException;
20import org.apache.commons.configuration.XMLConfiguration;
Jian Li97d6b2d2016-01-20 10:13:43 -080021import org.apache.commons.io.FileUtils;
Brian O'Connorbf7eca52015-04-15 16:25:46 -070022import org.apache.maven.artifact.repository.ArtifactRepository;
Thomas Vachuska8c8b0372015-03-10 11:11:24 -070023import org.apache.maven.plugin.AbstractMojo;
24import org.apache.maven.plugin.MojoExecutionException;
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -070025import org.apache.maven.plugins.annotations.Component;
Thomas Vachuska8c8b0372015-03-10 11:11:24 -070026import org.apache.maven.plugins.annotations.LifecyclePhase;
27import org.apache.maven.plugins.annotations.Mojo;
28import org.apache.maven.plugins.annotations.Parameter;
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -070029import org.apache.maven.project.MavenProject;
30import org.apache.maven.project.MavenProjectHelper;
Thomas Vachuska8c8b0372015-03-10 11:11:24 -070031
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -070032import java.io.File;
33import java.io.FileInputStream;
34import java.io.FileNotFoundException;
35import java.io.FileOutputStream;
36import java.io.IOException;
37import java.io.InputStream;
Jonathan Hartb8cd8032016-06-14 16:30:44 -070038import java.util.HashMap;
Thomas Vachuska8c8b0372015-03-10 11:11:24 -070039import java.util.List;
Jonathan Hartb8cd8032016-06-14 16:30:44 -070040import java.util.Map;
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -070041import java.util.stream.Collectors;
42import java.util.zip.ZipEntry;
43import java.util.zip.ZipOutputStream;
44
Jonathan Hartb8cd8032016-06-14 16:30:44 -070045import static com.google.common.base.Preconditions.checkArgument;
Thomas Vachuska586afd82015-04-17 11:06:53 -070046import static com.google.common.io.ByteStreams.toByteArray;
Jonathan Hartb8cd8032016-06-14 16:30:44 -070047import static org.codehaus.plexus.util.FileUtils.copyFile;
48import static org.codehaus.plexus.util.FileUtils.fileRead;
49import static org.codehaus.plexus.util.FileUtils.fileWrite;
50import static org.codehaus.plexus.util.FileUtils.forceMkdir;
Thomas Vachuska8c8b0372015-03-10 11:11:24 -070051
52/**
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -070053 * Produces ONOS application archive using the app.xml file information.
Thomas Vachuska8c8b0372015-03-10 11:11:24 -070054 */
55@Mojo(name = "app", defaultPhase = LifecyclePhase.PACKAGE)
56public class OnosAppMojo extends AbstractMojo {
57
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -070058 private static final String APP = "app";
59 private static final String NAME = "[@name]";
60 private static final String VERSION = "[@version]";
61 private static final String FEATURES_REPO = "[@featuresRepo]";
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -070062 private static final String ARTIFACT = "artifact";
Thomas Vachuska8c8b0372015-03-10 11:11:24 -070063
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -070064 private static final String APP_XML = "app.xml";
Jian Li97d6b2d2016-01-20 10:13:43 -080065 private static final String APP_PNG = "app.png";
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -070066 private static final String FEATURES_XML = "features.xml";
Thomas Vachuska8c8b0372015-03-10 11:11:24 -070067
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -070068 private static final String MVN_URL = "mvn:";
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -070069 private static final String M2_PREFIX = "m2";
Thomas Vachuska8c8b0372015-03-10 11:11:24 -070070
Thomas Vachuska586afd82015-04-17 11:06:53 -070071 private static final String ONOS_APP_NAME = "onos.app.name";
72 private static final String ONOS_APP_ORIGIN = "onos.app.origin";
Thomas Vachuska761f0042015-11-11 19:10:17 -080073 private static final String ONOS_APP_REQUIRES = "onos.app.requires";
Thomas Vachuska586afd82015-04-17 11:06:53 -070074
Jian Lic35415d2016-01-14 17:22:31 -080075 private static final String ONOS_APP_CATEGORY = "onos.app.category";
76 private static final String ONOS_APP_URL = "onos.app.url";
Simon Huntafae2f72016-03-04 21:18:23 -080077 private static final String ONOS_APP_TITLE = "onos.app.title";
Jian Lic35415d2016-01-14 17:22:31 -080078 private static final String ONOS_APP_README = "onos.app.readme";
79
Jonathan Hartb8cd8032016-06-14 16:30:44 -070080 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
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -070085 private static final String JAR = "jar";
86 private static final String XML = "xml";
87 private static final String APP_ZIP = "oar";
88 private static final String PACKAGE_DIR = "oar";
Thomas Vachuska8c8b0372015-03-10 11:11:24 -070089
Thomas Vachuska586afd82015-04-17 11:06:53 -070090 private static final String DEFAULT_ORIGIN = "ON.Lab";
Thomas Vachuska41e8c182015-04-21 11:09:19 -070091 private static final String DEFAULT_VERSION = "${project.version}";
Thomas Vachuska586afd82015-04-17 11:06:53 -070092
Jian Li97d6b2d2016-01-20 10:13:43 -080093 private static final String DEFAULT_CATEGORY = "default";
Jian Lic35415d2016-01-14 17:22:31 -080094 private static final String DEFAULT_URL = "http://onosproject.org";
95
Thomas Vachuska586afd82015-04-17 11:06:53 -070096 private static final String DEFAULT_FEATURES_REPO =
97 "mvn:${project.groupId}/${project.artifactId}/${project.version}/xml/features";
98 private static final String DEFAULT_ARTIFACT =
99 "mvn:${project.groupId}/${project.artifactId}/${project.version}";
100
Jonathan Hartb8cd8032016-06-14 16:30:44 -0700101 private static final String PROP_START = "${";
102 private static final String PROP_END = "}";
103
Thomas Vachuska41e8c182015-04-21 11:09:19 -0700104 private static final int BUFFER_SIZE = 8192;
Thomas Vachuska8c8b0372015-03-10 11:11:24 -0700105
Thomas Vachuska586afd82015-04-17 11:06:53 -0700106 private String name;
107 private String origin;
Thomas Vachuska761f0042015-11-11 19:10:17 -0800108 private String requiredApps;
Jian Lic35415d2016-01-14 17:22:31 -0800109 private String category;
110 private String url;
Simon Huntafae2f72016-03-04 21:18:23 -0800111 private String title;
Jian Lic35415d2016-01-14 17:22:31 -0800112 private String readme;
Thomas Vachuska586afd82015-04-17 11:06:53 -0700113 private String version = DEFAULT_VERSION;
Thomas Vachuska586afd82015-04-17 11:06:53 -0700114 private String featuresRepo = DEFAULT_FEATURES_REPO;
Thomas Vachuska8c8b0372015-03-10 11:11:24 -0700115 private List<String> artifacts;
116
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700117 /**
118 * The project base directory.
119 */
120 @Parameter(defaultValue = "${basedir}")
121 protected File baseDir;
Thomas Vachuska8c8b0372015-03-10 11:11:24 -0700122
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700123 /**
124 * The directory where the generated catalogue file will be put.
125 */
126 @Parameter(defaultValue = "${project.build.directory}")
127 protected File dstDirectory;
128
129 /**
130 * The project group ID.
131 */
132 @Parameter(defaultValue = "${project.groupId}")
133 protected String projectGroupId;
134
135 /**
136 * The project artifact ID.
137 */
138 @Parameter(defaultValue = "${project.artifactId}")
139 protected String projectArtifactId;
140
141 /**
142 * The project version.
143 */
144 @Parameter(defaultValue = "${project.version}")
145 protected String projectVersion;
146
147 /**
148 * The project version.
149 */
150 @Parameter(defaultValue = "${project.description}")
151 protected String projectDescription;
152
Brian O'Connorbf7eca52015-04-15 16:25:46 -0700153 @Parameter(defaultValue = "${localRepository}")
154 protected ArtifactRepository localRepository;
155
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700156 /**
157 * Maven project
158 */
Brian O'Connorbf7eca52015-04-15 16:25:46 -0700159 @Parameter(defaultValue = "${project}")
160 protected MavenProject project;
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700161
162 /**
163 * Maven project helper.
164 */
165 @Component
Brian O'Connorbf7eca52015-04-15 16:25:46 -0700166 protected MavenProjectHelper projectHelper;
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700167
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700168 private File m2Directory;
169 protected File stageDirectory;
170 protected String projectPath;
Jonathan Hartb8cd8032016-06-14 16:30:44 -0700171 private Map<String, String> properties;
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700172
173 @Override
Thomas Vachuska8c8b0372015-03-10 11:11:24 -0700174 public void execute() throws MojoExecutionException {
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700175 File appFile = new File(baseDir, APP_XML);
Jian Li97d6b2d2016-01-20 10:13:43 -0800176 File iconFile = new File(baseDir, APP_PNG);
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700177 File featuresFile = new File(baseDir, FEATURES_XML);
Thomas Vachuska8c8b0372015-03-10 11:11:24 -0700178
Thomas Vachuska586afd82015-04-17 11:06:53 -0700179 name = (String) project.getProperties().get(ONOS_APP_NAME);
180
181 // If neither the app.xml file exists, nor the onos.app.name property
182 // is defined, there is nothing for this Mojo to do, so bail.
183 if (!appFile.exists() && name == null) {
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700184 return;
185 }
186
Brian O'Connorbf7eca52015-04-15 16:25:46 -0700187 m2Directory = new File(localRepository.getBasedir());
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700188 stageDirectory = new File(dstDirectory, PACKAGE_DIR);
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700189 projectPath = M2_PREFIX + "/" + artifactDir(projectGroupId, projectArtifactId, projectVersion);
190
Thomas Vachuska586afd82015-04-17 11:06:53 -0700191 origin = (String) project.getProperties().get(ONOS_APP_ORIGIN);
192 origin = origin != null ? origin : DEFAULT_ORIGIN;
193
Thomas Vachuska761f0042015-11-11 19:10:17 -0800194 requiredApps = (String) project.getProperties().get(ONOS_APP_REQUIRES);
Thomas Vachuskafa776af2015-11-18 00:57:10 -0800195 requiredApps = requiredApps == null ? "" : requiredApps.replaceAll("[\\s]", "");
Thomas Vachuska761f0042015-11-11 19:10:17 -0800196
Jian Lic35415d2016-01-14 17:22:31 -0800197 category = (String) project.getProperties().get(ONOS_APP_CATEGORY);
198 category = category != null ? category : DEFAULT_CATEGORY;
199
200 url = (String) project.getProperties().get(ONOS_APP_URL);
201 url = url != null ? url : DEFAULT_URL;
202
Simon Huntafae2f72016-03-04 21:18:23 -0800203 // if title does not exist, fall back to the name
204 title = (String) project.getProperties().get(ONOS_APP_TITLE);
205 title = title != null ? title : name;
206
Jian Lic35415d2016-01-14 17:22:31 -0800207 // if readme does not exist, we simply fallback to use description
208 readme = (String) project.getProperties().get(ONOS_APP_README);
209 readme = readme != null ? readme : projectDescription;
210
Jonathan Hartb8cd8032016-06-14 16:30:44 -0700211 properties = buildProperties();
212
Thomas Vachuska586afd82015-04-17 11:06:53 -0700213 if (appFile.exists()) {
214 loadAppFile(appFile);
215 } else {
Jonathan Hartb8cd8032016-06-14 16:30:44 -0700216 artifacts = ImmutableList.of(expand(DEFAULT_ARTIFACT));
Thomas Vachuska586afd82015-04-17 11:06:53 -0700217 }
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700218
219 // If there are any artifacts, stage the
220 if (!artifacts.isEmpty()) {
Jonathan Hartb8cd8032016-06-14 16:30:44 -0700221 getLog().info("Building ONOS application package for " + name + " (v" + expand(version) + ")");
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700222 artifacts.forEach(a -> getLog().debug("Including artifact: " + a));
223
Brian O'Connorbf7eca52015-04-15 16:25:46 -0700224 if (stageDirectory.exists() || stageDirectory.mkdirs()) {
225 processAppXml(appFile);
Jian Li97d6b2d2016-01-20 10:13:43 -0800226 processAppPng(iconFile);
Brian O'Connorbf7eca52015-04-15 16:25:46 -0700227 processFeaturesXml(featuresFile);
228 processArtifacts();
229 generateAppPackage();
230 } else {
231 throw new MojoExecutionException("Unable to create directory: " + stageDirectory);
232 }
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700233 }
234 }
235
Jonathan Hartb8cd8032016-06-14 16:30:44 -0700236 // 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
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700254 // Loads the app.xml file.
255 private void loadAppFile(File appFile) throws MojoExecutionException {
256 XMLConfiguration xml = new XMLConfiguration();
257 xml.setRootElementName(APP);
258
259 try (FileInputStream stream = new FileInputStream(appFile)) {
260 xml.load(stream);
261 xml.setAttributeSplittingDisabled(true);
262 xml.setDelimiterParsingDisabled(true);
263
264 name = xml.getString(NAME);
Jonathan Hartb8cd8032016-06-14 16:30:44 -0700265 version = expand(xml.getString(VERSION));
266 featuresRepo = expand(xml.getString(FEATURES_REPO));
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700267
268 artifacts = xml.configurationsAt(ARTIFACT).stream()
Jonathan Hartb8cd8032016-06-14 16:30:44 -0700269 .map(cfg -> expand(cfg.getRootNode().getValue().toString()))
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700270 .collect(Collectors.toList());
271
柯志勇100686954df14a42018-10-23 09:19:06 +0800272 stream.close();
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700273 } catch (ConfigurationException e) {
274 throw new MojoExecutionException("Unable to parse app.xml file", e);
275 } catch (FileNotFoundException e) {
276 throw new MojoExecutionException("Unable to find app.xml file", e);
277 } catch (IOException e) {
278 throw new MojoExecutionException("Unable to read app.xml file", e);
279 }
280 }
281
282 // Processes and stages the app.xml file.
283 private void processAppXml(File appFile) throws MojoExecutionException {
284 try {
285 File file = new File(stageDirectory, APP_XML);
286 forceMkdir(stageDirectory);
Thomas Vachuska586afd82015-04-17 11:06:53 -0700287 String contents;
288
289 if (appFile.exists()) {
290 contents = fileRead(appFile);
291 } else {
292 byte[] bytes = toByteArray(getClass().getResourceAsStream(APP_XML));
293 contents = new String(bytes);
294 }
Jonathan Hartb8cd8032016-06-14 16:30:44 -0700295 fileWrite(file.getAbsolutePath(), expand(contents));
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700296 } catch (IOException e) {
297 throw new MojoExecutionException("Unable to process app.xml", e);
298 }
299 }
300
Jian Li97d6b2d2016-01-20 10:13:43 -0800301 // Stages the app.png file of a specific application.
302 private void processAppPng(File iconFile) throws MojoExecutionException {
303 try {
304 File stagedIconFile = new File(stageDirectory, APP_PNG);
305
306 if (iconFile.exists()) {
307 FileUtils.copyFile(iconFile, stagedIconFile);
308 }
309 } catch (IOException e) {
310 throw new MojoExecutionException("Unable to copy app.png", e);
311 }
312 }
313
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700314 private void processFeaturesXml(File featuresFile) throws MojoExecutionException {
315 boolean specified = featuresRepo != null && featuresRepo.length() > 0;
316
317 // If featuresRepo attribute is specified and there is a features.xml
318 // file present, add the features repo as an artifact
319 try {
320 if (specified && featuresFile.exists()) {
321 processFeaturesXml(new FileInputStream(featuresFile));
322 } else if (specified) {
323 processFeaturesXml(getClass().getResourceAsStream(FEATURES_XML));
324 }
325 } catch (FileNotFoundException e) {
326 throw new MojoExecutionException("Unable to find features.xml file", e);
327 } catch (IOException e) {
328 throw new MojoExecutionException("Unable to process features.xml file", e);
329 }
330 }
331
332 // Processes and stages the features.xml file.
333 private void processFeaturesXml(InputStream stream) throws IOException {
334 String featuresArtifact =
335 artifactFile(projectArtifactId, projectVersion, XML, "features");
336 File dstDir = new File(stageDirectory, projectPath);
337 forceMkdir(dstDir);
Jonathan Hartb8cd8032016-06-14 16:30:44 -0700338 String s = expand(new String(toByteArray(stream)));
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700339 fileWrite(new File(dstDir, featuresArtifact).getAbsolutePath(), s);
340 }
341
342 // Stages all artifacts.
Thomas Vachuskaa7a02202015-04-14 23:13:02 -0700343 private void processArtifacts() throws MojoExecutionException {
344 for (String artifact : artifacts) {
345 processArtifact(artifact);
346 }
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700347 }
348
349 // Stages the specified artifact.
Thomas Vachuskaa7a02202015-04-14 23:13:02 -0700350 private void processArtifact(String artifact) throws MojoExecutionException {
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700351 if (!artifact.startsWith(MVN_URL)) {
Thomas Vachuskaa7a02202015-04-14 23:13:02 -0700352 throw new MojoExecutionException("Unsupported artifact URL:" + artifact);
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700353 }
354
355 String[] fields = artifact.substring(4).split("/");
356 if (fields.length < 3) {
Thomas Vachuskaa7a02202015-04-14 23:13:02 -0700357 throw new MojoExecutionException("Illegal artifact URL:" + artifact);
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700358 }
359
360 try {
361 String file = artifactFile(fields);
362
363 if (projectGroupId.equals(fields[0]) && projectArtifactId.equals(fields[1])) {
364 // Local artifact is not installed yet, package it from target directory.
365 File dstDir = new File(stageDirectory, projectPath);
366 forceMkdir(dstDir);
367 copyFile(new File(dstDirectory, file), new File(dstDir, file));
368 } else {
369 // Other artifacts are packaged from ~/.m2/repository directory.
370 String m2Path = artifactDir(fields);
371 File srcDir = new File(m2Directory, m2Path);
Thomas Vachuskaa7a02202015-04-14 23:13:02 -0700372 File dstDir = new File(stageDirectory, M2_PREFIX + "/" + m2Path);
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700373 forceMkdir(dstDir);
374 copyFile(new File(srcDir, file), new File(dstDir, file));
375 }
376 } catch (IOException e) {
Thomas Vachuskaa7a02202015-04-14 23:13:02 -0700377 throw new MojoExecutionException("Unable to stage artifact " + artifact, e);
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700378 }
379 }
380
381 // Generates the ONOS package ZIP file.
382 private void generateAppPackage() throws MojoExecutionException {
383 File appZip = new File(dstDirectory, artifactFile(projectArtifactId, projectVersion,
Jian Lic35415d2016-01-14 17:22:31 -0800384 APP_ZIP, null));
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700385 try (FileOutputStream fos = new FileOutputStream(appZip);
386 ZipOutputStream zos = new ZipOutputStream(fos)) {
387 zipDirectory("", stageDirectory, zos);
388 projectHelper.attachArtifact(this.project, APP_ZIP, null, appZip);
389 } catch (IOException e) {
390 throw new MojoExecutionException("Unable to compress application package", e);
391 }
392 }
393
394 // Generates artifact directory name from the specified fields.
395 private String artifactDir(String[] fields) {
396 return artifactDir(fields[0], fields[1], fields[2]);
397 }
398
399 // Generates artifact directory name from the specified elements.
400 private String artifactDir(String gid, String aid, String version) {
Sanjana Agarwalde50ee52016-07-12 14:05:18 -0700401 return gid.replace('.', '/') + "/" + aid + "/" + version;
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700402 }
403
404 // Generates artifact file name from the specified fields.
405 private String artifactFile(String[] fields) {
406 return fields.length < 5 ?
407 artifactFile(fields[1], fields[2],
Jian Lic35415d2016-01-14 17:22:31 -0800408 (fields.length < 4 ? JAR : fields[3]), null) :
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700409 artifactFile(fields[1], fields[2], fields[3], fields[4]);
410 }
411
412 // Generates artifact file name from the specified elements.
413 private String artifactFile(String aid, String version, String type,
414 String classifier) {
415 return classifier == null ? aid + "-" + version + "." + type :
416 aid + "-" + version + "-" + classifier + "." + type;
417 }
418
Jonathan Hartb8cd8032016-06-14 16:30:44 -0700419 /**
420 * Expands any environment variables in the specified string. These are
421 * specified as ${property} tokens.
422 *
423 * @param string string to be processed
424 * @return original string with expanded substitutions
425 */
426 private String expand(String string) {
427 return expand(string, properties);
428 }
429
430 /**
431 * Expands any environment variables in the specified string. These are
432 * specified as ${property} tokens.
433 *
434 * @param string string to be processed
435 * @param properties dictionary of property values to substitute
436 * @return original string with expanded substitutions
437 */
438 private String expand(String string, Map<String, String> properties) {
439 if (string == null) {
440 return null;
441 }
442
443 String pString = string;
444 StringBuilder sb = new StringBuilder();
445 int start, end, last = 0;
446 while ((start = pString.indexOf(PROP_START, last)) >= 0) {
447 end = pString.indexOf(PROP_END, start + PROP_START.length());
448 checkArgument(end > start, "Malformed property in %s", pString);
449 sb.append(pString.substring(last, start));
450 String prop = pString.substring(start + PROP_START.length(), end);
451 String value;
452
453 value = properties.get(prop);
454
455 if (value == null) {
456 sb.append(PROP_START).append(prop).append(PROP_END);
457 } else {
458 sb.append(value != null ? value : "");
459 }
460 last = end + 1;
461 }
462 sb.append(pString.substring(last));
463 return sb.toString();
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700464 }
465
466 // Recursively archives the specified directory into a given ZIP stream.
467 private void zipDirectory(String root, File dir, ZipOutputStream zos)
468 throws IOException {
Thomas Vachuska41e8c182015-04-21 11:09:19 -0700469 byte[] buffer = new byte[BUFFER_SIZE];
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700470 File[] files = dir.listFiles();
471 if (files != null && files.length > 0) {
472 for (File file : files) {
473 if (file.isDirectory()) {
474 String path = root + file.getName() + "/";
475 zos.putNextEntry(new ZipEntry(path));
476 zipDirectory(path, file, zos);
477 zos.closeEntry();
478 } else {
479 FileInputStream fin = new FileInputStream(file);
480 zos.putNextEntry(new ZipEntry(root + file.getName()));
481 int length;
482 while ((length = fin.read(buffer)) > 0) {
483 zos.write(buffer, 0, length);
484 }
485 zos.closeEntry();
486 fin.close();
487 }
488 }
489 }
Thomas Vachuska8c8b0372015-03-10 11:11:24 -0700490 }
Jonathan Hartb8cd8032016-06-14 16:30:44 -0700491}