Beispiel #1
0
  private static TreeFilter getDiffTreeFilterFor(AbstractTreeIterator a, AbstractTreeIterator b) {
    if (a instanceof DirCacheIterator && b instanceof WorkingTreeIterator)
      return new IndexDiffFilter(0, 1);

    if (a instanceof WorkingTreeIterator && b instanceof DirCacheIterator)
      return new IndexDiffFilter(1, 0);

    TreeFilter filter = TreeFilter.ANY_DIFF;
    if (a instanceof WorkingTreeIterator)
      filter = AndTreeFilter.create(new NotIgnoredFilter(0), filter);
    if (b instanceof WorkingTreeIterator)
      filter = AndTreeFilter.create(new NotIgnoredFilter(1), filter);
    return filter;
  }
  protected boolean hasIgnoreFile(Repository repository, RevCommit revCommit, String relativePath)
      throws Exception {

    if (_ignoreFileName == null) {
      return false;
    }

    try (TreeWalk treeWalk = new TreeWalk(repository)) {
      treeWalk.addTree(revCommit.getTree());

      if (revCommit.getParentCount() > 0) {
        RevCommit parentRevCommit = revCommit.getParent(0);

        treeWalk.addTree(parentRevCommit.getTree());
      }

      treeWalk.setRecursive(true);

      treeWalk.setFilter(
          AndTreeFilter.create(
              PathFilter.create(relativePath + "/" + _ignoreFileName), TreeFilter.ANY_DIFF));

      return treeWalk.next();
    }
  }
Beispiel #3
0
  /**
   * Parses an array of Git commits and returns an array of commits that affected the specified
   * object.
   *
   * @param repository the Git repository
   * @param commitIds the Git commit IDs to parse
   * @param path the object affected
   * @return an array of {@link GitCommit} objects representing the commits
   */
  public NSArray<GitCommit> commitsWithIds(NSArray<ObjectId> commitIds, String path) {
    try {
      RevWalk rw = new RevWalk(repository);

      try {
        rw.sort(RevSort.COMMIT_TIME_DESC);

        if (path != null) {
          rw.setTreeFilter(
              AndTreeFilter.create(PathSuffixFilter.create(path), TreeFilter.ANY_DIFF));
        } else {
          rw.setTreeFilter(TreeFilter.ALL);
        }

        for (ObjectId commitId : commitIds) {
          rw.markStart(rw.parseCommit(commitId));
        }

        NSMutableArray<GitCommit> commits = new NSMutableArray<GitCommit>();

        for (RevCommit commit : rw) {
          commits.add(new GitCommit(commit));
        }

        return commits;
      } finally {
        rw.release();
      }
    } catch (Exception e) {
      log.error("An exception occurred while parsing the commit: ", e);
      return null;
    }
  }
  /**
   * Returns a list of commits for the repository or a path within the repository. Caller may
   * specify ending revision with objectId. Caller may specify offset and maxCount to achieve
   * pagination of results. If the repository does not exist or is empty, an empty list is returned.
   *
   * @param repository
   * @param objectId if unspecified, HEAD is assumed.
   * @param path if unspecified, commits for repository are returned. If specified, commits for the
   *     path are returned.
   * @param offset
   * @param maxCount if < 0, all commits are returned.
   * @return a paged list of commits
   */
  public static List<RevCommit> getRevLog(
      Repository repository, String objectId, String path, int offset, int maxCount) {
    List<RevCommit> list = new ArrayList<RevCommit>();
    if (maxCount == 0) {
      return list;
    }
    if (!hasCommits(repository)) {
      return list;
    }
    try {
      // resolve branch
      ObjectId branchObject;
      if (objectId == null) {
        branchObject = getDefaultBranch(repository);
      } else {
        branchObject = repository.resolve(objectId);
      }

      RevWalk rw = new RevWalk(repository);
      rw.markStart(rw.parseCommit(branchObject));
      if (!(path == null)) {
        TreeFilter filter =
            AndTreeFilter.create(
                PathFilterGroup.createFromStrings(Collections.singleton(path)),
                TreeFilter.ALL); // TreeFilter.ANY_DIFF
        rw.setTreeFilter(filter);
      }
      Iterable<RevCommit> revlog = rw;
      if (offset > 0) {
        int count = 0;
        for (RevCommit rev : revlog) {
          count++;
          if (count > offset) {
            list.add(rev);
            if (maxCount > 0 && list.size() == maxCount) {
              break;
            }
          }
        }
      } else {
        for (RevCommit rev : revlog) {
          list.add(rev);
          if (maxCount > 0 && list.size() == maxCount) {
            break;
          }
        }
      }
      rw.dispose();
    } catch (Throwable t) {
      // todo
      Logger.error(t, t.getMessage());
    }
    return list;
  }
Beispiel #5
0
  /**
   * Compute the current projects that will be missing after the given branch is checked out
   *
   * @param branch
   * @param currentProjects
   * @return non-null but possibly empty array of missing projects
   */
  private IProject[] getMissingProjects(String branch, IProject[] currentProjects) {
    if (delete || currentProjects.length == 0) return new IProject[0];

    ObjectId targetTreeId;
    ObjectId currentTreeId;
    try {
      targetTreeId = repository.resolve(branch + "^{tree}"); // $NON-NLS-1$
      currentTreeId = repository.resolve(Constants.HEAD + "^{tree}"); // $NON-NLS-1$
    } catch (IOException e) {
      return new IProject[0];
    }
    if (targetTreeId == null || currentTreeId == null) return new IProject[0];

    Map<File, IProject> locations = new HashMap<File, IProject>();
    for (IProject project : currentProjects) {
      IPath location = project.getLocation();
      if (location == null) continue;
      location = location.append(IProjectDescription.DESCRIPTION_FILE_NAME);
      locations.put(location.toFile(), project);
    }

    List<IProject> toBeClosed = new ArrayList<IProject>();
    File root = repository.getWorkTree();
    TreeWalk walk = new TreeWalk(repository);
    try {
      walk.addTree(targetTreeId);
      walk.addTree(currentTreeId);
      walk.addTree(new FileTreeIterator(repository));
      walk.setRecursive(true);
      walk.setFilter(
          AndTreeFilter.create(
              PathSuffixFilter.create(IProjectDescription.DESCRIPTION_FILE_NAME),
              TreeFilter.ANY_DIFF));
      while (walk.next()) {
        AbstractTreeIterator targetIter = walk.getTree(0, AbstractTreeIterator.class);
        if (targetIter != null) continue;

        AbstractTreeIterator currentIter = walk.getTree(1, AbstractTreeIterator.class);
        AbstractTreeIterator workingIter = walk.getTree(2, AbstractTreeIterator.class);
        if (currentIter == null || workingIter == null) continue;

        IProject project = locations.get(new File(root, walk.getPathString()));
        if (project != null) toBeClosed.add(project);
      }
    } catch (IOException e) {
      return new IProject[0];
    } finally {
      walk.release();
    }
    return toBeClosed.toArray(new IProject[toBeClosed.size()]);
  }
Beispiel #6
0
  /**
   * Determine the differences between two trees.
   *
   * <p>No output is created, instead only the file paths that are different are returned. Callers
   * may choose to format these paths themselves, or convert them into {@link FileHeader} instances
   * with a complete edit list by calling {@link #toFileHeader(DiffEntry)}.
   *
   * @param a the old (or previous) side.
   * @param b the new (or updated) side.
   * @return the paths that are different.
   * @throws IOException trees cannot be read or file contents cannot be read.
   */
  public List<DiffEntry> scan(AbstractTreeIterator a, AbstractTreeIterator b) throws IOException {
    assertHaveRepository();

    TreeWalk walk = new TreeWalk(reader);
    walk.addTree(a);
    walk.addTree(b);
    walk.setRecursive(true);

    TreeFilter filter = getDiffTreeFilterFor(a, b);
    if (pathFilter instanceof FollowFilter) {
      walk.setFilter(
          AndTreeFilter.create(PathFilter.create(((FollowFilter) pathFilter).getPath()), filter));
    } else {
      walk.setFilter(AndTreeFilter.create(pathFilter, filter));
    }

    source = new ContentSource.Pair(source(a), source(b));

    List<DiffEntry> files = DiffEntry.scan(walk);
    if (pathFilter instanceof FollowFilter && isAdd(files)) {
      // The file we are following was added here, find where it
      // came from so we can properly show the rename or copy,
      // then continue digging backwards.
      //
      a.reset();
      b.reset();
      walk.reset();
      walk.addTree(a);
      walk.addTree(b);
      walk.setFilter(filter);

      if (renameDetector == null) setDetectRenames(true);
      files = updateFollowFilter(detectRenames(DiffEntry.scan(walk)));

    } else if (renameDetector != null) files = detectRenames(files);

    return files;
  }
Beispiel #7
0
  private KidWalk buildWalk() {
    final RepositoryMapping rm = RepositoryMapping.getMapping(resource);
    if (rm == null) {
      Activator.logError(
          NLS.bind(CoreText.GitFileHistory_gitNotAttached, resource.getProject().getName()), null);
      return null;
    }

    final KidWalk w = new KidWalk(rm.getRepository());
    gitPath = rm.getRepoRelativePath(resource);
    w.setTreeFilter(
        AndTreeFilter.create(
            PathFilterGroup.createFromStrings(Collections.singleton(gitPath)),
            TreeFilter.ANY_DIFF));
    return w;
  }
  private boolean handleGetCommitBody(
      HttpServletRequest request,
      HttpServletResponse response,
      Repository db,
      String ref,
      String pattern)
      throws IOException, ServletException, CoreException {
    ObjectId refId = db.resolve(ref);
    if (refId == null) {
      String msg = NLS.bind("Failed to get commit body for ref {0}", ref);
      return statusHandler.handleRequest(
          request,
          response,
          new ServerStatus(IStatus.ERROR, HttpServletResponse.SC_BAD_REQUEST, msg, null));
    }
    RevWalk walk = new RevWalk(db);
    walk.setTreeFilter(
        AndTreeFilter.create(
            PathFilterGroup.createFromStrings(Collections.singleton(pattern)),
            TreeFilter.ANY_DIFF));
    RevCommit revCommit = walk.parseCommit(refId);
    walk.dispose();

    Commit commit = new Commit(null /* not needed */, db, revCommit, pattern);
    ObjectStream stream = commit.toObjectStream();
    if (stream == null) {
      String msg = NLS.bind("Commit body for ref {0} not found", ref);
      return statusHandler.handleRequest(
          request,
          response,
          new ServerStatus(IStatus.ERROR, HttpServletResponse.SC_NOT_FOUND, msg, null));
    }
    IOUtilities.pipe(stream, response.getOutputStream(), true, false);

    return true;
  }
  private boolean handleGetDiff(
      HttpServletRequest request,
      HttpServletResponse response,
      Repository db,
      String scope,
      String pattern,
      OutputStream out)
      throws Exception {
    Git git = new Git(db);
    DiffCommand diff = git.diff();
    diff.setOutputStream(new BufferedOutputStream(out));
    AbstractTreeIterator oldTree;
    AbstractTreeIterator newTree = new FileTreeIterator(db);
    if (scope.contains("..")) { // $NON-NLS-1$
      String[] commits = scope.split("\\.\\."); // $NON-NLS-1$
      if (commits.length != 2) {
        String msg = NLS.bind("Failed to generate diff for {0}", scope);
        return statusHandler.handleRequest(
            request,
            response,
            new ServerStatus(IStatus.ERROR, HttpServletResponse.SC_BAD_REQUEST, msg, null));
      }
      oldTree = getTreeIterator(db, commits[0]);
      newTree = getTreeIterator(db, commits[1]);
    } else if (scope.equals(GitConstants.KEY_DIFF_CACHED)) {
      ObjectId head = db.resolve(Constants.HEAD + "^{tree}"); // $NON-NLS-1$
      if (head == null) {
        String msg = NLS.bind("Failed to generate diff for {0}, no HEAD", scope);
        return statusHandler.handleRequest(
            request,
            response,
            new ServerStatus(IStatus.ERROR, HttpServletResponse.SC_BAD_REQUEST, msg, null));
      }
      CanonicalTreeParser p = new CanonicalTreeParser();
      ObjectReader reader = db.newObjectReader();
      try {
        p.reset(reader, head);
      } finally {
        reader.release();
      }
      oldTree = p;
      newTree = new DirCacheIterator(db.readDirCache());
    } else if (scope.equals(GitConstants.KEY_DIFF_DEFAULT)) {
      oldTree = new DirCacheIterator(db.readDirCache());
    } else {
      oldTree = getTreeIterator(db, scope);
    }

    String[] paths = request.getParameterValues(ProtocolConstants.KEY_PATH);
    TreeFilter filter = null;
    TreeFilter pathFilter = null;
    if (paths != null) {
      if (paths.length > 1) {
        Set<TreeFilter> pathFilters = new HashSet<TreeFilter>(paths.length);
        for (String path : paths) {
          pathFilters.add(PathFilter.create(path));
        }
        pathFilter = OrTreeFilter.create(pathFilters);
      } else if (paths.length == 1) {
        pathFilter = PathFilter.create(paths[0]);
      }
    }
    if (pattern != null) {
      PathFilter patternFilter = PathFilter.create(pattern);
      if (pathFilter != null) filter = AndTreeFilter.create(patternFilter, pathFilter);
      else filter = patternFilter;
    } else {
      filter = pathFilter;
    }
    if (filter != null) diff.setPathFilter(filter);

    diff.setOldTree(oldTree);
    diff.setNewTree(newTree);
    diff.call();
    return true;
  }
  @Override
  public void execute() throws BuildException {
    if (_property == null) {
      throw new BuildException("Property attribute is required", getLocation());
    }

    if (_path == null) {
      throw new BuildException("Path attribute is required", getLocation());
    }

    File gitDir = PathUtil.getGitDir(_gitDir, getProject(), getLocation());

    String relativePath = PathUtil.toRelativePath(gitDir, _path);

    if (_useCache) {
      String hash = _hashes.get(relativePath);

      if (hash != null) {
        Project currentProject = getProject();

        currentProject.setNewProperty(_property, hash);

        return;
      }
    }

    try (Repository repository = RepositoryCache.open(FileKey.exact(gitDir, FS.DETECTED))) {

      RevWalk revWalk = new RevWalk(repository);

      revWalk.setRetainBody(false);

      revWalk.markStart(revWalk.parseCommit(repository.resolve(Constants.HEAD)));

      if (_ignoreFileName == null) {
        revWalk.setRevFilter(MaxCountRevFilter.create(1));
      } else {
        revWalk.setRevFilter(MaxCountRevFilter.create(2));
      }

      revWalk.setTreeFilter(
          AndTreeFilter.create(PathFilter.create(relativePath), TreeFilter.ANY_DIFF));

      RevCommit revCommit = revWalk.next();

      if (revCommit == null) {
        throw new IllegalStateException("Unable to find any commit under " + _path);
      }

      if (hasIgnoreFile(repository, revCommit, relativePath)) {
        RevCommit secondRevCommit = revWalk.next();

        if (secondRevCommit != null) {
          revCommit = secondRevCommit;
        }
      }

      Project currentProject = getProject();

      String hash = revCommit.name();

      currentProject.setNewProperty(_property, hash);

      if (_useCache) {
        _hashes.put(relativePath, hash);
      }

      revWalk.dispose();
    } catch (Exception e) {
      throw new BuildException("Unable to get head hash for path " + _path, e);
    }
  }