View Javadoc
1   /*
2    * Copyright (C) 2011, 2019 GitHub Inc. and others
3    *
4    * This program and the accompanying materials are made available under the
5    * terms of the Eclipse Distribution License v. 1.0 which is available at
6    * https://www.eclipse.org/org/documents/edl-v10.php.
7    *
8    * SPDX-License-Identifier: BSD-3-Clause
9    */
10  package org.eclipse.jgit.api;
11  
12  import java.io.IOException;
13  import java.util.ArrayList;
14  import java.util.Collection;
15  import java.util.Collections;
16  
17  import org.eclipse.jgit.api.errors.GitAPIException;
18  import org.eclipse.jgit.api.errors.JGitInternalException;
19  import org.eclipse.jgit.blame.BlameGenerator;
20  import org.eclipse.jgit.blame.BlameResult;
21  import org.eclipse.jgit.diff.DiffAlgorithm;
22  import org.eclipse.jgit.diff.RawTextComparator;
23  import org.eclipse.jgit.lib.AnyObjectId;
24  import org.eclipse.jgit.lib.ObjectId;
25  import org.eclipse.jgit.lib.Repository;
26  
27  /**
28   * Blame command for building a {@link org.eclipse.jgit.blame.BlameResult} for a
29   * file path.
30   */
31  public class BlameCommand extends GitCommand<BlameResult> {
32  
33  	private String path;
34  
35  	private DiffAlgorithm diffAlgorithm;
36  
37  	private RawTextComparator textComparator;
38  
39  	private ObjectId startCommit;
40  
41  	private Collection<ObjectId> reverseEndCommits;
42  
43  	private Boolean followFileRenames;
44  
45  	/**
46  	 * Constructor for BlameCommand
47  	 *
48  	 * @param repo
49  	 *            the {@link org.eclipse.jgit.lib.Repository}
50  	 */
51  	public BlameCommand(Repository repo) {
52  		super(repo);
53  	}
54  
55  	/**
56  	 * Set file path.
57  	 *
58  	 * @param filePath
59  	 *            file path (with <code>/</code> as separator)
60  	 * @return this command
61  	 */
62  	public BlameCommand setFilePath(String filePath) {
63  		this.path = filePath;
64  		return this;
65  	}
66  
67  	/**
68  	 * Set diff algorithm
69  	 *
70  	 * @param diffAlgorithm
71  	 *            a {@link org.eclipse.jgit.diff.DiffAlgorithm} object.
72  	 * @return this command
73  	 */
74  	public BlameCommand setDiffAlgorithm(DiffAlgorithm diffAlgorithm) {
75  		this.diffAlgorithm = diffAlgorithm;
76  		return this;
77  	}
78  
79  	/**
80  	 * Set raw text comparator
81  	 *
82  	 * @param textComparator
83  	 *            a {@link org.eclipse.jgit.diff.RawTextComparator}
84  	 * @return this command
85  	 */
86  	public BlameCommand setTextComparator(RawTextComparator textComparator) {
87  		this.textComparator = textComparator;
88  		return this;
89  	}
90  
91  	/**
92  	 * Set start commit id
93  	 *
94  	 * @param commit
95  	 *            id of a commit
96  	 * @return this command
97  	 */
98  	public BlameCommand setStartCommit(AnyObjectId commit) {
99  		this.startCommit = commit.toObjectId();
100 		return this;
101 	}
102 
103 	/**
104 	 * Enable (or disable) following file renames.
105 	 * <p>
106 	 * If true renames are followed using the standard FollowFilter behavior
107 	 * used by RevWalk (which matches {@code git log --follow} in the C
108 	 * implementation). This is not the same as copy/move detection as
109 	 * implemented by the C implementation's of {@code git blame -M -C}.
110 	 *
111 	 * @param follow
112 	 *            enable following.
113 	 * @return {@code this}
114 	 */
115 	public BlameCommand setFollowFileRenames(boolean follow) {
116 		followFileRenames = Boolean.valueOf(follow);
117 		return this;
118 	}
119 
120 	/**
121 	 * Configure the command to compute reverse blame (history of deletes).
122 	 *
123 	 * @param start
124 	 *            oldest commit to traverse from. The result file will be loaded
125 	 *            from this commit's tree.
126 	 * @param end
127 	 *            most recent commit to stop traversal at. Usually an active
128 	 *            branch tip, tag, or HEAD.
129 	 * @return {@code this}
130 	 * @throws java.io.IOException
131 	 *             the repository cannot be read.
132 	 */
133 	public BlameCommand reverse(AnyObjectId/../../../org/eclipse/jgit/lib/AnyObjectId.html#AnyObjectId">AnyObjectId start, AnyObjectId end)
134 			throws IOException {
135 		return reverse(start, Collections.singleton(end.toObjectId()));
136 	}
137 
138 	/**
139 	 * Configure the generator to compute reverse blame (history of deletes).
140 	 *
141 	 * @param start
142 	 *            oldest commit to traverse from. The result file will be loaded
143 	 *            from this commit's tree.
144 	 * @param end
145 	 *            most recent commits to stop traversal at. Usually an active
146 	 *            branch tip, tag, or HEAD.
147 	 * @return {@code this}
148 	 * @throws java.io.IOException
149 	 *             the repository cannot be read.
150 	 */
151 	public BlameCommand reverse(AnyObjectId start, Collection<ObjectId> end)
152 			throws IOException {
153 		startCommit = start.toObjectId();
154 		reverseEndCommits = new ArrayList<>(end);
155 		return this;
156 	}
157 
158 	/**
159 	 * {@inheritDoc}
160 	 * <p>
161 	 * Generate a list of lines with information about when the lines were
162 	 * introduced into the file path.
163 	 */
164 	@Override
165 	public BlameResult call() throws GitAPIException {
166 		checkCallable();
167 		try (BlameGeneratorator.html#BlameGenerator">BlameGenerator gen = new BlameGenerator(repo, path)) {
168 			if (diffAlgorithm != null)
169 				gen.setDiffAlgorithm(diffAlgorithm);
170 			if (textComparator != null)
171 				gen.setTextComparator(textComparator);
172 			if (followFileRenames != null)
173 				gen.setFollowFileRenames(followFileRenames.booleanValue());
174 
175 			if (reverseEndCommits != null)
176 				gen.reverse(startCommit, reverseEndCommits);
177 			else if (startCommit != null)
178 				gen.push(null, startCommit);
179 			else {
180 				gen.prepareHead();
181 			}
182 			return gen.computeBlameResult();
183 		} catch (IOException e) {
184 			throw new JGitInternalException(e.getMessage(), e);
185 		}
186 	}
187 }