package org.jboss.shrinkwrap.resolver.impl.maven.embedded;
import org.apache.commons.codec.digest.DigestUtils;
import org.arquillian.spacelift.Spacelift;
import org.arquillian.spacelift.execution.Execution;
import org.arquillian.spacelift.execution.ExecutionException;
import org.arquillian.spacelift.task.archive.UntarTool;
import org.arquillian.spacelift.task.archive.UnzipTool;
import org.arquillian.spacelift.task.net.DownloadTool;
import org.jboss.shrinkwrap.resolver.api.maven.embedded.BuildStage;
import org.jboss.shrinkwrap.resolver.api.maven.embedded.DistributionStage;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.logging.Logger;
/**
* @author <a href="mailto:mjobanek@redhat.com">Matous Jobanek</a>
*/
public abstract class DistributionStageImpl<NEXT_STEP extends BuildStage>
implements DistributionStage<NEXT_STEP> {
private String maven3BaseUrl =
"https://archive.apache.org/dist/maven/maven-3/%version%/binaries/apache-maven-%version%-bin.tar.gz";
private File setMavenInstalation = null;
private String mavenTargetDir = "target" + File.separator + "resolver-maven";
private Logger log = Logger.getLogger(DistributionStage.class.getName());
@Override
public NEXT_STEP useMaven3Version(String version) {
try {
useDistribution(new URL(maven3BaseUrl.replaceAll("%version%", version)), true);
} catch (MalformedURLException e) {
throw new IllegalArgumentException(e);
}
return returnNextStepType();
}
@Override
public NEXT_STEP useDistribution(URL mavenDistribution, boolean useCache) {
File mavenDir = prepareMavenDir(useCache);
File downloaded = download(mavenDir, mavenDistribution);
String downloadedZipMd5hash = getMd5hash(downloaded);
File withExtractedDir = null;
if (downloadedZipMd5hash != null) {
withExtractedDir = checkIfItIsAlreadyExtracted(downloadedZipMd5hash);
if (withExtractedDir == null) {
withExtractedDir = extract(downloaded, downloadedZipMd5hash);
}
File binDirectory = retrieveBinDirectory(withExtractedDir);
useInstallation(binDirectory);
}
return returnNextStepType();
}
private File checkIfItIsAlreadyExtracted(final String downloadedZipMd5hash) {
File[] dirs = new File(mavenTargetDir).listFiles(new FileFilter() {
@Override
public boolean accept(File file) {
return file.isDirectory() && downloadedZipMd5hash.equals(file.getName());
}
});
if (dirs != null && dirs.length > 0) {
return dirs[0];
}
return null;
}
private File retrieveBinDirectory(File uncompressed) {
File[] extracted = uncompressed.listFiles(new FileFilter() {
@Override
public boolean accept(File file) {
return file.isDirectory();
}
});
if (extracted.length == 0) {
throw new IllegalArgumentException("No directory has been extracted from the archive: " + uncompressed);
}
if (extracted.length > 1) {
throw new IllegalArgumentException(
"More than one directory has been extracted from the archive: " + uncompressed);
}
return extracted[0];
}
private File extract(File downloaded, String downloadedZipMd5hash) {
File toExtract = new File(mavenTargetDir + File.separator + downloadedZipMd5hash);
toExtract.mkdirs();
String downloadedPath = downloaded.getAbsolutePath();
try {
if (downloadedPath.endsWith(".zip")) {
Spacelift.task(downloaded, UnzipTool.class).toDir(toExtract).execute().await();
} else if (downloadedPath.endsWith(".tar.gz")) {
Spacelift.task(downloaded, UntarTool.class).gzip(true).toDir(toExtract).execute().await();
} else if (downloadedPath.endsWith(".tar.bz2")) {
Spacelift.task(downloaded, UntarTool.class).bzip2(true).toDir(toExtract).execute().await();
} else {
throw new IllegalArgumentException(
"The distribution " + downloaded + " is compressed by unsupported format. "
+ "Supported formats are .zip, .tar.gz, .tar.bz2");
}
} catch (ExecutionException ee) {
throw new IllegalStateException(
"Something bad happened when the file: " + downloadedPath + " was being extracted. "
+ "For more information see the stacktrace");
}
return toExtract;
}
private String getMd5hash(File downloaded) {
FileInputStream fis = null;
try {
fis = new FileInputStream(downloaded);
return DigestUtils.md5Hex(fis);
} catch (IOException e) {
log.warning("A problem occurred when md5 hash of a file " + downloaded + " was being retrieved:\n"
+ e.getMessage());
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
log.warning("A problem occurred when FileInputStream of a file " + downloaded
+ "was being closed:\n" + e.getMessage());
}
}
}
return null;
}
private File download(File mavenDir, URL mavenDistribution) {
String distUrl = mavenDistribution.toString();
String target = mavenDir + distUrl.substring(distUrl.lastIndexOf("/"));
File downloaded = null;
for (File file : mavenDir.listFiles()) {
if (file.getAbsolutePath().equals(target)) {
downloaded = file;
}
}
if (downloaded == null) {
for (int i = 0; i < 3; i++) {
try {
downloaded = runDownloadExecution(mavenDistribution, target).await();
} catch (ExecutionException ee) {
System.err.print("ERROR: the downloading of Maven binaries has failed. ");
if (2 - i > 0) {
System.err.println("Trying again - number of remaining attempts: " + (2 - i));
continue;
} else {
System.err.println("For more information see the stacktrace of an exception");
throw ee;
}
}
break;
}
}
return downloaded;
}
private Execution<File> runDownloadExecution(URL mavenDistribution, String target) {
Execution<File> execution = Spacelift.task(DownloadTool.class).from(mavenDistribution).to(target).execute();
System.out.println("Resolver: downloading Maven binaries from " + mavenDistribution + " to " + target);
while (!execution.isFinished()) {
System.out.print(".");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
log.warning("Problem occurred when the thread was sleeping:\n" + e.getMessage());
}
}
System.out.println();
return execution;
}
private File prepareMavenDir(boolean useCache) {
String dirPath;
if (useCache) {
dirPath =
System.getProperty("user.home") + File.separator
+ ".arquillian" + File.separator
+ "resolver" + File.separator
+ "maven";
} else {
dirPath =
mavenTargetDir + File.separator
+ "downloaded" + File.separator;
}
File mavenDir = new File(dirPath);
if (!mavenDir.exists()) {
mavenDir.mkdirs();
}
return mavenDir;
}
@Override
public NEXT_STEP useInstallation(File mavenHome) {
this.setMavenInstalation = mavenHome;
return returnNextStepType();
}
@Override
public NEXT_STEP useDefaultDistribution() {
return returnNextStepType();
}
protected File getSetMavenInstalation() {
return setMavenInstalation;
}
protected abstract NEXT_STEP returnNextStepType();
}