/*
* Copyright (c) 2011, 2012 Roberto Tyley
*
* This file is part of 'Agit' - an Android Git client.
*
* Agit is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Agit is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/ .
*/
package com.madgag.agit.git;
import static android.os.Environment.getExternalStorageDirectory;
import static com.google.common.collect.Lists.newArrayList;
import static java.lang.System.identityHashCode;
import static org.eclipse.jgit.lib.Constants.DEFAULT_REMOTE_NAME;
import static org.eclipse.jgit.lib.Constants.DOT_GIT;
import static org.eclipse.jgit.lib.Constants.DOT_GIT_EXT;
import static org.eclipse.jgit.lib.Constants.R_HEADS;
import static org.eclipse.jgit.lib.Constants.R_REMOTES;
import static org.eclipse.jgit.lib.Repository.shortenRefName;
import static org.eclipse.jgit.storage.file.WindowCacheConfig.MB;
import android.util.Log;
import com.google.common.base.Function;
import com.google.common.collect.Ordering;
import com.madgag.agit.git.model.HasLatestCommit;
import com.madgag.agit.operations.Fetch;
import com.madgag.agit.operations.GitOperation;
import com.madgag.agit.operations.Pull;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.List;
import org.eclipse.jgit.lib.AbbreviatedObjectId;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.RepositoryCache;
import org.eclipse.jgit.lib.RepositoryCache.FileKey;
import org.eclipse.jgit.lib.StoredConfig;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.storage.file.WindowCacheConfig;
import org.eclipse.jgit.transport.RefSpec;
import org.eclipse.jgit.transport.RemoteConfig;
import org.eclipse.jgit.transport.URIish;
import org.eclipse.jgit.util.FS;
public class Repos {
private final static String TAG = "Repos";
static {
// Set memory config appropriate to Android devices
WindowCacheConfig cfg = new WindowCacheConfig();
cfg.setPackedGitLimit(2 * MB);
cfg.setDeltaBaseCacheLimit(2 * MB);
cfg.setStreamFileThreshold(1 * MB);
cfg.install();
}
public static List<File> reposInDefaultRepoDir() {
File reposDir = new File(getExternalStorageDirectory(), "git-repos");
List<File> repos = newArrayList();
if (!reposDir.exists() && !reposDir.mkdirs()) {
Log.d(TAG, "Could not create default repos dir " + reposDir);
return repos;
}
for (File repoDir : reposDir.listFiles()) {
File gitdir = RepositoryCache.FileKey.resolve(repoDir, FS.detect());
if (gitdir != null) {
repos.add(gitdir);
}
}
Log.d(TAG, "Found " + repos.size() + " repos in " + reposDir);
return repos;
}
public static Repository openRepoFor(File gitdir) {
try {
Repository repo = RepositoryCache.open(FileKey.lenient(gitdir, FS.DETECTED), false);
Log.d("REPO", "Opened " + describe(repo));
return repo;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static String niceNameFor(File gitdir) {
return niceNameFromNameDirectory(gitdir.getName().equals(DOT_GIT) ? gitdir.getParentFile() : gitdir);
}
public static String niceNameFor(Repository repo) {
return niceNameFromNameDirectory(topDirectoryFor(repo));
}
public static String shortenRevName(String revision) {
return AbbreviatedObjectId.isId(revision)?revision.substring(0,4):shortenRefName(revision);
}
public static File topDirectoryFor(Repository repo) {
return repo.isBare() ? repo.getDirectory() : repo.getWorkTree();
}
private static String niceNameFromNameDirectory(File directoryWithName) {
String name = directoryWithName.getName();
if (name.endsWith(DOT_GIT_EXT)) {
name = name.substring(0, name.length() - DOT_GIT_EXT.length());
}
return name;
}
public static String describe(Repository repository) {
return repository + " #" + identityHashCode(repository);
}
public static GitOperation refreshOperationFor(Repository repository) {
return repository.isBare() ? new Fetch(repository, DEFAULT_REMOTE_NAME) : new Pull(repository);
}
public static RemoteConfig remoteConfigFor(Repository repository, String remoteName) {
try {
return new RemoteConfig(repository.getConfig(), remoteName);
} catch (Exception e) {
throw new RuntimeException("Couldn't parse config for " + remoteName, e);
}
}
public static URIish uriForRemote(Repository repository, String remoteName) {
RemoteConfig remoteConfig = remoteConfigFor(repository, remoteName);
if (doesNotExist(remoteConfig)) {
try {
return new URIish(remoteName);
} catch (URISyntaxException e) {
throw new RuntimeException("Couldn't parse uri " + remoteName, e);
}
}
return remoteConfig.getURIs().get(0);
}
private static boolean doesNotExist(RemoteConfig cfg) {
return cfg.getURIs().isEmpty() && cfg.getPushURIs().isEmpty();
}
public static RemoteConfig addRemoteTo(Repository repository, String remoteName, URIish sourceUri)
throws IOException {
StoredConfig config = repository.getConfig();
RemoteConfig remote;
try {
remote = new RemoteConfig(config, remoteName);
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
remote.addURI(sourceUri);
remote.addFetchRefSpec(new RefSpec().setForceUpdate(true)
.setSourceDestination(R_HEADS + "*",
R_REMOTES + remoteName + "/*"));
remote.update(config);
Log.d(TAG, "About to save config...");
repository.getConfig().save();
return remote;
}
public final static Function<RevCommit, Integer> COMMIT_TIME = new Function<RevCommit, Integer>() {
public Integer apply(RevCommit commit) {
return commit == null ? 0 : commit.getCommitTime();
}
};
public final static Function<HasLatestCommit, RevCommit> LATEST_COMMIT = new Function<HasLatestCommit, RevCommit>() {
public RevCommit apply(HasLatestCommit branch) {
return branch == null ? null : branch.getLatestCommit();
}
};
public final static Ordering<HasLatestCommit> COMMIT_TIME_ORDERING =
Ordering.natural().reverse().onResultOf(COMMIT_TIME).onResultOf(LATEST_COMMIT);
}