/**
* Copyright 2012 R King
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.github.kingamajick.admp.maven;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import org.apache.commons.io.FilenameUtils;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.resolver.ArtifactResolutionRequest;
import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.repository.RepositorySystem;
import org.codehaus.plexus.util.FileUtils;
import org.codehaus.plexus.util.io.RawInputStreamFacade;
import com.github.kingamajick.admp.maven.beans.DrawableArtifact;
import com.github.kingamajick.admp.maven.util.Constants;
/**
* Unpack the bitmap resources contained in one or more 'android-drawables' artifacts.
*
* @author R King
*
* @goal unpack
*/
public class UnpackBitmapResourcesMojo extends AbstractMojo {
/**
* @component
* @readonly
*/
private RepositorySystem repositorySystem;
/**
* @parameter expression = "${localRepository}"
* @readonly
*/
private ArtifactRepository localRepository;
/**
* @parameter expression = "${project.remoteArtifactRepositories}"
* @readonly
*/
private List<ArtifactRepository> remoteRepositories;
/**
* The location to unpack the drawables too.
*
* @parameter expression = "${unpackLocation}" default-value = "${project.build.directory}/android-drawables"
*/
private File unpackLocation;
/**
* A list of {@link DrawableArtifact}s to unpack.
*
* @parameter expression = "${drawableArtifacts}"
*/
private List<DrawableArtifact> drawableArtifacts;
/**
* @parameter expression = "${cleanDrawableLocations} default-value = "false"
* @readonly
*/
private boolean cleanDrawableLocations;
/*
* (non-Javadoc)
*
* @see org.apache.maven.plugin.Mojo#execute()
*/
public void execute() throws MojoExecutionException, MojoFailureException {
if (this.cleanDrawableLocations) {
}
List<Artifact> artifacts = resolve(this.drawableArtifacts);
unpackArchive(this.unpackLocation, artifacts);
}
/**
* Resolves the given list of {@link DrawableArtifact} from both the local and remote repositories.
*
* @param drawableArtifacts
* @return
* @throws MojoFailureException
*/
List<Artifact> resolve(final List<DrawableArtifact> drawableArtifacts) throws MojoFailureException {
ArtifactResolutionRequest request = new ArtifactResolutionRequest();
request.setLocalRepository(this.localRepository);
request.setRemoteRepositories(this.remoteRepositories);
List<Artifact> artifacts = new ArrayList<Artifact>();
for (DrawableArtifact drawableArtifact : drawableArtifacts) {
Artifact artifact = this.repositorySystem.createArtifact(drawableArtifact.getGroupId(), drawableArtifact.getArtifactId(), drawableArtifact.getVersion(), "android-drawables");
request.setArtifact(artifact);
ArtifactResolutionResult result = this.repositorySystem.resolve(request);
if (!artifact.isResolved()) {
handleNotResolved(artifact, result);
}
artifacts.add(artifact);
}
return artifacts;
}
/**
* Unpacks the list of artifacts representing 'android-drawable' artifacts to given output location.
*
* @param outputLocation
* @param artifacts
* @throws MojoFailureException
*/
void unpackArchive(final File outputLocation, final List<Artifact> artifacts) throws MojoFailureException {
if (!outputLocation.exists()) {
boolean success = outputLocation.mkdirs();
if (!success) {
throw new MojoFailureException("Unable to create output location " + outputLocation.getAbsolutePath());
}
}
for (Artifact artifact : artifacts) {
File artifactFile = artifact.getFile();
// If artifact is resolved using m2e it's possible that the artifact file will actually be the target location of the workspace
// project.
if (artifactFile.isFile()) {
unpackZipFile(outputLocation, artifactFile);
}
if (artifactFile.isDirectory()) {
unpackDirectory(outputLocation, artifactFile);
}
}
}
/**
* @param outputLocation
* @param zipFile
*/
private void unpackZipFile(final File outputLocation, final File zipFile) throws MojoFailureException {
try {
ZipFile archiveFile = new ZipFile(zipFile);
for (ZipEntry zipEntry : Collections.list(archiveFile.entries())) {
String entryName = zipEntry.getName();
if (zipEntry.isDirectory()) {
continue;
}
if (Constants.IMAGE_TYPES.contains(FilenameUtils.getExtension(entryName))) {
InputStream is = archiveFile.getInputStream(zipEntry);
File destination = new File(outputLocation, entryName);
if (destination.exists()) {
// TODO: Check if source and destination are different!
getLog().warn("Overwritting " + destination + ", this entry must appear more than once in the 'artifact-drawable' artifacts");
}
getLog().debug("Unpacking " + entryName + " -> " + destination);
FileUtils.copyStreamToFile(new RawInputStreamFacade(is), destination);
}
else {
getLog().debug("Ignoring entry " + entryName);
}
}
}
catch (IOException e) {
throw new MojoFailureException("Unable to unpack jar " + zipFile.getAbsolutePath(), e);
}
}
/**
* @param outputLocation
* @param artifactFile
*/
private void unpackDirectory(final File outputLocation, final File directory) throws MojoFailureException {
getLog().info("unpackingDirectory");
File resDir = new File(directory, "res");
for (String dirName : Constants.DRAWABLE_DIRS) {
File dir = new File(resDir, dirName);
if (dir.exists()) {
File target = new File(outputLocation, "res/" + dirName);
for (File drawable : dir.listFiles()) {
String drawableName = drawable.getName();
if (Constants.IMAGE_TYPES.contains(FilenameUtils.getExtension(drawableName))) {
try {
FileUtils.copyFile(drawable, new File(target, drawableName));
}
catch (IOException e) {
throw new MojoFailureException("Unable to unpack drawable from workspace resolution " + directory.getAbsolutePath(), e);
}
}
}
}
}
}
/**
* Handles a result when the artifact hasn't been resolved. This is to wrap the separate problems that can occur when resolving an
* artifact, missing metadata, version range violations, version circular dependencies, missing artifacts, network/transfer errors, file
* system errors: permissions. This method should be factored out once {@link ArtifactResolutionResult} wraps these issues itself.
*
* @param result
* @throws MojoFailureException
*/
void handleNotResolved(final Artifact artifact, final ArtifactResolutionResult result) throws MojoFailureException {
if (result.hasMissingArtifacts()) {
throw new MojoFailureException("Unable to resolve " + artifact.getGroupId() + ":" + artifact.getArtifactId() + ":" + artifact.getVersion() + ":" + artifact.getType()
+ ", artifact is missing");
}
else if (result.hasExceptions()) {
throw new MojoFailureException("Unable to resolve " + artifact.getGroupId() + ":" + artifact.getArtifactId() + ":" + artifact.getVersion() + ":" + artifact.getType(), result
.getExceptions().get(0));
}
else {
throw new MojoFailureException("Unable to resolve " + artifact.getGroupId() + ":" + artifact.getArtifactId() + ":" + artifact.getVersion() + ":" + artifact.getType()
+ ", unknown resolution issue");
}
}
}