github-api/src/main/java/me/brianlong/git/LocalRepositoryCache.java
2020-12-07 13:46:48 -05:00

186 lines
5.9 KiB
Java

package me.brianlong.git;
import java.io.File;
import java.io.IOException;
import java.util.Map.Entry;
import java.util.UUID;
import org.eclipse.jgit.api.CloneCommand;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.api.errors.InvalidRemoteException;
import org.eclipse.jgit.api.errors.RefNotFoundException;
import org.eclipse.jgit.util.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class LocalRepositoryCache {
private static final LocalRepositoryCache INSTANCE = new LocalRepositoryCache();
public static LocalRepositoryCache getInstance() {
return INSTANCE;
}
private final Logger logger = LoggerFactory.getLogger(LocalRepositoryCache.class);
private final LRUExpiringHashMap<String, Git> cachedGits = new LRUExpiringHashMap<String, Git>(30);
// private final Map<String, String> gitIdsToUrls = new HashMap<String, String>();
private final File cacheDirectory = new File(System.getProperty("java.io.tmpdir"), "git");
private LocalRepositoryCache() {
this.cacheDirectory.mkdir();
this.cachedGits.addListener(new RepositoryCacheMapListener());
}
@Override
protected void finalize() throws Throwable {
try {
this.destroy();
} finally {
super.finalize();
}
}
private void destroy() {
if (this.logger.isDebugEnabled())
this.logger.debug("clearing local repo cache");
this.clear();
}
public synchronized ExtendedGit acquire(String url) throws GitAPIException, InvalidRemoteException, RefNotFoundException {
return this.acquire(url, null, null);
}
public synchronized ExtendedGit acquire(String url, GitCredentials creds) throws GitAPIException, InvalidRemoteException, RefNotFoundException {
return this.acquire(url, creds, null);
}
public synchronized ExtendedGit acquire(String url, String branch) throws GitAPIException, InvalidRemoteException, RefNotFoundException {
return this.acquire(url, null, branch);
}
public synchronized ExtendedGit acquire(String url, GitCredentials creds, String branch) throws GitAPIException, InvalidRemoteException, RefNotFoundException {
if (this.logger.isTraceEnabled())
this.logger.trace("acquire('" + url + "', " + creds + ", '" + branch + "')");
// Git git = this.cachedGits.remove(url);
// if (git == null) {
if (this.logger.isDebugEnabled())
this.logger.debug("creating temporary Git directory");
File gitRepoDirectory = new File(this.cacheDirectory, UUID.randomUUID().toString() + ".git");
CloneCommand clone = new CloneCommand()
.setURI(url)
.setDirectory(gitRepoDirectory);
if (branch != null)
clone.setBranch(branch);
if (this.logger.isDebugEnabled())
this.logger.debug("cloning Git repository: " + url);
ExtendedGit git = creds != null ? new CredentialedGit(clone, creds) : new ExtendedGit(clone);
if (this.logger.isInfoEnabled())
this.logger.info("Cloned Git Repository");
return git;
// git = creds != null ? new CredentialedGit(clone, creds) : new CachedGit(clone);
// this.gitIdsToUrls.put(git.getRepository().getIdentifier(), url);
// } else {
// if (branch != null) {
// if (this.logger.isDebugEnabled())
// this.logger.debug("switching Git branches: " + branch);
// git.checkout().setName(branch).call();
// }
//
// if (this.logger.isDebugEnabled())
// this.logger.debug("updating Git branch: " + branch);
// git.pull().call();
// }
}
public synchronized void release(Git git) {
if (this.logger.isTraceEnabled())
this.logger.trace("release('" + git.getRepository().getIdentifier() + "')");
// String url = this.gitIdsToUrls.get(git.getRepository().getIdentifier());
// this.cachedGits.put(url, git);
this.expunge(git);
}
public synchronized void clear() {
if (this.logger.isTraceEnabled())
this.logger.trace("clear()");
// this.cachedGits.clear();
}
private void expunge(Git git) {
// gitIdsToUrls.remove(git.getRepository().getIdentifier());
File gitDir = git.getRepository().getDirectory();
File workingTreeDir = git.getRepository().getWorkTree();
git.getRepository().close();
try {
if (this.logger.isDebugEnabled())
this.logger.debug("deleting: " + gitDir);
FileUtils.delete(gitDir, FileUtils.RECURSIVE);
} catch (IOException ie) {
this.logger.warn("Failed to delete a git directory: " + gitDir);
if (this.logger.isDebugEnabled())
this.logger.debug(ie.getMessage(), ie);
gitDir.deleteOnExit();
}
try {
if (this.logger.isDebugEnabled())
this.logger.debug("deleting: " + workingTreeDir);
FileUtils.delete(workingTreeDir, FileUtils.RECURSIVE);
} catch (IOException ie) {
this.logger.warn("Failed to delete a git directory: " + workingTreeDir);
if (this.logger.isDebugEnabled())
this.logger.debug(ie.getMessage(), ie);
workingTreeDir.deleteOnExit();
}
if (this.logger.isInfoEnabled())
this.logger.info("Deleted Git Repository");
}
private class RepositoryCacheMapListener implements ExpiringMapListener<String, Git> {
private final Logger logger = LoggerFactory.getLogger(LocalRepositoryCache.class);
@Override
public void accessed(Entry<String, Git> entry) {
}
@Override
public void added(Entry<String, Git> entry) {
// a clean one or one returned after being previously removed
}
@Override
public void expired(Entry<String, Git> entry) {
if (this.logger.isTraceEnabled())
this.logger.trace("expired('" + entry.getKey() + "', '" + entry.getValue().getRepository().getIdentifier() + "')");
expunge(entry.getValue());
}
@Override
public void removed(Entry<String, Git> entry) {
// expected to be removed only temporarily...for use elsewhere; do not close
}
@Override
public void cleared(Entry<String, Git> entry) {
if (this.logger.isTraceEnabled())
this.logger.trace("cleared('" + entry.getKey() + "', '" + entry.getValue().getRepository().getIdentifier() + "')");
expunge(entry.getValue());
}
}
}