blob: 70d0639ee548fce1dd0eb17b8fdf32672f647d54 [file] [log] [blame]
/*
* Copyright (c) 2004 - 2012 Eike Stepper (Loehne, Germany) and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Eike Stepper - initial API and implementation
*/
package promoter;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import java.util.StringTokenizer;
import promoter.util.Config;
import promoter.util.IO;
import promoter.util.XML;
/**
* @author Eike Stepper
*/
public class BuildCopier extends PromoterComponent
{
public BuildCopier()
{
}
public List<BuildInfo> copyBuilds()
{
List<BuildInfo> buildInfos = new ArrayList<>();
File configFolder = new File(PromoterConfig.INSTANCE.getConfigDirectory(), "jobs");
for (File jobDir : configFolder.listFiles())
{
if (!jobDir.isDirectory())
{
continue;
}
String jobName = jobDir.getName();
if (IO.isExcluded(jobName))
{
continue;
}
Properties jobProperties = Config.loadProperties(new File(jobDir, "promotion.properties"), false);
boolean disabled = Config.isDisabled(jobProperties);
if (disabled)
{
continue;
}
copyBuilds(jobName, jobProperties, buildInfos);
}
return buildInfos;
}
protected void copyBuilds(String jobName, Properties jobProperties, List<BuildInfo> buildInfos)
{
String jobURL = PromoterConfig.INSTANCE.getJobsURL() + "/" + jobName;
System.out.println();
System.out.println("Checking builds of " + jobURL);
Set<Integer> excludedBuilds = new HashSet<>();
StringTokenizer tokenizer = new StringTokenizer(jobProperties.getProperty("excluded.builds", ""), ",;: \t\n\r\f");
while (tokenizer.hasMoreTokens())
{
excludedBuilds.add(Integer.parseInt(tokenizer.nextToken()));
}
final int NO_BUILD = -1;
int nextBuildNumber = NO_BUILD;
boolean buildInProgress = false;
List<Integer> buildNumbers = getBuildNumbers(jobURL);
for (Integer buildNumber : buildNumbers)
{
if (excludedBuilds.contains(buildNumber))
{
System.out.println("Build " + buildNumber + " is excluded");
continue;
}
String buildURL = jobURL + "/" + buildNumber;
String buildResult = getBuildResult(buildURL);
if ("SUCCESS".equalsIgnoreCase(buildResult) || "UNSTABLE".equalsIgnoreCase(buildResult))
{
try
{
BuildInfo buildInfo = BuildInfo.read(new URL(buildURL + "/artifact/build-info.xml"));
if (copyBuild(jobProperties, buildURL, buildInfo))
{
buildInfos.add(buildInfo);
}
}
catch (FileNotFoundException ex)
{
System.out.println("Build " + buildNumber + " is missing build infos");
continue;
}
catch (IOException ex)
{
throw new RuntimeException(ex);
}
}
else if ("FAILURE".equalsIgnoreCase(buildResult))
{
System.out.println("Build " + buildNumber + " is failed");
}
else if ("ABORTED".equalsIgnoreCase(buildResult))
{
System.out.println("Build " + buildNumber + " is aborted");
}
else
{
System.out.println("Build " + buildNumber + " is in progress");
buildInProgress = true;
}
if (!buildInProgress)
{
nextBuildNumber = buildNumber + 1;
}
}
if (nextBuildNumber != NO_BUILD)
{
storeNextBuildNumber(jobName, nextBuildNumber);
}
}
protected boolean copyBuild(Properties jobProperties, String buildURL, BuildInfo buildInfo)
{
String buildType = buildInfo.getType();
String autoPromote = jobProperties.getProperty("auto.promote", "IMSR");
String autoVisible = jobProperties.getProperty("auto.visible", "");
String message = "Build " + buildInfo.getNumber() + " (" + buildType + ")";
if (autoPromote.contains(buildType))
{
File dropsDir = PromoterConfig.INSTANCE.getDropsArea();
dropsDir.mkdirs();
File drop = new File(dropsDir, buildInfo.getQualifier());
if (!drop.exists())
{
boolean isVisible = autoVisible.contains(buildType);
System.out.println("Build " + buildInfo.getNumber() + " is being copied to " + drop + (isVisible ? " (visible)" : " (invisible)"));
try
{
IO.unzip(new URL(buildURL + "/artifact/*zip*/archive.zip"), drop, "archive/");
}
catch (MalformedURLException ex)
{
throw new RuntimeException(ex);
}
// Handle old build results layout
File siteP2 = new File(drop, "site.p2");
if (siteP2.isDirectory())
{
for (File file : siteP2.listFiles())
{
file.renameTo(new File(drop, file.getName()));
}
siteP2.delete();
}
setTag(buildInfo);
DropProcessor.storeMarkers(drop, jobProperties, isVisible);
return true;
}
System.out.println(message + " is already promoted");
}
else
{
System.out.println(message + " is not configured for promotion");
}
return false;
}
protected void setTag(BuildInfo buildInfo)
{
System.out.println();
SourceCodeManager scm = getPromoter().getSourceCodeManager();
if (scm != null)
{
scm.setTag(buildInfo.getBranch(), buildInfo.getRevision(), buildInfo.getQualifier());
}
}
protected void storeNextBuildNumber(String jobName, final int nextBuildNumber)
{
IO.writeFile(new File(PromoterConfig.INSTANCE.getWorkingArea(), jobName + ".nextBuildNumber"), out -> {
PrintStream stream = new PrintStream(out);
stream.println(nextBuildNumber);
stream.flush();
});
}
protected List<Integer> getBuildNumbers(String jobURL)
{
final List<Integer> buildNumbers = new ArrayList<>();
try
{
XML.parseXML(new URL(jobURL + "/api/xml"), new DefaultHandler()
{
private int level;
private boolean build;
private boolean number;
private StringBuilder builder = new StringBuilder();
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException
{
++level;
if (level == 2 && "build".equalsIgnoreCase(qName))
{
build = true;
}
if (build && level == 3 && "number".equalsIgnoreCase(qName))
{
number = true;
}
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException
{
if (number)
{
buildNumbers.add(Integer.parseInt(builder.toString().trim()));
builder = new StringBuilder();
}
--level;
number = false;
build = false;
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException
{
if (number)
{
builder.append(ch, start, length);
}
}
});
}
catch (Exception ex)
{
ex.printStackTrace();
return null;
}
Collections.sort(buildNumbers);
return buildNumbers;
}
protected String getBuildResult(String buildURL)
{
final StringBuilder builder = new StringBuilder();
try
{
XML.parseXML(new URL(buildURL + "/api/xml"), new DefaultHandler()
{
private int level;
private boolean result;
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException
{
if (++level == 2)
{
if ("result".equalsIgnoreCase(qName))
{
result = true;
}
}
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException
{
--level;
result = false;
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException
{
if (result)
{
builder.append(ch, start, length);
}
}
});
}
catch (Exception ex)
{
ex.printStackTrace();
return null;
}
return builder.toString();
}
}