forked from reposense/RepoSense
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathFileInfoAnalyzer.java
More file actions
126 lines (109 loc) · 5.13 KB
/
FileInfoAnalyzer.java
File metadata and controls
126 lines (109 loc) · 5.13 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
package reposense.authorship;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.PathMatcher;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import reposense.authorship.analyzer.AnnotatorAnalyzer;
import reposense.authorship.model.FileInfo;
import reposense.authorship.model.FileResult;
import reposense.authorship.model.LineInfo;
import reposense.git.GitBlame;
import reposense.model.Author;
import reposense.model.CommitHash;
import reposense.model.RepoConfiguration;
import reposense.system.LogsManager;
/**
* Analyzes the target and information given in the {@code FileInfo}.
*/
public class FileInfoAnalyzer {
private static final Logger logger = LogsManager.getLogger(FileInfoAnalyzer.class);
private static final String REUSED_TAG = "//@reused";
private static final int AUTHOR_NAME_OFFSET = "author ".length();
private static final int AUTHOR_EMAIL_OFFSET = "author-mail ".length();
private static final int FULL_COMMIT_HASH_LENGTH = 40;
/**
* Analyzes the lines of the file, given in the {@code fileInfo}, that has changed in the time period provided
* by {@code config}.
* Returns null if the file contains the reused tag, or none of the {@code Author} specified in
* {@code config} contributed to the file in {@code fileInfo}.
*/
public static FileResult analyzeFile(RepoConfiguration config, FileInfo fileInfo) {
String relativePath = fileInfo.getPath();
if (isReused(config.getRepoRoot(), relativePath)) {
return null;
}
aggregateBlameAuthorInfo(config, fileInfo);
fileInfo.setFileType(config.getFileType(fileInfo.getPath()));
if (config.isAnnotationOverwrite()) {
AnnotatorAnalyzer.aggregateAnnotationAuthorInfo(fileInfo, config.getAuthorEmailsAndAliasesMap());
}
if (!config.getAuthorList().isEmpty() && fileInfo.isAllAuthorsIgnored(config.getAuthorList())) {
return null;
}
return generateFileResult(fileInfo);
}
/**
* Generates and returns a {@code FileResult} with the authorship results from {@code fileInfo} consolidated.
*/
private static FileResult generateFileResult(FileInfo fileInfo) {
HashMap<Author, Integer> authorContributionMap = new HashMap<>();
for (LineInfo line : fileInfo.getLines()) {
Author author = line.getAuthor();
authorContributionMap.put(author, authorContributionMap.getOrDefault(author, 0) + 1);
}
return new FileResult(fileInfo.getPath(), fileInfo.getFileType(), fileInfo.getLines(), authorContributionMap);
}
/**
* Sets the {@code Author} for each line in {@code fileInfo} based on the git blame analysis on the file.
*/
private static void aggregateBlameAuthorInfo(RepoConfiguration config, FileInfo fileInfo) {
String blameResults = getGitBlameResult(config, fileInfo.getPath());
String[] blameResultLines = blameResults.split("\n");
Path filePath = Paths.get(fileInfo.getPath());
for (int lineCount = 0; lineCount < blameResultLines.length; lineCount += 3) {
String commitHash = blameResultLines[lineCount].substring(0, FULL_COMMIT_HASH_LENGTH);
String authorName = blameResultLines[lineCount + 1].substring(AUTHOR_NAME_OFFSET);
String authorEmail = blameResultLines[lineCount + 2]
.substring(AUTHOR_EMAIL_OFFSET).replaceAll("<|>", "");
Author author = config.getAuthor(authorName, authorEmail);
if (!fileInfo.isFileLineTracked(lineCount / 3) || isAuthorIgnoringFile(author, filePath)
|| CommitHash.isInsideCommitList(commitHash, config.getIgnoreCommitList())) {
author = Author.UNKNOWN_AUTHOR;
}
fileInfo.setLineAuthor(lineCount / 3, author);
}
}
/**
* Returns the analysis result from running git blame on {@code filePath}.
*/
private static String getGitBlameResult(RepoConfiguration config, String filePath) {
return GitBlame.blame(config.getRepoRoot(), filePath);
}
/**
* Returns true if the first line in the file at {@code repoRoot}'s {@code relativePath} contains the reused tag.
*/
private static boolean isReused(String repoRoot, String relativePath) {
Path path = Paths.get(repoRoot, relativePath);
try (BufferedReader br = new BufferedReader(new FileReader(path.toFile()))) {
String firstLine = br.readLine();
if (firstLine == null || firstLine.contains(REUSED_TAG)) {
return true;
}
} catch (IOException ioe) {
logger.log(Level.WARNING, ioe.getMessage(), ioe);
}
return false;
}
/**
* Returns true if the {@code author} is ignoring the {@code filePath} based on its ignore glob list.
*/
private static boolean isAuthorIgnoringFile(Author author, Path filePath) {
PathMatcher ignoreGlobMatcher = author.getIgnoreGlobMatcher();
return ignoreGlobMatcher.matches(filePath);
}
}