James Moger
2012-10-31 40b07bca7d02438cd0d660f3b1713ffa86f6df76
src/com/gitblit/utils/JGitUtils.java
@@ -29,12 +29,14 @@
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import org.eclipse.jgit.api.CloneCommand;
import org.eclipse.jgit.api.FetchCommand;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.diff.DiffEntry;
import org.eclipse.jgit.diff.DiffEntry.ChangeType;
import org.eclipse.jgit.diff.DiffFormatter;
@@ -43,6 +45,7 @@
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.errors.StopWalkException;
import org.eclipse.jgit.lib.BlobBasedConfig;
import org.eclipse.jgit.lib.CommitBuilder;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.FileMode;
@@ -55,7 +58,6 @@
import org.eclipse.jgit.lib.RefUpdate.Result;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.RepositoryCache.FileKey;
import org.eclipse.jgit.lib.StoredConfig;
import org.eclipse.jgit.lib.TreeFormatter;
import org.eclipse.jgit.revwalk.RevBlob;
import org.eclipse.jgit.revwalk.RevCommit;
@@ -85,6 +87,7 @@
import com.gitblit.models.PathModel;
import com.gitblit.models.PathModel.PathChangeModel;
import com.gitblit.models.RefModel;
import com.gitblit.models.SubmoduleModel;
/**
 * Collection of static methods for retrieving information from a repository.
@@ -207,11 +210,10 @@
         if (credentialsProvider != null) {
            clone.setCredentialsProvider(credentialsProvider);
         }
         clone.call();
         Repository repository = clone.call().getRepository();
         // Now we have to fetch because CloneCommand doesn't fetch
         // refs/notes nor does it allow manual RefSpec.
         File gitDir = FileKey.resolve(new File(repositoriesFolder, name), FS.DETECTED);
         FileRepository repository = new FileRepository(gitDir);
         result.createdRepository = true;
         result.fetchResult = fetchRepository(credentialsProvider, repository);
         repository.close();
@@ -257,8 +259,12 @@
    * @return Repository
    */
   public static Repository createRepository(File repositoriesFolder, String name) {
      Git git = Git.init().setDirectory(new File(repositoriesFolder, name)).setBare(true).call();
      return git.getRepository();
      try {
         Git git = Git.init().setDirectory(new File(repositoriesFolder, name)).setBare(true).call();
         return git.getRepository();
      } catch (GitAPIException e) {
         throw new RuntimeException(e);
      }
   }
   /**
@@ -270,16 +276,26 @@
    *            false all repositories are included.
    * @param searchSubfolders
    *            recurse into subfolders to find grouped repositories
    * @param depth
    *            optional recursion depth, -1 = infinite recursion
    * @param exclusions
    *            list of regex exclusions for matching to folder names
    * @return list of repository names
    */
   public static List<String> getRepositoryList(File repositoriesFolder, boolean onlyBare,
         boolean searchSubfolders) {
         boolean searchSubfolders, int depth, List<String> exclusions) {
      List<String> list = new ArrayList<String>();
      if (repositoriesFolder == null || !repositoriesFolder.exists()) {
         return list;
      }
      List<Pattern> patterns = new ArrayList<Pattern>();
      if (!ArrayUtils.isEmpty(exclusions)) {
         for (String regex : exclusions) {
            patterns.add(Pattern.compile(regex));
         }
      }
      list.addAll(getRepositoryList(repositoriesFolder.getAbsolutePath(), repositoriesFolder,
            onlyBare, searchSubfolders));
            onlyBare, searchSubfolders, depth, patterns));
      StringUtils.sortRepositorynames(list);
      return list;
   }
@@ -296,25 +312,55 @@
    *            repositories are included.
    * @param searchSubfolders
    *            recurse into subfolders to find grouped repositories
    * @param depth
    *            recursion depth, -1 = infinite recursion
    * @param patterns
    *            list of regex patterns for matching to folder names
    * @return
    */
   private static List<String> getRepositoryList(String basePath, File searchFolder,
         boolean onlyBare, boolean searchSubfolders) {
         boolean onlyBare, boolean searchSubfolders, int depth, List<Pattern> patterns) {
      File baseFile = new File(basePath);
      List<String> list = new ArrayList<String>();
      if (depth == 0) {
         return list;
      }
      int nextDepth = (depth == -1) ? -1 : depth - 1;
      for (File file : searchFolder.listFiles()) {
         if (file.isDirectory()) {
            boolean exclude = false;
            for (Pattern pattern : patterns) {
               String path = FileUtils.getRelativePath(baseFile, file).replace('\\',  '/');
               if (pattern.matcher(path).matches()) {
                  LOGGER.debug(MessageFormat.format("excluding {0} because of rule {1}", path, pattern.pattern()));
                  exclude = true;
                  break;
               }
            }
            if (exclude) {
               // skip to next file
               continue;
            }
            File gitDir = FileKey.resolve(new File(searchFolder, file.getName()), FS.DETECTED);
            if (gitDir != null) {
               if (onlyBare && gitDir.getName().equals(".git")) {
                  continue;
               }
               // determine repository name relative to base path
               String repository = FileUtils.getRelativePath(baseFile, file);
               list.add(repository);
               if (gitDir.equals(file) || gitDir.getParentFile().equals(file)) {
                  // determine repository name relative to base path
                  String repository = FileUtils.getRelativePath(baseFile, file);
                  list.add(repository);
               } else if (searchSubfolders && file.canRead()) {
                  // look for repositories in subfolders
                  list.addAll(getRepositoryList(basePath, file, onlyBare, searchSubfolders,
                        nextDepth, patterns));
               }
            } else if (searchSubfolders && file.canRead()) {
               // look for repositories in subfolders
               list.addAll(getRepositoryList(basePath, file, onlyBare, searchSubfolders));
               list.addAll(getRepositoryList(basePath, file, onlyBare, searchSubfolders,
                     nextDepth, patterns));
            }
         }
      }
@@ -513,18 +559,20 @@
            }
            ObjectId entid = tw.getObjectId(0);
            FileMode entmode = tw.getFileMode(0);
            RevObject ro = rw.lookupAny(entid, entmode.getObjectType());
            rw.parseBody(ro);
            ByteArrayOutputStream os = new ByteArrayOutputStream();
            ObjectLoader ldr = repository.open(ro.getId(), Constants.OBJ_BLOB);
            byte[] tmp = new byte[4096];
            InputStream in = ldr.openStream();
            int n;
            while ((n = in.read(tmp)) > 0) {
               os.write(tmp, 0, n);
            if (entmode != FileMode.GITLINK) {
               RevObject ro = rw.lookupAny(entid, entmode.getObjectType());
               rw.parseBody(ro);
               ByteArrayOutputStream os = new ByteArrayOutputStream();
               ObjectLoader ldr = repository.open(ro.getId(), Constants.OBJ_BLOB);
               byte[] tmp = new byte[4096];
               InputStream in = ldr.openStream();
               int n;
               while ((n = in.read(tmp)) > 0) {
                  os.write(tmp, 0, n);
               }
               in.close();
               content = os.toByteArray();
            }
            in.close();
            content = os.toByteArray();
         }
      } catch (Throwable t) {
         error(t, repository, "{0} can't find {1} in tree {2}", path, tree.name());
@@ -684,7 +732,8 @@
            tw.addTree(commit.getTree());
            while (tw.next()) {
               list.add(new PathChangeModel(tw.getPathString(), tw.getPathString(), 0, tw
                     .getRawMode(0), commit.getId().getName(), ChangeType.ADD));
                     .getRawMode(0), tw.getObjectId(0).getName(), commit.getId().getName(),
                     ChangeType.ADD));
            }
            tw.release();
         } else {
@@ -695,17 +744,22 @@
            df.setDetectRenames(true);
            List<DiffEntry> diffs = df.scan(parent.getTree(), commit.getTree());
            for (DiffEntry diff : diffs) {
               String objectId = null;
               if (FileMode.GITLINK.equals(diff.getNewMode())) {
                  objectId = diff.getNewId().name();
               }
               if (diff.getChangeType().equals(ChangeType.DELETE)) {
                  list.add(new PathChangeModel(diff.getOldPath(), diff.getOldPath(), 0, diff
                        .getNewMode().getBits(), commit.getId().getName(), diff
                        .getNewMode().getBits(), objectId, commit.getId().getName(), diff
                        .getChangeType()));
               } else if (diff.getChangeType().equals(ChangeType.RENAME)) {
                  list.add(new PathChangeModel(diff.getOldPath(), diff.getNewPath(), 0, diff
                        .getNewMode().getBits(), commit.getId().getName(), diff
                        .getNewMode().getBits(), objectId, commit.getId().getName(), diff
                        .getChangeType()));
               } else {
                  list.add(new PathChangeModel(diff.getNewPath(), diff.getNewPath(), 0, diff
                        .getNewMode().getBits(), commit.getId().getName(), diff
                        .getNewMode().getBits(), objectId, commit.getId().getName(), diff
                        .getChangeType()));
               }
            }
@@ -798,15 +852,16 @@
      } else {
         name = tw.getPathString().substring(basePath.length() + 1);
      }
      ObjectId objectId = tw.getObjectId(0);
      try {
         if (!tw.isSubtree()) {
            size = tw.getObjectReader().getObjectSize(tw.getObjectId(0), Constants.OBJ_BLOB);
         if (!tw.isSubtree() && (tw.getFileMode(0) != FileMode.GITLINK)) {
            size = tw.getObjectReader().getObjectSize(objectId, Constants.OBJ_BLOB);
         }
      } catch (Throwable t) {
         error(t, null, "failed to retrieve blob size for " + tw.getPathString());
      }
      return new PathModel(name, tw.getPathString(), size, tw.getFileMode(0).getBits(),
            commit.getName());
            objectId.getName(), commit.getName());
   }
   /**
@@ -823,13 +878,10 @@
      } else if (FileMode.EXECUTABLE_FILE.equals(mode)) {
         return "-rwxr-xr-x";
      } else if (FileMode.SYMLINK.equals(mode)) {
         // FIXME symlink permissions
         return "symlink";
      } else if (FileMode.GITLINK.equals(mode)) {
         // FIXME gitlink permissions
         return "gitlink";
         return "submodule";
      }
      // FIXME missing permissions
      return "missing";
   }
@@ -1316,9 +1368,23 @@
    * @return all refs grouped by their referenced object id
    */
   public static Map<ObjectId, List<RefModel>> getAllRefs(Repository repository) {
      return getAllRefs(repository, true);
   }
   /**
    * Returns all refs grouped by their associated object id.
    *
    * @param repository
    * @param includeRemoteRefs
    * @return all refs grouped by their referenced object id
    */
   public static Map<ObjectId, List<RefModel>> getAllRefs(Repository repository, boolean includeRemoteRefs) {
      List<RefModel> list = getRefs(repository, org.eclipse.jgit.lib.RefDatabase.ALL, true, -1);
      Map<ObjectId, List<RefModel>> refs = new HashMap<ObjectId, List<RefModel>>();
      for (RefModel ref : list) {
         if (!includeRemoteRefs && ref.getName().startsWith(Constants.R_REMOTES)) {
            continue;
         }
         ObjectId objectid = ref.getReferencedObjectId();
         if (!refs.containsKey(objectid)) {
            refs.put(objectid, new ArrayList<RefModel>());
@@ -1485,6 +1551,62 @@
      }
      return branch;
   }
   /**
    * Returns the list of submodules for this repository.
    *
    * @param repository
    * @param commit
    * @return list of submodules
    */
   public static List<SubmoduleModel> getSubmodules(Repository repository, String commitId) {
      RevCommit commit = getCommit(repository, commitId);
      return getSubmodules(repository, commit.getTree());
   }
   /**
    * Returns the list of submodules for this repository.
    *
    * @param repository
    * @param commit
    * @return list of submodules
    */
   public static List<SubmoduleModel> getSubmodules(Repository repository, RevTree tree) {
      List<SubmoduleModel> list = new ArrayList<SubmoduleModel>();
      byte [] blob = getByteContent(repository, tree, ".gitmodules");
      if (blob == null) {
         return list;
      }
      try {
         BlobBasedConfig config = new BlobBasedConfig(repository.getConfig(), blob);
         for (String module : config.getSubsections("submodule")) {
            String path = config.getString("submodule", module, "path");
            String url = config.getString("submodule", module, "url");
            list.add(new SubmoduleModel(module, path, url));
         }
      } catch (ConfigInvalidException e) {
         LOGGER.error("Failed to load .gitmodules file for " + repository.getDirectory(), e);
      }
      return list;
   }
   /**
    * Returns the submodule definition for the specified path at the specified
    * commit.  If no module is defined for the path, null is returned.
    *
    * @param repository
    * @param commit
    * @param path
    * @return a submodule definition or null if there is no submodule
    */
   public static SubmoduleModel getSubmoduleModel(Repository repository, String commitId, String path) {
      for (SubmoduleModel model : getSubmodules(repository, commitId)) {
         if (model.path.equals(path)) {
            return model;
         }
      }
      return null;
   }
   /**
    * Returns the list of notes entered about the commit from the refs/notes
@@ -1603,24 +1725,6 @@
   }
   /**
    * Returns a StoredConfig object for the repository.
    *
    * @param repository
    * @return the StoredConfig of the repository
    */
   public static StoredConfig readConfig(Repository repository) {
      StoredConfig c = repository.getConfig();
      try {
         c.load();
      } catch (ConfigInvalidException cex) {
         error(cex, repository, "{0} configuration is invalid!");
      } catch (IOException cex) {
         error(cex, repository, "Could not open configuration for {0}!");
      }
      return c;
   }
   /**
    * Zips the contents of the tree at the (optionally) specified revision and
    * the (optionally) specified basepath to the supplied outputstream.
    * 
@@ -1652,6 +1756,9 @@
         }
         tw.setRecursive(true);
         while (tw.next()) {
            if (tw.getFileMode(0) == FileMode.GITLINK) {
               continue;
            }
            ZipEntry entry = new ZipEntry(tw.getPathString());
            entry.setSize(tw.getObjectReader().getObjectSize(tw.getObjectId(0),
                  Constants.OBJ_BLOB));