Skip to content

Commit 8711c8e

Browse files
authored
Merge pull request #209 from leonardoAnjos16/mergiraf-and-sepmerge-experiment
Estudo do Mergiraf vs SepMerge
2 parents 0c67e76 + f62d916 commit 8711c8e

12 files changed

Lines changed: 357 additions & 8 deletions

File tree

dependencies/mergiraf

46.2 MB
Binary file not shown.

dependencies/sepmerge.jar

10.3 MB
Binary file not shown.

src/main/arguments/Arguments.groovy

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ class Arguments {
3131
numOfThreads = 1
3232
keepProjects = false
3333
syntacticSeparators = '{ } ( ) ; ,'
34-
fileExtension = 'java'
34+
fileExtension = '.java'
3535
logLevel = Level.INFO
3636
}
3737

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package injectors
2+
3+
@Grab('com.google.inject:guice:4.2.2')
4+
import com.google.inject.AbstractModule
5+
import com.google.inject.multibindings.Multibinder
6+
7+
import interfaces.*
8+
import services.commitFilters.MutuallyModifiedFilesCommitFilter
9+
import services.dataCollectors.MergirafAndSepMergeCollector.MergesCollector
10+
import services.outputProcessors.EmptyOutputProcessor
11+
import services.projectProcessors.DummyProjectProcessor
12+
13+
class MergirafAndSepMergeModule extends AbstractModule {
14+
@Override
15+
protected void configure() {
16+
Multibinder<DataCollector> dataCollectorsBinder = Multibinder.newSetBinder(binder(), DataCollector)
17+
dataCollectorsBinder.addBinding().to(MergesCollector)
18+
19+
Multibinder<ProjectProcessor> projectProcessorsBinder = Multibinder.newSetBinder(binder(), ProjectProcessor)
20+
projectProcessorsBinder.addBinding().to(DummyProjectProcessor)
21+
22+
Multibinder<OutputProcessor> outputProcessorsBinder = Multibinder.newSetBinder(binder(), OutputProcessor)
23+
outputProcessorsBinder.addBinding().to(EmptyOutputProcessor)
24+
25+
bind(CommitFilter).to(MutuallyModifiedFilesCommitFilter)
26+
}
27+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package services.dataCollectors.MergirafAndSepMergeCollector
2+
3+
import java.nio.file.Path
4+
5+
class DataAnalyser {
6+
static List<MergeSummary> analyseMerges(List<Path> filesQuadruplePaths) {
7+
return filesQuadruplePaths.stream().map(MergeSummary::new).toList()
8+
}
9+
}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
package services.dataCollectors.MergirafAndSepMergeCollector
2+
3+
import services.util.MergeConflict
4+
import services.util.MergeToolRunner
5+
import services.util.Utils
6+
7+
import java.nio.file.Path
8+
import org.apache.commons.lang3.StringUtils
9+
10+
class MergeSummary {
11+
private Path filesQuadruplePath
12+
13+
Map<String, String> mergeContents
14+
Map<String, Set<MergeConflict>> mergeConflicts
15+
16+
MergeSummary(Path filesQuadruplePath) {
17+
this.filesQuadruplePath = filesQuadruplePath
18+
19+
Map<String, Path> mergePaths = getMergePaths()
20+
removeBaseFromConflicts(mergePaths)
21+
22+
this.mergeContents = readMergeContents(mergePaths)
23+
this.mergeConflicts = extractMergeConflicts(mergePaths)
24+
}
25+
26+
static List<String> getMergeIds() {
27+
List<String> mergeIds = MergesCollector.getMergeToolNames()
28+
mergeIds.add('actual')
29+
return mergeIds
30+
}
31+
32+
String getFileName() {
33+
return this.filesQuadruplePath.getFileName()
34+
}
35+
36+
int getNumberOfConflicts(String mergeId) {
37+
return this.mergeConflicts[mergeId].size()
38+
}
39+
40+
boolean mergesHaveSameContents(String firstMergeId, String secondMergeId) {
41+
String firstMergeContent = StringUtils.deleteWhitespace(this.mergeContents[firstMergeId])
42+
String secondMergeContent = StringUtils.deleteWhitespace(this.mergeContents[secondMergeId])
43+
return firstMergeContent == secondMergeContent
44+
}
45+
46+
boolean mergesHaveSameConflicts(String firstMergeId, String secondMergeId) {
47+
return this.mergeConflicts[firstMergeId] == this.mergeConflicts[secondMergeId]
48+
}
49+
50+
private Map<String, Path> getMergePaths() {
51+
Map<String, Path> mergePaths = [:]
52+
List<String> mergeToolNames = MergesCollector.getMergeToolNames()
53+
54+
for (String mergeToolName: mergeToolNames) {
55+
mergePaths[mergeToolName] = getMergeToolOutputPath(mergeToolName)
56+
}
57+
58+
mergePaths["actual"] = this.filesQuadruplePath.resolve(getMergeFileName())
59+
return mergePaths
60+
}
61+
62+
private Path getMergeToolOutputPath(String mergeToolName) {
63+
return this.filesQuadruplePath.resolve(mergeToolName).resolve(getMergeFileName())
64+
}
65+
66+
private String getMergeFileName() {
67+
return Utils.getfileNameWithExtension(MergeToolRunner.DEFAULT_MERGE_FILE_NAME)
68+
}
69+
70+
private void removeBaseFromConflicts(Map<String, Path> mergePaths) {
71+
mergePaths.each { _, mergePath ->
72+
MergeConflict.removeBaseFromConflicts(mergePath)
73+
}
74+
}
75+
76+
private Map<String, String> readMergeContents(Map<String, Path> mergePaths) {
77+
Map<String, String> mergeContents = [:]
78+
mergePaths.each { mergeId, mergePath ->
79+
String mergeContent = mergePath.getText()
80+
mergeContents[mergeId] = mergeContent
81+
}
82+
83+
return mergeContents
84+
}
85+
86+
private Map<String, Set<MergeConflict>> extractMergeConflicts(Map<String, Path> mergePaths) {
87+
Map<String, Set<MergeConflict>> mergeConflicts = [:]
88+
mergePaths.each { mergeId, mergePath ->
89+
Set<MergeConflict> conflicts = MergeConflict.extractMergeConflicts(mergePath)
90+
mergeConflicts[mergeId] = conflicts
91+
}
92+
93+
return mergeConflicts
94+
}
95+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package services.dataCollectors.MergirafAndSepMergeCollector
2+
3+
import java.nio.file.Path
4+
5+
import interfaces.DataCollector
6+
import project.MergeCommit
7+
import project.Project
8+
import services.dataCollectors.MergirafAndSepMergeCollector.mergeToolRunners.*
9+
import services.dataCollectors.S3MWithCSDiffCollector.mergeToolRunners.Diff3Runner
10+
import services.dataCollectors.S3MMergesCollector.MergeScenarioCollector
11+
import services.util.MergeToolRunner
12+
13+
class MergesCollector implements DataCollector {
14+
private static final List<MergeToolRunner> RUNNERS = [
15+
new Diff3Runner(),
16+
new MergirafRunner(),
17+
new SepMergeRunner(false),
18+
new SepMergeRunner(true)
19+
]
20+
21+
@Override
22+
void collectData(Project project, MergeCommit mergeCommit) {
23+
List<Path> mergeScenarios = MergeScenarioCollector.collectMergeScenarios(project, mergeCommit)
24+
println 'Collected merge scenarios'
25+
26+
for (MergeToolRunner runner: RUNNERS) {
27+
runner.collectResults(mergeScenarios)
28+
}
29+
30+
println 'Collected merge results'
31+
32+
List<MergeSummary> summaries = DataAnalyser.analyseMerges(mergeScenarios)
33+
println 'Built summaries over collected data'
34+
35+
SpreadsheetBuilder.updateSpreadsheet(project, mergeCommit, summaries)
36+
println 'Updated spreadsheet'
37+
}
38+
39+
static List<String> getMergeToolNames() {
40+
return RUNNERS.stream().map(MergeToolRunner::getMergeToolName).toList()
41+
}
42+
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
package services.dataCollectors.MergirafAndSepMergeCollector
2+
3+
import project.MergeCommit
4+
import project.Project
5+
import services.util.Utils
6+
7+
import java.nio.file.Path
8+
9+
class SpreadsheetBuilder {
10+
private static final String SEPARATOR = ','
11+
private static final String SPREADSHEET_NAME = 'results.csv'
12+
private static final Map<String, Closure> HEADER_NAME_TO_VALUE_GETTER
13+
14+
static {
15+
HEADER_NAME_TO_VALUE_GETTER = [
16+
project: { project, _, __ -> project.getName() },
17+
'merge commit': { _, mergeCommit, __ -> mergeCommit.getSHA() },
18+
file: { _, __, mergeSummary -> mergeSummary.getFileName() }
19+
]
20+
21+
List<String> mergeIds = MergeSummary.getMergeIds()
22+
for (String mergeId: mergeIds) {
23+
String currentMergeId = mergeId
24+
String headerName = "number of ${currentMergeId} conflicts"
25+
26+
HEADER_NAME_TO_VALUE_GETTER[headerName] = { _, __, mergeSummary ->
27+
Integer.toString(mergeSummary.getNumberOfConflicts(currentMergeId))
28+
}
29+
}
30+
31+
for (int i = 0; i < mergeIds.size(); i++) {
32+
String firstMergeId = mergeIds[i]
33+
for (int j = i + 1; j < mergeIds.size(); j++) {
34+
String secondMergeId = mergeIds[j]
35+
String headerName = "${firstMergeId} content = ${secondMergeId} content"
36+
37+
HEADER_NAME_TO_VALUE_GETTER[headerName] = { _, __, mergeSummary ->
38+
Boolean.toString(mergeSummary.mergesHaveSameContents(firstMergeId, secondMergeId))
39+
}
40+
}
41+
}
42+
43+
for (int i = 0; i < mergeIds.size(); i++) {
44+
String firstMergeId = mergeIds[i]
45+
for (int j = i + 1; j < mergeIds.size(); j++) {
46+
String secondMergeId = mergeIds[j]
47+
String headerName = "${firstMergeId} conflicts = ${secondMergeId} conflicts"
48+
49+
HEADER_NAME_TO_VALUE_GETTER[headerName] = { _, __, mergeSummary ->
50+
Boolean.toString(mergeSummary.mergesHaveSameConflicts(firstMergeId, secondMergeId))
51+
}
52+
}
53+
}
54+
}
55+
56+
static synchronized void updateSpreadsheet(Project project, MergeCommit mergeCommit, List<MergeSummary> summaries) {
57+
File spreadsheet = Utils.getOutputPath().resolve(SPREADSHEET_NAME).toFile()
58+
if (!spreadsheet.exists()) {
59+
String headerLine = getSpreadsheetHeaderLine()
60+
appendLineToSpreadsheet(spreadsheet, headerLine)
61+
}
62+
63+
summaries.each { summary ->
64+
String valuesLine = getSpreadsheetValuesLine(project, mergeCommit, summary)
65+
appendLineToSpreadsheet(spreadsheet, valuesLine)
66+
}
67+
}
68+
69+
private static String getSpreadsheetHeaderLine() {
70+
List<String> headerNames = HEADER_NAME_TO_VALUE_GETTER.keySet().toList()
71+
return headerNames.join(SEPARATOR)
72+
}
73+
74+
private static String getSpreadsheetValuesLine(Project project, MergeCommit mergeCommit, MergeSummary mergeSummary) {
75+
List<String> values = []
76+
HEADER_NAME_TO_VALUE_GETTER.each { _, getValue ->
77+
values.add(getValue(project, mergeCommit, mergeSummary))
78+
}
79+
80+
return values.join(SEPARATOR)
81+
}
82+
83+
private static void appendLineToSpreadsheet(File spreadsheet, String line) {
84+
spreadsheet << "${line.replaceAll('\\\\', '/')}\n"
85+
}
86+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package services.dataCollectors.MergirafAndSepMergeCollector.mergeToolRunners
2+
3+
import services.util.MergeToolRunner
4+
import util.ProcessRunner
5+
6+
import java.nio.file.Path
7+
import java.nio.file.Paths
8+
9+
class MergirafRunner extends MergeToolRunner {
10+
private static final Path MERGIRAF_PATH = Paths.get('dependencies/mergiraf')
11+
12+
MergirafRunner() {
13+
this.mergeToolName = 'mergiraf'
14+
}
15+
16+
protected ProcessBuilder buildProcess(Path leftFile, Path baseFile, Path rightFile) {
17+
String processDirectory = MERGIRAF_PATH.getParent().toString()
18+
return ProcessRunner.buildProcess(processDirectory)
19+
}
20+
21+
protected List<String> buildParameters(Path leftFile, Path baseFile, Path rightFile) {
22+
String binaryFileCommand = "./${MERGIRAF_PATH.getFileName().toString()}"
23+
List<String> parameters = [
24+
binaryFileCommand, 'merge',
25+
'-s', DEFAULT_BASE_MARKER_NAME,
26+
'-x', DEFAULT_LEFT_MARKER_NAME,
27+
'-y', DEFAULT_RIGHT_MARKER_NAME
28+
]
29+
30+
parameters.addAll(baseFile.toString(), leftFile.toString(), rightFile.toString())
31+
32+
Path filesQuadruplePath = baseFile.getParent()
33+
Path outputPath = getOutputPath(filesQuadruplePath, DEFAULT_MERGE_FILE_NAME)
34+
parameters.addAll('-o', outputPath.toString())
35+
36+
return parameters
37+
}
38+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package services.dataCollectors.MergirafAndSepMergeCollector.mergeToolRunners
2+
3+
import services.util.MergeToolRunner
4+
import util.ProcessRunner
5+
6+
import java.nio.file.Path
7+
import java.nio.file.Paths
8+
9+
class SepMergeRunner extends MergeToolRunner {
10+
private static final Path SEPMERGE_PATH = Paths.get('dependencies/sepmerge.jar')
11+
12+
private boolean extensive
13+
14+
SepMergeRunner(boolean extensive) {
15+
this.extensive = extensive
16+
this.mergeToolName = "sepmerge-${!extensive ? 'default' : 'extensive'}".toString()
17+
}
18+
19+
protected ProcessBuilder buildProcess(Path leftFile, Path baseFile, Path rightFile) {
20+
String processDirectory = SEPMERGE_PATH.getParent().toString()
21+
return ProcessRunner.buildProcess(processDirectory)
22+
}
23+
24+
protected List<String> buildParameters(Path leftFile, Path baseFile, Path rightFile) {
25+
String jarFileName = SEPMERGE_PATH.getFileName().toString()
26+
List<String> parameters = ['java', '-jar', jarFileName]
27+
parameters.addAll(leftFile.toString(), baseFile.toString(), rightFile.toString())
28+
29+
Path filesQuadruplePath = baseFile.getParent()
30+
Path outputPath = getOutputPath(filesQuadruplePath, DEFAULT_MERGE_FILE_NAME)
31+
parameters.addAll("-o=${outputPath.toString()}".toString())
32+
33+
if (this.extensive) {
34+
parameters.add('-e')
35+
}
36+
37+
return parameters
38+
}
39+
}

0 commit comments

Comments
 (0)