有没有一种方法可以在中途终止克隆操作?我将只使用克隆来验证存储库吗?有没有其他方法可以测试远程 url/repository 是否有效?
7 回答
您可以使用 JGIT 调用“git ls-remote”。看这里
示例代码如下:
final LsRemoteCommand lsCmd = new LsRemoteCommand(null);
final List<String> repos = Arrays.asList(
"https://github.com/MuchContact/java.git",
"git@github.com:MuchContact/java.git");
for (String gitRepo: repos){
lsCmd.setRemote(gitRepo);
System.out.println(lsCmd.call().toString());
}
我正在使用以下启发式方法(有待进一步改进):
private final static String INFO_REFS_PATH = "info/refs";
public static boolean isValidRepository(URIish repoUri) {
if (repoUri.isRemote()) {
return isValidRemoteRepository(repoUri);
} else {
return isValidLocalRepository(repoUri);
}
}
private static boolean isValidLocalRepository(URIish repoUri) {
boolean result;
try {
result = new FileRepository(repoUri.getPath()).getObjectDatabase().exists();
} catch (IOException e) {
result = false;
}
return result;
}
private static boolean isValidRemoteRepository(URIish repoUri) {
boolean result;
if (repoUri.getScheme().toLowerCase().startsWith("http") ) {
String path = repoUri.getPath();
String newPath = path.endsWith("/")? path + INFO_REFS_PATH : path + "/" + INFO_REFS_PATH;
URIish checkUri = repoUri.setPath(newPath);
InputStream ins = null;
try {
URLConnection conn = new URL(checkUri.toString()).openConnection();
conn.setReadTimeout(NETWORK_TIMEOUT_MSEC);
ins = conn.getInputStream();
result = true;
} catch (Exception e) {
result = false;
} finally {
try { ins.close(); } catch (Exception e) { /* ignore */ }
}
} else if (repoUri.getScheme().toLowerCase().startsWith("ssh") ) {
RemoteSession ssh = null;
Process exec = null;
try {
ssh = SshSessionFactory.getInstance().getSession(repoUri, null, FS.detect(), 5000);
exec = ssh.exec("cd " + repoUri.getPath() +"; git rev-parse --git-dir", 5000);
Integer exitValue = null;
do {
try {
exitValue = exec.exitValue();
} catch (Exception e) {
try{Thread.sleep(1000);}catch(Exception ee){}
}
} while (exitValue == null);
result = exitValue == 0;
} catch (Exception e) {
result = false;
} finally {
try { exec.destroy(); } catch (Exception e) { /* ignore */ }
try { ssh.disconnect(); } catch (Exception e) { /* ignore */ }
}
} else {
// TODO need to implement tests for other schemas
result = true;
}
return result;
}
这适用于裸存储库和非裸存储库。
请注意,URIish.isRemote() 方法似乎存在问题。当您从文件 URL 创建 URIish 时,主机不是 null 而是一个空字符串!但是,如果主机字段不为空,URIish.isRemote() 将返回 true...
编辑:向 isValidRemoteRepository() 方法添加了 ssh 支持。
我查看了 JGit 源代码,似乎没有一种方法可以检查远程仓库的有效性。
这是call
方法CloneCommand
:
public Git call() throws JGitInternalException {
try {
URIish u = new URIish(uri);
Repository repository = init(u);
FetchResult result = fetch(repository, u);
if (!noCheckout)
checkout(repository, result);
return new Git(repository);
} catch (IOException ioe) {
throw new JGitInternalException(ioe.getMessage(), ioe);
} catch (InvalidRemoteException e) {
throw new JGitInternalException(e.getMessage(), e);
} catch (URISyntaxException e) {
throw new JGitInternalException(e.getMessage(), e);
}
}
为了获取远程 URL 是否无效,在捕获 a 时,JGitInternalException
e
您可能会得到真正的原因e.getCause()
来寻找InvalidRemoteException
or URISyntaxException
,但正如您所指出的,如果它实际上是有效的,您最终会克隆;库不允许您中断操作。
更深入地研究 JGit 代码,TransportLocal
该类具有open(URIsh,Repository,String)
您可以用来检查是否InvalidRemoteException
抛出 an 的方法,但它的构造函数不是公共的。唉,需要一个自己动手的解决方案。您也许可以从TransportLocal.open
我提到的方法的内容开始。
AFAIK JGit 还没有实现git fsck
。
对于任何人来说,我正在使用以下更通用的方法来验证远程存储库(代码在 C# 中,但将其转换为 java 应该不难)。
public static bool IsValidRemoteRepository(URIish repoUri, CredentialsProvider credentialsProvider = null)
{
var repoPath = Path.Combine(Path.GetTempPath(), Path.GetFileNameWithoutExtension(Path.GetRandomFileName()));
Directory.CreateDirectory(repoPath);
var git = Git.Init().SetBare(true).SetDirectory(repoPath).Call();
var config = git.GetRepository().GetConfig();
config.SetString("remote", "origin", "url", repoUri.ToString());
config.Save();
try
{
var cmd = git.LsRemote();
if (credentialsProvider != null)
{
cmd.SetCredentialsProvider(credentialsProvider);
}
cmd.SetRemote("origin").Call();
}
catch (TransportException e)
{
LastException = e;
return false;
}
return true;
}
用于验证远程存储库的 API
public boolean validateRepository(String repositoryURL, String username, String password) throws Exception {
boolean result = false;
Repository db = FileRepositoryBuilder.create(new File("/tmp"));
Git git = Git.wrap(db);
final LsRemoteCommand lsCmd = git.lsRemote();
lsCmd.setRemote(repositoryURL);
if (username != null && password != null) {
lsCmd.setCredentialsProvider(new UsernamePasswordCredentialsProvider(username, password));
}
if (null != lsCmd.call()){
result = true;
}
return result;
}
注意:jgit 的 ls-remote api 会抛出已知错误的 NPE。因此添加了错误评论中提到的解决方法。
https://bugs.eclipse.org/bugs/show_bug.cgi?id=436695
JGit 正在研究该命令的实现,但据我所知,该git fsck
命令尚未在mvnrepository.com上发布。
有关它的外观示例,请查看此测试用例。
@Test
public void testHealthyRepo() throws Exception {
RevCommit commit0 = git.commit().message("0").create();
RevCommit commit1 = git.commit().message("1").parent(commit0).create();
git.update("master", commit1);
DfsFsck fsck = new DfsFsck(repo);
FsckError errors = fsck.check(null);
assertEquals(errors.getCorruptObjects().size(), 0);
assertEquals(errors.getMissingObjects().size(), 0);
assertEquals(errors.getCorruptIndices().size(), 0);
}