package org.bndtools.templating.jgit;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.net.URI;
import java.nio.file.Files;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import org.bndtools.templating.FileResource;
import org.bndtools.templating.FolderResource;
import org.bndtools.templating.ResourceMap;
import org.bndtools.templating.Template;
import org.bndtools.templating.util.ObjectClassDefinitionImpl;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.jgit.api.CheckoutCommand;
import org.eclipse.jgit.api.CloneCommand;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.ListBranchCommand.ListMode;
import org.eclipse.jgit.api.errors.JGitInternalException;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.osgi.framework.Version;
import org.osgi.service.metatype.ObjectClassDefinition;
import aQute.lib.io.IO;
public class GitCloneTemplate implements Template {
private static final Pattern SHA1_PATTERN = Pattern.compile("\\p{XDigit}{40}");
private final GitCloneTemplateParams params;
private Repository checkedOut = null;
public GitCloneTemplate(GitCloneTemplateParams params) {
this.params = params;
}
@Override
public String getName() {
return params.name != null ? params.name : params.cloneUrl;
}
@Override
public String getShortDescription() {
String desc;
String branch = params.branch != null ? params.branch : GitCloneTemplateParams.DEFAULT_BRANCH;
if (params.name == null) {
desc = branch;
} else {
desc = params.cloneUrl + " " + branch;
}
return desc;
}
@Override
public String getCategory() {
return params.category;
}
@Override
public int getRanking() {
return 0;
}
@Override
public Version getVersion() {
return null;
}
@Override
public ObjectClassDefinition getMetadata() throws Exception {
return getMetadata(new NullProgressMonitor());
}
@Override
public ObjectClassDefinition getMetadata(IProgressMonitor monitor) throws Exception {
return new ObjectClassDefinitionImpl(getName(), getShortDescription(), null);
}
@Override
public ResourceMap generateOutputs(Map<String,List<Object>> parameters) throws Exception {
return generateOutputs(parameters, new NullProgressMonitor());
}
@Override
public ResourceMap generateOutputs(Map<String,List<Object>> parameters, IProgressMonitor monitor) throws Exception {
File workingDir = null;
File gitDir = null;
// Get existing checkout if available
synchronized (this) {
if (checkedOut != null) {
workingDir = checkedOut.getWorkTree();
gitDir = new File(workingDir, ".git");
}
}
if (workingDir == null) {
// Need to do a new checkout
workingDir = Files.createTempDirectory("checkout").toFile();
gitDir = new File(workingDir, ".git");
try {
CloneCommand cloneCmd = Git.cloneRepository().setURI(params.cloneUrl).setDirectory(workingDir).setNoCheckout(true);
cloneCmd.setProgressMonitor(new EclipseGitProgressTransformer(monitor));
Git git = cloneCmd.call();
CheckoutCommand checkout = git.checkout().setCreateBranch(true).setName("_tmp");
if (params.branch == null) {
checkout.setStartPoint(GitCloneTemplateParams.DEFAULT_BRANCH);
} else {
String startPoint = null;
if (params.branch.startsWith(Constants.DEFAULT_REMOTE_NAME + "/")) {
startPoint = params.branch;
} else {
// Check for a matching tag
for (Ref ref : git.tagList().call()) {
if (ref.getName().endsWith("/" + params.branch)) {
startPoint = params.branch;
break;
}
}
if (startPoint == null) {
// Check remote branches
for (Ref ref : git.branchList().setListMode(ListMode.REMOTE).call()) {
if (ref.getName().endsWith("/" + params.branch)) {
startPoint = Constants.DEFAULT_REMOTE_NAME + "/" + params.branch;
break;
}
}
if (startPoint == null) {
if (SHA1_PATTERN.matcher(params.branch).matches()) {
startPoint = params.branch;
if (startPoint == null) {
throw new Exception("Unable to find requested ref \"" + params.branch + "\"");
}
}
}
}
}
checkout.setStartPoint(startPoint);
}
checkout.call();
checkedOut = git.getRepository();
} catch (JGitInternalException e) {
Throwable cause = e.getCause();
if (cause instanceof Exception)
throw (Exception) cause;
throw e;
}
}
final File exclude = gitDir;
FileFilter filter = new FileFilter() {
@Override
public boolean accept(File path) {
return !path.equals(exclude);
}
};
return toResourceMap(workingDir, filter);
}
@Override
public void close() throws IOException {
File tempDir = null;
synchronized (this) {
if (checkedOut != null)
tempDir = checkedOut.getWorkTree();
}
if (tempDir != null)
IO.delete(tempDir);
}
@Override
public URI getIcon() {
return params.iconUri;
}
@Override
public URI getHelpContent() {
return params.helpUri;
}
private static ResourceMap toResourceMap(File baseDir, FileFilter filter) {
ResourceMap result = new ResourceMap();
File[] files = baseDir.listFiles(filter);
if (files != null)
for (File file : files) {
recurse("", file, filter, result);
}
return result;
}
private static void recurse(String prefix, File file, FileFilter filter, ResourceMap resourceMap) {
if (file.isDirectory()) {
String path = prefix + file.getName() + "/";
resourceMap.put(path, new FolderResource());
File[] children = file.listFiles(filter);
for (File child : children) {
recurse(path, child, filter, resourceMap);
}
} else {
String path = prefix + file.getName();
// TODO: WTF is the encoding?
resourceMap.put(path, new FileResource(file, "UTF-8"));
}
}
}