/*
* Copyright 2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file 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.amazonaws.codepipeline.jenkinsplugin;
import hudson.FilePath.FileCallable;
import hudson.model.TaskListener;
import hudson.remoting.VirtualChannel;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Paths;
import org.apache.commons.io.FileUtils;
import com.amazonaws.services.codepipeline.model.Artifact;
import com.amazonaws.services.codepipeline.model.Job;
import com.amazonaws.services.codepipeline.model.S3ArtifactLocation;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.model.S3Object;
import com.amazonaws.services.s3.model.S3ObjectInputStream;
public final class DownloadCallable implements FileCallable<Void> {
private static final long serialVersionUID = 1L;
private final boolean clearWorkspace;
private final TaskListener listener;
private final Job job;
private final CodePipelineStateModel model;
private final AWSClientFactory awsClientFactory;
private final String pluginVersion;
public DownloadCallable(
final boolean clearWorkspace,
final Job job,
final CodePipelineStateModel model,
final AWSClientFactory awsClientFactory,
final String pluginVersion,
final TaskListener listener) {
this.clearWorkspace = clearWorkspace;
this.listener = listener;
this.job = job;
this.model = model;
this.awsClientFactory = awsClientFactory;
this.pluginVersion = pluginVersion;
}
@Override
public Void invoke(final File workspace, final VirtualChannel channel) throws InterruptedException {
clearWorkspaceIfSelected(workspace, listener);
final AWSClients awsClients = awsClientFactory.getAwsClient(
model.getAwsAccessKey(),
model.getAwsSecretKey(),
model.getProxyHost(),
model.getProxyPort(),
model.getRegion(),
pluginVersion);
final AWSCodePipelineJobCredentialsProvider credentialsProvider = new AWSCodePipelineJobCredentialsProvider(
job.getId(), awsClients.getCodePipelineClient());
final AmazonS3 s3Client = awsClients.getS3Client(credentialsProvider);
for (final Artifact artifact : job.getData().getInputArtifacts()) {
final S3Object sessionObject = getS3Object(s3Client, artifact);
model.setCompressionType(ExtractionTools.getCompressionType(sessionObject, listener));
final String downloadedFileName = Paths.get(sessionObject.getKey()).getFileName().toString();
try {
downloadAndExtract(sessionObject, workspace, downloadedFileName, listener);
} catch (final Exception ex) {
final String error = "Failed to acquire artifacts: " + ex.getMessage();
LoggingHelper.log(listener, error);
LoggingHelper.log(listener, ex);
throw new InterruptedException(error);
}
}
return null;
}
private void clearWorkspaceIfSelected(final File workspace, final TaskListener listener) {
if (clearWorkspace) {
try {
LoggingHelper.log(listener, "Clearing workspace '%s' before download", workspace.getAbsolutePath());
FileUtils.cleanDirectory(workspace);
} catch (final IOException ex) {
LoggingHelper.log(listener, "Unable to clear workspace: %s", ex.getMessage());
}
}
}
private S3Object getS3Object(final AmazonS3 s3Client, final Artifact artifact) {
final S3ArtifactLocation artifactLocation = artifact.getLocation().getS3Location();
return s3Client.getObject(artifactLocation.getBucketName(), artifactLocation.getObjectKey());
}
private void downloadAndExtract(
final S3Object sessionObject,
final File workspace,
final String downloadedFileName,
final TaskListener listener) throws IOException {
downloadArtifacts(sessionObject, workspace, downloadedFileName, listener);
final File fullFilePath = new File(workspace, downloadedFileName);
try {
ExtractionTools.decompressFile(fullFilePath, workspace, model.getCompressionType(), listener);
LoggingHelper.log(listener, "Artifact uncompressed successfully");
} finally {
if (fullFilePath != null) {
try {
ExtractionTools.deleteTemporaryCompressedFile(fullFilePath);
} catch (final IOException ex) {
LoggingHelper.log(listener, "Could not delete temporary file: %s", ex.getMessage());
LoggingHelper.log(listener, ex);
}
}
}
}
private static void downloadArtifacts(
final S3Object sessionObject,
final File workspace,
final String downloadedFileName,
final TaskListener listener)
throws IOException {
streamReadAndDownloadObject(workspace, sessionObject, downloadedFileName);
LoggingHelper.log(listener, "Successfully downloaded artifact from AWS CodePipeline");
}
private static void streamReadAndDownloadObject(
final File workspace,
final S3Object sessionObject,
final String downloadedFileName) throws IOException {
final File outputFile = new File(workspace, downloadedFileName);
try (final S3ObjectInputStream objectContents = sessionObject.getObjectContent();
final OutputStream outputStream = new FileOutputStream(outputFile)) {
final int BUFFER_SIZE = 8192;
final byte[] buffer = new byte[BUFFER_SIZE];
int i;
while ((i = objectContents.read(buffer)) != -1) {
outputStream.write(buffer, 0, i);
}
}
}
}