All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.undefinedlabs.scope.utils.GitUtils Maven / Gradle / Ivy

package com.undefinedlabs.scope.utils;

import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.diff.DiffEntry;
import org.eclipse.jgit.diff.DiffFormatter;
import org.eclipse.jgit.diff.Edit;
import org.eclipse.jgit.diff.RawTextComparator;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevTree;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.treewalk.AbstractTreeIterator;
import org.eclipse.jgit.treewalk.CanonicalTreeParser;
import org.eclipse.jgit.treewalk.EmptyTreeIterator;
import org.eclipse.jgit.treewalk.FileTreeIterator;
import org.eclipse.jgit.util.io.DisabledOutputStream;
import com.undefinedlabs.scope.utils.metadata.model.GitDiffData;
import com.undefinedlabs.scope.utils.metadata.model.GitDiffFile;
import com.undefinedlabs.scope.utils.metadata.model.GitDiffStatus;
import com.undefinedlabs.scope.utils.props.SystemProps;
import java.io.File;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

public enum GitUtils {
  INSTANCE;

  protected static final String SOURCE_CODE_PATH = "sourceCodePath";
  protected static final String REPOSITORY = "repository";
  protected static final String COMMIT = "commit";
  protected static final String BRANCH = "branch";
  protected static final String DIFF = "diff";

  private static final Map GIT_INFO_MAP;
  private static final String GIT_FOLDER_NAME = ".git";

  static {
    GIT_INFO_MAP = populateGitInfoMap(SystemProps.USER_DIR, GIT_FOLDER_NAME);
  }

  public String getSourceRootPath() {
    return (String) GIT_INFO_MAP.get(SOURCE_CODE_PATH);
  }

  public String getRepository() {
    return (String) GIT_INFO_MAP.get(REPOSITORY);
  }

  public String getCommit() {
    return (String) GIT_INFO_MAP.get(COMMIT);
  }

  public String getBranch() {
    return (String) GIT_INFO_MAP.get(BRANCH);
  }

  public GitDiffData getDiff() {
    return (GitDiffData) GIT_INFO_MAP.get(DIFF);
  }

  protected static Map populateGitInfoMap(
      final String userDirPath, final String filenameToSearch) {
    final File gitFolder = FileUtils.searchBackwardsByFilename(userDirPath, filenameToSearch);

    if (gitFolder == null) {
      System.err.println(
          "Could not locate " + filenameToSearch + " starting from user.dir: " + userDirPath);
      return Collections.unmodifiableMap(new HashMap());
    }

    final Map gitInfoMap = new HashMap<>();

    try {
      final Git git = Git.open(gitFolder);
      final Repository repository = git.getRepository();

      final String sourceRootPath = Paths.get(gitFolder.getParent()).toAbsolutePath().toString();
      final String repositoryUrl = repository.getConfig().getString("remote", "origin", "url");
      final String branch = repository.getBranch();

      final ObjectId head = repository.resolve("HEAD");
      final String commit = head != null ? head.name() : null;
      final GitDiffData diffData = getGitDiffWorkingDir(repository);

      gitInfoMap.put(SOURCE_CODE_PATH, sourceRootPath);
      gitInfoMap.put(REPOSITORY, repositoryUrl);
      gitInfoMap.put(COMMIT, commit);
      gitInfoMap.put(BRANCH, branch);
      gitInfoMap.put(DIFF, diffData);

    } catch (Exception e) {
      throw new RuntimeException(e);
    }

    return Collections.unmodifiableMap(gitInfoMap);
  }

  private static GitDiffData getGitDiffWorkingDir(Repository repository) {

    try {
      final DiffFormatter df = new DiffFormatter(DisabledOutputStream.INSTANCE);
      df.setRepository(repository);
      df.setDiffComparator(RawTextComparator.DEFAULT);
      df.setDetectRenames(true);

      final AbstractTreeIterator commitTreeIterator = prepareTreeParser(repository, Constants.HEAD);
      final FileTreeIterator workTreeIterator = new FileTreeIterator(repository);
      final List diffEntries = df.scan(commitTreeIterator, workTreeIterator);

      final List gitDiffFiles = new ArrayList<>();
      for (DiffEntry diffEntry : diffEntries) {
        int linesAdded = 0;
        int linesDeleted = 0;

        for (final Edit edit : df.toFileHeader(diffEntry).toEditList()) {
          linesDeleted += edit.getEndA() - edit.getBeginA();
          linesAdded += edit.getEndB() - edit.getBeginB();
        }

        final GitDiffFile diffFile =
            new GitDiffFile(
                diffEntry.getNewPath(),
                linesAdded,
                linesDeleted,
                GitDiffStatus.parseFrom(diffEntry.getChangeType()),
                diffEntry.getOldPath());
        gitDiffFiles.add(diffFile);
      }

      return new GitDiffData(
          GitDiffData.TYPE,
          GitDiffData.VERSION,
          UUID.randomUUID().toString(),
          Collections.unmodifiableList(gitDiffFiles));
    } catch (Exception e) {
      return GitDiffData.EMPTY;
    }
  }

  private static AbstractTreeIterator prepareTreeParser(
      final Repository repository, final String ref) throws Exception {
    final Ref head = repository.findRef(ref);
    if (head == null || head.getObjectId() == null) {
      return new EmptyTreeIterator();
    }

    final RevWalk walk = new RevWalk(repository);
    final RevCommit commit = walk.parseCommit(head.getObjectId());
    final RevTree tree = walk.parseTree(commit.getTree().getId());

    final CanonicalTreeParser oldTreeParser = new CanonicalTreeParser();
    try (ObjectReader oldReader = repository.newObjectReader()) {
      oldTreeParser.reset(oldReader, tree.getId());
    }
    return oldTreeParser;
  }

  public String removeRefs(String branch) {
    if (StringUtils.isEmpty(branch)) {
      return branch;
    }

    return branch.startsWith("/refs/heads/")
        ? branch.replace("/refs/heads/", "")
        : branch.startsWith("/refs/") ? branch.replace("/refs/", "") : branch;
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy