blob: ad60e68250f7e63b50ca01c48cd0095eaf1e16ca [file] [log] [blame]
/*
* Copyright (c) 2015 Eike Stepper (Berlin, 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
*/
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.jar.JarOutputStream;
import java.util.zip.ZipEntry;
/**
* @author Stepper
*/
public final class RepositoryComposer
{
public static final String PROJECT = "User Storage";
private static final String REMOVE_MARKER = "REMOVE";
private static final Comparator<String> ALPHA_COMPARATOR = new Comparator<String>()
{
@Override
public int compare(String n1, String n2)
{
if (n1 == null)
{
n1 = "";
}
if (n2 == null)
{
n2 = "";
}
return n2.compareTo(n1);
}
};
private static final Comparator<String> VERSION_COMPARATOR = new Comparator<String>()
{
@Override
public int compare(String n1, String n2)
{
return new Version(n2).compareTo(new Version(n1));
}
};
private RepositoryComposer()
{
}
public static void main(String[] args) throws Exception
{
File downloadsFolder = new File(args[0]).getCanonicalFile();
String buildType = args[1];
String buildKey = args[2];
String buildLabel = args[3];
String folder = buildKey;
if (buildLabel.length() != 0)
{
folder += "-" + buildLabel;
}
File dropsFolder = new File(downloadsFolder, "drops");
File dropTypeFolder = new File(dropsFolder, buildType);
File dropFolder = new File(dropTypeFolder, folder);
File updatesFolder = new File(downloadsFolder, "updates.tmp");
File updateTypeFolder = new File(updatesFolder, buildType);
if ("release".equals(buildType))
{
composeRepositories(dropTypeFolder, updateTypeFolder, VERSION_COMPARATOR, Integer.MAX_VALUE);
boolean milestonesChanged = false;
File milestonesFolder = new File(dropsFolder, "milestone");
File[] children = milestonesFolder.listFiles();
if (children != null)
{
for (File child : children)
{
if (child.isDirectory() && child.getName().contains("-" + buildLabel + "-"))
{
scheduleRemoval(child);
milestonesChanged = true;
}
}
}
if (milestonesChanged)
{
composeMilestoneRepositories(dropsFolder, new File(updatesFolder, "milestone"));
}
}
else if ("milestone".equals(buildType))
{
composeMilestoneRepositories(dropsFolder, updateTypeFolder);
}
else if ("nightly".equals(buildType))
{
composeRepositories(dropTypeFolder, updateTypeFolder, ALPHA_COMPARATOR, 5);
}
composeRepository(updatesFolder, PROJECT + " All", getComposites(updatesFolder));
composeRepository(new File(updatesFolder, "latest"), PROJECT + " Latest", Collections.singletonList(dropFolder));
}
private static void composeMilestoneRepositories(File dropsFolder, File updateTypeFolder) throws IOException
{
File milestonesFolder = new File(dropsFolder, "milestone");
if (!composeRepositories(milestonesFolder, updateTypeFolder, ALPHA_COMPARATOR, Integer.MAX_VALUE))
{
List<File> drops = new ArrayList<File>();
File releasesFolder = new File(dropsFolder, "release");
List<String> names = getSortedChildren(releasesFolder, VERSION_COMPARATOR);
if (!names.isEmpty())
{
drops.add(new File(releasesFolder, names.get(0)));
}
composeRepository(updateTypeFolder, PROJECT + " Milestones", drops);
composeRepository(new File(updateTypeFolder, "latest"), PROJECT + " Latest Milestone", drops);
}
}
private static boolean composeRepositories(File dropTypeFolder, File updateTypeFolder, Comparator<String> comparator, int max) throws IOException
{
List<String> names = getSortedChildren(dropTypeFolder, comparator);
if (names.isEmpty())
{
return false;
}
List<File> drops = new ArrayList<File>();
int count = 0;
for (String name : names)
{
File drop = new File(dropTypeFolder, name);
if (++count > max)
{
scheduleRemoval(drop);
}
else
{
drops.add(drop);
}
}
String name = dropTypeFolder.getName();
if ("release".equals(name))
{
name = "Releases";
}
else if ("milestone".equals(name))
{
name = "Milestones";
}
else if ("nightly".equals(name))
{
name = "Nightly Builds";
}
composeRepository(updateTypeFolder, PROJECT + " " + name, drops);
composeRepository(new File(updateTypeFolder, "latest"), PROJECT + " Latest " + name.substring(0, name.length() - 1),
Collections.singletonList(drops.get(0)));
return true;
}
private static void composeRepository(File compositeFolder, String name, List<File> drops) throws IOException
{
long timestamp = System.currentTimeMillis();
writeRepository(compositeFolder, true, name, timestamp, drops);
writeRepository(compositeFolder, false, name, timestamp, drops);
}
private static void writeRepository(File compositeFolder, boolean metadata, String name, long timestamp, List<File> drops) throws IOException
{
String entryName;
String fileName;
String processingInstruction;
String type;
if (metadata)
{
entryName = "compositeContent.xml";
fileName = "compositeContent.jar";
processingInstruction = "compositeMetadataRepository";
type = "org.eclipse.equinox.internal.p2.metadata.repository.CompositeMetadataRepository";
}
else
{
entryName = "compositeArtifacts.xml";
fileName = "compositeArtifacts.jar";
processingInstruction = "compositeArtifactRepository";
type = "org.eclipse.equinox.internal.p2.artifact.repository.CompositeArtifactRepository";
}
compositeFolder.mkdirs();
File file = new File(compositeFolder, fileName);
FileOutputStream fileOutputStream = new FileOutputStream(file);
JarOutputStream jarOutputStream = new JarOutputStream(fileOutputStream);
jarOutputStream.putNextEntry(new ZipEntry(entryName));
Writer out = new OutputStreamWriter(jarOutputStream, "UTF-8");
BufferedWriter writer = new BufferedWriter(out);
writeLine(writer, "<?xml version='1.0' encoding='UTF-8'?>");
writeLine(writer, "<?" + processingInstruction + " version='1.0.0'?>");
writeLine(writer, "<repository name='" + name + "' type='" + type + "' version='1.0.0'>");
writeLine(writer, " <properties size='2'>");
writeLine(writer, " <property name='p2.timestamp' value='" + timestamp + "'/>");
writeLine(writer, " <property name='p2.compressed' value='false'/>");
writeLine(writer, " </properties>");
writeLine(writer, " <children size='" + drops.size() + "'>");
for (File drop : drops)
{
String relativePath;
if (drop.isAbsolute())
{
relativePath = getRelativePath(compositeFolder, drop);
}
else
{
relativePath = drop.getPath().replace(File.separatorChar, '/');
}
writeLine(writer, " <child location='" + relativePath + "'/>");
}
writeLine(writer, " </children>");
writeLine(writer, "</repository>");
writer.flush();
jarOutputStream.closeEntry();
jarOutputStream.close();
}
private static void writeLine(BufferedWriter writer, String line) throws IOException
{
writer.write(line);
writer.write('\n');
}
private static String getRelativePath(File source, File target)
{
String targetPath = target.getAbsolutePath();
StringBuilder builder = new StringBuilder();
while (source != null)
{
String sourcePath = source.getAbsolutePath();
if (targetPath.startsWith(sourcePath))
{
return builder.toString() + targetPath.substring(sourcePath.length() + 1).replace(File.separatorChar, '/');
}
builder.append("../");
source = source.getParentFile();
}
throw new IllegalStateException();
}
private static List<File> getComposites(File updatesFolder)
{
List<File> composites = new ArrayList<File>();
addComposite(updatesFolder, composites, "release");
addComposite(updatesFolder, composites, "milestone");
addComposite(updatesFolder, composites, "nightly");
return composites;
}
private static void addComposite(File updatesFolder, List<File> composites, String name)
{
if (new File(updatesFolder, name).isDirectory())
{
composites.add(new File(name));
}
}
private static List<String> getSortedChildren(File folder, Comparator<String> comparator)
{
List<String> names = new ArrayList<String>();
File[] children = folder.listFiles();
if (children != null)
{
for (File child : children)
{
if (child.isDirectory() && !new File(child, REMOVE_MARKER).exists())
{
names.add(child.getName());
}
}
Collections.sort(names, comparator);
}
return names;
}
private static void scheduleRemoval(File folder) throws IOException
{
File marker = new File(folder, REMOVE_MARKER);
marker.createNewFile();
}
}