blob: 8e6addab6215003b0f7651e13d04c7887328c0c9 [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 java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintStream;
import promoter.util.IO;
/**
* @author Stefan Winkler
*/
public class Git extends SourceCodeManager
{
private static final String GIT_COMMAND = //
"cd " + PromoterConfig.INSTANCE.getProjectCloneLocation() + ";\n" + //
PromoterConfig.INSTANCE.getGitExecutable();
// The symbolic name (alternatively: the URL) of the upstream (main) Git repository
@Deprecated
public static final String REMOTE_GIT = "origin";
// the following makes Git output
// "--BEGIN-COMMIT--
// hash
// committer name
// committer date
// message (multiline)
// --BEGIN-SUMMARY--
// summary (multiline)"
// for each history entry
public static final String OUTPUT_FORMAT = "--BEGIN-COMMIT--%n%h%n%cn%n%ci%n%B%n--BEGIN-SUMMARY--%n";
private boolean fetched;
public Git()
{
}
private boolean cloneIfNeeded(PrintStream stream)
{
File clone = PromoterConfig.INSTANCE.getProjectCloneLocation();
if (clone.exists())
{
return false;
}
File parent = clone.getParentFile();
parent.mkdirs();
String url = PromoterConfig.INSTANCE.getGitRepositoryURL();
System.out.println("Cloning " + url + " to " + clone);
stream.println(PromoterConfig.INSTANCE.getGitExecutable() + " clone --bare " + url + " " + clone);
stream.flush();
return true;
}
private void fetchIfNeeded(PrintStream stream)
{
if (!fetched)
{
fetched = true;
if (cloneIfNeeded(stream))
{
return;
}
System.out.println("Fetching " + PromoterConfig.INSTANCE.getProjectCloneLocation() + " to " + PromoterConfig.INSTANCE.getProjectCloneLocation());
stream.println(GIT_COMMAND + " fetch");
stream.flush();
}
}
@Override
public void setTag(final String branch, final String revision, final String qualifier)
{
// TODO No write access to direct Git anymore ;-(
// IO.executeProcess("/bin/bash", new OutputHandler()
// {
// public void handleOutput(OutputStream out) throws IOException
// {
// PrintStream stream = new PrintStream(out);
// fetchIfNeeded(stream);
//
// String tag = "drops/" + qualifier;
// System.out.println("Tagging " + revision + " in " + branch + " as " + tag);
//
// // Create the tag
// String message = qualifier + " in " + branch;
// stream.println(GIT_BINARY + " tag -a -m \"" + message + "\" \"" + tag + "\" \"" + revision + "\"");
//
// // Push the tag
// stream.println(GIT_BINARY + " push \"" + REMOTE_GIT + "\" \"" + tag + "\"");
// stream.flush();
// }
// });
}
@Override
public void handleLogEntries(String branch, String fromRevision, String toRevision, boolean withPaths, LogEntryHandler handler)
{
try
{
final File outFile = File.createTempFile("promotion-", ".tmp");
IO.executeProcess("/bin/bash", out -> {
PrintStream stream = new PrintStream(out);
fetchIfNeeded(stream);
String range = fromRevision + ".." + toRevision;
System.out.println("Getting log entries for " + branch + " (" + range + ")");
String command = GIT_COMMAND + " log " + (withPaths ? "--name-only " : "") + " --format=\"" + OUTPUT_FORMAT + "\" " + range + " > " + outFile;
stream.println(command);
stream.flush();
});
FileReader fileReader = new FileReader(outFile);
BufferedReader bufferedReader = new BufferedReader(fileReader);
try
{
LogEntry logEntry;
// Start of file. First line has to be "--BEGIN-COMMIT--".
String line = bufferedReader.readLine();
if (line == null)
{
return; // Empty log.
}
if (!line.equals("--BEGIN-COMMIT--"))
{
throw new IllegalStateException("Read unexpected line " + line + " at beginning of file " + outFile.getAbsolutePath());
}
// First line successfully read. Start processing of log entries:
processing: //
for (;;)
{
String commitHash = readLineSafe(bufferedReader);
logEntry = new LogEntry(commitHash);
String committer = readLineSafe(bufferedReader);
logEntry.setAuthor(committer);
String date = readLineSafe(bufferedReader);
logEntry.setDate(date);
// Now follows the message until the summary marker is read.
StringBuilder messageString = new StringBuilder();
while (!(line = readLineSafe(bufferedReader)).equals("--BEGIN-SUMMARY--"))
{
messageString.append(line);
messageString.append("\n");
}
logEntry.setMessage(messageString.toString());
summaryReading: //
for (;;)
{
line = bufferedReader.readLine();
if (line == null)
{
handler.handleLogEntry(logEntry);
break processing; // End of file reached.
}
if (line.equals("--BEGIN-COMMIT--"))
{
handler.handleLogEntry(logEntry);
break summaryReading; // End of summary section reached.
}
if (line.trim().length() == 0)
{
continue; // Read over empty lines.
}
// We are in the summary section. Read line should contain a path.
logEntry.getPaths().add(line);
}
}
}
finally
{
bufferedReader.close();
fileReader.close();
outFile.delete();
}
}
catch (RuntimeException ex)
{
throw ex;
}
catch (Exception ex)
{
throw new RuntimeException(ex);
}
}
private String readLineSafe(BufferedReader bufferedReader) throws IOException
{
String result = bufferedReader.readLine();
if (result == null)
{
throw new IllegalStateException("Unexpected end of stream");
}
return result;
}
}