package com.heroku.sdk.deploy.endpoints;
import com.heroku.sdk.deploy.utils.RestClient;
import org.apache.commons.lang3.StringEscapeUtils;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
public class Builds extends ApiEndpoint {
private static final String JVM_BUILDPACK_URL="https://codon-buildpacks.s3.amazonaws.com/buildpacks/heroku/jvm-common.tgz";
private String blobGetUrl;
private List<String> buildpackUrls;
public Builds(String appName, String stackName, String commit, String encodedApiKey, List<String> buildpacks) {
super(appName, stackName, commit, encodedApiKey);
if (buildpacks == null || buildpacks.isEmpty()) {
buildpackUrls = Arrays.asList(JVM_BUILDPACK_URL);
} else {
buildpackUrls = new ArrayList<>(buildpacks.size());
for (String buildpack : buildpacks) {
if (buildpack.equals("jvm-common")) {
buildpackUrls.add(JVM_BUILDPACK_URL);
} else {
buildpackUrls.add(buildpack);
}
}
}
}
public Map createSource() throws IOException {
String urlStr = BASE_URL + "/apps/" + URLEncoder.encode(appName, "UTF-8") + "/sources";
Map sourceResponse = RestClient.post(urlStr, headers);
Map blobJson = (Map)sourceResponse.get("source_blob");
blobUrl = (String)blobJson.get("put_url");
blobGetUrl = (String)blobJson.get("get_url");
return sourceResponse;
}
public Map build(RestClient.OutputLogger logger) throws IOException, InterruptedException {
if (blobGetUrl == null) {
throw new IllegalStateException("Source must be created before releasing!");
}
String urlStr = BASE_URL + "/apps/" + appName + "/builds";
String data = "{"+
"\"buildpacks\":" + getBuildpacksJson() + ", " +
"\"source_blob\":{\"url\":\"" + (null == blobGetUrl ? "" : StringEscapeUtils.escapeJson(blobGetUrl)) +
"\",\"version\":\"" + (null == commit ? "" : StringEscapeUtils.escapeJson(commit)) + "\"}}";
Map buildResponse = RestClient.post(urlStr, data, headers);
String outputUrl = (String)buildResponse.get("output_stream_url");
String buildId = (String)buildResponse.get("id");
if (outputUrl != null) {
try {
RestClient.get(outputUrl, headers, logger);
} catch (IOException e) {
logger.log("Deployment output not available. Polling for status...");
}
return pollForBuildInfo(buildId);
} else {
logger.log("Deployment output not available. Polling for status...");
return pollForBuildInfo(buildId);
}
}
public Map pollForBuildInfo(String buildId) throws IOException, InterruptedException {
for (int i = 0; i < 15; i++) {
Thread.sleep(2000);
Map info = getBuildInfo(buildId);
if (!"pending".equals(info.get("status"))) {
return info;
}
}
return getBuildInfo(buildId);
}
public Map getBuildInfo(String buildId) throws IOException {
String buildStatusUrlStr = BASE_URL + "/apps/" + appName + "/builds/" + buildId;
return RestClient.get(buildStatusUrlStr, headers);
}
public String getBuildpacksJson() {
String buildpacksString = "";
for (String url : buildpackUrls) {
buildpacksString += ",{\"url\":\"" + StringEscapeUtils.escapeJson(url) + "\"}";
}
return buildpacksString.replaceFirst(",", "[") + "]";
}
}