【问题标题】:JGIT validate if repository is validJGIT 验证存储库是否有效
【发布时间】:2012-06-14 10:31:31
【问题描述】:

有没有一种方法可以在中途终止克隆操作? 我将只使用克隆来验证存储库吗? 有没有其他方法可以测试远程 url/repository 是否有效?

【问题讨论】:

标签: java validation jgit


【解决方案1】:

您可以使用 JGIT 调用“git ls-remote”。见here

示例代码如下:

    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());
    }

【讨论】:

  • 仅由代码组成的答案永远不是答案。请详细说明。
  • 知道了。谢谢! @SubliemeSiem
【解决方案2】:

我正在使用以下启发式方法(有待进一步改进):

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 支持。

【讨论】:

  • 用于检测本地 repo 是否有效的代码在所有情况下都不正确,即使部分克隆的 repo 处于无效状态,它也会返回 true。请参阅this 答案以获取一些也可以处理这种情况的代码。
  • 这将返回true:new URIish(new File("/tmp").toURI().toURL()).isRemote(),所以至少应该这样做repoUri.isRemote() &amp;&amp; !repoUri.getScheme().equals("file")
【解决方案3】:

我查看了 JGit 源代码,似乎没有一种方法可以检查远程 repo 的有效性。

这是CloneCommandcall方法:

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 是否无效,在捕获 JGitInternalException e 时,您可能会通过 e.getCause() 找到 InvalidRemoteException 甚至 URISyntaxException 的实际原因,但正如您指出的那样如果它实际上是有效的,你最终会克隆;库不允许您中断操作。

更深入地研究 JGit 代码,TransportLocal 类具有 open(URIsh,Repository,String) 方法,您可以使用该方法检查是否抛出了 InvalidRemoteException,但它的构造函数是不公开的。唉,需要一个自己动手的解决方案。你也许可以从我提到的TransportLocal.open 方法的内容开始。

【讨论】:

    【解决方案4】:

    AFAIK JGit 还没有实现 git fsck

    【讨论】:

      【解决方案5】:

      对于任何寻找的人,我正在使用以下更通用的方法来验证远程存储库(代码在 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;
      }
      

      【讨论】:

        【解决方案6】:

        JGit 正在开发git fsck 命令的实现,但据我所知,这还没有在mvnrepository.com 上发布。

        有关外观的示例,请查看test case

        @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);
        }
        

        【讨论】:

          【解决方案7】:

          用于验证远程存储库的 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。因此添加了 bug 的 cmets 中提到的解决方法。
          https://bugs.eclipse.org/bugs/show_bug.cgi?id=436695

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2016-01-22
            • 2016-01-29
            • 2014-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-11-18
            • 1970-01-01
            • 2014-06-13
            相关资源
            最近更新 更多