| /* |
| * Copyright (C) 2022, Simeon Andreev and others |
| * |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Distribution License v. 1.0 which is available at |
| * https://www.eclipse.org/org/documents/edl-v10.php. |
| * |
| * SPDX-License-Identifier: BSD-3-Clause |
| */ |
| |
| package org.eclipse.jgit.internal.diff; |
| |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Set; |
| |
| import org.eclipse.jgit.diff.DiffEntry; |
| import org.eclipse.jgit.diff.DiffEntry.ChangeType; |
| import org.eclipse.jgit.diff.RenameDetector; |
| import org.eclipse.jgit.lib.Repository; |
| import org.eclipse.jgit.treewalk.filter.PathFilter; |
| |
| /** |
| * Provides rename detection in special cases such as blame, where only a subset |
| * of the renames detected by {@link RenameDetector} is of interest. |
| */ |
| public class FilteredRenameDetector { |
| |
| private final RenameDetector renameDetector; |
| |
| /** |
| * @param repository |
| * The repository in which to check for renames. |
| */ |
| public FilteredRenameDetector(Repository repository) { |
| this(new RenameDetector(repository)); |
| } |
| |
| /** |
| * @param renameDetector |
| * The {@link RenameDetector} to use when checking for renames. |
| */ |
| public FilteredRenameDetector(RenameDetector renameDetector) { |
| this.renameDetector = renameDetector; |
| } |
| |
| /** |
| * @param diffs |
| * The set of changes to check. |
| * @param pathFilter |
| * Filter out changes that didn't affect this path. |
| * @return The subset of changes that affect only the filtered path. |
| * @throws IOException |
| */ |
| public List<DiffEntry> compute(List<DiffEntry> diffs, |
| PathFilter pathFilter) throws IOException { |
| return compute(diffs, Arrays.asList(pathFilter)); |
| } |
| |
| /** |
| * Tries to avoid computation overhead in {@link RenameDetector#compute()} |
| * by filtering diffs related to the path filters only. |
| * <p> |
| * Note: current implementation only optimizes added or removed diffs, |
| * further optimization is possible. |
| * |
| * @param changes |
| * The set of changes to check. |
| * @param pathFilters |
| * Filter out changes that didn't affect these paths. |
| * @return The subset of changes that affect only the filtered paths. |
| * @throws IOException |
| * @see RenameDetector#compute() |
| */ |
| public List<DiffEntry> compute(List<DiffEntry> changes, |
| List<PathFilter> pathFilters) throws IOException { |
| |
| if (pathFilters == null) { |
| throw new IllegalArgumentException("Must specify path filters"); //$NON-NLS-1$ |
| } |
| |
| Set<String> paths = new HashSet<>(pathFilters.size()); |
| for (PathFilter pathFilter : pathFilters) { |
| paths.add(pathFilter.getPath()); |
| } |
| |
| List<DiffEntry> filtered = new ArrayList<>(); |
| |
| // For new path: skip ADD's that don't match given paths |
| for (DiffEntry diff : changes) { |
| ChangeType changeType = diff.getChangeType(); |
| if (changeType != ChangeType.ADD |
| || paths.contains(diff.getNewPath())) { |
| filtered.add(diff); |
| } |
| } |
| |
| renameDetector.reset(); |
| renameDetector.addAll(filtered); |
| List<DiffEntry> sourceChanges = renameDetector.compute(); |
| |
| filtered.clear(); |
| |
| // For old path: skip DELETE's that don't match given paths |
| for (DiffEntry diff : changes) { |
| ChangeType changeType = diff.getChangeType(); |
| if (changeType != ChangeType.DELETE |
| || paths.contains(diff.getOldPath())) { |
| filtered.add(diff); |
| } |
| } |
| |
| renameDetector.reset(); |
| renameDetector.addAll(filtered); |
| List<DiffEntry> targetChanges = renameDetector.compute(); |
| |
| List<DiffEntry> result = new ArrayList<>(); |
| |
| for (DiffEntry sourceChange : sourceChanges) { |
| if (paths.contains(sourceChange.getNewPath())) { |
| result.add(sourceChange); |
| } |
| } |
| for (DiffEntry targetChange : targetChanges) { |
| if (paths.contains(targetChange.getOldPath())) { |
| result.add(targetChange); |
| } |
| } |
| |
| renameDetector.reset(); |
| return result; |
| } |
| } |