@Override
  public boolean checkout(
      AbstractBuild<?, ?> build,
      Launcher launcher,
      FilePath workspace,
      BuildListener listener,
      File changeLogFile)
      throws IOException, InterruptedException {
    if (workspace.exists()) {
      listener.getLogger().println("Deleting existing workspace " + workspace.getRemote());
      workspace.deleteRecursive();
    }
    listener.getLogger().println("Staging first zip: " + firstZip);
    workspace.unzipFrom(firstZip.openStream());
    listener.getLogger().println("Staging second zip: " + secondZip);
    workspace.unzipFrom(secondZip.openStream());

    // Get list of files changed in secondZip.
    ZipInputStream zip = new ZipInputStream(secondZip.openStream());
    ZipEntry e;
    ExtractChangeLogParser.ExtractChangeLogEntry changeLog =
        new ExtractChangeLogParser.ExtractChangeLogEntry(secondZip.toString());

    try {
      while ((e = zip.getNextEntry()) != null) {
        if (!e.isDirectory()) changeLog.addFile(new ExtractChangeLogParser.FileInZip(e.getName()));
      }
    } finally {
      zip.close();
    }
    saveToChangeLog(changeLogFile, changeLog);

    return true;
  }
  public void saveToChangeLog(
      File changeLogFile, ExtractChangeLogParser.ExtractChangeLogEntry changeLog)
      throws IOException {
    FileOutputStream outputStream = new FileOutputStream(changeLogFile);

    PrintStream stream = new PrintStream(outputStream, false, "UTF-8");

    stream.println("<?xml version='1.0' encoding='UTF-8'?>");
    stream.println("<extractChanges>");
    stream.println("<entry>");
    stream.println("<zipFile>" + escapeForXml(changeLog.getZipFile()) + "</zipFile>");

    for (String fileName : changeLog.getAffectedPaths()) {
      stream.println("<file>");
      stream.println("<fileName>" + escapeForXml(fileName) + "</fileName>");
      stream.println("</file>");
    }

    stream.println("</entry>");
    stream.println("</extractChanges>");

    stream.close();
  }